From 7397e53362d118d431c89148d02578a8a36b6961 Mon Sep 17 00:00:00 2001 From: Alan Rynne Date: Tue, 28 Nov 2023 16:22:03 +0100 Subject: [PATCH] fix(All): Solution pass to fix formatting warnings (#3068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Silence Bentley and AdvanceSteel warnings on CI * fix(rvt): Remove space in `Partial Classes` folder * fix(tekla): Remove space from `Partial Classes` folder * fix(dyn): REVERT THIS AT THE END. Fix dynamo build on mac for cleanup * chore(all): Run csharpier for entire monorepo * fix(IDE0161): File-scoped namespaces * fix(IDE0090): 'new' expression can be simplified * fix(IDE0022): Use block body for method * Revert "fix(IDE0022): Use block body for method" This reverts commit 8bb9b7e2c79ed62da8fc87e99cad78d3b334088e. * feat: Expression body for methods is suggestion now * chore: Enforce husky setup on restore * fix: PEBKAC 🤦🏼‍♂️ * fix(all): IDE0011 * Warnings for our first set of warnings * fix(all): IDE0011 * feat(ci): Enforce csharpier formatting * fix(ci): Wrong yaml indent and format * fix(tests): IsDesktopBuild passed to tests in core * fix(ci): Disable auto pre-commit hook install * removed accidental push of warning as error * Revert "fix(dyn): REVERT THIS AT THE END. Fix dynamo build on mac for cleanup" This reverts commit 0658b36373c12b2e761e8d1a2fa1769a4927dd60. --------- Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> --- .circleci/scripts/config-template.yml | 6 + .editorconfig | 3 +- All.sln.DotSettings | 2 +- .../Speckle.Automate.Sdk/AutomationContext.cs | 23 + Automate/Speckle.Automate.Sdk/Runner.cs | 8 +- .../TestAutomateFunction.cs | 2 + .../Communication/AsyncCommandProcessor.cs | 45 +- .../Communication/CommandRequest.cs | 98 +- .../Communication/CommandResponse.cs | 52 +- .../Commands/Command_CreateBeam.cs | 61 +- .../Commands/Command_CreateColumn.cs | 61 +- .../Commands/Command_CreateDirectShape.cs | 65 +- .../Commands/Command_CreateDoor.cs | 53 +- .../Commands/Command_CreateFloor.cs | 53 +- .../Commands/Command_CreateGridElement.cs | 53 +- .../Commands/Command_CreateObject.cs | 64 +- .../Commands/Command_CreateRoof.cs | 59 +- .../Commands/Command_CreateRoom.cs | 53 +- .../Commands/Command_CreateShell.cs | 59 +- .../Commands/Command_CreateSkylight.cs | 54 +- .../Commands/Command_CreateWall.cs | 61 +- .../Commands/Command_CreateWindow.cs | 53 +- .../Command_FinishReceiveTransaction.cs | 26 +- .../Commands/Command_GetBeamData.cs | 45 +- .../Commands/Command_GetColumnData.cs | 45 +- .../Commands/Command_GetDoorData.cs | 65 +- .../Commands/Command_GetElementBaseData.cs | 63 +- .../Commands/Command_GetElementIds.cs | 111 +- .../Commands/Command_GetElementType.cs | 111 +- .../Commands/Command_GetFloorData.cs | 45 +- .../Commands/Command_GetGridElementData.cs | 59 +- .../Commands/Command_GetModelOfElements.cs | 57 +- .../Commands/Command_GetObjectData.cs | 63 +- .../Commands/Command_GetProjectInfo.cs | 27 +- .../Commands/Command_GetRoofData.cs | 45 +- .../Commands/Command_GetRoomData.cs | 53 +- .../Commands/Command_GetShellData.cs | 45 +- .../Commands/Command_GetSkylightData.cs | 64 +- .../Commands/Command_GetSubelementInfo.cs | 59 +- .../Commands/Command_GetWallData.cs | 45 +- .../Commands/Command_GetWindowData.cs | 65 +- .../Commands/Command_SelectElements.cs | 98 +- .../Communication/Commands/ICommand.cs | 9 +- .../Communication/ConnectionManager.cs | 53 +- .../Communication/HttpCommandExecutor.cs | 112 +- .../ConnectorArchicad/ConnectorBinding.cs | 397 +-- .../Converters/ConversionOptions.cs | 24 +- .../Converters/ConverterArchicad.cs | 253 +- .../Converters/Converters/BeamConverter.cs | 146 +- .../Converters/Converters/ColumnConverter.cs | 138 +- .../Converters/DirectShapeConverter.cs | 140 +- .../Converters/Converters/DoorConverter.cs | 112 +- .../Converters/Converters/FloorConverter.cs | 120 +- .../Converters/GridLineConverter.cs | 187 +- .../Converters/IElementConverter.cs | 21 +- .../Converters/Converters/ObjectConverter.cs | 339 +- .../Converters/Converters/RoofConverter.cs | 218 +- .../Converters/Converters/RoomConverter.cs | 172 +- .../Converters/SkylightConverter.cs | 112 +- .../Converters/Converters/Utils.cs | 263 +- .../Converters/Converters/WallConverter.cs | 117 +- .../Converters/Converters/WindowConverter.cs | 112 +- .../Converters/ElementConverterManager.cs | 466 +-- .../ElementConverterManagerReceive.cs | 189 +- .../Converters/ElementTypeProvider.cs | 43 +- .../Converters/ModelConverter.cs | 558 ++-- .../ConnectorArchicad/Elements/GridElement.cs | 45 +- .../ConnectorArchicad/Elements/Object.cs | 45 +- .../ConnectorArchicad/Elements/Room.cs | 57 +- .../ConnectorArchicad/Helpers/Timer.cs | 73 +- .../Model/ElementModelData.cs | 15 +- .../ConnectorArchicad/Model/MeshModel.cs | 356 ++- .../Model/ProjectInfoData.cs | 97 +- .../ConnectorArchicad/Program.cs | 92 +- .../UI/ConnectorBinding.Selection.cs | 11 +- .../UI/ConnectorBinding.Settings.cs | 20 +- .../AdvanceSteelAddinRegistrator.csproj | 9 +- .../AdvanceSteelAddinRegistrator/Program.cs | 225 +- .../ConnectorAdvanceSteel2023.csproj | 9 +- .../ConnectorAdvanceSteel2024.csproj | 9 +- .../DocumentUtils/TransactionContext.cs | 93 +- .../ConnectorAutocadCivil/Entry/App.cs | 412 +-- .../Entry/SpeckleAutocadCommand.cs | 223 +- .../Storage/SpeckleStreamManager.cs | 231 +- .../ConnectorBindingsAutocadCivil.Events.cs | 87 +- .../ConnectorBindingsAutocadCivil.Previews.cs | 127 +- .../ConnectorBindingsAutocadCivil.Receive.cs | 936 +++--- ...ConnectorBindingsAutocadCivil.Selection.cs | 166 +- .../UI/ConnectorBindingsAutocadCivil.Send.cs | 503 +-- .../UI/ConnectorBindingsAutocadCivil.cs | 228 +- .../ConnectorAutocadCivil/Utils.cs | 1122 +++---- .../ConnectorBentleyShared/Entry/App.cs | 77 +- .../Entry/SpeckleBentleyCommand.cs | 62 +- .../ConnectorBentleyShared/Keyins.cs | 13 +- .../Storage/StreamStateManager.cs | 178 +- .../ConnectorBentleyShared/UI/Bindings.cs | 1369 ++++---- .../ConnectorBentleyShared/Utils.cs | 77 +- .../ConnectorMicroStation.csproj | 8 +- .../ConnectorOpenBuildings.csproj | 9 +- .../ConnectorOpenRail.csproj | 8 +- .../ConnectorOpenRoads.csproj | 10 +- .../StreamStateManager/StreamStateManager.cs | 284 +- .../ConnectorBindingsCSI.ClientOperations.cs | 37 +- .../UI/ConnectorBindingsCSI.Recieve.cs | 473 +-- .../UI/ConnectorBindingsCSI.Selection.cs | 206 +- .../UI/ConnectorBindingsCSI.Send.cs | 368 +-- .../UI/ConnectorBindingsCSI.Settings.cs | 110 +- .../UI/ConnectorBindingsCSI.cs | 125 +- .../ConnectorCSIShared/UnusedClass.cs | 19 +- .../Util/ConnectorCSIUtils.cs | 1237 ++++---- .../ConnectorCSIShared/Util/ResultUtils.cs | 25 +- ConnectorCSI/ConnectorCSIShared/cPlugin.cs | 173 +- .../Properties/AssemblyInfo.cs | 2 +- ConnectorCSI/DriverCSharp/PluginCallback.cs | 37 +- ConnectorCSI/DriverCSharp/Program.cs | 191 +- ConnectorCSI/DriverPluginCSharp/cPlugin.cs | 95 +- .../BatchUploadOperationDriver.cs | 4 + .../BatchUploader.Sdk/BatchUploaderClient.cs | 2 +- .../IApplicationFunctionalityController.cs | 2 +- .../ConnectorDynamo/AccountsNode/Accounts.cs | 198 +- .../AccountsNode/AccountsUi.xaml.cs | 19 +- .../AccountsNode/AccountsViewCustomization.cs | 79 +- .../CreateStreamNode/CreateStream.cs | 276 +- .../CreateStreamNode/CreateStreamUi.xaml.cs | 19 +- .../CreateStreamViewCustomization.cs | 116 +- .../ConnectorDynamo/DebounceTimer.cs | 75 +- .../ConnectorDynamo/ReceiveNode/Receive.cs | 990 +++--- .../ReceiveNode/ReceiveUi.xaml.cs | 19 +- .../ReceiveNode/ReceiveViewCustomization.cs | 159 +- .../ConnectorDynamo/SendNode/Send.cs | 832 ++--- .../ConnectorDynamo/SendNode/SendUi.xaml.cs | 19 +- .../SendNode/SendViewCustomization.cs | 143 +- .../ValueConverters/BoolVisibConverter.cs | 41 +- .../ConnectorDynamo/ViewNode/View.cs | 292 +- .../ConnectorDynamo/ViewNode/ViewUi.xaml.cs | 19 +- .../ViewNode/ViewViewCustomization.cs | 68 +- .../SpeckleExtension.cs | 71 +- .../SpeckleWatchHandler.cs | 109 +- .../ConnectorDynamoFunctions/Account.cs | 85 +- .../ConnectorDynamoFunctions/Auto.cs | 101 +- .../BatchConverter.cs | 531 ++-- .../Developer/Conversion.cs | 59 +- .../Developer/Local.cs | 77 +- .../Developer/Serialization.cs | 45 +- .../Developer/Transport.cs | 152 +- .../ConnectorDynamoFunctions/Functions.cs | 401 +-- .../ConnectorDynamoFunctions/Globals.cs | 19 +- .../ConnectorDynamoFunctions/Icon.cs | 25 +- .../ConnectorDynamoFunctions/InMemoryCache.cs | 36 +- .../OnErrorEventArgs.cs | 19 +- .../ConnectorDynamoFunctions/Stream.cs | 396 +-- .../ConnectorDynamoFunctions/Utils.cs | 249 +- .../Accounts/Accounts.AccountDetailsV2.cs | 4 +- .../Accounts/Accounts.GetAccountToken.cs | 9 +- .../Accounts/Accounts.ListAccounts.cs | 8 +- .../Accounts/Accounts.ServerAccount.cs | 17 +- .../Obsolete/Accounts.AccountDetails.cs | 8 +- .../Accounts/Obsolete/AccountsV2Upgrader.cs | 2 +- .../BaseComponents/ComponentTracker.cs | 11 +- .../GH_SpeckleAsyncComponent.cs | 4 +- .../BaseComponents/GH_SpeckleComponent.cs | 4 +- .../GH_SpeckleTaskCapableComponent.cs | 4 +- .../ISpeckleTrackingComponent.cs | 2 +- .../SelectKitAsyncComponentBase.cs | 14 +- .../BaseComponents/SelectKitComponentBase.cs | 6 +- .../SelectKitTaskCapableComponentBase.cs | 15 +- .../Collections/FlattenCollectionComponent.cs | 15 +- .../Collections/GH_SpeckleCollection.cs | 2 +- .../Collections/SpeckleCollectionParam.cs | 4 +- .../ComponentCategories.cs | 2 +- .../ConnectorGrasshopperInfo.cs | 2 +- .../DeserialiseTaskCapableComponent.cs | 11 +- .../SerialiseTaskCapableComponent.cs | 14 +- .../ToNativeTaskCapableComponent.cs | 12 +- .../ToSpeckleTaskCapableComponent.cs | 14 +- .../Extras/DebounceDispatcher.cs | 12 +- .../Extras/GH_SpeckleAccount.cs | 6 +- .../Extras/GH_SpeckleBase.cs | 11 +- .../Extras/GH_SpeckleGoo.cs | 2 +- .../Extras/GenericAccessParam.cs | 5 + .../Extras/SendReceiveDataParam.cs | 2 +- .../Extras/SpeckleBaseParam.cs | 10 +- .../Extras/SpeckleStateTag.cs | 6 +- .../Extras/SpeckleStatefulParam.cs | 27 +- .../Extras/SpeckleStreamParam.cs | 9 +- .../Extras/SpeckleUpgradeObject.cs | 6 +- .../Extras/TreeBuilder.cs | 16 +- .../Extras/Utilities.cs | 76 +- .../ConnectorGrasshopperShared/Loader.cs | 27 + ...eSpeckleObjectByKeyValueV2TaskComponent.cs | 18 +- .../CreateSpeckleObjectTaskComponent.cs | 28 + .../DeconstructSpeckleObjectTaskComponent.cs | 38 +- ...ateSpeckleObjectByKeyValueTaskComponent.cs | 31 +- .../ExpandSpeckleObjectTaskComponent.cs | 31 +- ...endSpeckleObjectByKeyValueTaskComponent.cs | 31 +- .../Objects/Deprecated/ObjectsV2Upgrader.cs | 10 +- ...dSpeckleObjectByKeyValueV2TaskComponent.cs | 20 +- .../ExtendSpeckleObjectTaskComponent.cs | 35 +- .../Objects/GetObjectKeysComponent.cs | 16 +- .../GetObjectValueByKeyTaskComponent.cs | 16 +- .../Objects/SpeckleObjectGroup.cs | 4 +- .../Deprecated/Operations.ReceiveComponent.cs | 53 +- .../Operations.ReceiveComponentSync.cs | 34 +- .../Deprecated/Operations.SendComponent.cs | 31 +- .../Operations.SendComponentSync.cs | 28 +- .../Ops/Deprecated/Operations.UpgradeUtils.cs | 12 +- .../Operations.VariableInputSendComponent.cs | 41 +- .../Ops/Operations.ReceiveLocalComponent.cs | 12 +- .../Ops/Operations.SendLocalComponent.cs | 7 +- .../Ops/Operations.SyncReceiveComponent.cs | 28 +- .../Ops/Operations.SyncSendComponent.cs | 14 +- ...perations.VariableInputReceiveComponent.cs | 79 +- .../Operations.VariableInputSendComponent.cs | 45 +- .../SchemaBuilder/CSOViewModel.cs | 2 +- .../SchemaBuilder/CreateSchemaObject.cs | 57 +- .../SchemaBuilder/CreateSchemaObjectBase.cs | 55 +- .../SchemaBuilder/CreateSchemaObjectDialog.cs | 24 + .../SchemaBuilder/SchemaBuilderGen.cs | 1212 +++++++ .../SpeckleGHSettings.cs | 2 +- .../Deprecated/StreamCreateComponent.cs | 4 +- .../Deprecated/StreamDetailsComponent.cs | 9 +- .../Streams/Deprecated/StreamGetComponent.cs | 7 +- .../Streams/Deprecated/StreamListComponent.cs | 8 +- .../Deprecated/StreamUpdateComponent.cs | 10 +- .../Streams/StreamCreateComponentV2.cs | 8 +- .../Streams/StreamDetailsComponentV2.cs | 6 +- .../Streams/StreamGetComponentV2.cs | 15 +- .../Streams/StreamGetWithTokenComponent.cs | 12 +- .../Streams/StreamListComponentV2.cs | 6 +- .../Streams/StreamUpdateComponentV2.cs | 9 +- .../Streams/Upgraders/V2Upgraders.cs | 2 +- .../Transports/SendReceiveTransport.cs | 23 +- .../Transports/Transports.Disk.cs | 9 +- .../Transports/Transports.Memory.cs | 9 +- .../Transports/Transports.Sqlite.cs | 7 + .../UpgradeUtilities.cs | 2 +- .../ConnectorGrasshopperUtils/CSOUtils.cs | 9 +- .../UserInterfaceUtils.cs | 2 +- .../ConnectorNavisworksBindings.File.cs | 9 +- .../ConnectorNavisworksBindings.Filters.cs | 18 +- .../ConnectorNavisworksBindings.Receive.cs | 2 +- .../ConnectorNavisworksBindings.Send.cs | 33 + .../ConnectorNavisworksBindings.Settings.cs | 2 +- .../Bindings/ConnectorNavisworksBindings.cs | 16 +- .../ConnectorNavisworks/Entry/Commands.cs | 2 +- .../ConnectorNavisworks/Entry/Ribbon.xaml.cs | 16 +- .../Entry/SpeckleHostPane.xaml.cs | 5 +- .../Entry/SpeckleNavisworksCommand.cs | 6 +- .../NavisworksOptions/Autosave.cs | 4 +- .../NavisworksOptions/Manager.cs | 2 +- .../NavisworksOptions/Properties.cs | 4 +- .../ConnectorNavisworks/Other/Constants.cs | 2 +- .../ConnectorNavisworks/Other/Elements.cs | 32 +- .../ConnectorNavisworks/Other/FilterTypes.cs | 2 +- .../ConnectorNavisworks/Other/Invokers.cs | 8 +- .../Other/SelectionBuilder.cs | 52 + .../ConnectorNavisworks/Other/Utilities.cs | 2 +- .../Storage/SpeckleStreamManager.cs | 27 + .../ConnectorRevit/ConnectorRevitUtils.cs | 387 ++- ConnectorRevit/ConnectorRevit/Entry/App.cs | 379 ++- .../Entry/CmdAvailabilityViews.cs | 26 +- .../ConnectorRevit/Entry/HelpCommand.cs | 102 +- .../ConnectorRevit/Entry/SchedulerCommand.cs | 53 +- .../Entry/SpeckleRevitCommand.cs | 270 +- .../ConnectorRevit/Revit/FamilyLoadOption.cs | 33 +- ...RevitApplicationFunctionalityController.cs | 33 +- .../ConnectorRevit/RevitVersionHelper.cs | 16 +- .../Storage/ConvertedObjectsCache.cs | 87 +- .../Storage/RevitDocumentAggregateCache.cs | 105 +- .../Storage/RevitObjectCache.cs | 127 +- .../Storage/StreamStateCache.cs | 92 +- .../Storage/StreamStateManager.cs | 210 +- .../Storage/UIDocumentProvider.cs | 33 +- .../TypeMapping/ElementTypeMapper.cs | 611 ++-- .../TypeMapping/FamilyImporter.cs | 360 ++- .../TypeMapping/HostTypeContainer.cs | 60 +- .../TypeMapping/RevitHostType.cs | 44 +- .../TypeMapping/RevitMappingValue.cs | 39 +- .../TypeMapping/SingleCategoryMap.cs | 58 +- .../ConnectorRevit/TypeMapping/TypeMap.cs | 172 +- .../UI/ConnectorBindingsRevit.Events.cs | 581 ++-- .../UI/ConnectorBindingsRevit.Previews.cs | 234 +- .../UI/ConnectorBindingsRevit.Receive.cs | 799 ++--- .../UI/ConnectorBindingsRevit.Selection.cs | 958 +++--- .../UI/ConnectorBindingsRevit.Send.cs | 401 +-- .../UI/ConnectorBindingsRevit.Settings.cs | 249 +- .../UI/ConnectorBindingsRevit.cs | 105 +- .../ConnectorRevit/UI/Panel.xaml.cs | 80 +- .../IRevitDocumentAggregateCacheExtensions.cs | 98 +- .../IRevitObjectCacheExtensions.cs | 36 +- .../Helpers/Categories.cs | 237 +- .../Helpers/Extensions.cs | 26 +- .../Helpers/RevitCategoryInfo.cs | 87 +- .../Interfaces/IAllRevitCategories.cs | 19 +- .../Interfaces/IAllRevitCategoriesExposer.cs | 15 +- .../Interfaces/IConvertedObjectsCache.cs | 47 +- .../Interfaces/IReceivedObjectIdMap.cs | 23 +- .../Interfaces/IRevitCategoryInfo.cs | 33 +- .../Interfaces/IRevitCommitObjectBuilder.cs | 11 +- .../IRevitCommitObjectBuilderExposer.cs | 9 +- .../IRevitDocumentAggregateCache.cs | 22 +- .../Interfaces/IRevitElementTypeRetriever.cs | 21 +- .../Interfaces/IRevitObjectCache.cs | 34 +- .../RevitSharedResources/Models/APIContext.cs | 182 +- .../Models/ConversionNotReadyCacheData.cs | 14 +- .../RevitSharedResources/Models/ErrorEater.cs | 120 +- .../Models/RevitConverterState.cs | 2 +- .../Models/TransactionManager.cs | 385 +-- .../ConnectorRhinoShared/Entry/Plugin.cs | 18 + .../Entry/SpeckleCommandWin.cs | 2 +- .../Entry/SpeckleMappingsCommandMac.cs | 2 +- .../Entry/SpeckleMappingsCommandWin.cs | 2 +- .../ConnectorRhinoShared/MacOSHelpers.cs | 2 +- .../UI/ConnectorBindingsRhino.3DView.cs | 6 + .../UI/ConnectorBindingsRhino.Events.cs | 8 + .../UI/ConnectorBindingsRhino.Previews.cs | 19 + .../UI/ConnectorBindingsRhino.Receive.cs | 81 + .../UI/ConnectorBindingsRhino.Selection.cs | 20 + .../UI/ConnectorBindingsRhino.Send.cs | 21 + .../UI/ConnectorBindingsRhino.Settings.cs | 5 +- .../UI/ConnectorBindingsRhino.cs | 14 + .../ConnectorRhinoShared/UI/DuiPanel.xaml.cs | 2 +- .../UI/MappingBindingsRhino.cs | 32 + .../UI/MappingsPanel.xaml.cs | 2 +- .../ConnectorRhinoShared/Utils.cs | 45 + .../MainForm.cs | 135 +- .../MainPlugin.cs | 43 +- .../PolygonMesherReferencer.cs | 23 +- .../StreamStateManager/StreamStateManager.cs | 201 +- .../ConnectorBindingsTeklaStructure.Send.cs | 251 +- ...onnectorBindingsTeklaStructure.Settings.cs | 26 +- ...indingsTeklaStructures.ClientOperations.cs | 61 +- ...onnectorBindingsTeklaStructures.Receive.cs | 190 +- ...onnectorBindingsTeklaStructures.Recieve.cs | 66 +- ...nectorBindingsTeklaStructures.Selection.cs | 200 +- .../UI/ConnectorBindingsTeklaStructures.cs | 69 +- .../Util/ConnectorTeklaStructuresUtils.cs | 63 +- .../Client.BranchOperations.cs | 3 +- .../Client.ObsoleteOperations.cs | 5 +- .../Client.ServerOperations.cs | 2 + .../Client.StreamOperations.cs | 6 + Core/Core/Api/GraphQL/Client.cs | 27 +- .../Serializer/ConstantCaseEnumConverter.cs | 3 + .../Api/GraphQL/Serializer/MapConverter.cs | 11 +- .../Serializer/NewtonsoftJsonSerializer.cs | 7 +- Core/Core/Api/Helpers.cs | 29 + .../Core/Api/Operations/Operations.Receive.cs | 34 +- Core/Core/Api/Operations/Operations.Send.cs | 15 + .../Api/Operations/Operations.Serialize.cs | 3 + Core/Core/Api/Operations/Operations.cs | 5 + Core/Core/Core.csproj | 3 +- Core/Core/Credentials/Account.cs | 6 + Core/Core/Credentials/AccountManager.cs | 43 + Core/Core/Credentials/StreamWrapper.cs | 48 + Core/Core/Helpers/Constants.cs | 2 +- Core/Core/Helpers/Crypt.cs | 3 + Core/Core/Helpers/Http.cs | 14 + Core/Core/Helpers/Path.cs | 2 + Core/Core/Helpers/State.cs | 18 +- Core/Core/Kits/Applications.cs | 96 + .../Kits/ConverterInterfaces/IFinalizable.cs | 9 +- Core/Core/Kits/Exceptions.cs | 30 +- Core/Core/Kits/KitManager.cs | 41 + Core/Core/Kits/Units.cs | 3 + Core/Core/Logging/Analytics.cs | 23 +- Core/Core/Logging/CumulativeTimer.cs | 109 +- Core/Core/Logging/LoggingHelpers.cs | 2 +- Core/Core/Logging/Setup.cs | 2 + Core/Core/Logging/SpeckleException.cs | 10 +- Core/Core/Logging/SpeckleLog.cs | 30 +- .../Logging/SpeckleNonUserFacingException.cs | 8 +- Core/Core/Models/Base.cs | 28 + Core/Core/Models/CommitObjectBuilder.cs | 9 + Core/Core/Models/DynamicBase.cs | 30 + Core/Core/Models/Extensions.cs | 28 + Core/Core/Models/Extras.cs | 68 + .../Models/GraphTraversal/GraphTraversal.cs | 16 + .../Core/Models/GraphTraversal/RuleBuilder.cs | 5 + Core/Core/Models/NestingInstructions.cs | 30 +- Core/Core/Models/Utilities.cs | 51 +- .../Serialisation/BaseObjectDeserializerV2.cs | 54 + .../Serialisation/BaseObjectSerializer.cs | 96 + .../Serialisation/BaseObjectSerializerV2.cs | 82 + .../BaseObjectSerialzerUtilities.cs | 77 +- .../DeserializationWorkerThreads.cs | 10 + Core/Core/Serialisation/OperationTask.cs | 23 +- Core/Core/Serialisation/ValueConverter.cs | 31 +- Core/Core/Transports/Exceptions.cs | 8 +- Core/Core/Transports/Memory.cs | 9 +- Core/Core/Transports/SQLite.cs | 12 + Core/Core/Transports/Server.cs | 32 + .../Transports/ServerUtils/GzipContent.cs | 4 + .../ServerUtils/ParallelServerAPI.cs | 31 + Core/Core/Transports/ServerUtils/ServerAPI.cs | 56 + Core/Core/Transports/ServerV2.cs | 50 + Core/Core/Transports/Utilities.cs | 4 + Core/IntegrationTests/Api.cs | 2 + .../IntegrationTests/Subscriptions/Commits.cs | 2 + Core/Tests/BaseExtensionsTests.cs | 8 +- Core/Tests/ClosureTests.cs | 3 + Core/Tests/GraphQLClient.cs | 3 + Core/Tests/Hashing.cs | 2 + .../Models/ObjectModelDeprecationTests.cs | 2 +- .../Tests/Models/SerializerBreakingChanges.cs | 2 +- .../Models/SerializerNonBreakingChanges.cs | 6 +- Core/Tests/Models/TraversalTests.cs | 2 - Core/Tests/Path.cs | 11 + Core/Tests/SendReceiveLocal.cs | 21 +- Core/Tests/SerializationTests.cs | 12 + Core/Tests/TestKit.cs | 4 + Core/Tests/Transports/DiskTransportTests.cs | 2 +- Core/Tests/Transports/MemoryTransportTests.cs | 2 +- Core/Tests/Transports/SQLiteTransportTests.cs | 2 +- Core/Tests/Transports/TransportTests.cs | 2 +- .../Api/Operations/ReceiveFromSQLite.cs | 2 +- .../Api/Operations/TraverseCommit.cs | 4 +- Core/TestsPerformance/Program.cs | 2 +- Core/TestsPerformance/RegressionTestConfig.cs | 2 +- .../DeserializationWorkerThreads.cs | 2 +- Core/TestsPerformance/TestDataHelper.cs | 2 +- .../Transports/DiskTransport/DiskTransport.cs | 21 +- Core/Transports/MongoDBTransport/MongoDB.cs | 11 + .../AvaloniaHwndHost/AvaloniaHwndHost.cs | 9 + DesktopUI2/DesktopUI2/App.xaml.cs | 2 + DesktopUI2/DesktopUI2/ConnectorHelpers.cs | 10 +- DesktopUI2/DesktopUI2/DummyBindings.cs | 28 + DesktopUI2/DesktopUI2/Models/ConfigManager.cs | 2 + .../Models/Filters/ListSelectionFilter.cs | 3 + .../Filters/SelectionFilterConverter.cs | 12 + .../Models/Filters/TreeSelectionFilter.cs | 5 + .../DesktopUI2/Models/NotificationManager.cs | 12 + .../Models/Settings/SettingsConverter.cs | 14 + DesktopUI2/DesktopUI2/Models/StreamState.cs | 2 + .../Models/TypeMappingOnReceive/HostType.cs | 19 +- .../IHostTypeContainer.cs | 11 +- .../TypeMappingOnReceive/ISingleHostType.cs | 11 +- .../TypeMappingOnReceive/ISingleValueToMap.cs | 15 +- .../Models/TypeMappingOnReceive/ITypeMap.cs | 11 +- .../TypeMappingOnReceive/MappingValue.cs | 63 +- DesktopUI2/DesktopUI2/Utils.cs | 25 + DesktopUI2/DesktopUI2/ViewLocator.cs | 3 + .../DesktopUI2/ViewModels/AccountViewModel.cs | 13 +- .../ViewModels/ApplicationObjectViewModel.cs | 10 + .../ViewModels/CollaboratorsViewModel.cs | 112 +- .../DesktopUI2/ViewModels/CommentViewModel.cs | 11 + .../DesignViewModels/DesignHomeViewModel.cs | 3 + .../DesktopUI2/ViewModels/DialogViewModel.cs | 17 +- .../DesktopUI2/ViewModels/FilterViewModel.cs | 42 +- .../DesktopUI2/ViewModels/HomeViewModel.cs | 86 + .../ImportFamiliesDialogViewModel.cs | 22 + .../DesktopUI2/ViewModels/MainViewModel.cs | 10 + .../MappingTool/MappingsViewModel.cs | 71 +- .../ViewModels/MappingTool/Schemas.cs | 10 + .../ViewModels/MenuItemViewModel.cs | 6 + .../ViewModels/OneClickViewModel.cs | 18 + .../ViewModels/ProgressViewModel.cs | 5 + .../ViewModels/SchedulerViewModel.cs | 6 + .../ViewModels/SettingsPageViewModel.cs | 2 + .../ViewModels/StreamSelectorViewModel.cs | 19 + .../DesktopUI2/ViewModels/StreamViewModel.cs | 180 +- .../TypeMappingOnReceiveViewModel.cs | 155 +- .../AttachedProperties/BlockSelection.cs | 2 + .../StreamEditControls/Receive.xaml.cs | 8 + .../Converters/OpacityDoubleConverter.cs | 3 + .../Views/Converters/OpacityValueConverter.cs | 3 + .../Views/Converters/RoleValueConverter.cs | 6 + .../Converters/StringOpacityValueConverter.cs | 3 + .../Windows/Dialogs/DialogUserControl.cs | 2 + .../Views/Windows/Dialogs/IDialog.cs | 13 +- Directory.Build.props | 8 + .../ConverterAdvanceSteel2023.csproj | 8 +- .../ConverterAdvanceSteel2024.csproj | 8 +- .../ConverterAutocadCivil.ASGeometry.cs | 555 ++-- .../ConverterAutocadCivil.AdvanceSteel.cs | 360 ++- .../ConverterAutocadCivil.Beams.cs | 247 +- .../ConverterAutocadCivil.Bolts.cs | 15 +- .../ConverterAutocadCivil.DxfNames.cs | 26 +- .../ConverterAutocadCivil.Gratings.cs | 15 +- .../ConverterAutocadCivil.Plates.cs | 21 +- .../ConverterAutocadCivil.Slabs.cs | 15 +- .../ConverterAutocadCivil.SpecialParts.cs | 15 +- .../Properties/ASBaseProperties.cs | 73 +- .../Properties/ASPropertiesCache.cs | 133 +- .../AdvanceSteel/Properties/ASProperty.cs | 229 +- .../Properties/ASPropertyMethods.cs | 57 +- .../AdvanceSteel/Properties/ASTypeData.cs | 51 +- .../AdvanceSteel/Properties/IASProperties.cs | 11 +- .../PropertySets/AtomicElementProperties.cs | 223 +- .../Properties/PropertySets/BeamProperties.cs | 219 +- .../PropertySets/BoltPatternProperties.cs | 2 +- .../ConstructionElementProperties.cs | 6 +- .../PropertySets/FilerObjectProperties.cs | 2 +- .../PropertySets/MainAliasProperties.cs | 49 +- .../PropertySets/PolybeamProperties.cs | 29 +- .../ScrewBoltPatternProperties.cs | 2 +- .../AdvanceSteel/Properties/StructureUtils.cs | 10 +- .../Converter.AutocadCivil.Utils.cs | 591 ++-- .../ConverterAutocadCivil.Civil.cs | 1933 +++++------ .../ConverterAutocadCivil.Geometry.cs | 2526 ++++++++------- .../ConverterAutocadCivil.Other.cs | 2454 +++++++------- .../ConverterAutocadCivil.cs | 907 +++--- .../ConverterBentley.Civil.cs | 363 ++- .../ConverterBentley.Geometry.cs | 2825 +++++++++-------- .../ConverterBentley.GridSystems.cs | 543 ++-- .../ConverterBentley.Utils.cs | 340 +- .../ConverterBentley.cs | 601 ++-- .../ConverterMicroStation.csproj | 8 +- .../ConverterOpenBuildings.csproj | 8 +- .../ConverterOpenRail.csproj | 8 +- .../ConverterOpenRoads.csproj | 9 +- .../ConverterCSIShared/AnalysisResultUtils.cs | 136 +- .../ConverterCSIShared/Constants.cs | 43 +- .../ConverterCSI.DatabaseTableUtils.cs | 16 +- .../ConverterCSIShared/ConverterCSI.cs | 747 ++--- .../ConverterCSIShared/ConverterCSIUtils.cs | 585 ++-- .../Extensions/ArcExtensions.cs | 107 +- .../Extensions/CurveExtensions.cs | 13 +- .../Extensions/ICurveExtensions.cs | 31 +- .../Extensions/LineExtensions.cs | 13 +- .../Extensions/PolycurveExtensions.cs | 31 +- .../Models/ApiResultValidator.cs | 41 +- .../Models/DatabaseTableWrapper.cs | 144 +- .../Models/ETABSGridLineDefinitionTable.cs | 443 ++- .../Element1DAnalyticalResultConverter.cs | 525 ++- .../Element2DAnalyticalResultConverter.cs | 378 ++- .../Models/NodeAnalyticalResultsConverter.cs | 351 +- .../Models/ResultsConverter.cs | 331 +- .../PartialClasses/Analysis/ConvertModel.cs | 211 +- .../Analysis/ConvertModelInfo.cs | 97 +- .../Analysis/ConvertModelSettings.cs | 43 +- .../Analysis/ConvertModelUnits.cs | 87 +- .../PartialClasses/Geometry/ConvertArea.cs | 729 +++-- .../PartialClasses/Geometry/ConvertBeam.cs | 13 +- .../PartialClasses/Geometry/ConvertBraces.cs | 13 +- .../Geometry/ConvertBuiltElement.cs | 77 +- .../PartialClasses/Geometry/ConvertColumn.cs | 13 +- .../PartialClasses/Geometry/ConvertFloor.cs | 13 +- .../PartialClasses/Geometry/ConvertFrame.cs | 672 ++-- .../Geometry/ConvertGridLines.cs | 131 +- .../PartialClasses/Geometry/ConvertLine.cs | 49 +- .../PartialClasses/Geometry/ConvertLinks.cs | 138 +- .../PartialClasses/Geometry/ConvertPier.cs | 67 +- .../PartialClasses/Geometry/ConvertPoint.cs | 291 +- .../Geometry/ConvertSpandrel.cs | 137 +- .../PartialClasses/Geometry/ConvertStories.cs | 165 +- .../PartialClasses/Geometry/ConvertTendon.cs | 57 +- .../PartialClasses/Geometry/ConvertWall.cs | 13 +- .../Loading/ConvertLoadCombination.cs | 91 +- .../Loading/ConvertLoadPattern.cs | 197 +- .../Loading/Loading1DElements.cs | 747 ++--- .../Loading/Loading2DElements.cs | 385 +-- .../PartialClasses/Loading/LoadingNode.cs | 219 +- .../Materials/ConvertMaterials.cs | 617 ++-- .../Properties/Convert1DProperty.cs | 289 +- .../Properties/Convert2DProperty.cs | 83 +- .../Properties/Convert2DPropertyFloor.cs | 673 ++-- .../Properties/Convert2DPropertyWall.cs | 67 +- .../Properties/ConvertDiaphragm.cs | 35 +- .../Properties/ConvertLinkProperty.cs | 78 +- .../Properties/ConvertSectionProfile.cs | 549 ++-- .../Properties/ConvertSpring.cs | 501 ++- .../Properties/ConvertTendonProperty.cs | 47 +- .../Results/ConvertResultGlobal.cs | 133 +- .../PartialClasses/Results/ConvertResults.cs | 46 +- .../Services/ToNativeScalingService.cs | 45 +- .../ConverterDxf.Tests/ConverterFixture.cs | 48 +- .../ConverterDxf.Tests/ConverterSetup.cs | 31 +- .../ConverterDxf.Tests/Geometry/BrepTests.cs | 49 +- .../ConverterDxf.Tests/Geometry/CurveTests.cs | 26 +- .../ConverterDxf.Tests/Geometry/MeshTests.cs | 47 +- .../Geometry/VectorTests.cs | 48 +- .../ConverterDxf/ConverterDxfSettings.cs | 13 +- .../SpeckleDxfConverter.Document.cs | 68 +- .../SpeckleDxfConverter.Geometry.cs | 151 +- .../SpeckleDxfConverter.Settings.cs | 19 +- .../ConverterDxf/SpeckleDxfConverter.Units.cs | 115 +- .../ConverterDxf/SpeckleDxfConverter.cs | 104 +- .../ConverterDxf/ConverterDxf/Utilities.cs | 99 +- .../ConverterDynamo.Geometry.cs | 1554 ++++----- .../ConverterDynamo.Units.cs | 182 +- .../ConverterDynamoShared/ConverterDynamo.cs | 351 +- .../ConverterDynamoShared/Utils.cs | 399 +-- .../ConverterNavisworks.Geometry.cs | 47 +- .../ConverterNavisworks.Other.cs | 6 +- .../ConverterNavisworks.Properties.cs | 25 + .../ConverterNavisworks.Settings.cs | 14 +- .../ConverterNavisworks.ToSpeckle.cs | 27 +- .../ConverterNavisworks.Types.cs | 4 +- .../ConverterNavisworks.Utilities.cs | 2 +- .../ConverterNavisworks.cs | 16 +- .../AllRevitCategories.cs | 267 +- .../ConverterRevitShared/Categories.cs | 80 +- .../ConverterRevitShared/ConversionUtils.cs | 2098 ++++++------ .../ConverterRevit.DxfImport.cs | 366 +-- .../ConverterRevit.MeshBuildHelper.cs | 94 +- .../ConverterRevit.Previews.cs | 52 +- .../ConverterRevit.SettingsHelpers.cs | 75 +- .../ConverterRevitShared/ConverterRevit.cs | 1437 +++++---- .../ConverterRevitShared.projitems | 126 +- .../DirectContext3DServer.cs | 759 +++-- .../Extensions/CategoryExtensions.cs | 13 +- .../Extensions/ConnectorExtensions.cs | 11 +- .../Extensions/DefinitionExtensions.cs | 33 +- .../Extensions/DisplayUnitTypeExtensions.cs | 27 +- .../Extensions/ElementExtensions.cs | 37 +- .../Extensions/ForgeTypeIdExtensions.cs | 30 +- .../Extensions/ParameterExtensions.cs | 84 +- .../Extensions/PointExtensions.cs | 23 +- .../Models/Element2DOutlineBuilder.cs | 375 +-- .../Models/ParameterToSpeckleData.cs | 57 +- .../ConvertAdaptiveComponent.cs | 130 - .../Partial Classes/ConvertAnalyticalNode.cs | 204 -- .../Partial Classes/ConvertAnalyticalStick.cs | 713 ----- .../ConvertAnalyticalSurface.cs | 410 --- .../Partial Classes/ConvertArea.cs | 66 - .../Partial Classes/ConvertBeam.cs | 159 - .../Partial Classes/ConvertBrace.cs | 62 - .../Partial Classes/ConvertBuildingPad.cs | 32 - .../Partial Classes/ConvertCableTray.cs | 102 - .../Partial Classes/ConvertCeiling.cs | 115 - .../Partial Classes/ConvertColumn.cs | 299 -- .../ConvertCombinableElement.cs | 76 - .../Partial Classes/ConvertConduit.cs | 103 - .../Partial Classes/ConvertConnector.cs | 47 - .../Partial Classes/ConvertCurves.cs | 363 --- .../Partial Classes/ConvertDirectShape.cs | 252 -- .../ConvertDirectTeklaMeshElements.cs | 17 - .../Partial Classes/ConvertDuct.cs | 204 -- .../Partial Classes/ConvertFabricationPart.cs | 20 - .../Partial Classes/ConvertFaceWall.cs | 230 -- .../Partial Classes/ConvertFamilyInstance.cs | 877 ----- .../Partial Classes/ConvertFitting.cs | 167 - .../Partial Classes/ConvertFloor.cs | 481 --- .../Partial Classes/ConvertFreeformElement.cs | 258 -- .../Partial Classes/ConvertGeometry.cs | 1376 -------- .../Partial Classes/ConvertGridLine.cs | 111 - .../Partial Classes/ConvertGroup.cs | 50 - .../Partial Classes/ConvertLevel.cs | 242 -- .../Partial Classes/ConvertLocation.cs | 110 - .../ConvertMEPFamilyInstance.cs | 124 - .../Partial Classes/ConvertMaterial.cs | 39 - .../ConvertMaterialQuantities.cs | 162 - .../Partial Classes/ConvertMeshUtils.cs | 352 -- .../Partial Classes/ConvertModel.cs | 72 - .../Partial Classes/ConvertNetwork.cs | 489 --- .../Partial Classes/ConvertOpening.cs | 186 -- .../Partial Classes/ConvertPanel.cs | 27 - .../Partial Classes/ConvertPipe.cs | 236 -- .../Partial Classes/ConvertPolygonElement.cs | 45 - .../Partial Classes/ConvertProfileWall.cs | 76 - .../Partial Classes/ConvertProjectInfo.cs | 35 - .../Partial Classes/ConvertRailing.cs | 146 - .../Partial Classes/ConvertRebar.cs | 345 -- .../Partial Classes/ConvertRevitElement.cs | 99 - .../Partial Classes/ConvertRoof.cs | 485 --- .../Partial Classes/ConvertRoom.cs | 88 - .../Partial Classes/ConvertSpace.cs | 282 -- .../Partial Classes/ConvertStair.cs | 94 - .../ConvertStructuralConnectionHandlers.cs | 73 - .../Partial Classes/ConvertStructuralModel.cs | 73 - .../Partial Classes/ConvertTeklaObjects.cs | 33 - .../Partial Classes/ConvertTopRail.cs | 26 - .../Partial Classes/ConvertTopography.cs | 63 - .../Partial Classes/ConvertToposolid.cs | 109 - .../Partial Classes/ConvertView.Schedule.cs | 575 ---- .../Partial Classes/ConvertView.cs | 246 -- .../Partial Classes/ConvertWall.cs | 345 -- .../Partial Classes/ConvertWire.cs | 147 - .../Partial Classes/ConvertZone.cs | 185 -- .../Partial Classes/Units.cs | 258 -- .../Partial Classes/UpdateParameter.cs | 55 - .../ConvertAdaptiveComponent.cs | 139 + .../PartialClasses/ConvertAnalyticalNode.cs | 245 ++ .../PartialClasses/ConvertAnalyticalStick.cs | 786 +++++ .../ConvertAnalyticalSurface.cs | 436 +++ .../PartialClasses/ConvertArea.cs | 70 + .../PartialClasses/ConvertBeam.cs | 165 + .../ConvertBlock.cs | 25 + .../PartialClasses/ConvertBrace.cs | 63 + .../PartialClasses/ConvertBuildingPad.cs | 32 + .../PartialClasses/ConvertCableTray.cs | 137 + .../PartialClasses/ConvertCeiling.cs | 143 + .../PartialClasses/ConvertColumn.cs | 316 ++ .../ConvertCombinableElement.cs | 77 + .../PartialClasses/ConvertConduit.cs | 120 + .../PartialClasses/ConvertConnector.cs | 46 + .../PartialClasses/ConvertCurves.cs | 426 +++ .../PartialClasses/ConvertDirectShape.cs | 288 ++ .../ConvertDirectTeklaMeshElements.cs | 17 + .../ConvertDisplayableObject.cs | 3 +- .../PartialClasses/ConvertDuct.cs | 259 ++ .../PartialClasses/ConvertFabricationPart.cs | 19 + .../PartialClasses/ConvertFaceWall.cs | 260 ++ .../PartialClasses/ConvertFamilyInstance.cs | 937 ++++++ .../PartialClasses/ConvertFitting.cs | 210 ++ .../PartialClasses/ConvertFloor.cs | 498 +++ .../PartialClasses/ConvertFreeformElement.cs | 298 ++ .../PartialClasses/ConvertGeometry.cs | 1437 +++++++++ .../PartialClasses/ConvertGridLine.cs | 140 + .../PartialClasses/ConvertGroup.cs | 54 + .../PartialClasses/ConvertLevel.cs | 298 ++ .../PartialClasses/ConvertLocation.cs | 111 + .../ConvertMEPFamilyInstance.cs | 125 + .../PartialClasses/ConvertMaterial.cs | 45 + .../ConvertMaterialQuantities.cs | 157 + .../PartialClasses/ConvertMeshUtils.cs | 380 +++ .../PartialClasses/ConvertModel.cs | 71 + .../PartialClasses/ConvertNetwork.cs | 623 ++++ .../PartialClasses/ConvertOpening.cs | 220 ++ .../PartialClasses/ConvertPanel.cs | 26 + .../PartialClasses/ConvertPipe.cs | 287 ++ .../PartialClasses/ConvertPolygonElement.cs | 41 + .../PartialClasses/ConvertProfileWall.cs | 89 + .../PartialClasses/ConvertProjectInfo.cs | 33 + .../PartialClasses/ConvertRailing.cs | 152 + .../PartialClasses/ConvertRebar.cs | 344 ++ .../PartialClasses/ConvertRevitElement.cs | 110 + .../PartialClasses/ConvertRoof.cs | 532 ++++ .../PartialClasses/ConvertRoom.cs | 92 + .../PartialClasses/ConvertSpace.cs | 292 ++ .../PartialClasses/ConvertStair.cs | 105 + .../ConvertStructuralConnectionHandlers.cs | 78 + .../PartialClasses/ConvertStructuralModel.cs | 73 + .../PartialClasses/ConvertTeklaObjects.cs | 38 + .../PartialClasses/ConvertTopRail.cs | 25 + .../PartialClasses/ConvertTopography.cs | 80 + .../PartialClasses/ConvertToposolid.cs | 112 + .../PartialClasses/ConvertView.Schedule.cs | 579 ++++ .../PartialClasses/ConvertView.cs | 279 ++ .../PartialClasses/ConvertWall.cs | 371 +++ .../PartialClasses/ConvertWire.cs | 167 + .../PartialClasses/ConvertZone.cs | 191 ++ .../DirectShape.cs | 98 +- .../PartialClasses/Units.cs | 270 ++ .../PartialClasses/UpdateParameter.cs | 54 + .../Revit/ConnectionPair.cs | 150 +- .../Revit/FamilyLoadOptions.cs | 33 +- .../RevitCommitObjectBuilder.cs | 5 + .../RevitCommitObjectBuilderExposer.cs | 10 +- .../RevitElementTypeUtils.cs | 312 +- .../RevitVersionHelper.cs | 245 +- .../ConverterRevitTestsShared/AssertUtils.cs | 529 +-- .../ConverterRevitTestsShared/BrepTests.cs | 128 +- .../ConverterRevitTestsShared/Globals.cs | 77 +- .../SpeckleConversionFixture.cs | 132 +- .../SpeckleConversionTest.cs | 479 +-- .../ConverterRevitTestsShared/SpeckleUtils.cs | 275 +- .../TestCategories.cs | 148 +- .../xUnitRevitUtils.cs | 4 +- .../TestGenerator/Categories.cs | 149 +- .../TestGenerator/Generator.cs | 196 +- .../TestGenerator/Globals.cs | 46 +- .../TestGenerator/TestTemplate.cs | 53 +- .../ConverterRhinoGhShared/BrepEncoder.cs | 22 +- .../ConverterRhinoGh.BuiltElements.cs | 17 + .../ConverterRhinoGh.Geometry.cs | 106 +- .../ConverterRhinoGh.Mappings.cs | 23 + .../ConverterRhinoGh.Organization.cs | 12 + .../ConverterRhinoGh.Other.cs | 138 + .../ConverterRhinoGh.Structural.cs | 2 +- .../ConverterRhinoGh.Utils.cs | 20 + .../ConverterRhinoGh.cs | 49 + .../ConverterRhinoGhShared/KnotListEncoder.cs | 30 +- .../ConverterTeklaStructureUtils.cs | 976 +++--- .../ConverterTeklaStructures.cs | 407 +-- .../ConverterTeklaStructuresShared.projitems | 28 +- .../Partial Classes/ConvertBeam.cs | 269 -- .../Partial Classes/ConvertBentPlate.cs | 10 - .../Partial Classes/ConvertBolts.cs | 163 - .../Partial Classes/ConvertBooleanPart.cs | 89 - .../Partial Classes/ConvertContourPlate.cs | 131 - .../Partial Classes/ConvertDirectShapeMesh.cs | 173 - .../Partial Classes/ConvertFitting.cs | 50 - .../Partial Classes/ConvertLoftedPlates.cs | 10 - .../Partial Classes/ConvertModel.cs | 10 - .../Partial Classes/ConvertPolyBeam.cs | 57 - .../Partial Classes/ConvertPolygonWelds.cs | 42 - .../Partial Classes/ConvertRebar.cs | 86 - .../Partial Classes/ConvertSpiralBeam.cs | 70 - .../Partial Classes/ConvertWelds.cs | 92 - .../PartialClasses/ConvertBeam.cs | 282 ++ .../PartialClasses/ConvertBentPlate.cs | 7 + .../PartialClasses/ConvertBolts.cs | 166 + .../PartialClasses/ConvertBooleanPart.cs | 95 + .../PartialClasses/ConvertContourPlate.cs | 133 + .../PartialClasses/ConvertDirectShapeMesh.cs | 180 ++ .../PartialClasses/ConvertFitting.cs | 50 + .../PartialClasses/ConvertLoftedPlates.cs | 7 + .../PartialClasses/ConvertModel.cs | 7 + .../ConvertPoint.cs | 4 +- .../PartialClasses/ConvertPolyBeam.cs | 55 + .../PartialClasses/ConvertPolygonWelds.cs | 41 + .../PartialClasses/ConvertRebar.cs | 83 + .../PartialClasses/ConvertSpiralBeam.cs | 76 + .../PartialClasses/ConvertWelds.cs | 93 + .../PolygonMesher/ClosedLoop.cs | 146 +- .../PolygonMesher/Extensions.cs | 339 +- .../PolygonMesher/IndexPair.cs | 24 +- .../PolygonMesher/IndexSet.cs | 33 +- .../PolygonMesher/PolygonMesher.cs | 561 ++-- .../PolygonMesher/TriangleIndexSet.cs | 14 +- .../PolygonMesher/Vertex.cs | 35 +- .../BuiltElements/AdvanceSteel/AsteelBolt.cs | 15 +- .../AdvanceSteel/AsteelGrating.cs | 5 +- .../BuiltElements/AdvanceSteel/AsteelPlate.cs | 5 +- .../AdvanceSteel/AsteelPolyBeam.cs | 5 +- .../BuiltElements/AdvanceSteel/AsteelSlab.cs | 5 +- .../AdvanceSteel/AsteelSpecialPart.cs | 5 +- .../AdvanceSteel/AsteelStraightBeam.cs | 5 +- .../BuiltElements/Archicad/Classification.cs | 29 +- Objects/Objects/BuiltElements/Level.cs | 2 +- Objects/Objects/BuiltElements/Network.cs | 8 +- Objects/Objects/BuiltElements/Opening.cs | 9 + .../BuiltElements/Revit/FreeformElement.cs | 15 + .../Revit/Interfaces/IHasMEPConnectors.cs | 9 +- .../BuiltElements/Revit/MEPFamilyInstance.cs | 15 +- .../Revit/RevitCurtainWallPanel.cs | 9 +- .../BuiltElements/Revit/RevitMEPConnector.cs | 23 +- .../BuiltElements/Revit/RevitToposolid.cs | 66 +- Objects/Objects/BuiltElements/Wall.cs | 5 + Objects/Objects/BuiltElements/Zone.cs | 6 +- Objects/Objects/GIS/GisTopography.cs | 25 +- Objects/Objects/GIS/PolygonElement.cs | 13 +- Objects/Objects/Geometry/Arc.cs | 16 + Objects/Objects/Geometry/Brep.cs | 48 + Objects/Objects/Geometry/Curve.cs | 10 + Objects/Objects/Geometry/Line.cs | 6 + Objects/Objects/Geometry/Mesh.cs | 14 + Objects/Objects/Geometry/Point.cs | 9 + Objects/Objects/Geometry/Pointcloud.cs | 5 + Objects/Objects/Geometry/Polycurve.cs | 2 + Objects/Objects/Geometry/Polyline.cs | 8 + .../Objects/Geometry/PolylineExtensions.cs | 27 +- Objects/Objects/Geometry/Surface.cs | 4 + Objects/Objects/Geometry/Vector.cs | 2 +- Objects/Objects/ObjectsKit.cs | 18 +- Objects/Objects/Organization/DataTable.cs | 58 +- .../Organization/Deprecated/Collection.cs | 2 +- Objects/Objects/Other/Instance.cs | 14 +- Objects/Objects/Other/MappedBlockWrapper.cs | 2 +- Objects/Objects/Other/Transform.cs | 14 + .../ETABS/Geometry/CSIElement1D.cs | 1 + .../ETABS/Geometry/CSIElement2D.cs | 1 + .../ETABS/Geometry/CSINode.cs | 1 + .../GSA/Analysis/GSAAnalysisCase.cs | 3 + .../GSA/Loading/GSALoadCombination.cs | 2 + .../Objects/Structural/Geometry/Restraint.cs | 11 + .../Structural/Loading/LoadCombination.cs | 2 + .../Structural/Results/AnalyticalResults.cs | 16 +- .../Objects/Utils/EncodingOptimisations.cs | 5 + .../Objects/Utils/MeshTriangulationHelper.cs | 7 + Objects/Objects/Utils/Parameters.cs | 5 + 852 files changed, 60133 insertions(+), 50614 deletions(-) delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAdaptiveComponent.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalNode.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalStick.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalSurface.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertArea.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBeam.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBrace.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBuildingPad.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCableTray.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCeiling.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertColumn.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCombinableElement.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConduit.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConnector.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCurves.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectShape.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectTeklaMeshElements.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDuct.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFabricationPart.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFaceWall.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFamilyInstance.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFitting.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFloor.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFreeformElement.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGeometry.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGridLine.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGroup.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLevel.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLocation.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMEPFamilyInstance.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterial.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMeshUtils.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertModel.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertNetwork.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertOpening.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPanel.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPipe.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPolygonElement.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProfileWall.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProjectInfo.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRailing.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRebar.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRevitElement.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoof.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoom.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertSpace.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStair.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralConnectionHandlers.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralModel.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTeklaObjects.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopRail.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopography.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertToposolid.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.Schedule.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWall.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWire.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertZone.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/Units.cs delete mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/UpdateParameter.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAdaptiveComponent.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalNode.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalStick.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalSurface.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertArea.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBeam.cs rename Objects/Converters/ConverterRevit/ConverterRevitShared/{Partial Classes => PartialClasses}/ConvertBlock.cs (99%) create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBuildingPad.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCableTray.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCeiling.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCombinableElement.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConduit.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConnector.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCurves.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectShape.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectTeklaMeshElements.cs rename Objects/Converters/ConverterRevit/ConverterRevitShared/{Partial Classes => PartialClasses}/ConvertDisplayableObject.cs (99%) create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDuct.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFabricationPart.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFaceWall.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFamilyInstance.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFitting.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFloor.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFreeformElement.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGeometry.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGridLine.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGroup.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLevel.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLocation.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMEPFamilyInstance.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterial.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterialQuantities.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMeshUtils.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertModel.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertNetwork.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertOpening.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPanel.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPipe.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPolygonElement.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProfileWall.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProjectInfo.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRailing.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRebar.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRevitElement.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoof.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoom.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertSpace.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStair.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralConnectionHandlers.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralModel.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTeklaObjects.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopRail.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopography.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertToposolid.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.Schedule.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWire.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertZone.cs rename Objects/Converters/ConverterRevit/ConverterRevitShared/{Partial Classes => PartialClasses}/DirectShape.cs (52%) create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/Units.cs create mode 100644 Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/UpdateParameter.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBeam.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBentPlate.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBolts.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBooleanPart.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertContourPlate.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertDirectShapeMesh.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertFitting.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertLoftedPlates.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertModel.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolyBeam.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolygonWelds.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertRebar.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertSpiralBeam.cs delete mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertWelds.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBentPlate.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBolts.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBooleanPart.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertContourPlate.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertDirectShapeMesh.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertFitting.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertLoftedPlates.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertModel.cs rename Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/{Partial Classes => PartialClasses}/ConvertPoint.cs (81%) create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolyBeam.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolygonWelds.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertRebar.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertSpiralBeam.cs create mode 100644 Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertWelds.cs diff --git a/.circleci/scripts/config-template.yml b/.circleci/scripts/config-template.yml index d02df9246f..1cf8ab1e64 100644 --- a/.circleci/scripts/config-template.yml +++ b/.circleci/scripts/config-template.yml @@ -78,6 +78,7 @@ commands: name: << parameters.title >> command: $HOME/.dotnet/dotnet test << parameters.project >> -c Release + -p:IsDesktopBuild=false --logger:"junit;LogFileName={assembly}.results.xml" --results-directory=TestResults --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover @@ -93,6 +94,11 @@ jobs: # Each project will have individual jobs for each specific task it has to command: | curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel Current $HOME/.dotnet/dotnet --version + - run: + name: Enforce formatting + command: | + $HOME/.dotnet/dotnet tool restore + $HOME/.dotnet/dotnet csharpier --check . - run: name: Build SDK Projects command: | diff --git a/.editorconfig b/.editorconfig index d6bd60f766..607ace1242 100644 --- a/.editorconfig +++ b/.editorconfig @@ -81,7 +81,7 @@ csharp_style_var_for_built_in_types = false:none csharp_style_var_when_type_is_apparent = false:none # Prefer method-like constructs to have a block body -csharp_style_expression_bodied_methods = false:suggestion +csharp_style_expression_bodied_methods = true:suggestion csharp_style_expression_bodied_constructors = false:suggestion csharp_style_expression_bodied_operators = true:suggestion @@ -212,6 +212,7 @@ dotnet_diagnostic.ide0046.severity = suggestion # Use conditional expression for dotnet_diagnostic.ide0078.severity = suggestion # Use pattern matching: Subjective dotnet_diagnostic.ide0260.severity = suggestion # Use pattern matching: Subjective dotnet_diagnostic.ide0058.severity = suggestion # Remove unnecessary expression value: Subjective +dotnet_diagnostic.ide0022.severity = suggestion # Use expression body for method: Subjective # Maintainability rules dotnet_diagnostic.ca1501.severity = warning # Avoid excessive inheritance diff --git a/All.sln.DotSettings b/All.sln.DotSettings index 1f8dbe0f40..b2c1dde104 100644 --- a/All.sln.DotSettings +++ b/All.sln.DotSettings @@ -412,7 +412,7 @@ HINT HINT SUGGESTION - HINT + DO_NOT_SHOW SUGGESTION SUGGESTION SUGGESTION diff --git a/Automate/Speckle.Automate.Sdk/AutomationContext.cs b/Automate/Speckle.Automate.Sdk/AutomationContext.cs index d3038244ab..0ce6eceaaf 100644 --- a/Automate/Speckle.Automate.Sdk/AutomationContext.cs +++ b/Automate/Speckle.Automate.Sdk/AutomationContext.cs @@ -77,7 +77,10 @@ public async Task ReceiveVersion() .Receive(commit.referencedObject, serverTransport, memoryTransport) .ConfigureAwait(false); if (commitRootObject == null) + { throw new Exception("Commit root object was null"); + } + Console.WriteLine( $"It took {Elapsed.TotalSeconds} seconds to receive the speckle version {AutomationRunData.VersionId}" ); @@ -87,10 +90,13 @@ public async Task ReceiveVersion() public async Task CreateNewVersionInProject(Base rootObject, string branchName, string versionMessage = "") { if (branchName == AutomationRunData.BranchName) + { throw new ArgumentException( $"The target model: {branchName} cannot match the model that triggered this automation: {AutomationRunData.ModelId}/{AutomationRunData.BranchName}", nameof(branchName) ); + } + var rootObjectId = await Operations .Send(rootObject, new List { serverTransport, memoryTransport }, useDefaultCache: false) .ConfigureAwait(false); @@ -121,11 +127,19 @@ public void SetContextView(List? resourceIds = null, bool includeSourceM { var linkResources = new List(); if (includeSourceModelVersion) + { linkResources.Add($@"{AutomationRunData.ModelId}@{AutomationRunData.VersionId}"); + } + if (resourceIds is not null) + { linkResources.AddRange(resourceIds); + } + if (linkResources.Count == 0) + { throw new Exception("We do not have enough resource ids to compose a context view"); + } AutomationResult.ResultView = $"/projects/{AutomationRunData.ProjectId}/models/{string.Join(",", linkResources)}"; } @@ -204,7 +218,10 @@ mutation ReportFunctionRunStatus( public async Task StoreFileResult(string filePath) { if (!File.Exists(filePath)) + { throw new FileNotFoundException("The given file path doesn't exist", fileName: filePath); + } + using var formData = new MultipartFormDataContent(); var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); @@ -221,7 +238,10 @@ public async Task StoreFileResult(string filePath) Console.WriteLine("RESPONSE - " + responseString); var uploadResponse = JsonConvert.DeserializeObject(responseString); if (uploadResponse.UploadResults.Count != 1) + { throw new Exception("Expected one upload result."); + } + AutomationResult.Blobs.AddRange(uploadResponse.UploadResults.Select(r => r.BlobId)); } @@ -235,7 +255,10 @@ private void _markRun(AutomationStatus status, string? statusMessage) var msg = $"Automation run {statusValue} after {duration} seconds."; if (statusMessage is not null) + { msg += $"\n{statusMessage}"; + } + Console.WriteLine(msg); } diff --git a/Automate/Speckle.Automate.Sdk/Runner.cs b/Automate/Speckle.Automate.Sdk/Runner.cs index 45adb74fa0..275749821c 100644 --- a/Automate/Speckle.Automate.Sdk/Runner.cs +++ b/Automate/Speckle.Automate.Sdk/Runner.cs @@ -27,9 +27,11 @@ TInput inputs { await automateFunction(automationContext, inputs).ConfigureAwait(false); if (automationContext.RunStatus is not ("FAILED" or "SUCCEEDED")) + { automationContext.MarkRunSuccess( "WARNING: Automate assumed a success status, but it was not marked as so by the function." ); + } } catch (Exception ex) { @@ -39,8 +41,10 @@ TInput inputs finally { if (automationContext.ContextView is null) + { automationContext.SetContextView(); - + } + await automationContext.ReportRunStatus().ConfigureAwait(false); } return automationContext; @@ -116,7 +120,9 @@ public static async Task Main(string[] args, Func? Execute(Commands.ICommand command) + where TResult : class + { + return Execute(command, CancellationToken.None); + } - public static Task? Execute(Commands.ICommand command) - where TResult : class + public static Task? Execute(Commands.ICommand command, CancellationToken token) + where TResult : class + { + try { - return Execute(command, CancellationToken.None); + return Task.Run(command.Execute, token); } - - public static Task? Execute(Commands.ICommand command, CancellationToken token) - where TResult : class + catch (Exception e) { - try - { - return Task.Run(command.Execute, token); - } - catch (Exception e) - { - return null; - } + return null; } - - #endregion } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/CommandRequest.cs b/ConnectorArchicad/ConnectorArchicad/Communication/CommandRequest.cs index ff2a5d9d46..2ad393d0c4 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/CommandRequest.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/CommandRequest.cs @@ -1,78 +1,78 @@ -using Speckle.Newtonsoft.Json; +using Speckle.Newtonsoft.Json; -namespace Archicad.Communication +namespace Archicad.Communication; + +[JsonObject(MemberSerialization.OptIn)] +internal sealed class AddOnCommandRequest + where T : class { + #region --- Classes --- + [JsonObject(MemberSerialization.OptIn)] - internal sealed class AddOnCommandRequest where T : class + private sealed class AddonCommandID { - #region --- Classes --- - - [JsonObject(MemberSerialization.OptIn)] - private sealed class AddonCommandID - { - #region --- Fields --- - - [JsonProperty("commandName")] - public string CommandName { get; private set; } + #region --- Fields --- - [JsonProperty("commandNamespace")] - public string CommandNamespace { get; } = "Speckle"; + [JsonProperty("commandName")] + public string CommandName { get; private set; } - #endregion + [JsonProperty("commandNamespace")] + public string CommandNamespace { get; } = "Speckle"; - #region --- Ctor \ Dtor --- + #endregion - public AddonCommandID(string commandName) - { - CommandName = commandName; - } + #region --- Ctor \ Dtor --- - #endregion + public AddonCommandID(string commandName) + { + CommandName = commandName; } - [JsonObject(MemberSerialization.OptIn)] - private sealed class AddonCommandParameters - { - #region --- Fields --- + #endregion + } - [JsonProperty("addOnCommandId")] - private AddonCommandID Id { get; set; } + [JsonObject(MemberSerialization.OptIn)] + private sealed class AddonCommandParameters + { + #region --- Fields --- - [JsonProperty("addOnCommandParameters")] - private T Parameters { get; set; } + [JsonProperty("addOnCommandId")] + private AddonCommandID Id { get; set; } - #endregion + [JsonProperty("addOnCommandParameters")] + private T Parameters { get; set; } - #region --- Ctor \ Dtor --- + #endregion - public AddonCommandParameters(string commandName, T parameters) - { - Id = new AddonCommandID(commandName); - Parameters = parameters; - } + #region --- Ctor \ Dtor --- - #endregion + public AddonCommandParameters(string commandName, T parameters) + { + Id = new AddonCommandID(commandName); + Parameters = parameters; } #endregion + } - #region --- Fields --- + #endregion - [JsonProperty("command")] - private string Command { get; } = "API.ExecuteAddOnCommand"; + #region --- Fields --- - [JsonProperty("parameters")] - private AddonCommandParameters Parameters { get; set; } + [JsonProperty("command")] + private string Command { get; } = "API.ExecuteAddOnCommand"; - #endregion + [JsonProperty("parameters")] + private AddonCommandParameters Parameters { get; set; } - #region --- Ctor \ Dtor --- + #endregion - public AddOnCommandRequest(string commandName, T requestParams) - { - Parameters = new AddonCommandParameters(commandName, requestParams); - } + #region --- Ctor \ Dtor --- - #endregion + public AddOnCommandRequest(string commandName, T requestParams) + { + Parameters = new AddonCommandParameters(commandName, requestParams); } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/CommandResponse.cs b/ConnectorArchicad/ConnectorArchicad/Communication/CommandResponse.cs index 2c758d7e0b..1dffed50bd 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/CommandResponse.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/CommandResponse.cs @@ -1,42 +1,42 @@ -using Speckle.Newtonsoft.Json; +using Speckle.Newtonsoft.Json; -namespace Archicad.Communication +namespace Archicad.Communication; + +[JsonObject(MemberSerialization.OptIn)] +internal sealed class AddOnCommandResponse + where T : class { + #region --- Classes --- + [JsonObject(MemberSerialization.OptIn)] - internal sealed class AddOnCommandResponse where T : class + private sealed class AddOnCommandResult { - #region --- Classes --- - - [JsonObject(MemberSerialization.OptIn)] - private sealed class AddOnCommandResult - { - #region --- Fields --- - - [JsonProperty("addOnCommandResponse")] - public T Response { get; private set; } + #region --- Fields --- - #endregion - } + [JsonProperty("addOnCommandResponse")] + public T Response { get; private set; } #endregion + } - #region --- Fields --- + #endregion - [JsonProperty("succeeded")] - public bool Succeeded { get; private set; } + #region --- Fields --- - [JsonProperty("result")] - private AddOnCommandResult Response { get; set; } + [JsonProperty("succeeded")] + public bool Succeeded { get; private set; } - #endregion + [JsonProperty("result")] + private AddOnCommandResult Response { get; set; } - #region --- Properties --- + #endregion - public T Result - { - get { return Response?.Response; } - } + #region --- Properties --- - #endregion + public T Result + { + get { return Response?.Response; } } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateBeam.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateBeam.cs index 153fafbbe0..a63103cfd6 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateBeam.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateBeam.cs @@ -4,46 +4,45 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateBeam : ICommand> { - sealed internal class CreateBeam : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("beams")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("beams")] private IEnumerable Datas { get; } - public CreateBeam(IEnumerable datas) + public Parameters(IEnumerable datas) { - foreach (var data in datas) - { - data.displayValue = null; - data.baseLine = null; - } - Datas = datas; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateBeam(IEnumerable datas) + { + foreach (var data in datas) { - var result = await HttpCommandExecutor.Execute("CreateBeam", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; + data.displayValue = null; + data.baseLine = null; } + + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateBeam", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateColumn.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateColumn.cs index 9413f65685..ceee938fa1 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateColumn.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateColumn.cs @@ -4,46 +4,45 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateColumn : ICommand> { - sealed internal class CreateColumn : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("columns")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("columns")] private IEnumerable Datas { get; } - public CreateColumn(IEnumerable datas) + public Parameters(IEnumerable datas) { - foreach (var data in datas) - { - data.displayValue = null; - data.baseLine = null; - } - Datas = datas; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateColumn(IEnumerable datas) + { + foreach (var data in datas) { - var result = await HttpCommandExecutor.Execute("CreateColumn", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; + data.displayValue = null; + data.baseLine = null; } + + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateColumn", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDirectShape.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDirectShape.cs index 855fc747ae..ab416a5ebf 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDirectShape.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDirectShape.cs @@ -4,48 +4,47 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateDirectShape : ICommand> { - sealed internal class CreateDirectShape : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("directShapes")] - private IEnumerable DirectShapes { get; } - - public Parameters(IEnumerable directShapes) - { - DirectShapes = directShapes; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("directShapes")] private IEnumerable DirectShapes { get; } - public CreateDirectShape(IEnumerable directShapes) + public Parameters(IEnumerable directShapes) { - foreach (var directShape in directShapes) - { - directShape.displayValue = null; - } - DirectShapes = directShapes; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable DirectShapes { get; } + + public CreateDirectShape(IEnumerable directShapes) + { + foreach (var directShape in directShapes) { - var result = await HttpCommandExecutor.Execute( - "CreateDirectShape", - new Parameters(DirectShapes) - ); - return result == null ? null : result.ApplicationObjects; + directShape.displayValue = null; } + + DirectShapes = directShapes; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute( + "CreateDirectShape", + new Parameters(DirectShapes) + ); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDoor.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDoor.cs index 839678c645..7388404de6 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDoor.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateDoor.cs @@ -4,40 +4,39 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateDoor : ICommand> { - sealed internal class CreateDoor : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("subElements")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("subElements")] private IEnumerable Datas { get; } - public CreateDoor(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("CreateDoor", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateDoor(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateDoor", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateFloor.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateFloor.cs index 9abfd5571b..ddba97fb14 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateFloor.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateFloor.cs @@ -4,40 +4,39 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateFloor : ICommand> { - sealed internal class CreateFloor : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("slabs")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("slabs")] private IEnumerable Datas { get; } - public CreateFloor(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute("CreateSlab", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateFloor(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute("CreateSlab", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateGridElement.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateGridElement.cs index 3f560de448..3b28dd3efc 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateGridElement.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateGridElement.cs @@ -3,40 +3,39 @@ using Speckle.Core.Models; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateGridElement : ICommand> { - sealed internal class CreateGridElement : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("gridElements")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("gridElements")] private IEnumerable Datas { get; } - public CreateGridElement(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("CreateGridElement", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateGridElement(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateGridElement", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateObject.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateObject.cs index 291f2434ee..fd17b2586c 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateObject.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateObject.cs @@ -5,46 +5,48 @@ using Objects.BuiltElements.Archicad; using Archicad.Model; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateObject : ICommand> { - sealed internal class CreateObject : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("objects")] - private IEnumerable Objects { get; } - [JsonProperty("meshModels")] - private IEnumerable MeshModels { get; } - - - public Parameters(IEnumerable objects, IEnumerable meshModels) - { - Objects = objects; - MeshModels = meshModels; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("objects")] private IEnumerable Objects { get; } + + [JsonProperty("meshModels")] private IEnumerable MeshModels { get; } - public CreateObject(IEnumerable objects, IEnumerable meshModels) + public Parameters(IEnumerable objects, IEnumerable meshModels) { Objects = objects; MeshModels = meshModels; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("CreateObject", new Parameters(Objects, MeshModels)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Objects { get; } + private IEnumerable MeshModels { get; } + + public CreateObject(IEnumerable objects, IEnumerable meshModels) + { + Objects = objects; + MeshModels = meshModels; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute( + "CreateObject", + new Parameters(Objects, MeshModels) + ); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoof.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoof.cs index 71304e24ee..c8204daa44 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoof.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoof.cs @@ -4,45 +4,44 @@ using Speckle.Newtonsoft.Json; using Speckle.Core.Models; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateRoof : ICommand> { - sealed internal class CreateRoof : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("roofs")] - private IEnumerable Roofs { get; } - - public Parameters(IEnumerable roofs) - { - Roofs = roofs; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("roofs")] private IEnumerable Roofs { get; } - public CreateRoof(IEnumerable roofs) + public Parameters(IEnumerable roofs) { - foreach (var roof in roofs) - { - roof.displayValue = null; - } - Roofs = roofs; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Roofs { get; } + + public CreateRoof(IEnumerable roofs) + { + foreach (var roof in roofs) { - var result = await HttpCommandExecutor.Execute("CreateRoof", new Parameters(Roofs)); - return result == null ? null : result.ApplicationObjects; + roof.displayValue = null; } + + Roofs = roofs; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateRoof", new Parameters(Roofs)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoom.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoom.cs index fa8b82dde6..624aee7dde 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoom.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateRoom.cs @@ -3,40 +3,39 @@ using Speckle.Core.Models; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateRoom : ICommand> { - sealed internal class CreateRoom : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("zones")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("zones")] private IEnumerable Datas { get; } - public CreateRoom(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute("CreateZone", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateRoom(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute("CreateZone", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateShell.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateShell.cs index 6051d875a8..e3f28c5bce 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateShell.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateShell.cs @@ -4,45 +4,44 @@ using Speckle.Newtonsoft.Json; using Speckle.Core.Models; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateShell : ICommand> { - sealed internal class CreateShell : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("shells")] - private IEnumerable Shells { get; } - - public Parameters(IEnumerable shells) - { - Shells = shells; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("shells")] private IEnumerable Shells { get; } - public CreateShell(IEnumerable shells) + public Parameters(IEnumerable shells) { - foreach (var shell in shells) - { - shell.displayValue = null; - } - Shells = shells; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Shells { get; } + + public CreateShell(IEnumerable shells) + { + foreach (var shell in shells) { - var result = await HttpCommandExecutor.Execute("CreateShell", new Parameters(Shells)); - return result == null ? null : result.ApplicationObjects; + shell.displayValue = null; } + + Shells = shells; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateShell", new Parameters(Shells)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateSkylight.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateSkylight.cs index c1b41a1878..8c79a78b44 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateSkylight.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateSkylight.cs @@ -4,45 +4,39 @@ using Speckle.Core.Models; using Speckle.Newtonsoft.Json; +namespace Archicad.Communication.Commands; -namespace Archicad.Communication.Commands +sealed internal class CreateSkylight : ICommand> { - sealed internal class CreateSkylight : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("subElements")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - - } + [JsonProperty("subElements")] private IEnumerable Datas { get; } - public CreateSkylight(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("CreateSkylight", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + private IEnumerable Datas { get; } + + public CreateSkylight(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateSkylight", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWall.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWall.cs index 6f76d744ff..a7832497c4 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWall.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWall.cs @@ -4,46 +4,45 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateWall : ICommand> { - sealed internal class CreateWall : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("walls")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("walls")] private IEnumerable Datas { get; } - public CreateWall(IEnumerable datas) + public Parameters(IEnumerable datas) { - foreach (var data in datas) - { - data.displayValue = null; - data.baseLine = null; - } - Datas = datas; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateWall(IEnumerable datas) + { + foreach (var data in datas) { - var result = await HttpCommandExecutor.Execute("CreateWall", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; + data.displayValue = null; + data.baseLine = null; } + + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateWall", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWindow.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWindow.cs index af3d13a376..386c75bf53 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWindow.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateWindow.cs @@ -4,40 +4,39 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class CreateWindow : ICommand> { - sealed internal class CreateWindow : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("subElements")] - private IEnumerable Datas { get; } - - public Parameters(IEnumerable datas) - { - Datas = datas; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("applicationObjects")] - public IEnumerable ApplicationObjects { get; private set; } - } - + [JsonProperty("subElements")] private IEnumerable Datas { get; } - public CreateWindow(IEnumerable datas) + public Parameters(IEnumerable datas) { Datas = datas; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("CreateWindow", new Parameters(Datas)); - return result == null ? null : result.ApplicationObjects; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateWindow(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateWindow", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_FinishReceiveTransaction.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_FinishReceiveTransaction.cs index d781bb5788..0d18b25ff5 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_FinishReceiveTransaction.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_FinishReceiveTransaction.cs @@ -6,23 +6,19 @@ using Speckle.Core.Models; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class FinishReceiveTransaction : ICommand { - sealed internal class FinishReceiveTransaction : ICommand - { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters { } + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { } - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result { } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result { } - public async Task Execute() - { - Result result = await HttpCommandExecutor.Execute( - "FinishReceiveTransaction", - new Parameters() - ); - return result; - } + public async Task Execute() + { + Result result = await HttpCommandExecutor.Execute("FinishReceiveTransaction", new Parameters()); + return result; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetBeamData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetBeamData.cs index f0d99e9c59..36f7fd5716 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetBeamData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetBeamData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetBeamData : ICommand { - sealed internal class GetBeamData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetBeamData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetBeamData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["beams"]; - } + public GetBeamData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetBeamData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["beams"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetColumnData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetColumnData.cs index 545c6c174b..e4e9d62fe6 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetColumnData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetColumnData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetColumnData : ICommand { - sealed internal class GetColumnData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetColumnData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetColumnData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["columns"]; - } + public GetColumnData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetColumnData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["columns"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetDoorData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetDoorData.cs index b4fd2589a8..18c8a4fdcd 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetDoorData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetDoorData.cs @@ -4,46 +4,45 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetDoorData : ICommand> { - sealed internal class GetDoorData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("doors")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetDoorData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetDoorData", - new Parameters(ApplicationIds) - ); - //foreach (var subelement in result.Datas) - //subelement.units = Units.Meters; - - return result.Datas; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("doors")] + public IEnumerable Datas { get; private set; } + } + + private IEnumerable ApplicationIds { get; } + + public GetDoorData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetDoorData", + new Parameters(ApplicationIds) + ); + //foreach (var subelement in result.Datas) + //subelement.units = Units.Meters; + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs index df315ea066..5b70119fe9 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs @@ -4,46 +4,47 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetElementBaseData : ICommand> { - sealed internal class GetElementBaseData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("elements")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetElementBaseData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("elements")] + public IEnumerable Datas { get; private set; } + } + + private IEnumerable ApplicationIds { get; } + + public GetElementBaseData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetElementBaseData", + new Parameters(ApplicationIds) + ); + foreach (var directShape in result.Datas) { - Result result = await HttpCommandExecutor.Execute( - "GetElementBaseData", - new Parameters(ApplicationIds) - ); - foreach (var directShape in result.Datas) - directShape.units = Units.Meters; - - return result.Datas; + directShape.units = Units.Meters; } + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementIds.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementIds.cs index 8e38022ad4..aa13354f2c 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementIds.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementIds.cs @@ -5,84 +5,83 @@ using Speckle.Newtonsoft.Json.Converters; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +internal sealed class GetElementIds : ICommand> { - internal sealed class GetElementIds : ICommand> + public enum ElementFilter { - public enum ElementFilter - { - All, - Selection, - ElementType - } - - #region --- Classes --- - - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - #region --- Fields --- + All, + Selection, + ElementType + } - [JsonProperty("elementFilter")] - [JsonConverter(typeof(StringEnumConverter))] - private ElementFilter Filter { get; } + #region --- Classes --- - [JsonProperty("filterBy")] - private List? FilterBy { get; } - #endregion + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters + { + #region --- Fields --- - #region --- Ctor \ Dtor --- + [JsonProperty("elementFilter")] + [JsonConverter(typeof(StringEnumConverter))] + private ElementFilter Filter { get; } - public Parameters(ElementFilter filter, List? filterBy = null) - { - Filter = filter; - FilterBy = filterBy; - } + [JsonProperty("filterBy")] + private List? FilterBy { get; } + #endregion - #endregion - } + #region --- Ctor \ Dtor --- - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result + public Parameters(ElementFilter filter, List? filterBy = null) { - #region --- Fields --- - - [JsonProperty("applicationIds")] - public IEnumerable ApplicationIds { get; private set; } - - #endregion + Filter = filter; + FilterBy = filterBy; } #endregion + } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { #region --- Fields --- - private ElementFilter Filter { get; } - private List? FilterBy { get; } + [JsonProperty("applicationIds")] + public IEnumerable ApplicationIds { get; private set; } #endregion + } - #region --- Ctor \ Dtor --- + #endregion - public GetElementIds(ElementFilter filter, List? filterBy = null) - { - Filter = filter; - FilterBy = filterBy; - } + #region --- Fields --- - #endregion + private ElementFilter Filter { get; } + private List? FilterBy { get; } - #region --- Functions --- + #endregion - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetElementIds", - new Parameters(Filter, FilterBy) - ); - return result.ApplicationIds; - } + #region --- Ctor \ Dtor --- - #endregion + public GetElementIds(ElementFilter filter, List? filterBy = null) + { + Filter = filter; + FilterBy = filterBy; } + + #endregion + + #region --- Functions --- + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetElementIds", + new Parameters(Filter, FilterBy) + ); + return result.ApplicationIds; + } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementType.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementType.cs index 7c826ff9d4..a53ebb6e53 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementType.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementType.cs @@ -5,83 +5,82 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands -{ - internal sealed class GetElementsType : ICommand>> - { - #region --- Classes --- +namespace Archicad.Communication.Commands; - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - #region --- Fields --- +internal sealed class GetElementsType : ICommand>> +{ + #region --- Classes --- - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters + { + #region --- Fields --- - #endregion + [JsonProperty("applicationIds")] + private IEnumerable ApplicationIds { get; } - #region --- Ctor \ Dtor --- + #endregion - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } + #region --- Ctor \ Dtor --- - #endregion + public Parameters(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; } - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - #region --- Fields --- + #endregion + } - [JsonProperty("elementTypes")] - public IEnumerable ElementTypes { get; private set; } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + #region --- Fields --- - #endregion - } + [JsonProperty("elementTypes")] + public IEnumerable ElementTypes { get; private set; } - [JsonObject(MemberSerialization.OptIn)] - private sealed class TypeDescription - { - [JsonProperty("applicationId")] - public string ApplicationId { get; private set; } + #endregion + } - [JsonProperty("elementType")] - public string ElementType { get; private set; } - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class TypeDescription + { + [JsonProperty("applicationId")] + public string ApplicationId { get; private set; } - #endregion + [JsonProperty("elementType")] + public string ElementType { get; private set; } + } - #region --- Fields --- + #endregion - private IEnumerable ApplicationIds { get; } + #region --- Fields --- - #endregion + private IEnumerable ApplicationIds { get; } - #region --- Ctor \ Dtor --- + #endregion - public GetElementsType(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } + #region --- Ctor \ Dtor --- - #endregion + public GetElementsType(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } - #region --- Functions --- + #endregion - public async Task>> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetElementTypes", - new Parameters(ApplicationIds) - ); - return result.ElementTypes - .GroupBy(row => row.ElementType) - .ToDictionary(group => group.Key, group => group.Select(x => x.ApplicationId)); - } + #region --- Functions --- - #endregion + public async Task>> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetElementTypes", + new Parameters(ApplicationIds) + ); + return result.ElementTypes + .GroupBy(row => row.ElementType) + .ToDictionary(group => group.Key, group => group.Select(x => x.ApplicationId)); } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetFloorData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetFloorData.cs index 3bc509c9d9..2f0181ac02 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetFloorData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetFloorData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +internal sealed class GetFloorData : ICommand { - internal sealed class GetFloorData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetFloorData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetSlabData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["slabs"]; - } + public GetFloorData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetSlabData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["slabs"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetGridElementData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetGridElementData.cs index a8c9e4bd6d..24f5506ff8 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetGridElementData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetGridElementData.cs @@ -4,44 +4,43 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetGridElementData : ICommand> { - sealed internal class GetGridElementData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("gridElements")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetGridElementData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetGridElementData", - new Parameters(ApplicationIds) - ); + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("gridElements")] + public IEnumerable Datas { get; private set; } + } - return result.Datas; - } + private IEnumerable ApplicationIds { get; } + + public GetGridElementData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetGridElementData", + new Parameters(ApplicationIds) + ); + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetModelOfElements.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetModelOfElements.cs index 80d7c3e16c..992b315a79 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetModelOfElements.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetModelOfElements.cs @@ -2,43 +2,42 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetModelForElements : ICommand> { - sealed internal class GetModelForElements : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("models")] public IEnumerable Models { get; private set; } - } - - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - - public GetModelForElements(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("models")] + public IEnumerable Models { get; private set; } + } - public async Task> Execute() - { - Result result = - await HttpCommandExecutor.Execute("GetModelForElements", new Parameters(ApplicationIds)); - return result.Models; - } + private IEnumerable ApplicationIds { get; } + + public GetModelForElements(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetModelForElements", + new Parameters(ApplicationIds) + ); + return result.Models; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetObjectData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetObjectData.cs index f80e9c6a43..5e13efaad4 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetObjectData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetObjectData.cs @@ -4,46 +4,47 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetObjectData : ICommand> { - sealed internal class GetObjectData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("objects")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetObjectData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("objects")] + public IEnumerable Datas { get; private set; } + } + + private IEnumerable ApplicationIds { get; } + + public GetObjectData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetObjectData", + new Parameters(ApplicationIds) + ); + foreach (var @object in result.Datas) { - Result result = await HttpCommandExecutor.Execute( - "GetObjectData", - new Parameters(ApplicationIds) - ); - foreach (var @object in result.Datas) - @object.units = Units.Meters; - - return result.Datas; + @object.units = Units.Meters; } + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetProjectInfo.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetProjectInfo.cs index 35d1326f77..fcad46dcc3 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetProjectInfo.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetProjectInfo.cs @@ -1,24 +1,23 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands -{ - internal sealed class GetProjectInfo : ICommand - { - #region --- Classes --- +namespace Archicad.Communication.Commands; - [JsonObject] - public sealed class Parameters { } +internal sealed class GetProjectInfo : ICommand +{ + #region --- Classes --- - #endregion + [JsonObject] + public sealed class Parameters { } - #region --- Functions --- + #endregion - public async Task Execute() - { - return await HttpCommandExecutor.Execute("GetProjectInfo", null); - } + #region --- Functions --- - #endregion + public async Task Execute() + { + return await HttpCommandExecutor.Execute("GetProjectInfo", null); } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoofData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoofData.cs index 5afb40d44f..dc8dadf112 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoofData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoofData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +internal sealed class GetRoofData : ICommand { - internal sealed class GetRoofData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetRoofData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetRoofData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["roofs"]; - } + public GetRoofData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetRoofData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["roofs"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoomData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoomData.cs index 86ed84d4a7..654a5349e2 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoomData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetRoomData.cs @@ -4,41 +4,40 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetRoomData : ICommand> { - sealed internal class GetRoomData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("zones")] - public IEnumerable Rooms { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetRoomData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() - { - var result = await HttpCommandExecutor.Execute("GetRoomData", new Parameters(ApplicationIds)); + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("zones")] + public IEnumerable Rooms { get; private set; } + } - return result.Rooms; - } + private IEnumerable ApplicationIds { get; } + + public GetRoomData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("GetRoomData", new Parameters(ApplicationIds)); + + return result.Rooms; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetShellData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetShellData.cs index c43c192fd8..b2a9c9f065 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetShellData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetShellData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +internal sealed class GetShellData : ICommand { - internal sealed class GetShellData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetShellData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetShellData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["shells"]; - } + public GetShellData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetShellData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["shells"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSkylightData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSkylightData.cs index 195ec31438..50cfe77f77 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSkylightData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSkylightData.cs @@ -4,49 +4,45 @@ using Speckle.Core.Kits; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetSkylightData : ICommand> { - sealed internal class GetSkylightData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - - [JsonProperty("skylights")] - public IEnumerable Datas { get; private set; } - - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetSkylightData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute("GetSkylightData", new Parameters(ApplicationIds)); - //foreach (var subelement in result.Datas) - //subelement.units = Units.Meters; + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("skylights")] + public IEnumerable Datas { get; private set; } + } - return result.Datas; - } + private IEnumerable ApplicationIds { get; } + public GetSkylightData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetSkylightData", + new Parameters(ApplicationIds) + ); + //foreach (var subelement in result.Datas) + //subelement.units = Units.Meters; + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSubelementInfo.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSubelementInfo.cs index 99d699f8b3..2b0da5a7ad 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSubelementInfo.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetSubelementInfo.cs @@ -4,43 +4,42 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetSubElementInfo : ICommand> { - sealed internal class GetSubElementInfo : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationId")] - private string ApplicationId { get; } - - public Parameters(string applicationId) - { - ApplicationId = applicationId; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("subelementModels")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationId")] private string ApplicationId { get; } - public GetSubElementInfo(string applicationId) + public Parameters(string applicationId) { ApplicationId = applicationId; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetSubelementInfo", - new Parameters(ApplicationId) - ); - return result.Datas; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("subelementModels")] + public IEnumerable Datas { get; private set; } + } + + private string ApplicationId { get; } + + public GetSubElementInfo(string applicationId) + { + ApplicationId = applicationId; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetSubelementInfo", + new Parameters(ApplicationId) + ); + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWallData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWallData.cs index a304fc21ae..103a7f9551 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWallData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWallData.cs @@ -2,37 +2,36 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetWallData : ICommand { - sealed internal class GetWallData : ICommand + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetWallData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task Execute() - { - dynamic result = await HttpCommandExecutor.Execute( - "GetWallData", - new Parameters(ApplicationIds) - ); + private IEnumerable ApplicationIds { get; } - return (Speckle.Newtonsoft.Json.Linq.JArray)result["walls"]; - } + public GetWallData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetWallData", + new Parameters(ApplicationIds) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["walls"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWindowData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWindowData.cs index 1c94a99700..8fb5267582 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWindowData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetWindowData.cs @@ -4,46 +4,45 @@ using Speckle.Newtonsoft.Json; using Objects.BuiltElements.Archicad; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +sealed internal class GetWindowData : ICommand> { - sealed internal class GetWindowData : ICommand> + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters { - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - [JsonProperty("applicationIds")] - private IEnumerable ApplicationIds { get; } - - public Parameters(IEnumerable applicationIds) - { - ApplicationIds = applicationIds; - } - } - - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result - { - [JsonProperty("windows")] - public IEnumerable Datas { get; private set; } - } - + [JsonProperty("applicationIds")] private IEnumerable ApplicationIds { get; } - public GetWindowData(IEnumerable applicationIds) + public Parameters(IEnumerable applicationIds) { ApplicationIds = applicationIds; } + } - public async Task> Execute() - { - Result result = await HttpCommandExecutor.Execute( - "GetWindowData", - new Parameters(ApplicationIds) - ); - //foreach (var subelement in result.Datas) - //subelement.units = Units.Meters; - - return result.Datas; - } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("windows")] + public IEnumerable Datas { get; private set; } + } + + private IEnumerable ApplicationIds { get; } + + public GetWindowData(IEnumerable applicationIds) + { + ApplicationIds = applicationIds; + } + + public async Task> Execute() + { + Result result = await HttpCommandExecutor.Execute( + "GetWindowData", + new Parameters(ApplicationIds) + ); + //foreach (var subelement in result.Datas) + //subelement.units = Units.Meters; + + return result.Datas; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_SelectElements.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_SelectElements.cs index 16118b9efe..56d1db191d 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_SelectElements.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_SelectElements.cs @@ -3,76 +3,78 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication.Commands -{ - internal sealed class SelectElements : ICommand - { - #region --- Classes --- +namespace Archicad.Communication.Commands; - [JsonObject(MemberSerialization.OptIn)] - public sealed class Parameters - { - #region --- Fields --- - - [JsonProperty("applicationIds")] - private IEnumerable ElementIds { get; } +internal sealed class SelectElements : ICommand +{ + #region --- Classes --- - [JsonProperty("deselect")] - private bool Deselect { get; } + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters + { + #region --- Fields --- - [JsonProperty("clearSelection")] - private bool ClearSelection { get; } + [JsonProperty("applicationIds")] + private IEnumerable ElementIds { get; } - #endregion + [JsonProperty("deselect")] + private bool Deselect { get; } - #region --- Ctor \ Dtor --- + [JsonProperty("clearSelection")] + private bool ClearSelection { get; } - public Parameters(IEnumerable elementIds, bool deselect) - { - ElementIds = elementIds; - Deselect = deselect; - ClearSelection = !deselect; - } + #endregion - #endregion - } + #region --- Ctor \ Dtor --- - [JsonObject(MemberSerialization.OptIn)] - private sealed class Result + public Parameters(IEnumerable elementIds, bool deselect) { - #region --- Fields --- - - #endregion + ElementIds = elementIds; + Deselect = deselect; + ClearSelection = !deselect; } #endregion + } + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { #region --- Fields --- - private IEnumerable ElementIds { get; } + #endregion + } - private bool Deselect { get; } + #endregion - #endregion + #region --- Fields --- - #region --- Ctor \ Dtor --- + private IEnumerable ElementIds { get; } - public SelectElements(IEnumerable elementIds, bool deselect) - { - ElementIds = elementIds; - Deselect = deselect; - } + private bool Deselect { get; } - #endregion + #endregion - #region --- Functions --- + #region --- Ctor \ Dtor --- - public async Task Execute() - { - Result result = await HttpCommandExecutor.Execute("SelectElements", new Parameters(ElementIds, Deselect)); - return result; - } + public SelectElements(IEnumerable elementIds, bool deselect) + { + ElementIds = elementIds; + Deselect = deselect; + } - #endregion + #endregion + + #region --- Functions --- + + public async Task Execute() + { + Result result = await HttpCommandExecutor.Execute( + "SelectElements", + new Parameters(ElementIds, Deselect) + ); + return result; } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/ICommand.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/ICommand.cs index 7cc172dd05..9ccc37256a 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/ICommand.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/ICommand.cs @@ -1,9 +1,8 @@ using System.Threading.Tasks; -namespace Archicad.Communication.Commands +namespace Archicad.Communication.Commands; + +internal interface ICommand { - internal interface ICommand - { - Task Execute(); - } + Task Execute(); } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/ConnectionManager.cs b/ConnectorArchicad/ConnectorArchicad/Communication/ConnectionManager.cs index c4d000fd7d..2d9a2f84b7 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/ConnectionManager.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/ConnectionManager.cs @@ -2,42 +2,45 @@ using System.Net.Http; using System.Threading.Tasks; -namespace Archicad.Communication +namespace Archicad.Communication; + +internal class ConnectionManager { - internal class ConnectionManager - { - #region --- Fields --- + #region --- Fields --- - private HttpClient HttpClient { get; set; } + private HttpClient HttpClient { get; set; } - public static ConnectionManager Instance { get; } = new ConnectionManager(); + public static ConnectionManager Instance { get; } = new ConnectionManager(); - #endregion + #endregion - #region --- Functions --- + #region --- Functions --- - public void Start(uint portNumber) + public void Start(uint portNumber) + { + HttpClient = new HttpClient { - HttpClient = new HttpClient { BaseAddress = new System.Uri("http://127.0.0.1:" + portNumber), Timeout = TimeSpan.FromSeconds(300) }; - } + BaseAddress = new System.Uri("http://127.0.0.1:" + portNumber), + Timeout = TimeSpan.FromSeconds(300) + }; + } - public void Stop() - { - HttpClient?.CancelPendingRequests(); - } + public void Stop() + { + HttpClient?.CancelPendingRequests(); + } - public async Task Send(string message) + public async Task Send(string message) + { + if (HttpClient is null) { - if (HttpClient is null) - { - throw new System.Exception("Connection is not started!"); - } - - HttpRequestMessage requestMessage = new HttpRequestMessage { Method = HttpMethod.Post, Content = new StringContent(message) }; - HttpResponseMessage responseMessage = await HttpClient.SendAsync(requestMessage); - return await responseMessage.Content.ReadAsStringAsync(); + throw new System.Exception("Connection is not started!"); } - #endregion + HttpRequestMessage requestMessage = new() { Method = HttpMethod.Post, Content = new StringContent(message) }; + HttpResponseMessage responseMessage = await HttpClient.SendAsync(requestMessage); + return await responseMessage.Content.ReadAsStringAsync(); } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/HttpCommandExecutor.cs b/ConnectorArchicad/ConnectorArchicad/Communication/HttpCommandExecutor.cs index b7aa0932d4..4828527898 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/HttpCommandExecutor.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/HttpCommandExecutor.cs @@ -3,85 +3,79 @@ using System.Threading.Tasks; using Speckle.Newtonsoft.Json; -namespace Archicad.Communication +namespace Archicad.Communication; + +internal static class HttpCommandExecutor { - internal static class HttpCommandExecutor - { - #region --- Functions --- + #region --- Functions --- - private static string SerializeRequest(TRequest request) - { - JsonSerializerSettings settings = new JsonSerializerSettings + private static string SerializeRequest(TRequest request) + { + JsonSerializerSettings settings = + new() { NullValueHandling = NullValueHandling.Ignore, Context = new StreamingContext(StreamingContextStates.Remoting) }; - return JsonConvert.SerializeObject(request, settings); - } + return JsonConvert.SerializeObject(request, settings); + } - private static TResponse DeserializeResponse(string obj) - { - JsonSerializerSettings settings = new JsonSerializerSettings - { - Context = new StreamingContext(StreamingContextStates.Remoting) - }; + private static TResponse DeserializeResponse(string obj) + { + JsonSerializerSettings settings = new() { Context = new StreamingContext(StreamingContextStates.Remoting) }; - return JsonConvert.DeserializeObject(obj, settings); - } + return JsonConvert.DeserializeObject(obj, settings); + } - public static async Task Execute(string commandName, TParameters parameters) - where TParameters : class - where TResult : class - { - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin( - ConnectorArchicad.Properties.OperationNameTemplates.HttpCommandExecute, - commandName - ) + public static async Task Execute(string commandName, TParameters parameters) + where TParameters : class + where TResult : class + { + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin( + ConnectorArchicad.Properties.OperationNameTemplates.HttpCommandExecute, + commandName ) - { - bool log = false; + ) + { + bool log = false; - AddOnCommandRequest request = new AddOnCommandRequest(commandName, parameters); + AddOnCommandRequest request = new(commandName, parameters); - string requestMsg = SerializeRequest(request); + string requestMsg = SerializeRequest(request); - if (log) - { - Console.WriteLine(requestMsg); - } + if (log) + { + Console.WriteLine(requestMsg); + } - string responseMsg; + string responseMsg; - using ( - context?.cumulativeTimer?.Begin( - ConnectorArchicad.Properties.OperationNameTemplates.HttpCommandAPI, - commandName - ) - ) - { - responseMsg = await ConnectionManager.Instance.Send(requestMsg); - } + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.HttpCommandAPI, commandName) + ) + { + responseMsg = await ConnectionManager.Instance.Send(requestMsg); + } - if (log) - { - Console.WriteLine(responseMsg); - } + if (log) + { + Console.WriteLine(responseMsg); + } - AddOnCommandResponse response = DeserializeResponse>(responseMsg); + AddOnCommandResponse response = DeserializeResponse>(responseMsg); - // TODO - //if (!response.Succeeded) - //{ - // throw new CommandFailedException (response.ErrorStatus.Code, response.ErrorStatus.Message); - //} + // TODO + //if (!response.Succeeded) + //{ + // throw new CommandFailedException (response.ErrorStatus.Code, response.ErrorStatus.Message); + //} - return response.Result; - } + return response.Result; } - - #endregion } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/ConnectorBinding.cs b/ConnectorArchicad/ConnectorArchicad/ConnectorBinding.cs index 58c0600f93..3dc7e6aa50 100644 --- a/ConnectorArchicad/ConnectorArchicad/ConnectorBinding.cs +++ b/ConnectorArchicad/ConnectorArchicad/ConnectorBinding.cs @@ -15,249 +15,254 @@ using Speckle.Core.Logging; using Speckle.Core.Models; -namespace Archicad.Launcher +namespace Archicad.Launcher; + +public partial class ArchicadBinding : ConnectorBindings { - public partial class ArchicadBinding : ConnectorBindings - { - public uint archicadVersion { get; } + public uint archicadVersion { get; } - public ArchicadBinding(uint archicadVersion) - { - this.archicadVersion = archicadVersion; - } + public ArchicadBinding(uint archicadVersion) + { + this.archicadVersion = archicadVersion; + } - public override string GetActiveViewName() - { - throw new NotImplementedException(); - } + public override string GetActiveViewName() + { + throw new NotImplementedException(); + } - public override List GetCustomStreamMenuItems() - { - return new List(); - } + public override List GetCustomStreamMenuItems() + { + return new List(); + } - public ProjectInfoData? GetProjectInfo() - { - return AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; - } + public ProjectInfoData? GetProjectInfo() + { + return AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; + } - public override string GetDocumentId() - { - var projectInfo = AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; - return projectInfo is null ? string.Empty : projectInfo.name; - } + public override string GetDocumentId() + { + var projectInfo = AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; + return projectInfo is null ? string.Empty : projectInfo.name; + } - public override string GetDocumentLocation() - { - var projectInfo = AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; - return projectInfo is null ? string.Empty : projectInfo.location; - } + public override string GetDocumentLocation() + { + var projectInfo = AsyncCommandProcessor.Execute(new Communication.Commands.GetProjectInfo())?.Result; + return projectInfo is null ? string.Empty : projectInfo.location; + } - public override string GetFileName() - { - return Path.GetFileName(GetDocumentLocation()); - } + public override string GetFileName() + { + return Path.GetFileName(GetDocumentLocation()); + } - public override string GetHostAppNameVersion() - { - return string.Format("Archicad {0}", archicadVersion); - } + public override string GetHostAppNameVersion() + { + return string.Format("Archicad {0}", archicadVersion); + } - public override string GetHostAppName() - { - return "Archicad"; - } + public override string GetHostAppName() + { + return "Archicad"; + } - public override List GetObjectsInView() - { - throw new NotImplementedException(); - } + public override List GetObjectsInView() + { + throw new NotImplementedException(); + } - public override List GetSelectedObjects() - { - var elementIds = AsyncCommandProcessor - .Execute(new Communication.Commands.GetElementIds(Communication.Commands.GetElementIds.ElementFilter.Selection)) - ?.Result; - return elementIds is null ? new List() : elementIds.ToList(); - } + public override List GetSelectedObjects() + { + var elementIds = AsyncCommandProcessor + .Execute(new Communication.Commands.GetElementIds(Communication.Commands.GetElementIds.ElementFilter.Selection)) + ?.Result; + return elementIds is null ? new List() : elementIds.ToList(); + } - public override List GetSelectionFilters() + public override List GetSelectionFilters() + { + return new List() { - return new List() + new ManualSelectionFilter(), + new AllSelectionFilter + { + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Sends all supported elements and project information." + }, + new ListSelectionFilter { - new ManualSelectionFilter(), - new AllSelectionFilter + Slug = "elementType", + Name = "Element Type", + Icon = "Category", + Values = new List { - Slug = "all", - Name = "Everything", - Icon = "CubeScan", - Description = "Sends all supported elements and project information." + "Wall", + "Column", + "Beam", + "Slab", + "Roof", + "Shell", + "Stair", + "Railing", + "Curtain Wall", + "Door", + "Window", + "Skylight", + "Opening", + "Zone", + "Mesh", + "Morph", + "Object", + "Lamp" }, - new ListSelectionFilter - { - Slug = "elementType", - Name = "Element Type", - Icon = "Category", - Values = new List - { - "Wall", - "Column", - "Beam", - "Slab", - "Roof", - "Shell", - "Stair", - "Railing", - "Curtain Wall", - "Door", - "Window", - "Skylight", - "Opening", - "Zone", - "Mesh", - "Morph", - "Object", - "Lamp" - }, - Description = "Adds all elements with the selected Element Types" - } - }; - } + Description = "Adds all elements with the selected Element Types" + } + }; + } - public override List GetStreamsInFile() - { - return new List(); - } + public override List GetStreamsInFile() + { + return new List(); + } - public override void ResetDocument() - { - // TODO! - } + public override void ResetDocument() + { + // TODO! + } - public override List GetReceiveModes() - { - return new List { ReceiveMode.Create }; - } + public override List GetReceiveModes() + { + return new List { ReceiveMode.Create }; + } - public override bool CanPreviewReceive => false; + public override bool CanPreviewReceive => false; - public override Task PreviewReceive(StreamState state, ProgressViewModel progress) - { - throw new NotImplementedException("Preview receiving not supported"); - } + public override Task PreviewReceive(StreamState state, ProgressViewModel progress) + { + throw new NotImplementedException("Preview receiving not supported"); + } - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + { + try { - try + using (var timer = Archicad.Helpers.Timer.CreateReceive(state.StreamId)) { - using (var timer = Archicad.Helpers.Timer.CreateReceive(state.StreamId)) + Base commitObject; + + var context = Archicad.Helpers.Timer.Context.Peek; + using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.SendToServer)) { - Base commitObject; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.SendToServer)) - { - commitObject = await Speckle.Core.Api.Helpers.Receive(IdentifyStream(state)); - } - - if (commitObject is not null) - await ElementConverterManager.Instance.ConvertToNative(state, commitObject, progress); - - await AsyncCommandProcessor.Execute(new Communication.Commands.FinishReceiveTransaction()); - - if (commitObject == null) - { - timer.Cancel(); - throw new SpeckleException("Failed to receive specified"); - } + commitObject = await Speckle.Core.Api.Helpers.Receive(IdentifyStream(state)); } - } - catch (Exception ex) - { - // log - if (ex is not OperationCanceledException) - SpeckleLog.Logger.Error("Conversion to native failed."); - // throw - switch (ex) + if (commitObject is not null) { - case OperationCanceledException: - throw new OperationCanceledException(ex.Message); - default: - throw new SpeckleException(ex.Message, ex); + await ElementConverterManager.Instance.ConvertToNative(state, commitObject, progress); } + + await AsyncCommandProcessor.Execute(new Communication.Commands.FinishReceiveTransaction()); + + if (commitObject == null) + { + timer.Cancel(); + throw new SpeckleException("Failed to receive specified"); + } + } + } + catch (Exception ex) + { + // log + if (ex is not OperationCanceledException) + { + SpeckleLog.Logger.Error("Conversion to native failed."); } - return state; + // throw + switch (ex) + { + case OperationCanceledException: + throw new OperationCanceledException(ex.Message); + default: + throw new SpeckleException(ex.Message, ex); + } } - public override bool CanPreviewSend => false; + return state; + } - public override void PreviewSend(StreamState state, ProgressViewModel progress) - { - throw new NotImplementedException("Preview send not supported"); - } + public override bool CanPreviewSend => false; - public override async Task SendStream(StreamState state, ProgressViewModel progress) + public override void PreviewSend(StreamState state, ProgressViewModel progress) + { + throw new NotImplementedException("Preview send not supported"); + } + + public override async Task SendStream(StreamState state, ProgressViewModel progress) + { + try { - try + using (var timer = Archicad.Helpers.Timer.CreateSend(state.StreamId)) { - using (var timer = Archicad.Helpers.Timer.CreateSend(state.StreamId)) + if (state.Filter == null) { - if (state.Filter == null) - { - throw new InvalidOperationException("Expected selection filter to be non-null"); - } - - var commitObject = await ElementConverterManager.Instance.ConvertToSpeckle(state.Filter, progress); - - if (commitObject == null) - { - timer.Cancel(); - throw new SpeckleException("Failed to convert objects to Speckle"); - } - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.SendToServer)) - { - return await Speckle.Core.Api.Helpers.Send( - IdentifyStream(state), - commitObject, - state.CommitMessage, - HostApplications.Archicad.Name - ); - } + throw new InvalidOperationException("Expected selection filter to be non-null"); + } + + var commitObject = await ElementConverterManager.Instance.ConvertToSpeckle(state.Filter, progress); + + if (commitObject == null) + { + timer.Cancel(); + throw new SpeckleException("Failed to convert objects to Speckle"); } - } - catch (Exception ex) - { - // log - if (ex is not OperationCanceledException) - SpeckleLog.Logger.Error("Conversion to Speckle failed."); - // throw - switch (ex) + var context = Archicad.Helpers.Timer.Context.Peek; + using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.SendToServer)) { - case OperationCanceledException: - throw new OperationCanceledException(ex.Message); - default: - throw new SpeckleException(ex.Message, ex); + return await Speckle.Core.Api.Helpers.Send( + IdentifyStream(state), + commitObject, + state.CommitMessage, + HostApplications.Archicad.Name + ); } } } - - public override void WriteStreamsToFile(List streams) { } - - private static string IdentifyStream(StreamState state) + catch (Exception ex) { - var stream = new StreamWrapper + // log + if (ex is not OperationCanceledException) + { + SpeckleLog.Logger.Error("Conversion to Speckle failed."); + } + + // throw + switch (ex) { - StreamId = state.StreamId, - ServerUrl = state.ServerUrl, - BranchName = state.BranchName, - CommitId = state.CommitId != "latest" ? state.CommitId : null - }; - return stream.ToString(); + case OperationCanceledException: + throw new OperationCanceledException(ex.Message); + default: + throw new SpeckleException(ex.Message, ex); + } } } + + public override void WriteStreamsToFile(List streams) { } + + private static string IdentifyStream(StreamState state) + { + var stream = new StreamWrapper + { + StreamId = state.StreamId, + ServerUrl = state.ServerUrl, + BranchName = state.BranchName, + CommitId = state.CommitId != "latest" ? state.CommitId : null + }; + return stream.ToString(); + } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ConversionOptions.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ConversionOptions.cs index aedba6ef22..b426e11b12 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ConversionOptions.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ConversionOptions.cs @@ -3,20 +3,24 @@ using DesktopUI2.Models.Settings; using DesktopUI2.Views.Controls.StreamEditControls; -namespace Archicad +namespace Archicad; + +public class ConversionOptions { - public class ConversionOptions + public ConversionOptions(List settings) { - public ConversionOptions (List settings) + foreach (var setting in settings) { - foreach (var setting in settings) + if (setting.Slug.Equals("receive - parametric")) { - if (setting.Slug.Equals("receive - parametric")) - if (bool.Parse(setting.Selection ?? "False")) - ReceiveParametric = true; - }; + if (bool.Parse(setting.Selection ?? "False")) + { + ReceiveParametric = true; + } + } } - - public bool ReceiveParametric { get; set; } + ; } + + public bool ReceiveParametric { get; set; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs index d9ae3fc506..1ff153fe6a 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs @@ -8,163 +8,162 @@ using Speckle.Core.Models.GraphTraversal; using static Speckle.Core.Models.ApplicationObject; -namespace Objects.Converter.Archicad +namespace Objects.Converter.Archicad; + +public partial class ConverterArchicad : ISpeckleConverter { - public partial class ConverterArchicad : ISpeckleConverter - { - public string Description => "Default Speckle Kit for Archicad"; - public string Name => nameof(ConverterArchicad); - public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; + public string Description => "Default Speckle Kit for Archicad"; + public string Name => nameof(ConverterArchicad); + public string Author => "Speckle"; + public string WebsiteOrEmail => "https://speckle.systems"; - public IEnumerable GetServicedApplications() => new string[] { "Archicad" }; + public IEnumerable GetServicedApplications() => new string[] { "Archicad" }; - public ConversionOptions ConversionOptions { get; set; } + public ConversionOptions ConversionOptions { get; set; } - /// - /// Keeps track of the conversion process - /// - public ProgressReport Report { get; private set; } = new ProgressReport(); + /// + /// Keeps track of the conversion process + /// + public ProgressReport Report { get; private set; } = new ProgressReport(); - /// - /// Decides what to do when an element being received already exists - /// - public ReceiveMode ReceiveMode { get; set; } + /// + /// Decides what to do when an element being received already exists + /// + public ReceiveMode ReceiveMode { get; set; } - // send - public Base ConvertToSpeckle(object @object) - { - return null; - } + // send + public Base ConvertToSpeckle(object @object) + { + return null; + } - public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); + public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); - public bool CanConvertToSpeckle(object @object) - { - return false; - } + public bool CanConvertToSpeckle(object @object) + { + return false; + } - // receive - public object ConvertToNative(Base @object) - { - return null; - } + // receive + public object ConvertToNative(Base @object) + { + return null; + } - public object ConvertToNativeDisplayable(Base @object) - { - throw new NotImplementedException(); - } + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } - public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); + public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); - public bool CanConvertToNativeImplemented(Base @object) + public bool CanConvertToNativeImplemented(Base @object) + { + return @object switch { - return @object switch - { - // Speckle BIM elements - Objects.BuiltElements.Beam _ => true, - Objects.BuiltElements.Column _ => true, - Objects.BuiltElements.Floor _ => true, - Objects.BuiltElements.Ceiling _ => true, - Objects.BuiltElements.GridLine => true, - Objects.BuiltElements.Roof _ => true, - Objects.BuiltElements.Room _ => true, - Objects.BuiltElements.Wall _ => true, - - // Archicad elements - Objects.BuiltElements.Archicad.ArchicadDoor _ => true, - Objects.BuiltElements.Archicad.ArchicadWindow _ => true, - Objects.BuiltElements.Archicad.ArchicadSkylight _ => true, - Objects.BuiltElements.Archicad.DirectShape _ => true, - - // Revit elements - Objects.BuiltElements.Revit.FamilyInstance _ => true, - Objects.Other.Revit.RevitInstance _ => true, - - // Other - Objects.Other.BlockInstance _ => true, - - // Speckle geomtries - Objects.Geometry.Mesh _ => true, - Objects.Geometry.Brep _ => true, - - _ => false - }; - } + // Speckle BIM elements + Objects.BuiltElements.Beam _ => true, + Objects.BuiltElements.Column _ => true, + Objects.BuiltElements.Floor _ => true, + Objects.BuiltElements.Ceiling _ => true, + Objects.BuiltElements.GridLine => true, + Objects.BuiltElements.Roof _ => true, + Objects.BuiltElements.Room _ => true, + Objects.BuiltElements.Wall _ => true, + + // Archicad elements + Objects.BuiltElements.Archicad.ArchicadDoor _ => true, + Objects.BuiltElements.Archicad.ArchicadWindow _ => true, + Objects.BuiltElements.Archicad.ArchicadSkylight _ => true, + Objects.BuiltElements.Archicad.DirectShape _ => true, + + // Revit elements + Objects.BuiltElements.Revit.FamilyInstance _ => true, + Objects.Other.Revit.RevitInstance _ => true, + + // Other + Objects.Other.BlockInstance _ => true, + + // Speckle geomtries + Objects.Geometry.Mesh _ => true, + Objects.Geometry.Brep _ => true, + + _ => false + }; + } - public bool CanConvertToNativeNotImplemented(Base @object) + public bool CanConvertToNativeNotImplemented(Base @object) + { + return @object switch { - return @object switch - { - // Project info - Objects.Organization.ModelInfo _ => true, + // Project info + Objects.Organization.ModelInfo _ => true, - _ => false - }; - } + _ => false + }; + } - public bool CanConvertToNative(Base @object) - { - return CanConvertToNativeImplemented(@object) || CanConvertToNativeNotImplemented(@object); - } + public bool CanConvertToNative(Base @object) + { + return CanConvertToNativeImplemented(@object) || CanConvertToNativeNotImplemented(@object); + } - public bool CanConvertToNativeDisplayable(Base @object) - { - return false; - } + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; + } - /// - /// To know which other objects are being converted, in order to sort relationships between them. - /// For example, elements that have children use this to determine whether they should send their children out or not. - /// - public List ContextObjects { get; set; } = new List(); + /// + /// To know which other objects are being converted, in order to sort relationships between them. + /// For example, elements that have children use this to determine whether they should send their children out or not. + /// + public List ContextObjects { get; set; } = new List(); - /// - /// To keep track of previously received objects from a given stream in here. If possible, conversions routines - /// will edit an existing object, otherwise they will delete the old one and create the new one. - /// - public List PreviousContextObjects { get; set; } = new List(); + /// + /// To keep track of previously received objects from a given stream in here. If possible, conversions routines + /// will edit an existing object, otherwise they will delete the old one and create the new one. + /// + public List PreviousContextObjects { get; set; } = new List(); - public void SetContextDocument(object doc) { } + public void SetContextDocument(object doc) { } - public void SetContextObjects(List objects) => ContextObjects = objects; + public void SetContextObjects(List objects) => ContextObjects = objects; - /// - /// Removes all inherited classes from speckle type string - /// - /// - /// - public static string SimplifySpeckleType(string type) - { - return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); - } + /// + /// Removes all inherited classes from speckle type string + /// + /// + /// + public static string SimplifySpeckleType(string type) + { + return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + } - public void SetContextObjects(List flattenObjects) - { - List objects; + public void SetContextObjects(List flattenObjects) + { + List objects; - foreach (var tc in flattenObjects) + foreach (var tc in flattenObjects) + { + var applicationObject = new ApplicationObject(tc.current.id, SimplifySpeckleType(tc.current.speckle_type)) { - var applicationObject = new ApplicationObject(tc.current.id, SimplifySpeckleType(tc.current.speckle_type)) - { - applicationId = tc.current.applicationId, - Convertible = true - }; - - ContextObjects.Add(applicationObject); - } + applicationId = tc.current.applicationId, + Convertible = true + }; + + ContextObjects.Add(applicationObject); } + } - public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; + public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; - public void SetConverterSettings(object settings) { } + public void SetConverterSettings(object settings) { } - public ConverterArchicad(ConversionOptions conversionOptions) - { - this.ConversionOptions = conversionOptions; + public ConverterArchicad(ConversionOptions conversionOptions) + { + this.ConversionOptions = conversionOptions; - var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterArchicad)).GetName().Version; - Report.Log($"Using converter: {Name} v{ver}"); - } + var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterArchicad)).GetName().Version; + Report.Log($"Using converter: {Name} v{ver}"); } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/BeamConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/BeamConverter.cs index 27e29d4327..8112141ef5 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/BeamConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/BeamConverter.cs @@ -10,100 +10,100 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Beam : IConverter { - public sealed class Beam : IConverter + public Type Type => typeof(Objects.BuiltElements.Beam); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Beam); + var beams = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var beams = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) + token.ThrowIfCancellationRequested(); + + switch (tc.current) { - token.ThrowIfCancellationRequested(); + case Objects.BuiltElements.Archicad.ArchicadBeam archiBeam: + beams.Add(archiBeam); + break; + case Objects.BuiltElements.Beam beam: + + // upgrade (if not Archicad beam): Objects.BuiltElements.Beam --> Objects.BuiltElements.Archicad.ArchicadBeam + { + var baseLine = (Line)beam.baseLine; + var newBeam = new Objects.BuiltElements.Archicad.ArchicadBeam + { + id = beam.id, + applicationId = beam.applicationId, + archicadLevel = Archicad.Converters.Utils.ConvertLevel(beam.level), + begC = Utils.ScaleToNative(baseLine.start), + endC = Utils.ScaleToNative(baseLine.end) + }; - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadBeam archiBeam: - beams.Add(archiBeam); - break; - case Objects.BuiltElements.Beam beam: + beams.Add(newBeam); + } - // upgrade (if not Archicad beam): Objects.BuiltElements.Beam --> Objects.BuiltElements.Archicad.ArchicadBeam - { - var baseLine = (Line)beam.baseLine; - var newBeam = new Objects.BuiltElements.Archicad.ArchicadBeam - { - id = beam.id, - applicationId = beam.applicationId, - archicadLevel = Archicad.Converters.Utils.ConvertLevel(beam.level), - begC = Utils.ScaleToNative(baseLine.start), - endC = Utils.ScaleToNative(baseLine.end) - }; - - beams.Add(newBeam); - } - - break; - } + break; } } + } - IEnumerable result; - result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateBeam(beams), token); + IEnumerable result; + result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateBeam(beams), token); - return result is null ? new List() : result.ToList(); - } + return result is null ? new List() : result.ToList(); + } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token - ) - { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetBeamData(elementModels.Select(e => e.applicationId)), - token - ); + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetBeamData(elementModels.Select(e => e.applicationId)), + token + ); - var beams = new List(); - if (jArray is null) - return beams; + var beams = new List(); + if (jArray is null) + { + return beams; + } - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) + ) + { + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadBeam beam = + Archicad.Converters.Utils.ConvertDTOs(jToken); + + // downgrade (always): Objects.BuiltElements.Archicad.ArchicadBeam --> Objects.BuiltElements.Beam { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadBeam beam = - Archicad.Converters.Utils.ConvertDTOs(jToken); - - // downgrade (always): Objects.BuiltElements.Archicad.ArchicadBeam --> Objects.BuiltElements.Beam - { - beam.units = Units.Meters; - beam.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == beam.applicationId).model - ); - beam.baseLine = new Line(beam.begC, beam.endC); - } - - beams.Add(beam); + beam.units = Units.Meters; + beam.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == beam.applicationId).model + ); + beam.baseLine = new Line(beam.begC, beam.endC); } - } - return beams; + beams.Add(beam); + } } + + return beams; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ColumnConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ColumnConverter.cs index 20414eb44d..306343175f 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ColumnConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ColumnConverter.cs @@ -10,93 +10,93 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Column : IConverter { - public sealed class Column : IConverter + public Type Type => typeof(Objects.BuiltElements.Column); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Column); + var columns = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var columns = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadColumn archicadColumn: - columns.Add(archicadColumn); - break; - case Objects.BuiltElements.Column column: - var baseLine = (Line)column.baseLine; - Objects.BuiltElements.Archicad.ArchicadColumn newColumn = - new Objects.BuiltElements.Archicad.ArchicadColumn - { - id = column.id, - applicationId = column.applicationId, - archicadLevel = Archicad.Converters.Utils.ConvertLevel(column.level), - origoPos = Utils.ScaleToNative(baseLine.start), - height = Math.Abs( - Utils.ScaleToNative(baseLine.end.z, baseLine.end.units) - - Utils.ScaleToNative(baseLine.start.z, baseLine.start.units) - ) - }; + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadColumn archicadColumn: + columns.Add(archicadColumn); + break; + case Objects.BuiltElements.Column column: + var baseLine = (Line)column.baseLine; + Objects.BuiltElements.Archicad.ArchicadColumn newColumn = + new() + { + id = column.id, + applicationId = column.applicationId, + archicadLevel = Archicad.Converters.Utils.ConvertLevel(column.level), + origoPos = Utils.ScaleToNative(baseLine.start), + height = Math.Abs( + Utils.ScaleToNative(baseLine.end.z, baseLine.end.units) + - Utils.ScaleToNative(baseLine.start.z, baseLine.start.units) + ) + }; - columns.Add(newColumn); - break; - } + columns.Add(newColumn); + break; } } + } + + IEnumerable result; + result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateColumn(columns), token); + return result is null ? new List() : result.ToList(); + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetColumnData(elementModels.Select(e => e.applicationId)), + token + ); - IEnumerable result; - result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateColumn(columns), token); - return result is null ? new List() : result.ToList(); + var columns = new List(); + if (jArray is null) + { + return columns; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetColumnData(elementModels.Select(e => e.applicationId)), - token - ); - - var columns = new List(); - if (jArray is null) - return columns; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) - { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadColumn column = - Archicad.Converters.Utils.ConvertDTOs(jToken); + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadColumn column = + Archicad.Converters.Utils.ConvertDTOs(jToken); - column.units = Units.Meters; - column.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == column.applicationId).model - ); - column.baseLine = new Line(column.origoPos, column.origoPos + new Point(0, 0, column.height)); - columns.Add(column); - } + column.units = Units.Meters; + column.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == column.applicationId).model + ); + column.baseLine = new Line(column.origoPos, column.origoPos + new Point(0, 0, column.height)); + columns.Add(column); } - - return columns; } + + return columns; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs index 2ae21e6294..cf2915958b 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs @@ -13,98 +13,104 @@ using Speckle.Core.Models.GraphTraversal; using Speckle.Newtonsoft.Json.Linq; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class DirectShape : IConverter { - public sealed class DirectShape : IConverter - { - #region --- Properties --- + #region --- Properties --- - public Type Type => typeof(Objects.BuiltElements.Archicad.DirectShape); + public Type Type => typeof(Objects.BuiltElements.Archicad.DirectShape); - #endregion + #endregion - #region --- Functions --- + #region --- Functions --- + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) + { + var directShapes = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var directShapes = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); - - switch (tc.current) - { - case Objects.BuiltElements.Archicad.DirectShape directShape: - // get the geometry - MeshModel meshModel = null; + token.ThrowIfCancellationRequested(); + switch (tc.current) + { + case Objects.BuiltElements.Archicad.DirectShape directShape: + // get the geometry + MeshModel meshModel = null; + + { + List meshes = null; + var m = directShape["displayValue"] ?? directShape["@displayValue"]; + if (m is List) { - List meshes = null; - var m = directShape["displayValue"] ?? directShape["@displayValue"]; - if (m is List) - meshes = (List)m; - else if (m is List) - meshes = ((List)m).Cast().ToList(); - - if (meshes == null) - continue; + meshes = (List)m; + } + else if (m is List) + { + meshes = ((List)m).Cast().ToList(); + } - meshModel = ModelConverter.MeshToNative(meshes); + if (meshes == null) + { + continue; } - directShape["model"] = meshModel; - directShapes.Add(directShape); - break; - } + meshModel = ModelConverter.MeshToNative(meshes); + } + + directShape["model"] = meshModel; + directShapes.Add(directShape); + break; } } + } - IEnumerable result; - result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateDirectShape(directShapes), token); - return result is null ? new List() : result.ToList(); + IEnumerable result; + result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateDirectShape(directShapes), token); + return result is null ? new List() : result.ToList(); + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetElementBaseData(elementModels.Select(e => e.applicationId)), + token + ); + + var directShapes = new List(); + if (data is null) + { + return directShapes; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetElementBaseData(elementModels.Select(e => e.applicationId)), - token - ); - - var directShapes = new List(); - if (data is null) - return directShapes; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Objects.BuiltElements.Archicad.DirectShape directShape in data) { - foreach (Objects.BuiltElements.Archicad.DirectShape directShape in data) { - { - directShape.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == directShape.applicationId).model - ); - directShapes.Add(directShape); - } + directShape.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == directShape.applicationId).model + ); + directShapes.Add(directShape); } } - - return directShapes; } - #endregion + return directShapes; } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DoorConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DoorConverter.cs index 79e3e1f6df..6a937fc4a1 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DoorConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DoorConverter.cs @@ -11,79 +11,79 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Door : IConverter { - public sealed class Door : IConverter + public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadDoor); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadDoor); + var doors = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var doors = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadDoor archicadDoor: - archicadDoor.parentApplicationId = tc.parent.current.id; - doors.Add(archicadDoor); - break; - //case Objects.BuiltElements.Opening window: - // var baseLine = (Line)wall.baseLine; - // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), - // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); - // if (el is RevitWall revitWall) - // newWall.flipped = revitWall.flipped; - // walls.Add(newWall); - // break; - } + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadDoor archicadDoor: + archicadDoor.parentApplicationId = tc.parent.current.id; + doors.Add(archicadDoor); + break; + //case Objects.BuiltElements.Opening window: + // var baseLine = (Line)wall.baseLine; + // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), + // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); + // if (el is RevitWall revitWall) + // newWall.flipped = revitWall.flipped; + // walls.Add(newWall); + // break; } } + } + + IEnumerable result; + result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateDoor(doors), token); - IEnumerable result; - result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateDoor(doors), token); + return result is null ? new List() : result.ToList(); + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetDoorData(elementModels.Select(e => e.applicationId)) + ); - return result is null ? new List() : result.ToList(); + var openings = new List(); + if (data is null) + { + return openings; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetDoorData(elementModels.Select(e => e.applicationId)) - ); - - var openings = new List(); - if (data is null) - return openings; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Objects.BuiltElements.Archicad.ArchicadDoor subelement in data) { - foreach (Objects.BuiltElements.Archicad.ArchicadDoor subelement in data) - { - subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == subelement.applicationId).model - ); - openings.Add(subelement); - } + subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == subelement.applicationId).model + ); + openings.Add(subelement); } - - return openings; } + + return openings; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/FloorConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/FloorConverter.cs index 99e9b2829f..c3b67f21e2 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/FloorConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/FloorConverter.cs @@ -9,36 +9,37 @@ using Speckle.Core.Kits; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Floor : IConverter { - public sealed class Floor : IConverter + public Type Type => typeof(Objects.BuiltElements.Floor); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Floor); + var floors = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var floors = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadFloor archiFloor: - floors.Add(archiFloor); - break; - case Objects.BuiltElements.Floor floor: + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadFloor archiFloor: + floors.Add(archiFloor); + break; + case Objects.BuiltElements.Floor floor: - Objects.BuiltElements.Archicad.ArchicadFloor newFloor = new Objects.BuiltElements.Archicad.ArchicadFloor + Objects.BuiltElements.Archicad.ArchicadFloor newFloor = + new() { id = floor.id, applicationId = floor.applicationId, @@ -46,54 +47,57 @@ CancellationToken token shape = Utils.PolycurvesToElementShape(floor.outline, floor.voids) }; - floors.Add(newFloor); - break; - } + floors.Add(newFloor); + break; } } + } + + IEnumerable result; + result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateFloor(floors), token); - IEnumerable result; - result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateFloor(floors), token); + return result is null ? new List() : result.ToList(); + ; + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetFloorData(elements.Select(e => e.applicationId)), + token + ); - return result is null ? new List() : result.ToList(); - ; + var floors = new List(); + if (jArray is null) + { + return floors; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetFloorData(elements.Select(e => e.applicationId)), - token - ); - - var floors = new List(); - if (jArray is null) - return floors; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) - { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadFloor slab = - Archicad.Converters.Utils.ConvertDTOs(jToken); + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadFloor slab = + Archicad.Converters.Utils.ConvertDTOs(jToken); - slab.units = Units.Meters; - slab.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elements.First(e => e.applicationId == slab.applicationId).model - ); - slab.outline = Utils.PolycurveToSpeckle(slab.shape.contourPolyline); - if (slab.shape.holePolylines?.Count > 0) - slab.voids = new List(slab.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); - floors.Add(slab); + slab.units = Units.Meters; + slab.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elements.First(e => e.applicationId == slab.applicationId).model + ); + slab.outline = Utils.PolycurveToSpeckle(slab.shape.contourPolyline); + if (slab.shape.holePolylines?.Count > 0) + { + slab.voids = new List(slab.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); } - } - return floors; + floors.Add(slab); + } } + + return floors; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/GridLineConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/GridLineConverter.cs index 4b5c923516..d4c075f86a 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/GridLineConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/GridLineConverter.cs @@ -10,128 +10,127 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class GridLineConverter : IConverter { - public sealed class GridLineConverter : IConverter + public Type Type => typeof(Archicad.GridElement); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Archicad.GridElement); + var archicadGridElements = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var archicadGridElements = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.GridLine grid: + switch (tc.current) + { + case Objects.BuiltElements.GridLine grid: - Archicad.GridElement archicadGridElement = new Archicad.GridElement + Archicad.GridElement archicadGridElement = + new() { id = grid.id, applicationId = grid.applicationId, markerText = grid.label }; - if (grid.baseLine is Line) - { - var baseLine = (Line)grid.baseLine; - archicadGridElement.begin = Utils.ScaleToNative(baseLine.start); - archicadGridElement.end = Utils.ScaleToNative(baseLine.end); - archicadGridElement.isArc = false; - } - else if (grid.baseLine is Arc) - { - var baseLine = (Arc)grid.baseLine; - archicadGridElement.begin = Utils.ScaleToNative(baseLine.startPoint); - archicadGridElement.end = Utils.ScaleToNative(baseLine.endPoint); - archicadGridElement.arcAngle = baseLine.angleRadians; - archicadGridElement.isArc = true; - } - - archicadGridElements.Add(archicadGridElement); - break; - } + if (grid.baseLine is Line) + { + var baseLine = (Line)grid.baseLine; + archicadGridElement.begin = Utils.ScaleToNative(baseLine.start); + archicadGridElement.end = Utils.ScaleToNative(baseLine.end); + archicadGridElement.isArc = false; + } + else if (grid.baseLine is Arc) + { + var baseLine = (Arc)grid.baseLine; + archicadGridElement.begin = Utils.ScaleToNative(baseLine.startPoint); + archicadGridElement.end = Utils.ScaleToNative(baseLine.endPoint); + archicadGridElement.arcAngle = baseLine.angleRadians; + archicadGridElement.isArc = true; + } + + archicadGridElements.Add(archicadGridElement); + break; } } + } + + var result = await AsyncCommandProcessor.Execute( + new Communication.Commands.CreateGridElement(archicadGridElements), + token + ); + + return result is null ? new List() : result.ToList(); + } - var result = await AsyncCommandProcessor.Execute( - new Communication.Commands.CreateGridElement(archicadGridElements), - token - ); + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetGridElementData(elementModels.Select(e => e.applicationId)), + token + ); - return result is null ? new List() : result.ToList(); + if (data is null) + { + return new List(); } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetGridElementData(elementModels.Select(e => e.applicationId)), - token - ); - - if (data is null) + List gridlines = new(); + foreach (Archicad.GridElement archicadGridElement in data) { - return new List(); - } + Objects.BuiltElements.GridLine speckleGridLine = new(); - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) - { - List gridlines = new List(); - foreach (Archicad.GridElement archicadGridElement in data) + // convert from Archicad to Speckle data structure + // Speckle base properties + speckleGridLine.id = archicadGridElement.id; + speckleGridLine.applicationId = archicadGridElement.applicationId; + speckleGridLine.label = archicadGridElement.markerText; + speckleGridLine.units = Units.Meters; + + // Archicad properties + // elementType and classifications do not exist in Objects.BuiltElements.GridLine + //speckleGrid.elementType = archicadGridElement.elementType; + //speckleGrid.classifications = archicadGridElement.classifications; + + if (!archicadGridElement.isArc) + { + speckleGridLine.baseLine = new Line(archicadGridElement.begin, archicadGridElement.end); + } + else { - Objects.BuiltElements.GridLine speckleGridLine = new Objects.BuiltElements.GridLine(); - - // convert from Archicad to Speckle data structure - // Speckle base properties - speckleGridLine.id = archicadGridElement.id; - speckleGridLine.applicationId = archicadGridElement.applicationId; - speckleGridLine.label = archicadGridElement.markerText; - speckleGridLine.units = Units.Meters; - - // Archicad properties - // elementType and classifications do not exist in Objects.BuiltElements.GridLine - //speckleGrid.elementType = archicadGridElement.elementType; - //speckleGrid.classifications = archicadGridElement.classifications; - - if (!archicadGridElement.isArc) - { - speckleGridLine.baseLine = new Line(archicadGridElement.begin, archicadGridElement.end); - } - else - { - speckleGridLine.baseLine = new Arc( - archicadGridElement.begin, - archicadGridElement.end, - archicadGridElement.arcAngle - ); - } - - speckleGridLine.displayValue = Operations.ModelConverter - .MeshesAndLinesToSpeckle(elementModels.First(e => e.applicationId == archicadGridElement.applicationId).model) - .Cast() - .ToList(); - - gridlines.Add(speckleGridLine); + speckleGridLine.baseLine = new Arc( + archicadGridElement.begin, + archicadGridElement.end, + archicadGridElement.arcAngle + ); } - return gridlines; + speckleGridLine.displayValue = Operations.ModelConverter + .MeshesAndLinesToSpeckle(elementModels.First(e => e.applicationId == archicadGridElement.applicationId).model) + .Cast() + .ToList(); + + gridlines.Add(speckleGridLine); } + + return gridlines; } } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/IElementConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/IElementConverter.cs index 591e190216..ddcec831ee 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/IElementConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/IElementConverter.cs @@ -5,22 +5,21 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public interface IConverter { - public interface IConverter - { - #region --- Properties --- + #region --- Properties --- - Type Type { get; } + Type Type { get; } - #endregion + #endregion - #region --- Functions --- + #region --- Functions --- - Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token); + Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token); - Task> ConvertToArchicad(IEnumerable elements, CancellationToken token); + Task> ConvertToArchicad(IEnumerable elements, CancellationToken token); - #endregion - } + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ObjectConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ObjectConverter.cs index f4ead7ce15..af19245732 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ObjectConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/ObjectConverter.cs @@ -14,126 +14,149 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Object : IConverter { - public sealed class Object : IConverter - { - #region --- Properties --- + #region --- Properties --- - public Type Type => null; + public Type Type => null; - private const string _cumulativeTransformKey = "cumulativeTransformId"; + private const string _cumulativeTransformKey = "cumulativeTransformId"; - #endregion + #endregion - #region --- Functions --- + #region --- Functions --- - static List GetMesh(Base element) + static List GetMesh(Base element) + { + List meshes = new(); + if (element is Mesh mesh) { - List meshes = new List(); - if (element is Mesh mesh) - meshes.Add(mesh); - - return meshes; + meshes.Add(mesh); } - public sealed class ArchicadGeometryCollectorContext : TraversalContext - { - public string cumulativeTransformKey { get; set; } + return meshes; + } - public ArchicadGeometryCollectorContext(Base current, string? propName = null, ArchicadGeometryCollectorContext? parent = default) - : base(current, propName, parent) - { - } - } + public sealed class ArchicadGeometryCollectorContext : TraversalContext + { + public string cumulativeTransformKey { get; set; } - public sealed class ArchicadGeometryCollector : GraphTraversal - { - public ArchicadGeometryCollector(params ITraversalRule[] traversalRule) : base(traversalRule) { } + public ArchicadGeometryCollectorContext( + Base current, + string? propName = null, + ArchicadGeometryCollectorContext? parent = default + ) + : base(current, propName, parent) { } + } - protected override ArchicadGeometryCollectorContext NewContext(Base current, string? propName, ArchicadGeometryCollectorContext? parent) - { - return new ArchicadGeometryCollectorContext(current, propName, parent); - } + public sealed class ArchicadGeometryCollector : GraphTraversal + { + public ArchicadGeometryCollector(params ITraversalRule[] traversalRule) + : base(traversalRule) { } + + protected override ArchicadGeometryCollectorContext NewContext( + Base current, + string? propName, + ArchicadGeometryCollectorContext? parent + ) + { + return new ArchicadGeometryCollectorContext(current, propName, parent); } + } - public static ArchicadGeometryCollector CreateArchicadGeometryCollectorFunc(Base root) + public static ArchicadGeometryCollector CreateArchicadGeometryCollectorFunc(Base root) + { + IEnumerable AllAliases(Base @base) { - IEnumerable AllAliases(Base @base) - { - List membersToTraverse = new List(); + List membersToTraverse = new(); - // hosted elements traversals + // hosted elements traversals + { + // #1: via the "elements" field of definition classes, but don't traverse the "elements" field of the root (it is traversed by the main element traversal) + if (root != @base) { - // #1: via the "elements" field of definition classes, but don't traverse the "elements" field of the root (it is traversed by the main element traversal) - if (root != @base) - membersToTraverse.AddRange(DefaultTraversal.elementsPropAliases); - - // #2: BlockInstance elements could be also in geometry field - membersToTraverse.AddRange(DefaultTraversal.geometryPropAliases); + membersToTraverse.AddRange(DefaultTraversal.elementsPropAliases); } - // instance <-> definition traversal - { - membersToTraverse.AddRange(DefaultTraversal.definitionPropAliases); - } + // #2: BlockInstance elements could be also in geometry field + membersToTraverse.AddRange(DefaultTraversal.geometryPropAliases); + } - // geometry traversals - { - // #1: visiting the elements in "displayValue" field - membersToTraverse.AddRange(DefaultTraversal.displayValuePropAliases); + // instance <-> definition traversal + { + membersToTraverse.AddRange(DefaultTraversal.definitionPropAliases); + } - // #2: visiting the elements in "geometry" field - membersToTraverse.AddRange(DefaultTraversal.geometryPropAliases); // already added before - } + // geometry traversals + { + // #1: visiting the elements in "displayValue" field + membersToTraverse.AddRange(DefaultTraversal.displayValuePropAliases); - return membersToTraverse; + // #2: visiting the elements in "geometry" field + membersToTraverse.AddRange(DefaultTraversal.geometryPropAliases); // already added before } - var traversalRule = TraversalRule.NewTraversalRule().When(_ => true).ContinueTraversing(AllAliases); - - return new ArchicadGeometryCollector(traversalRule); + return membersToTraverse; } - private static TraversalContext StoreTransformationMatrix(ArchicadGeometryCollectorContext tc, Dictionary transformMatrixById) + var traversalRule = TraversalRule.NewTraversalRule().When(_ => true).ContinueTraversing(AllAliases); + + return new ArchicadGeometryCollector(traversalRule); + } + + private static TraversalContext StoreTransformationMatrix( + ArchicadGeometryCollectorContext tc, + Dictionary transformMatrixById + ) + { + if (tc.parent != null) { - if (tc.parent != null) + TraversalContext root = tc.parent; + while (root.parent != null) { - TraversalContext root = tc.parent; - while (root.parent != null) - root = root.parent; - - // transform appleid only elements via the "definition" property (not via "elements" property) - // and root elements transform is skipped, because it will be added on GDL level - var currentTransform = (tc.parent.current != root.current && (tc.parent.current["transform"] is Transform) && DefaultTraversal.definitionPropAliases.Contains (tc.propName)) - ? (Transform)(tc.parent.current["transform"]) - : new Transform(); - - string parentCumulativeTransformId = (tc.parent as ArchicadGeometryCollectorContext).cumulativeTransformKey; - string cumulativeTransformId = Utilities.HashString(parentCumulativeTransformId + currentTransform.id); - tc.cumulativeTransformKey = cumulativeTransformId; - transformMatrixById.TryAdd( - cumulativeTransformId, - transformMatrixById[parentCumulativeTransformId] * currentTransform - ); + root = root.parent; } - else - { - tc.cumulativeTransformKey = ""; - transformMatrixById.TryAdd("", new Transform()); - } - return tc; - } - private static List Store( - TraversalContext tc, - Dictionary transformMatrixById, - Dictionary transformedMeshById - ) + // transform appleid only elements via the "definition" property (not via "elements" property) + // and root elements transform is skipped, because it will be added on GDL level + var currentTransform = + ( + tc.parent.current != root.current + && (tc.parent.current["transform"] is Transform) + && DefaultTraversal.definitionPropAliases.Contains(tc.propName) + ) + ? (Transform)(tc.parent.current["transform"]) + : new Transform(); + + string parentCumulativeTransformId = (tc.parent as ArchicadGeometryCollectorContext).cumulativeTransformKey; + string cumulativeTransformId = Utilities.HashString(parentCumulativeTransformId + currentTransform.id); + tc.cumulativeTransformKey = cumulativeTransformId; + transformMatrixById.TryAdd( + cumulativeTransformId, + transformMatrixById[parentCumulativeTransformId] * currentTransform + ); + } + else { - var meshes = GetMesh(tc.current); + tc.cumulativeTransformKey = ""; + transformMatrixById.TryAdd("", new Transform()); + } + return tc; + } + + private static List Store( + TraversalContext tc, + Dictionary transformMatrixById, + Dictionary transformedMeshById + ) + { + var meshes = GetMesh(tc.current); - return meshes.Select(mesh => { + return meshes + .Select(mesh => + { string cumulativeTransformId = (tc as ArchicadGeometryCollectorContext).cumulativeTransformKey; var transformedMeshId = Utilities.HashString(cumulativeTransformId + mesh.id); if (!transformedMeshById.TryGetValue(transformedMeshId, out Mesh transformedMesh)) @@ -144,91 +167,91 @@ Dictionary transformedMeshById transformedMeshById.Add(transformedMeshId, transformedMesh); } return transformedMeshId; - }).ToList(); - } + }) + .ToList(); + } - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) + { + var archicadObjects = new List(); + var meshModels = new List(); + var transformMatrixById = new Dictionary(); + var transformedMeshById = new Dictionary(); + + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, "Object") ) { - var archicadObjects = new List(); - var meshModels = new List(); - var transformMatrixById = new Dictionary(); - var transformedMeshById = new Dictionary(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, "Object") - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - var element = tc.current; + var element = tc.current; - // base point - var basePoint = new Point(0, 0, 0); - // var specialKeys = element.GetMembers(); - var transform = (Transform)(element["transform"]) ?? new Transform(); + // base point + var basePoint = new Point(0, 0, 0); + // var specialKeys = element.GetMembers(); + var transform = (Transform)(element["transform"]) ?? new Transform(); - // todo Speckle schema - //if (specialKeys.ContainsKey("basePoint")) - // basePoint = (Point)element["basePoint"]; + // todo Speckle schema + //if (specialKeys.ContainsKey("basePoint")) + // basePoint = (Point)element["basePoint"]; - List meshIdHashes; - { - ArchicadGeometryCollector collector = CreateArchicadGeometryCollectorFunc(element); - meshIdHashes = collector.Traverse(element) - .Select(tc => StoreTransformationMatrix(tc, transformMatrixById)) - .SelectMany(tc => Store(tc, transformMatrixById, transformedMeshById)) - .ToList(); - - if (meshIdHashes == null) - continue; - } - - // if the same geometry representation is not used before - if (!archicadObjects.Any(archicadObject => archicadObject.modelIds.SequenceEqual(meshIdHashes))) + List meshIdHashes; + { + ArchicadGeometryCollector collector = CreateArchicadGeometryCollectorFunc(element); + meshIdHashes = collector + .Traverse(element) + .Select(tc => StoreTransformationMatrix(tc, transformMatrixById)) + .SelectMany(tc => Store(tc, transformMatrixById, transformedMeshById)) + .ToList(); + + if (meshIdHashes == null) { - var meshes = meshIdHashes.ConvertAll(meshIdHash => transformedMeshById[meshIdHash]); - var meshModel = ModelConverter.MeshToNative(meshes); - meshModels.Add(meshModel); + continue; } + } - var newObject = new Archicad.ArchicadObject - { - id = element.id, - applicationId = element.applicationId, - pos = Utils.ScaleToNative(basePoint), - transform = new Objects.Other.Transform(transform.ConvertToUnits(Units.Meters), Units.Meters), - modelIds = meshIdHashes, - level = element["level"] as Objects.BuiltElements.Archicad.ArchicadLevel, - classifications = element["classifications"] as List - }; - - archicadObjects.Add(newObject); + // if the same geometry representation is not used before + if (!archicadObjects.Any(archicadObject => archicadObject.modelIds.SequenceEqual(meshIdHashes))) + { + var meshes = meshIdHashes.ConvertAll(meshIdHash => transformedMeshById[meshIdHash]); + var meshModel = ModelConverter.MeshToNative(meshes); + meshModels.Add(meshModel); } - } - IEnumerable result; - result = await AsyncCommandProcessor.Execute( - new Communication.Commands.CreateObject(archicadObjects, meshModels), - token - ); - return result is null ? new List() : result.ToList(); + var newObject = new Archicad.ArchicadObject + { + id = element.id, + applicationId = element.applicationId, + pos = Utils.ScaleToNative(basePoint), + transform = new Objects.Other.Transform(transform.ConvertToUnits(Units.Meters), Units.Meters), + modelIds = meshIdHashes, + level = element["level"] as Objects.BuiltElements.Archicad.ArchicadLevel, + classifications = element["classifications"] as List + }; + + archicadObjects.Add(newObject); + } } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token - ) - { - // Objects not stored on the server - return new List(); - } + IEnumerable result; + result = await AsyncCommandProcessor.Execute( + new Communication.Commands.CreateObject(archicadObjects, meshModels), + token + ); + return result is null ? new List() : result.ToList(); + } - #endregion + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + // Objects not stored on the server + return new List(); } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoofConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoofConverter.cs index 8e02eb8ea6..2d423c6047 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoofConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoofConverter.cs @@ -10,147 +10,153 @@ using Speckle.Core.Kits; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Roof : IConverter { - public sealed class Roof : IConverter + public Type Type => typeof(Objects.BuiltElements.Roof); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Roof); + var roofs = new List(); + var shells = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var roofs = new List(); - var shells = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadRoof archiRoof: - roofs.Add(archiRoof); - break; - case Objects.BuiltElements.Archicad.ArchicadShell archiShell: - shells.Add(archiShell); - break; - case Objects.BuiltElements.Roof roof: - roofs.Add( - new Objects.BuiltElements.Archicad.ArchicadRoof - { - id = roof.id, - applicationId = roof.applicationId, - archicadLevel = Archicad.Converters.Utils.ConvertLevel(roof.level), - shape = Utils.PolycurvesToElementShape(roof.outline, roof.voids) - } - ); - break; - } + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadRoof archiRoof: + roofs.Add(archiRoof); + break; + case Objects.BuiltElements.Archicad.ArchicadShell archiShell: + shells.Add(archiShell); + break; + case Objects.BuiltElements.Roof roof: + roofs.Add( + new Objects.BuiltElements.Archicad.ArchicadRoof + { + id = roof.id, + applicationId = roof.applicationId, + archicadLevel = Archicad.Converters.Utils.ConvertLevel(roof.level), + shape = Utils.PolycurvesToElementShape(roof.outline, roof.voids) + } + ); + break; } } + } - var resultRoofs = - roofs.Count > 0 - ? await AsyncCommandProcessor.Execute(new Communication.Commands.CreateRoof(roofs), token) - : null; - var resultShells = - shells.Count > 0 - ? await AsyncCommandProcessor.Execute(new Communication.Commands.CreateShell(shells), token) - : null; - - var result = new List(); - if (resultRoofs is not null) - result.AddRange(resultRoofs.ToList()); - - if (resultShells is not null) - result.AddRange(resultShells.ToList()); + var resultRoofs = + roofs.Count > 0 ? await AsyncCommandProcessor.Execute(new Communication.Commands.CreateRoof(roofs), token) : null; + var resultShells = + shells.Count > 0 + ? await AsyncCommandProcessor.Execute(new Communication.Commands.CreateShell(shells), token) + : null; - return result is null ? new List() : result; + var result = new List(); + if (resultRoofs is not null) + { + result.AddRange(resultRoofs.ToList()); } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token - ) + if (resultShells is not null) { - Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetRoofData(elements.Select(e => e.applicationId)), - token - ); + result.AddRange(resultShells.ToList()); + } + + return result is null ? new List() : result; + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetRoofData(elements.Select(e => e.applicationId)), + token + ); - var roofs = new List(); - if (jArray is not null) + var roofs = new List(); + if (jArray is not null) + { + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) + ) { - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) - { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadRoof roof = - Archicad.Converters.Utils.ConvertDTOs(jToken); + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadRoof roof = + Archicad.Converters.Utils.ConvertDTOs(jToken); - roof.units = Units.Meters; - roof.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elements.First(e => e.applicationId == roof.applicationId).model - ); + roof.units = Units.Meters; + roof.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elements.First(e => e.applicationId == roof.applicationId).model + ); - if (roof.shape != null) + if (roof.shape != null) + { + roof.outline = Utils.PolycurveToSpeckle(roof.shape.contourPolyline); + if (roof.shape.holePolylines?.Count > 0) { - roof.outline = Utils.PolycurveToSpeckle(roof.shape.contourPolyline); - if (roof.shape.holePolylines?.Count > 0) - roof.voids = new List(roof.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); + roof.voids = new List(roof.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); } - - roofs.Add(roof); } + + roofs.Add(roof); } } + } - jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetShellData(elements.Select(e => e.applicationId)), - token - ); + jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetShellData(elements.Select(e => e.applicationId)), + token + ); - var shells = new List(); - if (jArray is not null) + var shells = new List(); + if (jArray is not null) + { + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) + ) { - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) - { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadShell shell = - Archicad.Converters.Utils.ConvertDTOs(jToken); + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadShell shell = + Archicad.Converters.Utils.ConvertDTOs(jToken); - shell.units = Units.Meters; - shell.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elements.First(e => e.applicationId == shell.applicationId).model - ); + shell.units = Units.Meters; + shell.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elements.First(e => e.applicationId == shell.applicationId).model + ); - if (shell.shape != null) + if (shell.shape != null) + { + shell.outline = Utils.PolycurveToSpeckle(shell.shape.contourPolyline); + if (shell.shape.holePolylines?.Count > 0) { - shell.outline = Utils.PolycurveToSpeckle(shell.shape.contourPolyline); - if (shell.shape.holePolylines?.Count > 0) - shell.voids = new List(shell.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); + shell.voids = new List(shell.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); } - - shells.Add(shell); } + + shells.Add(shell); } } - - var result = roofs; - result.AddRange(shells); - return result; } + + var result = roofs; + result.AddRange(shells); + return result; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoomConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoomConverter.cs index 01cbcc64e4..792b261899 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoomConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/RoomConverter.cs @@ -14,34 +14,35 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Room : IConverter { - public sealed class Room : IConverter + public Type Type => typeof(Archicad.Room); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Archicad.Room); + var rooms = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var rooms = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadRoom speckleRoom: + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadRoom speckleRoom: - { - Archicad.Room archicadRoom = new Archicad.Room + { + Archicad.Room archicadRoom = + new() { // convert from Speckle to Archicad data structure // Speckle base properties @@ -58,13 +59,14 @@ CancellationToken token shape = speckleRoom.shape }; - rooms.Add(archicadRoom); - } - break; - case Objects.BuiltElements.Room speckleRoom: + rooms.Add(archicadRoom); + } + break; + case Objects.BuiltElements.Room speckleRoom: - { - Archicad.Room archicadRoom = new Archicad.Room + { + Archicad.Room archicadRoom = + new() { // Speckle base properties id = speckleRoom.id, @@ -77,76 +79,78 @@ CancellationToken token shape = Utils.PolycurvesToElementShape(speckleRoom.outline, speckleRoom.voids) }; - rooms.Add(archicadRoom); - } - break; - } + rooms.Add(archicadRoom); + } + break; } } + } - var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateRoom(rooms), token); + var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateRoom(rooms), token); + + return result is null ? new List() : result.ToList(); + } - return result is null ? new List() : result.ToList(); + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetRoomData(elementModels.Select(e => e.applicationId)), + token + ); + + var rooms = new List(); + if (data is null) + { + return rooms; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetRoomData(elementModels.Select(e => e.applicationId)), - token - ); - - var rooms = new List(); - if (data is null) - return rooms; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Archicad.Room archicadRoom in data) { - foreach (Archicad.Room archicadRoom in data) + Objects.BuiltElements.Archicad.ArchicadRoom speckleRoom = new(); + + // convert from Archicad to Speckle data structure + // Speckle base properties + speckleRoom.id = archicadRoom.id; + speckleRoom.applicationId = archicadRoom.applicationId; + speckleRoom.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == archicadRoom.applicationId).model + ); + speckleRoom.units = Units.Meters; + + // Archicad properties + speckleRoom.elementType = archicadRoom.elementType; + speckleRoom.classifications = archicadRoom.classifications; + speckleRoom.archicadLevel = archicadRoom.level; + speckleRoom.height = archicadRoom.height ?? .0; + speckleRoom.shape = archicadRoom.shape; + + // downdgrade + speckleRoom.name = archicadRoom.name; + speckleRoom.number = archicadRoom.number; + speckleRoom.area = archicadRoom.area ?? .0; + speckleRoom.volume = archicadRoom.volume ?? .0; + + ElementShape.Polyline polyLine = archicadRoom.shape.contourPolyline; + Polycurve polycurve = Utils.PolycurveToSpeckle(polyLine); + speckleRoom.outline = polycurve; + if (archicadRoom.shape.holePolylines?.Count > 0) { - Objects.BuiltElements.Archicad.ArchicadRoom speckleRoom = new Objects.BuiltElements.Archicad.ArchicadRoom(); - - // convert from Archicad to Speckle data structure - // Speckle base properties - speckleRoom.id = archicadRoom.id; - speckleRoom.applicationId = archicadRoom.applicationId; - speckleRoom.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == archicadRoom.applicationId).model - ); - speckleRoom.units = Units.Meters; - - // Archicad properties - speckleRoom.elementType = archicadRoom.elementType; - speckleRoom.classifications = archicadRoom.classifications; - speckleRoom.archicadLevel = archicadRoom.level; - speckleRoom.height = archicadRoom.height ?? .0; - speckleRoom.shape = archicadRoom.shape; - - // downdgrade - speckleRoom.name = archicadRoom.name; - speckleRoom.number = archicadRoom.number; - speckleRoom.area = archicadRoom.area ?? .0; - speckleRoom.volume = archicadRoom.volume ?? .0; - - ElementShape.Polyline polyLine = archicadRoom.shape.contourPolyline; - Polycurve polycurve = Utils.PolycurveToSpeckle(polyLine); - speckleRoom.outline = polycurve; - if (archicadRoom.shape.holePolylines?.Count > 0) - speckleRoom.voids = new List(archicadRoom.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); - - // calculate base point - speckleRoom.basePoint = archicadRoom.basePoint; - - rooms.Add(speckleRoom); + speckleRoom.voids = new List(archicadRoom.shape.holePolylines.Select(Utils.PolycurveToSpeckle)); } - } - return rooms; + // calculate base point + speckleRoom.basePoint = archicadRoom.basePoint; + + rooms.Add(speckleRoom); + } } + + return rooms; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/SkylightConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/SkylightConverter.cs index 4ce5effa85..ddb6a116dc 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/SkylightConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/SkylightConverter.cs @@ -11,79 +11,79 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Skylight : IConverter { - public sealed class Skylight : IConverter + public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadSkylight); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadSkylight); + var skylights = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var skylights = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadSkylight archicadSkylight: - archicadSkylight.parentApplicationId = tc.parent.current.id; - skylights.Add(archicadSkylight); - break; - //case Objects.BuiltElements.Opening skylight: - // var baseLine = (Line)wall.baseLine; - // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), - // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); - // if (el is RevitWall revitWall) - // newWall.flipped = revitWall.flipped; - // walls.Add(newWall); - // break; - } + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadSkylight archicadSkylight: + archicadSkylight.parentApplicationId = tc.parent.current.id; + skylights.Add(archicadSkylight); + break; + //case Objects.BuiltElements.Opening skylight: + // var baseLine = (Line)wall.baseLine; + // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), + // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); + // if (el is RevitWall revitWall) + // newWall.flipped = revitWall.flipped; + // walls.Add(newWall); + // break; } } + } + + var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateSkylight(skylights), token); - var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateSkylight(skylights), token); + return result is null ? new List() : result.ToList(); + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + // Get subelements + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetSkylightData(elementModels.Select(e => e.applicationId)) + ); - return result is null ? new List() : result.ToList(); + var openings = new List(); + if (data is null) + { + return openings; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - // Get subelements - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetSkylightData(elementModels.Select(e => e.applicationId)) - ); - - var openings = new List(); - if (data is null) - return openings; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Objects.BuiltElements.Archicad.ArchicadSkylight subelement in data) { - foreach (Objects.BuiltElements.Archicad.ArchicadSkylight subelement in data) - { - subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == subelement.applicationId).model - ); - openings.Add(subelement); - } + subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == subelement.applicationId).model + ); + openings.Add(subelement); } - - return openings; } + + return openings; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs index 1aff4bdcd3..ba1b6aed5d 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs @@ -9,170 +9,171 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Archicad.Converters +namespace Archicad.Converters; + +public static class Utils { - public static class Utils + public static Point VertexToPoint(MeshModel.Vertex vertex) { - public static Point VertexToPoint(MeshModel.Vertex vertex) + return new Point { - return new Point - { - x = vertex.x, - y = vertex.y, - z = vertex.z - }; - } + x = vertex.x, + y = vertex.y, + z = vertex.z + }; + } - public static Vector VertexToVector(MeshModel.Vertex vertex) + public static Vector VertexToVector(MeshModel.Vertex vertex) + { + return new Vector { - return new Vector - { - x = vertex.x, - y = vertex.y, - z = vertex.z - }; - } + x = vertex.x, + y = vertex.y, + z = vertex.z + }; + } - public static System.Numerics.Vector3 VertexToVector3(MeshModel.Vertex vertex) + public static System.Numerics.Vector3 VertexToVector3(MeshModel.Vertex vertex) + { + return new System.Numerics.Vector3 { - return new System.Numerics.Vector3 - { - X = (float)vertex.x, - Y = (float)vertex.y, - Z = (float)vertex.z - }; - } + X = (float)vertex.x, + Y = (float)vertex.y, + Z = (float)vertex.z + }; + } - public static Point ScaleToNative(Point point, string? units = null) - { - units ??= point.units; - var scale = Units.GetConversionFactor(units, Units.Meters); + public static Point ScaleToNative(Point point, string? units = null) + { + units ??= point.units; + var scale = Units.GetConversionFactor(units, Units.Meters); - return new Point(point.x * scale, point.y * scale, point.z * scale); - } + return new Point(point.x * scale, point.y * scale, point.z * scale); + } - public static double ScaleToNative(double value, string sourceUnits) - { - return value * Units.GetConversionFactor(sourceUnits, Units.Meters); - } + public static double ScaleToNative(double value, string sourceUnits) + { + return value * Units.GetConversionFactor(sourceUnits, Units.Meters); + } - public static MeshModel.Vertex PointToNative(Point point, string? units = null) - { - units ??= point.units; - var scale = Units.GetConversionFactor(units, Units.Meters); - - return new MeshModel.Vertex - { - x = point.x * scale, - y = point.y * scale, - z = point.z * scale - }; - } + public static MeshModel.Vertex PointToNative(Point point, string? units = null) + { + units ??= point.units; + var scale = Units.GetConversionFactor(units, Units.Meters); - public static Polycurve PolycurveToSpeckle(ElementShape.Polyline archiPolyline) + return new MeshModel.Vertex { - var poly = new Polycurve - { - units = Units.Meters, - closed = archiPolyline.polylineSegments.First().startPoint == archiPolyline.polylineSegments.Last().endPoint - }; - foreach (var segment in archiPolyline.polylineSegments) - { - poly.segments.Add( - segment.arcAngle == 0 - ? new Line(segment.startPoint, segment.endPoint) - : new Arc(segment.startPoint, segment.endPoint, segment.arcAngle) - ); - } - - return poly; - } + x = point.x * scale, + y = point.y * scale, + z = point.z * scale + }; + } - public static ElementShape.PolylineSegment LineToNative(Line line) + public static Polycurve PolycurveToSpeckle(ElementShape.Polyline archiPolyline) + { + var poly = new Polycurve { - return new ElementShape.PolylineSegment(ScaleToNative(line.start), ScaleToNative(line.end)); - } - - public static ElementShape.Polyline PolycurveToNative(Polycurve polycurve) + units = Units.Meters, + closed = archiPolyline.polylineSegments.First().startPoint == archiPolyline.polylineSegments.Last().endPoint + }; + foreach (var segment in archiPolyline.polylineSegments) { - var segments = polycurve.segments.Select(CurveSegmentToNative).ToList(); - return new ElementShape.Polyline(segments); + poly.segments.Add( + segment.arcAngle == 0 + ? new Line(segment.startPoint, segment.endPoint) + : new Arc(segment.startPoint, segment.endPoint, segment.arcAngle) + ); } - public static ElementShape.Polyline PolylineToNative(Polyline polyline) - { - var archiPoly = new ElementShape.Polyline(); - var points = polyline.GetPoints(); - points.ForEach(p => ScaleToNative(p)); - for (var i = 0; i < points.Count - 1; i++) - { - archiPoly.polylineSegments.Add(new ElementShape.PolylineSegment(points[i], points[i + 1])); - } - - return archiPoly; - } + return poly; + } - public static ElementShape.PolylineSegment ArcToNative(Arc arc) - { - return new ElementShape.PolylineSegment( - ScaleToNative(arc.startPoint), - ScaleToNative(arc.endPoint), - arc.angleRadians - ); - } + public static ElementShape.PolylineSegment LineToNative(Line line) + { + return new ElementShape.PolylineSegment(ScaleToNative(line.start), ScaleToNative(line.end)); + } + + public static ElementShape.Polyline PolycurveToNative(Polycurve polycurve) + { + var segments = polycurve.segments.Select(CurveSegmentToNative).ToList(); + return new ElementShape.Polyline(segments); + } - public static ElementShape.Polyline? CurveToNative(ICurve curve) + public static ElementShape.Polyline PolylineToNative(Polyline polyline) + { + var archiPoly = new ElementShape.Polyline(); + var points = polyline.GetPoints(); + points.ForEach(p => ScaleToNative(p)); + for (var i = 0; i < points.Count - 1; i++) { - return curve switch - { - Polyline polyline => PolylineToNative(polyline), - Polycurve polycurve => PolycurveToNative(polycurve), - _ => null - }; + archiPoly.polylineSegments.Add(new ElementShape.PolylineSegment(points[i], points[i + 1])); } - public static ElementShape.PolylineSegment? CurveSegmentToNative(ICurve curve) + return archiPoly; + } + + public static ElementShape.PolylineSegment ArcToNative(Arc arc) + { + return new ElementShape.PolylineSegment( + ScaleToNative(arc.startPoint), + ScaleToNative(arc.endPoint), + arc.angleRadians + ); + } + + public static ElementShape.Polyline? CurveToNative(ICurve curve) + { + return curve switch { - return curve switch - { - Line line => LineToNative(line), - Arc arc => ArcToNative(arc), - _ => throw new SpeckleException("Archicad Element Shapes can only be created with Lines or Arcs.") - }; - } + Polyline polyline => PolylineToNative(polyline), + Polycurve polycurve => PolycurveToNative(polycurve), + _ => null + }; + } - public static ElementShape PolycurvesToElementShape(ICurve outline, List voids = null) + public static ElementShape.PolylineSegment? CurveSegmentToNative(ICurve curve) + { + return curve switch { - var shape = new ElementShape(CurveToNative(outline)); - if (voids?.Count > 0) - shape.holePolylines = new List(voids.Select(CurveToNative)); + Line line => LineToNative(line), + Arc arc => ArcToNative(arc), + _ => throw new SpeckleException("Archicad Element Shapes can only be created with Lines or Arcs.") + }; + } - return shape; + public static ElementShape PolycurvesToElementShape(ICurve outline, List voids = null) + { + var shape = new ElementShape(CurveToNative(outline)); + if (voids?.Count > 0) + { + shape.holePolylines = new List(voids.Select(CurveToNative)); } - public static T ConvertDTOs(dynamic jObject) - { - Objects.BuiltElements.Archicad.ArchicadLevel level = - jObject.level.ToObject(); + return shape; + } - jObject.Remove("level"); - T speckleObject = jObject.ToObject(); + public static T ConvertDTOs(dynamic jObject) + { + Objects.BuiltElements.Archicad.ArchicadLevel level = + jObject.level.ToObject(); - PropertyInfo prop = speckleObject.GetType().GetProperty("archicadLevel"); - prop.SetValue(speckleObject, level); + jObject.Remove("level"); + T speckleObject = jObject.ToObject(); - return speckleObject; - } + PropertyInfo prop = speckleObject.GetType().GetProperty("archicadLevel"); + prop.SetValue(speckleObject, level); - public static Objects.BuiltElements.Archicad.ArchicadLevel ConvertLevel(Objects.BuiltElements.Level level) + return speckleObject; + } + + public static Objects.BuiltElements.Archicad.ArchicadLevel ConvertLevel(Objects.BuiltElements.Level level) + { + return new Objects.BuiltElements.Archicad.ArchicadLevel { - return new Objects.BuiltElements.Archicad.ArchicadLevel - { - id = level.id, - applicationId = level.applicationId, - elevation = level.elevation * Units.GetConversionFactor(level.units, Units.Meters), - name = level.name - }; - } + id = level.id, + applicationId = level.applicationId, + elevation = level.elevation * Units.GetConversionFactor(level.units, Units.Meters), + name = level.name + }; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WallConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WallConverter.cs index e0c7c8dfe9..4bd34d7aef 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WallConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WallConverter.cs @@ -13,37 +13,38 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Wall : IConverter { - public sealed class Wall : IConverter + public Type Type => typeof(Objects.BuiltElements.Wall); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Wall); + var walls = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var walls = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadWall archiWall: - walls.Add(archiWall); - break; - case Objects.BuiltElements.Wall wall: - var baseLine = (Line)wall.baseLine; + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadWall archiWall: + walls.Add(archiWall); + break; + case Objects.BuiltElements.Wall wall: + var baseLine = (Line)wall.baseLine; - ArchicadWall newWall = new Objects.BuiltElements.Archicad.ArchicadWall + ArchicadWall newWall = + new() { id = wall.id, applicationId = wall.applicationId, @@ -54,52 +55,52 @@ CancellationToken token flipped = (tc.current is RevitWall revitWall) ? revitWall.flipped : false }; - walls.Add(newWall); - break; - } + walls.Add(newWall); + break; } } + } - var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateWall(walls), token); + var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateWall(walls), token); - return result is null ? new List() : result.ToList(); - } + return result is null ? new List() : result.ToList(); + } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token - ) - { - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetWallData(elementModels.Select(e => e.applicationId)), - token - ); + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetWallData(elementModels.Select(e => e.applicationId)), + token + ); - var walls = new List(); - if (jArray is null) - return walls; + var walls = new List(); + if (jArray is null) + { + return walls; + } - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) + ) + { + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { - foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) - { - // convert between DTOs - Objects.BuiltElements.Archicad.ArchicadWall wall = - Archicad.Converters.Utils.ConvertDTOs(jToken); + // convert between DTOs + Objects.BuiltElements.Archicad.ArchicadWall wall = + Archicad.Converters.Utils.ConvertDTOs(jToken); - wall.units = Units.Meters; - wall.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == wall.applicationId).model - ); - wall.baseLine = new Line(wall.startPoint, wall.endPoint); - walls.Add(wall); - } + wall.units = Units.Meters; + wall.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == wall.applicationId).model + ); + wall.baseLine = new Line(wall.startPoint, wall.endPoint); + walls.Add(wall); } - - return walls; } + + return walls; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WindowConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WindowConverter.cs index d2ccc0c693..497ac33805 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WindowConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/WindowConverter.cs @@ -11,79 +11,79 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad.Converters +namespace Archicad.Converters; + +public sealed class Window : IConverter { - public sealed class Window : IConverter + public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadWindow); + + public async Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) { - public Type Type => typeof(Objects.BuiltElements.Archicad.ArchicadWindow); + var windows = new List(); - public async Task> ConvertToArchicad( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) ) { - var windows = new List(); - - var context = Archicad.Helpers.Timer.Context.Peek; - using ( - context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) - ) + foreach (var tc in elements) { - foreach (var tc in elements) - { - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - switch (tc.current) - { - case Objects.BuiltElements.Archicad.ArchicadWindow archicadWindow: - archicadWindow.parentApplicationId = tc.parent.current.id; - windows.Add(archicadWindow); - break; - //case Objects.BuiltElements.Opening window: - // var baseLine = (Line)wall.baseLine; - // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), - // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); - // if (el is RevitWall revitWall) - // newWall.flipped = revitWall.flipped; - // walls.Add(newWall); - // break; - } + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadWindow archicadWindow: + archicadWindow.parentApplicationId = tc.parent.current.id; + windows.Add(archicadWindow); + break; + //case Objects.BuiltElements.Opening window: + // var baseLine = (Line)wall.baseLine; + // var newWall = new Objects.BuiltElements.Archicad.ArchicadDoor(Utils.ScaleToNative(baseLine.start), + // Utils.ScaleToNative(baseLine.end), Utils.ScaleToNative(wall.height, wall.units)); + // if (el is RevitWall revitWall) + // newWall.flipped = revitWall.flipped; + // walls.Add(newWall); + // break; } } + } + + var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateWindow(windows), token); - var result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateWindow(windows), token); + return result is null ? new List() : result.ToList(); + } + + public async Task> ConvertToSpeckle(IEnumerable elements, CancellationToken token) + { + // Get subelements + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + IEnumerable data = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetWindowData(elementModels.Select(e => e.applicationId)) + ); - return result is null ? new List() : result.ToList(); + List openings = new(); + if (data is null) + { + return openings; } - public async Task> ConvertToSpeckle( - IEnumerable elements, - CancellationToken token + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - // Get subelements - var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetWindowData(elementModels.Select(e => e.applicationId)) - ); - - List openings = new List(); - if (data is null) - return openings; - - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name)) + foreach (Objects.BuiltElements.Archicad.ArchicadWindow subelement in data) { - foreach (Objects.BuiltElements.Archicad.ArchicadWindow subelement in data) - { - subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( - elementModels.First(e => e.applicationId == subelement.applicationId).model - ); - openings.Add(subelement); - } + subelement.displayValue = Operations.ModelConverter.MeshesToSpeckle( + elementModels.First(e => e.applicationId == subelement.applicationId).model + ); + openings.Add(subelement); } - - return openings; } + + return openings; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs index 4fb1e4b54c..10b7e51289 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs @@ -22,296 +22,348 @@ using Skylight = Objects.BuiltElements.Archicad.ArchicadSkylight; using GridLine = Objects.BuiltElements.GridLine; -namespace Archicad +namespace Archicad; + +public sealed partial class ElementConverterManager { - public sealed partial class ElementConverterManager - { - #region --- Fields --- + #region --- Fields --- - public static ElementConverterManager Instance { get; } = new(); + public static ElementConverterManager Instance { get; } = new(); - private Dictionary Converters { get; } = new(); + private Dictionary Converters { get; } = new(); - private Converters.IConverter DefaultConverterForSend { get; } = new Converters.DirectShape(); - private Converters.IConverter DefaultConverterForReceive { get; } = new Converters.Object(); + private Converters.IConverter DefaultConverterForSend { get; } = new Converters.DirectShape(); + private Converters.IConverter DefaultConverterForReceive { get; } = new Converters.Object(); - private Dictionary> ReceivedObjects { get; set; } - private Dictionary> SelectedObjects { get; set; } + private Dictionary> ReceivedObjects { get; set; } + private Dictionary> SelectedObjects { get; set; } - private List CanHaveSubElements = new List { "Wall", "Roof", "Shell" }; // Hardcoded until we know whats the shared property that defines wether elements may be have subelements or not. - #endregion + private List CanHaveSubElements = new() { "Wall", "Roof", "Shell" }; // Hardcoded until we know whats the shared property that defines wether elements may be have subelements or not. + #endregion - #region --- Ctor \ Dtor --- + #region --- Ctor \ Dtor --- - private ElementConverterManager() - { - RegisterConverters(); - } + private ElementConverterManager() + { + RegisterConverters(); + } + + #endregion - #endregion + #region --- Functions --- - #region --- Functions --- + public async Task ConvertToSpeckle(ISelectionFilter filter, ProgressViewModel progress) + { + var objectToCommit = new Collection("Archicad model", "model"); - public async Task ConvertToSpeckle(ISelectionFilter filter, ProgressViewModel progress) + IEnumerable elementIds = filter.Selection; + if (filter.Slug == "all") { - var objectToCommit = new Collection("Archicad model", "model"); - - IEnumerable elementIds = filter.Selection; - if (filter.Slug == "all") - elementIds = AsyncCommandProcessor - .Execute(new Communication.Commands.GetElementIds(Communication.Commands.GetElementIds.ElementFilter.All)) - ?.Result; - else if (filter.Slug == "elementType") - { - var elementTypes = filter.Summary.Split(",").Select(elementType => elementType.Trim()).ToList(); - elementIds = AsyncCommandProcessor - .Execute( - new Communication.Commands.GetElementIds( - Communication.Commands.GetElementIds.ElementFilter.ElementType, - elementTypes - ) + elementIds = AsyncCommandProcessor + .Execute(new Communication.Commands.GetElementIds(Communication.Commands.GetElementIds.ElementFilter.All)) + ?.Result; + } + else if (filter.Slug == "elementType") + { + var elementTypes = filter.Summary.Split(",").Select(elementType => elementType.Trim()).ToList(); + elementIds = AsyncCommandProcessor + .Execute( + new Communication.Commands.GetElementIds( + Communication.Commands.GetElementIds.ElementFilter.ElementType, + elementTypes ) - ?.Result; - } + ) + ?.Result; + } - SelectedObjects = await GetElementsType(elementIds, progress.CancellationToken); // Gets all selected objects - SelectedObjects = SortSelectedObjects(); + SelectedObjects = await GetElementsType(elementIds, progress.CancellationToken); // Gets all selected objects + SelectedObjects = SortSelectedObjects(); - SpeckleLog.Logger.Debug("Conversion started (element types: {0})", SelectedObjects.Count); + SpeckleLog.Logger.Debug("Conversion started (element types: {0})", SelectedObjects.Count); - foreach (var (element, guids) in SelectedObjects) // For all kind of selected objects (like window, door, wall, etc.) - { - SpeckleLog.Logger.Debug("{0}: {1}", element, guids.Count()); + foreach (var (element, guids) in SelectedObjects) // For all kind of selected objects (like window, door, wall, etc.) + { + SpeckleLog.Logger.Debug("{0}: {1}", element, guids.Count()); - var objects = await ConvertOneTypeToSpeckle( - guids, - ElementTypeProvider.GetTypeByName(element), - progress.CancellationToken - ); // Deserialize all objects with hiven type + var objects = await ConvertOneTypeToSpeckle( + guids, + ElementTypeProvider.GetTypeByName(element), + progress.CancellationToken + ); // Deserialize all objects with hiven type + + if (objects.Count() > 0) + { + var elementCollection = new Collection(element, "Element Type"); + elementCollection.applicationId = element; + elementCollection.elements = objects; + objectToCommit.elements.Add(elementCollection); - if (objects.Count() > 0) + // itermediate solution for the OneClick Send report + for (int i = 0; i < objects.Count(); i++) { - var elementCollection = new Collection(element, "Element Type"); - elementCollection.applicationId = element; - elementCollection.elements = objects; - objectToCommit.elements.Add(elementCollection); - - // itermediate solution for the OneClick Send report - for (int i = 0; i < objects.Count(); i++) - if (!progress.Report.ReportObjects.ContainsKey(objects[i].applicationId)) - progress.Report.ReportObjects.Add(objects[i].applicationId, new ApplicationObject("", "")); + if (!progress.Report.ReportObjects.ContainsKey(objects[i].applicationId)) + { + progress.Report.ReportObjects.Add(objects[i].applicationId, new ApplicationObject("", "")); + } } } + } + + SpeckleLog.Logger.Debug("Conversion done"); + + return objectToCommit; + } - SpeckleLog.Logger.Debug("Conversion done"); + Dictionary> SortSelectedObjects() + { + var retval = new Dictionary>(); + var canHave = SelectedObjects.Where(e => CanHaveSubElements.Contains(e.Key)); + var cannotHave = SelectedObjects.Where(e => !CanHaveSubElements.Contains(e.Key)); - return objectToCommit; + foreach (var (key, value) in canHave) + { + retval[key] = value; } - Dictionary> SortSelectedObjects() + foreach (var (key, value) in cannotHave) { - var retval = new Dictionary>(); - var canHave = SelectedObjects.Where(e => CanHaveSubElements.Contains(e.Key)); - var cannotHave = SelectedObjects.Where(e => !CanHaveSubElements.Contains(e.Key)); + retval[key] = value; + } - foreach (var (key, value) in canHave) - { - retval[key] = value; - } + return retval; + } - foreach (var (key, value) in cannotHave) + private void RegisterConverters() + { + IEnumerable convertes = Assembly + .GetExecutingAssembly() + .GetTypes() + .Where(t => t.IsClass && !t.IsAbstract && typeof(Converters.IConverter).IsAssignableFrom(t)); + + foreach (Type converterType in convertes) + { + var converter = Activator.CreateInstance(converterType) as Converters.IConverter; + if (converter?.Type is null) { - retval[key] = value; + continue; } - return retval; + Converters.Add(converter.Type, converter); } + } - private void RegisterConverters() + public Converters.IConverter GetConverterForElement( + Type elementType, + ConversionOptions conversionOptions, + bool forReceive + ) + { + if (forReceive) { - IEnumerable convertes = Assembly - .GetExecutingAssembly() - .GetTypes() - .Where(t => t.IsClass && !t.IsAbstract && typeof(Converters.IConverter).IsAssignableFrom(t)); - - foreach (Type converterType in convertes) + // always convert to Archicad GridElement + if (elementType.IsAssignableFrom(typeof(GridLine))) { - var converter = Activator.CreateInstance(converterType) as Converters.IConverter; - if (converter?.Type is null) - continue; + return Converters[typeof(Archicad.GridElement)]; + } - Converters.Add(converter.Type, converter); + if (conversionOptions != null && !conversionOptions.ReceiveParametric) + { + return DefaultConverterForReceive; } } - public Converters.IConverter GetConverterForElement( - Type elementType, - ConversionOptions conversionOptions, - bool forReceive - ) + if (Converters.ContainsKey(elementType)) { - if (forReceive) - { - // always convert to Archicad GridElement - if (elementType.IsAssignableFrom(typeof(GridLine))) - return Converters[typeof(Archicad.GridElement)]; + return Converters[elementType]; + } - if (conversionOptions != null && !conversionOptions.ReceiveParametric) - return DefaultConverterForReceive; - } + if (elementType.IsSubclassOf(typeof(Wall))) + { + return Converters[typeof(Wall)]; + } - if (Converters.ContainsKey(elementType)) - return Converters[elementType]; - if (elementType.IsSubclassOf(typeof(Wall))) - return Converters[typeof(Wall)]; - if (elementType.IsSubclassOf(typeof(Beam))) - return Converters[typeof(Beam)]; - if (elementType.IsSubclassOf(typeof(Column))) - return Converters[typeof(Column)]; - if (elementType.IsSubclassOf(typeof(Door))) - return Converters[typeof(Door)]; - if (elementType.IsSubclassOf(typeof(Window))) - return Converters[typeof(Window)]; - if (elementType.IsSubclassOf(typeof(Skylight))) - return Converters[typeof(Skylight)]; - if (elementType.IsSubclassOf(typeof(Floor)) || elementType.IsSubclassOf(typeof(Ceiling))) - return Converters[typeof(Floor)]; - if (elementType.IsSubclassOf(typeof(Roof))) - return Converters[typeof(Roof)]; - if (elementType.IsAssignableFrom(typeof(Objects.BuiltElements.Room))) - return Converters[typeof(Archicad.Room)]; - if (elementType.IsAssignableFrom(typeof(Archicad.GridElement))) - return Converters[typeof(Archicad.GridElement)]; + if (elementType.IsSubclassOf(typeof(Beam))) + { + return Converters[typeof(Beam)]; + } - return forReceive ? DefaultConverterForReceive : DefaultConverterForSend; + if (elementType.IsSubclassOf(typeof(Column))) + { + return Converters[typeof(Column)]; } - #endregion + if (elementType.IsSubclassOf(typeof(Door))) + { + return Converters[typeof(Door)]; + } - private async Task>?> GetElementsType( - IEnumerable applicationIds, - CancellationToken token - ) + if (elementType.IsSubclassOf(typeof(Window))) { - var retval = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetElementsType(applicationIds), - token - ); - return retval; + return Converters[typeof(Window)]; } - public async Task?> ConvertOneTypeToSpeckle( - IEnumerable applicationIds, - Type elementType, - CancellationToken token - ) + if (elementType.IsSubclassOf(typeof(Skylight))) { - var rawModels = await GetModelForElements(applicationIds, token); // Model data, like meshes - var elementConverter = ElementConverterManager.Instance.GetConverterForElement(elementType, null, false); // Object converter - var convertedObjects = await elementConverter.ConvertToSpeckle(rawModels, token); // Deserialization + return Converters[typeof(Skylight)]; + } - foreach (var convertedObject in convertedObjects) - { - var subElementsAsBases = await ConvertSubElementsToSpeckle(convertedObject, token); - if (subElementsAsBases.Count() > 0) - { - convertedObject["elements"] = subElementsAsBases; - } - } + if (elementType.IsSubclassOf(typeof(Floor)) || elementType.IsSubclassOf(typeof(Ceiling))) + { + return Converters[typeof(Floor)]; + } - return convertedObjects; + if (elementType.IsSubclassOf(typeof(Roof))) + { + return Converters[typeof(Roof)]; } - private async Task> GetModelForElements( - IEnumerable applicationIds, - CancellationToken token - ) + if (elementType.IsAssignableFrom(typeof(Objects.BuiltElements.Room))) { - var retval = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetModelForElements(applicationIds), - token - ); - return retval; + return Converters[typeof(Archicad.Room)]; } - public async Task?> ConvertSubElementsToSpeckle(Base convertedObject, CancellationToken token) + if (elementType.IsAssignableFrom(typeof(Archicad.GridElement))) { - var subElementsAsBases = new List(); - - if ( - convertedObject - is not ( - Objects.BuiltElements.Archicad.ArchicadWall - or Objects.BuiltElements.Archicad.ArchicadRoof - or Objects.BuiltElements.Archicad.ArchicadShell - ) - ) - return subElementsAsBases; + return Converters[typeof(Archicad.GridElement)]; + } - var subElements = await GetAllSubElements(convertedObject.applicationId); - if (subElements.Count() == 0) - return subElementsAsBases; + return forReceive ? DefaultConverterForReceive : DefaultConverterForSend; + } - var subElementsByGuid = await GetElementsType(subElements.Select(e => e.applicationId), token); - var mutualSubElements = GetAllMutualSubElements(subElementsByGuid); + #endregion - foreach (var (element, guids) in mutualSubElements) + private async Task>?> GetElementsType( + IEnumerable applicationIds, + CancellationToken token + ) + { + var retval = await AsyncCommandProcessor.Execute(new Communication.Commands.GetElementsType(applicationIds), token); + return retval; + } + + public async Task?> ConvertOneTypeToSpeckle( + IEnumerable applicationIds, + Type elementType, + CancellationToken token + ) + { + var rawModels = await GetModelForElements(applicationIds, token); // Model data, like meshes + var elementConverter = ElementConverterManager.Instance.GetConverterForElement(elementType, null, false); // Object converter + var convertedObjects = await elementConverter.ConvertToSpeckle(rawModels, token); // Deserialization + + foreach (var convertedObject in convertedObjects) + { + var subElementsAsBases = await ConvertSubElementsToSpeckle(convertedObject, token); + if (subElementsAsBases.Count() > 0) { - if (guids.Count() == 0) - continue; - var convertedSubElements = await ConvertOneTypeToSpeckle( - guids, - ElementTypeProvider.GetTypeByName(element), - token - ); - subElementsAsBases = subElementsAsBases.Concat(convertedSubElements).ToList(); // Update list with new values + convertedObject["elements"] = subElementsAsBases; } - RemoveSubElements(mutualSubElements); // Remove subelements from SelectedObjects (where we stored all selected objects) + } + return convertedObjects; + } + + private async Task> GetModelForElements( + IEnumerable applicationIds, + CancellationToken token + ) + { + var retval = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetModelForElements(applicationIds), + token + ); + return retval; + } + + public async Task?> ConvertSubElementsToSpeckle(Base convertedObject, CancellationToken token) + { + var subElementsAsBases = new List(); + + if ( + convertedObject + is not ( + Objects.BuiltElements.Archicad.ArchicadWall + or Objects.BuiltElements.Archicad.ArchicadRoof + or Objects.BuiltElements.Archicad.ArchicadShell + ) + ) + { return subElementsAsBases; } - private async Task?> GetAllSubElements(string apllicationId) + var subElements = await GetAllSubElements(convertedObject.applicationId); + if (subElements.Count() == 0) { - IEnumerable? currentSubElements = await AsyncCommandProcessor.Execute( - new Communication.Commands.GetSubElementInfo(apllicationId), - CancellationToken.None - ); - - return currentSubElements; + return subElementsAsBases; } - private Dictionary> GetAllMutualSubElements( - Dictionary> allSubElementsByGuid - ) - { - Dictionary> mutualSubElements = new Dictionary>(); + var subElementsByGuid = await GetElementsType(subElements.Select(e => e.applicationId), token); + var mutualSubElements = GetAllMutualSubElements(subElementsByGuid); - foreach (var (element, guids) in allSubElementsByGuid) + foreach (var (element, guids) in mutualSubElements) + { + if (guids.Count() == 0) { - mutualSubElements[element] = GetMutualSubElementsByType(element, guids); + continue; } - return mutualSubElements; + var convertedSubElements = await ConvertOneTypeToSpeckle( + guids, + ElementTypeProvider.GetTypeByName(element), + token + ); + subElementsAsBases = subElementsAsBases.Concat(convertedSubElements).ToList(); // Update list with new values } + RemoveSubElements(mutualSubElements); // Remove subelements from SelectedObjects (where we stored all selected objects) + + return subElementsAsBases; + } + + private async Task?> GetAllSubElements(string apllicationId) + { + IEnumerable? currentSubElements = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetSubElementInfo(apllicationId), + CancellationToken.None + ); - private IEnumerable GetMutualSubElementsByType(string elementType, IEnumerable applicationIds) + return currentSubElements; + } + + private Dictionary> GetAllMutualSubElements( + Dictionary> allSubElementsByGuid + ) + { + Dictionary> mutualSubElements = new(); + + foreach (var (element, guids) in allSubElementsByGuid) { - if (!SelectedObjects.ContainsKey(elementType)) - return new List(); + mutualSubElements[element] = GetMutualSubElementsByType(element, guids); + } + + return mutualSubElements; + } - return SelectedObjects[elementType].Where(guid => applicationIds.Contains(guid)); + private IEnumerable GetMutualSubElementsByType(string elementType, IEnumerable applicationIds) + { + if (!SelectedObjects.ContainsKey(elementType)) + { + return new List(); } - public void RemoveSubElements(Dictionary> mutualSubElements) + return SelectedObjects[elementType].Where(guid => applicationIds.Contains(guid)); + } + + public void RemoveSubElements(Dictionary> mutualSubElements) + { + foreach (var (element, guids) in mutualSubElements) { - foreach (var (element, guids) in mutualSubElements) + if (guids.Count() == 0) { - if (guids.Count() == 0) - continue; - var guidsToKeep = SelectedObjects[element].Where(guid => !guids.Contains(guid)); - SelectedObjects[element] = guidsToKeep.ToList(); + continue; } + + var guidsToKeep = SelectedObjects[element].Where(guid => !guids.Contains(guid)); + SelectedObjects[element] = guidsToKeep.ToList(); } } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManagerReceive.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManagerReceive.cs index 15bfd62a44..5ab5e5eb7a 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManagerReceive.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManagerReceive.cs @@ -10,130 +10,133 @@ using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; -namespace Archicad +namespace Archicad; + +public sealed partial class ElementConverterManager { - public sealed partial class ElementConverterManager + public async Task> ConvertOneTypeToNative( + Type elementType, + IEnumerable elements, + ConversionOptions conversionOptions, + CancellationToken token + ) { - public async Task> ConvertOneTypeToNative( - Type elementType, - IEnumerable elements, - ConversionOptions conversionOptions, - CancellationToken token - ) + try { - try - { - var elementConverter = GetConverterForElement(elementType, conversionOptions, true); - return await elementConverter.ConvertToArchicad(elements, token); - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception) - { - SpeckleLog.Logger.Warning("Failed to convert element type {elementType}", elementType.ToString()); - return null; - } + var elementConverter = GetConverterForElement(elementType, conversionOptions, true); + return await elementConverter.ConvertToArchicad(elements, token); } - - private async Task ConvertReceivedObjects( - List flattenObjects, - ConverterArchicad converter, - ProgressViewModel progress - ) + catch (OperationCanceledException) + { + throw; + } + catch (Exception) { - Dictionary> receivedObjects; + SpeckleLog.Logger.Warning("Failed to convert element type {elementType}", elementType.ToString()); + return null; + } + } - receivedObjects = flattenObjects - .GroupBy(tc => tc.current.GetType()) - .ToDictionary(group => group.Key, group => group.Cast()); - SpeckleLog.Logger.Debug("Conversion started (element types: {0})", receivedObjects.Count); + private async Task ConvertReceivedObjects( + List flattenObjects, + ConverterArchicad converter, + ProgressViewModel progress + ) + { + Dictionary> receivedObjects; - foreach (var (elementType, tc) in receivedObjects) - { - SpeckleLog.Logger.Debug("{0}: {1}", elementType, tc.Count()); + receivedObjects = flattenObjects + .GroupBy(tc => tc.current.GetType()) + .ToDictionary(group => group.Key, group => group.Cast()); + SpeckleLog.Logger.Debug("Conversion started (element types: {0})", receivedObjects.Count); - List elements = tc.Select(tc => tc.current).ToList(); - var convertedElements = await ConvertOneTypeToNative( - elementType, - tc, - converter.ConversionOptions, - progress.CancellationTokenSource.Token - ); + foreach (var (elementType, tc) in receivedObjects) + { + SpeckleLog.Logger.Debug("{0}: {1}", elementType, tc.Count()); + + List elements = tc.Select(tc => tc.current).ToList(); + var convertedElements = await ConvertOneTypeToNative( + elementType, + tc, + converter.ConversionOptions, + progress.CancellationTokenSource.Token + ); - if (convertedElements != null) + if (convertedElements != null) + { + var dict = convertedElements + .Where(obj => (!string.IsNullOrEmpty(obj.OriginalId))) + .ToDictionary(obj => obj.OriginalId, obj => obj); + foreach (var contextObject in converter.ContextObjects) { - var dict = convertedElements - .Where(obj => (!string.IsNullOrEmpty(obj.OriginalId))) - .ToDictionary(obj => obj.OriginalId, obj => obj); - foreach (var contextObject in converter.ContextObjects) + if (dict.ContainsKey(contextObject.OriginalId)) { - if (dict.ContainsKey(contextObject.OriginalId)) - { - ApplicationObject obj = dict[contextObject.OriginalId]; + ApplicationObject obj = dict[contextObject.OriginalId]; - contextObject.Update(status: obj.Status, createdIds: obj.CreatedIds, log: obj.Log); - progress.Report.UpdateReportObject(contextObject); - } + contextObject.Update(status: obj.Status, createdIds: obj.CreatedIds, log: obj.Log); + progress.Report.UpdateReportObject(contextObject); } } } - - SpeckleLog.Logger.Debug("Conversion done."); - - return true; } - public async Task ConvertToNative(StreamState state, Base commitObject, ProgressViewModel progress) - { - ConversionOptions conversionOptions = new ConversionOptions(state.Settings); - - Objects.Converter.Archicad.ConverterArchicad converter = new Objects.Converter.Archicad.ConverterArchicad( - conversionOptions - ); - List flattenObjects = FlattenCommitObject(commitObject, converter); + SpeckleLog.Logger.Debug("Conversion done."); - converter.SetContextObjects(flattenObjects); + return true; + } - foreach (var applicationObject in converter.ContextObjects) - progress.Report.Log(applicationObject); + public async Task ConvertToNative(StreamState state, Base commitObject, ProgressViewModel progress) + { + ConversionOptions conversionOptions = new(state.Settings); - converter.ReceiveMode = state.ReceiveMode; + Objects.Converter.Archicad.ConverterArchicad converter = new(conversionOptions); + List flattenObjects = FlattenCommitObject(commitObject, converter); - return await ConvertReceivedObjects(flattenObjects, converter, progress); - } + converter.SetContextObjects(flattenObjects); - private List FlattenCommitObject( - Base commitObject, - Objects.Converter.Archicad.ConverterArchicad converter - ) + foreach (var applicationObject in converter.ContextObjects) { - // to filter out already traversed objects (e.g. the same Mesh in displayValue and in topRail member of the Railing) - HashSet traversedObjects = new HashSet(); + progress.Report.Log(applicationObject); + } - TraversalContext Store(TraversalContext context, Objects.Converter.Archicad.ConverterArchicad converter) - { - if (!converter.CanConvertToNativeImplemented(context.current)) - return null; + converter.ReceiveMode = state.ReceiveMode; - if (traversedObjects.Contains(context.current.id)) - return null; + return await ConvertReceivedObjects(flattenObjects, converter, progress); + } - traversedObjects.Add(context.current.id); + private List FlattenCommitObject( + Base commitObject, + Objects.Converter.Archicad.ConverterArchicad converter + ) + { + // to filter out already traversed objects (e.g. the same Mesh in displayValue and in topRail member of the Railing) + HashSet traversedObjects = new(); - return context; + TraversalContext Store(TraversalContext context, Objects.Converter.Archicad.ConverterArchicad converter) + { + if (!converter.CanConvertToNativeImplemented(context.current)) + { + return null; } - var traverseFunction = DefaultTraversal.CreateBIMTraverseFunc(converter); + if (traversedObjects.Contains(context.current.id)) + { + return null; + } - var objectsToConvert = traverseFunction - .Traverse(commitObject) - .Select(tc => Store(tc, converter)) - .Where(tc => tc != null) - .ToList(); + traversedObjects.Add(context.current.id); - return objectsToConvert; + return context; } + + var traverseFunction = DefaultTraversal.CreateBIMTraverseFunc(converter); + + var objectsToConvert = traverseFunction + .Traverse(commitObject) + .Select(tc => Store(tc, converter)) + .Where(tc => tc != null) + .ToList(); + + return objectsToConvert; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs index 0cb725ff86..d83d1e3260 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs @@ -13,29 +13,28 @@ using Window = Objects.BuiltElements.Archicad.ArchicadWindow; using Skylight = Objects.BuiltElements.Archicad.ArchicadSkylight; -namespace Archicad -{ - public static class ElementTypeProvider - { - private static Dictionary _nameToType = - new() - { - { "Wall", typeof(Wall) }, - { "Slab", typeof(Floor) }, - { "Roof", typeof(Roof) }, - { "Shell", typeof(Shell) }, - { "Zone", typeof(Room) }, - { "Beam", typeof(Beam) }, - { "Column", typeof(Column) }, - { "Door", typeof(Door) }, - { "Window", typeof(Window) }, - { "Skylight", typeof(Skylight) }, - { "GridElement", typeof(GridElement) } - }; +namespace Archicad; - public static Type GetTypeByName(string name) +public static class ElementTypeProvider +{ + private static Dictionary _nameToType = + new() { - return _nameToType.TryGetValue(name, out var value) ? value : typeof(DirectShape); - } + { "Wall", typeof(Wall) }, + { "Slab", typeof(Floor) }, + { "Roof", typeof(Roof) }, + { "Shell", typeof(Shell) }, + { "Zone", typeof(Room) }, + { "Beam", typeof(Beam) }, + { "Column", typeof(Column) }, + { "Door", typeof(Door) }, + { "Window", typeof(Window) }, + { "Skylight", typeof(Skylight) }, + { "GridElement", typeof(GridElement) } + }; + + public static Type GetTypeByName(string name) + { + return _nameToType.TryGetValue(name, out var value) ? value : typeof(DirectShape); } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs index 32f9767214..f19785f14a 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs @@ -9,370 +9,388 @@ using Speckle.Core.Kits; using static Archicad.Model.MeshModel; -namespace Archicad.Operations +namespace Archicad.Operations; + +public static class ModelConverter { - public static class ModelConverter - { - private static readonly double angleCosLimit = Math.Cos(Math.PI / 4); + private static readonly double angleCosLimit = Math.Cos(Math.PI / 4); - public static List MeshesToSpeckle(MeshModel meshModel) + public static List MeshesToSpeckle(MeshModel meshModel) + { + var context = Archicad.Helpers.Timer.Context.Peek; + using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.MeshToSpeckle)) { - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.MeshToSpeckle)) - { - var materials = meshModel.materials.Select(MaterialToSpeckle).ToList(); - var meshes = materials.Select(m => new Mesh { units = Units.Meters, ["renderMaterial"] = m }).ToList(); - var vertCount = new int[materials.Count]; + var materials = meshModel.materials.Select(MaterialToSpeckle).ToList(); + var meshes = materials.Select(m => new Mesh { units = Units.Meters, ["renderMaterial"] = m }).ToList(); + var vertCount = new int[materials.Count]; - foreach (var poly in meshModel.polygons) - { - var meshIndex = poly.material; - meshes[meshIndex].vertices.AddRange( - poly.pointIds.SelectMany(id => FlattenPoint(meshModel.vertices[id])).ToList() - ); - meshes[meshIndex].faces.AddRange(PolygonToSpeckle(poly, vertCount[meshIndex])); - vertCount[meshIndex] += poly.pointIds.Count; - } - - return meshes; + foreach (var poly in meshModel.polygons) + { + var meshIndex = poly.material; + meshes[meshIndex].vertices.AddRange( + poly.pointIds.SelectMany(id => FlattenPoint(meshModel.vertices[id])).ToList() + ); + meshes[meshIndex].faces.AddRange(PolygonToSpeckle(poly, vertCount[meshIndex])); + vertCount[meshIndex] += poly.pointIds.Count; } + + return meshes; } + } - public static List MeshesAndLinesToSpeckle(MeshModel meshModel) - { - List meshes = MeshesToSpeckle(meshModel).Cast().ToList(); + public static List MeshesAndLinesToSpeckle(MeshModel meshModel) + { + List meshes = MeshesToSpeckle(meshModel).Cast().ToList(); - List lines = new List(); - foreach (var edge in meshModel.edges) + List lines = new(); + foreach (var edge in meshModel.edges) + { + if (edge.Value.polygonId1 == EdgeData.InvalidPolygonId && edge.Value.polygonId2 == EdgeData.InvalidPolygonId) { - if (edge.Value.polygonId1 == EdgeData.InvalidPolygonId && edge.Value.polygonId2 == EdgeData.InvalidPolygonId) - { - var line = new Line( - new Point( - meshModel.vertices[edge.Key.vertexId1].x, - meshModel.vertices[edge.Key.vertexId1].y, - meshModel.vertices[edge.Key.vertexId1].z - ), - new Point( - meshModel.vertices[edge.Key.vertexId2].x, - meshModel.vertices[edge.Key.vertexId2].y, - meshModel.vertices[edge.Key.vertexId2].z - ) - ); - - lines.Add(line); - } + var line = new Line( + new Point( + meshModel.vertices[edge.Key.vertexId1].x, + meshModel.vertices[edge.Key.vertexId1].y, + meshModel.vertices[edge.Key.vertexId1].z + ), + new Point( + meshModel.vertices[edge.Key.vertexId2].x, + meshModel.vertices[edge.Key.vertexId2].y, + meshModel.vertices[edge.Key.vertexId2].z + ) + ); + + lines.Add(line); } - - meshes.AddRange(lines.Cast().ToList()); - return meshes; } - public static MeshModel MeshToNative(IEnumerable meshes) + meshes.AddRange(lines.Cast().ToList()); + return meshes; + } + + public static MeshModel MeshToNative(IEnumerable meshes) + { + var context = Archicad.Helpers.Timer.Context.Peek; + using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.MeshToNative)) { - var context = Archicad.Helpers.Timer.Context.Peek; - using (context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.MeshToNative)) - { - var mergedVertexIndices = new Dictionary(); - var originalToMergedVertexIndices = new List(); - var neigbourPolygonsByEdge = new Dictionary>(); - var polygonNormals = new Dictionary(); + var mergedVertexIndices = new Dictionary(); + var originalToMergedVertexIndices = new List(); + var neigbourPolygonsByEdge = new Dictionary>(); + var polygonNormals = new Dictionary(); - var vertexOffset = 0; + var vertexOffset = 0; - var meshModel = new MeshModel(); - var enumerable = meshes as Mesh[] ?? meshes.ToArray(); + var meshModel = new MeshModel(); + var enumerable = meshes as Mesh[] ?? meshes.ToArray(); - #region Local Funcitions - // converts from original to merged vertex index - int ToMergedVertexIndex(int i) => originalToMergedVertexIndices[i + vertexOffset]; - #endregion + #region Local Funcitions + // converts from original to merged vertex index + int ToMergedVertexIndex(int i) => originalToMergedVertexIndices[i + vertexOffset]; + #endregion - foreach (var mesh in enumerable) + foreach (var mesh in enumerable) + { + MeshModel.Material material = null; + if (mesh["renderMaterial"] is RenderMaterial renderMaterial) { - MeshModel.Material material = null; - if (mesh["renderMaterial"] is RenderMaterial renderMaterial) + material = MaterialToNative(renderMaterial); + meshModel.materials.Add(material); + } + + foreach (var vertex in mesh.GetPoints().Select(p => Utils.PointToNative(p))) + { + if (mergedVertexIndices.TryGetValue(vertex, out int idx)) { - material = MaterialToNative(renderMaterial); - meshModel.materials.Add(material); + originalToMergedVertexIndices.Add(idx); } - - foreach (var vertex in mesh.GetPoints().Select(p => Utils.PointToNative(p))) + else { - if (mergedVertexIndices.TryGetValue(vertex, out int idx)) - { - originalToMergedVertexIndices.Add(idx); - } - else - { - originalToMergedVertexIndices.Add(mergedVertexIndices.Count); - mergedVertexIndices.Add(vertex, mergedVertexIndices.Count); - meshModel.vertices.Add(vertex); - } + originalToMergedVertexIndices.Add(mergedVertexIndices.Count); + mergedVertexIndices.Add(vertex, mergedVertexIndices.Count); + meshModel.vertices.Add(vertex); } + } - for (var i = 0; i < mesh.faces.Count; ++i) - { - var polygon = new Polygon(); + for (var i = 0; i < mesh.faces.Count; ++i) + { + var polygon = new Polygon(); - var n = mesh.faces[i]; - if (n < 3) - n += 3; + var n = mesh.faces[i]; + if (n < 3) + { + n += 3; + } - for (var vertexIdx = i + 1; vertexIdx <= i + n; vertexIdx++) + for (var vertexIdx = i + 1; vertexIdx <= i + n; vertexIdx++) + { + var pointId = ToMergedVertexIndex(mesh.faces[vertexIdx]); + if (polygon.pointIds.Count == 0 || pointId != polygon.pointIds[^1]) { - var pointId = ToMergedVertexIndex(mesh.faces[vertexIdx]); - if (polygon.pointIds.Count == 0 || pointId != polygon.pointIds[^1]) - polygon.pointIds.Add(pointId); + polygon.pointIds.Add(pointId); } + } - if (polygon.pointIds[0] == polygon.pointIds[^1]) - { - polygon.pointIds.RemoveAt(0); - } + if (polygon.pointIds[0] == polygon.pointIds[^1]) + { + polygon.pointIds.RemoveAt(0); + } - if (material != null) + if (material != null) + { + polygon.material = meshModel.materials.Count - 1; + } + + // check result polygon + if (polygon.pointIds.Count >= 3) + { + if (meshModel.IsCoplanar(polygon)) { - polygon.material = meshModel.materials.Count - 1; + ProcessPolygonEdges(meshModel, neigbourPolygonsByEdge, polygonNormals, polygon); + meshModel.polygons.Add(polygon); } - - // check result polygon - if (polygon.pointIds.Count >= 3) + else { - if (meshModel.IsCoplanar(polygon)) + var triangleFaces = MeshTriangulationHelper.TriangulateFace(i, mesh, includeIndicators: false); + for (int triangleStartIdx = 0; triangleStartIdx < triangleFaces.Count; triangleStartIdx += 3) { - ProcessPolygonEdges(meshModel, neigbourPolygonsByEdge, polygonNormals, polygon); - meshModel.polygons.Add(polygon); - } - else - { - var triangleFaces = MeshTriangulationHelper.TriangulateFace(i, mesh, includeIndicators: false); - for (int triangleStartIdx = 0; triangleStartIdx < triangleFaces.Count; triangleStartIdx += 3) + var triangle = new Polygon { material = polygon.material }; + for (int triangleVertexIdx = 0; triangleVertexIdx < 3; triangleVertexIdx++) { - var triangle = new Polygon { material = polygon.material }; - for (int triangleVertexIdx = 0; triangleVertexIdx < 3; triangleVertexIdx++) - { - int trianglePointId = ToMergedVertexIndex(triangleFaces[triangleStartIdx + triangleVertexIdx]); - triangle.pointIds.Add(trianglePointId); - } - - ProcessPolygonEdges(meshModel, neigbourPolygonsByEdge, polygonNormals, triangle); - meshModel.polygons.Add(triangle); + int trianglePointId = ToMergedVertexIndex(triangleFaces[triangleStartIdx + triangleVertexIdx]); + triangle.pointIds.Add(trianglePointId); } + + ProcessPolygonEdges(meshModel, neigbourPolygonsByEdge, polygonNormals, triangle); + meshModel.polygons.Add(triangle); } } - - i += n; } - vertexOffset += mesh.VerticesCount; - meshModel.ids.Add(mesh.id); + i += n; } + vertexOffset += mesh.VerticesCount; - return meshModel; + meshModel.ids.Add(mesh.id); } + + return meshModel; } + } - public static MeshModel MeshToNative2(IEnumerable meshes) + public static MeshModel MeshToNative2(IEnumerable meshes) + { + var meshModel = new MeshModel(); + var enumerable = meshes as Mesh[] ?? meshes.ToArray(); + foreach (var mesh in enumerable) { - var meshModel = new MeshModel(); - var enumerable = meshes as Mesh[] ?? meshes.ToArray(); - foreach (var mesh in enumerable) - { - int vertexOffset = meshModel.vertices.Count; - var polygons = PolygonToNative(mesh.faces); - polygons.ForEach(p => p.pointIds = p.pointIds.Select(l => l + vertexOffset).ToList()); + int vertexOffset = meshModel.vertices.Count; + var polygons = PolygonToNative(mesh.faces); + polygons.ForEach(p => p.pointIds = p.pointIds.Select(l => l + vertexOffset).ToList()); - meshModel.vertices.AddRange(mesh.GetPoints().Select(p => Utils.PointToNative(p))); - meshModel.polygons.AddRange(polygons); + meshModel.vertices.AddRange(mesh.GetPoints().Select(p => Utils.PointToNative(p))); + meshModel.polygons.AddRange(polygons); - if (mesh["renderMaterial"] is RenderMaterial renderMaterial) - { - Model.MeshModel.Material material = MaterialToNative(renderMaterial); - polygons.ForEach(p => p.material = meshModel.materials.Count); - meshModel.materials.Add(material); - } - meshModel.ids.Add(mesh.id); + if (mesh["renderMaterial"] is RenderMaterial renderMaterial) + { + Model.MeshModel.Material material = MaterialToNative(renderMaterial); + polygons.ForEach(p => p.material = meshModel.materials.Count); + meshModel.materials.Add(material); } - - return meshModel; + meshModel.ids.Add(mesh.id); } - private static IEnumerable FlattenPoint(MeshModel.Vertex vertex) - { - return new List { vertex.x, vertex.y, vertex.z }; - } + return meshModel; + } - private static IEnumerable PolygonToSpeckle(MeshModel.Polygon polygon, int offset = 0) - { - var vertexIds = new List { polygon.pointIds.Count }; - vertexIds.AddRange(Enumerable.Range(0, polygon.pointIds.Count).Select(r => r + offset)); + private static IEnumerable FlattenPoint(MeshModel.Vertex vertex) + { + return new List { vertex.x, vertex.y, vertex.z }; + } - return vertexIds; - } + private static IEnumerable PolygonToSpeckle(MeshModel.Polygon polygon, int offset = 0) + { + var vertexIds = new List { polygon.pointIds.Count }; + vertexIds.AddRange(Enumerable.Range(0, polygon.pointIds.Count).Select(r => r + offset)); - private static List PolygonToNative(List polygon) - { - var result = new List(); + return vertexIds; + } + + private static List PolygonToNative(List polygon) + { + var result = new List(); - for (var i = 0; i < polygon.Count; i++) + for (var i = 0; i < polygon.Count; i++) + { + var n = polygon[i]; + if (n < 3) { - var n = polygon[i]; - if (n < 3) - n += 3; - result.Add(new MeshModel.Polygon { pointIds = polygon.GetRange(i + 1, n) }); - i += n; + n += 3; } - return result; + result.Add(new MeshModel.Polygon { pointIds = polygon.GetRange(i + 1, n) }); + i += n; } - private static RenderMaterial MaterialToSpeckle(Model.MeshModel.Material material) - { - System.Drawing.Color ConvertColor(Model.MeshModel.Material.Color color) - { - // In AC the Colors are encoded in ushort - return System.Drawing.Color.FromArgb(color.red / 256, color.green / 256, color.blue / 256); - } + return result; + } - return new RenderMaterial - { - name = material.name, - diffuse = ConvertColor(material.ambientColor).ToArgb(), - emissive = ConvertColor(material.emissionColor).ToArgb(), - opacity = 1.0 - material.transparency / 100.0 - }; + private static RenderMaterial MaterialToSpeckle(Model.MeshModel.Material material) + { + System.Drawing.Color ConvertColor(Model.MeshModel.Material.Color color) + { + // In AC the Colors are encoded in ushort + return System.Drawing.Color.FromArgb(color.red / 256, color.green / 256, color.blue / 256); } - private static Model.MeshModel.Material MaterialToNative(RenderMaterial renderMaterial) + return new RenderMaterial { - Model.MeshModel.Material.Color ConvertColor(System.Drawing.Color color) - { - // In AC the Colors are encoded in ushort - return new Model.MeshModel.Material.Color - { - red = color.R * 256, - green = color.G * 256, - blue = color.B * 256 - }; - } + name = material.name, + diffuse = ConvertColor(material.ambientColor).ToArgb(), + emissive = ConvertColor(material.emissionColor).ToArgb(), + opacity = 1.0 - material.transparency / 100.0 + }; + } - return new Model.MeshModel.Material + private static Model.MeshModel.Material MaterialToNative(RenderMaterial renderMaterial) + { + Model.MeshModel.Material.Color ConvertColor(System.Drawing.Color color) + { + // In AC the Colors are encoded in ushort + return new Model.MeshModel.Material.Color { - name = renderMaterial.name, - ambientColor = ConvertColor(System.Drawing.Color.FromArgb(renderMaterial.diffuse)), - emissionColor = ConvertColor(System.Drawing.Color.FromArgb(renderMaterial.emissive)), - transparency = (short)((1.0 - renderMaterial.opacity) * 100.0) + red = color.R * 256, + green = color.G * 256, + blue = color.B * 256 }; } - private static void ProcessPolygonEdges( - MeshModel meshModel, - Dictionary> neigbourPolygonsByEdge, - Dictionary polygonNormals, - Polygon polygon - ) + return new Model.MeshModel.Material { - for (var pointIdx = 0; pointIdx < polygon.pointIds.Count; pointIdx++) + name = renderMaterial.name, + ambientColor = ConvertColor(System.Drawing.Color.FromArgb(renderMaterial.diffuse)), + emissionColor = ConvertColor(System.Drawing.Color.FromArgb(renderMaterial.emissive)), + transparency = (short)((1.0 - renderMaterial.opacity) * 100.0) + }; + } + + private static void ProcessPolygonEdges( + MeshModel meshModel, + Dictionary> neigbourPolygonsByEdge, + Dictionary polygonNormals, + Polygon polygon + ) + { + for (var pointIdx = 0; pointIdx < polygon.pointIds.Count; pointIdx++) + { + var edge = new EdgeId(polygon.pointIds[pointIdx], polygon.pointIds[(pointIdx + 1) % polygon.pointIds.Count]); + if (TryGetNeigbourPolygonListByEdge(neigbourPolygonsByEdge, ref edge, out List neigbourPolygonIdxs)) { - var edge = new EdgeId(polygon.pointIds[pointIdx], polygon.pointIds[(pointIdx + 1) % polygon.pointIds.Count]); - if (TryGetNeigbourPolygonListByEdge(neigbourPolygonsByEdge, ref edge, out List neigbourPolygonIdxs)) + if (!neigbourPolygonIdxs.Contains(meshModel.polygons.Count)) { - if (!neigbourPolygonIdxs.Contains(meshModel.polygons.Count)) - { - neigbourPolygonIdxs.Add(meshModel.polygons.Count); + neigbourPolygonIdxs.Add(meshModel.polygons.Count); - if (neigbourPolygonIdxs.Count > 2) - meshModel.edges[edge] = new EdgeData(EdgeStatus.HiddenEdge); - else if (IsHiddenEdge(edge, meshModel.polygons[neigbourPolygonIdxs[0]], polygon, polygonNormals, meshModel)) - { - meshModel.edges[edge] = new EdgeData(EdgeStatus.HiddenEdge); - } + if (neigbourPolygonIdxs.Count > 2) + { + meshModel.edges[edge] = new EdgeData(EdgeStatus.HiddenEdge); + } + else if (IsHiddenEdge(edge, meshModel.polygons[neigbourPolygonIdxs[0]], polygon, polygonNormals, meshModel)) + { + meshModel.edges[edge] = new EdgeData(EdgeStatus.HiddenEdge); } } - else - { - neigbourPolygonsByEdge.Add(edge, new List { meshModel.polygons.Count }); - meshModel.edges.Add(edge, new EdgeData(EdgeStatus.VisibleEdge)); - } + } + else + { + neigbourPolygonsByEdge.Add(edge, new List { meshModel.polygons.Count }); + meshModel.edges.Add(edge, new EdgeData(EdgeStatus.VisibleEdge)); } } + } - // try to find the list of neighbouring polygons of an edge - // returns true if the edge or its inversion is present in neigbourPolygonsByEdge dictionary as key - private static bool TryGetNeigbourPolygonListByEdge( - Dictionary> neigbourPolygonsByEdge, - ref EdgeId edge, - out List neigbourPolygonIndices - ) + // try to find the list of neighbouring polygons of an edge + // returns true if the edge or its inversion is present in neigbourPolygonsByEdge dictionary as key + private static bool TryGetNeigbourPolygonListByEdge( + Dictionary> neigbourPolygonsByEdge, + ref EdgeId edge, + out List neigbourPolygonIndices + ) + { + if (neigbourPolygonsByEdge.TryGetValue(edge, out neigbourPolygonIndices)) { - if (neigbourPolygonsByEdge.TryGetValue(edge, out neigbourPolygonIndices)) - return true; - edge = new EdgeId(edge.vertexId2, edge.vertexId1); - return neigbourPolygonsByEdge.TryGetValue(edge, out neigbourPolygonIndices); + return true; } - private static System.Numerics.Vector3 GetOrientedNormal( - Polygon polygon, - Dictionary polygonNormals, - MeshModel meshModel - ) - { - if (polygonNormals.TryGetValue(polygon, out System.Numerics.Vector3 normal)) - return normal; + edge = new EdgeId(edge.vertexId2, edge.vertexId1); + return neigbourPolygonsByEdge.TryGetValue(edge, out neigbourPolygonIndices); + } - normal = new System.Numerics.Vector3(); - System.Numerics.Vector3 vertex0, - vertex1, - vertex2; + private static System.Numerics.Vector3 GetOrientedNormal( + Polygon polygon, + Dictionary polygonNormals, + MeshModel meshModel + ) + { + if (polygonNormals.TryGetValue(polygon, out System.Numerics.Vector3 normal)) + { + return normal; + } - vertex0 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[0]]); + normal = new System.Numerics.Vector3(); + System.Numerics.Vector3 vertex0, + vertex1, + vertex2; - int count = polygon.pointIds.Count; - for (int first = count - 1, second = 0; second < count; first = second++) - { - vertex1 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[first]]); - vertex2 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[second]]); + vertex0 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[0]]); - normal += System.Numerics.Vector3.Cross(vertex1 - vertex0, vertex2 - vertex0); - } + int count = polygon.pointIds.Count; + for (int first = count - 1, second = 0; second < count; first = second++) + { + vertex1 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[first]]); + vertex2 = Utils.VertexToVector3(meshModel.vertices[polygon.pointIds[second]]); - polygonNormals.Add(polygon, normal); - return normal; + normal += System.Numerics.Vector3.Cross(vertex1 - vertex0, vertex2 - vertex0); } - private static int GetOrientation(EdgeId edge, Polygon polygon) + polygonNormals.Add(polygon, normal); + return normal; + } + + private static int GetOrientation(EdgeId edge, Polygon polygon) + { + int count = polygon.pointIds.Count; + for (int first = count - 1, second = 0; second < count; first = second++) { - int count = polygon.pointIds.Count; - for (int first = count - 1, second = 0; second < count; first = second++) + if (polygon.pointIds[first] == edge.vertexId1 && polygon.pointIds[second] == edge.vertexId2) + { + return 1; + } + + if (polygon.pointIds[first] == edge.vertexId2 && polygon.pointIds[second] == edge.vertexId1) { - if (polygon.pointIds[first] == edge.vertexId1 && polygon.pointIds[second] == edge.vertexId2) - return 1; - if (polygon.pointIds[first] == edge.vertexId2 && polygon.pointIds[second] == edge.vertexId1) - return -1; + return -1; } - return 0; } + return 0; + } - private static bool IsHiddenEdge( - EdgeId edge, - Polygon polygon1, - Polygon polygon2, - Dictionary polygonNormals, - MeshModel meshModel - ) - { - System.Numerics.Vector3 normal1 = - GetOrientation(edge, polygon1) * GetOrientedNormal(polygon1, polygonNormals, meshModel); - System.Numerics.Vector3 normal2 = - -1 * GetOrientation(edge, polygon2) * GetOrientedNormal(polygon2, polygonNormals, meshModel); + private static bool IsHiddenEdge( + EdgeId edge, + Polygon polygon1, + Polygon polygon2, + Dictionary polygonNormals, + MeshModel meshModel + ) + { + System.Numerics.Vector3 normal1 = + GetOrientation(edge, polygon1) * GetOrientedNormal(polygon1, polygonNormals, meshModel); + System.Numerics.Vector3 normal2 = + -1 * GetOrientation(edge, polygon2) * GetOrientedNormal(polygon2, polygonNormals, meshModel); - normal1 = System.Numerics.Vector3.Normalize(normal1); - normal2 = System.Numerics.Vector3.Normalize(normal2); + normal1 = System.Numerics.Vector3.Normalize(normal1); + normal2 = System.Numerics.Vector3.Normalize(normal2); - var angleCos = System.Numerics.Vector3.Dot(normal1, normal2); + var angleCos = System.Numerics.Vector3.Dot(normal1, normal2); - return angleCos > angleCosLimit; - } + return angleCos > angleCosLimit; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Elements/GridElement.cs b/ConnectorArchicad/ConnectorArchicad/Elements/GridElement.cs index 520c842f6a..91b117623b 100644 --- a/ConnectorArchicad/ConnectorArchicad/Elements/GridElement.cs +++ b/ConnectorArchicad/ConnectorArchicad/Elements/GridElement.cs @@ -2,33 +2,32 @@ using Objects.Geometry; using Objects.BuiltElements.Archicad; -namespace Archicad +namespace Archicad; + +public class GridElement { - public class GridElement - { - // Speckle-specific properties - // Base - public string? id { get; set; } - public string? applicationId { get; set; } + // Speckle-specific properties + // Base + public string? id { get; set; } + public string? applicationId { get; set; } - // Archicad API properties - // Element base - public string? elementType { get; set; } - public List? classifications { get; set; } + // Archicad API properties + // Element base + public string? elementType { get; set; } + public List? classifications { get; set; } - // Grid - public Point begin { get; set; } - public Point end { get; set; } - public string markerText { get; set; } - public bool isArc { get; set; } - public double arcAngle { get; set; } + // Grid + public Point begin { get; set; } + public Point end { get; set; } + public string markerText { get; set; } + public bool isArc { get; set; } + public double arcAngle { get; set; } - public GridElement() { } + public GridElement() { } - public GridElement(string id, string applicationId) - { - this.id = id; - this.applicationId = applicationId; - } + public GridElement(string id, string applicationId) + { + this.id = id; + this.applicationId = applicationId; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Elements/Object.cs b/ConnectorArchicad/ConnectorArchicad/Elements/Object.cs index 92d5e34fe9..fcfb383549 100644 --- a/ConnectorArchicad/ConnectorArchicad/Elements/Object.cs +++ b/ConnectorArchicad/ConnectorArchicad/Elements/Object.cs @@ -10,37 +10,36 @@ using Speckle.Newtonsoft.Json; using Archicad.Model; -namespace Archicad +namespace Archicad; + +public class ArchicadObject { - public class ArchicadObject - { - public string id { get; set; } - public string applicationId { get; set; } + public string id { get; set; } + public string applicationId { get; set; } - // Element base - public string elementType { get; set; } - public List classifications { get; set; } + // Element base + public string elementType { get; set; } + public List classifications { get; set; } - public ArchicadLevel level { get; set; } + public ArchicadLevel level { get; set; } - public string? layer { get; set; } + public string? layer { get; set; } - public Point pos { get; set; } - public Objects.Other.Transform transform { get; set; } + public Point pos { get; set; } + public Objects.Other.Transform transform { get; set; } - public List modelIds { get; set; } + public List modelIds { get; set; } - public string units { get; set; } + public string units { get; set; } - public ArchicadObject() { } + public ArchicadObject() { } - [SchemaInfo("ArchicadObject", "Creates an Archicad object.", "Archicad", "Structure")] - public ArchicadObject(string id, string applicationId, Point basePoint, List modelIds) - { - this.id = id; - this.applicationId = applicationId; - this.pos = basePoint; - this.modelIds = modelIds; - } + [SchemaInfo("ArchicadObject", "Creates an Archicad object.", "Archicad", "Structure")] + public ArchicadObject(string id, string applicationId, Point basePoint, List modelIds) + { + this.id = id; + this.applicationId = applicationId; + this.pos = basePoint; + this.modelIds = modelIds; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Elements/Room.cs b/ConnectorArchicad/ConnectorArchicad/Elements/Room.cs index a7bf63e8f4..ad906ce600 100644 --- a/ConnectorArchicad/ConnectorArchicad/Elements/Room.cs +++ b/ConnectorArchicad/ConnectorArchicad/Elements/Room.cs @@ -2,43 +2,42 @@ using System.Collections.Generic; using Objects.BuiltElements.Archicad; -namespace Archicad +namespace Archicad; + +public class Room { - public class Room - { - // Speckle-specific properties - // Base - public string? id { get; set; } - public string? applicationId { get; set; } + // Speckle-specific properties + // Base + public string? id { get; set; } + public string? applicationId { get; set; } - // General - public string? name { get; set; } - public string? number { get; set; } + // General + public string? name { get; set; } + public string? number { get; set; } - public double? area { get; set; } - public double? volume { get; set; } + public double? area { get; set; } + public double? volume { get; set; } - // Helper - public Point? basePoint { get; set; } // Archicad geometry kernel needed for calculation + // Helper + public Point? basePoint { get; set; } // Archicad geometry kernel needed for calculation - // Archicad API properties - // Element base - public string? elementType { get; set; } - public List? classifications { get; set; } - public ArchicadLevel? level { get; set; } - public string? layer { get; set; } + // Archicad API properties + // Element base + public string? elementType { get; set; } + public List? classifications { get; set; } + public ArchicadLevel? level { get; set; } + public string? layer { get; set; } - // Room - public double? height { get; set; } + // Room + public double? height { get; set; } - public ElementShape? shape { get; set; } + public ElementShape? shape { get; set; } - public Room() { } + public Room() { } - public Room(string id, string applicationId) - { - this.id = id; - this.applicationId = applicationId; - } + public Room(string id, string applicationId) + { + this.id = id; + this.applicationId = applicationId; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Helpers/Timer.cs b/ConnectorArchicad/ConnectorArchicad/Helpers/Timer.cs index 659ca9b725..0e68efa3e8 100755 --- a/ConnectorArchicad/ConnectorArchicad/Helpers/Timer.cs +++ b/ConnectorArchicad/ConnectorArchicad/Helpers/Timer.cs @@ -1,44 +1,43 @@ using System; using Speckle.Core.Logging; -namespace Archicad.Helpers +namespace Archicad.Helpers; + +public class Timer : IDisposable { - public class Timer : IDisposable + internal sealed class Context : Speckle.Core.Helpers.State + { + public Speckle.Core.Logging.CumulativeTimer cumulativeTimer = null; + } + + private SerilogTimings.Operation serilogOperation = null; + + public static Timer CreateReceive(string streamId) + { + return new Timer("Receive stream {streamId}", streamId); + } + + public static Timer CreateSend(string streamId) + { + return new Timer("Send stream {streamId}", streamId); + } + + public Timer(string messageTemplate, params object[] args) + { + Context context = Context.Push(); + serilogOperation = SerilogTimings.Operation.Begin(messageTemplate, args); + context.cumulativeTimer = new CumulativeTimer(); + } + + public void Cancel() + { + serilogOperation.Cancel(); + } + + void IDisposable.Dispose() { - internal sealed class Context : Speckle.Core.Helpers.State - { - public Speckle.Core.Logging.CumulativeTimer cumulativeTimer = null; - } - - private SerilogTimings.Operation serilogOperation = null; - - public static Timer CreateReceive(string streamId) - { - return new Timer("Receive stream {streamId}", streamId); - } - - public static Timer CreateSend(string streamId) - { - return new Timer("Send stream {streamId}", streamId); - } - - public Timer(string messageTemplate, params object[] args) - { - Context context = Context.Push(); - serilogOperation = SerilogTimings.Operation.Begin(messageTemplate, args); - context.cumulativeTimer = new CumulativeTimer(); - } - - public void Cancel () - { - serilogOperation.Cancel(); - } - - void IDisposable.Dispose() - { - Context context = Context.Peek; - context?.cumulativeTimer?.EnrichSerilogOperation(serilogOperation); - serilogOperation.Complete(); - } + Context context = Context.Peek; + context?.cumulativeTimer?.EnrichSerilogOperation(serilogOperation); + serilogOperation.Complete(); } } diff --git a/ConnectorArchicad/ConnectorArchicad/Model/ElementModelData.cs b/ConnectorArchicad/ConnectorArchicad/Model/ElementModelData.cs index d5733b6dad..3d5772556c 100644 --- a/ConnectorArchicad/ConnectorArchicad/Model/ElementModelData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Model/ElementModelData.cs @@ -1,13 +1,12 @@ -namespace Archicad.Model +namespace Archicad.Model; + +public sealed class ElementModelData { - public sealed class ElementModelData - { - #region --- Fields --- + #region --- Fields --- - public MeshModel model { get; set; } + public MeshModel model { get; set; } - public string applicationId { get; set; } + public string applicationId { get; set; } - #endregion - } + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Model/MeshModel.cs b/ConnectorArchicad/ConnectorArchicad/Model/MeshModel.cs index e5b687f60e..e2de3ae868 100644 --- a/ConnectorArchicad/ConnectorArchicad/Model/MeshModel.cs +++ b/ConnectorArchicad/ConnectorArchicad/Model/MeshModel.cs @@ -1,265 +1,279 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using Objects.Geometry; using Speckle.Newtonsoft.Json; using Speckle.Newtonsoft.Json.Linq; -namespace Archicad.Model +namespace Archicad.Model; + +public sealed class MeshModel { - public sealed class MeshModel + public enum EdgeStatus { - public enum EdgeStatus - { - HiddenEdge = 1, // invisible - SmoothEdge = 2, // visible if countour bit - VisibleEdge = 3 // visible (AKA hard, sharp, welded edge) - }; + HiddenEdge = 1, // invisible + SmoothEdge = 2, // visible if countour bit + VisibleEdge = 3 // visible (AKA hard, sharp, welded edge) + }; - #region --- Classes --- + #region --- Classes --- - public class MeshModelEdgeConverter : JsonConverter> + public class MeshModelEdgeConverter : JsonConverter> + { + public override void WriteJson(JsonWriter writer, Dictionary value, JsonSerializer serializer) { - public override void WriteJson(JsonWriter writer, Dictionary value, JsonSerializer serializer) - { - StringBuilder jsonString = new StringBuilder(); - jsonString.Append("["); + StringBuilder jsonString = new(); + jsonString.Append("["); - bool first = true; - foreach (var entry in value) + bool first = true; + foreach (var entry in value) + { + // skip hidden edges + if (entry.Value.edgeStatus == EdgeStatus.HiddenEdge) { - // skip hidden edges - if (entry.Value.edgeStatus == EdgeStatus.HiddenEdge) - continue; - - if (!first) - jsonString.Append(", "); - else - first = false; - - jsonString.Append("{ \"v1\": "); - jsonString.Append(entry.Key.vertexId1.ToString()); + continue; + } - jsonString.Append(", \"v2\": "); - jsonString.Append(entry.Key.vertexId2.ToString()); + if (!first) + { + jsonString.Append(", "); + } + else + { + first = false; + } - if (entry.Value.polygonId1 != EdgeData.InvalidPolygonId) - { - jsonString.Append(", \"p1\": "); - jsonString.Append(entry.Value.polygonId1.ToString()); - } + jsonString.Append("{ \"v1\": "); + jsonString.Append(entry.Key.vertexId1.ToString()); - if (entry.Value.polygonId2 != EdgeData.InvalidPolygonId) - { - jsonString.Append(", \"p2\": "); - jsonString.Append(entry.Value.polygonId2.ToString()); - } + jsonString.Append(", \"v2\": "); + jsonString.Append(entry.Key.vertexId2.ToString()); - jsonString.Append(", \"s\": \""); - jsonString.Append(entry.Value.edgeStatus.ToString()); + if (entry.Value.polygonId1 != EdgeData.InvalidPolygonId) + { + jsonString.Append(", \"p1\": "); + jsonString.Append(entry.Value.polygonId1.ToString()); + } - jsonString.Append("\" }"); + if (entry.Value.polygonId2 != EdgeData.InvalidPolygonId) + { + jsonString.Append(", \"p2\": "); + jsonString.Append(entry.Value.polygonId2.ToString()); } - jsonString.Append("]"); - writer.WriteRawValue(jsonString.ToString()); + jsonString.Append(", \"s\": \""); + jsonString.Append(entry.Value.edgeStatus.ToString()); + + jsonString.Append("\" }"); } - public override Dictionary ReadJson( - JsonReader reader, - Type objectType, - Dictionary existingValue, - bool hasExistingValue, - JsonSerializer serializer - ) - { - Dictionary edges = new Dictionary(); + jsonString.Append("]"); + writer.WriteRawValue(jsonString.ToString()); + } - JArray ja = JArray.Load(reader); + public override Dictionary ReadJson( + JsonReader reader, + Type objectType, + Dictionary existingValue, + bool hasExistingValue, + JsonSerializer serializer + ) + { + Dictionary edges = new(); - foreach (JObject jo in ja) - { - JToken v1; - jo.TryGetValue("v1", out v1); + JArray ja = JArray.Load(reader); + + foreach (JObject jo in ja) + { + JToken v1; + jo.TryGetValue("v1", out v1); - JToken v2; - jo.TryGetValue("v2", out v2); + JToken v2; + jo.TryGetValue("v2", out v2); - JToken s; - jo.TryGetValue("s", out s); + JToken s; + jo.TryGetValue("s", out s); - JToken p1; - jo.TryGetValue("p1", out p1); + JToken p1; + jo.TryGetValue("p1", out p1); - JToken p2; - jo.TryGetValue("p2", out p2); + JToken p2; + jo.TryGetValue("p2", out p2); - if (v1 == null || v2 == null || s == null) - continue; + if (v1 == null || v2 == null || s == null) + { + continue; + } - EdgeId edgeId = new EdgeId(((int)v1), ((int)v2)); + EdgeId edgeId = new(((int)v1), ((int)v2)); - MeshModel.EdgeStatus edgeStatus = MeshModel.EdgeStatus.HiddenEdge; - if (((string)s).Equals("SmoothEdge")) - edgeStatus = MeshModel.EdgeStatus.SmoothEdge; - else if (((string)s).Equals("VisibleEdge")) - edgeStatus = MeshModel.EdgeStatus.VisibleEdge; + MeshModel.EdgeStatus edgeStatus = MeshModel.EdgeStatus.HiddenEdge; + if (((string)s).Equals("SmoothEdge")) + { + edgeStatus = MeshModel.EdgeStatus.SmoothEdge; + } + else if (((string)s).Equals("VisibleEdge")) + { + edgeStatus = MeshModel.EdgeStatus.VisibleEdge; + } - EdgeData edgeData = new EdgeData( + EdgeData edgeData = + new( edgeStatus, p1 != null ? ((int)p1) : MeshModel.EdgeData.InvalidPolygonId, p2 != null ? ((int)p2) : MeshModel.EdgeData.InvalidPolygonId ); - edges.Add(edgeId, edgeData); - } - - return edges; + edges.Add(edgeId, edgeData); } + + return edges; } + } - public sealed class Vertex - { - #region --- Fields --- + public sealed class Vertex + { + #region --- Fields --- - public double x { get; set; } + public double x { get; set; } - public double y { get; set; } + public double y { get; set; } - public double z { get; set; } + public double z { get; set; } - public bool Equals(Vertex vertex) => vertex.x.Equals(x) && vertex.y.Equals(y) && vertex.z.Equals(z); + public bool Equals(Vertex vertex) => vertex.x.Equals(x) && vertex.y.Equals(y) && vertex.z.Equals(z); - public override bool Equals(object o) => Equals(o as Vertex); + public override bool Equals(object o) => Equals(o as Vertex); - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - #endregion - } + #endregion + } - public sealed class EdgeId - { - #region --- Fields --- + public sealed class EdgeId + { + #region --- Fields --- - public int vertexId1 { get; set; } + public int vertexId1 { get; set; } - public int vertexId2 { get; set; } + public int vertexId2 { get; set; } - #endregion + #endregion - #region --- Methods --- + #region --- Methods --- - public EdgeId(int vertexId1, int vertexId2) - { - this.vertexId1 = vertexId1; - this.vertexId2 = vertexId2; - } - - public bool Equals(EdgeId edge) => edge.vertexId1.Equals(vertexId1) && edge.vertexId2.Equals(vertexId2); + public EdgeId(int vertexId1, int vertexId2) + { + this.vertexId1 = vertexId1; + this.vertexId2 = vertexId2; + } - public override bool Equals(object o) => Equals(o as EdgeId); + public bool Equals(EdgeId edge) => edge.vertexId1.Equals(vertexId1) && edge.vertexId2.Equals(vertexId2); - public override int GetHashCode() => vertexId1.GetHashCode() ^ vertexId2.GetHashCode(); + public override bool Equals(object o) => Equals(o as EdgeId); - #endregion - } + public override int GetHashCode() => vertexId1.GetHashCode() ^ vertexId2.GetHashCode(); - public sealed class EdgeData - { - public const int InvalidPolygonId = -1; + #endregion + } - #region --- Fields --- + public sealed class EdgeData + { + public const int InvalidPolygonId = -1; - public EdgeStatus edgeStatus { get; set; } + #region --- Fields --- - public int polygonId1 { get; set; } + public EdgeStatus edgeStatus { get; set; } - public int polygonId2 { get; set; } + public int polygonId1 { get; set; } - #endregion + public int polygonId2 { get; set; } - #region --- Methods --- + #endregion - public EdgeData(EdgeStatus edgeStatus, int polygonId1 = InvalidPolygonId, int polygonId2 = InvalidPolygonId) - { - this.edgeStatus = edgeStatus; - this.polygonId1 = polygonId1; - this.polygonId2 = polygonId2; - } + #region --- Methods --- - #endregion + public EdgeData(EdgeStatus edgeStatus, int polygonId1 = InvalidPolygonId, int polygonId2 = InvalidPolygonId) + { + this.edgeStatus = edgeStatus; + this.polygonId1 = polygonId1; + this.polygonId2 = polygonId2; } - public sealed class Material - { - #region --- Classes --- + #endregion + } - public class Color - { - public int red { get; set; } + public sealed class Material + { + #region --- Classes --- - public int green { get; set; } + public class Color + { + public int red { get; set; } - public int blue { get; set; } - } + public int green { get; set; } - #endregion + public int blue { get; set; } + } - #region --- Fields --- + #endregion - public string name { get; set; } + #region --- Fields --- - public Color ambientColor { get; set; } + public string name { get; set; } - public Color emissionColor { get; set; } + public Color ambientColor { get; set; } - public short transparency { get; set; } + public Color emissionColor { get; set; } - #endregion - } + public short transparency { get; set; } - public sealed class Polygon - { - public List pointIds { get; set; } = new List(); + #endregion + } - public int material { get; set; } - } + public sealed class Polygon + { + public List pointIds { get; set; } = new List(); - #endregion + public int material { get; set; } + } - #region --- Fields --- + #endregion + + #region --- Fields --- - public List ids { get; set; } = new List(); + public List ids { get; set; } = new List(); - public List vertices { get; set; } = new List(); + public List vertices { get; set; } = new List(); - [JsonConverter(typeof(MeshModelEdgeConverter))] - public Dictionary edges { get; set; } = new Dictionary(); + [JsonConverter(typeof(MeshModelEdgeConverter))] + public Dictionary edges { get; set; } = new Dictionary(); - public List polygons { get; set; } = new List(); + public List polygons { get; set; } = new List(); - public List materials { get; set; } = new List(); + public List materials { get; set; } = new List(); - public bool IsCoplanar(Polygon polygon) + public bool IsCoplanar(Polygon polygon) + { + Vector vector1 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[0]]); + Vector vector2 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[1]]); + Vector vector3 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[2]]); + for (int i = 3; i < polygon.pointIds.Count; i++) { - Vector vector1 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[0]]); - Vector vector2 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[1]]); - Vector vector3 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[2]]); - for (int i = 3; i < polygon.pointIds.Count; i++) + Vector vector4 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[i]]); + if (!IsCoplanar(vector1, vector2, vector3, vector4)) { - Vector vector4 = Archicad.Converters.Utils.VertexToVector(vertices[polygon.pointIds[i]]); - if (!IsCoplanar(vector1, vector2, vector3, vector4)) - return false; + return false; } - return true; - } - - private bool IsCoplanar(Vector vector1, Vector vector2, Vector vector3, Vector vector4) - { - var dotProduct = Vector.DotProduct(vector2 - vector1, Vector.CrossProduct(vector4 - vector1, vector3 - vector1)); - return Math.Abs(dotProduct) < Speckle.Core.Helpers.Constants.SmallEps; } + return true; + } - #endregion + private bool IsCoplanar(Vector vector1, Vector vector2, Vector vector3, Vector vector4) + { + var dotProduct = Vector.DotProduct(vector2 - vector1, Vector.CrossProduct(vector4 - vector1, vector3 - vector1)); + return Math.Abs(dotProduct) < Speckle.Core.Helpers.Constants.SmallEps; } + + #endregion } diff --git a/ConnectorArchicad/ConnectorArchicad/Model/ProjectInfoData.cs b/ConnectorArchicad/ConnectorArchicad/Model/ProjectInfoData.cs index 2ca7de6f37..fbe05970e3 100644 --- a/ConnectorArchicad/ConnectorArchicad/Model/ProjectInfoData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Model/ProjectInfoData.cs @@ -1,55 +1,54 @@ -namespace Archicad.Model +namespace Archicad.Model; + +public sealed class ProjectInfoData { - public sealed class ProjectInfoData - { - public string name { get; set; } = string.Empty; - public string location { get; set; } = string.Empty; - public LengthUnit lengthUnit { get; set; } = 0; - public AreaUnit areaUnit { get; set; } = 0; - public VolumeUnit volumeUnit { get; set; } = 0; - public AngleUnit angleUnit { get; set; } = 0; - } + public string name { get; set; } = string.Empty; + public string location { get; set; } = string.Empty; + public LengthUnit lengthUnit { get; set; } = 0; + public AreaUnit areaUnit { get; set; } = 0; + public VolumeUnit volumeUnit { get; set; } = 0; + public AngleUnit angleUnit { get; set; } = 0; +} - public enum LengthUnit - { - Meter, - Decimeter, - Centimeter, - Millimeter, - FootFracInch, - FootDecInch, - DecFoot, - FracInch, - DecInch - } +public enum LengthUnit +{ + Meter, + Decimeter, + Centimeter, + Millimeter, + FootFracInch, + FootDecInch, + DecFoot, + FracInch, + DecInch +} - public enum AreaUnit - { - SquareMeter, - SquareCentimeter, - SquareMillimeter, - SquareFoot, - SquareInch - } +public enum AreaUnit +{ + SquareMeter, + SquareCentimeter, + SquareMillimeter, + SquareFoot, + SquareInch +} - public enum VolumeUnit - { - CubicMeter, - Liter, - CubicCentimeter, - CubicMillimeter, - CubicFoot, - CubicInch, - CubicYard, - Gallon - } +public enum VolumeUnit +{ + CubicMeter, + Liter, + CubicCentimeter, + CubicMillimeter, + CubicFoot, + CubicInch, + CubicYard, + Gallon +} - public enum AngleUnit - { - DecimalDegree, - DegreeMinSec, - Grad, - Radian, - Surveyors - } +public enum AngleUnit +{ + DecimalDegree, + DegreeMinSec, + Grad, + Radian, + Surveyors } diff --git a/ConnectorArchicad/ConnectorArchicad/Program.cs b/ConnectorArchicad/ConnectorArchicad/Program.cs index ddca50840a..4f592b5ae7 100644 --- a/ConnectorArchicad/ConnectorArchicad/Program.cs +++ b/ConnectorArchicad/ConnectorArchicad/Program.cs @@ -8,67 +8,77 @@ using DesktopUI2.Views; using Speckle.Core.Logging; -namespace Archicad.Launcher +namespace Archicad.Launcher; + +class Program { - class Program - { - public static Window? MainWindow { get; private set; } - public static ArchicadBinding? Bindings { get; set; } + public static Window? MainWindow { get; private set; } + public static ArchicadBinding? Bindings { get; set; } - public static void Main(string[] args) + public static void Main(string[] args) + { + if (args.Length != 2) { - if (args.Length != 2) - { - System.Diagnostics.Debug.Fail("Communication port number is missing!"); - return; - } + System.Diagnostics.Debug.Fail("Communication port number is missing!"); + return; + } - if (!uint.TryParse(args[0], out uint portNumber)) - { - System.Diagnostics.Debug.Fail("Invalid communication port number!"); - return; - } + if (!uint.TryParse(args[0], out uint portNumber)) + { + System.Diagnostics.Debug.Fail("Invalid communication port number!"); + return; + } - if (!uint.TryParse(args[1], out uint archicadVersion)) - { - System.Diagnostics.Debug.Fail("Invalid Archicad version number!"); - return; - } + if (!uint.TryParse(args[1], out uint archicadVersion)) + { + System.Diagnostics.Debug.Fail("Invalid Archicad version number!"); + return; + } - Communication.ConnectionManager.Instance.Start(portNumber); + Communication.ConnectionManager.Instance.Start(portNumber); - Bindings = new ArchicadBinding(archicadVersion); - Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); + Bindings = new ArchicadBinding(archicadVersion); + Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); - CreateOrFocusSpeckle(args); - // BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, Avalonia.Controls.ShutdownMode.OnMainWindowClose); - } + CreateOrFocusSpeckle(args); + // BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, Avalonia.Controls.ShutdownMode.OnMainWindowClose); + } - public static void CreateOrFocusSpeckle(string[] args) + public static void CreateOrFocusSpeckle(string[] args) + { + if (MainWindow == null) { - if (MainWindow == null) - BuildAvaloniaApp().Start(AppMain, args); - - MainWindow.Show(); - MainWindow.Activate(); + BuildAvaloniaApp().Start(AppMain, args); } - public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() + MainWindow.Show(); + MainWindow.Activate(); + } + + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() .UsePlatformDetect() .With(new X11PlatformOptions { UseGpu = false }) - .With(new MacOSPlatformOptions { ShowInDock = true, DisableDefaultApplicationMenuItems = true, DisableNativeMenus = true }) + .With( + new MacOSPlatformOptions + { + ShowInDock = true, + DisableDefaultApplicationMenuItems = true, + DisableNativeMenus = true + } + ) .With(new AvaloniaNativePlatformOptions { UseGpu = false, UseDeferredRendering = true }) .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) .LogToTrace() .UseReactiveUI(); - private static void AppMain(Application app, string[] args) - { - var viewModel = new MainViewModel(Bindings); - MainWindow = new MainWindow { DataContext = viewModel }; + private static void AppMain(Application app, string[] args) + { + var viewModel = new MainViewModel(Bindings); + MainWindow = new MainWindow { DataContext = viewModel }; - app.Run(MainWindow); - } + app.Run(MainWindow); } } diff --git a/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Selection.cs b/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Selection.cs index b3d12cc75a..fda8c4e9c5 100644 --- a/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Selection.cs +++ b/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Selection.cs @@ -3,13 +3,12 @@ using System.Linq; using Archicad.Communication; -namespace Archicad.Launcher +namespace Archicad.Launcher; + +public partial class ArchicadBinding { - public partial class ArchicadBinding + public override void SelectClientObjects(List elemntIds, bool deselect = false) { - public override void SelectClientObjects(List elemntIds, bool deselect = false) - { - var result = AsyncCommandProcessor.Execute(new Communication.Commands.SelectElements(elemntIds, deselect))?.Result; - } + var result = AsyncCommandProcessor.Execute(new Communication.Commands.SelectElements(elemntIds, deselect))?.Result; } } diff --git a/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Settings.cs b/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Settings.cs index 9bf4397d5f..d9641a4a1e 100644 --- a/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Settings.cs +++ b/ConnectorArchicad/ConnectorArchicad/UI/ConnectorBinding.Settings.cs @@ -2,16 +2,22 @@ using System.Linq; using DesktopUI2.Models.Settings; -namespace Archicad.Launcher +namespace Archicad.Launcher; + +public partial class ArchicadBinding { - public partial class ArchicadBinding + public override List GetSettings() { - public override List GetSettings() + return new List { - return new List + new CheckBoxSetting { - new CheckBoxSetting {Slug = "receive - parametric", Name = "Receive parametric elements", Icon = "Link", IsChecked = false, Description = "Receive parametric elements where applicable"}, - }; - } + Slug = "receive - parametric", + Name = "Receive parametric elements", + Icon = "Link", + IsChecked = false, + Description = "Receive parametric elements where applicable" + }, + }; } } diff --git a/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/AdvanceSteelAddinRegistrator.csproj b/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/AdvanceSteelAddinRegistrator.csproj index 668de71c8e..2ab855a58d 100644 --- a/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/AdvanceSteelAddinRegistrator.csproj +++ b/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/AdvanceSteelAddinRegistrator.csproj @@ -8,9 +8,16 @@ false Pedro Henrique Liberato + + + 0 + false + false + + - \ No newline at end of file + diff --git a/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/Program.cs b/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/Program.cs index 1333a78062..552fd016dc 100644 --- a/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/Program.cs +++ b/ConnectorAutocadCivil/AdvanceSteelAddinRegistrator/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,153 +6,150 @@ using System.Threading.Tasks; using System.Xml.Serialization; -namespace AdvanceSteelAddinRegistrator +namespace AdvanceSteelAddinRegistrator; + +internal class Program { - internal class Program + private static string _year = null; + static string manifestBasePath => $"C:\\Program Files\\Autodesk\\AutoCAD {_year}\\ADVS\\Addons\\"; + static string addinPath => $"C:\\Program Files\\Autodesk\\Advance Steel Speckle Connector\\{_year}\\"; + private static string manifest => Path.Combine(manifestBasePath, "MyAddons.xml"); + const string addinDllName = "SpeckleConnectorAdvanceSteel.dll"; + const string addinName = "Speckle"; + + enum ExitCode : int + { + Success = 0, + ErrorParsingXml = 1, + ErrorUpdatingXml = 2, + ErrorWritingXml = 3, + NoAdminRights = 4, + Unknown = 5, + NoYearArgument = 6 + } + + static int Main(string[] args) { - private static string _year = null; - static string manifestBasePath => $"C:\\Program Files\\Autodesk\\AutoCAD {_year}\\ADVS\\Addons\\"; - static string addinPath => $"C:\\Program Files\\Autodesk\\Advance Steel Speckle Connector\\{_year}\\"; - private static string manifest => Path.Combine(manifestBasePath, "MyAddons.xml"); - const string addinDllName = "SpeckleConnectorAdvanceSteel.dll"; - const string addinName = "Speckle"; - - enum ExitCode : int + if (args == null || !args.Any() || args[0].Length != 4) { - Success = 0, - ErrorParsingXml = 1, - ErrorUpdatingXml = 2, - ErrorWritingXml = 3, - NoAdminRights = 4, - Unknown = 5, - NoYearArgument = 6 + Console.WriteLine("Please provide a Year argument (eg: '202X')"); + return (int)ExitCode.NoYearArgument; } - static int Main(string[] args) + + _year = args[0]; + + AddonsData addonsData = new(); + + try { - if (args == null || !args.Any() || args[0].Length!=4) + if (File.Exists(manifest)) { - Console.WriteLine("Please provide a Year argument (eg: '202X')"); - return (int)ExitCode.NoYearArgument; + addonsData = ParseManifestFile(); } - _year = args[0]; - - - AddonsData addonsData = new AddonsData(); - - try + if (!Directory.Exists(manifestBasePath)) { + Directory.CreateDirectory(manifestBasePath); + } - if (File.Exists(manifest)) - addonsData = ParseManifestFile(); - - if (!Directory.Exists(manifestBasePath)) - Directory.CreateDirectory(manifestBasePath); - - addonsData = UpdateManifestFile(addonsData); + addonsData = UpdateManifestFile(addonsData); - if (addonsData != null && addonsData.Addons.Any(x => x.Name == addinName)) - WriteManifestFile(addonsData); - } - catch (Exception ex) + if (addonsData != null && addonsData.Addons.Any(x => x.Name == addinName)) { - if (ex.InnerException != null && ex.InnerException is System.UnauthorizedAccessException) - { - Console.WriteLine("Admin Rights required to continue."); - return (int)ExitCode.NoAdminRights; - } - - else if (ex.Message.Contains("updating")) - { - Console.WriteLine(ex.Message); - return (int)ExitCode.ErrorUpdatingXml; - } - - else if (ex.Message.Contains("parsing")) - { - Console.WriteLine(ex.Message); - return (int)ExitCode.ErrorParsingXml; - } - - else if (ex.Message.Contains("writing")) - { - Console.WriteLine(ex.Message); - return (int)ExitCode.ErrorWritingXml; - } - - else - { - Console.WriteLine(ex.Message); - return (int)ExitCode.Unknown; - } - + WriteManifestFile(addonsData); } - return (int)ExitCode.Success; } - - private static AddonsData UpdateManifestFile(AddonsData addonsData) + catch (Exception ex) { - try + if (ex.InnerException != null && ex.InnerException is System.UnauthorizedAccessException) + { + Console.WriteLine("Admin Rights required to continue."); + return (int)ExitCode.NoAdminRights; + } + else if (ex.Message.Contains("updating")) { - //safety check - if (addonsData.Addons == null || !addonsData.Addons.Any()) - { - addonsData.Addons = new AddonsDataAddon[] { new AddonsDataAddon() }; - } - - if (addonsData.Addons.Any(x => x.Name == addinName)) - { - Console.WriteLine($"{addinName} addin already registered"); - return addonsData; - } - - addonsData.Addons = addonsData.Addons.Append(new AddonsDataAddon() { Name = addinName, FullPath = Path.Combine(addinPath, addinDllName) }).ToArray(); + Console.WriteLine(ex.Message); + return (int)ExitCode.ErrorUpdatingXml; } - catch (Exception ex) + else if (ex.Message.Contains("parsing")) { - throw new Exception($"Error updating manifest: {ex.Message}", ex); + Console.WriteLine(ex.Message); + return (int)ExitCode.ErrorParsingXml; + } + else if (ex.Message.Contains("writing")) + { + Console.WriteLine(ex.Message); + return (int)ExitCode.ErrorWritingXml; + } + else + { + Console.WriteLine(ex.Message); + return (int)ExitCode.Unknown; } - return addonsData; } + return (int)ExitCode.Success; + } - - private static AddonsData ParseManifestFile() + private static AddonsData UpdateManifestFile(AddonsData addonsData) + { + try { - - AddonsData addonsData = null; - try + //safety check + if (addonsData.Addons == null || !addonsData.Addons.Any()) { - - using (var stream = new FileStream(manifest, FileMode.Open)) - { - var serializer = new XmlSerializer(typeof(AddonsData)); - addonsData = serializer.Deserialize(stream) as AddonsData; - } + addonsData.Addons = new AddonsDataAddon[] { new() }; } - catch (Exception ex) + + if (addonsData.Addons.Any(x => x.Name == addinName)) { - throw new Exception($"Error parsing manifest: {ex.Message}", ex); + Console.WriteLine($"{addinName} addin already registered"); + return addonsData; } - return addonsData; - + addonsData.Addons = addonsData.Addons + .Append(new AddonsDataAddon() { Name = addinName, FullPath = Path.Combine(addinPath, addinDllName) }) + .ToArray(); + } + catch (Exception ex) + { + throw new Exception($"Error updating manifest: {ex.Message}", ex); } + return addonsData; + } - private static void WriteManifestFile(AddonsData addonsData) + private static AddonsData ParseManifestFile() + { + AddonsData addonsData = null; + try { - try + using (var stream = new FileStream(manifest, FileMode.Open)) { - using (var stream = new FileStream(manifest, FileMode.Create)) - { - var serializer = new XmlSerializer(typeof(AddonsData)); - serializer.Serialize(stream, addonsData); - stream.Close(); - } + var serializer = new XmlSerializer(typeof(AddonsData)); + addonsData = serializer.Deserialize(stream) as AddonsData; } - catch (Exception ex) + } + catch (Exception ex) + { + throw new Exception($"Error parsing manifest: {ex.Message}", ex); + } + + return addonsData; + } + + private static void WriteManifestFile(AddonsData addonsData) + { + try + { + using (var stream = new FileStream(manifest, FileMode.Create)) { - throw new Exception($"Error writing manifest: {ex.Message}", ex); + var serializer = new XmlSerializer(typeof(AddonsData)); + serializer.Serialize(stream, addonsData); + stream.Close(); } } + catch (Exception ex) + { + throw new Exception($"Error writing manifest: {ex.Message}", ex); + } } } diff --git a/ConnectorAutocadCivil/ConnectorAdvanceSteel2023/ConnectorAdvanceSteel2023.csproj b/ConnectorAutocadCivil/ConnectorAdvanceSteel2023/ConnectorAdvanceSteel2023.csproj index f7b63a6de1..7c1cf0a4c7 100644 --- a/ConnectorAutocadCivil/ConnectorAdvanceSteel2023/ConnectorAdvanceSteel2023.csproj +++ b/ConnectorAutocadCivil/ConnectorAdvanceSteel2023/ConnectorAdvanceSteel2023.csproj @@ -10,6 +10,13 @@ false Pedro Henrique Liberato + + + 0 + false + false + + @@ -61,4 +68,4 @@ - \ No newline at end of file + diff --git a/ConnectorAutocadCivil/ConnectorAdvanceSteel2024/ConnectorAdvanceSteel2024.csproj b/ConnectorAutocadCivil/ConnectorAdvanceSteel2024/ConnectorAdvanceSteel2024.csproj index 898f68ee64..571aa90fc2 100644 --- a/ConnectorAutocadCivil/ConnectorAdvanceSteel2024/ConnectorAdvanceSteel2024.csproj +++ b/ConnectorAutocadCivil/ConnectorAdvanceSteel2024/ConnectorAdvanceSteel2024.csproj @@ -10,6 +10,13 @@ false Pedro Henrique Liberato + + + 0 + false + false + + @@ -61,4 +68,4 @@ - \ No newline at end of file + diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/DocumentUtils/TransactionContext.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/DocumentUtils/TransactionContext.cs index 3677f82e52..97ac9e654f 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/DocumentUtils/TransactionContext.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/DocumentUtils/TransactionContext.cs @@ -10,69 +10,68 @@ using Autodesk.AutoCAD.DatabaseServices; #endif -namespace Speckle.ConnectorAutocadCivil.DocumentUtils -{ +namespace Speckle.ConnectorAutocadCivil.DocumentUtils; + #if ADVANCESTEEL - public class TransactionContext : IDisposable +public class TransactionContext : IDisposable +{ + private bool DocumentLocked = false; + private Autodesk.AdvanceSteel.CADAccess.Transaction Transaction = null; + + public static TransactionContext StartTransaction(Document document) { - private bool DocumentLocked = false; - private Autodesk.AdvanceSteel.CADAccess.Transaction Transaction = null; + return new TransactionContext(document); + } - public static TransactionContext StartTransaction(Document document) + private TransactionContext(Document document) + { + if (!DocumentLocked) { - return new TransactionContext(document); + DocumentLocked = DocumentManager.LockCurrentDocument(); } - private TransactionContext(Document document) + if (Transaction == null && DocumentLocked) { - if (!DocumentLocked) - { - DocumentLocked = DocumentManager.LockCurrentDocument(); - } - - if (Transaction == null && DocumentLocked) - { - Transaction = Autodesk.AdvanceSteel.CADAccess.TransactionManager.StartTransaction(); - } + Transaction = Autodesk.AdvanceSteel.CADAccess.TransactionManager.StartTransaction(); } + } - public void Dispose() - { - Transaction?.Commit(); - Transaction = null; + public void Dispose() + { + Transaction?.Commit(); + Transaction = null; - if (DocumentLocked == true) - { - DocumentManager.UnlockCurrentDocument(); - DocumentLocked = false; - } + if (DocumentLocked == true) + { + DocumentManager.UnlockCurrentDocument(); + DocumentLocked = false; } } +} #else - public class TransactionContext : IDisposable - { - private DocumentLock DocumentLock; - private Transaction Transaction; +public class TransactionContext : IDisposable +{ + private DocumentLock DocumentLock; + private Transaction Transaction; - public static TransactionContext StartTransaction(Document document) - { - return new TransactionContext(document); - } + public static TransactionContext StartTransaction(Document document) + { + return new TransactionContext(document); + } - private TransactionContext(Document document) - { - DocumentLock = document.LockDocument(); - Transaction = document.Database.TransactionManager.StartTransaction(); - } + private TransactionContext(Document document) + { + DocumentLock = document.LockDocument(); + Transaction = document.Database.TransactionManager.StartTransaction(); + } - public void Dispose() - { - Transaction?.Commit(); - Transaction = null; + public void Dispose() + { + Transaction?.Commit(); + Transaction = null; - DocumentLock?.Dispose(); - DocumentLock = null; - } + DocumentLock?.Dispose(); + DocumentLock = null; } -#endif } +#endif diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/App.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/App.cs index 432fe3ce29..6924657a22 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/App.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/App.cs @@ -21,244 +21,278 @@ [assembly: ExtensionApplication(typeof(Speckle.ConnectorAutocadCivil.Entry.App))] #endif -namespace Speckle.ConnectorAutocadCivil.Entry +namespace Speckle.ConnectorAutocadCivil.Entry; + +public class App : IExtensionApplication { - public class App : IExtensionApplication - { - public RibbonControl ribbon; + public RibbonControl ribbon; - #region Initializing and termination - public void Initialize() + #region Initializing and termination + public void Initialize() + { + try { - try - { - //Advance Steel addon is initialized after ribbon creation - bool advanceSteel = false; + //Advance Steel addon is initialized after ribbon creation + bool advanceSteel = false; #if ADVANCESTEEL - advanceSteel = true; + advanceSteel = true; #endif - ribbon = ComponentManager.Ribbon; - if (ribbon != null && !advanceSteel) //the assembly was loaded using netload - { - Create(); - } - else - { - // load the custom ribbon on startup, but wait for ribbon control to be created - ComponentManager.ItemInitialized += new System.EventHandler(ComponentManager_ItemInitialized); - Application.SystemVariableChanged += TrapWSCurrentChange; - } - - //Some dlls fail to load due to versions matching (0.10.7 vs 0.10.0) - //the below should fix it! This affects Avalonia and Material - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); - - // DUI2 - var bindings = new ConnectorBindingsAutocad(); - Setup.Init(bindings.GetHostAppNameVersion(), bindings.GetHostAppName()); - SpeckleAutocadCommand.InitAvalonia(); - bindings.RegisterAppEvents(); - SpeckleAutocadCommand.Bindings = bindings; + ribbon = ComponentManager.Ribbon; + if (ribbon != null && !advanceSteel) //the assembly was loaded using netload + { + Create(); } - catch (System.Exception e) + else { - Forms.MessageBox.Show($"Add-in initialize context (true = application, false = doc): {Application.DocumentManager.IsApplicationContext.ToString()}. Error encountered: {e.ToString()}"); + // load the custom ribbon on startup, but wait for ribbon control to be created + ComponentManager.ItemInitialized += new System.EventHandler( + ComponentManager_ItemInitialized + ); + Application.SystemVariableChanged += TrapWSCurrentChange; } - } - Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + //Some dlls fail to load due to versions matching (0.10.7 vs 0.10.0) + //the below should fix it! This affects Avalonia and Material + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); + + // DUI2 + var bindings = new ConnectorBindingsAutocad(); + Setup.Init(bindings.GetHostAppNameVersion(), bindings.GetHostAppName()); + SpeckleAutocadCommand.InitAvalonia(); + bindings.RegisterAppEvents(); + SpeckleAutocadCommand.Bindings = bindings; + } + catch (System.Exception e) { - Assembly a = null; - var name = args.Name.Split(',')[0]; - string path = Path.GetDirectoryName(typeof(App).Assembly.Location); + Forms.MessageBox.Show( + $"Add-in initialize context (true = application, false = doc): {Application.DocumentManager.IsApplicationContext.ToString()}. Error encountered: {e.ToString()}" + ); + } + } - string assemblyFile = Path.Combine(path, name + ".dll"); + Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly a = null; + var name = args.Name.Split(',')[0]; + string path = Path.GetDirectoryName(typeof(App).Assembly.Location); - if (File.Exists(assemblyFile)) - a = Assembly.LoadFrom(assemblyFile); + string assemblyFile = Path.Combine(path, name + ".dll"); - return a; + if (File.Exists(assemblyFile)) + { + a = Assembly.LoadFrom(assemblyFile); } - public void ComponentManager_ItemInitialized(object sender, RibbonItemEventArgs e) + return a; + } + + public void ComponentManager_ItemInitialized(object sender, RibbonItemEventArgs e) + { + // one Ribbon item is initialized, check for Ribbon control + ribbon = ComponentManager.Ribbon; + if (ribbon != null) { - // one Ribbon item is initialized, check for Ribbon control - ribbon = ComponentManager.Ribbon; - if (ribbon != null) - { - Create(); - // remove the event handler - ComponentManager.ItemInitialized -= new System.EventHandler(ComponentManager_ItemInitialized); - } + Create(); + // remove the event handler + ComponentManager.ItemInitialized -= new System.EventHandler( + ComponentManager_ItemInitialized + ); } + } - // solving workspace changing - public void TrapWSCurrentChange(object sender, SystemVariableChangedEventArgs e) + // solving workspace changing + public void TrapWSCurrentChange(object sender, SystemVariableChangedEventArgs e) + { + if (e.Name.Equals("WSCURRENT")) { - if (e.Name.Equals("WSCURRENT")) - Create(); + Create(); } + } - public void Create() + public void Create() + { + RibbonTab tab = FindOrMakeTab("Add-ins"); // add to Add-Ins tab + if (tab == null) { - RibbonTab tab = FindOrMakeTab("Add-ins"); // add to Add-Ins tab - if (tab == null) - return; - RibbonPanelSource panel = CreateButtonPanel("Speckle 2", tab); - if (panel == null) - return; - RibbonToolTip speckleTip = CreateToolTip("Speckle", "Speckle Connector for " + Utils.AppName); - RibbonToolTip oneClickTip = CreateToolTip("Send", "Sends your selected objects to your account's document stream. If nothing is selected, sends everything in the document."); - RibbonButton button = CreateButton("Connector " + Utils.AppName, "Speckle", panel, null, speckleTip, "logo"); - RibbonButton oneClickSendButton = CreateButton("Send", "SpeckleSend", panel, null, oneClickTip, "send"); - - // help and resources buttons - RibbonSplitButton helpButton = new RibbonSplitButton(); - helpButton.Text = "Help & Resources"; - helpButton.Image = LoadPngImgSource("help16.png"); - helpButton.LargeImage = LoadPngImgSource("help32.png"); - helpButton.ShowImage = true; - helpButton.ShowText = true; - helpButton.Size = RibbonItemSize.Large; - helpButton.Orientation = Orientation.Vertical; - panel.Items.Add(helpButton); - - RibbonToolTip communityTip = CreateToolTip("Community", "Check out our community forum! Opens a page in your web browser."); - RibbonToolTip tutorialsTip = CreateToolTip("Tutorials", "Check out our tutorials! Opens a page in your web browser"); - RibbonToolTip docsTip = CreateToolTip("Docs", "Check out our documentation! Opens a page in your web browser"); - RibbonButton community = CreateButton("Community", "SpeckleCommunity", null, helpButton, communityTip, "forum"); - RibbonButton tutorials = CreateButton("Tutorials", "SpeckleTutorials", null, helpButton, tutorialsTip, "tutorials"); - RibbonButton docs = CreateButton("Docs", "SpeckleDocs", null, helpButton, docsTip, "docs"); + return; } - public void Terminate() + RibbonPanelSource panel = CreateButtonPanel("Speckle 2", tab); + if (panel == null) { + return; } - private RibbonTab FindOrMakeTab(string name) - { - // check to see if tab exists - RibbonTab tab = ribbon.Tabs.Where(o => o.Title.Equals(name)).FirstOrDefault(); + RibbonToolTip speckleTip = CreateToolTip("Speckle", "Speckle Connector for " + Utils.AppName); + RibbonToolTip oneClickTip = CreateToolTip( + "Send", + "Sends your selected objects to your account's document stream. If nothing is selected, sends everything in the document." + ); + RibbonButton button = CreateButton("Connector " + Utils.AppName, "Speckle", panel, null, speckleTip, "logo"); + RibbonButton oneClickSendButton = CreateButton("Send", "SpeckleSend", panel, null, oneClickTip, "send"); + + // help and resources buttons + RibbonSplitButton helpButton = new(); + helpButton.Text = "Help & Resources"; + helpButton.Image = LoadPngImgSource("help16.png"); + helpButton.LargeImage = LoadPngImgSource("help32.png"); + helpButton.ShowImage = true; + helpButton.ShowText = true; + helpButton.Size = RibbonItemSize.Large; + helpButton.Orientation = Orientation.Vertical; + panel.Items.Add(helpButton); + + RibbonToolTip communityTip = CreateToolTip( + "Community", + "Check out our community forum! Opens a page in your web browser." + ); + RibbonToolTip tutorialsTip = CreateToolTip( + "Tutorials", + "Check out our tutorials! Opens a page in your web browser" + ); + RibbonToolTip docsTip = CreateToolTip("Docs", "Check out our documentation! Opens a page in your web browser"); + RibbonButton community = CreateButton("Community", "SpeckleCommunity", null, helpButton, communityTip, "forum"); + RibbonButton tutorials = CreateButton("Tutorials", "SpeckleTutorials", null, helpButton, tutorialsTip, "tutorials"); + RibbonButton docs = CreateButton("Docs", "SpeckleDocs", null, helpButton, docsTip, "docs"); + } - // if not, create a new one - if (tab == null) - { - tab = new RibbonTab(); - tab.Title = name; - tab.Id = name; - ribbon.Tabs.Add(tab); - } + public void Terminate() { } -#if !ADVANCESTEEL - tab.IsActive = true; // optional debug: set ribbon tab active -#endif - return tab; - } + private RibbonTab FindOrMakeTab(string name) + { + // check to see if tab exists + RibbonTab tab = ribbon.Tabs.Where(o => o.Title.Equals(name)).FirstOrDefault(); - private RibbonPanelSource CreateButtonPanel(string name, RibbonTab tab) + // if not, create a new one + if (tab == null) { - var source = new RibbonPanelSource() { Title = name }; - var panel = new RibbonPanel() { Source = source }; - tab.Panels.Add(panel); - return source; + tab = new RibbonTab(); + tab.Title = name; + tab.Id = name; + ribbon.Tabs.Add(tab); } - private RibbonToolTip CreateToolTip(string title, string content) - { - RibbonToolTip toolTip = new RibbonToolTip(); +#if !ADVANCESTEEL + tab.IsActive = true; // optional debug: set ribbon tab active +#endif + return tab; + } - //toolTip.Command = ""; - toolTip.Title = title; - toolTip.Content = content; - toolTip.IsHelpEnabled = true; // Without this "Press F1 for help" does not appear in the tooltip + private RibbonPanelSource CreateButtonPanel(string name, RibbonTab tab) + { + var source = new RibbonPanelSource() { Title = name }; + var panel = new RibbonPanel() { Source = source }; + tab.Panels.Add(panel); + return source; + } - return toolTip; - } + private RibbonToolTip CreateToolTip(string title, string content) + { + RibbonToolTip toolTip = new(); - private RibbonButton CreateButton(string name, string CommandParameter, RibbonPanelSource sourcePanel = null, RibbonSplitButton sourceButton = null, RibbonToolTip tooltip = null, string imageName = "") + //toolTip.Command = ""; + toolTip.Title = title; + toolTip.Content = content; + toolTip.IsHelpEnabled = true; // Without this "Press F1 for help" does not appear in the tooltip + + return toolTip; + } + + private RibbonButton CreateButton( + string name, + string CommandParameter, + RibbonPanelSource sourcePanel = null, + RibbonSplitButton sourceButton = null, + RibbonToolTip tooltip = null, + string imageName = "" + ) + { + var button = new RibbonButton(); + + // ribbon panel source info assignment + button.Text = name; + button.Id = name; + button.ShowImage = true; + button.ShowText = true; + button.ToolTip = tooltip; + button.HelpSource = new System.Uri("https://speckle.guide/user/autocadcivil.html"); + button.Size = RibbonItemSize.Large; + button.Image = LoadPngImgSource(imageName + "16.png"); + button.LargeImage = LoadPngImgSource(imageName + "32.png"); + + // add ribbon button pannel to the ribbon panel source + if (sourcePanel != null) { - var button = new RibbonButton(); - - // ribbon panel source info assignment - button.Text = name; - button.Id = name; - button.ShowImage = true; - button.ShowText = true; - button.ToolTip = tooltip; - button.HelpSource = new System.Uri("https://speckle.guide/user/autocadcivil.html"); - button.Size = RibbonItemSize.Large; - button.Image = LoadPngImgSource(imageName + "16.png"); - button.LargeImage = LoadPngImgSource(imageName + "32.png"); - - // add ribbon button pannel to the ribbon panel source - if (sourcePanel != null) - { - button.Orientation = Orientation.Vertical; - button.CommandParameter = CommandParameter; - button.CommandHandler = new ButtonCommandHandler(CommandParameter); - sourcePanel.Items.Add(button); - } - else if (sourceButton != null) - { - button.Orientation = Orientation.Horizontal; - button.CommandParameter = CommandParameter; - button.CommandHandler = new ButtonCommandHandler(CommandParameter); - sourceButton.Items.Add(button); - } - return button; + button.Orientation = Orientation.Vertical; + button.CommandParameter = CommandParameter; + button.CommandHandler = new ButtonCommandHandler(CommandParameter); + sourcePanel.Items.Add(button); } + else if (sourceButton != null) + { + button.Orientation = Orientation.Horizontal; + button.CommandParameter = CommandParameter; + button.CommandHandler = new ButtonCommandHandler(CommandParameter); + sourceButton.Items.Add(button); + } + return button; + } - private ImageSource LoadPngImgSource(string sourceName) + private ImageSource LoadPngImgSource(string sourceName) + { + try { - try - { - string resource = this.GetType().Assembly.GetManifestResourceNames().Where(o => o.EndsWith(sourceName)).FirstOrDefault(); - Assembly assembly = Assembly.GetExecutingAssembly(); - Stream stream = assembly.GetManifestResourceStream(resource); - PngBitmapDecoder decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); - ImageSource source = decoder.Frames[0]; - return source; - } - catch { } - return null; + string resource = this.GetType() + .Assembly.GetManifestResourceNames() + .Where(o => o.EndsWith(sourceName)) + .FirstOrDefault(); + Assembly assembly = Assembly.GetExecutingAssembly(); + Stream stream = assembly.GetManifestResourceStream(resource); + PngBitmapDecoder decoder = new(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); + ImageSource source = decoder.Frames[0]; + return source; } + catch { } + return null; + } - #endregion + #endregion - public class ButtonCommandHandler : System.Windows.Input.ICommand - { - private string commandParameter; + public class ButtonCommandHandler : System.Windows.Input.ICommand + { + private string commandParameter; - public ButtonCommandHandler(string commandParameter) - { - this.commandParameter = commandParameter; - } + public ButtonCommandHandler(string commandParameter) + { + this.commandParameter = commandParameter; + } - public event System.EventHandler CanExecuteChanged; + public event System.EventHandler CanExecuteChanged; - public void Execute(object parameter) + public void Execute(object parameter) + { + RibbonButton btn = parameter as RibbonButton; + if (btn != null) { - RibbonButton btn = parameter as RibbonButton; - if (btn != null) - switch (commandParameter) - { - case "Speckle": - SpeckleAutocadCommand.SpeckleCommand(); - break; - case "SpeckleCommunity": - SpeckleAutocadCommand.SpeckleCommunity(); - break; - case "SpeckleTutorials": - SpeckleAutocadCommand.SpeckleTutorials(); - break; - case "SpeckleDocs": - SpeckleAutocadCommand.SpeckleDocs(); - break; - } + switch (commandParameter) + { + case "Speckle": + SpeckleAutocadCommand.SpeckleCommand(); + break; + case "SpeckleCommunity": + SpeckleAutocadCommand.SpeckleCommunity(); + break; + case "SpeckleTutorials": + SpeckleAutocadCommand.SpeckleTutorials(); + break; + case "SpeckleDocs": + SpeckleAutocadCommand.SpeckleDocs(); + break; + } } - - public bool CanExecute(object parameter) => true; } + + public bool CanExecute(object parameter) => true; } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/SpeckleAutocadCommand.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/SpeckleAutocadCommand.cs index 9bb9b077d9..0ca03ba939 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/SpeckleAutocadCommand.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/Entry/SpeckleAutocadCommand.cs @@ -27,145 +27,158 @@ [assembly: CommandClass(typeof(Speckle.ConnectorAutocadCivil.Entry.SpeckleAutocadCommand))] #endif -namespace Speckle.ConnectorAutocadCivil.Entry +namespace Speckle.ConnectorAutocadCivil.Entry; + +public class SpeckleAutocadCommand { - public class SpeckleAutocadCommand - { - #region Avalonia parent window - [DllImport("user32.dll", SetLastError = true)] - [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] - static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); - const int GWL_HWNDPARENT = -8; - #endregion - private static Avalonia.Application AvaloniaApp { get; set; } - public static Window MainWindow { get; private set; } - private static CancellationTokenSource Lifetime = null; - public static ConnectorBindingsAutocad Bindings { get; set; } - - public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() + #region Avalonia parent window + [DllImport("user32.dll", SetLastError = true)] + [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] + static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); + + const int GWL_HWNDPARENT = -8; + #endregion + private static Avalonia.Application AvaloniaApp { get; set; } + public static Window MainWindow { get; private set; } + private static CancellationTokenSource Lifetime = null; + public static ConnectorBindingsAutocad Bindings { get; set; } + + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() .UsePlatformDetect() .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) .LogToTrace() .UseReactiveUI(); - /// - /// Main command to initialize Speckle Connector - /// - [CommandMethod("Speckle", CommandFlags.Modal)] - public static void SpeckleCommand() - { - CreateOrFocusSpeckle(); - } + /// + /// Main command to initialize Speckle Connector + /// + [CommandMethod("Speckle", CommandFlags.Modal)] + public static void SpeckleCommand() + { + CreateOrFocusSpeckle(); + } - public static void InitAvalonia() + public static void InitAvalonia() + { + BuildAvaloniaApp().Start(AppMain, null); + } + + public static void CreateOrFocusSpeckle(bool showWindow = true) + { + if (MainWindow == null) { - BuildAvaloniaApp().Start(AppMain, null); + var viewModel = new MainViewModel(Bindings); + MainWindow = new MainWindow { DataContext = viewModel }; } - public static void CreateOrFocusSpeckle(bool showWindow = true) + try { - if (MainWindow == null) + if (showWindow) { - var viewModel = new MainViewModel(Bindings); - MainWindow = new MainWindow + MainWindow.Show(); + MainWindow.Activate(); + + //required to gracefully quit avalonia and the skia processes + //https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes + if (Lifetime == null) { - DataContext = viewModel - }; - } + Lifetime = new CancellationTokenSource(); + Task.Run(() => AvaloniaApp.Run(Lifetime.Token)); + } - try - { - if (showWindow) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - MainWindow.Show(); - MainWindow.Activate(); - - //required to gracefully quit avalonia and the skia processes - //https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes - if (Lifetime == null) - { - Lifetime = new CancellationTokenSource(); - Task.Run(() => AvaloniaApp.Run(Lifetime.Token)); - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var parentHwnd = Application.MainWindow.Handle; - var hwnd = MainWindow.PlatformImpl.Handle.Handle; - SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); - } + var parentHwnd = Application.MainWindow.Handle; + var hwnd = MainWindow.PlatformImpl.Handle.Handle; + SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); } } - catch { } } + catch { } + } - private static void AppMain(Avalonia.Application app, string[] args) - { - AvaloniaApp = app; - } + private static void AppMain(Avalonia.Application app, string[] args) + { + AvaloniaApp = app; + } - [CommandMethod("SpeckleCommunity", CommandFlags.ActionMacro)] - public static void SpeckleCommunity() + [CommandMethod("SpeckleCommunity", CommandFlags.ActionMacro)] + public static void SpeckleCommunity() + { + try { - try - { - Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_browser https://speckle.community ", false, false, true); - } - catch { } + Application.DocumentManager.MdiActiveDocument.SendStringToExecute( + "_browser https://speckle.community ", + false, + false, + true + ); } + catch { } + } - [CommandMethod("SpeckleTutorials", CommandFlags.ActionMacro)] - public static void SpeckleTutorials() + [CommandMethod("SpeckleTutorials", CommandFlags.ActionMacro)] + public static void SpeckleTutorials() + { + try { - try - { - Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_browser https://speckle.systems/tutorials ", false, false, true); - } - catch { } + Application.DocumentManager.MdiActiveDocument.SendStringToExecute( + "_browser https://speckle.systems/tutorials ", + false, + false, + true + ); } + catch { } + } - [CommandMethod("SpeckleDocs", CommandFlags.ActionMacro)] - public static void SpeckleDocs() + [CommandMethod("SpeckleDocs", CommandFlags.ActionMacro)] + public static void SpeckleDocs() + { + try { - try - { - Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_browser https://speckle.guide/user/autocadcivil.html ", false, false, true); - } - catch { } + Application.DocumentManager.MdiActiveDocument.SendStringToExecute( + "_browser https://speckle.guide/user/autocadcivil.html ", + false, + false, + true + ); } + catch { } } +} - /* - [CommandMethod("SpeckleSchema", CommandFlags.UsePickSet | CommandFlags.Transparent)] - public static void SetSchema() +/* +[CommandMethod("SpeckleSchema", CommandFlags.UsePickSet | CommandFlags.Transparent)] +public static void SetSchema() +{ + var ids = new List(); + PromptSelectionResult selection = Doc.Editor.GetSelection(); + if (selection.Status == PromptStatus.OK) + ids = selection.Value.GetObjectIds().ToList(); + foreach (var id in ids) { - var ids = new List(); - PromptSelectionResult selection = Doc.Editor.GetSelection(); - if (selection.Status == PromptStatus.OK) - ids = selection.Value.GetObjectIds().ToList(); - foreach (var id in ids) + // decide schema here, assumption or user input. + string schema = ""; + switch (id.ObjectClass.DxfName) { - // decide schema here, assumption or user input. - string schema = ""; - switch (id.ObjectClass.DxfName) - { - case "LINE": - schema = "Column"; - break; - } + case "LINE": + schema = "Column"; + break; + } - // add schema to object XData - using (Transaction tr = Doc.TransactionManager.StartTransaction()) - { - DBObject obj = tr.GetObject(id, OpenMode.ForWrite); - if (obj.XData == null) - obj.XData = new ResultBuffer(new TypedValue(Convert.ToInt32(DxfCode.Text), schema)); - else - obj.XData.Add(new TypedValue(Convert.ToInt32(DxfCode.Text), schema)); - } + // add schema to object XData + using (Transaction tr = Doc.TransactionManager.StartTransaction()) + { + DBObject obj = tr.GetObject(id, OpenMode.ForWrite); + if (obj.XData == null) + obj.XData = new ResultBuffer(new TypedValue(Convert.ToInt32(DxfCode.Text), schema)); + else + obj.XData.Add(new TypedValue(Convert.ToInt32(DxfCode.Text), schema)); } } - */ } - +*/ diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/Storage/SpeckleStreamManager.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/Storage/SpeckleStreamManager.cs index 756f486b65..c46e1bc48e 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/Storage/SpeckleStreamManager.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/Storage/SpeckleStreamManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,151 +9,158 @@ using Speckle.ConnectorAutocadCivil.DocumentUtils; using Speckle.Newtonsoft.Json; -namespace Speckle.ConnectorAutocadCivil.Storage +namespace Speckle.ConnectorAutocadCivil.Storage; + +/// +/// Manages the serialisation of speckle stream state +/// +/// +/// Uses a child dictionary for custom data in the Named Object Dictionary (NOD) which is the root level dictionary. +/// This is because NOD persists after a document is closed (unlike file User Data). +/// Custom data is stored as XRecord key value entries of type (string, ResultBuffer). +/// ResultBuffers are TypedValue arrays, with the DxfCode of the input type as an integer. +/// Used for DesktopUI2 +/// +public static class SpeckleStreamManager { + readonly static string SpeckleExtensionDictionary = "Speckle"; + readonly static string SpeckleStreamStates = "StreamStates"; + /// - /// Manages the serialisation of speckle stream state + /// Returns all the speckle stream states present in the current document. /// - /// - /// Uses a child dictionary for custom data in the Named Object Dictionary (NOD) which is the root level dictionary. - /// This is because NOD persists after a document is closed (unlike file User Data). - /// Custom data is stored as XRecord key value entries of type (string, ResultBuffer). - /// ResultBuffers are TypedValue arrays, with the DxfCode of the input type as an integer. - /// Used for DesktopUI2 - /// - public static class SpeckleStreamManager + /// + /// + public static List ReadState(Document doc) { - readonly static string SpeckleExtensionDictionary = "Speckle"; - readonly static string SpeckleStreamStates = "StreamStates"; - - /// - /// Returns all the speckle stream states present in the current document. - /// - /// - /// - public static List ReadState(Document doc) + var streams = new List(); + + if (doc == null) { - var streams = new List(); + return streams; + } - if (doc == null) + using (TransactionContext.StartTransaction(doc)) + { + Transaction tr = doc.Database.TransactionManager.TopTransaction; + var NOD = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead); + if (!NOD.Contains(SpeckleExtensionDictionary)) + { return streams; + } - using (TransactionContext.StartTransaction(doc)) + var speckleDict = tr.GetObject(NOD.GetAt(SpeckleExtensionDictionary), OpenMode.ForRead) as DBDictionary; + if (speckleDict == null || speckleDict.Count == 0) { - Transaction tr = doc.Database.TransactionManager.TopTransaction; - var NOD = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead); - if (!NOD.Contains(SpeckleExtensionDictionary)) - return streams; - - var speckleDict = tr.GetObject(NOD.GetAt(SpeckleExtensionDictionary), OpenMode.ForRead) as DBDictionary; - if (speckleDict == null || speckleDict.Count == 0) - return streams; - - var id = speckleDict.GetAt(SpeckleStreamStates); - if (id == ObjectId.Null) - return streams; - - var record = tr.GetObject(id, OpenMode.ForRead) as Xrecord; - var value = GetXrecordData(record); - - try - { - //Try to decode here because there is old data - value = Base64Decode(value); - } - catch (Exception e) - { } - - streams = JsonConvert.DeserializeObject>(value); - return streams; } - } - /// - /// Writes the stream states to the current document. - /// - /// - /// - public static void WriteStreamStateList(Document doc, List streamStates) - { - if (doc == null) - return; - - using (TransactionContext.StartTransaction(doc)) + var id = speckleDict.GetAt(SpeckleStreamStates); + if (id == ObjectId.Null) { - Transaction tr = doc.Database.TransactionManager.TopTransaction; - var NOD = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead); - DBDictionary speckleDict; - if (NOD.Contains(SpeckleExtensionDictionary)) - { - speckleDict = (DBDictionary)tr.GetObject(NOD.GetAt(SpeckleExtensionDictionary), OpenMode.ForWrite); - } - else - { - speckleDict = new DBDictionary(); - NOD.UpgradeOpen(); - NOD.SetAt(SpeckleExtensionDictionary, speckleDict); - tr.AddNewlyCreatedDBObject(speckleDict, true); - } - var xRec = new Xrecord(); - var value = JsonConvert.SerializeObject(streamStates) as string; - xRec.Data = CreateResultBuffer(value); - speckleDict.SetAt(SpeckleStreamStates, xRec); - tr.AddNewlyCreatedDBObject(xRec, true); + return streams; } - } - - private static ResultBuffer CreateResultBuffer(string value) - { - int size = 1024; - var valueEncoded = Base64Encode(value); - var valueEncodedList = SplitString(valueEncoded, size); - ResultBuffer rb = new ResultBuffer(); + var record = tr.GetObject(id, OpenMode.ForRead) as Xrecord; + var value = GetXrecordData(record); - foreach (var valueEncodedSplited in valueEncodedList) + try { - rb.Add(new TypedValue((int)DxfCode.Text, valueEncodedSplited)); + //Try to decode here because there is old data + value = Base64Decode(value); } + catch (Exception e) { } - return rb; + streams = JsonConvert.DeserializeObject>(value); + + return streams; } + } - private static string GetXrecordData(Xrecord pXrecord) + /// + /// Writes the stream states to the current document. + /// + /// + /// + public static void WriteStreamStateList(Document doc, List streamStates) + { + if (doc == null) { - StringBuilder valueEncoded = new StringBuilder(); - foreach (TypedValue typedValue in pXrecord.Data) - { - if (typedValue.TypeCode == (int)DxfCode.Text) - { - valueEncoded.Append(typedValue.Value.ToString()); - } - } - - return valueEncoded.ToString(); + return; } - private static string Base64Encode(string plainText) + using (TransactionContext.StartTransaction(doc)) { - var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); - return System.Convert.ToBase64String(plainTextBytes); + Transaction tr = doc.Database.TransactionManager.TopTransaction; + var NOD = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead); + DBDictionary speckleDict; + if (NOD.Contains(SpeckleExtensionDictionary)) + { + speckleDict = (DBDictionary)tr.GetObject(NOD.GetAt(SpeckleExtensionDictionary), OpenMode.ForWrite); + } + else + { + speckleDict = new DBDictionary(); + NOD.UpgradeOpen(); + NOD.SetAt(SpeckleExtensionDictionary, speckleDict); + tr.AddNewlyCreatedDBObject(speckleDict, true); + } + var xRec = new Xrecord(); + var value = JsonConvert.SerializeObject(streamStates) as string; + xRec.Data = CreateResultBuffer(value); + speckleDict.SetAt(SpeckleStreamStates, xRec); + tr.AddNewlyCreatedDBObject(xRec, true); } + } + + private static ResultBuffer CreateResultBuffer(string value) + { + int size = 1024; + var valueEncoded = Base64Encode(value); + var valueEncodedList = SplitString(valueEncoded, size); - private static string Base64Decode(string base64EncodedData) + ResultBuffer rb = new(); + + foreach (var valueEncodedSplited in valueEncodedList) { - var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); - return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); + rb.Add(new TypedValue((int)DxfCode.Text, valueEncodedSplited)); } - private static IEnumerable SplitString(string text, int chunkSize) + return rb; + } + + private static string GetXrecordData(Xrecord pXrecord) + { + StringBuilder valueEncoded = new(); + foreach (TypedValue typedValue in pXrecord.Data) { - for (int offset = 0; offset < text.Length; offset += chunkSize) + if (typedValue.TypeCode == (int)DxfCode.Text) { - int size = Math.Min(chunkSize, text.Length - offset); - yield return text.Substring(offset, size); + valueEncoded.Append(typedValue.Value.ToString()); } } + return valueEncoded.ToString(); + } + + private static string Base64Encode(string plainText) + { + var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + return System.Convert.ToBase64String(plainTextBytes); + } + + private static string Base64Decode(string base64EncodedData) + { + var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); + return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); + } + + private static IEnumerable SplitString(string text, int chunkSize) + { + for (int offset = 0; offset < text.Length; offset += chunkSize) + { + int size = Math.Min(chunkSize, text.Length - offset); + yield return text.Substring(offset, size); + } } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Events.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Events.cs index 2c149e17d8..c8dcc79864 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Events.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Events.cs @@ -8,66 +8,75 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings + public void RegisterAppEvents() { - public void RegisterAppEvents() - { - //// GLOBAL EVENT HANDLERS - Application.DocumentWindowCollection.DocumentWindowActivated += Application_WindowActivated; - Application.DocumentManager.DocumentActivated += Application_DocumentActivated; + //// GLOBAL EVENT HANDLERS + Application.DocumentWindowCollection.DocumentWindowActivated += Application_WindowActivated; + Application.DocumentManager.DocumentActivated += Application_DocumentActivated; - var layers = Application.UIBindings.Collections.Layers; - layers.CollectionChanged += Application_LayerChanged; - } + var layers = Application.UIBindings.Collections.Layers; + layers.CollectionChanged += Application_LayerChanged; + } - public void Application_LayerChanged(object sender, EventArgs e) + public void Application_LayerChanged(object sender, EventArgs e) + { + if (UpdateSelectedStream != null) { - if (UpdateSelectedStream != null) - UpdateSelectedStream(); + UpdateSelectedStream(); } + } - //checks whether to refresh the stream list in case the user changes active view and selects a different document - private void Application_WindowActivated(object sender, DocumentWindowActivatedEventArgs e) + //checks whether to refresh the stream list in case the user changes active view and selects a different document + private void Application_WindowActivated(object sender, DocumentWindowActivatedEventArgs e) + { + try { - try + if (e.DocumentWindow.Document == null || UpdateSavedStreams == null) { - if (e.DocumentWindow.Document == null || UpdateSavedStreams == null) - return; + return; + } - var streams = GetStreamsInFile(); - UpdateSavedStreams(streams); + var streams = GetStreamsInFile(); + UpdateSavedStreams(streams); - MainViewModel.GoHome(); - } - catch { } + MainViewModel.GoHome(); } + catch { } + } - private void Application_DocumentActivated(object sender, DocumentCollectionEventArgs e) + private void Application_DocumentActivated(object sender, DocumentCollectionEventArgs e) + { + try { - try + // Triggered when a document window is activated. This will happen automatically if a document is newly created or opened. + if (e.Document == null) { - // Triggered when a document window is activated. This will happen automatically if a document is newly created or opened. - if (e.Document == null) + if (SpeckleAutocadCommand.MainWindow != null) { - if (SpeckleAutocadCommand.MainWindow != null) - SpeckleAutocadCommand.MainWindow.Hide(); - - MainViewModel.GoHome(); - return; + SpeckleAutocadCommand.MainWindow.Hide(); } - var streams = GetStreamsInFile(); - if (streams.Count > 0) - SpeckleAutocadCommand.CreateOrFocusSpeckle(); + MainViewModel.GoHome(); + return; + } - if (UpdateSavedStreams != null) - UpdateSavedStreams(streams); + var streams = GetStreamsInFile(); + if (streams.Count > 0) + { + SpeckleAutocadCommand.CreateOrFocusSpeckle(); + } - MainViewModel.GoHome(); + if (UpdateSavedStreams != null) + { + UpdateSavedStreams(streams); } - catch { } + + MainViewModel.GoHome(); } + catch { } } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Previews.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Previews.cs index c7222de601..fd0de31160 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Previews.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Previews.cs @@ -12,86 +12,85 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings - { - public override bool CanPreviewSend => true; + public override bool CanPreviewSend => true; - public override async void PreviewSend(StreamState state, ProgressViewModel progress) + public override async void PreviewSend(StreamState state, ProgressViewModel progress) + { + // report and converter + progress.Report = new ProgressReport(); + var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); + if (converter == null) { - // report and converter - progress.Report = new ProgressReport(); - var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); - if (converter == null) - { - progress.Report.LogOperationError(new Exception("Could not load converter")); - return; - } - converter.SetContextDocument(Doc); + progress.Report.LogOperationError(new Exception("Could not load converter")); + return; + } + converter.SetContextDocument(Doc); - var filterObjs = GetObjectsFromFilter(state.Filter, converter); - var existingIds = new List(); - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + var filterObjs = GetObjectsFromFilter(state.Filter, converter); + var existingIds = new List(); + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + foreach (var id in filterObjs) { - foreach (var id in filterObjs) + DBObject obj = null; + string type = ""; + if (Utils.GetHandle(id, out Handle hn)) + { + obj = hn.GetObject(tr, out type, out string layer, out string applicationId); + } + if (obj == null) { - DBObject obj = null; - string type = ""; - if (Utils.GetHandle(id, out Handle hn)) - { - obj = hn.GetObject(tr, out type, out string layer, out string applicationId); - } - if (obj == null) - { - progress.Report.Log( - new ApplicationObject(id, "unknown") - { - Status = ApplicationObject.State.Failed, - Log = new List() { "Could not find object in document" } - } - ); - continue; - } + progress.Report.Log( + new ApplicationObject(id, "unknown") + { + Status = ApplicationObject.State.Failed, + Log = new List() { "Could not find object in document" } + } + ); + continue; + } - var appObj = new ApplicationObject(id, type) { Status = ApplicationObject.State.Unknown }; + var appObj = new ApplicationObject(id, type) { Status = ApplicationObject.State.Unknown }; - if (converter.CanConvertToSpeckle(obj)) - { - appObj.Update(status: ApplicationObject.State.Created); - } - else - { + if (converter.CanConvertToSpeckle(obj)) + { + appObj.Update(status: ApplicationObject.State.Created); + } + else + { #if ADVANCESTEEL - UpdateASObject(appObj, obj); + UpdateASObject(appObj, obj); #endif - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: "Object type conversion to Speckle not supported" - ); - } - - progress.Report.Log(appObj); - existingIds.Add(id); + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "Object type conversion to Speckle not supported" + ); } - tr.Commit(); - } - if (existingIds.Count == 0) - { - progress.Report.LogOperationError(new Exception("No valid objects selected, nothing will be sent!")); - return; + progress.Report.Log(appObj); + existingIds.Add(id); } - - Doc.Editor.SetImpliedSelection(new ObjectId[0]); - SelectClientObjects(existingIds); + tr.Commit(); } - public override bool CanPreviewReceive => false; - - public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + if (existingIds.Count == 0) { - return null; + progress.Report.LogOperationError(new Exception("No valid objects selected, nothing will be sent!")); + return; } + + Doc.Editor.SetImpliedSelection(new ObjectId[0]); + SelectClientObjects(existingIds); + } + + public override bool CanPreviewReceive => false; + + public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + { + return null; } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Receive.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Receive.cs index 0c16fb83a8..78ff8af3fb 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Receive.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Receive.cs @@ -21,577 +21,655 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) { - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + if (Doc == null) { - if (Doc == null) - throw new InvalidOperationException("No Document is open"); + throw new InvalidOperationException("No Document is open"); + } - var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); + var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); - var stream = await state.Client.StreamGet(state.StreamId); + var stream = await state.Client.StreamGet(state.StreamId); - Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - state.LastCommit = commit; + Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + state.LastCommit = commit; - Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); - await ConnectorHelpers.TryCommitReceived(state, commit, Utils.VersionedAppName, progress.CancellationToken); + Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); + await ConnectorHelpers.TryCommitReceived(state, commit, Utils.VersionedAppName, progress.CancellationToken); - // invoke conversions on the main thread via control - try + // invoke conversions on the main thread via control + try + { + if (Control.InvokeRequired) { - if (Control.InvokeRequired) - Control.Invoke( - new ReceivingDelegate(ConvertReceiveCommit), - commitObject, - converter, - state, - progress, - stream, - commit.id - ); - else - ConvertReceiveCommit(commitObject, converter, state, progress, stream, commit.id); + Control.Invoke( + new ReceivingDelegate(ConvertReceiveCommit), + commitObject, + converter, + state, + progress, + stream, + commit.id + ); } - catch (Exception ex) + else { - throw new Exception($"Could not convert commit: {ex.Message}", ex); + ConvertReceiveCommit(commitObject, converter, state, progress, stream, commit.id); } - - return state; } + catch (Exception ex) + { + throw new Exception($"Could not convert commit: {ex.Message}", ex); + } + + return state; + } - delegate void ReceivingDelegate( - Base commitObject, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress, - Stream stream, - string id - ); - - private void ConvertReceiveCommit( - Base commitObject, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress, - Stream stream, - string id - ) + delegate void ReceivingDelegate( + Base commitObject, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress, + Stream stream, + string id + ); + + private void ConvertReceiveCommit( + Base commitObject, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress, + Stream stream, + string id + ) + { + using (DocumentLock l = Doc.LockDocument()) { - using (DocumentLock l = Doc.LockDocument()) + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // set the context doc for conversion - this is set inside the transaction loop because the converter retrieves this transaction for all db editing when the context doc is set! + converter.SetContextDocument(Doc); + converter.ReceiveMode = state.ReceiveMode; + + // set converter settings as tuples (setting slug, setting selection) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - // set the context doc for conversion - this is set inside the transaction loop because the converter retrieves this transaction for all db editing when the context doc is set! - converter.SetContextDocument(Doc); - converter.ReceiveMode = state.ReceiveMode; - - // set converter settings as tuples (setting slug, setting selection) - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); - - // keep track of conversion progress here - progress.Report = new ProgressReport(); - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 0; - - // create a commit prefix: used for layers and block definition names - var commitPrefix = Formatting.CommitInfo(stream.name, state.BranchName, id); - - // give converter a way to access the commit info - if (Doc.UserData.ContainsKey("commit")) - Doc.UserData["commit"] = commitPrefix; - else - Doc.UserData.Add("commit", commitPrefix); + settings.Add(setting.Slug, setting.Selection); + } - // delete existing commit layers - try - { - DeleteBlocksWithPrefix(commitPrefix, tr); - } - catch - { - converter.Report.LogOperationError( - new Exception( - $"Failed to remove existing layers or blocks starting with {commitPrefix} before importing new geometry." - ) - ); - } + converter.SetConverterSettings(settings); - // clear previously stored objects - StoredObjects.Clear(); + // keep track of conversion progress here + progress.Report = new ProgressReport(); + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 0; - // flatten the commit object to retrieve children objs - var commitObjs = FlattenCommitObject(commitObject, converter); + // create a commit prefix: used for layers and block definition names + var commitPrefix = Formatting.CommitInfo(stream.name, state.BranchName, id); - // open model space block table record for write - BlockTableRecord btr = (BlockTableRecord)tr.GetObject(Doc.Database.CurrentSpaceId, OpenMode.ForWrite); + // give converter a way to access the commit info + if (Doc.UserData.ContainsKey("commit")) + { + Doc.UserData["commit"] = commitPrefix; + } + else + { + Doc.UserData.Add("commit", commitPrefix); + } - // Get doc line types for bake: more efficient this way than doing this per object - LineTypeDictionary.Clear(); - var lineTypeTable = (LinetypeTable)tr.GetObject(Doc.Database.LinetypeTableId, OpenMode.ForRead); - foreach (ObjectId lineTypeId in lineTypeTable) - { - var linetype = (LinetypeTableRecord)tr.GetObject(lineTypeId, OpenMode.ForRead); - LineTypeDictionary.Add(linetype.Name, lineTypeId); - } + // delete existing commit layers + try + { + DeleteBlocksWithPrefix(commitPrefix, tr); + } + catch + { + converter.Report.LogOperationError( + new Exception( + $"Failed to remove existing layers or blocks starting with {commitPrefix} before importing new geometry." + ) + ); + } + + // clear previously stored objects + StoredObjects.Clear(); + + // flatten the commit object to retrieve children objs + var commitObjs = FlattenCommitObject(commitObject, converter); + + // open model space block table record for write + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(Doc.Database.CurrentSpaceId, OpenMode.ForWrite); + + // Get doc line types for bake: more efficient this way than doing this per object + LineTypeDictionary.Clear(); + var lineTypeTable = (LinetypeTable)tr.GetObject(Doc.Database.LinetypeTableId, OpenMode.ForRead); + foreach (ObjectId lineTypeId in lineTypeTable) + { + var linetype = (LinetypeTableRecord)tr.GetObject(lineTypeId, OpenMode.ForRead); + LineTypeDictionary.Add(linetype.Name, lineTypeId); + } - #region layer creation + #region layer creation - Application.UIBindings.Collections.Layers.CollectionChanged -= Application_LayerChanged; // temporarily unsubscribe from layer handler since layer creation will trigger it. + Application.UIBindings.Collections.Layers.CollectionChanged -= Application_LayerChanged; // temporarily unsubscribe from layer handler since layer creation will trigger it. - // sort by depth and create all the containers as layers first - var layers = new Dictionary(); - var containers = commitObjs.Select(o => o.Container).Distinct().ToList(); + // sort by depth and create all the containers as layers first + var layers = new Dictionary(); + var containers = commitObjs.Select(o => o.Container).Distinct().ToList(); - // create the layers - var layerTable = (LayerTable)tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead); // get the layer table - foreach (var container in containers) + // create the layers + var layerTable = (LayerTable)tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead); // get the layer table + foreach (var container in containers) + { + var path = state.ReceiveMode == ReceiveMode.Create ? $"{commitPrefix}${container}" : container; + string layer = null; + + // try to see if there's a collection object first + var collection = commitObjs + .Where(o => o.Container == container && o.Descriptor.Contains("Collection")) + .FirstOrDefault(); + if (collection != null) { - var path = state.ReceiveMode == ReceiveMode.Create ? $"{commitPrefix}${container}" : container; - string layer = null; - - // try to see if there's a collection object first - var collection = commitObjs - .Where(o => o.Container == container && o.Descriptor.Contains("Collection")) - .FirstOrDefault(); - if (collection != null) + var storedCollection = StoredObjects[collection.OriginalId]; + storedCollection["path"] = path; // needed by converter + converter.Report.Log(collection); // Log object so converter can access + var convertedCollection = converter.ConvertToNative(storedCollection) as List; + if (convertedCollection != null && convertedCollection.Count > 0) { - var storedCollection = StoredObjects[collection.OriginalId]; - storedCollection["path"] = path; // needed by converter - converter.Report.Log(collection); // Log object so converter can access - var convertedCollection = converter.ConvertToNative(storedCollection) as List; - if (convertedCollection != null && convertedCollection.Count > 0) - { - layer = (convertedCollection.First() as LayerTableRecord)?.Name; - commitObjs[commitObjs.IndexOf(collection)] = converter.Report.ReportObjects[collection.OriginalId]; - } - } - // otherwise create the layer here (old commits before collections implementations, or from apps not supporting collections) - else - { - if (GetOrMakeLayer(path, tr, out string cleanName)) - { - layer = cleanName; - } + layer = (convertedCollection.First() as LayerTableRecord)?.Name; + commitObjs[commitObjs.IndexOf(collection)] = converter.Report.ReportObjects[collection.OriginalId]; } - - if (layer == null) + } + // otherwise create the layer here (old commits before collections implementations, or from apps not supporting collections) + else + { + if (GetOrMakeLayer(path, tr, out string cleanName)) { - progress.Report.ConversionErrors.Add( - new Exception($"Could not create layer [{path}]. Objects will be placed on default layer.") - ); - continue; + layer = cleanName; } + } - layers.Add(path, layer); + if (layer == null) + { + progress.Report.ConversionErrors.Add( + new Exception($"Could not create layer [{path}]. Objects will be placed on default layer.") + ); + continue; } - #endregion + + layers.Add(path, layer); + } + #endregion - // conversion - foreach (var commitObj in commitObjs) + // conversion + foreach (var commitObj in commitObjs) + { + // handle user cancellation + if (progress.CancellationToken.IsCancellationRequested) { - // handle user cancellation - if (progress.CancellationToken.IsCancellationRequested) - return; + return; + } - // convert base (or base fallback values) and store in appobj converted prop - if (commitObj.Convertible) + // convert base (or base fallback values) and store in appobj converted prop + if (commitObj.Convertible) + { + converter.Report.Log(commitObj); // Log object so converter can access + try + { + commitObj.Converted = ConvertObject(commitObj, converter); + } + catch (Exception e) + { + commitObj.Log.Add($"Failed conversion: {e.Message}"); + } + } + else + { + foreach (var fallback in commitObj.Fallback) { - converter.Report.Log(commitObj); // Log object so converter can access try { - commitObj.Converted = ConvertObject(commitObj, converter); + fallback.Converted = ConvertObject(fallback, converter); } catch (Exception e) { - commitObj.Log.Add($"Failed conversion: {e.Message}"); + commitObj.Log.Add($"Fallback {fallback.applicationId} failed conversion: {e.Message}"); } + commitObj.Log.AddRange(fallback.Log); } - else - foreach (var fallback in commitObj.Fallback) - { - try - { - fallback.Converted = ConvertObject(fallback, converter); - } - catch (Exception e) - { - commitObj.Log.Add($"Fallback {fallback.applicationId} failed conversion: {e.Message}"); - } - commitObj.Log.AddRange(fallback.Log); - } + } - // if the object wasnt converted, log fallback status - if (commitObj.Converted == null || commitObj.Converted.Count == 0) + // if the object wasnt converted, log fallback status + if (commitObj.Converted == null || commitObj.Converted.Count == 0) + { + var convertedFallback = commitObj.Fallback.Where(o => o.Converted != null || o.Converted.Count > 0); + if (convertedFallback != null && convertedFallback.Count() > 0) { - var convertedFallback = commitObj.Fallback.Where(o => o.Converted != null || o.Converted.Count > 0); - if (convertedFallback != null && convertedFallback.Count() > 0) - commitObj.Update(logItem: $"Creating with {convertedFallback.Count()} fallback values"); - else - commitObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Couldn't convert object or any fallback values" - ); + commitObj.Update(logItem: $"Creating with {convertedFallback.Count()} fallback values"); + } + else + { + commitObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Couldn't convert object or any fallback values" + ); } - - // add to progress report - progress.Report.Log(commitObj); } - progress.Report.Merge(converter.Report); - // add applicationID xdata before bake - if (!ApplicationIdManager.AddApplicationIdXDataToDoc(Doc, tr)) + // add to progress report + progress.Report.Log(commitObj); + } + progress.Report.Merge(converter.Report); + + // add applicationID xdata before bake + if (!ApplicationIdManager.AddApplicationIdXDataToDoc(Doc, tr)) + { + progress.Report.LogOperationError(new Exception("Could not create document application id reg table")); + return; + } + + // handle operation errors + if (progress.Report.OperationErrorsCount != 0) + { + return; + } + + // bake + var fileNameHash = GetDocumentId(); + foreach (var commitObj in commitObjs) + { + // handle user cancellation + if (progress.CancellationToken.IsCancellationRequested) { - progress.Report.LogOperationError(new Exception("Could not create document application id reg table")); return; } - // handle operation errors - if (progress.Report.OperationErrorsCount != 0) - return; + // find existing doc objects if they exist + var existingObjs = new List(); + var layer = layers.ContainsKey(commitObj.Container) ? layers[commitObj.Container] : "0"; + if (state.ReceiveMode == ReceiveMode.Update) // existing objs will be removed if it exists in the received commit + { + existingObjs = ApplicationIdManager.GetObjectsByApplicationId( + Doc, + tr, + commitObj.applicationId, + fileNameHash + ); + } // bake - var fileNameHash = GetDocumentId(); - foreach (var commitObj in commitObjs) + if (commitObj.Convertible) { - // handle user cancellation - if (progress.CancellationToken.IsCancellationRequested) - return; - - // find existing doc objects if they exist - var existingObjs = new List(); - var layer = layers.ContainsKey(commitObj.Container) ? layers[commitObj.Container] : "0"; - if (state.ReceiveMode == ReceiveMode.Update) // existing objs will be removed if it exists in the received commit + BakeObject(commitObj, converter, tr, layer, existingObjs); + commitObj.Status = !commitObj.CreatedIds.Any() + ? ApplicationObject.State.Failed + : existingObjs.Count > 0 + ? ApplicationObject.State.Updated + : ApplicationObject.State.Created; + } + else + { + foreach (var fallback in commitObj.Fallback) { - existingObjs = ApplicationIdManager.GetObjectsByApplicationId( - Doc, - tr, - commitObj.applicationId, - fileNameHash - ); + BakeObject(fallback, converter, tr, layer, existingObjs, commitObj); } - // bake - if (commitObj.Convertible) - { - BakeObject(commitObj, converter, tr, layer, existingObjs); - commitObj.Status = !commitObj.CreatedIds.Any() + commitObj.Status = + commitObj.Fallback.Where(o => o.Status == ApplicationObject.State.Failed).Count() + == commitObj.Fallback.Count ? ApplicationObject.State.Failed : existingObjs.Count > 0 ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - } - else - { - foreach (var fallback in commitObj.Fallback) - BakeObject(fallback, converter, tr, layer, existingObjs, commitObj); - commitObj.Status = - commitObj.Fallback.Where(o => o.Status == ApplicationObject.State.Failed).Count() - == commitObj.Fallback.Count - ? ApplicationObject.State.Failed - : existingObjs.Count > 0 - ? ApplicationObject.State.Updated - : ApplicationObject.State.Created; - } - Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); - - // log to progress report and update progress - progress.Report.Log(commitObj); - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); } + Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); - // remove commit info from doc userdata - Doc.UserData.Remove("commit"); - - tr.Commit(); + // log to progress report and update progress + progress.Report.Log(commitObj); + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); } + + // remove commit info from doc userdata + Doc.UserData.Remove("commit"); + + tr.Commit(); } } + } - private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + { + //TODO: this implementation is almost identical to Rhino, we should try and extract as much of it as we can into Core + void StoreObject(Base @base, ApplicationObject appObj) { - //TODO: this implementation is almost identical to Rhino, we should try and extract as much of it as we can into Core - void StoreObject(Base @base, ApplicationObject appObj) + if (StoredObjects.ContainsKey(@base.id)) { - if (StoredObjects.ContainsKey(@base.id)) - appObj.Update(logItem: "Found another object in this commit with the same id. Skipped other object"); //TODO check if we are actually ignoring duplicates, since we are returning the app object anyway... - else - StoredObjects.Add(@base.id, @base); + appObj.Update(logItem: "Found another object in this commit with the same id. Skipped other object"); //TODO check if we are actually ignoring duplicates, since we are returning the app object anyway... } - - ApplicationObject CreateApplicationObject(Base current, string containerId) + else { - ApplicationObject NewAppObj() - { - var speckleType = current.speckle_type - .Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries) - .LastOrDefault(); - return new ApplicationObject(current.id, speckleType) - { - applicationId = current.applicationId, - Container = containerId - }; - } - - // skip if it is the base commit collection - if (current is Collection && string.IsNullOrEmpty(containerId)) - return null; - - //Handle convertable objects - if (converter.CanConvertToNative(current)) - { - var appObj = NewAppObj(); - appObj.Convertible = true; - StoreObject(current, appObj); - return appObj; - } + StoredObjects.Add(@base.id, @base); + } + } - //Handle objects convertable using displayValues - var fallbackMember = current["displayValue"] ?? current["@displayValue"]; - if (fallbackMember != null) + ApplicationObject CreateApplicationObject(Base current, string containerId) + { + ApplicationObject NewAppObj() + { + var speckleType = current.speckle_type + .Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries) + .LastOrDefault(); + return new ApplicationObject(current.id, speckleType) { - var appObj = NewAppObj(); - var fallbackObjects = GraphTraversal - .TraverseMember(fallbackMember) - .Select(o => CreateApplicationObject(o, containerId)); - appObj.Fallback.AddRange(fallbackObjects); - - StoreObject(current, appObj); - return appObj; - } + applicationId = current.applicationId, + Container = containerId + }; + } + // skip if it is the base commit collection + if (current is Collection && string.IsNullOrEmpty(containerId)) + { return null; } - string LayerId(TraversalContext context) => LayerIdRecurse(context, new StringBuilder()).ToString(); - StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) + //Handle convertable objects + if (converter.CanConvertToNative(current)) { - if (context.propName == null) - return stringBuilder; - - string objectLayerName = string.Empty; - if (context.propName.ToLower() == "elements" && context.current is Collection coll) - objectLayerName = coll.name; - else if (context.propName.ToLower() != "elements") // this is for any other property on the collection. skip elements props in layer structure. - objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; - LayerIdRecurse(context.parent, stringBuilder); - if (stringBuilder.Length != 0 && !string.IsNullOrEmpty(objectLayerName)) - stringBuilder.Append('$'); - stringBuilder.Append(objectLayerName); - - return stringBuilder; + var appObj = NewAppObj(); + appObj.Convertible = true; + StoreObject(current, appObj); + return appObj; } - var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); - - var objectsToConvert = traverseFunction - .Traverse(obj) - .Select(tc => CreateApplicationObject(tc.current, LayerId(tc))) - .Where(appObject => appObject != null) - .Reverse() //just for the sake of matching the previous behaviour as close as possible - .ToList(); + //Handle objects convertable using displayValues + var fallbackMember = current["displayValue"] ?? current["@displayValue"]; + if (fallbackMember != null) + { + var appObj = NewAppObj(); + var fallbackObjects = GraphTraversal + .TraverseMember(fallbackMember) + .Select(o => CreateApplicationObject(o, containerId)); + appObj.Fallback.AddRange(fallbackObjects); + + StoreObject(current, appObj); + return appObj; + } - return objectsToConvert; + return null; } - private List ConvertObject(ApplicationObject appObj, ISpeckleConverter converter) + string LayerId(TraversalContext context) => LayerIdRecurse(context, new StringBuilder()).ToString(); + StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) { - var obj = StoredObjects[appObj.OriginalId]; - var convertedList = new List(); + if (context.propName == null) + { + return stringBuilder; + } - var converted = converter.ConvertToNative(obj); - if (converted == null) - return convertedList; + string objectLayerName = string.Empty; + if (context.propName.ToLower() == "elements" && context.current is Collection coll) + { + objectLayerName = coll.name; + } + else if (context.propName.ToLower() != "elements") // this is for any other property on the collection. skip elements props in layer structure. + { + objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; + } - //Iteratively flatten any lists - void FlattenConvertedObject(object item) + LayerIdRecurse(context.parent, stringBuilder); + if (stringBuilder.Length != 0 && !string.IsNullOrEmpty(objectLayerName)) { - if (item is IList list) - foreach (object child in list) - FlattenConvertedObject(child); - else - convertedList.Add(item); + stringBuilder.Append('$'); } - FlattenConvertedObject(converted); + stringBuilder.Append(objectLayerName); + + return stringBuilder; + } + + var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); + + var objectsToConvert = traverseFunction + .Traverse(obj) + .Select(tc => CreateApplicationObject(tc.current, LayerId(tc))) + .Where(appObject => appObject != null) + .Reverse() //just for the sake of matching the previous behaviour as close as possible + .ToList(); + + return objectsToConvert; + } + + private List ConvertObject(ApplicationObject appObj, ISpeckleConverter converter) + { + var obj = StoredObjects[appObj.OriginalId]; + var convertedList = new List(); + + var converted = converter.ConvertToNative(obj); + if (converted == null) + { return convertedList; } - private void BakeObject( - ApplicationObject appObj, - ISpeckleConverter converter, - Transaction tr, - string layer, - List toRemove, - ApplicationObject parent = null - ) + //Iteratively flatten any lists + void FlattenConvertedObject(object item) { - var obj = StoredObjects[appObj.OriginalId]; - int bakedCount = 0; - bool remove = - appObj.Status == ApplicationObject.State.Created - || appObj.Status == ApplicationObject.State.Updated - || appObj.Status == ApplicationObject.State.Failed - ? false - : true; - - foreach (var convertedItem in appObj.Converted) + if (item is IList list) { - switch (convertedItem) + foreach (object child in list) { - case Entity o: + FlattenConvertedObject(child); + } + } + else + { + convertedList.Add(item); + } + } + FlattenConvertedObject(converted); - if (o == null) - continue; + return convertedList; + } - var res = o.Append(layer); - if (res.IsValid) + private void BakeObject( + ApplicationObject appObj, + ISpeckleConverter converter, + Transaction tr, + string layer, + List toRemove, + ApplicationObject parent = null + ) + { + var obj = StoredObjects[appObj.OriginalId]; + int bakedCount = 0; + bool remove = + appObj.Status == ApplicationObject.State.Created + || appObj.Status == ApplicationObject.State.Updated + || appObj.Status == ApplicationObject.State.Failed + ? false + : true; + + foreach (var convertedItem in appObj.Converted) + { + switch (convertedItem) + { + case Entity o: + + if (o == null) + { + continue; + } + + var res = o.Append(layer); + if (res.IsValid) + { + // handle display - fallback to rendermaterial if no displaystyle exists + Base display = obj[@"displayStyle"] as Base; + if (display == null) { - // handle display - fallback to rendermaterial if no displaystyle exists - Base display = obj[@"displayStyle"] as Base; - if (display == null) - display = obj[@"renderMaterial"] as Base; - if (display != null) - Utils.SetStyle(display, o, LineTypeDictionary); - - // add property sets if this is Civil3D + display = obj[@"renderMaterial"] as Base; + } + + if (display != null) + { + Utils.SetStyle(display, o, LineTypeDictionary); + } + + // add property sets if this is Civil3D #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - try + try + { + if (obj["propertySets"] is IReadOnlyList list) { - if (obj["propertySets"] is IReadOnlyList list) + var propertySets = new List>(); + foreach (var listObj in list) { - var propertySets = new List>(); - foreach (var listObj in list) - propertySets.Add(listObj as Dictionary); - o.SetPropertySets(Doc, propertySets); + propertySets.Add(listObj as Dictionary); } - } - catch (Exception e) - { - appObj.Log.Add($"Could not attach property sets: {e.Message}"); - } -#endif - // set application id - var appId = parent != null ? parent.applicationId : obj.applicationId; - var newObj = tr.GetObject(res, OpenMode.ForWrite); - if (!ApplicationIdManager.SetObjectCustomApplicationId(newObj, appId, out appId)) + o.SetPropertySets(Doc, propertySets); + } + } + catch (Exception e) { - appObj.Log.Add($"Could not attach applicationId xdata"); + appObj.Log.Add($"Could not attach property sets: {e.Message}"); } +#endif - tr.TransactionManager.QueueForGraphicsFlush(); + // set application id + var appId = parent != null ? parent.applicationId : obj.applicationId; + var newObj = tr.GetObject(res, OpenMode.ForWrite); + if (!ApplicationIdManager.SetObjectCustomApplicationId(newObj, appId, out appId)) + { + appObj.Log.Add($"Could not attach applicationId xdata"); + } - if (parent != null) - parent.Update(createdId: res.Handle.ToString()); - else - appObj.Update(createdId: res.Handle.ToString()); + tr.TransactionManager.QueueForGraphicsFlush(); - bakedCount++; + if (parent != null) + { + parent.Update(createdId: res.Handle.ToString()); } else { - var bakeMessage = $"Could not bake to document."; - if (parent != null) - parent.Update(logItem: $"fallback {appObj.applicationId}: {bakeMessage}"); - else - appObj.Update(logItem: bakeMessage); - continue; + appObj.Update(createdId: res.Handle.ToString()); } - break; - default: - break; - } + + bakedCount++; + } + else + { + var bakeMessage = $"Could not bake to document."; + if (parent != null) + { + parent.Update(logItem: $"fallback {appObj.applicationId}: {bakeMessage}"); + } + else + { + appObj.Update(logItem: bakeMessage); + } + + continue; + } + break; + default: + break; } + } - if (bakedCount == 0) + if (bakedCount == 0) + { + if (parent != null) { - if (parent != null) - parent.Update(logItem: $"fallback {appObj.applicationId}: could not bake object"); - else - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not bake object"); + parent.Update(logItem: $"fallback {appObj.applicationId}: could not bake object"); } else { - // remove existing objects if they exist - if (remove) + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not bake object"); + } + } + else + { + // remove existing objects if they exist + if (remove) + { + foreach (var objId in toRemove) { - foreach (var objId in toRemove) + try { - try - { - DBObject objToRemove = tr.GetObject(objId, OpenMode.ForWrite); - objToRemove.Erase(); - } - catch (Exception e) + DBObject objToRemove = tr.GetObject(objId, OpenMode.ForWrite); + objToRemove.Erase(); + } + catch (Exception e) + { + if (!e.Message.Contains("eWasErased")) // this couldve been previously received and deleted { - if (!e.Message.Contains("eWasErased")) // this couldve been previously received and deleted + if (parent != null) { - if (parent != null) - parent.Log.Add(e.Message); - else - appObj.Log.Add(e.Message); + parent.Log.Add(e.Message); + } + else + { + appObj.Log.Add(e.Message); } } } - appObj.Status = toRemove.Count > 0 ? ApplicationObject.State.Updated : ApplicationObject.State.Created; } + appObj.Status = toRemove.Count > 0 ? ApplicationObject.State.Updated : ApplicationObject.State.Created; } } + } - private void DeleteBlocksWithPrefix(string prefix, Transaction tr) + private void DeleteBlocksWithPrefix(string prefix, Transaction tr) + { + BlockTable blockTable = tr.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; + foreach (ObjectId blockId in blockTable) { - BlockTable blockTable = tr.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; - foreach (ObjectId blockId in blockTable) + BlockTableRecord block = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead); + if (block.Name.StartsWith(prefix)) { - BlockTableRecord block = (BlockTableRecord)tr.GetObject(blockId, OpenMode.ForRead); - if (block.Name.StartsWith(prefix)) - { - block.UpgradeOpen(); - block.Erase(); - } + block.UpgradeOpen(); + block.Erase(); } } + } - private bool GetOrMakeLayer(string layerName, Transaction tr, out string cleanName) + private bool GetOrMakeLayer(string layerName, Transaction tr, out string cleanName) + { + cleanName = Utils.RemoveInvalidChars(layerName); + try { - cleanName = Utils.RemoveInvalidChars(layerName); - try + LayerTable layerTable = tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable; + if (layerTable.Has(cleanName)) { - LayerTable layerTable = tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable; - if (layerTable.Has(cleanName)) - { - return true; - } - else - { - layerTable.UpgradeOpen(); - var _layer = new LayerTableRecord(); - - // Assign the layer properties - _layer.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByColor, 7); // white - _layer.Name = cleanName; - - // Append the new layer to the layer table and the transaction - layerTable.Add(_layer); - tr.AddNewlyCreatedDBObject(_layer, true); - } + return true; } - catch + else { - return false; + layerTable.UpgradeOpen(); + var _layer = new LayerTableRecord(); + + // Assign the layer properties + _layer.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(ColorMethod.ByColor, 7); // white + _layer.Name = cleanName; + + // Append the new layer to the layer table and the transaction + layerTable.Add(_layer); + tr.AddNewlyCreatedDBObject(_layer, true); } - return true; } + catch + { + return false; + } + return true; } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Selection.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Selection.cs index d28057ef05..b06e876eaa 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Selection.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Selection.cs @@ -11,114 +11,130 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings + public override List GetObjectsInView() // this returns all visible doc objects. { - public override List GetObjectsInView() // this returns all visible doc objects. + var objs = new List(); + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - var objs = new List(); - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + BlockTableRecord modelSpace = Doc.Database.GetModelSpace(); + foreach (ObjectId id in modelSpace) { - BlockTableRecord modelSpace = Doc.Database.GetModelSpace(); - foreach (ObjectId id in modelSpace) + var dbObj = tr.GetObject(id, OpenMode.ForRead); + if (dbObj.Visible()) { - var dbObj = tr.GetObject(id, OpenMode.ForRead); - if (dbObj.Visible()) - objs.Add(dbObj.Handle.ToString()); + objs.Add(dbObj.Handle.ToString()); } - tr.Commit(); } - return objs; + tr.Commit(); } + return objs; + } - public override List GetSelectedObjects() + public override List GetSelectedObjects() + { + var objs = new List(); + if (Doc != null) { - var objs = new List(); - if (Doc != null) + PromptSelectionResult selection = Doc.Editor.SelectImplied(); + if (selection.Status == PromptStatus.OK) { - PromptSelectionResult selection = Doc.Editor.SelectImplied(); - if (selection.Status == PromptStatus.OK) - objs = selection.Value.GetHandles(); + objs = selection.Value.GetHandles(); } - return objs; } + return objs; + } - public override List GetSelectionFilters() + public override List GetSelectionFilters() + { + return new List() { - return new List() + new ManualSelectionFilter(), + new ListSelectionFilter { - new ManualSelectionFilter(), - new ListSelectionFilter - { - Slug = "layer", - Name = "Layers", - Icon = "LayersTriple", - Description = "Selects objects based on their layers.", - Values = GetLayers() - }, - new AllSelectionFilter - { - Slug = "all", - Name = "Everything", - Icon = "CubeScan", - Description = "Selects all document objects." - } - }; - } + Slug = "layer", + Name = "Layers", + Icon = "LayersTriple", + Description = "Selects objects based on their layers.", + Values = GetLayers() + }, + new AllSelectionFilter + { + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Selects all document objects." + } + }; + } - public override void SelectClientObjects(List args, bool deselect = false) + public override void SelectClientObjects(List args, bool deselect = false) + { + var editor = Application.DocumentManager.MdiActiveDocument.Editor; + var currentSelection = editor.SelectImplied().Value?.GetObjectIds()?.ToList() ?? new List(); + foreach (var arg in args) { - var editor = Application.DocumentManager.MdiActiveDocument.Editor; - var currentSelection = editor.SelectImplied().Value?.GetObjectIds()?.ToList() ?? new List(); - foreach (var arg in args) + try { - try + if (Utils.GetHandle(arg, out Handle handle)) { - if (Utils.GetHandle(arg, out Handle handle)) - if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) + if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) + { + if (deselect) { - if (deselect) + if (currentSelection.Contains(id)) { - if (currentSelection.Contains(id)) - currentSelection.Remove(id); + currentSelection.Remove(id); } - else + } + else + { + if (!currentSelection.Contains(id)) { - if (!currentSelection.Contains(id)) - currentSelection.Add(id); + currentSelection.Add(id); } } + } } - catch { } } - if (currentSelection.Count == 0) - editor.SetImpliedSelection(new ObjectId[0]); - else - Autodesk.AutoCAD.Internal.Utils.SelectObjects(currentSelection.ToArray()); - Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); + catch { } + } + if (currentSelection.Count == 0) + { + editor.SetImpliedSelection(new ObjectId[0]); + } + else + { + Autodesk.AutoCAD.Internal.Utils.SelectObjects(currentSelection.ToArray()); } - private List GetObjectsFromFilter(ISelectionFilter filter, ISpeckleConverter converter) + Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); + } + + private List GetObjectsFromFilter(ISelectionFilter filter, ISpeckleConverter converter) + { + var selection = new List(); + switch (filter.Slug) { - var selection = new List(); - switch (filter.Slug) - { - case "manual": - return filter.Selection; - case "all": - return Doc.ConvertibleObjects(converter); - case "layer": - foreach (var layerName in filter.Selection) + case "manual": + return filter.Selection; + case "all": + return Doc.ConvertibleObjects(converter); + case "layer": + foreach (var layerName in filter.Selection) + { + TypedValue[] layerType = new TypedValue[1] { new((int)DxfCode.LayerName, layerName) }; + PromptSelectionResult prompt = Doc.Editor.SelectAll(new SelectionFilter(layerType)); + if (prompt.Status == PromptStatus.OK) { - TypedValue[] layerType = new TypedValue[1] { new TypedValue((int)DxfCode.LayerName, layerName) }; - PromptSelectionResult prompt = Doc.Editor.SelectAll(new SelectionFilter(layerType)); - if (prompt.Status == PromptStatus.OK) - selection.AddRange(prompt.Value.GetHandles()); + selection.AddRange(prompt.Value.GetHandles()); } - return selection; - } - return selection; + } + return selection; } + return selection; } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Send.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Send.cs index 2527d5e2e3..287a8f193c 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Send.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.Send.cs @@ -19,321 +19,348 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings + public override async Task SendStream(StreamState state, ProgressViewModel progress) { - public override async Task SendStream(StreamState state, ProgressViewModel progress) - { - var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); - - var streamId = state.StreamId; - var client = state.Client; - progress.Report = new ProgressReport(); - - if (state.Filter != null) - state.SelectedObjectIds = GetObjectsFromFilter(state.Filter, converter); + var converter = KitManager.GetDefaultKit().LoadConverter(Utils.VersionedAppName); - // remove deleted object ids - var deletedElements = new List(); - foreach (var selectedId in state.SelectedObjectIds) - if (Utils.GetHandle(selectedId, out Handle handle)) - if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) - if (id.IsErased || id.IsNull) - deletedElements.Add(selectedId); + var streamId = state.StreamId; + var client = state.Client; + progress.Report = new ProgressReport(); - state.SelectedObjectIds = state.SelectedObjectIds.Where(o => !deletedElements.Contains(o)).ToList(); + if (state.Filter != null) + { + state.SelectedObjectIds = GetObjectsFromFilter(state.Filter, converter); + } - if (state.SelectedObjectIds.Count == 0) + // remove deleted object ids + var deletedElements = new List(); + foreach (var selectedId in state.SelectedObjectIds) + { + if (Utils.GetHandle(selectedId, out Handle handle)) { - throw new InvalidOperationException( - "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." - ); + if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) + { + if (id.IsErased || id.IsNull) + { + deletedElements.Add(selectedId); + } + } } + } - var modelName = $"{Utils.AppName} Model"; - var commitObject = new Collection(modelName, modelName.ToLower()); - commitObject["units"] = Utils.GetUnits(Doc); // TODO: check whether commits base needs units attached + state.SelectedObjectIds = state.SelectedObjectIds.Where(o => !deletedElements.Contains(o)).ToList(); - int convertedCount = 0; + if (state.SelectedObjectIds.Count == 0) + { + throw new InvalidOperationException( + "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." + ); + } + + var modelName = $"{Utils.AppName} Model"; + var commitObject = new Collection(modelName, modelName.ToLower()); + commitObject["units"] = Utils.GetUnits(Doc); // TODO: check whether commits base needs units attached - // invoke conversions on the main thread via control - try + int convertedCount = 0; + + // invoke conversions on the main thread via control + try + { + if (Control.InvokeRequired) { - if (Control.InvokeRequired) - Control.Invoke( - new Action(() => ConvertSendCommit(commitObject, converter, state, progress, ref convertedCount)), - new object[] { } - ); - else - ConvertSendCommit(commitObject, converter, state, progress, ref convertedCount); - progress.Report.Merge(converter.Report); + Control.Invoke( + new Action(() => ConvertSendCommit(commitObject, converter, state, progress, ref convertedCount)), + new object[] { } + ); } - catch (Exception e) + else { - progress.Report.LogOperationError(e); + ConvertSendCommit(commitObject, converter, state, progress, ref convertedCount); } - if (convertedCount == 0) - { - throw new SpeckleException("Zero objects converted successfully. Send stopped."); - } + progress.Report.Merge(converter.Report); + } + catch (Exception e) + { + progress.Report.LogOperationError(e); + } - progress.CancellationToken.ThrowIfCancellationRequested(); + if (convertedCount == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } - var transports = new List() { new ServerTransport(client.Account, streamId) }; + progress.CancellationToken.ThrowIfCancellationRequested(); - var commitObjId = await Operations.Send( - commitObject, - progress.CancellationToken, - transports, - onProgressAction: dict => progress.Update(dict), - onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, - disposeTransports: true - ); + var transports = new List() { new ServerTransport(client.Account, streamId) }; - progress.CancellationToken.ThrowIfCancellationRequested(); + var commitObjId = await Operations.Send( + commitObject, + progress.CancellationToken, + transports, + onProgressAction: dict => progress.Update(dict), + onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, + disposeTransports: true + ); - var actualCommit = new CommitCreateInput - { - streamId = streamId, - objectId = commitObjId, - branchName = state.BranchName, - message = state.CommitMessage ?? $"Pushed {convertedCount} elements from {Utils.AppName}.", - sourceApplication = Utils.VersionedAppName - }; - - if (state.PreviousCommitId != null) - { - actualCommit.parents = new List() { state.PreviousCommitId }; - } + progress.CancellationToken.ThrowIfCancellationRequested(); - var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); - return commitId; + var actualCommit = new CommitCreateInput + { + streamId = streamId, + objectId = commitObjId, + branchName = state.BranchName, + message = state.CommitMessage ?? $"Pushed {convertedCount} elements from {Utils.AppName}.", + sourceApplication = Utils.VersionedAppName + }; + + if (state.PreviousCommitId != null) + { + actualCommit.parents = new List() { state.PreviousCommitId }; } - delegate void SendingDelegate( - Collection commitObject, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress, - ref int convertedCount - ); + var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); + return commitId; + } - private void ConvertSendCommit( - Collection commitObject, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress, - ref int convertedCount - ) + delegate void SendingDelegate( + Collection commitObject, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress, + ref int convertedCount + ); + + private void ConvertSendCommit( + Collection commitObject, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress, + ref int convertedCount + ) + { + using (DocumentLock acLckDoc = Doc.LockDocument()) { - using (DocumentLock acLckDoc = Doc.LockDocument()) + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // set the context doc for conversion - this is set inside the transaction loop because the converter retrieves this transaction for all db editing when the context doc is set! + converter.SetContextDocument(Doc); + + // set converter settings as tuples (setting slug, setting selection) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - // set the context doc for conversion - this is set inside the transaction loop because the converter retrieves this transaction for all db editing when the context doc is set! - converter.SetContextDocument(Doc); + settings.Add(setting.Slug, setting.Selection); + } + + converter.SetConverterSettings(settings); + + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 0; + + // add applicationID xdata before send + if (!ApplicationIdManager.AddApplicationIdXDataToDoc(Doc, tr)) + { + progress.Report.LogOperationError(new Exception("Could not create document application id reg table")); + return; + } - // set converter settings as tuples (setting slug, setting selection) - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); + // get the hash of the file name to create a more unique application id + var fileNameHash = GetDocumentId(); - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 0; + string servicedApplication = converter.GetServicedApplications().First(); - // add applicationID xdata before send - if (!ApplicationIdManager.AddApplicationIdXDataToDoc(Doc, tr)) + // store converted commit objects and layers by layer paths + var commitLayerObjects = new Dictionary>(); + var commitCollections = new Dictionary(); + + foreach (var autocadObjectHandle in state.SelectedObjectIds) + { + // handle user cancellation + if (progress.CancellationToken.IsCancellationRequested) { - progress.Report.LogOperationError(new Exception("Could not create document application id reg table")); return; } - // get the hash of the file name to create a more unique application id - var fileNameHash = GetDocumentId(); + // get the db object from id + DBObject obj = null; + string layer = null; + string applicationId = null; + if (Utils.GetHandle(autocadObjectHandle, out Handle hn)) + { + obj = hn.GetObject(tr, out string type, out layer, out applicationId); + } + else + { + progress.Report.LogOperationError(new Exception($"Failed to find doc object ${autocadObjectHandle}.")); + continue; + } - string servicedApplication = converter.GetServicedApplications().First(); + // create applicationobject for reporting + Base converted = null; + var descriptor = Utils.ObjectDescriptor(obj); + ApplicationObject reportObj = new(autocadObjectHandle, descriptor) { applicationId = autocadObjectHandle }; - // store converted commit objects and layers by layer paths - var commitLayerObjects = new Dictionary>(); - var commitCollections = new Dictionary(); + if (!converter.CanConvertToSpeckle(obj)) + { +#if ADVANCESTEEL + UpdateASObject(reportObj, obj); +#endif + reportObj.Update( + status: ApplicationObject.State.Skipped, + logItem: $"Sending this object type is not supported in {Utils.AppName}" + ); + progress.Report.Log(reportObj); + continue; + } - foreach (var autocadObjectHandle in state.SelectedObjectIds) + try { - // handle user cancellation - if (progress.CancellationToken.IsCancellationRequested) + // convert obj + converter.Report.Log(reportObj); // Log object so converter can access + converted = converter.ConvertToSpeckle(obj); + if (converted == null) { - return; + reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); + progress.Report.Log(reportObj); + continue; } - // get the db object from id - DBObject obj = null; - string layer = null; - string applicationId = null; - if (Utils.GetHandle(autocadObjectHandle, out Handle hn)) + /* TODO: adding the extension dictionary / xdata per object + foreach (var key in obj.ExtensionDictionary) + converted[key] = obj.ExtensionDictionary.GetUserString(key); + */ + +#if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 + // add property sets if this is Civil3D + var propertySets = obj.GetPropertySets(tr); + if (propertySets.Count > 0) { - obj = hn.GetObject(tr, out string type, out layer, out applicationId); + converted["propertySets"] = propertySets; + } +#endif + // handle converted object layer + if (commitLayerObjects.ContainsKey(layer)) + { + commitLayerObjects[layer].Add(converted); } else { - progress.Report.LogOperationError(new Exception($"Failed to find doc object ${autocadObjectHandle}.")); - continue; + commitLayerObjects.Add(layer, new List { converted }); } - // create applicationobject for reporting - Base converted = null; - var descriptor = Utils.ObjectDescriptor(obj); - ApplicationObject reportObj = new ApplicationObject(autocadObjectHandle, descriptor) + // set application id + #region backwards compatibility + // this is just to overwrite old files with objects that have the unappended autocad native application id + bool isOldApplicationId(string appId) { - applicationId = autocadObjectHandle - }; + if (string.IsNullOrEmpty(appId)) + { + return false; + } - if (!converter.CanConvertToSpeckle(obj)) + return appId.Length == 5 ? true : false; + } + if (isOldApplicationId(applicationId)) { -#if ADVANCESTEEL - UpdateASObject(reportObj, obj); -#endif - reportObj.Update( - status: ApplicationObject.State.Skipped, - logItem: $"Sending this object type is not supported in {Utils.AppName}" + ApplicationIdManager.SetObjectCustomApplicationId( + obj, + autocadObjectHandle, + out applicationId, + fileNameHash ); - progress.Report.Log(reportObj); - continue; } + #endregion - try + if (applicationId == null) // this object didn't have an xdata appId field { - // convert obj - converter.Report.Log(reportObj); // Log object so converter can access - converted = converter.ConvertToSpeckle(obj); - if (converted == null) - { - reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); - progress.Report.Log(reportObj); - continue; - } - - /* TODO: adding the extension dictionary / xdata per object - foreach (var key in obj.ExtensionDictionary) - converted[key] = obj.ExtensionDictionary.GetUserString(key); - */ - -#if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - // add property sets if this is Civil3D - var propertySets = obj.GetPropertySets(tr); - if (propertySets.Count > 0) - converted["propertySets"] = propertySets; -#endif - // handle converted object layer - if (commitLayerObjects.ContainsKey(layer)) - commitLayerObjects[layer].Add(converted); - else - commitLayerObjects.Add(layer, new List { converted }); - - // set application id - #region backwards compatibility - // this is just to overwrite old files with objects that have the unappended autocad native application id - bool isOldApplicationId(string appId) - { - if (string.IsNullOrEmpty(appId)) - return false; - return appId.Length == 5 ? true : false; - } - if (isOldApplicationId(applicationId)) - { - ApplicationIdManager.SetObjectCustomApplicationId( + if ( + !ApplicationIdManager.SetObjectCustomApplicationId( obj, autocadObjectHandle, out applicationId, fileNameHash - ); - } - #endregion - - if (applicationId == null) // this object didn't have an xdata appId field - { - if ( - !ApplicationIdManager.SetObjectCustomApplicationId( - obj, - autocadObjectHandle, - out applicationId, - fileNameHash - ) ) - { - reportObj.Log.Add("Could not set application id xdata"); - } + ) + { + reportObj.Log.Add("Could not set application id xdata"); } - converted.applicationId = applicationId; + } + converted.applicationId = applicationId; - // update progress - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + // update progress + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); - // log report object - reportObj.Update(status: ApplicationObject.State.Created, logItem: $"Sent as {converted.GetType().Name}"); - progress.Report.Log(reportObj); + // log report object + reportObj.Update(status: ApplicationObject.State.Created, logItem: $"Sent as {converted.GetType().Name}"); + progress.Report.Log(reportObj); - convertedCount++; - } - catch (Exception e) - { - //TODO: Log to serilog failed conversions - reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); - progress.Report.Log(reportObj); - continue; - } + convertedCount++; + } + catch (Exception e) + { + //TODO: Log to serilog failed conversions + reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); + progress.Report.Log(reportObj); + continue; } + } - #region layer handling - // get the layer table - var layerTable = (LayerTable)tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead); + #region layer handling + // get the layer table + var layerTable = (LayerTable)tr.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead); - // convert layers as collections and attach all layer objects - foreach (var layerPath in commitLayerObjects.Keys) - if (commitCollections.ContainsKey(layerPath)) - { - commitCollections[layerPath].elements = commitLayerObjects[layerPath]; - } - else + // convert layers as collections and attach all layer objects + foreach (var layerPath in commitLayerObjects.Keys) + { + if (commitCollections.ContainsKey(layerPath)) + { + commitCollections[layerPath].elements = commitLayerObjects[layerPath]; + } + else + { + var layerRecord = (LayerTableRecord)tr.GetObject(layerTable[layerPath], OpenMode.ForRead); + var collection = converter.ConvertToSpeckle(layerRecord) as Collection; + if (collection != null) { - var layerRecord = (LayerTableRecord)tr.GetObject(layerTable[layerPath], OpenMode.ForRead); - var collection = converter.ConvertToSpeckle(layerRecord) as Collection; - if (collection != null) - { - collection.elements = commitLayerObjects[layerPath]; - commitCollections.Add(layerPath, collection); - } + collection.elements = commitLayerObjects[layerPath]; + commitCollections.Add(layerPath, collection); } - - // attach collections to the base commit - foreach (var collection in commitCollections) - { - commitObject.elements.Add(collection.Value); } + } - #endregion - - tr.Commit(); + // attach collections to the base commit + foreach (var collection in commitCollections) + { + commitObject.elements.Add(collection.Value); } + + #endregion + + tr.Commit(); } } + } #if ADVANCESTEEL - private void UpdateASObject(ApplicationObject applicationObject, DBObject obj) + private void UpdateASObject(ApplicationObject applicationObject, DBObject obj) + { + if (!CheckAdvanceSteelObject(obj)) { - if (!CheckAdvanceSteelObject(obj)) - return; + return; + } - ASFilerObject filerObject = GetFilerObjectByEntity(obj); - if (filerObject != null) - { - applicationObject.Update(descriptor: filerObject.GetType().Name); - } + ASFilerObject filerObject = GetFilerObjectByEntity(obj); + if (filerObject != null) + { + applicationObject.Update(descriptor: filerObject.GetType().Name); } -#endif } +#endif } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.cs index bdce3c2653..eb537087b0 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/UI/ConnectorBindingsAutocadCivil.cs @@ -13,150 +13,156 @@ using ASFilerObject = Autodesk.AdvanceSteel.CADAccess.FilerObject; #endif -namespace Speckle.ConnectorAutocadCivil.UI +namespace Speckle.ConnectorAutocadCivil.UI; + +public partial class ConnectorBindingsAutocad : ConnectorBindings { - public partial class ConnectorBindingsAutocad : ConnectorBindings - { - public static Document Doc => Application.DocumentManager.MdiActiveDocument; + public static Document Doc => Application.DocumentManager.MdiActiveDocument; - /// - /// Stored Base objects from commit flattening on receive: key is the Base id - /// - public Dictionary StoredObjects = new Dictionary(); + /// + /// Stored Base objects from commit flattening on receive: key is the Base id + /// + public Dictionary StoredObjects = new(); - /// - /// Stored document line types used for baking objects on receive - /// - public Dictionary LineTypeDictionary = new Dictionary(); + /// + /// Stored document line types used for baking objects on receive + /// + public Dictionary LineTypeDictionary = new(); - public List GetLayers() + public List GetLayers() + { + var layers = new List(); + foreach (var docLayer in Application.UIBindings.Collections.Layers) { - var layers = new List(); - foreach (var docLayer in Application.UIBindings.Collections.Layers) - { - var name = docLayer.GetProperties().Find("Name", true).GetValue(docLayer); - layers.Add(name as string); - } - return layers; + var name = docLayer.GetProperties().Find("Name", true).GetValue(docLayer); + layers.Add(name as string); } + return layers; + } - // AutoCAD API should only be called on the main thread. - // Not doing so results in botched conversions for any that require adding objects to Document model space before modifying (eg adding vertices and faces for meshes) - // There's no easy way to access main thread from document object, therefore we are creating a control during Connector Bindings constructor (since it's called on main thread) that allows for invoking worker threads on the main thread - public System.Windows.Forms.Control Control; + // AutoCAD API should only be called on the main thread. + // Not doing so results in botched conversions for any that require adding objects to Document model space before modifying (eg adding vertices and faces for meshes) + // There's no easy way to access main thread from document object, therefore we are creating a control during Connector Bindings constructor (since it's called on main thread) that allows for invoking worker threads on the main thread + public System.Windows.Forms.Control Control; - public ConnectorBindingsAutocad() - : base() - { - Control = new System.Windows.Forms.Control(); - Control.CreateControl(); - } + public ConnectorBindingsAutocad() + : base() + { + Control = new System.Windows.Forms.Control(); + Control.CreateControl(); + } - public override List GetReceiveModes() - { - return new List { ReceiveMode.Create, ReceiveMode.Update }; - } + public override List GetReceiveModes() + { + return new List { ReceiveMode.Create, ReceiveMode.Update }; + } - #region local streams - public override void WriteStreamsToFile(List streams) - { - SpeckleStreamManager.WriteStreamStateList(Doc, streams); - } + #region local streams + public override void WriteStreamsToFile(List streams) + { + SpeckleStreamManager.WriteStreamStateList(Doc, streams); + } - public override List GetStreamsInFile() + public override List GetStreamsInFile() + { + var streams = new List(); + if (Doc != null) { - var streams = new List(); - if (Doc != null) - streams = SpeckleStreamManager.ReadState(Doc); - return streams; + streams = SpeckleStreamManager.ReadState(Doc); } - #endregion - public override string GetHostAppNameVersion() => - Utils.VersionedAppName - .Replace("AutoCAD", "AutoCAD ") - .Replace("Civil3D", "Civil 3D ") - .Replace("AdvanceSteel", "Advance Steel "); //hack for ADSK store; + return streams; + } + #endregion + + public override string GetHostAppNameVersion() => + Utils.VersionedAppName + .Replace("AutoCAD", "AutoCAD ") + .Replace("Civil3D", "Civil 3D ") + .Replace("AdvanceSteel", "Advance Steel "); //hack for ADSK store; - public override string GetHostAppName() => Utils.Slug; + public override string GetHostAppName() => Utils.Slug; - private string GetDocPath(Document doc) => - HostApplicationServices.Current.FindFile(doc?.Name, doc?.Database, FindFileHint.Default); + private string GetDocPath(Document doc) => + HostApplicationServices.Current.FindFile(doc?.Name, doc?.Database, FindFileHint.Default); - public override string GetDocumentId() + public override string GetDocumentId() + { + string path = null; + try { - string path = null; - try - { - path = GetDocPath(Doc); - } - catch { } - var docString = $"{(path != null ? path : "")}{(Doc != null ? Doc.Name : "")}"; - var hash = !string.IsNullOrEmpty(docString) - ? Core.Models.Utilities.HashString(docString, Core.Models.Utilities.HashingFunctions.MD5) - : null; - return hash; + path = GetDocPath(Doc); } + catch { } + var docString = $"{(path != null ? path : "")}{(Doc != null ? Doc.Name : "")}"; + var hash = !string.IsNullOrEmpty(docString) + ? Core.Models.Utilities.HashString(docString, Core.Models.Utilities.HashingFunctions.MD5) + : null; + return hash; + } - public override string GetDocumentLocation() => GetDocPath(Doc); + public override string GetDocumentLocation() => GetDocPath(Doc); - public override string GetFileName() => (Doc != null) ? System.IO.Path.GetFileName(Doc.Name) : string.Empty; + public override string GetFileName() => (Doc != null) ? System.IO.Path.GetFileName(Doc.Name) : string.Empty; - public override string GetActiveViewName() => "Entire Document"; + public override string GetActiveViewName() => "Entire Document"; - private List CurrentSettings { get; set; } // used to store the Stream State settings when sending/receiving + private List CurrentSettings { get; set; } // used to store the Stream State settings when sending/receiving - // CAUTION: these strings need to have the same values as in the converter - const string InternalOrigin = "Internal Origin (default)"; - const string UCS = "Current User Coordinate System"; + // CAUTION: these strings need to have the same values as in the converter + const string InternalOrigin = "Internal Origin (default)"; + const string UCS = "Current User Coordinate System"; - public override List GetSettings() - { - List referencePoints = new List() { InternalOrigin }; + public override List GetSettings() + { + List referencePoints = new() { InternalOrigin }; - // add the current UCS if it exists - if (Doc.Editor.CurrentUserCoordinateSystem != null) - referencePoints.Add(UCS); + // add the current UCS if it exists + if (Doc.Editor.CurrentUserCoordinateSystem != null) + { + referencePoints.Add(UCS); + } - // add any named UCS if they exist - var namedUCS = new List(); - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // add any named UCS if they exist + var namedUCS = new List(); + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + var UCSTable = tr.GetObject(Doc.Database.UcsTableId, OpenMode.ForRead) as UcsTable; + foreach (var entry in UCSTable) { - var UCSTable = tr.GetObject(Doc.Database.UcsTableId, OpenMode.ForRead) as UcsTable; - foreach (var entry in UCSTable) - { - var ucs = tr.GetObject(entry, OpenMode.ForRead) as UcsTableRecord; - namedUCS.Add(ucs.Name); - } - tr.Commit(); + var ucs = tr.GetObject(entry, OpenMode.ForRead) as UcsTableRecord; + namedUCS.Add(ucs.Name); } - if (namedUCS.Any()) - referencePoints.AddRange(namedUCS); - - return new List - { - new ListBoxSetting - { - Slug = "reference-point", - Name = "Reference Point", - Icon = "LocationSearching", - Values = referencePoints, - Selection = InternalOrigin, - Description = "Sends or receives stream objects in relation to this document point" - }, - }; + tr.Commit(); } - - //TODO - public override List GetCustomStreamMenuItems() + if (namedUCS.Any()) { - return new List(); + referencePoints.AddRange(namedUCS); } - public override void ResetDocument() + return new List { - Doc.Editor.SetImpliedSelection(new ObjectId[0]); - Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); - } + new ListBoxSetting + { + Slug = "reference-point", + Name = "Reference Point", + Icon = "LocationSearching", + Values = referencePoints, + Selection = InternalOrigin, + Description = "Sends or receives stream objects in relation to this document point" + }, + }; + } + + //TODO + public override List GetCustomStreamMenuItems() + { + return new List(); + } + + public override void ResetDocument() + { + Doc.Editor.SetImpliedSelection(new ObjectId[0]); + Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); } } diff --git a/ConnectorAutocadCivil/ConnectorAutocadCivil/Utils.cs b/ConnectorAutocadCivil/ConnectorAutocadCivil/Utils.cs index 00cad83e85..afe5e3832a 100644 --- a/ConnectorAutocadCivil/ConnectorAutocadCivil/Utils.cs +++ b/ConnectorAutocadCivil/ConnectorAutocadCivil/Utils.cs @@ -26,702 +26,758 @@ using Autodesk.AdvanceSteel.Modelling; #endif -namespace Speckle.ConnectorAutocadCivil +namespace Speckle.ConnectorAutocadCivil; + +public static class Utils { - public static class Utils - { #if AUTOCAD2021 - public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2021); - public static string AppName = HostApplications.AutoCAD.Name; - public static string Slug = HostApplications.AutoCAD.Slug; + public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2021); + public static string AppName = HostApplications.AutoCAD.Name; + public static string Slug = HostApplications.AutoCAD.Slug; #elif AUTOCAD2022 - public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2022); - public static string AppName = HostApplications.AutoCAD.Name; - public static string Slug = HostApplications.AutoCAD.Slug; + public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2022); + public static string AppName = HostApplications.AutoCAD.Name; + public static string Slug = HostApplications.AutoCAD.Slug; #elif AUTOCAD2023 - public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2023); - public static string AppName = HostApplications.AutoCAD.Name; - public static string Slug = HostApplications.AutoCAD.Slug; + public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2023); + public static string AppName = HostApplications.AutoCAD.Name; + public static string Slug = HostApplications.AutoCAD.Slug; #elif AUTOCAD2024 - public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2024); - public static string AppName = HostApplications.AutoCAD.Name; - public static string Slug = HostApplications.AutoCAD.Slug; + public static string VersionedAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2024); + public static string AppName = HostApplications.AutoCAD.Name; + public static string Slug = HostApplications.AutoCAD.Slug; #elif CIVIL2021 - public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2021); - public static string AppName = HostApplications.Civil.Name; - public static string Slug = HostApplications.Civil.Slug; + public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2021); + public static string AppName = HostApplications.Civil.Name; + public static string Slug = HostApplications.Civil.Slug; #elif CIVIL2022 - public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2022); - public static string AppName = HostApplications.Civil.Name; - public static string Slug = HostApplications.Civil.Slug; + public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2022); + public static string AppName = HostApplications.Civil.Name; + public static string Slug = HostApplications.Civil.Slug; #elif CIVIL2023 - public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2023); - public static string AppName = HostApplications.Civil.Name; - public static string Slug = HostApplications.Civil.Slug; + public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2023); + public static string AppName = HostApplications.Civil.Name; + public static string Slug = HostApplications.Civil.Slug; #elif CIVIL2024 - public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2024); - public static string AppName = HostApplications.Civil.Name; - public static string Slug = HostApplications.Civil.Slug; + public static string VersionedAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2024); + public static string AppName = HostApplications.Civil.Name; + public static string Slug = HostApplications.Civil.Slug; #elif ADVANCESTEEL2023 - public static string VersionedAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2023); - public static string AppName = HostApplications.AdvanceSteel.Name; - public static string Slug = HostApplications.AdvanceSteel.Slug; + public static string VersionedAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2023); + public static string AppName = HostApplications.AdvanceSteel.Name; + public static string Slug = HostApplications.AdvanceSteel.Slug; #elif ADVANCESTEEL2024 - public static string VersionedAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2024); - public static string AppName = HostApplications.AdvanceSteel.Name; - public static string Slug = HostApplications.AdvanceSteel.Slug; + public static string VersionedAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2024); + public static string AppName = HostApplications.AdvanceSteel.Name; + public static string Slug = HostApplications.AdvanceSteel.Slug; #endif - public static string invalidChars = @"<>/\:;""?*|=,‘"; - - #region extension methods - - /// - /// Retrieves object ids as strings - /// - /// - /// - /// - /// This is used because for some unfathomable reason, ObjectId.ToString() returns "(id)" instead of "id". - /// The Handle is a persisitent indentifier which is unique per drawing. - /// The ObjectId is a non - persitent identifier(reassigned each time the drawing is opened) which is unique per session. - /// - public static List ToStrings(this ObjectId[] ids) => - ids.Select(o => o.Handle.ToString().Trim(new char[] { '(', ')' })).ToList(); + public static string invalidChars = @"<>/\:;""?*|=,‘"; + + #region extension methods + + /// + /// Retrieves object ids as strings + /// + /// + /// + /// + /// This is used because for some unfathomable reason, ObjectId.ToString() returns "(id)" instead of "id". + /// The Handle is a persisitent indentifier which is unique per drawing. + /// The ObjectId is a non - persitent identifier(reassigned each time the drawing is opened) which is unique per session. + /// + public static List ToStrings(this ObjectId[] ids) => + ids.Select(o => o.Handle.ToString().Trim(new char[] { '(', ')' })).ToList(); + + /// + /// Retrieve handles of visible objects in a selection + /// + /// + /// List of handles as strings + /// + /// We are storing obj handles instead of ids because handles persist and are saved with the doc. + /// ObjectIds are unique to an application session (useful for multi-document operations) but are created with each new session. + /// + public static List GetHandles(this SelectionSet selection) + { + var handles = new List(); - /// - /// Retrieve handles of visible objects in a selection - /// - /// - /// List of handles as strings - /// - /// We are storing obj handles instead of ids because handles persist and are saved with the doc. - /// ObjectIds are unique to an application session (useful for multi-document operations) but are created with each new session. - /// - public static List GetHandles(this SelectionSet selection) + if (selection == null) { - var handles = new List(); - - if (selection == null) - return handles; + return handles; + } - Document Doc = Application.DocumentManager.MdiActiveDocument; - using (TransactionContext.StartTransaction(Doc)) + Document Doc = Application.DocumentManager.MdiActiveDocument; + using (TransactionContext.StartTransaction(Doc)) + { + Transaction tr = Doc.TransactionManager.TopTransaction; + foreach (SelectedObject selObj in selection) { - Transaction tr = Doc.TransactionManager.TopTransaction; - foreach (SelectedObject selObj in selection) + DBObject obj = tr.GetObject(selObj.ObjectId, OpenMode.ForRead); + if (obj != null && obj.Visible()) { - DBObject obj = tr.GetObject(selObj.ObjectId, OpenMode.ForRead); - if (obj != null && obj.Visible()) - { #if ADVANCESTEEL - if (CheckAdvanceSteelObject(obj)) + if (CheckAdvanceSteelObject(obj)) + { + ASFilerObject filerObject = GetFilerObjectByEntity(obj); + if (filerObject is FeatureObject || filerObject is PlateFoldRelation) //Don't select features objects, they are going with Advance Steel objects { - ASFilerObject filerObject = GetFilerObjectByEntity(obj); - if (filerObject is FeatureObject || filerObject is PlateFoldRelation) //Don't select features objects, they are going with Advance Steel objects - continue; + continue; } + } #endif - handles.Add(obj.Handle.ToString()); - } + handles.Add(obj.Handle.ToString()); } } - - return handles; } - /// - /// Adds an entity to the autocad database model space record - /// - /// - /// - public static ObjectId Append(this Entity entity, string layer = null) + return handles; + } + + /// + /// Adds an entity to the autocad database model space record + /// + /// + /// + public static ObjectId Append(this Entity entity, string layer = null) + { + var db = (entity.Database == null) ? Application.DocumentManager.MdiActiveDocument.Database : entity.Database; + Transaction tr = db.TransactionManager.TopTransaction; + if (tr == null) { - var db = (entity.Database == null) ? Application.DocumentManager.MdiActiveDocument.Database : entity.Database; - Transaction tr = db.TransactionManager.TopTransaction; - if (tr == null) - return ObjectId.Null; + return ObjectId.Null; + } - BlockTableRecord btr = db.GetModelSpace(OpenMode.ForWrite); - if (entity.IsNewObject) + BlockTableRecord btr = db.GetModelSpace(OpenMode.ForWrite); + if (entity.IsNewObject) + { + if (layer != null) { - if (layer != null) - entity.Layer = layer; - var id = btr.AppendEntity(entity); - tr.AddNewlyCreatedDBObject(entity, true); - return id; + entity.Layer = layer; } - else + + var id = btr.AppendEntity(entity); + tr.AddNewlyCreatedDBObject(entity, true); + return id; + } + else + { + if (layer != null) { - if (layer != null) - entity.Layer = layer; - return entity.Id; + entity.Layer = layer; } + + return entity.Id; } + } - /// - /// Gets the document model space - /// - /// - /// - /// - public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead) + /// + /// Gets the document model space + /// + /// + /// + /// + public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead) + { + return (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(mode); + } + + /// + /// Used to retrieve a DB Object from its handle + /// + /// Object handle as string + /// Object class dxf name + /// Object layer name + /// + public static DBObject GetObject( + this Handle handle, + Transaction tr, + out string type, + out string layer, + out string applicationId + ) + { + Document Doc = Application.DocumentManager.MdiActiveDocument; + DBObject obj = null; + type = null; + layer = null; + applicationId = null; + + // get objectId + ObjectId id = Doc.Database.GetObjectId(false, handle, 0); + if (!id.IsErased && !id.IsNull) { - return (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(mode); + type = id.ObjectClass.DxfName; + + // get the db object from id + obj = tr.GetObject(id, OpenMode.ForRead); + if (obj != null) + { + Entity objEntity = obj as Entity; + layer = objEntity.Layer; + applicationId = ApplicationIdManager.GetFromXData(objEntity); + } } + return obj; + } - /// - /// Used to retrieve a DB Object from its handle - /// - /// Object handle as string - /// Object class dxf name - /// Object layer name - /// - public static DBObject GetObject( - this Handle handle, - Transaction tr, - out string type, - out string layer, - out string applicationId - ) + /// + /// Get visibility of a DBObject + /// + /// + /// + public static bool Visible(this DBObject obj) + { + bool isVisible = true; + + if (obj is Entity) { - Document Doc = Application.DocumentManager.MdiActiveDocument; - DBObject obj = null; - type = null; - layer = null; - applicationId = null; - - // get objectId - ObjectId id = Doc.Database.GetObjectId(false, handle, 0); - if (!id.IsErased && !id.IsNull) + Entity ent = obj as Entity; + + if (!ent.Visible) { - type = id.ObjectClass.DxfName; + return ent.Visible; + } - // get the db object from id - obj = tr.GetObject(id, OpenMode.ForRead); - if (obj != null) + Document Doc = Application.DocumentManager.MdiActiveDocument; + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + LayerTableRecord lyrTblRec = tr.GetObject(ent.LayerId, OpenMode.ForRead) as LayerTableRecord; + if (lyrTblRec.IsOff) { - Entity objEntity = obj as Entity; - layer = objEntity.Layer; - applicationId = ApplicationIdManager.GetFromXData(objEntity); + isVisible = false; } + + tr.Commit(); } - return obj; } - - /// - /// Get visibility of a DBObject - /// - /// - /// - public static bool Visible(this DBObject obj) + else { - bool isVisible = true; - - if (obj is Entity) + PropertyInfo prop = obj.GetType().GetProperty("Visible"); + try { - Entity ent = obj as Entity; + isVisible = (bool)prop.GetValue(obj); + } + catch { } + } + return isVisible; + } - if (!ent.Visible) - return ent.Visible; +#if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 + private static Autodesk.Aec.PropertyData.DataType? GetPropertySetType(object prop) + { + switch (prop) + { + case IEnumerable _: + case IEnumerable _: + case IEnumerable _: + case IEnumerable _: + return Autodesk.Aec.PropertyData.DataType.List; + + case string _: + return Autodesk.Aec.PropertyData.DataType.Text; + case int _: + return Autodesk.Aec.PropertyData.DataType.Integer; + case double _: + return Autodesk.Aec.PropertyData.DataType.Real; + case bool _: + return Autodesk.Aec.PropertyData.DataType.TrueFalse; + + default: + return null; + } + } - Document Doc = Application.DocumentManager.MdiActiveDocument; - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + public static void SetPropertySets(this Entity entity, Document doc, List> propertySetDicts) + { + // create a dictionary for property sets for this object + var name = $"Speckle {entity.Handle} Property Set"; + int count = 0; + foreach (var propertySetDict in propertySetDicts) + { + // create the property set definition for this set. + var propSetDef = new PropertySetDefinition(); + propSetDef.SetToStandard(doc.Database); + propSetDef.SubSetDatabaseDefaults(doc.Database); + var propSetDefName = name += $" - {count}"; + propSetDef.Description = "Property Set Definition added with Speckle"; + propSetDef.AppliesToAll = true; + + // Create the definition for each property + foreach (var entry in propertySetDict) + { + var propDef = new PropertyDefinition(); + propDef.SetToStandard(doc.Database); + propDef.SubSetDatabaseDefaults(doc.Database); + propDef.Name = entry.Key; + var dataType = GetPropertySetType(entry.Value); + if (dataType != null) { - LayerTableRecord lyrTblRec = tr.GetObject(ent.LayerId, OpenMode.ForRead) as LayerTableRecord; - if (lyrTblRec.IsOff) - isVisible = false; - tr.Commit(); + propDef.DataType = (Autodesk.Aec.PropertyData.DataType)dataType; } + + propDef.DefaultData = entry.Value; + propSetDef.Definitions.Add(propDef); } - else + + // add the property sets to the object + try { - PropertyInfo prop = obj.GetType().GetProperty("Visible"); - try + // add property set to the database + // todo: add logging if the property set couldnt be added because a def already exists + using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) { - isVisible = (bool)prop.GetValue(obj); + var dictPropSetDef = new DictionaryPropertySetDefinitions(doc.Database); + dictPropSetDef.AddNewRecord(propSetDefName, propSetDef); + tr.AddNewlyCreatedDBObject(propSetDef, true); + + entity.UpgradeOpen(); + PropertyDataServices.AddPropertySet(entity, propSetDef.ObjectId); + tr.Commit(); } - catch { } } - return isVisible; + catch { } } + } -#if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - private static Autodesk.Aec.PropertyData.DataType? GetPropertySetType(object prop) + /// + /// Get the property sets of DBObject + /// + /// + /// + public static List> GetPropertySets(this DBObject obj, Transaction tr) + { + var sets = new List>(); + ObjectIdCollection propertySets = null; + try { - switch (prop) - { - case IEnumerable _: - case IEnumerable _: - case IEnumerable _: - case IEnumerable _: - return Autodesk.Aec.PropertyData.DataType.List; + propertySets = PropertyDataServices.GetPropertySets(obj); + } + catch (Exception e) + { } + if (propertySets == null) + { + return sets; + } - case string _: - return Autodesk.Aec.PropertyData.DataType.Text; - case int _: - return Autodesk.Aec.PropertyData.DataType.Integer; - case double _: - return Autodesk.Aec.PropertyData.DataType.Real; - case bool _: - return Autodesk.Aec.PropertyData.DataType.TrueFalse; + foreach (ObjectId id in propertySets) + { + var setDictionary = new Dictionary(); - default: - return null; + PropertySet propertySet = (PropertySet)tr.GetObject(id, OpenMode.ForRead); + PropertySetDefinition setDef = (PropertySetDefinition)tr.GetObject(propertySet.PropertySetDefinition, OpenMode.ForRead); + + PropertyDefinitionCollection propDef = setDef.Definitions; + var propDefs = new Dictionary(); + foreach (PropertyDefinition def in propDef) + { + propDefs.Add(def.Id, def); } - } - public static void SetPropertySets(this Entity entity, Document doc, List> propertySetDicts) - { - // create a dictionary for property sets for this object - var name = $"Speckle {entity.Handle} Property Set"; - int count = 0; - foreach (var propertySetDict in propertySetDicts) + foreach (PropertySetData data in propertySet.PropertySetData) { - // create the property set definition for this set. - var propSetDef = new PropertySetDefinition(); - propSetDef.SetToStandard(doc.Database); - propSetDef.SubSetDatabaseDefaults(doc.Database); - var propSetDefName = name += $" - {count}"; - propSetDef.Description = "Property Set Definition added with Speckle"; - propSetDef.AppliesToAll = true; - - // Create the definition for each property - foreach (var entry in propertySetDict) + if (propDefs.ContainsKey(data.Id)) { - var propDef = new PropertyDefinition(); - propDef.SetToStandard(doc.Database); - propDef.SubSetDatabaseDefaults(doc.Database); - propDef.Name = entry.Key; - var dataType = GetPropertySetType(entry.Value); - if (dataType != null) - propDef.DataType = (Autodesk.Aec.PropertyData.DataType)dataType; - propDef.DefaultData = entry.Value; - propSetDef.Definitions.Add(propDef); + setDictionary.Add(propDefs[data.Id].Name, data.GetData()); } - - // add the property sets to the object - try + else { - // add property set to the database - // todo: add logging if the property set couldnt be added because a def already exists - using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) - { - var dictPropSetDef = new DictionaryPropertySetDefinitions(doc.Database); - dictPropSetDef.AddNewRecord(propSetDefName, propSetDef); - tr.AddNewlyCreatedDBObject(propSetDef, true); - - entity.UpgradeOpen(); - PropertyDataServices.AddPropertySet(entity, propSetDef.ObjectId); - tr.Commit(); - } + setDictionary.Add(data.FieldBucketId, data.GetData()); } - catch { } } - } - /// - /// Get the property sets of DBObject - /// - /// - /// - public static List> GetPropertySets(this DBObject obj, Transaction tr) - { - var sets = new List>(); - ObjectIdCollection propertySets = null; - try + if (setDictionary.Count > 0) { - propertySets = PropertyDataServices.GetPropertySets(obj); + sets.Add(CleanDictionary(setDictionary)); } - catch (Exception e) - { } - if (propertySets == null) return sets; + } + return sets; + } - foreach (ObjectId id in propertySets) + // Handles object types from property set dictionaries + private static Dictionary CleanDictionary(Dictionary dict) + { + var target = new Dictionary(); + foreach (var key in dict.Keys) + { + var obj = dict[key]; + switch (obj) { - var setDictionary = new Dictionary(); - - PropertySet propertySet = (PropertySet)tr.GetObject(id, OpenMode.ForRead); - PropertySetDefinition setDef = (PropertySetDefinition)tr.GetObject(propertySet.PropertySetDefinition, OpenMode.ForRead); + case double _: + case bool _: + case int _: + case string _: + case IEnumerable _: + case IEnumerable _: + case IEnumerable _: + case IEnumerable _: + target[key] = obj; + continue; - PropertyDefinitionCollection propDef = setDef.Definitions; - var propDefs = new Dictionary(); - foreach (PropertyDefinition def in propDef) propDefs.Add(def.Id, def); + case long o: + target[key] = Convert.ToDouble(o); + continue; - foreach (PropertySetData data in propertySet.PropertySetData) - { - if (propDefs.ContainsKey(data.Id)) - setDictionary.Add(propDefs[data.Id].Name, data.GetData()); - else - setDictionary.Add(data.FieldBucketId, data.GetData()); - } + case ObjectId o: + target[key] = o.ToString(); + continue; - if (setDictionary.Count > 0) - sets.Add(CleanDictionary(setDictionary)); + default: + continue; } - return sets; } + return target; + } +#endif - // Handles object types from property set dictionaries - private static Dictionary CleanDictionary(Dictionary dict) + /// + /// Gets the handles of all visible document objects that can be converted to Speckle + /// + /// + /// + /// + public static List ConvertibleObjects(this Document doc, ISpeckleConverter converter) + { + var objs = new List(); + using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) { - var target = new Dictionary(); - foreach (var key in dict.Keys) + BlockTable blckTbl = tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; + BlockTableRecord blckTblRcrd = + tr.GetObject(blckTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord; + foreach (ObjectId id in blckTblRcrd) { - var obj = dict[key]; - switch (obj) + DBObject dbObj = tr.GetObject(id, OpenMode.ForRead); + if (converter.CanConvertToSpeckle(dbObj) && dbObj.Visible()) { - case double _: - case bool _: - case int _: - case string _: - case IEnumerable _: - case IEnumerable _: - case IEnumerable _: - case IEnumerable _: - target[key] = obj; - continue; - - case long o: - target[key] = Convert.ToDouble(o); - continue; - - case ObjectId o: - target[key] = o.ToString(); - continue; - - default: - continue; + objs.Add(dbObj.Handle.ToString()); } } - return target; + tr.Commit(); } -#endif + return objs; + } + #endregion + + #region application id + public static class ApplicationIdManager + { + readonly static string ApplicationIdKey = "applicationId"; /// - /// Gets the handles of all visible document objects that can be converted to Speckle + /// Creates the application id xdata table in the doc if it doesn't already exist /// - /// - /// /// - public static List ConvertibleObjects(this Document doc, ISpeckleConverter converter) + public static bool AddApplicationIdXDataToDoc(Document doc, Transaction tr) { - var objs = new List(); - using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) + var regAppTable = (RegAppTable)tr.GetObject(doc.Database.RegAppTableId, OpenMode.ForRead); + if (!regAppTable.Has(ApplicationIdKey)) { - BlockTable blckTbl = tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; - BlockTableRecord blckTblRcrd = - tr.GetObject(blckTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord; - foreach (ObjectId id in blckTblRcrd) + try + { + using (RegAppTableRecord regAppRecord = new()) + { + regAppRecord.Name = ApplicationIdKey; + regAppTable.UpgradeOpen(); + regAppTable.Add(regAppRecord); + regAppTable.DowngradeOpen(); + tr.AddNewlyCreatedDBObject(regAppRecord, true); + } + } + catch (Exception e) { - DBObject dbObj = tr.GetObject(id, OpenMode.ForRead); - if (converter.CanConvertToSpeckle(dbObj) && dbObj.Visible()) - objs.Add(dbObj.Handle.ToString()); + return false; } - tr.Commit(); } - return objs; + return true; } - #endregion - #region application id - public static class ApplicationIdManager + public static string GetFromXData(Entity obj) { - readonly static string ApplicationIdKey = "applicationId"; - - /// - /// Creates the application id xdata table in the doc if it doesn't already exist - /// - /// - public static bool AddApplicationIdXDataToDoc(Document doc, Transaction tr) + string appId = null; + if (!obj.IsReadEnabled) { - var regAppTable = (RegAppTable)tr.GetObject(doc.Database.RegAppTableId, OpenMode.ForRead); - if (!regAppTable.Has(ApplicationIdKey)) - { - try - { - using (RegAppTableRecord regAppRecord = new RegAppTableRecord()) - { - regAppRecord.Name = ApplicationIdKey; - regAppTable.UpgradeOpen(); - regAppTable.Add(regAppRecord); - regAppTable.DowngradeOpen(); - tr.AddNewlyCreatedDBObject(regAppRecord, true); - } - } - catch (Exception e) - { - return false; - } - } - return true; + obj.UpgradeOpen(); } - public static string GetFromXData(Entity obj) + ResultBuffer rb = obj.GetXDataForApplication(ApplicationIdKey); + if (rb != null) { - string appId = null; - if (!obj.IsReadEnabled) - obj.UpgradeOpen(); - - ResultBuffer rb = obj.GetXDataForApplication(ApplicationIdKey); - if (rb != null) + foreach (var entry in rb) { - foreach (var entry in rb) + if (entry.TypeCode == 1000) { - if (entry.TypeCode == 1000) - { - appId = entry.Value as string; - break; - } + appId = entry.Value as string; + break; } } - return appId; } + return appId; + } - /// - /// Attaches a custom application Id to an object's application id xdata using the has of the file name. - /// This is used because the persistent id of the db object in the file is almost guaranteed to not be unique between files - /// - /// - /// - /// - public static bool SetObjectCustomApplicationId( - DBObject obj, - string id, - out string applicationId, - string fileNameHash = null - ) - { - applicationId = fileNameHash == null ? id : $"{fileNameHash}-{id}"; - var rb = new ResultBuffer( - new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), - new TypedValue(1000, applicationId) - ); + /// + /// Attaches a custom application Id to an object's application id xdata using the has of the file name. + /// This is used because the persistent id of the db object in the file is almost guaranteed to not be unique between files + /// + /// + /// + /// + public static bool SetObjectCustomApplicationId( + DBObject obj, + string id, + out string applicationId, + string fileNameHash = null + ) + { + applicationId = fileNameHash == null ? id : $"{fileNameHash}-{id}"; + var rb = new ResultBuffer( + new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), + new TypedValue(1000, applicationId) + ); - try - { - if (!obj.IsWriteEnabled) - obj.UpgradeOpen(); - obj.XData = rb; - } - catch (Exception e) + try + { + if (!obj.IsWriteEnabled) { - return false; + obj.UpgradeOpen(); } - return true; + obj.XData = rb; + } + catch (Exception e) + { + return false; } - /// - /// Returns, if found, the corresponding doc element. - /// The doc object can be null if the user deleted it. - /// - /// Id of the application that originally created the element, in AutocadCivil it should be "{fileNameHash}-{handle}" - /// The element, if found, otherwise null - /// - /// Updating can be buggy because of limitations to how object handles are generated. - /// See: https://forums.autodesk.com/t5/net/is-the-quot-objectid-quot-unique-in-a-drawing-file/m-p/6527799#M49953 - /// This is temporarily improved by attaching a custom application id xdata "{fileNameHash}-{handle}" to each object when sending, or checking against the fileNameHash on receive - /// - public static List GetObjectsByApplicationId( - Document doc, - Transaction tr, - string appId, - string fileNameHash - ) + return true; + } + + /// + /// Returns, if found, the corresponding doc element. + /// The doc object can be null if the user deleted it. + /// + /// Id of the application that originally created the element, in AutocadCivil it should be "{fileNameHash}-{handle}" + /// The element, if found, otherwise null + /// + /// Updating can be buggy because of limitations to how object handles are generated. + /// See: https://forums.autodesk.com/t5/net/is-the-quot-objectid-quot-unique-in-a-drawing-file/m-p/6527799#M49953 + /// This is temporarily improved by attaching a custom application id xdata "{fileNameHash}-{handle}" to each object when sending, or checking against the fileNameHash on receive + /// + public static List GetObjectsByApplicationId( + Document doc, + Transaction tr, + string appId, + string fileNameHash + ) + { + var foundObjects = new List(); + if (string.IsNullOrEmpty(appId)) { - var foundObjects = new List(); - if (string.IsNullOrEmpty(appId)) - return foundObjects; - // first check for custom xdata application ids, because object handles tend to be duplicated + return foundObjects; + } + // first check for custom xdata application ids, because object handles tend to be duplicated - // Create a TypedValue array to define the filter criteria - TypedValue[] acTypValAr = new TypedValue[1]; - acTypValAr.SetValue(new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), 0); + // Create a TypedValue array to define the filter criteria + TypedValue[] acTypValAr = new TypedValue[1]; + acTypValAr.SetValue(new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), 0); - // Create a selection filter for the applicationID xdata entry and find all objs with this field - SelectionFilter acSelFtr = new SelectionFilter(acTypValAr); - var editor = Application.DocumentManager.MdiActiveDocument.Editor; - var res = editor.SelectAll(acSelFtr); + // Create a selection filter for the applicationID xdata entry and find all objs with this field + SelectionFilter acSelFtr = new(acTypValAr); + var editor = Application.DocumentManager.MdiActiveDocument.Editor; + var res = editor.SelectAll(acSelFtr); - if (res.Status != PromptStatus.None && res.Status != PromptStatus.Error) + if (res.Status != PromptStatus.None && res.Status != PromptStatus.Error) + { + // loop through all obj with an appId + foreach (var appIdObj in res.Value.GetObjectIds()) { - // loop through all obj with an appId - foreach (var appIdObj in res.Value.GetObjectIds()) + // get the db object from id + var obj = tr.GetObject(appIdObj, OpenMode.ForRead); + if (obj != null) { - // get the db object from id - var obj = tr.GetObject(appIdObj, OpenMode.ForRead); - if (obj != null) + foreach (var entry in obj.XData) { - foreach (var entry in obj.XData) + if (entry.Value as string == appId) { - if (entry.Value as string == appId) - { - foundObjects.Add(appIdObj); - break; - } + foundObjects.Add(appIdObj); + break; } } } } - if (foundObjects.Any()) - return foundObjects; + } + if (foundObjects.Any()) + { + return foundObjects; + } - // if no matching xdata appids were found, loop through handles instead - var autocadAppIdParts = appId.Split('-'); - if (autocadAppIdParts.Count() == 2 && autocadAppIdParts.FirstOrDefault().StartsWith(fileNameHash)) + // if no matching xdata appids were found, loop through handles instead + var autocadAppIdParts = appId.Split('-'); + if (autocadAppIdParts.Count() == 2 && autocadAppIdParts.FirstOrDefault().StartsWith(fileNameHash)) + { + if (Utils.GetHandle(autocadAppIdParts.Last(), out Handle handle)) { - if (Utils.GetHandle(autocadAppIdParts.Last(), out Handle handle)) + if (doc.Database.TryGetObjectId(handle, out ObjectId id)) { - if (doc.Database.TryGetObjectId(handle, out ObjectId id)) - { - return id.IsErased ? foundObjects : new List() { id }; - } + return id.IsErased ? foundObjects : new List() { id }; } } - - return foundObjects; } + + return foundObjects; } - #endregion + } + #endregion - /// - /// Returns a descriptive string for reporting - /// - /// - /// - public static string ObjectDescriptor(DBObject obj) + /// + /// Returns a descriptive string for reporting + /// + /// + /// + public static string ObjectDescriptor(DBObject obj) + { + if (obj == null) { - if (obj == null) - return String.Empty; - var simpleType = obj.GetType().Name; - return $"{simpleType}"; + return String.Empty; } - /// - /// Retrieves the document's units. - /// - /// - /// - public static string GetUnits(Document doc) - { - var insUnits = doc.Database.Insunits; - string units = (insUnits == UnitsValue.Undefined) ? Units.None : Units.GetUnitsFromString(insUnits.ToString()); + var simpleType = obj.GetType().Name; + return $"{simpleType}"; + } + + /// + /// Retrieves the document's units. + /// + /// + /// + public static string GetUnits(Document doc) + { + var insUnits = doc.Database.Insunits; + string units = (insUnits == UnitsValue.Undefined) ? Units.None : Units.GetUnitsFromString(insUnits.ToString()); #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - if (units == Units.None) + if (units == Units.None) + { + // try to get the drawing unit instead + using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) { - // try to get the drawing unit instead - using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) - { - var id = DrawingSetupVariables.GetInstance(doc.Database, false); - var setupVariables = (DrawingSetupVariables)tr.GetObject(id, OpenMode.ForRead); - var linearUnit = setupVariables.LinearUnit; - units = Units.GetUnitsFromString(linearUnit.ToString()); - tr.Commit(); - } + var id = DrawingSetupVariables.GetInstance(doc.Database, false); + var setupVariables = (DrawingSetupVariables)tr.GetObject(id, OpenMode.ForRead); + var linearUnit = setupVariables.LinearUnit; + units = Units.GetUnitsFromString(linearUnit.ToString()); + tr.Commit(); } -#endif - return units; } +#endif + return units; + } - /// - /// Retrieves the handle from an input string - /// - /// - /// - public static bool GetHandle(string str, out Handle handle) + /// + /// Retrieves the handle from an input string + /// + /// + /// + public static bool GetHandle(string str, out Handle handle) + { + handle = new Handle(); + try { - handle = new Handle(); - try - { - handle = new Handle(Convert.ToInt64(str, 16)); - } - catch - { - return false; - } - return true; + handle = new Handle(Convert.ToInt64(str, 16)); } - - /// - /// Gets the closes approximate lineweight from double value in mm - /// - /// - /// - public static LineWeight GetLineWeight(double weight) + catch { - double hundredthMM = weight * 100; - var weights = Enum.GetValues(typeof(LineWeight)).Cast().ToList(); - int closest = weights.Aggregate((x, y) => Math.Abs(x - hundredthMM) < Math.Abs(y - hundredthMM) ? x : y); - return (LineWeight)closest; + return false; } + return true; + } - public static void SetStyle(Base styleBase, Entity entity, Dictionary lineTypeDictionary) + /// + /// Gets the closes approximate lineweight from double value in mm + /// + /// + /// + public static LineWeight GetLineWeight(double weight) + { + double hundredthMM = weight * 100; + var weights = Enum.GetValues(typeof(LineWeight)).Cast().ToList(); + int closest = weights.Aggregate((x, y) => Math.Abs(x - hundredthMM) < Math.Abs(y - hundredthMM) ? x : y); + return (LineWeight)closest; + } + + public static void SetStyle(Base styleBase, Entity entity, Dictionary lineTypeDictionary) + { + var units = styleBase["units"] as string; + var color = styleBase["color"] as int?; + if (color == null) { - var units = styleBase["units"] as string; - var color = styleBase["color"] as int?; - if (color == null) - color = styleBase["diffuse"] as int?; // in case this is from a rendermaterial base - var transparency = styleBase["opacity"] as double?; - var lineType = styleBase["linetype"] as string; - var lineWidth = styleBase["lineweight"] as double?; - - if (color != null) - { - var systemColor = System.Drawing.Color.FromArgb((int)color); - entity.Color = Color.FromRgb(systemColor.R, systemColor.G, systemColor.B); - var alpha = - transparency != null - ? (byte)(transparency * 255d) //render material - : systemColor.A; //display style - entity.Transparency = new Transparency(alpha); - } + color = styleBase["diffuse"] as int?; // in case this is from a rendermaterial base + } - double conversionFactor = - (units != null) ? Units.GetConversionFactor(Units.GetUnitsFromString(units), Units.Millimeters) : 1; - if (lineWidth != null) - entity.LineWeight = GetLineWeight((double)lineWidth * conversionFactor); + var transparency = styleBase["opacity"] as double?; + var lineType = styleBase["linetype"] as string; + var lineWidth = styleBase["lineweight"] as double?; - if (lineType != null) - if (lineTypeDictionary.ContainsKey(lineType)) - entity.LinetypeId = lineTypeDictionary[lineType]; + if (color != null) + { + var systemColor = System.Drawing.Color.FromArgb((int)color); + entity.Color = Color.FromRgb(systemColor.R, systemColor.G, systemColor.B); + var alpha = + transparency != null + ? (byte)(transparency * 255d) //render material + : systemColor.A; //display style + entity.Transparency = new Transparency(alpha); } - /// - /// Removes invalid characters for Autocad layer and block names - /// - /// - /// - public static string RemoveInvalidChars(string str) + double conversionFactor = + (units != null) ? Units.GetConversionFactor(Units.GetUnitsFromString(units), Units.Millimeters) : 1; + if (lineWidth != null) { - // using this to handle rhino nested layer syntax - // replace "::" layer delimiter with "$" (acad standard) - string cleanDelimiter = str.Replace("::", "$"); + entity.LineWeight = GetLineWeight((double)lineWidth * conversionFactor); + } - // remove all other invalid chars - return Regex.Replace(cleanDelimiter, $"[{invalidChars}]", string.Empty); + if (lineType != null) + { + if (lineTypeDictionary.ContainsKey(lineType)) + { + entity.LinetypeId = lineTypeDictionary[lineType]; + } } + } -#if ADVANCESTEEL + /// + /// Removes invalid characters for Autocad layer and block names + /// + /// + /// + public static string RemoveInvalidChars(string str) + { + // using this to handle rhino nested layer syntax + // replace "::" layer delimiter with "$" (acad standard) + string cleanDelimiter = str.Replace("::", "$"); - public static T GetFilerObjectByEntity(DBObject @object) where T : ASFilerObject - { - ASObjectId idCadEntity = new ASObjectId(@object.ObjectId.OldIdPtr); - ASObjectId idFilerObject = Autodesk.AdvanceSteel.CADAccess.DatabaseManager.GetFilerObjectId(idCadEntity, false); - if (idFilerObject.IsNull()) - return null; + // remove all other invalid chars + return Regex.Replace(cleanDelimiter, $"[{invalidChars}]", string.Empty); + } - return Autodesk.AdvanceSteel.CADAccess.DatabaseManager.Open(idFilerObject) as T; - } +#if ADVANCESTEEL - public static bool CheckAdvanceSteelObject(DBObject @object) + public static T GetFilerObjectByEntity(DBObject @object) where T : ASFilerObject + { + ASObjectId idCadEntity = new(@object.ObjectId.OldIdPtr); + ASObjectId idFilerObject = Autodesk.AdvanceSteel.CADAccess.DatabaseManager.GetFilerObjectId(idCadEntity, false); + if (idFilerObject.IsNull()) { - return @object.ObjectId.ObjectClass.DxfName.IndexOf("AST") == 0; + return null; } -#endif + return Autodesk.AdvanceSteel.CADAccess.DatabaseManager.Open(idFilerObject) as T; + } + + public static bool CheckAdvanceSteelObject(DBObject @object) + { + return @object.ObjectId.ObjectClass.DxfName.IndexOf("AST") == 0; } + +#endif } diff --git a/ConnectorBentley/ConnectorBentleyShared/Entry/App.cs b/ConnectorBentley/ConnectorBentleyShared/Entry/App.cs index 3e8ff98704..2c54967095 100644 --- a/ConnectorBentley/ConnectorBentleyShared/Entry/App.cs +++ b/ConnectorBentley/ConnectorBentleyShared/Entry/App.cs @@ -1,4 +1,4 @@ -using Bentley.DgnPlatformNET; +using Bentley.DgnPlatformNET; using Bentley.DgnPlatformNET.Elements; using Bentley.GeometryNET; using Bentley.MstnPlatformNET; @@ -13,52 +13,51 @@ using System.Threading.Tasks; using System.Windows; -namespace Speckle.ConnectorBentley.Entry +namespace Speckle.ConnectorBentley.Entry; + +[AddIn(MdlTaskID = "Speckle")] +public class SpeckleBentleyApp : AddIn { - [AddIn(MdlTaskID = "Speckle")] - public class SpeckleBentleyApp : AddIn - { - public static SpeckleBentleyApp App; + public static SpeckleBentleyApp App; - public SpeckleBentleyApp(IntPtr mdlDesc) : base(mdlDesc) - { - } + public SpeckleBentleyApp(IntPtr mdlDesc) + : base(mdlDesc) { } - protected override int Run(string[] commandLine) - { - App = this; - return 0; - } - - internal static SpeckleBentleyApp Instance - { - get { return App; } - } + protected override int Run(string[] commandLine) + { + App = this; + return 0; + } - // for DUI2 - public void Start(string unparsed) - { - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); + internal static SpeckleBentleyApp Instance + { + get { return App; } + } - SpeckleBentleyCommand.InitAvalonia(); - SpeckleBentleyCommand.Bindings = new ConnectorBindingsBentley(); - SpeckleBentleyCommand.CreateOrFocusSpeckle(); - } + // for DUI2 + public void Start(string unparsed) + { + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); - // This is necessary for finding assemblies when building Avalonia - static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) - { - Assembly a = null; - var name = args.Name.Split(',')[0]; - string path = Path.GetDirectoryName(typeof(App).Assembly.Location); + SpeckleBentleyCommand.InitAvalonia(); + SpeckleBentleyCommand.Bindings = new ConnectorBindingsBentley(); + SpeckleBentleyCommand.CreateOrFocusSpeckle(); + } - string assemblyFile = Path.Combine(path, name + ".dll"); + // This is necessary for finding assemblies when building Avalonia + static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly a = null; + var name = args.Name.Split(',')[0]; + string path = Path.GetDirectoryName(typeof(App).Assembly.Location); - if (File.Exists(assemblyFile)) - a = Assembly.LoadFrom(assemblyFile); + string assemblyFile = Path.Combine(path, name + ".dll"); - return a; + if (File.Exists(assemblyFile)) + { + a = Assembly.LoadFrom(assemblyFile); } - } -} \ No newline at end of file + return a; + } +} diff --git a/ConnectorBentley/ConnectorBentleyShared/Entry/SpeckleBentleyCommand.cs b/ConnectorBentley/ConnectorBentleyShared/Entry/SpeckleBentleyCommand.cs index 1970f5dcb4..6488c2ee17 100644 --- a/ConnectorBentley/ConnectorBentleyShared/Entry/SpeckleBentleyCommand.cs +++ b/ConnectorBentley/ConnectorBentleyShared/Entry/SpeckleBentleyCommand.cs @@ -1,4 +1,4 @@ -using Avalonia; +using Avalonia; using Avalonia.Controls; using Avalonia.ReactiveUI; using Bentley.DgnPlatformNET; @@ -14,52 +14,46 @@ using System.Reflection; using System.Threading.Tasks; -namespace Speckle.ConnectorBentley.Entry +namespace Speckle.ConnectorBentley.Entry; + +public class SpeckleBentleyCommand { - public class SpeckleBentleyCommand - { - public static Window MainWindow { get; private set; } - public static ConnectorBindingsBentley Bindings { get; set; } - private static Avalonia.Application AvaloniaApp { get; set; } + public static Window MainWindow { get; private set; } + public static ConnectorBindingsBentley Bindings { get; set; } + private static Avalonia.Application AvaloniaApp { get; set; } - public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() .UsePlatformDetect() .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) .LogToTrace() .UseReactiveUI(); - public static void InitAvalonia() - { - try - { - BuildAvaloniaApp().Start(AppMain, null); - } - catch (Exception e) - { - - } - } - - public static void CreateOrFocusSpeckle() + public static void InitAvalonia() + { + try { - if (MainWindow == null) - { - var viewModel = new MainViewModel(Bindings); - MainWindow = new MainWindow - { - DataContext = viewModel - }; - Task.Run(() => AvaloniaApp.Run(MainWindow)); - } - MainWindow.Show(); - MainWindow.Activate(); + BuildAvaloniaApp().Start(AppMain, null); } + catch (Exception e) { } + } - private static void AppMain(Avalonia.Application app, string[] args) + public static void CreateOrFocusSpeckle() + { + if (MainWindow == null) { - AvaloniaApp = app; + var viewModel = new MainViewModel(Bindings); + MainWindow = new MainWindow { DataContext = viewModel }; + Task.Run(() => AvaloniaApp.Run(MainWindow)); } + MainWindow.Show(); + MainWindow.Activate(); + } + private static void AppMain(Avalonia.Application app, string[] args) + { + AvaloniaApp = app; } } diff --git a/ConnectorBentley/ConnectorBentleyShared/Keyins.cs b/ConnectorBentley/ConnectorBentleyShared/Keyins.cs index d0e1aaeb4c..e0759dcf98 100644 --- a/ConnectorBentley/ConnectorBentleyShared/Keyins.cs +++ b/ConnectorBentley/ConnectorBentleyShared/Keyins.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -7,13 +7,12 @@ using Speckle.ConnectorBentley.Entry; -namespace Speckle.ConnectorBentley +namespace Speckle.ConnectorBentley; + +public class Keyins { - public class Keyins + public static void Start(string unparsed) { - public static void Start(string unparsed) - { - SpeckleBentleyApp.Instance.Start(unparsed); - } + SpeckleBentleyApp.Instance.Start(unparsed); } } diff --git a/ConnectorBentley/ConnectorBentleyShared/Storage/StreamStateManager.cs b/ConnectorBentley/ConnectorBentleyShared/Storage/StreamStateManager.cs index 6e53fcd9a3..5dfcd32ea6 100644 --- a/ConnectorBentley/ConnectorBentleyShared/Storage/StreamStateManager.cs +++ b/ConnectorBentley/ConnectorBentleyShared/Storage/StreamStateManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -14,120 +14,124 @@ using Speckle.Newtonsoft.Json; using DesktopUI2.Models; -namespace Speckle.ConnectorBentley.Storage +namespace Speckle.ConnectorBentley.Storage; + +public static class StreamStateManager { - public static class StreamStateManager + static readonly string schemaName = "StreamStateWrapper"; + static readonly string className = "StreamState"; + static readonly string propertyName = "StreamData"; + + /// + /// Returns all the speckle stream states present in the file. + /// + /// + /// + public static List ReadState(DgnFile file) { - static readonly string schemaName = "StreamStateWrapper"; - static readonly string className = "StreamState"; - static readonly string propertyName = "StreamData"; - - /// - /// Returns all the speckle stream states present in the file. - /// - /// - /// - public static List ReadState(DgnFile file) + var states = new List(); + try { - var states = new List(); - try + FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption(DgnECHostType.All)); + var schema = (ECSchema)DgnECManager.Manager.LocateSchemaInScope(scope, schemaName, 1, 0, SchemaMatchType.Latest); + + if (schema == null) { - FindInstancesScope scope = FindInstancesScope.CreateScope(file, new FindInstancesScopeOption(DgnECHostType.All)); - var schema = (ECSchema)DgnECManager.Manager.LocateSchemaInScope(scope, schemaName, 1, 0, SchemaMatchType.Latest); + return states; + } - if (schema == null) - return states; + ECQuery readWidget = new(schema.GetClass(className)); + readWidget.SelectClause.SelectAllProperties = true; - ECQuery readWidget = new ECQuery(schema.GetClass(className)); - readWidget.SelectClause.SelectAllProperties = true; - - using (DgnECInstanceCollection ecInstances = DgnECManager.Manager.FindInstances(scope, readWidget)) + using (DgnECInstanceCollection ecInstances = DgnECManager.Manager.FindInstances(scope, readWidget)) + { + var streamStatesInstance = ecInstances.First(); + if (streamStatesInstance != null) { - var streamStatesInstance = ecInstances.First(); - if (streamStatesInstance != null) - { - var str = streamStatesInstance[propertyName].StringValue; - states = JsonConvert.DeserializeObject>(str); - } + var str = streamStatesInstance[propertyName].StringValue; + states = JsonConvert.DeserializeObject>(str); } - - return states; - } - catch (Exception e) - { - return new List(); } - } - /// - /// Writes the stream states to the current schema. - /// - /// - public static void WriteStreamStateList(DgnFile File, List streamStates) + return states; + } + catch (Exception e) { - DgnECManager Manager = DgnECManager.Manager; - FindInstancesScope scope = FindInstancesScope.CreateScope(File, new FindInstancesScopeOption(DgnECHostType.All)); + return new List(); + } + } - IECSchema schema = RetrieveSchema(File, scope); - IECClass ecClass = schema.GetClass(className); + /// + /// Writes the stream states to the current schema. + /// + /// + public static void WriteStreamStateList(DgnFile File, List streamStates) + { + DgnECManager Manager = DgnECManager.Manager; + FindInstancesScope scope = FindInstancesScope.CreateScope(File, new FindInstancesScopeOption(DgnECHostType.All)); - ECQuery readWidget = new ECQuery(ecClass); - readWidget.SelectClause.SelectAllProperties = true; + IECSchema schema = RetrieveSchema(File, scope); + IECClass ecClass = schema.GetClass(className); + + ECQuery readWidget = new(ecClass); + readWidget.SelectClause.SelectAllProperties = true; - using (DgnECInstanceCollection instances = Manager.FindInstances(scope, readWidget)) + using (DgnECInstanceCollection instances = Manager.FindInstances(scope, readWidget)) + { + foreach (IDgnECInstance instance in instances) { - foreach (IDgnECInstance instance in instances) - instance.Delete(); + instance.Delete(); } - - DgnECInstanceEnabler instanceEnabler = Manager.ObtainInstanceEnabler(File, ecClass); - - var data = JsonConvert.SerializeObject(streamStates) as string; - StandaloneECDInstance _instance = instanceEnabler.SharedWipInstance; - _instance.SetAsString(propertyName, data); - instanceEnabler.CreateInstanceOnFile(File, _instance); } - private static ECSchema CreateSchema(DgnFile File) - { - ECSchema newSchema = new ECSchema(schemaName, 1, 0, schemaName); - ECClass streamStateClass = new ECClass(className); - ECProperty streamDataProp = new ECProperty(propertyName, ECObjects.StringType); - streamStateClass.Add(streamDataProp); - newSchema.AddClass(streamStateClass); + DgnECInstanceEnabler instanceEnabler = Manager.ObtainInstanceEnabler(File, ecClass); - var status = DgnECManager.Manager.ImportSchema(newSchema, File, new ImportSchemaOptions()); + var data = JsonConvert.SerializeObject(streamStates) as string; + StandaloneECDInstance _instance = instanceEnabler.SharedWipInstance; + _instance.SetAsString(propertyName, data); + instanceEnabler.CreateInstanceOnFile(File, _instance); + } - if (status != SchemaImportStatus.Success) - return null; + private static ECSchema CreateSchema(DgnFile File) + { + ECSchema newSchema = new(schemaName, 1, 0, schemaName); + ECClass streamStateClass = new(className); + ECProperty streamDataProp = new(propertyName, ECObjects.StringType); + streamStateClass.Add(streamDataProp); + newSchema.AddClass(streamStateClass); - return newSchema; - } + var status = DgnECManager.Manager.ImportSchema(newSchema, File, new ImportSchemaOptions()); - private static ECSchema RetrieveSchema(DgnFile File, FindInstancesScope scope) + if (status != SchemaImportStatus.Success) { - DgnECManager Manager = DgnECManager.Manager; - DgnModel model = Session.Instance.GetActiveDgnModel(); - var schemas = (List)Manager.DiscoverSchemasForModel(model, ReferencedModelScopeOption.All, false); - var schemaString = schemas.Where(x => x.Contains(schemaName)).FirstOrDefault(); + return null; + } - if (schemaString != null) + return newSchema; + } + + private static ECSchema RetrieveSchema(DgnFile File, FindInstancesScope scope) + { + DgnECManager Manager = DgnECManager.Manager; + DgnModel model = Session.Instance.GetActiveDgnModel(); + var schemas = (List)Manager.DiscoverSchemasForModel(model, ReferencedModelScopeOption.All, false); + var schemaString = schemas.Where(x => x.Contains(schemaName)).FirstOrDefault(); + + if (schemaString != null) + { + try { - try - { - IECSchema schema = Manager.LocateSchemaInScope(scope, schemaName, 1, 0, SchemaMatchType.Latest); - return (ECSchema)schema; - } - catch (Exception e) - { - return null; - } + IECSchema schema = Manager.LocateSchemaInScope(scope, schemaName, 1, 0, SchemaMatchType.Latest); + return (ECSchema)schema; } - - else + catch (Exception e) { - return CreateSchema(File); + return null; } } + else + { + return CreateSchema(File); + } } } diff --git a/ConnectorBentley/ConnectorBentleyShared/UI/Bindings.cs b/ConnectorBentley/ConnectorBentleyShared/UI/Bindings.cs index c3e97e1aa0..43a1dcd9c1 100644 --- a/ConnectorBentley/ConnectorBentleyShared/UI/Bindings.cs +++ b/ConnectorBentley/ConnectorBentleyShared/UI/Bindings.cs @@ -32,852 +32,941 @@ using Bentley.CifNET.SDK; #endif -namespace Speckle.ConnectorBentley.UI +namespace Speckle.ConnectorBentley.UI; + +public partial class ConnectorBindingsBentley : ConnectorBindings { - public partial class ConnectorBindingsBentley : ConnectorBindings - { - public DgnFile File => Session.Instance.GetActiveDgnFile(); - public DgnModel Model => Session.Instance.GetActiveDgnModel(); - public string ModelUnits { get; set; } - public List DocumentStreams { get; set; } = new List(); + public DgnFile File => Session.Instance.GetActiveDgnFile(); + public DgnModel Model => Session.Instance.GetActiveDgnModel(); + public string ModelUnits { get; set; } + public List DocumentStreams { get; set; } = new List(); #if (OPENROADS || OPENRAIL) - public GeometricModel GeomModel { get; private set; } - public List civilElementKeys => new List { "Alignment" }; + public GeometricModel GeomModel { get; private set; } + public List civilElementKeys => new() { "Alignment" }; #endif #if (OPENBUILDINGS) - public bool ExportGridLines { get; set; } = true; + public bool ExportGridLines { get; set; } = true; #else - public bool ExportGridLines = false; + public bool ExportGridLines = false; #endif - // Like the AutoCAD API, the Bentley APIs should only be called on the main thread. - // As in the AutoCAD/Civil3D connectors, we therefore creating a control in the ConnectorBindings constructor (since it's called on main thread) that allows for invoking worker threads on the main thread - thank you Claire!! - public System.Windows.Forms.Control Control; - delegate void SetContextDelegate(object session); - delegate List GetObjectsFromFilterDelegate( - ISelectionFilter filter, - ISpeckleConverter converter, - ProgressViewModel progress - ); - delegate Base SpeckleConversionDelegate(object commitObject); - - public ConnectorBindingsBentley() - : base() - { - Control = new System.Windows.Forms.Control(); - Control.CreateControl(); + // Like the AutoCAD API, the Bentley APIs should only be called on the main thread. + // As in the AutoCAD/Civil3D connectors, we therefore creating a control in the ConnectorBindings constructor (since it's called on main thread) that allows for invoking worker threads on the main thread - thank you Claire!! + public System.Windows.Forms.Control Control; + delegate void SetContextDelegate(object session); + delegate List GetObjectsFromFilterDelegate( + ISelectionFilter filter, + ISpeckleConverter converter, + ProgressViewModel progress + ); + delegate Base SpeckleConversionDelegate(object commitObject); + + public ConnectorBindingsBentley() + : base() + { + Control = new System.Windows.Forms.Control(); + Control.CreateControl(); - ModelUnits = Model.GetModelInfo().GetMasterUnit().GetName(true, true); + ModelUnits = Model.GetModelInfo().GetMasterUnit().GetName(true, true); #if (OPENROADS || OPENRAIL) - ConsensusConnection sdkCon = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive(); - GeomModel = sdkCon.GetActiveGeometricModel(); + ConsensusConnection sdkCon = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive(); + GeomModel = sdkCon.GetActiveGeometricModel(); #endif + } + + #region local streams + public override void WriteStreamsToFile(List streams) + { + StreamStateManager.WriteStreamStateList(File, streams); + } + + public override List GetStreamsInFile() + { + var streams = new List(); + if (File != null) + { + streams = StreamStateManager.ReadState(File); } - #region local streams - public override void WriteStreamsToFile(List streams) + return streams; + } + #endregion + + #region boilerplate + public override string GetHostAppNameVersion() => Utils.VersionedAppName; + + public override string GetHostAppName() => Utils.Slug; + + public override string GetDocumentId() + { + string path = GetDocumentLocation(); + return Core.Models.Utilities.HashString( + path + File.GetFileName(), + Speckle.Core.Models.Utilities.HashingFunctions.MD5 + ); + } + + public override string GetDocumentLocation() => Path.GetDirectoryName(File.GetFileName()); + + public override string GetFileName() => Path.GetFileName(File.GetFileName()); + + public override string GetActiveViewName() => "Entire Document"; + + public override List GetObjectsInView() + { + if (Model == null) { - StreamStateManager.WriteStreamStateList(File, streams); + return new List(); } - public override List GetStreamsInFile() + var graphicElements = Model.GetGraphicElements(); + + var objs = new List(); + using (var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator()) { - var streams = new List(); - if (File != null) - streams = StreamStateManager.ReadState(File); - return streams; + objs = graphicElements.Where(el => !el.IsInvisible).Select(el => el.ElementId.ToString()).ToList(); // Note: this returns all graphic objects in the model. } - #endregion - #region boilerplate - public override string GetHostAppNameVersion() => Utils.VersionedAppName; + return objs; + } - public override string GetHostAppName() => Utils.Slug; + public override List GetSelectedObjects() + { + var objs = new List(); - public override string GetDocumentId() + if (Model == null) { - string path = GetDocumentLocation(); - return Core.Models.Utilities.HashString( - path + File.GetFileName(), - Speckle.Core.Models.Utilities.HashingFunctions.MD5 - ); + return objs; } - public override string GetDocumentLocation() => Path.GetDirectoryName(File.GetFileName()); + uint numSelected = SelectionSetManager.NumSelected(); + DgnModelRef modelRef = Session.Instance.GetActiveDgnModelRef(); - public override string GetFileName() => Path.GetFileName(File.GetFileName()); + for (uint i = 0; i < numSelected; i++) + { + Bentley.DgnPlatformNET.Elements.Element el = null; + SelectionSetManager.GetElement(i, ref el, ref modelRef); + objs.Add(el.ElementId.ToString()); + } - public override string GetActiveViewName() => "Entire Document"; + return objs; + } - public override List GetObjectsInView() + public override List GetSelectionFilters() + { + //Element Type, Element Class, Element Template, Material, Level, Color, Line Style, Line Weight + var levels = new List(); + FileLevelCache levelCache = Model.GetFileLevelCache(); + foreach (var level in levelCache.GetHandles()) { - if (Model == null) - return new List(); + levels.Add(level.Name); + } - var graphicElements = Model.GetGraphicElements(); + levels.Sort(); - var objs = new List(); - using (var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator()) + var elementTypes = new List + { + "Arc", + "Ellipse", + "Line", + "Spline", + "Line String", + "Complex Chain", + "Shape", + "Complex Shape", + "Mesh" + }; + + var filterList = new List(); + filterList.Add( + new AllSelectionFilter + { + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Selects all document objects." + } + ); + filterList.Add( + new ListSelectionFilter { - objs = graphicElements.Where(el => !el.IsInvisible).Select(el => el.ElementId.ToString()).ToList(); // Note: this returns all graphic objects in the model. + Slug = "level", + Name = "Levels", + Icon = "LayersTriple", + Description = "Selects objects based on their level.", + Values = levels } + ); + filterList.Add( + new ListSelectionFilter + { + Slug = "elementType", + Name = "Element Types", + Icon = "Category", + Description = "Selects objects based on their element type.", + Values = elementTypes + } + ); - return objs; - } +#if (OPENROADS || OPENRAIL) + var civilElementTypes = new List { "Alignment" }; + filterList.Add(new ListSelectionFilter { Slug = "civilElementType", Name = "Civil Features", Icon = "RailroadVariant", Description = "Selects civil features based on their type.", Values = civilElementTypes }); +#endif - public override List GetSelectedObjects() - { - var objs = new List(); + return filterList; + } - if (Model == null) - { - return objs; - } + public override List GetReceiveModes() + { + return new List { ReceiveMode.Create }; + } - uint numSelected = SelectionSetManager.NumSelected(); - DgnModelRef modelRef = Session.Instance.GetActiveDgnModelRef(); + public override List GetSettings() + { + return new List(); + } - for (uint i = 0; i < numSelected; i++) - { - Bentley.DgnPlatformNET.Elements.Element el = null; - SelectionSetManager.GetElement(i, ref el, ref modelRef); - objs.Add(el.ElementId.ToString()); - } + //TODO + public override List GetCustomStreamMenuItems() + { + return new List(); + } - return objs; - } + public override void SelectClientObjects(List args, bool deselect = false) + { + // TODO! + } + #endregion - public override List GetSelectionFilters() - { - //Element Type, Element Class, Element Template, Material, Level, Color, Line Style, Line Weight - var levels = new List(); - FileLevelCache levelCache = Model.GetFileLevelCache(); - foreach (var level in levelCache.GetHandles()) - levels.Add(level.Name); - levels.Sort(); + #region receiving + public override bool CanPreviewReceive => false; - var elementTypes = new List - { - "Arc", - "Ellipse", - "Line", - "Spline", - "Line String", - "Complex Chain", - "Shape", - "Complex Shape", - "Mesh" - }; - - var filterList = new List(); - filterList.Add( - new AllSelectionFilter - { - Slug = "all", - Name = "Everything", - Icon = "CubeScan", - Description = "Selects all document objects." - } - ); - filterList.Add( - new ListSelectionFilter - { - Slug = "level", - Name = "Levels", - Icon = "LayersTriple", - Description = "Selects objects based on their level.", - Values = levels - } - ); - filterList.Add( - new ListSelectionFilter - { - Slug = "elementType", - Name = "Element Types", - Icon = "Category", - Description = "Selects objects based on their element type.", - Values = elementTypes - } - ); + public override Task PreviewReceive(StreamState state, ProgressViewModel progress) + { + return null; + } -#if (OPENROADS || OPENRAIL) - var civilElementTypes = new List { "Alignment" }; - filterList.Add(new ListSelectionFilter { Slug = "civilElementType", Name = "Civil Features", Icon = "RailroadVariant", Description = "Selects civil features based on their type.", Values = civilElementTypes }); -#endif + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + { + var kit = KitManager.GetDefaultKit(); + var converter = kit.LoadConverter(Utils.VersionedAppName); + var previouslyReceivedObjects = state.ReceivedObjects; - return filterList; + if (Control.InvokeRequired) + { + Control.Invoke(new SetContextDelegate(converter.SetContextDocument), new object[] { Session.Instance }); } - - public override List GetReceiveModes() + else { - return new List { ReceiveMode.Create }; + converter.SetContextDocument(Session.Instance); } - public override List GetSettings() + progress.CancellationToken.ThrowIfCancellationRequested(); + + /* + if (Doc == null) { - return new List(); + throw new OperationInvalidException($"No Document is open.")); } - - //TODO - public override List GetCustomStreamMenuItems() + */ + + //if "latest", always make sure we get the latest commit when the user clicks "receive" + Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + state.LastCommit = commit; + Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); + await ConnectorHelpers.TryCommitReceived(state, commit, Utils.VersionedAppName, progress.CancellationToken); + + // invoke conversions on the main thread via control + int count = 0; + var flattenedObjects = FlattenCommitObject(commitObject, converter, ref count); + List newPlaceholderObjects; + if (Control.InvokeRequired) { - return new List(); + newPlaceholderObjects = + (List) + Control.Invoke( + new NativeConversionAndBakeDelegate(ConvertAndBakeReceivedObjects), + new object[] { flattenedObjects, converter, state, progress } + ); } - - public override void SelectClientObjects(List args, bool deselect = false) + else { - // TODO! + newPlaceholderObjects = ConvertAndBakeReceivedObjects(flattenedObjects, converter, state, progress); } - #endregion - #region receiving - public override bool CanPreviewReceive => false; + DeleteObjects(previouslyReceivedObjects, newPlaceholderObjects); + + state.ReceivedObjects = newPlaceholderObjects; - public override Task PreviewReceive(StreamState state, ProgressViewModel progress) + progress.Report.Merge(converter.Report); + + if (progress.Report.OperationErrorsCount != 0) { - return null; + return null; // the commit is being rolled back } - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + try + { + //await state.RefreshStream(); + WriteStateToFile(); + } + catch (Exception e) { - var kit = KitManager.GetDefaultKit(); - var converter = kit.LoadConverter(Utils.VersionedAppName); - var previouslyReceivedObjects = state.ReceivedObjects; + progress.Report.OperationErrors.Add(e); + } - if (Control.InvokeRequired) - Control.Invoke(new SetContextDelegate(converter.SetContextDocument), new object[] { Session.Instance }); - else - converter.SetContextDocument(Session.Instance); + return state; + } + delegate List NativeConversionAndBakeDelegate( + List objects, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress + ); + + private List ConvertAndBakeReceivedObjects( + List objects, + ISpeckleConverter converter, + StreamState state, + ProgressViewModel progress + ) + { + var placeholders = new List(); + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 0; + progress.Max = state.SelectedObjectIds.Count(); + Action updateProgressAction = () => + { + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); + }; + + foreach (var @base in objects) + { progress.CancellationToken.ThrowIfCancellationRequested(); - /* - if (Doc == null) + try { - throw new OperationInvalidException($"No Document is open.")); - } - */ + var convRes = converter.ConvertToNative(@base); - //if "latest", always make sure we get the latest commit when the user clicks "receive" - Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - state.LastCommit = commit; - Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); - await ConnectorHelpers.TryCommitReceived(state, commit, Utils.VersionedAppName, progress.CancellationToken); + if (convRes is ApplicationObject placeholder) + { + placeholders.Add(placeholder); + } + else if (convRes is List placeholderList) + { + placeholders.AddRange(placeholderList); + } - // invoke conversions on the main thread via control - int count = 0; - var flattenedObjects = FlattenCommitObject(commitObject, converter, ref count); - List newPlaceholderObjects; - if (Control.InvokeRequired) - newPlaceholderObjects = - (List) - Control.Invoke( - new NativeConversionAndBakeDelegate(ConvertAndBakeReceivedObjects), - new object[] { flattenedObjects, converter, state, progress } + // creating new elements, not updating existing! + var convertedElement = convRes as Element; + if (convertedElement != null) + { + var status = convertedElement.AddToModel(); + if (status == StatusInt.Error) + { + converter.Report.LogConversionError( + new Exception($"Failed to bake object {@base.id} of type {@base.speckle_type}.") ); - else - newPlaceholderObjects = ConvertAndBakeReceivedObjects(flattenedObjects, converter, state, progress); - - DeleteObjects(previouslyReceivedObjects, newPlaceholderObjects); - - state.ReceivedObjects = newPlaceholderObjects; - - progress.Report.Merge(converter.Report); - - if (progress.Report.OperationErrorsCount != 0) - return null; // the commit is being rolled back - - try - { - //await state.RefreshStream(); - WriteStateToFile(); + } + } + else + { + converter.Report.LogConversionError( + new Exception($"Failed to convert object {@base.id} of type {@base.speckle_type}.") + ); + } } catch (Exception e) { - progress.Report.OperationErrors.Add(e); + converter.Report.LogConversionError(e); } - - return state; } - delegate List NativeConversionAndBakeDelegate( - List objects, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress - ); + return placeholders; + } - private List ConvertAndBakeReceivedObjects( - List objects, - ISpeckleConverter converter, - StreamState state, - ProgressViewModel progress - ) - { - var placeholders = new List(); - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 0; - progress.Max = state.SelectedObjectIds.Count(); - Action updateProgressAction = () => - { - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); - }; + /// + /// Recurses through the commit object and flattens it + /// + /// + /// + /// + /// + /// + private List FlattenCommitObject( + object obj, + ISpeckleConverter converter, + ref int count, + bool foundConvertibleMember = false + ) + { + List objects = new(); - foreach (var @base in objects) + if (obj is Base @base) + { + if (converter.CanConvertToNative(@base)) + { + objects.Add(@base); + return objects; + } + else { - progress.CancellationToken.ThrowIfCancellationRequested(); + List props = @base.GetDynamicMembers().ToList(); + if (@base.GetMembers().ContainsKey("displayValue")) + { + props.Add("displayValue"); + } - try + if (@base.GetMembers().ContainsKey("elements")) // this is for builtelements like roofs, walls, and floors. { - var convRes = converter.ConvertToNative(@base); + props.Add("elements"); + } - if (convRes is ApplicationObject placeholder) - placeholders.Add(placeholder); - else if (convRes is List placeholderList) - placeholders.AddRange(placeholderList); + int totalMembers = props.Count; - // creating new elements, not updating existing! - var convertedElement = convRes as Element; - if (convertedElement != null) - { - var status = convertedElement.AddToModel(); - if (status == StatusInt.Error) - converter.Report.LogConversionError( - new Exception($"Failed to bake object {@base.id} of type {@base.speckle_type}.") - ); - } - else + foreach (var prop in props) + { + count++; + + var nestedObjects = FlattenCommitObject(@base[prop], converter, ref count, foundConvertibleMember); + if (nestedObjects.Count > 0) { - converter.Report.LogConversionError( - new Exception($"Failed to convert object {@base.id} of type {@base.speckle_type}.") - ); + objects.AddRange(nestedObjects); + foundConvertibleMember = true; } } - catch (Exception e) + + if (!foundConvertibleMember && count == totalMembers) // this was an unsupported geo { - converter.Report.LogConversionError(e); + converter.Report.Log($"Skipped not supported type: {@base.speckle_type}. Object {@base.id} not baked."); } - } - return placeholders; + return objects; + } } - /// - /// Recurses through the commit object and flattens it - /// - /// - /// - /// - /// - /// - private List FlattenCommitObject( - object obj, - ISpeckleConverter converter, - ref int count, - bool foundConvertibleMember = false - ) + if (obj is IReadOnlyList list) { - List objects = new List(); - - if (obj is Base @base) + count = 0; + foreach (var listObj in list) { - if (converter.CanConvertToNative(@base)) - { - objects.Add(@base); - return objects; - } - else - { - List props = @base.GetDynamicMembers().ToList(); - if (@base.GetMembers().ContainsKey("displayValue")) - props.Add("displayValue"); - if (@base.GetMembers().ContainsKey("elements")) // this is for builtelements like roofs, walls, and floors. - props.Add("elements"); - int totalMembers = props.Count; - - foreach (var prop in props) - { - count++; - - var nestedObjects = FlattenCommitObject(@base[prop], converter, ref count, foundConvertibleMember); - if (nestedObjects.Count > 0) - { - objects.AddRange(nestedObjects); - foundConvertibleMember = true; - } - } - - if (!foundConvertibleMember && count == totalMembers) // this was an unsupported geo - converter.Report.Log($"Skipped not supported type: {@base.speckle_type}. Object {@base.id} not baked."); - - return objects; - } + objects.AddRange(FlattenCommitObject(listObj, converter, ref count)); } - if (obj is IReadOnlyList list) - { - count = 0; - foreach (var listObj in list) - objects.AddRange(FlattenCommitObject(listObj, converter, ref count)); - return objects; - } + return objects; + } - if (obj is IDictionary dict) + if (obj is IDictionary dict) + { + count = 0; + foreach (DictionaryEntry kvp in dict) { - count = 0; - foreach (DictionaryEntry kvp in dict) - objects.AddRange(FlattenCommitObject(kvp.Value, converter, ref count)); - return objects; + objects.AddRange(FlattenCommitObject(kvp.Value, converter, ref count)); } return objects; } - //delete previously sent object that are no longer in this stream - private void DeleteObjects( - List previouslyReceiveObjects, - List newPlaceholderObjects - ) + return objects; + } + + //delete previously sent object that are no longer in this stream + private void DeleteObjects( + List previouslyReceiveObjects, + List newPlaceholderObjects + ) + { + foreach (var obj in previouslyReceiveObjects) { - foreach (var obj in previouslyReceiveObjects) + if (newPlaceholderObjects.Any(x => x.applicationId == obj.applicationId)) { - if (newPlaceholderObjects.Any(x => x.applicationId == obj.applicationId)) - continue; + continue; + } - // get the model object from id - ulong id = Convert.ToUInt64(obj.CreatedIds.FirstOrDefault()); - var element = Model.FindElementById((ElementId)id); - if (element != null) - element.DeleteFromModel(); + // get the model object from id + ulong id = Convert.ToUInt64(obj.CreatedIds.FirstOrDefault()); + var element = Model.FindElementById((ElementId)id); + if (element != null) + { + element.DeleteFromModel(); } } - #endregion + } + #endregion + + #region sending + public override bool CanPreviewSend => false; - #region sending - public override bool CanPreviewSend => false; + public override void PreviewSend(StreamState state, ProgressViewModel progress) + { + return; + } - public override void PreviewSend(StreamState state, ProgressViewModel progress) + public override async Task SendStream(StreamState state, ProgressViewModel progress) + { + var kit = KitManager.GetDefaultKit(); + var converter = kit.LoadConverter(Utils.VersionedAppName); + var streamId = state.StreamId; + var client = state.Client; + + if (Control.InvokeRequired) { - return; + Control.Invoke(new SetContextDelegate(converter.SetContextDocument), new object[] { Session.Instance }); } - - public override async Task SendStream(StreamState state, ProgressViewModel progress) + else { - var kit = KitManager.GetDefaultKit(); - var converter = kit.LoadConverter(Utils.VersionedAppName); - var streamId = state.StreamId; - var client = state.Client; - - if (Control.InvokeRequired) - Control.Invoke(new SetContextDelegate(converter.SetContextDocument), new object[] { Session.Instance }); - else - converter.SetContextDocument(Session.Instance); + converter.SetContextDocument(Session.Instance); + } - var selectedObjects = new List(); + var selectedObjects = new List(); - if (state.Filter != null) + if (state.Filter != null) + { + if (Control.InvokeRequired) { - if (Control.InvokeRequired) - state.SelectedObjectIds = - (List) - Control.Invoke( - new GetObjectsFromFilterDelegate(GetObjectsFromFilter), - new object[] { state.Filter, converter, progress } - ); - else - state.SelectedObjectIds = GetObjectsFromFilter(state.Filter, converter, progress); + state.SelectedObjectIds = + (List) + Control.Invoke( + new GetObjectsFromFilterDelegate(GetObjectsFromFilter), + new object[] { state.Filter, converter, progress } + ); } - - if (state.SelectedObjectIds.Count == 0 && !ExportGridLines) + else { - throw new InvalidOperationException( - "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." - ); + state.SelectedObjectIds = GetObjectsFromFilter(state.Filter, converter, progress); } + } - var commitObj = new Base(); + if (state.SelectedObjectIds.Count == 0 && !ExportGridLines) + { + throw new InvalidOperationException( + "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." + ); + } - var units = Units.GetUnitsFromString(ModelUnits).ToLower(); - commitObj["units"] = units; + var commitObj = new Base(); - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 0; - progress.Max = state.SelectedObjectIds.Count(); - int convertedCount = 0; + var units = Units.GetUnitsFromString(ModelUnits).ToLower(); + commitObj["units"] = units; - // grab elements from active model - var objs = new List(); + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 0; + progress.Max = state.SelectedObjectIds.Count(); + int convertedCount = 0; + + // grab elements from active model + var objs = new List(); #if (OPENROADS || OPENRAIL) - bool convertCivilObject = false; - var civObjs = new List(); + bool convertCivilObject = false; + var civObjs = new List(); - if (civilElementKeys.Count(x => state.SelectedObjectIds.Contains(x)) > 0) + if (civilElementKeys.Count(x => state.SelectedObjectIds.Contains(x)) > 0) + { + if (Control.InvokeRequired) { - if (Control.InvokeRequired) - civObjs = (List)Control.Invoke(new GetCivilObjectsDelegate(GetCivilObjects), new object[] { state }); - else - civObjs = GetCivilObjects(state); - - objs = civObjs.Select(x => x.Element).ToList(); - convertCivilObject = true; + civObjs = (List)Control.Invoke(new GetCivilObjectsDelegate(GetCivilObjects), new object[] { state }); } else { - objs = state.SelectedObjectIds.Select(x => Model.FindElementById((ElementId)Convert.ToUInt64(x))).ToList(); + civObjs = GetCivilObjects(state); } -#else + + objs = civObjs.Select(x => x.Element).ToList(); + convertCivilObject = true; + } + else + { objs = state.SelectedObjectIds.Select(x => Model.FindElementById((ElementId)Convert.ToUInt64(x))).ToList(); + } +#else + objs = state.SelectedObjectIds.Select(x => Model.FindElementById((ElementId)Convert.ToUInt64(x))).ToList(); #endif #if (OPENBUILDINGS) - if (ExportGridLines) + if (ExportGridLines) + { + var converted = ConvertGridLines(converter, progress); + + if (converted == null) + { + progress.Report.LogConversionError(new Exception($"Failed to convert Gridlines.")); + } + else { - var converted = ConvertGridLines(converter, progress); + var containerName = "Grid Systems"; - if (converted == null) + if (commitObj[$"@{containerName}"] == null) { - progress.Report.LogConversionError(new Exception($"Failed to convert Gridlines.")); + commitObj[$"@{containerName}"] = new List(); } - else - { - var containerName = "Grid Systems"; - if (commitObj[$"@{containerName}"] == null) - commitObj[$"@{containerName}"] = new List(); - ((List)commitObj[$"@{containerName}"]).Add(converted); + ((List)commitObj[$"@{containerName}"]).Add(converted); - // not sure this makes much sense here - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + // not sure this makes much sense here + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); - convertedCount++; - } + convertedCount++; } + } #endif - foreach (var obj in objs) + foreach (var obj in objs) + { + progress.CancellationToken.ThrowIfCancellationRequested(); + + if (obj == null) { - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.Report.Log($"Skipped not found object."); + continue; + } - if (obj == null) - { - progress.Report.Log($"Skipped not found object."); - continue; - } + var objId = obj.ElementId.ToString(); + var objType = obj.ElementType; - var objId = obj.ElementId.ToString(); - var objType = obj.ElementType; + if (!converter.CanConvertToSpeckle(obj)) + { + progress.Report.Log($"Skipped not supported type: ${objType}. Object ${objId} not sent."); + continue; + } - if (!converter.CanConvertToSpeckle(obj)) + // convert obj + Base converted = null; + string containerName = string.Empty; + try + { + var levelCache = Model.GetFileLevelCache(); + var objLevel = levelCache.GetLevel(obj.LevelId); + var layerName = "Unknown"; + if (objLevel != null) { - progress.Report.Log($"Skipped not supported type: ${objType}. Object ${objId} not sent."); - continue; + layerName = objLevel.Name; } - // convert obj - Base converted = null; - string containerName = string.Empty; - try - { - var levelCache = Model.GetFileLevelCache(); - var objLevel = levelCache.GetLevel(obj.LevelId); - var layerName = "Unknown"; - if (objLevel != null) - layerName = objLevel.Name; - #if (OPENROADS || OPENRAIL) - if (convertCivilObject) + if (convertCivilObject) + { + var civilObj = civObjs[objs.IndexOf(obj)]; + if (Control.InvokeRequired) { - var civilObj = civObjs[objs.IndexOf(obj)]; - if (Control.InvokeRequired) - { - converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { civilObj }); - Control.Invoke((Action)(() => { containerName = civilObj.Name == "" ? "Unnamed" : civilObj.Name; })); - } - else - { - converted = converter.ConvertToSpeckle(civilObj); - containerName = civilObj.Name == "" ? "Unnamed" : civilObj.Name; - } + converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { civilObj }); + Control.Invoke((Action)(() => { containerName = civilObj.Name == "" ? "Unnamed" : civilObj.Name; })); } else { - if (Control.InvokeRequired) - converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { obj }); - else - converted = converter.ConvertToSpeckle(obj); - containerName = layerName; + converted = converter.ConvertToSpeckle(civilObj); + containerName = civilObj.Name == "" ? "Unnamed" : civilObj.Name; } -#else + } + else + { if (Control.InvokeRequired) - converted = (Base) - Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { obj }); + { + converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { obj }); + } else + { converted = converter.ConvertToSpeckle(obj); + } containerName = layerName; -#endif - if (converted == null) - { - progress.Report.LogConversionError(new Exception($"Failed to convert object {objId} of type {objType}.")); - continue; - } } - catch +#else + if (Control.InvokeRequired) { - progress.Report.LogConversionError(new Exception($"Failed to convert object {objId} of type {objType}.")); - continue; + converted = (Base) + Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { obj }); + } + else + { + converted = converter.ConvertToSpeckle(obj); } - /* TODO: adding the feature data and properties per object - foreach (var key in obj.ExtensionDictionary) + containerName = layerName; +#endif + if (converted == null) { - converted[key] = obj.ExtensionDictionary.GetUserString(key); + progress.Report.LogConversionError(new Exception($"Failed to convert object {objId} of type {objType}.")); + continue; } - */ + } + catch + { + progress.Report.LogConversionError(new Exception($"Failed to convert object {objId} of type {objType}.")); + continue; + } - if (commitObj[$"@{containerName}"] == null) - commitObj[$"@{containerName}"] = new List(); - ((List)commitObj[$"@{containerName}"]).Add(converted); + /* TODO: adding the feature data and properties per object + foreach (var key in obj.ExtensionDictionary) + { + converted[key] = obj.ExtensionDictionary.GetUserString(key); + } + */ - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + if (commitObj[$"@{containerName}"] == null) + { + commitObj[$"@{containerName}"] = new List(); + } - converted.applicationId = objId; + ((List)commitObj[$"@{containerName}"]).Add(converted); - convertedCount++; - } + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); - progress.Report.Merge(converter.Report); + converted.applicationId = objId; - if (convertedCount == 0) - { - throw new SpeckleException("Zero objects converted successfully. Send stopped."); - } + convertedCount++; + } - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.Report.Merge(converter.Report); - progress.Max = convertedCount; + if (convertedCount == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } - var transports = new List() { new ServerTransport(client.Account, streamId) }; + progress.CancellationToken.ThrowIfCancellationRequested(); - var commitObjId = await Operations.Send( - commitObj, - progress.CancellationToken, - transports, - onProgressAction: dict => progress.Update(dict), - onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, - disposeTransports: true - ); - var actualCommit = new CommitCreateInput - { - streamId = streamId, - objectId = commitObjId, - branchName = state.BranchName, - message = - state.CommitMessage != null ? state.CommitMessage : $"Pushed {convertedCount} elements from {Utils.AppName}.", - sourceApplication = Utils.VersionedAppName - }; - - if (state.PreviousCommitId != null) - { - actualCommit.parents = new List() { state.PreviousCommitId }; - } + progress.Max = convertedCount; - var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); - return commitId; + var transports = new List() { new ServerTransport(client.Account, streamId) }; + + var commitObjId = await Operations.Send( + commitObj, + progress.CancellationToken, + transports, + onProgressAction: dict => progress.Update(dict), + onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, + disposeTransports: true + ); + var actualCommit = new CommitCreateInput + { + streamId = streamId, + objectId = commitObjId, + branchName = state.BranchName, + message = + state.CommitMessage != null ? state.CommitMessage : $"Pushed {convertedCount} elements from {Utils.AppName}.", + sourceApplication = Utils.VersionedAppName + }; + + if (state.PreviousCommitId != null) + { + actualCommit.parents = new List() { state.PreviousCommitId }; } + var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); + return commitId; + } + #if (OPENROADS || OPENRAIL) - delegate List GetCivilObjectsDelegate(StreamState state); - private List GetCivilObjects(StreamState state) + delegate List GetCivilObjectsDelegate(StreamState state); + private List GetCivilObjects(StreamState state) + { + var civilObjs = new List(); + foreach (var objId in state.SelectedObjectIds) { - var civilObjs = new List(); - foreach (var objId in state.SelectedObjectIds) + switch (objId) { - switch (objId) - { - case "Alignment": - civilObjs.AddRange(GeomModel.Alignments); - break; - case "Corridor": - civilObjs.AddRange(GeomModel.Corridors); - break; - } + case "Alignment": + civilObjs.AddRange(GeomModel.Alignments); + break; + case "Corridor": + civilObjs.AddRange(GeomModel.Corridors); + break; } - return civilObjs; } + return civilObjs; + } #endif #if (OPENBUILDINGS) - private Base ConvertGridLines(ISpeckleConverter converter, ProgressViewModel progress) - { - Base converted = null; + private Base ConvertGridLines(ISpeckleConverter converter, ProgressViewModel progress) + { + Base converted = null; - ITFApplication appInst = new TFApplicationList(); - if (0 == appInst.GetProject(0, out ITFLoadableProjectList projList) && projList != null) + ITFApplication appInst = new TFApplicationList(); + if (0 == appInst.GetProject(0, out ITFLoadableProjectList projList) && projList != null) + { + ITFLoadableProject proj = projList.AsTFLoadableProject; + if (null == proj) { - ITFLoadableProject proj = projList.AsTFLoadableProject; - if (null == proj) - { - progress.Report.ConversionErrors.Add(new Exception("Could not retrieve project for exporting gridlines")); - return converted; - } + progress.Report.ConversionErrors.Add(new Exception("Could not retrieve project for exporting gridlines")); + return converted; + } - ITFDrawingGrid drawingGrid = null; - if (Control.InvokeRequired) - Control.Invoke((Action)(() => { proj.GetDrawingGrid(false, 0, out drawingGrid); })); - else - proj.GetDrawingGrid(false, 0, out drawingGrid); + ITFDrawingGrid drawingGrid = null; + if (Control.InvokeRequired) + { + Control.Invoke((Action)(() => { proj.GetDrawingGrid(false, 0, out drawingGrid); })); + } + else + { + proj.GetDrawingGrid(false, 0, out drawingGrid); + } - if (null == drawingGrid) - { - progress.Report.ConversionErrors.Add(new Exception("Could not retrieve drawing grid for exporting gridlines")); - return converted; - } + if (null == drawingGrid) + { + progress.Report.ConversionErrors.Add(new Exception("Could not retrieve drawing grid for exporting gridlines")); + return converted; + } - if (Control.InvokeRequired) - converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { drawingGrid }); - else - converted = converter.ConvertToSpeckle(drawingGrid); + if (Control.InvokeRequired) + { + converted = (Base)Control.Invoke(new SpeckleConversionDelegate(converter.ConvertToSpeckle), new object[] { drawingGrid }); + } + else + { + converted = converter.ConvertToSpeckle(drawingGrid); } - return converted; } + return converted; + } #endif - private List GetObjectsFromFilter( - ISelectionFilter filter, - ISpeckleConverter converter, - ProgressViewModel progress - ) + private List GetObjectsFromFilter( + ISelectionFilter filter, + ISpeckleConverter converter, + ProgressViewModel progress + ) + { + var selection = new List(); + switch (filter.Slug) { - var selection = new List(); - switch (filter.Slug) - { - case "all": - return Model.ConvertibleObjects(converter); - case "level": - foreach (var levelName in filter.Selection) - { - var levelCache = Model.GetFileLevelCache(); - var levelHandle = levelCache.GetLevelByName(levelName); - var levelId = levelHandle.LevelId; - - var graphicElements = Model.GetGraphicElements(); - var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); - var objs = graphicElements - .Where(el => el.LevelId == levelId) - .Select(el => el.ElementId.ToString()) - .ToList(); - selection.AddRange(objs); - } - return selection; - case "elementType": - foreach (var typeName in filter.Selection) + case "all": + return Model.ConvertibleObjects(converter); + case "level": + foreach (var levelName in filter.Selection) + { + var levelCache = Model.GetFileLevelCache(); + var levelHandle = levelCache.GetLevelByName(levelName); + var levelId = levelHandle.LevelId; + + var graphicElements = Model.GetGraphicElements(); + var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); + var objs = graphicElements.Where(el => el.LevelId == levelId).Select(el => el.ElementId.ToString()).ToList(); + selection.AddRange(objs); + } + return selection; + case "elementType": + foreach (var typeName in filter.Selection) + { + MSElementType selectedType = MSElementType.None; + switch (typeName) { - MSElementType selectedType = MSElementType.None; - switch (typeName) - { - case "Arc": - selectedType = MSElementType.Arc; - break; - case "Ellipse": - selectedType = MSElementType.Ellipse; - break; - case "Line": - selectedType = MSElementType.Line; - break; - case "Spline": - selectedType = MSElementType.BsplineCurve; - break; - case "Line String": - selectedType = MSElementType.LineString; - break; - case "Complex Chain": - selectedType = MSElementType.ComplexString; - break; - case "Shape": - selectedType = MSElementType.Shape; - break; - case "Complex Shape": - selectedType = MSElementType.ComplexShape; - break; - case "Mesh": - selectedType = MSElementType.MeshHeader; - break; - case "Surface": - selectedType = MSElementType.BsplineSurface; - break; - default: - break; - } - var graphicElements = Model.GetGraphicElements(); - var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); - var objs = graphicElements - .Where(el => el.ElementType == selectedType) - .Select(el => el.ElementId.ToString()) - .ToList(); - selection.AddRange(objs); + case "Arc": + selectedType = MSElementType.Arc; + break; + case "Ellipse": + selectedType = MSElementType.Ellipse; + break; + case "Line": + selectedType = MSElementType.Line; + break; + case "Spline": + selectedType = MSElementType.BsplineCurve; + break; + case "Line String": + selectedType = MSElementType.LineString; + break; + case "Complex Chain": + selectedType = MSElementType.ComplexString; + break; + case "Shape": + selectedType = MSElementType.Shape; + break; + case "Complex Shape": + selectedType = MSElementType.ComplexShape; + break; + case "Mesh": + selectedType = MSElementType.MeshHeader; + break; + case "Surface": + selectedType = MSElementType.BsplineSurface; + break; + default: + break; } - return selection; + var graphicElements = Model.GetGraphicElements(); + var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); + var objs = graphicElements + .Where(el => el.ElementType == selectedType) + .Select(el => el.ElementId.ToString()) + .ToList(); + selection.AddRange(objs); + } + return selection; #if (OPENROADS || OPENRAIL) - case "civilElementType": - foreach (var typeName in filter.Selection) + case "civilElementType": + foreach (var typeName in filter.Selection) + { + switch (typeName) { - switch (typeName) - { - case "Alignment": - var alignments = GeomModel.Alignments; - if (alignments != null) - if (alignments.Count() > 0) - selection.Add("Alignment"); - break; - case "Corridor": - var corridors = GeomModel.Corridors; - if (corridors != null) - if (corridors.Count() > 0) - selection.Add("Corridor"); - break; - default: - break; - } + case "Alignment": + var alignments = GeomModel.Alignments; + if (alignments != null) + { + if (alignments.Count() > 0) + { + selection.Add("Alignment"); + } + } + + break; + case "Corridor": + var corridors = GeomModel.Corridors; + if (corridors != null) + { + if (corridors.Count() > 0) + { + selection.Add("Corridor"); + } + } + + break; + default: + break; } - return selection; + } + return selection; #endif - default: - progress.Report.LogConversionError( - new Exception( - "Filter type is not supported in this app. Why did the developer implement it in the first place?" - ) - ); - return selection; - } + default: + progress.Report.LogConversionError( + new Exception( + "Filter type is not supported in this app. Why did the developer implement it in the first place?" + ) + ); + return selection; } - #endregion + } + #endregion - #region helper methods - delegate void WriteStateDelegate(DgnFile File, List DocumentStreams); + #region helper methods + delegate void WriteStateDelegate(DgnFile File, List DocumentStreams); - /// - /// Transaction wrapper around writing the local streams to the file. - /// - private void WriteStateToFile() + /// + /// Transaction wrapper around writing the local streams to the file. + /// + private void WriteStateToFile() + { + if (Control.InvokeRequired) { - if (Control.InvokeRequired) - Control.Invoke( - new WriteStateDelegate(StreamStateManager.WriteStreamStateList), - new object[] { File, DocumentStreams } - ); - else - StreamStateManager.WriteStreamStateList(File, DocumentStreams); + Control.Invoke( + new WriteStateDelegate(StreamStateManager.WriteStreamStateList), + new object[] { File, DocumentStreams } + ); } - - public override void ResetDocument() + else { - // TODO! + StreamStateManager.WriteStreamStateList(File, DocumentStreams); } - #endregion } + + public override void ResetDocument() + { + // TODO! + } + #endregion } diff --git a/ConnectorBentley/ConnectorBentleyShared/Utils.cs b/ConnectorBentley/ConnectorBentleyShared/Utils.cs index 4061927a45..72348690cf 100644 --- a/ConnectorBentley/ConnectorBentleyShared/Utils.cs +++ b/ConnectorBentley/ConnectorBentleyShared/Utils.cs @@ -1,4 +1,4 @@ -using Bentley.DgnPlatformNET; +using Bentley.DgnPlatformNET; using Bentley.GeometryNET; using Bentley.MstnPlatformNET; using Speckle.Core.Kits; @@ -8,55 +8,56 @@ using System.Text; using System.Threading.Tasks; -namespace Speckle.ConnectorBentley +namespace Speckle.ConnectorBentley; + +public static class Utils { - public static class Utils - { #if MICROSTATION - public static string VersionedAppName = HostApplications.MicroStation.GetVersion(HostAppVersion.v); - public static string AppName = HostApplications.MicroStation.Name; - public static string Slug = HostApplications.MicroStation.Slug; + public static string VersionedAppName = HostApplications.MicroStation.GetVersion(HostAppVersion.v); + public static string AppName = HostApplications.MicroStation.Name; + public static string Slug = HostApplications.MicroStation.Slug; #elif OPENROADS - public static string VersionedAppName = HostApplications.OpenRoads.GetVersion(HostAppVersion.v); - public static string AppName = HostApplications.OpenRoads.Name; - public static string Slug = HostApplications.OpenRoads.Slug; + public static string VersionedAppName = HostApplications.OpenRoads.GetVersion(HostAppVersion.v); + public static string AppName = HostApplications.OpenRoads.Name; + public static string Slug = HostApplications.OpenRoads.Slug; #elif OPENRAIL - public static string VersionedAppName = HostApplications.OpenRail.GetVersion(HostAppVersion.v); - public static string AppName = HostApplications.OpenRail.Name; - public static string Slug = HostApplications.OpenRail.Slug; + public static string VersionedAppName = HostApplications.OpenRail.GetVersion(HostAppVersion.v); + public static string AppName = HostApplications.OpenRail.Name; + public static string Slug = HostApplications.OpenRail.Slug; #elif OPENBUILDINGS - public static string VersionedAppName = HostApplications.OpenBuildings.GetVersion(HostAppVersion.v); - public static string AppName = HostApplications.OpenBuildings.Name; - public static string Slug = HostApplications.OpenBuildings.Slug; + public static string VersionedAppName = HostApplications.OpenBuildings.GetVersion(HostAppVersion.v); + public static string AppName = HostApplications.OpenBuildings.Name; + public static string Slug = HostApplications.OpenBuildings.Slug; #endif - /// - /// Gets the ids of all visible model objects that can be converted to Speckle - /// - /// - /// - /// - public static List ConvertibleObjects(this DgnModel model, ISpeckleConverter converter) - { - var objs = new List(); + /// + /// Gets the ids of all visible model objects that can be converted to Speckle + /// + /// + /// + /// + public static List ConvertibleObjects(this DgnModel model, ISpeckleConverter converter) + { + var objs = new List(); - if (model == null) - { - return new List(); - } + if (model == null) + { + return new List(); + } - var graphicElements = model.GetGraphicElements(); - var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); - var elements = graphicElements.Where(el => !el.IsInvisible).Select(el => el).ToList(); + var graphicElements = model.GetGraphicElements(); + var elementEnumerator = (ModelElementsEnumerator)graphicElements.GetEnumerator(); + var elements = graphicElements.Where(el => !el.IsInvisible).Select(el => el).ToList(); - foreach (var element in elements) + foreach (var element in elements) + { + if (converter.CanConvertToSpeckle(element) && !element.IsInvisible) { - if (converter.CanConvertToSpeckle(element) && !element.IsInvisible) - objs.Add(element.ElementId.ToString()); + objs.Add(element.ElementId.ToString()); } - - objs = graphicElements.Where(el => !el.IsInvisible).Select(el => el.ElementId.ToString()).ToList(); - return objs; } + + objs = graphicElements.Where(el => !el.IsInvisible).Select(el => el.ElementId.ToString()).ToList(); + return objs; } } diff --git a/ConnectorBentley/ConnectorMicroStation/ConnectorMicroStation.csproj b/ConnectorBentley/ConnectorMicroStation/ConnectorMicroStation.csproj index baac6860e2..be794c2fab 100644 --- a/ConnectorBentley/ConnectorMicroStation/ConnectorMicroStation.csproj +++ b/ConnectorBentley/ConnectorMicroStation/ConnectorMicroStation.csproj @@ -13,6 +13,12 @@ false + + 0 + false + false + + @@ -69,4 +75,4 @@ - \ No newline at end of file + diff --git a/ConnectorBentley/ConnectorOpenBuildings/ConnectorOpenBuildings.csproj b/ConnectorBentley/ConnectorOpenBuildings/ConnectorOpenBuildings.csproj index 5eac0fa72c..f64e8763a8 100644 --- a/ConnectorBentley/ConnectorOpenBuildings/ConnectorOpenBuildings.csproj +++ b/ConnectorBentley/ConnectorOpenBuildings/ConnectorOpenBuildings.csproj @@ -12,6 +12,13 @@ $(DefineConstants);OPENBUILDINGS false + + + 0 + false + false + + @@ -62,4 +69,4 @@ - \ No newline at end of file + diff --git a/ConnectorBentley/ConnectorOpenRail/ConnectorOpenRail.csproj b/ConnectorBentley/ConnectorOpenRail/ConnectorOpenRail.csproj index b39cb6157d..05c7347fac 100644 --- a/ConnectorBentley/ConnectorOpenRail/ConnectorOpenRail.csproj +++ b/ConnectorBentley/ConnectorOpenRail/ConnectorOpenRail.csproj @@ -13,6 +13,12 @@ false + + 0 + false + false + + @@ -72,4 +78,4 @@ - \ No newline at end of file + diff --git a/ConnectorBentley/ConnectorOpenRoads/ConnectorOpenRoads.csproj b/ConnectorBentley/ConnectorOpenRoads/ConnectorOpenRoads.csproj index 34679b4e00..8b1ddae0f3 100644 --- a/ConnectorBentley/ConnectorOpenRoads/ConnectorOpenRoads.csproj +++ b/ConnectorBentley/ConnectorOpenRoads/ConnectorOpenRoads.csproj @@ -12,7 +12,13 @@ $(DefineConstants);OPENROADS false - + + + 0 + false + false + + @@ -62,4 +68,4 @@ - \ No newline at end of file + diff --git a/ConnectorCSI/ConnectorCSIShared/StreamStateManager/StreamStateManager.cs b/ConnectorCSI/ConnectorCSIShared/StreamStateManager/StreamStateManager.cs index be01ee1006..f94d91ed43 100644 --- a/ConnectorCSI/ConnectorCSIShared/StreamStateManager/StreamStateManager.cs +++ b/ConnectorCSI/ConnectorCSIShared/StreamStateManager/StreamStateManager.cs @@ -1,4 +1,4 @@ -using CSiAPIv1; +using CSiAPIv1; using DesktopUI2.Models; using Speckle.Newtonsoft.Json; using System; @@ -7,177 +7,179 @@ using System.Linq; using System.Text; -namespace ConnectorCSI.Storage +namespace ConnectorCSI.Storage; + +public static class StreamStateManager { - public static class StreamStateManager + private static string _speckleFilePath; + + public static List ReadState(cSapModel model) { - private static string _speckleFilePath; + var strings = ReadSpeckleFile(model); + if (strings == "") + { + return new List(); + } + try + { + return JsonConvert.DeserializeObject>(strings); + } + catch (Exception e) + { + return new List(); + } + } - public static List ReadState(cSapModel model) + /// + /// Writes the stream states to the .txt file in speckle folder + /// that exists or is created in the folder where the CSI model exists. + /// + /// + /// + public static void WriteStreamStateList(cSapModel model, List streamStates) + { + if (_speckleFilePath == null) { - var strings = ReadSpeckleFile(model); - if (strings == "") - { - return new List(); - } - try - { - return JsonConvert.DeserializeObject>(strings); - } - catch (Exception e) - { - return new List(); - } + GetOrCreateSpeckleFilePath(model); } - /// - /// Writes the stream states to the .txt file in speckle folder - /// that exists or is created in the folder where the CSI model exists. - /// - /// - /// - public static void WriteStreamStateList(cSapModel model, List streamStates) - { - if (_speckleFilePath == null) - GetOrCreateSpeckleFilePath(model); - FileStream fileStream = new FileStream( - _speckleFilePath, - FileMode.Open, - FileAccess.ReadWrite, - FileShare.ReadWrite - ); + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); - using (var streamWriter = new StreamWriter(fileStream)) - { - streamWriter.Write(JsonConvert.SerializeObject(streamStates) as string); - streamWriter.Flush(); - } + using (var streamWriter = new StreamWriter(fileStream)) + { + streamWriter.Write(JsonConvert.SerializeObject(streamStates) as string); + streamWriter.Flush(); } + } - public static void ClearStreamStateList(cSapModel model) + public static void ClearStreamStateList(cSapModel model) + { + if (_speckleFilePath == null) { - if (_speckleFilePath == null) - GetOrCreateSpeckleFilePath(model); - FileStream fileStream = new FileStream( - _speckleFilePath, - FileMode.Open, - FileAccess.ReadWrite, - FileShare.ReadWrite - ); - try - { - fileStream.SetLength(0); - } - catch { } + GetOrCreateSpeckleFilePath(model); } - /// - /// We need a folder in CSI model folder named "speckle" and a file in it - /// called ".txt". This function create this file and folder if - /// they doesn't exists and returns it, otherwise just returns the file path - /// - /// - private static void GetOrCreateSpeckleFilePath(cSapModel model) + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + try { - string CSIModelfilePath = model.GetModelFilename(true); - string CSIModelFolder = Path.GetDirectoryName(CSIModelfilePath); - if (string.IsNullOrEmpty(CSIModelFolder)) - { - // CSI model is probably not saved, so speckle shouldn't do much - _speckleFilePath = null; - return; - } - string CSIFileName = Path.GetFileNameWithoutExtension(CSIModelfilePath); - string speckleFolderPath = Path.Combine(CSIModelFolder, "speckle"); - string speckleFilePath = Path.Combine(CSIModelFolder, "speckle", $"{CSIFileName}.txt"); - try - { - if (!Directory.Exists(speckleFolderPath)) - { - Directory.CreateDirectory(speckleFolderPath); - } - if (!File.Exists(speckleFilePath)) - { - File.CreateText(speckleFilePath); - } - _speckleFilePath = speckleFilePath; - } - catch - { - _speckleFilePath = null; - return; - } + fileStream.SetLength(0); } + catch { } + } - /// - /// Reads the "/speckle/.txt" file and returns the string in it - /// - /// - private static string ReadSpeckleFile(cSapModel model) + /// + /// We need a folder in CSI model folder named "speckle" and a file in it + /// called ".txt". This function create this file and folder if + /// they doesn't exists and returns it, otherwise just returns the file path + /// + /// + private static void GetOrCreateSpeckleFilePath(cSapModel model) + { + string CSIModelfilePath = model.GetModelFilename(true); + string CSIModelFolder = Path.GetDirectoryName(CSIModelfilePath); + if (string.IsNullOrEmpty(CSIModelFolder)) { - if (_speckleFilePath == null) - GetOrCreateSpeckleFilePath(model); - - if (_speckleFilePath == null) - return ""; - FileStream fileStream = new FileStream(_speckleFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - try + // CSI model is probably not saved, so speckle shouldn't do much + _speckleFilePath = null; + return; + } + string CSIFileName = Path.GetFileNameWithoutExtension(CSIModelfilePath); + string speckleFolderPath = Path.Combine(CSIModelFolder, "speckle"); + string speckleFilePath = Path.Combine(CSIModelFolder, "speckle", $"{CSIFileName}.txt"); + try + { + if (!Directory.Exists(speckleFolderPath)) { - using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) - { - return streamReader.ReadToEnd(); - } + Directory.CreateDirectory(speckleFolderPath); } - catch + if (!File.Exists(speckleFilePath)) { - return ""; + File.CreateText(speckleFilePath); } + _speckleFilePath = speckleFilePath; + } + catch + { + _speckleFilePath = null; + return; } + } - /// - /// Saves a backup file with the extension _speckleBackup1 (number ranges from 1-3) - /// if all three backups already exist, it will override the oldest one - /// - /// - public static void SaveBackupFile(cSapModel model) + /// + /// Reads the "/speckle/.txt" file and returns the string in it + /// + /// + private static string ReadSpeckleFile(cSapModel model) + { + if (_speckleFilePath == null) { - string CSIModelfilePath = model.GetModelFilename(true); - string CSIModelFolder = Path.GetDirectoryName(CSIModelfilePath); - if (string.IsNullOrEmpty(CSIModelFolder)) - // CSI model is probably not saved, so speckle shouldn't do much - return; + GetOrCreateSpeckleFilePath(model); + } - string fileExtension = CSIModelfilePath.Split('.').Last(); - string CSIFileName = Path.GetFileNameWithoutExtension(CSIModelfilePath); - string speckleFolderPath = Path.Combine(CSIModelFolder, "speckle"); + if (_speckleFilePath == null) + { + return ""; + } - var backups = new List<(DateTime, string)>(); - foreach (var fileName in Directory.GetFiles(speckleFolderPath)) + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + try + { + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { - if ( - fileName.Contains($"{CSIFileName}_speckleBackup") - && fileName.Split('.').Last().ToLower() == fileExtension.ToLower() - ) - { - backups.Add((File.GetLastWriteTime(fileName), fileName)); - } + return streamReader.ReadToEnd(); } + } + catch + { + return ""; + } + } - if (backups.Count < 3) - { - model.File.Save( - Path.Combine(speckleFolderPath, $"{CSIFileName}_speckleBackup{backups.Count + 1}.{fileExtension}") - ); - } - else + /// + /// Saves a backup file with the extension _speckleBackup1 (number ranges from 1-3) + /// if all three backups already exist, it will override the oldest one + /// + /// + public static void SaveBackupFile(cSapModel model) + { + string CSIModelfilePath = model.GetModelFilename(true); + string CSIModelFolder = Path.GetDirectoryName(CSIModelfilePath); + if (string.IsNullOrEmpty(CSIModelFolder)) + { + // CSI model is probably not saved, so speckle shouldn't do much + return; + } + + string fileExtension = CSIModelfilePath.Split('.').Last(); + string CSIFileName = Path.GetFileNameWithoutExtension(CSIModelfilePath); + string speckleFolderPath = Path.Combine(CSIModelFolder, "speckle"); + + var backups = new List<(DateTime, string)>(); + foreach (var fileName in Directory.GetFiles(speckleFolderPath)) + { + if ( + fileName.Contains($"{CSIFileName}_speckleBackup") + && fileName.Split('.').Last().ToLower() == fileExtension.ToLower() + ) { - var oldestBackup = backups.Min(o => o.Item1); - var oldestFileName = backups.Where(o => o.Item1 == oldestBackup).First().Item2; - model.File.Save(oldestFileName); + backups.Add((File.GetLastWriteTime(fileName), fileName)); } + } - // save back as the original file - model.File.Save(CSIModelfilePath); + if (backups.Count < 3) + { + model.File.Save( + Path.Combine(speckleFolderPath, $"{CSIFileName}_speckleBackup{backups.Count + 1}.{fileExtension}") + ); } + else + { + var oldestBackup = backups.Min(o => o.Item1); + var oldestFileName = backups.Where(o => o.Item1 == oldestBackup).First().Item2; + model.File.Save(oldestFileName); + } + + // save back as the original file + model.File.Save(CSIModelfilePath); } } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.ClientOperations.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.ClientOperations.cs index a217c234b8..f2ca88aa1a 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.ClientOperations.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.ClientOperations.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using DesktopUI2; using DesktopUI2.Models; @@ -9,27 +9,26 @@ using System.Threading.Tasks; using DesktopUI2.Models.Settings; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings + #region Local stream I/O with local file + public override List GetCustomStreamMenuItems() { - #region Local stream I/O with local file - public override List GetCustomStreamMenuItems() - { - return new List(); - } - - public override void WriteStreamsToFile(List streams) - { - StreamStateManager.ClearStreamStateList(Model); - StreamStateManager.WriteStreamStateList(Model, streams); - } + return new List(); + } - public override List GetStreamsInFile() - { - return Model == null ? new List() : StreamStateManager.ReadState(Model); - } + public override void WriteStreamsToFile(List streams) + { + StreamStateManager.ClearStreamStateList(Model); + StreamStateManager.WriteStreamStateList(Model, streams); + } - #endregion + public override List GetStreamsInFile() + { + return Model == null ? new List() : StreamStateManager.ReadState(Model); } + + #endregion } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Recieve.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Recieve.cs index d810f40ada..b599546ed1 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Recieve.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Recieve.cs @@ -21,296 +21,317 @@ using Speckle.Core.Logging; using Speckle.Core.Kits.ConverterInterfaces; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings + public List Preview { get; set; } = new List(); + public Dictionary StoredObjects = new(); + public override bool CanPreviewReceive => false; + + public override Task PreviewReceive(StreamState state, ProgressViewModel progress) { - public List Preview { get; set; } = new List(); - public Dictionary StoredObjects = new Dictionary(); - public override bool CanPreviewReceive => false; + return null; + } - public override Task PreviewReceive(StreamState state, ProgressViewModel progress) - { - return null; - } + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + { + Exceptions.Clear(); - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) - { - Exceptions.Clear(); + var kit = KitManager.GetDefaultKit(); + var appName = GetHostAppVersion(Model); + ISpeckleConverter converter = kit.LoadConverter(appName); - var kit = KitManager.GetDefaultKit(); - var appName = GetHostAppVersion(Model); - ISpeckleConverter converter = kit.LoadConverter(appName); + // set converter settings as tuples (setting slug, setting selection) + // for csi, these must go before the SetContextDocument method. + var settings = new Dictionary(); + foreach (var setting in state.Settings) + { + settings.Add(setting.Slug, setting.Selection); + } - // set converter settings as tuples (setting slug, setting selection) - // for csi, these must go before the SetContextDocument method. - var settings = new Dictionary(); - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - settings.Add("operation", "receive"); - converter.SetConverterSettings(settings); + settings.Add("operation", "receive"); + converter.SetConverterSettings(settings); - converter.SetContextDocument(Model); - Exceptions.Clear(); - var previouslyReceivedObjects = state.ReceivedObjects; + converter.SetContextDocument(Model); + Exceptions.Clear(); + var previouslyReceivedObjects = state.ReceivedObjects; - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.CancellationToken.ThrowIfCancellationRequested(); - Exceptions.Clear(); + Exceptions.Clear(); - Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - state.LastCommit = commit; - Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); - await ConnectorHelpers.TryCommitReceived(state, commit, GetHostAppVersion(Model), progress.CancellationToken); + Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + state.LastCommit = commit; + Base commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); + await ConnectorHelpers.TryCommitReceived(state, commit, GetHostAppVersion(Model), progress.CancellationToken); - Preview.Clear(); - StoredObjects.Clear(); + Preview.Clear(); + StoredObjects.Clear(); - //Execute.PostToUIThread(() => state.Progress.Maximum = state.SelectedObjectIds.Count()); + //Execute.PostToUIThread(() => state.Progress.Maximum = state.SelectedObjectIds.Count()); - Preview = FlattenCommitObject(commitObject, converter); - foreach (var previewObj in Preview) - progress.Report.Log(previewObj); + Preview = FlattenCommitObject(commitObject, converter); + foreach (var previewObj in Preview) + { + progress.Report.Log(previewObj); + } - converter.ReceiveMode = state.ReceiveMode; - // needs to be set for editing to work - converter.SetPreviousContextObjects(previouslyReceivedObjects); + converter.ReceiveMode = state.ReceiveMode; + // needs to be set for editing to work + converter.SetPreviousContextObjects(previouslyReceivedObjects); - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.CancellationToken.ThrowIfCancellationRequested(); - StreamStateManager.SaveBackupFile(Model); + StreamStateManager.SaveBackupFile(Model); - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); - using var d3 = LogContext.PushProperty("converterSettings", settings); - using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); + using var d3 = LogContext.PushProperty("converterSettings", settings); + using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); - var newPlaceholderObjects = ConvertReceivedObjects(converter, progress); + var newPlaceholderObjects = ConvertReceivedObjects(converter, progress); - DeleteObjects(previouslyReceivedObjects, newPlaceholderObjects, progress); + DeleteObjects(previouslyReceivedObjects, newPlaceholderObjects, progress); - // The following block of code is a hack to properly refresh the view - // I've only experienced this bug in ETABS so far + // The following block of code is a hack to properly refresh the view + // I've only experienced this bug in ETABS so far #if ETABS - if (newPlaceholderObjects.Any(o => o.Status == ApplicationObject.State.Updated)) - RefreshDatabaseTable("Beam Object Connectivity"); + if (newPlaceholderObjects.Any(o => o.Status == ApplicationObject.State.Updated)) + { + RefreshDatabaseTable("Beam Object Connectivity"); + } #endif - Model.View.RefreshWindow(); - Model.View.RefreshView(); + Model.View.RefreshWindow(); + Model.View.RefreshView(); - state.ReceivedObjects = newPlaceholderObjects; + state.ReceivedObjects = newPlaceholderObjects; - return state; - } + return state; + } - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - private List ConvertReceivedObjects(ISpeckleConverter converter, ProgressViewModel progress) - { - List conversionResults = new(); - ConcurrentDictionary conversionProgressDict = new() { ["Conversion"] = 1 }; + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + private List ConvertReceivedObjects(ISpeckleConverter converter, ProgressViewModel progress) + { + List conversionResults = new(); + ConcurrentDictionary conversionProgressDict = new() { ["Conversion"] = 1 }; - foreach (var obj in Preview) + foreach (var obj in Preview) + { + if (!StoredObjects.ContainsKey(obj.OriginalId)) { - if (!StoredObjects.ContainsKey(obj.OriginalId)) - continue; - - progress.CancellationToken.ThrowIfCancellationRequested(); + continue; + } - var @base = StoredObjects[obj.OriginalId]; - using var _0 = LogContext.PushProperty("fromType", @base.GetType()); + progress.CancellationToken.ThrowIfCancellationRequested(); - try - { - var conversionResult = (ApplicationObject)converter.ConvertToNative(@base); - - var finalStatus = - conversionResult.Status != ApplicationObject.State.Unknown - ? conversionResult.Status - : ApplicationObject.State.Created; - - obj.Update( - status: finalStatus, - createdIds: conversionResult.CreatedIds, - converted: conversionResult.Converted, - log: conversionResult.Log - ); - } - catch (Exception ex) - { - ConnectorHelpers.LogConversionException(ex); + var @base = StoredObjects[obj.OriginalId]; + using var _0 = LogContext.PushProperty("fromType", @base.GetType()); - var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); - obj.Update(status: failureStatus, logItem: ex.Message); - } + try + { + var conversionResult = (ApplicationObject)converter.ConvertToNative(@base); + + var finalStatus = + conversionResult.Status != ApplicationObject.State.Unknown + ? conversionResult.Status + : ApplicationObject.State.Created; + + obj.Update( + status: finalStatus, + createdIds: conversionResult.CreatedIds, + converted: conversionResult.Converted, + log: conversionResult.Log + ); + } + catch (Exception ex) + { + ConnectorHelpers.LogConversionException(ex); - conversionResults.Add(obj); + var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); + obj.Update(status: failureStatus, logItem: ex.Message); + } - progress.Report.UpdateReportObject(obj); + conversionResults.Add(obj); - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); - } + progress.Report.UpdateReportObject(obj); - if (converter is IFinalizable finalizable) - { - finalizable.FinalizeConversion(); - } + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); + } - return conversionResults; + if (converter is IFinalizable finalizable) + { + finalizable.FinalizeConversion(); } - /// - /// Traverses the object graph, returning objects to be converted. - /// - /// The root object to traverse - /// The converter instance, used to define what objects are convertable - /// A flattened list of objects to be converted ToNative - private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + return conversionResults; + } + + /// + /// Traverses the object graph, returning objects to be converted. + /// + /// The root object to traverse + /// The converter instance, used to define what objects are convertable + /// A flattened list of objects to be converted ToNative + private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + { + void StoreObject(Base b) { - void StoreObject(Base b) + if (!StoredObjects.ContainsKey(b.id)) { - if (!StoredObjects.ContainsKey(b.id)) - StoredObjects.Add(b.id, b); + StoredObjects.Add(b.id, b); } + } - ApplicationObject CreateApplicationObject(Base current) + ApplicationObject CreateApplicationObject(Base current) + { + ApplicationObject NewAppObj() { - ApplicationObject NewAppObj() - { - var speckleType = current.speckle_type - .Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries) - .LastOrDefault(); + var speckleType = current.speckle_type + .Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries) + .LastOrDefault(); - return new ApplicationObject(current.id, speckleType) { applicationId = current.applicationId, }; - } - - //Handle convertable objects - if (converter.CanConvertToNative(current)) - { - var appObj = NewAppObj(); - appObj.Convertible = true; - StoreObject(current); - return appObj; - } + return new ApplicationObject(current.id, speckleType) { applicationId = current.applicationId, }; + } - //Handle objects convertable using displayValues - var fallbackMember = DefaultTraversal.displayValuePropAliases - .Where(o => current[o] != null) - .Select(o => current[o]) - .FirstOrDefault(); + //Handle convertable objects + if (converter.CanConvertToNative(current)) + { + var appObj = NewAppObj(); + appObj.Convertible = true; + StoreObject(current); + return appObj; + } - if (fallbackMember != null) - { - var appObj = NewAppObj(); - var fallbackObjects = GraphTraversal.TraverseMember(fallbackMember).Select(CreateApplicationObject); - appObj.Fallback.AddRange(fallbackObjects); + //Handle objects convertable using displayValues + var fallbackMember = DefaultTraversal.displayValuePropAliases + .Where(o => current[o] != null) + .Select(o => current[o]) + .FirstOrDefault(); - StoreObject(current); - return appObj; - } + if (fallbackMember != null) + { + var appObj = NewAppObj(); + var fallbackObjects = GraphTraversal.TraverseMember(fallbackMember).Select(CreateApplicationObject); + appObj.Fallback.AddRange(fallbackObjects); - return null; + StoreObject(current); + return appObj; } - var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); + return null; + } - var objectsToConvert = traverseFunction - .Traverse(obj) - .Select(tc => CreateApplicationObject(tc.current)) - .Where(appObject => appObject != null) - .Reverse() //just for the sake of matching the previous behaviour as close as possible - .ToList(); + var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); - return objectsToConvert; - } + var objectsToConvert = traverseFunction + .Traverse(obj) + .Select(tc => CreateApplicationObject(tc.current)) + .Where(appObject => appObject != null) + .Reverse() //just for the sake of matching the previous behaviour as close as possible + .ToList(); + + return objectsToConvert; + } - private void RefreshDatabaseTable(string floorTableKey) + private void RefreshDatabaseTable(string floorTableKey) + { + int tableVersion = 0; + int numberRecords = 0; + string[] fieldsKeysIncluded = null; + string[] tableData = null; + int numFatalErrors = 0; + int numWarnMsgs = 0; + int numInfoMsgs = 0; + int numErrorMsgs = 0; + string importLog = ""; + Model.DatabaseTables.GetTableForEditingArray( + floorTableKey, + "ThisParamIsNotActiveYet", + ref tableVersion, + ref fieldsKeysIncluded, + ref numberRecords, + ref tableData + ); + + double version = 0; + string versionString = null; + Model.GetVersion(ref versionString, ref version); + var programVersion = versionString; + + // this is a workaround for a CSI bug. The applyEditedTables is looking for "Unique Name", not "UniqueName" + // this bug is patched in version 20.0.0 + if (programVersion.CompareTo("20.0.0") < 0 && fieldsKeysIncluded[0] == "UniqueName") { - int tableVersion = 0; - int numberRecords = 0; - string[] fieldsKeysIncluded = null; - string[] tableData = null; - int numFatalErrors = 0; - int numWarnMsgs = 0; - int numInfoMsgs = 0; - int numErrorMsgs = 0; - string importLog = ""; - Model.DatabaseTables.GetTableForEditingArray( - floorTableKey, - "ThisParamIsNotActiveYet", - ref tableVersion, - ref fieldsKeysIncluded, - ref numberRecords, - ref tableData - ); - - double version = 0; - string versionString = null; - Model.GetVersion(ref versionString, ref version); - var programVersion = versionString; - - // this is a workaround for a CSI bug. The applyEditedTables is looking for "Unique Name", not "UniqueName" - // this bug is patched in version 20.0.0 - if (programVersion.CompareTo("20.0.0") < 0 && fieldsKeysIncluded[0] == "UniqueName") - fieldsKeysIncluded[0] = "Unique Name"; - - Model.DatabaseTables.SetTableForEditingArray( - floorTableKey, - ref tableVersion, - ref fieldsKeysIncluded, - numberRecords, - ref tableData - ); - Model.DatabaseTables.ApplyEditedTables( - false, - ref numFatalErrors, - ref numErrorMsgs, - ref numWarnMsgs, - ref numInfoMsgs, - ref importLog - ); + fieldsKeysIncluded[0] = "Unique Name"; } - // delete previously sent objects that are no longer in this stream - private void DeleteObjects( - IReadOnlyCollection previouslyReceiveObjects, - IReadOnlyCollection newPlaceholderObjects, - ProgressViewModel progress - ) + Model.DatabaseTables.SetTableForEditingArray( + floorTableKey, + ref tableVersion, + ref fieldsKeysIncluded, + numberRecords, + ref tableData + ); + Model.DatabaseTables.ApplyEditedTables( + false, + ref numFatalErrors, + ref numErrorMsgs, + ref numWarnMsgs, + ref numInfoMsgs, + ref importLog + ); + } + + // delete previously sent objects that are no longer in this stream + private void DeleteObjects( + IReadOnlyCollection previouslyReceiveObjects, + IReadOnlyCollection newPlaceholderObjects, + ProgressViewModel progress + ) + { + foreach (var obj in previouslyReceiveObjects) { - foreach (var obj in previouslyReceiveObjects) + if (obj.Converted.Count == 0) { - if (obj.Converted.Count == 0) - continue; - if (newPlaceholderObjects.Any(x => x.applicationId == obj.applicationId)) + continue; + } + + if (newPlaceholderObjects.Any(x => x.applicationId == obj.applicationId)) + { + continue; + } + + foreach (var o in obj.Converted) + { + if (o is not string s) + { continue; + } - foreach (var o in obj.Converted) + string[] typeAndName = s.Split(new[] { ConnectorCSIUtils.Delimiter }, StringSplitOptions.None); + if (typeAndName.Length != 2) { - if (o is not string s) - continue; + continue; + } - string[] typeAndName = s.Split(new[] { ConnectorCSIUtils.Delimiter }, StringSplitOptions.None); - if (typeAndName.Length != 2) + switch (typeAndName[0]) + { + case "Frame": + Model.FrameObj.Delete(typeAndName[1]); + break; + case "Area": + Model.AreaObj.Delete(typeAndName[1]); + break; + default: continue; - - switch (typeAndName[0]) - { - case "Frame": - Model.FrameObj.Delete(typeAndName[1]); - break; - case "Area": - Model.AreaObj.Delete(typeAndName[1]); - break; - default: - continue; - } - - obj.Update(status: ApplicationObject.State.Removed); - progress.Report.Log(obj); } + + obj.Update(status: ApplicationObject.State.Removed); + progress.Report.Log(obj); } } } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Selection.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Selection.cs index 8f673691e6..e8d5a972b5 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Selection.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Selection.cs @@ -1,130 +1,140 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models.Filters; using Speckle.ConnectorCSI.Util; using System; using System.Collections.Generic; using System.Linq; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings + public override List GetSelectedObjects() { - public override List GetSelectedObjects() + var names = new List(); + var typeNameTupleList = ConnectorCSIUtils.SelectedObjects(Model); + if (typeNameTupleList == null) { - var names = new List(); - var typeNameTupleList = ConnectorCSIUtils.SelectedObjects(Model); - if (typeNameTupleList == null) - return new List() { }; - foreach (var item in typeNameTupleList) - { - (string typeName, string name) = item; - if (ConnectorCSIUtils.IsTypeCSIAPIUsable(typeName)) - names.Add(string.Concat(typeName, ": ", name)); - } - if (names.Count == 0) - return new List() { }; - - return names; + return new List() { }; } - public override List GetSelectionFilters() + foreach (var item in typeNameTupleList) { - var filters = new List(); - filters.Add( - new AllSelectionFilter - { - Slug = "all", - Name = "Everything", - Icon = "CubeScan", - Description = "Selects all document objects." - } - ); - filters.Add(new ManualSelectionFilter()); - - if (Model != null) + (string typeName, string name) = item; + if (ConnectorCSIUtils.IsTypeCSIAPIUsable(typeName)) { - ConnectorCSIUtils.GetObjectIDsTypesAndNames(Model); - var objectTypes = ConnectorCSIUtils.ObjectIDsTypesAndNames.Select(pair => pair.Value.Item1).Distinct().ToList(); - - if (objectTypes.Any()) - filters.Add( - new ListSelectionFilter - { - Slug = "type", - Name = "Categories", - Icon = "Category", - Values = objectTypes, - Description = "Adds all objects belonging to the selected types." - } - ); - - string[] groupNames = new string[0]; - int numNames = 0; - Model.GroupDef.GetNameList(ref numNames, ref groupNames); - if (groupNames.Any()) - filters.Add( - new ListSelectionFilter - { - Slug = "group", - Name = "Group", - Icon = "SelectGroup", - Values = groupNames.ToList(), - Description = "Add all objects belonging to CSI Group." - } - ); + names.Add(string.Concat(typeName, ": ", name)); } - - return filters; } - - public override void SelectClientObjects(List args, bool deselect = false) + if (names.Count == 0) { - // TODO! + return new List() { }; } - private List GetSelectionFilterObjects(ISelectionFilter filter) - { - var doc = Model; - - var selection = new List(); - ConnectorCSIUtils.GetObjectIDsTypesAndNames(Model); + return names; + } - switch (filter.Slug) + public override List GetSelectionFilters() + { + var filters = new List(); + filters.Add( + new AllSelectionFilter { - case "manual": - return GetSelectedObjects(); - case "all": - - selection.AddRange(ConnectorCSIUtils.ObjectIDsTypesAndNames.Select(pair => pair.Key).ToList()); - return selection; + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Selects all document objects." + } + ); + filters.Add(new ManualSelectionFilter()); - case "type": - var typeFilter = filter as ListSelectionFilter; + if (Model != null) + { + ConnectorCSIUtils.GetObjectIDsTypesAndNames(Model); + var objectTypes = ConnectorCSIUtils.ObjectIDsTypesAndNames.Select(pair => pair.Value.Item1).Distinct().ToList(); - foreach (var type in typeFilter.Selection) + if (objectTypes.Any()) + { + filters.Add( + new ListSelectionFilter { - selection.AddRange( - ConnectorCSIUtils.ObjectIDsTypesAndNames - .Where(pair => pair.Value.Item1 == type) - .Select(pair => pair.Key) - .ToList() - ); + Slug = "type", + Name = "Categories", + Icon = "Category", + Values = objectTypes, + Description = "Adds all objects belonging to the selected types." } - return selection; + ); + } - case "group": - //Clear objects first - Model.SelectObj.ClearSelection(); - var groupFilter = filter as ListSelectionFilter; - foreach (var group in groupFilter.Selection) + string[] groupNames = new string[0]; + int numNames = 0; + Model.GroupDef.GetNameList(ref numNames, ref groupNames); + if (groupNames.Any()) + { + filters.Add( + new ListSelectionFilter { - Model.SelectObj.Group(group); + Slug = "group", + Name = "Group", + Icon = "SelectGroup", + Values = groupNames.ToList(), + Description = "Add all objects belonging to CSI Group." } - - return GetSelectedObjects(); + ); } + } + + return filters; + } + + public override void SelectClientObjects(List args, bool deselect = false) + { + // TODO! + } + + private List GetSelectionFilterObjects(ISelectionFilter filter) + { + var doc = Model; + + var selection = new List(); + ConnectorCSIUtils.GetObjectIDsTypesAndNames(Model); - return selection; + switch (filter.Slug) + { + case "manual": + return GetSelectedObjects(); + case "all": + + selection.AddRange(ConnectorCSIUtils.ObjectIDsTypesAndNames.Select(pair => pair.Key).ToList()); + return selection; + + case "type": + var typeFilter = filter as ListSelectionFilter; + + foreach (var type in typeFilter.Selection) + { + selection.AddRange( + ConnectorCSIUtils.ObjectIDsTypesAndNames + .Where(pair => pair.Value.Item1 == type) + .Select(pair => pair.Key) + .ToList() + ); + } + return selection; + + case "group": + //Clear objects first + Model.SelectObj.ClearSelection(); + var groupFilter = filter as ListSelectionFilter; + foreach (var group in groupFilter.Selection) + { + Model.SelectObj.Group(group); + } + + return GetSelectedObjects(); } + + return selection; } } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Send.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Send.cs index 77b7c9345f..9fb9657f91 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Send.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Send.cs @@ -1,4 +1,4 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models; using DesktopUI2.ViewModels; using Speckle.ConnectorCSI.Util; @@ -15,240 +15,250 @@ using Serilog.Context; using SCT = Speckle.Core.Transports; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings + public override bool CanPreviewSend => false; + + public override void PreviewSend(StreamState state, ProgressViewModel progress) { - public override bool CanPreviewSend => false; + // TODO! + } - public override void PreviewSend(StreamState state, ProgressViewModel progress) + public override async Task SendStream(StreamState state, ProgressViewModel progress) + { + var kit = KitManager.GetDefaultKit(); + //var converter = new ConverterCSI(); + var appName = GetHostAppVersion(Model); + var converter = kit.LoadConverter(appName); + + // set converter settings as tuples (setting slug, setting selection) + // for csi, these must go before the SetContextDocument method. + var settings = new Dictionary(); + foreach (var setting in state.Settings) { - // TODO! + settings.Add(setting.Slug, setting.Selection); } - public override async Task SendStream(StreamState state, ProgressViewModel progress) - { - var kit = KitManager.GetDefaultKit(); - //var converter = new ConverterCSI(); - var appName = GetHostAppVersion(Model); - var converter = kit.LoadConverter(appName); + settings.Add("operation", "send"); + converter.SetConverterSettings(settings); - // set converter settings as tuples (setting slug, setting selection) - // for csi, these must go before the SetContextDocument method. - var settings = new Dictionary(); - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - settings.Add("operation", "send"); - converter.SetConverterSettings(settings); + converter.SetContextDocument(Model); + converter.SetPreviousContextObjects(state.ReceivedObjects); + Exceptions.Clear(); - converter.SetContextDocument(Model); - converter.SetPreviousContextObjects(state.ReceivedObjects); - Exceptions.Clear(); + int objCount = 0; - int objCount = 0; - - if (state.Filter != null) - state.SelectedObjectIds = GetSelectionFilterObjects(state.Filter); + if (state.Filter != null) + { + state.SelectedObjectIds = GetSelectionFilterObjects(state.Filter); + } - var totalObjectCount = state.SelectedObjectIds.Count; + var totalObjectCount = state.SelectedObjectIds.Count; - if (totalObjectCount == 0) - { - throw new InvalidOperationException( - "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." - ); - } + if (totalObjectCount == 0) + { + throw new InvalidOperationException( + "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." + ); + } - var conversionProgressDict = new ConcurrentDictionary(); - progress.Max = totalObjectCount; - conversionProgressDict["Conversion"] = 0; - progress.Update(conversionProgressDict); + var conversionProgressDict = new ConcurrentDictionary(); + progress.Max = totalObjectCount; + conversionProgressDict["Conversion"] = 0; + progress.Update(conversionProgressDict); - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); - using var d3 = LogContext.PushProperty("converterSettings", settings); + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); + using var d3 = LogContext.PushProperty("converterSettings", settings); - BuildSendCommitObj(converter, state.SelectedObjectIds, ref progress, ref conversionProgressDict); + BuildSendCommitObj(converter, state.SelectedObjectIds, ref progress, ref conversionProgressDict); - var commitObj = GetCommitObj(converter, progress, conversionProgressDict); + var commitObj = GetCommitObj(converter, progress, conversionProgressDict); - return await SendCommitObj(state, progress, commitObj, conversionProgressDict); - } + return await SendCommitObj(state, progress, commitObj, conversionProgressDict); + } - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - public void BuildSendCommitObj( - ISpeckleConverter converter, - List selectedObjIds, - ref ProgressViewModel progress, - ref ConcurrentDictionary conversionProgressDict - ) + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + public void BuildSendCommitObj( + ISpeckleConverter converter, + List selectedObjIds, + ref ProgressViewModel progress, + ref ConcurrentDictionary conversionProgressDict + ) + { + foreach (var applicationId in selectedObjIds) { - foreach (var applicationId in selectedObjIds) - { - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.CancellationToken.ThrowIfCancellationRequested(); - Base converted = null; - string containerName = string.Empty; + Base converted = null; + string containerName = string.Empty; - var selectedObjectType = ConnectorCSIUtils.ObjectIDsTypesAndNames - .Where(pair => pair.Key == applicationId) - .Select(pair => pair.Value.Item1) - .FirstOrDefault(); + var selectedObjectType = ConnectorCSIUtils.ObjectIDsTypesAndNames + .Where(pair => pair.Key == applicationId) + .Select(pair => pair.Value.Item1) + .FirstOrDefault(); - var reportObj = new ApplicationObject(applicationId, selectedObjectType) { applicationId = applicationId }; + var reportObj = new ApplicationObject(applicationId, selectedObjectType) { applicationId = applicationId }; - if (!converter.CanConvertToSpeckle(selectedObjectType)) - { - progress.Report.Log($"Skipped not supported type: ${selectedObjectType} are not supported"); - continue; - } + if (!converter.CanConvertToSpeckle(selectedObjectType)) + { + progress.Report.Log($"Skipped not supported type: ${selectedObjectType} are not supported"); + continue; + } - var typeAndName = ConnectorCSIUtils.ObjectIDsTypesAndNames - .Where(pair => pair.Key == applicationId) - .Select(pair => pair.Value) - .FirstOrDefault(); + var typeAndName = ConnectorCSIUtils.ObjectIDsTypesAndNames + .Where(pair => pair.Key == applicationId) + .Select(pair => pair.Value) + .FirstOrDefault(); - using var _0 = LogContext.PushProperty("fromType", typeAndName.typeName); + using var _0 = LogContext.PushProperty("fromType", typeAndName.typeName); - try + try + { + converted = converter.ConvertToSpeckle(typeAndName); + if (converted == null) { - converted = converter.ConvertToSpeckle(typeAndName); - if (converted == null) - throw new ConversionException("Conversion Returned Null"); - - reportObj.Update( - status: ApplicationObject.State.Created, - logItem: $"Sent as {ConnectorCSIUtils.SimplifySpeckleType(converted.speckle_type)}" - ); + throw new ConversionException("Conversion Returned Null"); } - catch (Exception ex) - { - ConnectorHelpers.LogConversionException(ex); - var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); - reportObj.Update(status: failureStatus, logItem: ex.Message); - } - - progress.Report.Log(reportObj); + reportObj.Update( + status: ApplicationObject.State.Created, + logItem: $"Sent as {ConnectorCSIUtils.SimplifySpeckleType(converted.speckle_type)}" + ); + } + catch (Exception ex) + { + ConnectorHelpers.LogConversionException(ex); - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); + reportObj.Update(status: failureStatus, logItem: ex.Message); } + + progress.Report.Log(reportObj); + + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); } + } - public Base GetCommitObj( - ISpeckleConverter converter, - ProgressViewModel progress, - ConcurrentDictionary conversionProgressDict - ) + public Base GetCommitObj( + ISpeckleConverter converter, + ProgressViewModel progress, + ConcurrentDictionary conversionProgressDict + ) + { + var commitObj = new Base(); + var reportObj = new ApplicationObject("model", "ModelInfo"); + if (commitObj["@Model"] == null) { - var commitObj = new Base(); - var reportObj = new ApplicationObject("model", "ModelInfo"); - if (commitObj["@Model"] == null) + try { - try - { - commitObj["@Model"] = converter.ConvertToSpeckle(("Model", "CSI")); - reportObj.Update(status: ApplicationObject.State.Created); - } - catch (Exception ex) - { - reportObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); - } - progress.Report.Log(reportObj); + commitObj["@Model"] = converter.ConvertToSpeckle(("Model", "CSI")); + reportObj.Update(status: ApplicationObject.State.Created); } - - reportObj = new ApplicationObject("results", "AnalysisResults"); - if (commitObj["AnalysisResults"] == null) + catch (Exception ex) { - try - { - commitObj["AnalysisResults"] = converter.ConvertToSpeckle(("AnalysisResults", "CSI")); - reportObj.Update(status: ApplicationObject.State.Created); - } - catch (Exception ex) - { - reportObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); - } - progress.Report.Log(reportObj); + reportObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); } + progress.Report.Log(reportObj); + } - progress.Report.Merge(converter.Report); - - if (conversionProgressDict["Conversion"] == 0) + reportObj = new ApplicationObject("results", "AnalysisResults"); + if (commitObj["AnalysisResults"] == null) + { + try { - throw new SpeckleException("Zero objects converted successfully. Send stopped."); + commitObj["AnalysisResults"] = converter.ConvertToSpeckle(("AnalysisResults", "CSI")); + reportObj.Update(status: ApplicationObject.State.Created); } + catch (Exception ex) + { + reportObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); + } + progress.Report.Log(reportObj); + } - progress.CancellationToken.ThrowIfCancellationRequested(); + progress.Report.Merge(converter.Report); - return commitObj; + if (conversionProgressDict["Conversion"] == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); } - public async Task SendCommitObj( - StreamState state, - ProgressViewModel progress, - Base commitObj, - ConcurrentDictionary conversionProgressDict, - string branchName = null - ) - { - var streamId = state.StreamId; - var client = state.Client; + progress.CancellationToken.ThrowIfCancellationRequested(); - var transports = new List() { new SCT.ServerTransport(client.Account, streamId) }; - progress.Max = conversionProgressDict["Conversion"]; + return commitObj; + } - var objectId = await Operations.Send( - @object: commitObj, - cancellationToken: progress.CancellationToken, - transports: transports, - onProgressAction: dict => - { - progress.Update(dict); - }, - onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, - disposeTransports: true - ); + public async Task SendCommitObj( + StreamState state, + ProgressViewModel progress, + Base commitObj, + ConcurrentDictionary conversionProgressDict, + string branchName = null + ) + { + var streamId = state.StreamId; + var client = state.Client; + + var transports = new List() { new SCT.ServerTransport(client.Account, streamId) }; + progress.Max = conversionProgressDict["Conversion"]; - if (branchName != null) + var objectId = await Operations.Send( + @object: commitObj, + cancellationToken: progress.CancellationToken, + transports: transports, + onProgressAction: dict => { - var branchesSplit = state.BranchName.Split('/'); - branchesSplit[branchesSplit.Count() - 1] = branchName; - branchName = string.Join("", branchesSplit); + progress.Update(dict); + }, + onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, + disposeTransports: true + ); - var branchInput = new BranchCreateInput() - { - streamId = streamId, - name = branchName, - description = "This branch holds the comprehensive reports generated by Speckle" - }; - var branch = await client.BranchGet(streamId, branchName); - if (branch == null) - await client.BranchCreate(branchInput); - } - else - branchName = state.BranchName; + if (branchName != null) + { + var branchesSplit = state.BranchName.Split('/'); + branchesSplit[branchesSplit.Count() - 1] = branchName; + branchName = string.Join("", branchesSplit); - var actualCommit = new CommitCreateInput + var branchInput = new BranchCreateInput() { streamId = streamId, - objectId = objectId, - branchName = branchName, - message = - state.CommitMessage != null - ? state.CommitMessage - : $"Pushed {conversionProgressDict["Conversion"]} elements from CSI.", - sourceApplication = GetHostAppVersion(Model) + name = branchName, + description = "This branch holds the comprehensive reports generated by Speckle" }; - - if (state.PreviousCommitId != null) + var branch = await client.BranchGet(streamId, branchName); + if (branch == null) { - actualCommit.parents = new List() { state.PreviousCommitId }; + await client.BranchCreate(branchInput); } + } + else + { + branchName = state.BranchName; + } - return await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); + var actualCommit = new CommitCreateInput + { + streamId = streamId, + objectId = objectId, + branchName = branchName, + message = + state.CommitMessage != null + ? state.CommitMessage + : $"Pushed {conversionProgressDict["Conversion"]} elements from CSI.", + sourceApplication = GetHostAppVersion(Model) + }; + + if (state.PreviousCommitId != null) + { + actualCommit.parents = new List() { state.PreviousCommitId }; } + + return await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); } } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Settings.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Settings.cs index a5f9fdc4ed..d990675744 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Settings.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.Settings.cs @@ -5,65 +5,63 @@ using System.Collections.Generic; using System.Text; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings - { - // WARNING: These strings need to have the same value as the strings in ConverterCSIUtils - public const string RESULTS_NODE_SLUG = "node-results"; - public const string RESULTS_1D_SLUG = "1d-results"; - public const string RESULTS_2D_SLUG = "2d-results"; - public const string RESULTS_LOAD_CASES_SLUG = "load-cases"; + // WARNING: These strings need to have the same value as the strings in ConverterCSIUtils + public const string RESULTS_NODE_SLUG = "node-results"; + public const string RESULTS_1D_SLUG = "1d-results"; + public const string RESULTS_2D_SLUG = "2d-results"; + public const string RESULTS_LOAD_CASES_SLUG = "load-cases"; - public const string BEAM_FORCES = "Beam Forces"; - public const string BRACE_FORCES = "Brace Forces"; - public const string COLUMN_FORCES = "Column Forces"; - public const string OTHER_FORCES = "Other Forces"; - public const string FORCES = "Forces"; - public const string STRESSES = "Stresses"; - public const string DISPLACEMENTS = "Displacements"; - public const string VELOCITIES = "Velocities"; - public const string ACCELERATIONS = "Accelerations"; - public override List GetSettings() + public const string BEAM_FORCES = "Beam Forces"; + public const string BRACE_FORCES = "Brace Forces"; + public const string COLUMN_FORCES = "Column Forces"; + public const string OTHER_FORCES = "Other Forces"; + public const string FORCES = "Forces"; + public const string STRESSES = "Stresses"; + public const string DISPLACEMENTS = "Displacements"; + public const string VELOCITIES = "Velocities"; + public const string ACCELERATIONS = "Accelerations"; + + public override List GetSettings() + { + return new List { - return new List + new MultiSelectBoxSetting + { + Slug = RESULTS_LOAD_CASES_SLUG, + Name = "Load Case Results To Send", + Icon = "Link", + Description = + "Only the analytical results that belong to the load combinations selected here \nwill be sent to Speckle", + Values = ResultUtils.GetNamesOfAllLoadCasesAndCombos(Model) + }, + new MultiSelectBoxSetting + { + Slug = RESULTS_NODE_SLUG, + Name = "Node Results To Send", + Icon = "Link", + Description = "Determines which node results are sent to Speckle", + Values = new List() { DISPLACEMENTS, FORCES, VELOCITIES, ACCELERATIONS } + }, + new MultiSelectBoxSetting + { + Slug = RESULTS_1D_SLUG, + Name = "1D Element Results To Send", + Icon = "Link", + Description = "Determines which 1D element results and sent to Speckle", + Values = new List() { BEAM_FORCES, BRACE_FORCES, COLUMN_FORCES, OTHER_FORCES } + }, + new MultiSelectBoxSetting { - new MultiSelectBoxSetting - { - Slug = RESULTS_LOAD_CASES_SLUG, - Name = "Load Case Results To Send", - Icon = "Link", - Description = "Only the analytical results that belong to the load combinations selected here \nwill be sent to Speckle", - Values = ResultUtils.GetNamesOfAllLoadCasesAndCombos(Model) - }, - - new MultiSelectBoxSetting - { - Slug = RESULTS_NODE_SLUG, - Name = "Node Results To Send", - Icon = "Link", - Description = "Determines which node results are sent to Speckle", - Values = new List() { DISPLACEMENTS, FORCES, VELOCITIES, ACCELERATIONS } - }, - - new MultiSelectBoxSetting - { - Slug = RESULTS_1D_SLUG, - Name = "1D Element Results To Send", - Icon = "Link", - Description = "Determines which 1D element results and sent to Speckle", - Values = new List() { BEAM_FORCES, BRACE_FORCES, COLUMN_FORCES, OTHER_FORCES } - }, - - new MultiSelectBoxSetting - { - Slug = RESULTS_2D_SLUG, - Name = "2D Element Results To Send", - Icon = "Link", - Description = "Determines which 2D element results are computed and sent to Speckle", - Values = new List() { FORCES, STRESSES } - }, - }; - } + Slug = RESULTS_2D_SLUG, + Name = "2D Element Results To Send", + Icon = "Link", + Description = "Determines which 2D element results are computed and sent to Speckle", + Values = new List() { FORCES, STRESSES } + }, + }; } } diff --git a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.cs b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.cs index eef4e234c2..12a6d9e447 100644 --- a/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.cs +++ b/ConnectorCSI/ConnectorCSIShared/UI/ConnectorBindingsCSI.cs @@ -9,70 +9,69 @@ using Speckle.Core.Kits; using System.Threading.Tasks; -namespace Speckle.ConnectorCSI.UI +namespace Speckle.ConnectorCSI.UI; + +public partial class ConnectorBindingsCSI : ConnectorBindings { - public partial class ConnectorBindingsCSI : ConnectorBindings + public static cSapModel Model { get; set; } + public List Exceptions { get; set; } = new List(); + + public ConnectorBindingsCSI(cSapModel model) + { + Model = model; + } + + public override List GetReceiveModes() + { + return new List { ReceiveMode.Update, ReceiveMode.Create }; + } + + #region boilerplate + public override string GetActiveViewName() { - public static cSapModel Model { get; set; } - public List Exceptions { get; set; } = new List(); - - public ConnectorBindingsCSI(cSapModel model) - { - Model = model; - } - - public override List GetReceiveModes() - { - return new List { ReceiveMode.Update, ReceiveMode.Create }; - } - - #region boilerplate - public override string GetActiveViewName() - { - throw new NotImplementedException(); - } - - public override string GetDocumentId() => GetDocHash(); - - private string GetDocHash() => - Utilities.HashString(Model.GetModelFilepath() + Model.GetModelFilename(), Utilities.HashingFunctions.MD5); - - public override string GetDocumentLocation() => Model.GetModelFilepath(); - - public override string GetFileName() => Model.GetModelFilename(); - - public override string GetHostAppNameVersion() => GetHostAppVersion(Model); - - public override string GetHostAppName() => GetHostAppName(Model); - - public string GetHostAppVersion(cSapModel model) - { - var name = ""; - var ver = ""; - var type = ""; - model.GetProgramInfo(ref name, ref ver, ref type); - return name; - } - - public string GetHostAppName(cSapModel model) - { - var name = ""; - var ver = ""; - var type = ""; - model.GetProgramInfo(ref name, ref ver, ref type); - return name.ToLower(); - } - - public override List GetObjectsInView() - { - throw new NotImplementedException(); - } - - public override void ResetDocument() - { - // TODO! - } - - #endregion + throw new NotImplementedException(); } + + public override string GetDocumentId() => GetDocHash(); + + private string GetDocHash() => + Utilities.HashString(Model.GetModelFilepath() + Model.GetModelFilename(), Utilities.HashingFunctions.MD5); + + public override string GetDocumentLocation() => Model.GetModelFilepath(); + + public override string GetFileName() => Model.GetModelFilename(); + + public override string GetHostAppNameVersion() => GetHostAppVersion(Model); + + public override string GetHostAppName() => GetHostAppName(Model); + + public string GetHostAppVersion(cSapModel model) + { + var name = ""; + var ver = ""; + var type = ""; + model.GetProgramInfo(ref name, ref ver, ref type); + return name; + } + + public string GetHostAppName(cSapModel model) + { + var name = ""; + var ver = ""; + var type = ""; + model.GetProgramInfo(ref name, ref ver, ref type); + return name.ToLower(); + } + + public override List GetObjectsInView() + { + throw new NotImplementedException(); + } + + public override void ResetDocument() + { + // TODO! + } + + #endregion } diff --git a/ConnectorCSI/ConnectorCSIShared/UnusedClass.cs b/ConnectorCSI/ConnectorCSIShared/UnusedClass.cs index 34c38a8aa4..07d652c019 100644 --- a/ConnectorCSI/ConnectorCSIShared/UnusedClass.cs +++ b/ConnectorCSI/ConnectorCSIShared/UnusedClass.cs @@ -1,16 +1,15 @@ using StructuralUtilities.PolygonMesher; -namespace ConnectorCSIShared +namespace ConnectorCSIShared; + +internal class UnusedClass { - internal class UnusedClass + public PolygonMesher UnusedMethod() { - public PolygonMesher UnusedMethod() - { - // This class is only here to throw an error if the polygon mesher dependency is ever removed - // The dependency is needed for the converter, however the assembly resolve doesn't look in the kits - // folder for missing dlls, it looks in the connector folder. We should probably figure out a different - // method for dealing with converter dependencies - return null; - } + // This class is only here to throw an error if the polygon mesher dependency is ever removed + // The dependency is needed for the converter, however the assembly resolve doesn't look in the kits + // folder for missing dlls, it looks in the connector folder. We should probably figure out a different + // method for dealing with converter dependencies + return null; } } diff --git a/ConnectorCSI/ConnectorCSIShared/Util/ConnectorCSIUtils.cs b/ConnectorCSI/ConnectorCSIShared/Util/ConnectorCSIUtils.cs index 2655d3c1a1..af7a8d02d8 100644 --- a/ConnectorCSI/ConnectorCSIShared/Util/ConnectorCSIUtils.cs +++ b/ConnectorCSI/ConnectorCSIShared/Util/ConnectorCSIUtils.cs @@ -1,759 +1,758 @@ -using System; +using System; using System.Collections.Generic; using Speckle.Core.Logging; using System.Linq; using CSiAPIv1; -namespace Speckle.ConnectorCSI.Util +namespace Speckle.ConnectorCSI.Util; + +public static class ConnectorCSIUtils { - public static class ConnectorCSIUtils - { - //#if ETABS - // public static string CSIAppName = VersionedHostApplications.ETABS; - // public static string CSISlug = HostApplications.ETABS.Slug; - //#elif SAP2000 - // public static string CSIAppName = VersionedHostApplications.SAP2000; - // public static string CSISlug = HostApplications.SAP2000.Slug; - //#elif CSIBridge - // public static string CSIAppName = VersionedHostApplications.CSIBridge; - // public static string CSISlug = HostApplications.CSIBridge.Slug; - //#elif SAFE - // public static string CSIAppName = VersionedHostApplications.SAFE; - // public static string CSISlug = HostApplications.SAFE.Slug; - //#else - // public static string CSIAppName = VersionedHostApplications.CSI; - // public static string CSISlug = HostApplications.CSI.Slug; - //#endif - - public static Dictionary ObjectIDsTypesAndNames { get; set; } - - public static List ConversionErrors { get; set; } - - // warning: this delimter string needs to be the same as the delimter string in "converterCSIUtils" - public const string Delimiter = "::"; - - public static void GetObjectIDsTypesAndNames(cSapModel model) - { - ObjectIDsTypesAndNames = new Dictionary(); - foreach (var objectType in Enum.GetNames(typeof(CSIAPIUsableTypes))) + //#if ETABS + // public static string CSIAppName = VersionedHostApplications.ETABS; + // public static string CSISlug = HostApplications.ETABS.Slug; + //#elif SAP2000 + // public static string CSIAppName = VersionedHostApplications.SAP2000; + // public static string CSISlug = HostApplications.SAP2000.Slug; + //#elif CSIBridge + // public static string CSIAppName = VersionedHostApplications.CSIBridge; + // public static string CSISlug = HostApplications.CSIBridge.Slug; + //#elif SAFE + // public static string CSIAppName = VersionedHostApplications.SAFE; + // public static string CSISlug = HostApplications.SAFE.Slug; + //#else + // public static string CSIAppName = VersionedHostApplications.CSI; + // public static string CSISlug = HostApplications.CSI.Slug; + //#endif + + public static Dictionary ObjectIDsTypesAndNames { get; set; } + + public static List ConversionErrors { get; set; } + + // warning: this delimter string needs to be the same as the delimter string in "converterCSIUtils" + public const string Delimiter = "::"; + + public static void GetObjectIDsTypesAndNames(cSapModel model) + { + ObjectIDsTypesAndNames = new Dictionary(); + foreach (var objectType in Enum.GetNames(typeof(CSIAPIUsableTypes))) + { + var names = new List(); + try { - var names = new List(); - try - { - names = GetAllNamesOfObjectType(model, objectType); - } - catch { } - if (names.Count > 0) + names = GetAllNamesOfObjectType(model, objectType); + } + catch { } + if (names.Count > 0) + { + foreach (string name in names) { - foreach (string name in names) - { - ObjectIDsTypesAndNames.Add(string.Concat(objectType, ": ", name), (objectType, name)); - } + ObjectIDsTypesAndNames.Add(string.Concat(objectType, ": ", name), (objectType, name)); } } } + } - public static bool IsTypeCSIAPIUsable(string type) - { - return Enum.GetNames(typeof(CSIAPIUsableTypes)).Contains(type); + public static bool IsTypeCSIAPIUsable(string type) + { + return Enum.GetNames(typeof(CSIAPIUsableTypes)).Contains(type); + } + + public static List GetAllNamesOfObjectType(cSapModel model, string objectType) + { + switch (objectType) + { + case "Point": + return GetAllPointNames(model); + case "Frame": + return GetAllFrameNames(model); + case "Beam": + return GetBeamNames(model); + case "Column": + return GetColumnNames(model); + case "Brace": + return GetBraceNames(model); + case "Area": + return GetAllAreaNames(model); + case "Floor": + return GetAllFloorNames(model); + case "Wall": + return GetAllWallNames(model); + case "Links": + return GetAllLinkNames(model); + case "Spandrel": + return GetAllSpandrelLabelNames(model); + case "Tendon": + return GetAllTendonNames(model); + case "Pier": + return GetAllPierLabelNames(model); + case "Grids": + return GetAllGridNames(model); + case "LoadPattern": + return GetAllLoadPatternNames(model); + case "BeamLoading": + return GetBeamNames(model); + case "ColumnLoading": + return GetColumnNames(model); + case "BraceLoading": + return GetBraceNames(model); + case "FrameLoading": + return GetAllFrameNames(model); + case "FloorLoading": + return GetAllFloorNames(model); + case "WallLoading": + return GetAllWallNames(model); + case "AreaLoading": + return GetAllAreaNames(model); + case "NodeLoading": + return GetAllPointNames(model); + case "Model": + var names = new string[] { }; + names.Append(model.GetModelFilename()); + return names.ToList(); + case "ColumnResults": + return GetColumnNames(model); + case "BeamResults": + return GetBeamNames(model); + case "BraceResults": + return GetBraceNames(model); + case "PierResults": + return GetAllPierLabelNames(model); + case "SpandrelResults": + return GetAllSpandrelLabelNames(model); + case "AnalysisResults": + return GetAllElementNames(model); + default: + return null; } + } - public static List GetAllNamesOfObjectType(cSapModel model, string objectType) + #region Get List Names + public static List GetAllPointNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - switch (objectType) - { - case "Point": - return GetAllPointNames(model); - case "Frame": - return GetAllFrameNames(model); - case "Beam": - return GetBeamNames(model); - case "Column": - return GetColumnNames(model); - case "Brace": - return GetBraceNames(model); - case "Area": - return GetAllAreaNames(model); - case "Floor": - return GetAllFloorNames(model); - case "Wall": - return GetAllWallNames(model); - case "Links": - return GetAllLinkNames(model); - case "Spandrel": - return GetAllSpandrelLabelNames(model); - case "Tendon": - return GetAllTendonNames(model); - case "Pier": - return GetAllPierLabelNames(model); - case "Grids": - return GetAllGridNames(model); - case "LoadPattern": - return GetAllLoadPatternNames(model); - case "BeamLoading": - return GetBeamNames(model); - case "ColumnLoading": - return GetColumnNames(model); - case "BraceLoading": - return GetBraceNames(model); - case "FrameLoading": - return GetAllFrameNames(model); - case "FloorLoading": - return GetAllFloorNames(model); - case "WallLoading": - return GetAllWallNames(model); - case "AreaLoading": - return GetAllAreaNames(model); - case "NodeLoading": - return GetAllPointNames(model); - case "Model": - var names = new string[] { }; - names.Append(model.GetModelFilename()); - return names.ToList(); - case "ColumnResults": - return GetColumnNames(model); - case "BeamResults": - return GetBeamNames(model); - case "BraceResults": - return GetBraceNames(model); - case "PierResults": - return GetAllPierLabelNames(model); - case "SpandrelResults": - return GetAllSpandrelLabelNames(model); - case "AnalysisResults": - return GetAllElementNames(model); - default: - return null; - } + model.PointObj.GetNameList(ref num, ref names); + return names.ToList(); } - - #region Get List Names - public static List GetAllPointNames(cSapModel model) + catch { - int num = 0; - var names = new string[] { }; - try - { - model.PointObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + return null; } + } - public static List GetAllFrameNames(cSapModel model) + public static List GetAllFrameNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.FrameObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.FrameObj.GetNameList(ref num, ref names); + return names.ToList(); } - - public static List GetColumnNames(cSapModel model) + catch { - var frameNames = GetAllFrameNames(model); + return null; + } + } - List columnNames = new List(); + public static List GetColumnNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List columnNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("c")) - { - columnNames.Add(frameName); - } - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); - return columnNames; + if (frameLabel.ToLower().StartsWith("c")) + { + columnNames.Add(frameName); + } } - public static List GetBeamNames(cSapModel model) - { - var frameNames = GetAllFrameNames(model); + return columnNames; + } - List beamNames = new List(); + public static List GetBeamNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List beamNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("b")) - { - beamNames.Add(frameName); - } - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); - return beamNames; + if (frameLabel.ToLower().StartsWith("b")) + { + beamNames.Add(frameName); + } } - public static List GetBraceNames(cSapModel model) - { - var frameNames = GetAllFrameNames(model); + return beamNames; + } - List braceNames = new List(); + public static List GetBraceNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List braceNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("d")) - { - braceNames.Add(frameName); - } - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); - return braceNames; + if (frameLabel.ToLower().StartsWith("d")) + { + braceNames.Add(frameName); + } } - public static List GetAllElementNames(cSapModel model) - { - var elementNames = new List(); + return braceNames; + } - elementNames.AddRange(GetColumnNames(model)); - elementNames.AddRange(GetBeamNames(model)); - elementNames.AddRange(GetBraceNames(model)); - elementNames.AddRange(GetAllPierLabelNames(model)); - elementNames.AddRange(GetAllSpandrelLabelNames(model)); + public static List GetAllElementNames(cSapModel model) + { + var elementNames = new List(); - return elementNames; - } + elementNames.AddRange(GetColumnNames(model)); + elementNames.AddRange(GetBeamNames(model)); + elementNames.AddRange(GetBraceNames(model)); + elementNames.AddRange(GetAllPierLabelNames(model)); + elementNames.AddRange(GetAllSpandrelLabelNames(model)); - public static List GetAllTendonNames(cSapModel model) + return elementNames; + } + + public static List GetAllTendonNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.TendonObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.TendonObj.GetNameList(ref num, ref names); + return names.ToList(); } - - public static List GetAllAreaNames(cSapModel model) + catch { - int num = 0; - var names = new string[] { }; - try - { - model.AreaObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + return null; } + } - public static List GetAllWallNames(cSapModel model) + public static List GetAllAreaNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try + { + model.AreaObj.GetNameList(ref num, ref names); + return names.ToList(); + } + catch { - var WallNames = GetAllAreaNames(model); + return null; + } + } - List WallName = new List(); + public static List GetAllWallNames(cSapModel model) + { + var WallNames = GetAllAreaNames(model); - string wallLabel = ""; - string wallStory = ""; + List WallName = new(); - foreach (var wallName in WallNames) - { - model.AreaObj.GetLabelFromName(wallName, ref wallLabel, ref wallStory); + string wallLabel = ""; + string wallStory = ""; - if (wallLabel.ToLower().StartsWith("w")) - { - WallName.Add(wallName); - } - } + foreach (var wallName in WallNames) + { + model.AreaObj.GetLabelFromName(wallName, ref wallLabel, ref wallStory); - return WallName; + if (wallLabel.ToLower().StartsWith("w")) + { + WallName.Add(wallName); + } } - public static List GetAllFloorNames(cSapModel model) - { - var FloorNames = GetAllAreaNames(model); + return WallName; + } - List FloorName = new List(); + public static List GetAllFloorNames(cSapModel model) + { + var FloorNames = GetAllAreaNames(model); - string FloorLabel = ""; - string FloorStory = ""; + List FloorName = new(); - foreach (var floorName in FloorNames) - { - model.AreaObj.GetLabelFromName(floorName, ref FloorLabel, ref FloorStory); + string FloorLabel = ""; + string FloorStory = ""; - if (FloorLabel.ToLower().StartsWith("f")) - { - FloorName.Add(floorName); - } - } + foreach (var floorName in FloorNames) + { + model.AreaObj.GetLabelFromName(floorName, ref FloorLabel, ref FloorStory); - return FloorName; + if (FloorLabel.ToLower().StartsWith("f")) + { + FloorName.Add(floorName); + } } - public static List GetAllLinkNames(cSapModel model) + return FloorName; + } + + public static List GetAllLinkNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.LinkObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.LinkObj.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropMaterialNames(cSapModel model) + public static List GetAllPropMaterialNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropMaterial.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropMaterial.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllPropRebarNames(cSapModel model) + public static List GetAllPropRebarNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropRebar.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropRebar.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropFrameNames(cSapModel model) + public static List GetAllPropFrameNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropFrame.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropFrame.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllLoadCaseNames(cSapModel model) + public static List GetAllLoadCaseNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.LoadCases.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.LoadCases.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllGroupNames(cSapModel model) + public static List GetAllGroupNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.GroupDef.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.GroupDef.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllGridNames(cSapModel model) + public static List GetAllGridNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.GridSys.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.GridSys.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllComboNames(cSapModel model) + public static List GetAllComboNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.RespCombo.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.RespCombo.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllConstraintNames(cSapModel model) + public static List GetAllConstraintNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.ConstraintDef.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.ConstraintDef.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllLoadPatternNames(cSapModel model) + public static List GetAllLoadPatternNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.LoadPatterns.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.LoadPatterns.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllSteelDesignNames(cSapModel model) + public static List GetAllSteelDesignNames(cSapModel model) + { + var name = ""; + try { - var name = ""; - try - { - model.DesignSteel.GetCode(ref name); - return new List() { name }; - } - catch - { - return null; - } + model.DesignSteel.GetCode(ref name); + return new List() { name }; + } + catch + { + return null; } + } - public static List GetAllConcreteDesignNames(cSapModel model) + public static List GetAllConcreteDesignNames(cSapModel model) + { + var name = ""; + try { - var name = ""; - try - { - model.DesignConcrete.GetCode(ref name); - return new List() { name }; - } - catch - { - return null; - } + model.DesignConcrete.GetCode(ref name); + return new List() { name }; + } + catch + { + return null; } + } - public static List GetAllStoryNames(cSapModel model) + public static List GetAllStoryNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.Story.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.Story.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllDiaphragmNames(cSapModel model) + public static List GetAllDiaphragmNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.Diaphragm.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.Diaphragm.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllLineNames(cSapModel model) + public static List GetAllLineNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.LineElm.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.LineElm.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPierLabelNames(cSapModel model) + public static List GetAllPierLabelNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PierLabel.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PierLabel.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropAreaSpringNames(cSapModel model) + public static List GetAllPropAreaSpringNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropAreaSpring.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropAreaSpring.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllPropLineSpringNames(cSapModel model) + public static List GetAllPropLineSpringNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropLineSpring.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropLineSpring.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropPointSpringNames(cSapModel model) + public static List GetAllPropPointSpringNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropPointSpring.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropPointSpring.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllSpandrelLabelNames(cSapModel model) + public static List GetAllSpandrelLabelNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + var isMultiStory = new bool[] { }; + try { - int num = 0; - var names = new string[] { }; - var isMultiStory = new bool[] { }; - try - { - model.SpandrelLabel.GetNameList(ref num, ref names, ref isMultiStory); - return names.ToList(); - } - catch - { - return null; - } + model.SpandrelLabel.GetNameList(ref num, ref names, ref isMultiStory); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllTowerNames(cSapModel model) + public static List GetAllTowerNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.Tower.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.Tower.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropTendonNames(cSapModel model) + public static List GetAllPropTendonNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropTendon.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropTendon.GetNameList(ref num, ref names); + return names.ToList(); + } + catch + { + return null; } + } - public static List GetAllPropLinkNames(cSapModel model) + public static List GetAllPropLinkNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.PropLink.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.PropLink.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - #endregion + #endregion - public static List<(string, string)> SelectedObjects(cSapModel model) - { - int num = 0; - var types = new int[] { }; - var names = new string[] { }; - model.SelectObj.GetSelected(ref num, ref types, ref names); - var typesAndNames = new List<(string, string)>(); - if (num < 1) - { - return null; - } - for (int i = 0; i < num; i++) - { - switch (types[i]) - { - case 1: - typesAndNames.Add(("Point", names[i])); - break; - case 2: - typesAndNames.Add(("Frame", names[i])); - break; - case 3: - typesAndNames.Add(("Cable", names[i])); - break; - case 4: - typesAndNames.Add(("Tendon", names[i])); - break; - case 5: - typesAndNames.Add(("Area", names[i])); - break; - case 6: - typesAndNames.Add(("Solid", names[i])); - break; - case 7: - typesAndNames.Add(("Link", names[i])); - break; - default: - break; - } + public static List<(string, string)> SelectedObjects(cSapModel model) + { + int num = 0; + var types = new int[] { }; + var names = new string[] { }; + model.SelectObj.GetSelected(ref num, ref types, ref names); + var typesAndNames = new List<(string, string)>(); + if (num < 1) + { + return null; + } + for (int i = 0; i < num; i++) + { + switch (types[i]) + { + case 1: + typesAndNames.Add(("Point", names[i])); + break; + case 2: + typesAndNames.Add(("Frame", names[i])); + break; + case 3: + typesAndNames.Add(("Cable", names[i])); + break; + case 4: + typesAndNames.Add(("Tendon", names[i])); + break; + case 5: + typesAndNames.Add(("Area", names[i])); + break; + case 6: + typesAndNames.Add(("Solid", names[i])); + break; + case 7: + typesAndNames.Add(("Link", names[i])); + break; + default: + break; } - return typesAndNames; - } - - /// - /// Removes all inherited classes from speckle type string (copied from Revit converter) - /// - /// - /// - public static string SimplifySpeckleType(string type) - { - return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); - } - - public enum CSIAPIUsableTypes - { - Point, // cPointObj - Frame, // cFrameObj - Beam, - Column, - Brace, - Area, - Wall, - Spandrel, - Pier, - Floor, - Grids, - Links, - Tendon, - LoadPattern, - Model, - - //Diaphragm, - BeamLoading, - ColumnLoading, - BraceLoading, - FrameLoading, - FloorLoading, - AreaLoading, - WallLoading, - NodeLoading, - - //ColumnResults, - //BeamResults, - //BraceResults, - //PierResults, - //SpandrelResults, - //AnalysisResults - } - - /// - /// same as ObjectType in CSI cSelect.GetSelected API function - /// - public enum CSIViewSelectableTypes - { - Point = 1, - Frame = 2, - Area = 4 } + return typesAndNames; + } + + /// + /// Removes all inherited classes from speckle type string (copied from Revit converter) + /// + /// + /// + public static string SimplifySpeckleType(string type) + { + return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + } + + public enum CSIAPIUsableTypes + { + Point, // cPointObj + Frame, // cFrameObj + Beam, + Column, + Brace, + Area, + Wall, + Spandrel, + Pier, + Floor, + Grids, + Links, + Tendon, + LoadPattern, + Model, + + //Diaphragm, + BeamLoading, + ColumnLoading, + BraceLoading, + FrameLoading, + FloorLoading, + AreaLoading, + WallLoading, + NodeLoading, + + //ColumnResults, + //BeamResults, + //BraceResults, + //PierResults, + //SpandrelResults, + //AnalysisResults + } + + /// + /// same as ObjectType in CSI cSelect.GetSelected API function + /// + public enum CSIViewSelectableTypes + { + Point = 1, + Frame = 2, + Area = 4 } } diff --git a/ConnectorCSI/ConnectorCSIShared/Util/ResultUtils.cs b/ConnectorCSI/ConnectorCSIShared/Util/ResultUtils.cs index df3310906b..ee0ab1b3f6 100644 --- a/ConnectorCSI/ConnectorCSIShared/Util/ResultUtils.cs +++ b/ConnectorCSI/ConnectorCSIShared/Util/ResultUtils.cs @@ -3,23 +3,22 @@ using System.Text; using CSiAPIv1; -namespace ConnectorCSIShared.Util +namespace ConnectorCSIShared.Util; + +internal static class ResultUtils { - internal static class ResultUtils + public static List GetNamesOfAllLoadCasesAndCombos(cSapModel sapModel) { - public static List GetNamesOfAllLoadCasesAndCombos(cSapModel sapModel) - { - List names = new(); + List names = new(); - int numberOfLoadCombinations = 0; - string[] loadCombinationNames = Array.Empty(); - sapModel.RespCombo.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); - names.AddRange(loadCombinationNames); + int numberOfLoadCombinations = 0; + string[] loadCombinationNames = Array.Empty(); + sapModel.RespCombo.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); + names.AddRange(loadCombinationNames); - sapModel.LoadCases.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); - names.AddRange(loadCombinationNames); + sapModel.LoadCases.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); + names.AddRange(loadCombinationNames); - return names; - } + return names; } } diff --git a/ConnectorCSI/ConnectorCSIShared/cPlugin.cs b/ConnectorCSI/ConnectorCSIShared/cPlugin.cs index a1131185bb..bde6185d0d 100644 --- a/ConnectorCSI/ConnectorCSIShared/cPlugin.cs +++ b/ConnectorCSI/ConnectorCSIShared/cPlugin.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using DesktopUI2.ViewModels; using DesktopUI2.Views; @@ -13,114 +13,117 @@ using System.IO; using Speckle.Core.Logging; -namespace SpeckleConnectorCSI +namespace SpeckleConnectorCSI; + +public class cPlugin { - public class cPlugin - { - public static cPluginCallback pluginCallback { get; set; } - public static bool isSpeckleClosed { get; set; } = false; - public Timer SelectionTimer; - public static cSapModel model { get; set; } + public static cPluginCallback pluginCallback { get; set; } + public static bool isSpeckleClosed { get; set; } = false; + public Timer SelectionTimer; + public static cSapModel model { get; set; } - public static Window MainWindow { get; private set; } + public static Window MainWindow { get; private set; } - public static ConnectorBindingsCSI Bindings { get; set; } + public static ConnectorBindingsCSI Bindings { get; set; } - public static AppBuilder BuildAvaloniaApp() => - AppBuilder - .Configure() - .UsePlatformDetect() - .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) - .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) - .LogToTrace() - .UseReactiveUI(); + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() + .UsePlatformDetect() + .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) + .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) + .LogToTrace() + .UseReactiveUI(); - public static void CreateOrFocusSpeckle() + public static void CreateOrFocusSpeckle() + { + if (MainWindow == null) { - if (MainWindow == null) - { - BuildAvaloniaApp().Start(AppMain, null); - } - - MainWindow.Show(); - MainWindow.Activate(); + BuildAvaloniaApp().Start(AppMain, null); } - private static void AppMain(Application app, string[] args) - { - var viewModel = new MainViewModel(Bindings); + MainWindow.Show(); + MainWindow.Activate(); + } - var streams = Bindings.GetStreamsInFile(); - streams = streams ?? new List(); - Bindings.UpdateSavedStreams?.Invoke(streams); + private static void AppMain(Application app, string[] args) + { + var viewModel = new MainViewModel(Bindings); - MainWindow = new MainWindow { DataContext = viewModel }; - MainWindow.Closed += SpeckleWindowClosed; - MainWindow.Closing += SpeckleWindowClosed; - app.Run(MainWindow); - //Task.Run(() => app.Run(MainWindow)); - } + var streams = Bindings.GetStreamsInFile(); + streams = streams ?? new List(); + Bindings.UpdateSavedStreams?.Invoke(streams); - public static void OpenOrFocusSpeckle(cSapModel model) - { - Bindings = new ConnectorBindingsCSI(model); - Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); - CreateOrFocusSpeckle(); - } + MainWindow = new MainWindow { DataContext = viewModel }; + MainWindow.Closed += SpeckleWindowClosed; + MainWindow.Closing += SpeckleWindowClosed; + app.Run(MainWindow); + //Task.Run(() => app.Run(MainWindow)); + } - private static void SpeckleWindowClosed(object sender, EventArgs e) + public static void OpenOrFocusSpeckle(cSapModel model) + { + Bindings = new ConnectorBindingsCSI(model); + Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); + CreateOrFocusSpeckle(); + } + + private static void SpeckleWindowClosed(object sender, EventArgs e) + { + isSpeckleClosed = true; + Process[] processCollection = Process.GetProcesses(); + foreach (Process p in processCollection) { - isSpeckleClosed = true; - Process[] processCollection = Process.GetProcesses(); - foreach (Process p in processCollection) + if (p.ProcessName == "DriverCSharp") { - if (p.ProcessName == "DriverCSharp") - Environment.Exit(0); + Environment.Exit(0); } - //Environment.Exit(0); - pluginCallback.Finish(0); - } - - public int Info(ref string Text) - { - Text = "This is a Speckle plugin for CSI Products"; - return 0; } + //Environment.Exit(0); + pluginCallback.Finish(0); + } - public static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) - { - Assembly a = null; - var name = args.Name.Split(',')[0]; - string path = Path.GetDirectoryName(typeof(cPlugin).Assembly.Location); + public int Info(ref string Text) + { + Text = "This is a Speckle plugin for CSI Products"; + return 0; + } - string assemblyFile = Path.Combine(path, name + ".dll"); + public static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly a = null; + var name = args.Name.Split(',')[0]; + string path = Path.GetDirectoryName(typeof(cPlugin).Assembly.Location); - if (File.Exists(assemblyFile)) - a = Assembly.LoadFrom(assemblyFile); + string assemblyFile = Path.Combine(path, name + ".dll"); - return a; + if (File.Exists(assemblyFile)) + { + a = Assembly.LoadFrom(assemblyFile); } - public void Main(ref cSapModel SapModel, ref cPluginCallback ISapPlugin) - { - cSapModel model; - pluginCallback = ISapPlugin; - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); - model = SapModel; - AppDomain domain = null; + return a; + } - try - { - OpenOrFocusSpeckle(model); - } - catch (Exception e) - { - throw; - ISapPlugin.Finish(0); - //return; - } + public void Main(ref cSapModel SapModel, ref cPluginCallback ISapPlugin) + { + cSapModel model; + pluginCallback = ISapPlugin; + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); + model = SapModel; + AppDomain domain = null; - return; + try + { + OpenOrFocusSpeckle(model); + } + catch (Exception e) + { + throw; + ISapPlugin.Finish(0); + //return; } + + return; } } diff --git a/ConnectorCSI/ConnectorSAP2000/Properties/AssemblyInfo.cs b/ConnectorCSI/ConnectorSAP2000/Properties/AssemblyInfo.cs index a9a902fdd6..0c2e52ed9d 100644 --- a/ConnectorCSI/ConnectorSAP2000/Properties/AssemblyInfo.cs +++ b/ConnectorCSI/ConnectorSAP2000/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/ConnectorCSI/DriverCSharp/PluginCallback.cs b/ConnectorCSI/DriverCSharp/PluginCallback.cs index 671df0a684..f9444d15e3 100644 --- a/ConnectorCSI/DriverCSharp/PluginCallback.cs +++ b/ConnectorCSI/DriverCSharp/PluginCallback.cs @@ -1,26 +1,25 @@ -using CSiAPIv1; +using CSiAPIv1; -namespace DriverCSharp +namespace DriverCSharp; + +class PluginCallback : cPluginCallback { - class PluginCallback : cPluginCallback - { - private bool m_IsFinished; - private int m_ErrorFlag; + private bool m_IsFinished; + private int m_ErrorFlag; - public int ErrorFlag - { - get { return m_ErrorFlag; } - } + public int ErrorFlag + { + get { return m_ErrorFlag; } + } - public bool Finished - { - get { return m_IsFinished; } - } + public bool Finished + { + get { return m_IsFinished; } + } - public void Finish(int iVal) - { - m_IsFinished = true; - m_ErrorFlag = iVal; - } + public void Finish(int iVal) + { + m_IsFinished = true; + m_ErrorFlag = iVal; } } diff --git a/ConnectorCSI/DriverCSharp/Program.cs b/ConnectorCSI/DriverCSharp/Program.cs index 2ddae118e7..259504b593 100644 --- a/ConnectorCSI/DriverCSharp/Program.cs +++ b/ConnectorCSI/DriverCSharp/Program.cs @@ -1,132 +1,141 @@ -using System; +using System; using System.Diagnostics; using System.Linq; using System.Windows.Forms; using CSiAPIv1; using SpeckleConnectorCSI; -namespace DriverCSharp +namespace DriverCSharp; + +class Program { - class Program - { - private const string ProgID_SAP2000 = "CSI.SAP2000.API.SapObject"; - private const string ProgID_ETABS = "CSI.ETABS.API.ETABSObject"; - private const string ProgID_CSiBridge = "CSI.CSiBridge.API.SapObject"; - private const string ProgID_SAFE = "CSI.SAFE.API.SAFEObject"; + private const string ProgID_SAP2000 = "CSI.SAP2000.API.SapObject"; + private const string ProgID_ETABS = "CSI.ETABS.API.ETABSObject"; + private const string ProgID_CSiBridge = "CSI.CSiBridge.API.SapObject"; + private const string ProgID_SAFE = "CSI.SAFE.API.SAFEObject"; - static int Main(string[] args) - { + static int Main(string[] args) + { #if DEBUG - Debugger.Launch(); + Debugger.Launch(); #endif - //MessageBox.Show("Starting DriverCSharp"); + //MessageBox.Show("Starting DriverCSharp"); - // dimension the SapObject as cOAPI type - cOAPI mySapObject = null; + // dimension the SapObject as cOAPI type + cOAPI mySapObject = null; - // Use ret to check if functions return successfully (ret = 0) or fail (ret = nonzero) - int ret = -1; + // Use ret to check if functions return successfully (ret = 0) or fail (ret = nonzero) + int ret = -1; - // create API helper object - cHelper myHelper = null; + // create API helper object + cHelper myHelper = null; - try + try + { + myHelper = new Helper(); + } + catch (Exception ex) + { + MessageBox.Show("Cannot create an instance of the Helper object: " + ex.Message); + ret = -1; + return ret; + } + + // attach to a running program instance + try + { + // get the active SapObject + // determine program type + string progID = null; + string[] arguments = Environment.GetCommandLineArgs(); + + if (arguments.Count() > 1) { - myHelper = new Helper(); + string arg = arguments[1]; + if (string.Compare(arg, "SAP2000", true) == 0) + { + progID = ProgID_SAP2000; + } + else if (string.Compare(arg, "ETABS", true) == 0) + { + progID = ProgID_ETABS; + } + else if (string.Compare(arg, "SAFE", true) == 0) + { + progID = ProgID_SAFE; + } + else if (string.Compare(arg, "CSiBridge", true) == 0) + { + progID = ProgID_CSiBridge; + } } - catch (Exception ex) + + if (progID != null) { - MessageBox.Show("Cannot create an instance of the Helper object: " + ex.Message); - ret = -1; - return ret; + mySapObject = myHelper.GetObject(progID); } - - // attach to a running program instance - try + else { - // get the active SapObject - // determine program type - string progID = null; - string[] arguments = Environment.GetCommandLineArgs(); - - if (arguments.Count() > 1) + // missing/unknown program type, try one by one + try { - string arg = arguments[1]; - if (string.Compare(arg, "SAP2000", true) == 0) - progID = ProgID_SAP2000; - else if (string.Compare(arg, "ETABS", true) == 0) - progID = ProgID_ETABS; - else if (string.Compare(arg, "SAFE", true) == 0) - progID = ProgID_SAFE; - else if (string.Compare(arg, "CSiBridge", true) == 0) - progID = ProgID_CSiBridge; + progID = ProgID_SAP2000; + mySapObject = myHelper.GetObject(progID); } + catch (Exception ex) { } - if (progID != null) - mySapObject = myHelper.GetObject(progID); - else + if (mySapObject == null) { - // missing/unknown program type, try one by one try { - progID = ProgID_SAP2000; + progID = ProgID_ETABS; mySapObject = myHelper.GetObject(progID); } catch (Exception ex) { } - - if (mySapObject == null) - { - try - { - progID = ProgID_ETABS; - mySapObject = myHelper.GetObject(progID); - } - catch (Exception ex) { } - } - if (mySapObject == null) + } + if (mySapObject == null) + { + try { - try - { - progID = ProgID_CSiBridge; - mySapObject = myHelper.GetObject(progID); - } - catch (Exception ex) { } + progID = ProgID_CSiBridge; + mySapObject = myHelper.GetObject(progID); } + catch (Exception ex) { } } } - catch (Exception ex) - { - MessageBox.Show("No running instance of the program found or failed to attach: " + ex.Message); - - ret = -2; - return ret; - } + } + catch (Exception ex) + { + MessageBox.Show("No running instance of the program found or failed to attach: " + ex.Message); - // Get a reference to cSapModel to access all API classes and functions - cSapModel mySapModel = mySapObject.SapModel; + ret = -2; + return ret; + } - // call Speckle plugin - try - { - cPlugin p = new cPlugin(); - cPluginCallback cb = new PluginCallback(); + // Get a reference to cSapModel to access all API classes and functions + cSapModel mySapModel = mySapObject.SapModel; - // DO NOT return from SpeckleConnectorETABS.cPlugin.Main() until all work is done. - p.Main(ref mySapModel, ref cb); - if (cb.Finished == true) - { - Environment.Exit(0); - } + // call Speckle plugin + try + { + cPlugin p = new(); + cPluginCallback cb = new PluginCallback(); - return cb.ErrorFlag; - } - catch (Exception ex) + // DO NOT return from SpeckleConnectorETABS.cPlugin.Main() until all work is done. + p.Main(ref mySapModel, ref cb); + if (cb.Finished == true) { - MessageBox.Show("Failed to call plugin: " + ex.Message); - - ret = -3; - return ret; + Environment.Exit(0); } + + return cb.ErrorFlag; + } + catch (Exception ex) + { + MessageBox.Show("Failed to call plugin: " + ex.Message); + + ret = -3; + return ret; } } } diff --git a/ConnectorCSI/DriverPluginCSharp/cPlugin.cs b/ConnectorCSI/DriverPluginCSharp/cPlugin.cs index 88a78526a4..e0d0239c86 100644 --- a/ConnectorCSI/DriverPluginCSharp/cPlugin.cs +++ b/ConnectorCSI/DriverPluginCSharp/cPlugin.cs @@ -1,66 +1,65 @@ -using System; +using System; using System.Diagnostics; using System.Threading.Tasks; using CSiAPIv1; -namespace SpeckleConnector +namespace SpeckleConnector; + +public class cPlugin { - public class cPlugin - { - private cSapModel m_SapModel; - private cPluginCallback m_PluginCallback; - private Process connectorProcess; + private cSapModel m_SapModel; + private cPluginCallback m_PluginCallback; + private Process connectorProcess; - public void Main(ref cSapModel SapModel, ref cPluginCallback ISapPlugin) - { - m_SapModel = SapModel; - m_PluginCallback = ISapPlugin; + public void Main(ref cSapModel SapModel, ref cPluginCallback ISapPlugin) + { + m_SapModel = SapModel; + m_PluginCallback = ISapPlugin; - string appPath = (new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase)).LocalPath; - appPath = System.IO.Path.GetDirectoryName(appPath); - appPath = System.IO.Path.Combine(appPath, "DriverCSharp.exe"); + string appPath = (new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase)).LocalPath; + appPath = System.IO.Path.GetDirectoryName(appPath); + appPath = System.IO.Path.Combine(appPath, "DriverCSharp.exe"); - Process currentProcess = Process.GetCurrentProcess(); - string guiType = System.IO.Path.GetFileNameWithoutExtension(currentProcess.ProcessName); + Process currentProcess = Process.GetCurrentProcess(); + string guiType = System.IO.Path.GetFileNameWithoutExtension(currentProcess.ProcessName); - connectorProcess = new Process(); - { - var withBlock = connectorProcess.StartInfo; - withBlock.CreateNoWindow = true; - withBlock.FileName = appPath; - withBlock.UseShellExecute = false; - withBlock.Arguments = guiType; - } + connectorProcess = new Process(); + { + var withBlock = connectorProcess.StartInfo; + withBlock.CreateNoWindow = true; + withBlock.FileName = appPath; + withBlock.UseShellExecute = false; + withBlock.Arguments = guiType; + } - connectorProcess.Start(); + connectorProcess.Start(); - // wait a few seconds for the Speckle connector to launch before showing the "plugin successful" UI - Task.Delay(4000).Wait(); + // wait a few seconds for the Speckle connector to launch before showing the "plugin successful" UI + Task.Delay(4000).Wait(); - // we need to immediately call this or else the program UI will be blocked by the connector process which will cause API calls to hang - m_PluginCallback.Finish(0); + // we need to immediately call this or else the program UI will be blocked by the connector process which will cause API calls to hang + m_PluginCallback.Finish(0); - // setup events - connectorProcess.EnableRaisingEvents = true; - connectorProcess.Exited += ConnectorProcess_Exited; - System.Windows.Forms.Application.ApplicationExit += Application_ApplicationExit; - } + // setup events + connectorProcess.EnableRaisingEvents = true; + connectorProcess.Exited += ConnectorProcess_Exited; + System.Windows.Forms.Application.ApplicationExit += Application_ApplicationExit; + } - private void ConnectorProcess_Exited(object sender, EventArgs e) - { - // unsubscribe from the event because the "closeMainWindow" will throw an error if the process has already exited - System.Windows.Forms.Application.ApplicationExit -= Application_ApplicationExit; - } + private void ConnectorProcess_Exited(object sender, EventArgs e) + { + // unsubscribe from the event because the "closeMainWindow" will throw an error if the process has already exited + System.Windows.Forms.Application.ApplicationExit -= Application_ApplicationExit; + } - private void Application_ApplicationExit(object sender, EventArgs e) - { - connectorProcess?.CloseMainWindow(); - } + private void Application_ApplicationExit(object sender, EventArgs e) + { + connectorProcess?.CloseMainWindow(); + } - public int Info(ref string Text) - { - Text = "This is a Speckle plugin for CSI Products"; - return 0; - } + public int Info(ref string Text) + { + Text = "This is a Speckle plugin for CSI Products"; + return 0; } } diff --git a/ConnectorCore/BatchUploader.OperationDriver/BatchUploadOperationDriver.cs b/ConnectorCore/BatchUploader.OperationDriver/BatchUploadOperationDriver.cs index d99e133b64..b3266f2c97 100644 --- a/ConnectorCore/BatchUploader.OperationDriver/BatchUploadOperationDriver.cs +++ b/ConnectorCore/BatchUploader.OperationDriver/BatchUploadOperationDriver.cs @@ -96,7 +96,9 @@ private void AddProgressListener(Guid jobId, ProgressViewModel viewModel) viewModel.PropertyChanged += (_, p) => { if (p.PropertyName is not (nameof(ProgressViewModel.Value) or nameof(ProgressViewModel.Max))) + { return; + } Task.Run(() => OnProgressUpdate(jobId, viewModel)); }; @@ -107,7 +109,9 @@ private async Task OnProgressUpdate(Guid jobId, ProgressViewModel viewModel) //Check for cancel var status = await _client.GetJobStatus(jobId).ConfigureAwait(false); if (status is JobStatus.Cancelled or JobStatus.Failed) + { viewModel.CancellationTokenSource.Cancel(); + } //Update Progress JobProgress newProgress = new((long)viewModel.Value, (long)viewModel.Max); diff --git a/ConnectorCore/BatchUploader.Sdk/BatchUploaderClient.cs b/ConnectorCore/BatchUploader.Sdk/BatchUploaderClient.cs index 8e60e53c96..d85845b1b6 100644 --- a/ConnectorCore/BatchUploader.Sdk/BatchUploaderClient.cs +++ b/ConnectorCore/BatchUploader.Sdk/BatchUploaderClient.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using System.Text.Json; using Speckle.BatchUploader.Sdk.CommunicationModels; diff --git a/ConnectorCore/BatchUploader.Sdk/Interfaces/IApplicationFunctionalityController.cs b/ConnectorCore/BatchUploader.Sdk/Interfaces/IApplicationFunctionalityController.cs index d430f397b6..3700cd54eb 100644 --- a/ConnectorCore/BatchUploader.Sdk/Interfaces/IApplicationFunctionalityController.cs +++ b/ConnectorCore/BatchUploader.Sdk/Interfaces/IApplicationFunctionalityController.cs @@ -1,4 +1,4 @@ -namespace Speckle.BatchUploader.Sdk.Interfaces; +namespace Speckle.BatchUploader.Sdk.Interfaces; public interface IApplicationFunctionalityController { diff --git a/ConnectorDynamo/ConnectorDynamo/AccountsNode/Accounts.cs b/ConnectorDynamo/ConnectorDynamo/AccountsNode/Accounts.cs index 1a7a9f60c0..4f67cb4317 100644 --- a/ConnectorDynamo/ConnectorDynamo/AccountsNode/Accounts.cs +++ b/ConnectorDynamo/ConnectorDynamo/AccountsNode/Accounts.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -10,126 +10,132 @@ using Speckle.Core.Logging; using Account = Speckle.Core.Credentials.Account; -namespace Speckle.ConnectorDynamo.AccountsNode +namespace Speckle.ConnectorDynamo.AccountsNode; + +/// +/// List Accounts +/// +[NodeName("Select")] +[NodeCategory("Speckle 2.Account.Create")] +[NodeDescription("Select a Speckle account")] +[NodeSearchTags("accounts", "speckle")] +[IsDesignScriptCompatible] +public class Accounts : NodeModel { + public string SelectedUserId = ""; + private ObservableCollection _accountList = new(); + /// - /// List Accounts + /// UI Binding /// - [NodeName("Select")] - [NodeCategory("Speckle 2.Account.Create")] - [NodeDescription("Select a Speckle account")] - [NodeSearchTags("accounts", "speckle")] - [IsDesignScriptCompatible] - public class Accounts : NodeModel + [JsonIgnore] + public ObservableCollection AccountList { - public string SelectedUserId = ""; - private ObservableCollection _accountList = new ObservableCollection(); - - /// - /// UI Binding - /// - [JsonIgnore] - public ObservableCollection AccountList + get => _accountList; + set { - get => _accountList; - set - { - _accountList = value; - RaisePropertyChanged("AccountList"); - } + _accountList = value; + RaisePropertyChanged("AccountList"); } + } - private Account _selectedAccount; + private Account _selectedAccount; - /// - /// UI Binding - /// - [JsonIgnore] - public Account SelectedAccount + /// + /// UI Binding + /// + [JsonIgnore] + public Account SelectedAccount + { + get => _selectedAccount; + set { - get => _selectedAccount; - set - { - _selectedAccount = value; - RaisePropertyChanged("SelectedAccount"); - } + _selectedAccount = value; + RaisePropertyChanged("SelectedAccount"); } + } - - /// - /// JSON constructor, called on file open - /// - /// - /// - [JsonConstructor] - private Accounts(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) + /// + /// JSON constructor, called on file open + /// + /// + /// + [JsonConstructor] + private Accounts(IEnumerable inPorts, IEnumerable outPorts) + : base(inPorts, outPorts) + { + if (outPorts.Count() == 0) { - if (outPorts.Count() == 0) - AddOutputs(); - - ArgumentLacing = LacingStrategy.Disabled; + AddOutputs(); } - /// - /// Normal constructor, called when adding node to canvas - /// - public Accounts() - { - AddOutputs(); + ArgumentLacing = LacingStrategy.Disabled; + } - RegisterAllPorts(); - ArgumentLacing = LacingStrategy.Disabled; - } + /// + /// Normal constructor, called when adding node to canvas + /// + public Accounts() + { + AddOutputs(); - private void AddOutputs() - { - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("account", "Selected account"))); - } + RegisterAllPorts(); + ArgumentLacing = LacingStrategy.Disabled; + } - internal void RestoreSelection() + private void AddOutputs() + { + OutPorts.Add(new PortModel(PortType.Output, this, new PortData("account", "Selected account"))); + } + + internal void RestoreSelection() + { + AccountList = new ObservableCollection(AccountManager.GetAccounts()); + if (AccountList.Count == 0) { - AccountList = new ObservableCollection(AccountManager.GetAccounts()); - if (AccountList.Count == 0) - { - Warning("No accounts found. Please use the Speckle Manager to manage your accounts on this computer."); - SelectedAccount = null; - SelectedUserId = ""; - return; - } - - SelectedAccount = !string.IsNullOrEmpty(SelectedUserId) - ? AccountList.FirstOrDefault(x => x.userInfo.id == SelectedUserId) - : AccountList.FirstOrDefault(x => x.isDefault); + Warning("No accounts found. Please use the Speckle Manager to manage your accounts on this computer."); + SelectedAccount = null; + SelectedUserId = ""; + return; } - internal void SelectionChanged(Account account) - { - SelectedUserId = account.userInfo.id; + SelectedAccount = !string.IsNullOrEmpty(SelectedUserId) + ? AccountList.FirstOrDefault(x => x.userInfo.id == SelectedUserId) + : AccountList.FirstOrDefault(x => x.isDefault); + } - Analytics.TrackEvent(account, Analytics.Events.NodeRun, new Dictionary() { { "name", "Account Select" } }); + internal void SelectionChanged(Account account) + { + SelectedUserId = account.userInfo.id; - OnNodeModified(true); - } + Analytics.TrackEvent( + account, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Account Select" } } + ); - #region overrides + OnNodeModified(true); + } - /// - /// Returns the selected account if found - /// NOTE: if an account is deleted via the account manager after being selected in this node and saved - /// upon open it will return null - /// - /// - /// - public override IEnumerable BuildOutputAst(List inputAstNodes) - { - var id = SelectedUserId ?? ""; - var functionCall = AstFactory.BuildFunctionCall( - new Func(Functions.Account.GetById), - new List { AstFactory.BuildStringNode(id) }); + #region overrides - return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), functionCall) }; - } + /// + /// Returns the selected account if found + /// NOTE: if an account is deleted via the account manager after being selected in this node and saved + /// upon open it will return null + /// + /// + /// + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + var id = SelectedUserId ?? ""; + var functionCall = AstFactory.BuildFunctionCall( + new Func(Functions.Account.GetById), + new List { AstFactory.BuildStringNode(id) } + ); - #endregion + return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), functionCall) }; } + + #endregion } diff --git a/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsUi.xaml.cs b/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsUi.xaml.cs index e937b523d9..eecd8d095b 100644 --- a/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsUi.xaml.cs +++ b/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsUi.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,16 +13,15 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace Speckle.ConnectorDynamo.AccountsNode +namespace Speckle.ConnectorDynamo.AccountsNode; + +/// +/// Interaction logic for AccountsUi.xaml +/// +public partial class AccountsUi : UserControl { - /// - /// Interaction logic for AccountsUi.xaml - /// - public partial class AccountsUi : UserControl + public AccountsUi() { - public AccountsUi() - { - InitializeComponent(); - } + InitializeComponent(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsViewCustomization.cs b/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsViewCustomization.cs index 26a137e3e3..20b99ab0e7 100644 --- a/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsViewCustomization.cs +++ b/ConnectorDynamo/ConnectorDynamo/AccountsNode/AccountsViewCustomization.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dynamo.Configuration; using Dynamo.Controls; using Dynamo.Models; @@ -11,55 +11,56 @@ using System.Windows.Threading; using Speckle.Core.Credentials; -namespace Speckle.ConnectorDynamo.AccountsNode -{ - public class AccountsViewCustomization : INodeViewCustomization - { +namespace Speckle.ConnectorDynamo.AccountsNode; - private DynamoViewModel dynamoViewModel; - private DispatcherSynchronizationContext syncContext; - private Accounts accountsNode; - private DynamoModel dynamoModel; +public class AccountsViewCustomization : INodeViewCustomization +{ + private DynamoViewModel dynamoViewModel; + private DispatcherSynchronizationContext syncContext; + private Accounts accountsNode; + private DynamoModel dynamoModel; - public void CustomizeView(Accounts model, NodeView nodeView) - { - dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; - dynamoViewModel = nodeView.ViewModel.DynamoViewModel; - syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); - accountsNode = model; + public void CustomizeView(Accounts model, NodeView nodeView) + { + dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; + dynamoViewModel = nodeView.ViewModel.DynamoViewModel; + syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); + accountsNode = model; - var ui = new AccountsUi(); - nodeView.inputGrid.Children.Add(ui); + var ui = new AccountsUi(); + nodeView.inputGrid.Children.Add(ui); - //bindings - ui.DataContext = model; - ui.Loaded += Loaded; - ui.AccountsComboBox.SelectionChanged += SelectionChanged; - ui.AccountsComboBox.DropDownOpened += AccountsComboBoxOnDropDownOpened; + //bindings + ui.DataContext = model; + ui.Loaded += Loaded; + ui.AccountsComboBox.SelectionChanged += SelectionChanged; + ui.AccountsComboBox.DropDownOpened += AccountsComboBoxOnDropDownOpened; + } - } + private void AccountsComboBoxOnDropDownOpened(object sender, EventArgs e) + { + accountsNode.ClearErrorsAndWarnings(); + accountsNode.RestoreSelection(); + } - private void AccountsComboBoxOnDropDownOpened(object sender, EventArgs e) + private void Loaded(object o, RoutedEventArgs a) + { + Task.Run(async () => { - accountsNode.ClearErrorsAndWarnings(); accountsNode.RestoreSelection(); - } - - private void Loaded(object o, RoutedEventArgs a) - { - Task.Run(async () => { accountsNode.RestoreSelection(); }); - } + }); + } - private void SelectionChanged(object sender, SelectionChangedEventArgs e) + private void SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (e.AddedItems.Count == 0) { - if(e.AddedItems.Count ==0) - return; - var account = e.AddedItems[0] as Account; - accountsNode.SelectionChanged(account); + return; } - - - public void Dispose() { } + var account = e.AddedItems[0] as Account; + accountsNode.SelectionChanged(account); } + + public void Dispose() { } } diff --git a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStream.cs b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStream.cs index 77efa42ee7..40f25e3941 100644 --- a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStream.cs +++ b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -12,178 +12,190 @@ using Speckle.Core.Logging; using Account = Speckle.Core.Credentials.Account; -namespace Speckle.ConnectorDynamo.CreateStreamNode +namespace Speckle.ConnectorDynamo.CreateStreamNode; + +/// +/// Create Stream +/// +[NodeName("Create Stream")] +[NodeCategory("Speckle 2.Stream.Create")] +[NodeDescription("Create a new Speckle Stream")] +[NodeSearchTags("stream", "create", "speckle")] +[IsDesignScriptCompatible] +public class CreateStream : NodeModel { + private bool _createEnabled = true; + + private ObservableCollection _accountList = new(); + /// - /// Create Stream + /// Current Stream /// - [NodeName("Create Stream")] - [NodeCategory("Speckle 2.Stream.Create")] - [NodeDescription("Create a new Speckle Stream")] - [NodeSearchTags("stream", "create", "speckle")] - [IsDesignScriptCompatible] - public class CreateStream : NodeModel - { - private bool _createEnabled = true; + public StreamWrapper Stream { get; set; } - private ObservableCollection _accountList = new ObservableCollection(); + public string SelectedUserId = ""; - /// - /// Current Stream - /// - public StreamWrapper Stream { get; set; } - - public string SelectedUserId = ""; + /// + /// UI Binding + /// + [JsonIgnore] + public ObservableCollection AccountList + { + get => _accountList; + set + { + _accountList = value; + RaisePropertyChanged("AccountList"); + } + } + private Account _selectedAccount; - /// - /// UI Binding - /// - [JsonIgnore] - public ObservableCollection AccountList + /// + /// UI Binding + /// + [JsonIgnore] + public Account SelectedAccount + { + get => _selectedAccount; + set { - get => _accountList; - set - { - _accountList = value; - RaisePropertyChanged("AccountList"); - } + _selectedAccount = value; + RaisePropertyChanged("SelectedAccount"); } + } - private Account _selectedAccount; - - /// - /// UI Binding - /// - [JsonIgnore] - public Account SelectedAccount + /// + /// UI Binding + /// + public bool CreateEnabled + { + get => _createEnabled; + set { - get => _selectedAccount; - set - { - _selectedAccount = value; - RaisePropertyChanged("SelectedAccount"); - } + _createEnabled = value; + RaisePropertyChanged("CreateEnabled"); } + } - /// - /// UI Binding - /// - public bool CreateEnabled + /// + /// JSON constructor, called on file open + /// + /// + /// + [JsonConstructor] + private CreateStream(IEnumerable inPorts, IEnumerable outPorts) + : base(inPorts, outPorts) + { + if (outPorts.Count() == 0) { - get => _createEnabled; - set - { - _createEnabled = value; - RaisePropertyChanged("CreateEnabled"); - } + AddOutputs(); } + ArgumentLacing = LacingStrategy.Disabled; + } - /// - /// JSON constructor, called on file open - /// - /// - /// - [JsonConstructor] - private CreateStream(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) - { - if (outPorts.Count() == 0) - AddOutputs(); + /// + /// Normal constructor, called when adding node to canvas + /// + public CreateStream() + { + AddOutputs(); - ArgumentLacing = LacingStrategy.Disabled; - } + RegisterAllPorts(); + ArgumentLacing = LacingStrategy.Disabled; + } - /// - /// Normal constructor, called when adding node to canvas - /// - public CreateStream() - { - AddOutputs(); + private void AddOutputs() + { + OutPorts.Add(new PortModel(PortType.Output, this, new PortData("stream", "The new Stream"))); + } - RegisterAllPorts(); - ArgumentLacing = LacingStrategy.Disabled; + internal void RestoreSelection() + { + AccountList = new ObservableCollection(AccountManager.GetAccounts()); + if (AccountList.Count == 0) + { + Warning("No accounts found. Please use the Speckle Manager to manage your accounts on this computer."); + SelectedAccount = null; + SelectedUserId = ""; + return; } - private void AddOutputs() + SelectedAccount = !string.IsNullOrEmpty(SelectedUserId) + ? AccountList.FirstOrDefault(x => x.userInfo.id == SelectedUserId) + : AccountList.FirstOrDefault(x => x.isDefault); + } + + internal void DoCreateStream() + { + ClearErrorsAndWarnings(); + + if (SelectedAccount == null) { - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("stream", "The new Stream"))); + Error("An account must be selected."); + return; } - internal void RestoreSelection() + var client = new Client(SelectedAccount); + try { - AccountList = new ObservableCollection(AccountManager.GetAccounts()); - if (AccountList.Count == 0) - { - Warning("No accounts found. Please use the Speckle Manager to manage your accounts on this computer."); - SelectedAccount = null; - SelectedUserId = ""; - return; - } + var res = client.StreamCreate(new StreamCreateInput { isPublic = false }).Result; - SelectedAccount = !string.IsNullOrEmpty(SelectedUserId) - ? AccountList.FirstOrDefault(x => x.userInfo.id == SelectedUserId) - : AccountList.FirstOrDefault(x => x.isDefault); - } + Stream = new StreamWrapper(res, SelectedAccount.userInfo.id, SelectedAccount.serverInfo.url); + CreateEnabled = false; + SelectedUserId = SelectedAccount.userInfo.id; - internal void DoCreateStream() - { - ClearErrorsAndWarnings(); + this.Name = "Stream Created"; + + Analytics.TrackEvent( + SelectedAccount, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Stream Create" } } + ); - if (SelectedAccount == null) + OnNodeModified(true); + } + catch (Exception ex) + { + //someone improve this pls :) + if (ex.InnerException != null && ex.InnerException.InnerException != null) { - Error("An account must be selected."); - return; + Error(ex.InnerException.InnerException.Message); } - var client = new Client(SelectedAccount); - try + if (ex.InnerException != null) { - var res = client.StreamCreate(new StreamCreateInput { isPublic = false }).Result; - - Stream = new StreamWrapper(res, SelectedAccount.userInfo.id, SelectedAccount.serverInfo.url); - CreateEnabled = false; - SelectedUserId = SelectedAccount.userInfo.id; - - this.Name = "Stream Created"; - - Analytics.TrackEvent(SelectedAccount, Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream Create" } }); - - OnNodeModified(true); + Error(ex.InnerException.Message); } - catch (Exception ex) + else { - //someone improve this pls :) - if (ex.InnerException != null && ex.InnerException.InnerException != null) - Error(ex.InnerException.InnerException.Message); - if (ex.InnerException != null) - Error(ex.InnerException.Message); - else - Error(ex.Message); - + Error(ex.Message); } - } + } - #region overrides + #region overrides - /// - /// Returns the StreamWrapper saved in this node - /// To create a new stream, a new node has to be placed - /// - /// - /// - public override IEnumerable BuildOutputAst(List inputAstNodes) + /// + /// Returns the StreamWrapper saved in this node + /// To create a new stream, a new node has to be placed + /// + /// + /// + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + if (Stream == null) { - if (Stream == null) - return OutPorts.Enumerate().Select(output => - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); - - var sw = AstFactory.BuildStringNode(Stream.ToString()); - - return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), sw) }; + return OutPorts + .Enumerate() + .Select(output => AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); } - #endregion + var sw = AstFactory.BuildStringNode(Stream.ToString()); + + return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), sw) }; } + + #endregion } diff --git a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamUi.xaml.cs b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamUi.xaml.cs index e015c23ef7..053a339788 100644 --- a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamUi.xaml.cs +++ b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamUi.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,16 +13,15 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace Speckle.ConnectorDynamo.CreateStreamNode +namespace Speckle.ConnectorDynamo.CreateStreamNode; + +/// +/// Interaction logic for AccountsUi.xaml +/// +public partial class CreateStreamUi : UserControl { - /// - /// Interaction logic for AccountsUi.xaml - /// - public partial class CreateStreamUi : UserControl + public CreateStreamUi() { - public CreateStreamUi() - { - InitializeComponent(); - } + InitializeComponent(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamViewCustomization.cs b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamViewCustomization.cs index 3c8f9f3278..39f8d56ce3 100644 --- a/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamViewCustomization.cs +++ b/ConnectorDynamo/ConnectorDynamo/CreateStreamNode/CreateStreamViewCustomization.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dynamo.Configuration; using Dynamo.Controls; using Dynamo.Models; @@ -11,77 +11,77 @@ using System.Windows.Threading; using Speckle.Core.Credentials; -namespace Speckle.ConnectorDynamo.CreateStreamNode +namespace Speckle.ConnectorDynamo.CreateStreamNode; + +public class CreateStreamViewCustomization : INodeViewCustomization { - public class CreateStreamViewCustomization : INodeViewCustomization + private DynamoViewModel dynamoViewModel; + private DispatcherSynchronizationContext syncContext; + private CreateStream createNode; + private DynamoModel dynamoModel; + private NodeView _nodeView; + + public void CustomizeView(CreateStream model, NodeView nodeView) { - private DynamoViewModel dynamoViewModel; - private DispatcherSynchronizationContext syncContext; - private CreateStream createNode; - private DynamoModel dynamoModel; - private NodeView _nodeView; + _nodeView = nodeView; + dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; + dynamoViewModel = nodeView.ViewModel.DynamoViewModel; + syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); + createNode = model; - public void CustomizeView(CreateStream model, NodeView nodeView) - { - _nodeView = nodeView; - dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; - dynamoViewModel = nodeView.ViewModel.DynamoViewModel; - syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); - createNode = model; + var ui = new CreateStreamUi(); + nodeView.inputGrid.Children.Add(ui); - var ui = new CreateStreamUi(); - nodeView.inputGrid.Children.Add(ui); + //bindings + ui.DataContext = model; + ui.Loaded += Loaded; + ui.CreateStreamButton.Click += CreateStreamButtonClick; + ui.AccountsComboBox.DropDownOpened += AccountsComboBoxOnDropDownOpened; - //bindings - ui.DataContext = model; - ui.Loaded += Loaded; - ui.CreateStreamButton.Click += CreateStreamButtonClick; - ui.AccountsComboBox.DropDownOpened += AccountsComboBoxOnDropDownOpened; + //nodeView.grid.ContextMenu.Items.Add(new Separator()); + } - //nodeView.grid.ContextMenu.Items.Add(new Separator()); - } + private void AccountsComboBoxOnDropDownOpened(object sender, EventArgs e) + { + createNode.ClearErrorsAndWarnings(); + createNode.RestoreSelection(); + } - private void AccountsComboBoxOnDropDownOpened(object sender, EventArgs e) + private void Loaded(object o, RoutedEventArgs a) + { + Task.Run(async () => { - createNode.ClearErrorsAndWarnings(); createNode.RestoreSelection(); - } - - private void Loaded(object o, RoutedEventArgs a) - { - Task.Run(async () => { createNode.RestoreSelection(); }); - } + }); + } - private void CreateStreamButtonClick(object sender, RoutedEventArgs e) + private void CreateStreamButtonClick(object sender, RoutedEventArgs e) + { + Task.Run(async () => { - Task.Run(async () => - { - createNode.DoCreateStream(); - UpdateContextMenu(); - }); - } + createNode.DoCreateStream(); + UpdateContextMenu(); + }); + } - private void UpdateContextMenu() + private void UpdateContextMenu() + { + createNode.DispatchOnUIThread(() => { - createNode.DispatchOnUIThread(() => + if (createNode.Stream != null) { - - if (createNode.Stream != null) + var viewStreamMenuItem = new MenuItem { - var viewStreamMenuItem = new MenuItem { Header = $"View stream {createNode.Stream.StreamId} @ {createNode.Stream.ServerUrl} online ↗" }; - viewStreamMenuItem.Click += (a, e) => - { - System.Diagnostics.Process.Start($"{createNode.Stream.ServerUrl}/streams/{createNode.Stream.StreamId}"); - }; - _nodeView.grid.ContextMenu.Items.Add(viewStreamMenuItem); - - } - }); - } - - - public void Dispose() - { - } + Header = $"View stream {createNode.Stream.StreamId} @ {createNode.Stream.ServerUrl} online ↗" + }; + viewStreamMenuItem.Click += (a, e) => + { + System.Diagnostics.Process.Start($"{createNode.Stream.ServerUrl}/streams/{createNode.Stream.StreamId}"); + }; + _nodeView.grid.ContextMenu.Items.Add(viewStreamMenuItem); + } + }); } + + public void Dispose() { } } diff --git a/ConnectorDynamo/ConnectorDynamo/DebounceTimer.cs b/ConnectorDynamo/ConnectorDynamo/DebounceTimer.cs index 54a05d1713..352b9327c4 100644 --- a/ConnectorDynamo/ConnectorDynamo/DebounceTimer.cs +++ b/ConnectorDynamo/ConnectorDynamo/DebounceTimer.cs @@ -1,49 +1,50 @@ -using System; +using System; using System.Timers; using System.Windows.Threading; -namespace Speckle.ConnectorDynamo +namespace Speckle.ConnectorDynamo; + +public class DebounceTimer { - public class DebounceTimer + private Timer timer; + + /// + /// Adapted from: https://weblog.west-wind.com/posts/2017/jul/02/debouncing-and-throttling-dispatcher-events + /// Debounce an event by resetting the event timeout every time the event is + /// fired. The behavior is that the Action passed is fired only after events + /// stop firing for the given timeout period. + /// + /// Use Debounce when you want events to fire only after events stop firing + /// after the given interval timeout period. + /// + /// Wrap the logic you would normally use in your event code into + /// the Action you pass to this method to debounce the event. + /// Example: https://gist.github.com/RickStrahl/0519b678f3294e27891f4d4f0608519a + /// + /// Timeout in Milliseconds + /// Action to fire when debounced event fires + public void Debounce(int interval, Action action) { - private Timer timer; + // kill pending timer and pending ticks + timer?.Stop(); + timer = null; - /// - /// Adapted from: https://weblog.west-wind.com/posts/2017/jul/02/debouncing-and-throttling-dispatcher-events - /// Debounce an event by resetting the event timeout every time the event is - /// fired. The behavior is that the Action passed is fired only after events - /// stop firing for the given timeout period. - /// - /// Use Debounce when you want events to fire only after events stop firing - /// after the given interval timeout period. - /// - /// Wrap the logic you would normally use in your event code into - /// the Action you pass to this method to debounce the event. - /// Example: https://gist.github.com/RickStrahl/0519b678f3294e27891f4d4f0608519a - /// - /// Timeout in Milliseconds - /// Action to fire when debounced event fires - public void Debounce(int interval, Action action) + // timer is recreated for each event and effectively + // resets the timeout. Action only fires after timeout has fully + // elapsed without other events firing in between + timer = new Timer(interval); + timer.Elapsed += delegate { - // kill pending timer and pending ticks - timer?.Stop(); - timer = null; - - // timer is recreated for each event and effectively - // resets the timeout. Action only fires after timeout has fully - // elapsed without other events firing in between - timer = new Timer(interval); - timer.Elapsed += delegate + if (timer == null) { - if (timer == null) - return; + return; + } - timer?.Stop(); - timer = null; - action.Invoke(); - }; + timer?.Stop(); + timer = null; + action.Invoke(); + }; - timer.Start(); - } + timer.Start(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/Receive.cs b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/Receive.cs index 316f24c522..9bea337c71 100644 --- a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/Receive.cs +++ b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/Receive.cs @@ -17,630 +17,660 @@ using Speckle.Core.Logging; using Speckle.Core.Models.Extensions; -namespace Speckle.ConnectorDynamo.ReceiveNode +namespace Speckle.ConnectorDynamo.ReceiveNode; + +/// +/// Receive data from Speckle +/// +[NodeName("Receive")] +[NodeCategory("Speckle 2")] +[NodeDescription("Receive data from a Speckle server")] +[NodeSearchTags("receive", "speckle")] +[IsDesignScriptCompatible] +public class Receive : NodeModel { - /// - /// Receive data from Speckle - /// - [NodeName("Receive")] - [NodeCategory("Speckle 2")] - [NodeDescription("Receive data from a Speckle server")] - [NodeSearchTags("receive", "speckle")] - [IsDesignScriptCompatible] - public class Receive : NodeModel - { - #region fields & props + #region fields & props - #region private fields & props + #region private fields & props - private bool _transmitting = false; - private string _message = ""; - private double _progress = 0; - private string _expiredCount = ""; - private bool _receiveEnabled = false; - private int _objectCount = 1; - private bool _hasOutput = false; - private bool _autoUpdate = false; - private bool _autoUpdateEnabled = true; - private CancellationTokenSource _cancellationToken; - private Client _client; + private bool _transmitting = false; + private string _message = ""; + private double _progress = 0; + private string _expiredCount = ""; + private bool _receiveEnabled = false; + private int _objectCount = 1; + private bool _hasOutput = false; + private bool _autoUpdate = false; + private bool _autoUpdateEnabled = true; + private CancellationTokenSource _cancellationToken; + private Client _client; - private List _errors = new List(); + private List _errors = new(); - private Client Client + private Client Client + { + get { - get + if (_client == null && Stream != null) { - if (_client == null && Stream != null) - { - var account = Stream.GetAccount().Result; - _client = new Client(account); - } - - return _client; + var account = Stream.GetAccount().Result; + _client = new Client(account); } - set { _client = value; } + + return _client; } + set { _client = value; } + } - #endregion + #endregion - #region public properties + #region public properties - /// - /// Current Stream - /// - public StreamWrapper Stream { get; set; } + /// + /// Current Stream + /// + public StreamWrapper Stream { get; set; } - /// - /// Latest Commit received - /// - public string LastCommitId { get; set; } + /// + /// Latest Commit received + /// + public string LastCommitId { get; set; } - #endregion + #endregion - #region ui bindings + #region ui bindings - /// - /// UI Binding - /// - [JsonIgnore] - public bool Transmitting + /// + /// UI Binding + /// + [JsonIgnore] + public bool Transmitting + { + get => _transmitting; + set { - get => _transmitting; - set - { - _transmitting = value; - RaisePropertyChanged("Transmitting"); - } + _transmitting = value; + RaisePropertyChanged("Transmitting"); } + } - /// - /// UI Binding - /// - [JsonIgnore] - public string Message + /// + /// UI Binding + /// + [JsonIgnore] + public string Message + { + get => _message; + set { - get => _message; - set - { - _message = value; - RaisePropertyChanged("Message"); - } + _message = value; + RaisePropertyChanged("Message"); } + } - /// - /// UI Binding - /// - [JsonIgnore] - public double Progress + /// + /// UI Binding + /// + [JsonIgnore] + public double Progress + { + get => _progress; + set { - get => _progress; - set - { - _progress = value; - RaisePropertyChanged("Progress"); - } + _progress = value; + RaisePropertyChanged("Progress"); } + } - /// - /// UI Binding - /// - public bool ReceiveEnabled + /// + /// UI Binding + /// + public bool ReceiveEnabled + { + get => _receiveEnabled; + set { - get => _receiveEnabled; - set - { - _receiveEnabled = value; - RaisePropertyChanged("ReceiveEnabled"); - } + _receiveEnabled = value; + RaisePropertyChanged("ReceiveEnabled"); } + } - //BINDINGS TO SAVE + //BINDINGS TO SAVE - /// - /// UI Binding - /// - public string ExpiredCount + /// + /// UI Binding + /// + public string ExpiredCount + { + get => _expiredCount; + set { - get => _expiredCount; - set - { - _expiredCount = value; - RaisePropertyChanged("ExpiredCount"); - } + _expiredCount = value; + RaisePropertyChanged("ExpiredCount"); } + } - /// - /// UI Binding - /// - public bool AutoUpdate + /// + /// UI Binding + /// + public bool AutoUpdate + { + get => _autoUpdate; + set { - get => _autoUpdate; - set - { - _autoUpdate = value; - RaisePropertyChanged("AutoUpdate"); - } + _autoUpdate = value; + RaisePropertyChanged("AutoUpdate"); } + } - /// - /// UI Binding - /// - public bool AutoUpdateEnabled + /// + /// UI Binding + /// + public bool AutoUpdateEnabled + { + get => _autoUpdateEnabled; + set { - get => _autoUpdateEnabled; - set - { - _autoUpdateEnabled = value; - RaisePropertyChanged("AutoUpdateEnabled"); - } + _autoUpdateEnabled = value; + RaisePropertyChanged("AutoUpdateEnabled"); } + } - #endregion + #endregion - #endregion + #endregion - /// - /// JSON constructor, called on file open - /// - /// - /// - [JsonConstructor] - private Receive(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) + /// + /// JSON constructor, called on file open + /// + /// + /// + [JsonConstructor] + private Receive(IEnumerable inPorts, IEnumerable outPorts) + : base(inPorts, outPorts) + { + if (inPorts.Count() == 1) { - if (inPorts.Count() == 1) - { - //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 - //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; - } - else - { - // If information from json does not look correct, clear the default ports and add ones with default value - InPorts.Clear(); - AddInputs(); - } + //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 + //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; + } + else + { + // If information from json does not look correct, clear the default ports and add ones with default value + InPorts.Clear(); + AddInputs(); + } - if (!outPorts.Any()) - AddOutputs(); + if (!outPorts.Any()) + { + AddOutputs(); + } - ArgumentLacing = LacingStrategy.Disabled; + ArgumentLacing = LacingStrategy.Disabled; - PropertyChanged += HandlePropertyChanged; - } + PropertyChanged += HandlePropertyChanged; + } - /// - /// Normal constructor, called when adding node to canvas - /// - public Receive() - { + /// + /// Normal constructor, called when adding node to canvas + /// + public Receive() + { + AddInputs(); + AddOutputs(); - AddInputs(); - AddOutputs(); + RegisterAllPorts(); + ArgumentLacing = LacingStrategy.Disabled; - RegisterAllPorts(); - ArgumentLacing = LacingStrategy.Disabled; + PropertyChanged += HandlePropertyChanged; + } - PropertyChanged += HandlePropertyChanged; - } + private void AddInputs() + { + InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream", "The stream to receive from"))); + } - private void AddInputs() - { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream", "The stream to receive from"))); - } + private void AddOutputs() + { + OutPorts.Add(new PortModel(PortType.Output, this, new PortData("data", "Data received"))); + OutPorts.Add(new PortModel(PortType.Output, this, new PortData("info", "Commit information"))); + } - private void AddOutputs() + internal void CancelReceive() + { + _cancellationToken.Cancel(); + ResetNode(); + } + + /// + /// Takes care of actually receiving data + /// it then stores the data in memory and expires the node + /// the node AST function retrieves the data from the memory and outputs it + /// + internal void DoReceive() + { + ClearErrorsAndWarnings(); + //double check, but can probably remove it + if (!InPorts[0].IsConnected) { - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("data", "Data received"))); - OutPorts.Add(new PortModel(PortType.Output, this, new PortData("info", "Commit information"))); + ResetNode(true); + return; } - internal void CancelReceive() + //if already receiving, stop and start again + if (Transmitting) { - _cancellationToken.Cancel(); - ResetNode(); + CancelReceive(); } - /// - /// Takes care of actually receiving data - /// it then stores the data in memory and expires the node - /// the node AST function retrieves the data from the memory and outputs it - /// - internal void DoReceive() + Transmitting = true; + Message = "Receiving..."; + _cancellationToken = new CancellationTokenSource(); + + try { - ClearErrorsAndWarnings(); - //double check, but can probably remove it - if (!InPorts[0].IsConnected) + if (Stream == null) { - ResetNode(true); - return; + throw new SpeckleException("The stream provided is invalid"); } - //if already receiving, stop and start again - if (Transmitting) - CancelReceive(); - - Transmitting = true; - Message = "Receiving..."; - _cancellationToken = new CancellationTokenSource(); - - try + void ProgressAction(ConcurrentDictionary dict) { - if (Stream == null) - throw new SpeckleException("The stream provided is invalid"); + //NOTE: progress set to indeterminate until the TotalChildrenCount is correct + //var val = dict.Values.Average() / _objectCount; + //Message = val.ToString("0%"); + //Progress = val * 100; - void ProgressAction(ConcurrentDictionary dict) + //NOTE: remove when restoring % progress + Message = ""; + foreach (var kvp in dict) { - //NOTE: progress set to indeterminate until the TotalChildrenCount is correct - //var val = dict.Values.Average() / _objectCount; - //Message = val.ToString("0%"); - //Progress = val * 100; - - //NOTE: remove when restoring % progress - Message = ""; - foreach (var kvp in dict) - { - Message += $"{kvp.Key}: {kvp.Value} "; - } + Message += $"{kvp.Key}: {kvp.Value} "; } + } - var hasErrors = false; + var hasErrors = false; - void ErrorAction(string transportName, Exception e) + void ErrorAction(string transportName, Exception e) + { + hasErrors = true; + var msg = e.ToFormattedString(); + if (msg.Contains("401 ")) { - hasErrors = true; - var msg = e.ToFormattedString(); - if (msg.Contains("401 ")) - { - Message = "Not authorized"; - Warning(msg); - ReceiveEnabled = false; - _cancellationToken.Cancel(); - } - else if (msg.Contains("404 ")) - { - Message = "Not found"; - Warning(msg); - ReceiveEnabled = false; - _cancellationToken.Cancel(); - } - else - { - //Message = "Conversion error"; - _errors.Add(e); - } + Message = "Not authorized"; + Warning(msg); + ReceiveEnabled = false; + _cancellationToken.Cancel(); } - - var data = Functions.Functions.Receive(Stream, _cancellationToken.Token, ProgressAction, - ErrorAction); - - if (data != null) + else if (msg.Contains("404 ")) { - LastCommitId = ((Commit)data["commit"]).id; - InMemoryCache.Set(LastCommitId, data); - Message = ""; + Message = "Not found"; + Warning(msg); + ReceiveEnabled = false; + _cancellationToken.Cancel(); } - } - catch (Exception e) - { - if (!_cancellationToken.IsCancellationRequested) + else { - _cancellationToken.Cancel(); - var msg = e.ToFormattedString(); - Message = msg.Contains("401") || msg.Contains("don't have access") ? "Not authorized" : "Error"; - Warning(msg); + //Message = "Conversion error"; _errors.Add(e); - throw; } } - finally + + var data = Functions.Functions.Receive(Stream, _cancellationToken.Token, ProgressAction, ErrorAction); + + if (data != null) { - ResetNode(); - if (!_cancellationToken.IsCancellationRequested) - { - _hasOutput = true; - ExpireNode(); - } + LastCommitId = ((Commit)data["commit"]).id; + InMemoryCache.Set(LastCommitId, data); + Message = ""; } } + catch (Exception e) + { + if (!_cancellationToken.IsCancellationRequested) + { + _cancellationToken.Cancel(); + var msg = e.ToFormattedString(); + Message = msg.Contains("401") || msg.Contains("don't have access") ? "Not authorized" : "Error"; + Warning(msg); + _errors.Add(e); + throw; + } + } + finally + { + ResetNode(); + if (!_cancellationToken.IsCancellationRequested) + { + _hasOutput = true; + ExpireNode(); + } + } + } - /// - /// Triggered when the node inputs change - /// Caches a copy of the inputs (Stream and BranchName) - /// - /// - internal void LoadInputs(EngineController engine) + /// + /// Triggered when the node inputs change + /// Caches a copy of the inputs (Stream and BranchName) + /// + /// + internal void LoadInputs(EngineController engine) + { + // Report any errors of the receive operation upon input load. This ensures they're not erased. + if (_errors.Count > 0) { - // Report any errors of the receive operation upon input load. This ensures they're not erased. - if (_errors.Count > 0) + foreach (var error in _errors) { - foreach (var error in _errors) - Warning(error.ToFormattedString()); - Message = "Conversion error"; - _errors = new List(); + Warning(error.ToFormattedString()); } - // Load inputs - var oldStream = Stream; - StreamWrapper newStream = null; + Message = "Conversion error"; + _errors = new List(); + } + + // Load inputs + var oldStream = Stream; + StreamWrapper newStream = null; - //update inputs stored locally - //try parse as streamWrapper + //update inputs stored locally + //try parse as streamWrapper + try + { + var inputStream = GetInputAs(engine, 0); + //avoid editing upstream stream! + newStream = new StreamWrapper(inputStream.StreamId, inputStream.UserId, inputStream.ServerUrl) + { + BranchName = inputStream.BranchName, + CommitId = inputStream.CommitId + }; + } + catch + { + // ignored + } + + //try parse as Url + if (newStream == null) + { try { - var inputStream = GetInputAs(engine, 0); - //avoid editing upstream stream! - newStream = new StreamWrapper(inputStream.StreamId, inputStream.UserId, inputStream.ServerUrl) - { - BranchName = inputStream.BranchName, - CommitId = inputStream.CommitId - }; + var url = GetInputAs(engine, 0); + newStream = new StreamWrapper(url); } catch { // ignored } + } - //try parse as Url - if (newStream == null) - { - try - { - var url = GetInputAs(engine, 0); - newStream = new StreamWrapper(url); - } - catch - { - // ignored - } - } + //invalid input + if (newStream == null) + { + ResetNode(true); + Message = "Stream is invalid"; + return; + } - //invalid input - if (newStream == null) - { - ResetNode(true); - Message = "Stream is invalid"; - return; - } + //if (newStream.Type != StreamWrapperType.Branch) + // newStream.BranchName = "main"; - //if (newStream.Type != StreamWrapperType.Branch) - // newStream.BranchName = "main"; + //no need to re-subscribe. it's the same stream + if (oldStream != null && newStream.ToString() == oldStream.ToString()) + { + return; + } - //no need to re-subscribe. it's the same stream - if (oldStream != null && newStream.ToString() == oldStream.ToString()) - return; + ResetNode(true); + Stream = newStream; - ResetNode(true); - Stream = newStream; + //StreamWrapper points to a Stream + if (newStream.Type == StreamWrapperType.Commit) + { + Name = "Receive Commit"; + AutoUpdate = false; + AutoUpdateEnabled = false; + } + else if (newStream.Type == StreamWrapperType.Object) + { + Name = "Receive Object"; + AutoUpdate = false; + AutoUpdateEnabled = false; + } + else + { + Name = "Receive"; + AutoUpdateEnabled = true; + InitializeReceiver(); + } + ReceiveEnabled = true; + } - //StreamWrapper points to a Stream - if (newStream.Type == StreamWrapperType.Commit) - { - Name = "Receive Commit"; - AutoUpdate = false; - AutoUpdateEnabled = false; - } - else if (newStream.Type == StreamWrapperType.Object) - { - Name = "Receive Object"; - AutoUpdate = false; - AutoUpdateEnabled = false; - } - else - { - Name = "Receive"; - AutoUpdateEnabled = true; - InitializeReceiver(); - } - ReceiveEnabled = true; + internal void InitializeReceiver() + { + ClearErrorsAndWarnings(); + if (Stream == null) + { + return; } - internal void InitializeReceiver() + try { - ClearErrorsAndWarnings(); - if (Stream == null) - return; - try - { - var account = Stream.GetAccount().Result; - Client = new Client(account); - Client.SubscribeCommitCreated(Stream.StreamId); - Client.OnCommitCreated += OnCommitChange; + var account = Stream.GetAccount().Result; + Client = new Client(account); + Client.SubscribeCommitCreated(Stream.StreamId); + Client.OnCommitCreated += OnCommitChange; - CheckIfBehind(); - } - catch (Exception e) - { - Console.WriteLine(e); - var exceptionMessage = e.InnerException?.Message ?? e.Message; - Warning(exceptionMessage); - Message = exceptionMessage.Contains("don't have access") ? "Not authorised" : "Error"; - ReceiveEnabled = false; - throw; - } + CheckIfBehind(); } + catch (Exception e) + { + Console.WriteLine(e); + var exceptionMessage = e.InnerException?.Message ?? e.Message; + Warning(exceptionMessage); + Message = exceptionMessage.Contains("don't have access") ? "Not authorised" : "Error"; + ReceiveEnabled = false; + throw; + } + } + + private T GetInputAs(EngineController engine, int port) + { + var valuesNode = InPorts[port].Connectors[0].Start.Owner; + var valuesIndex = InPorts[port].Connectors[0].Start.Index; + var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; + var inputMirror = engine.GetMirror(astId); - private T GetInputAs(EngineController engine, int port) + if (inputMirror?.GetData() == null) { - var valuesNode = InPorts[port].Connectors[0].Start.Owner; - var valuesIndex = InPorts[port].Connectors[0].Start.Index; - var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; - var inputMirror = engine.GetMirror(astId); + return default(T); + } - if (inputMirror?.GetData() == null) return default(T); + var data = inputMirror.GetData(); - var data = inputMirror.GetData(); + return (T)data.Data; + } - return (T)data.Data; + private void CheckIfBehind() + { + if (Stream == null) + { + return; } - private void CheckIfBehind() + try { - if (Stream == null) - return; - try + var branches = Client.StreamGetBranches(Stream.StreamId).Result; + var branchName = string.IsNullOrEmpty(Stream.BranchName) ? "main" : Stream.BranchName; + var mainBranch = branches.FirstOrDefault(b => b.name == branchName); + if (mainBranch == null || !mainBranch.commits.items.Any()) { - var branches = Client.StreamGetBranches(Stream.StreamId).Result; - var branchName = string.IsNullOrEmpty(Stream.BranchName) ? "main" : Stream.BranchName; - var mainBranch = branches.FirstOrDefault(b => b.name == branchName); - if (mainBranch == null || !mainBranch.commits.items.Any()) - { - Message = "Empty Stream"; - return; - } + Message = "Empty Stream"; + return; + } - var lastCommit = mainBranch.commits.items[0]; + var lastCommit = mainBranch.commits.items[0]; - //it's behind! Get objects count from last commit - if (lastCommit.id != LastCommitId) - { - Message = "Updates available"; - GetExpiredObjectCount(lastCommit.referencedObject); - } - else - { - Message = "Up to date"; - } + //it's behind! Get objects count from last commit + if (lastCommit.id != LastCommitId) + { + Message = "Updates available"; + GetExpiredObjectCount(lastCommit.referencedObject); } - catch (Exception ex) + else { - SpeckleLog.Logger.Error( - ex, - "Swallowing exception in {methodName}: {exceptionMessage}", - nameof(CheckIfBehind), - ex.Message - ); + Message = "Up to date"; } } + catch (Exception ex) + { + SpeckleLog.Logger.Error( + ex, + "Swallowing exception in {methodName}: {exceptionMessage}", + nameof(CheckIfBehind), + ex.Message + ); + } + } - private void GetExpiredObjectCount(string objectId) + private void GetExpiredObjectCount(string objectId) + { + if (Stream == null) { - if (Stream == null) - return; - try - { - var @object = Client.ObjectGet(Stream.StreamId, objectId).Result; - //quick fix for the scenario in which a single base is sent, we don't want to show 0! - var count = @object.totalChildrenCount == 0 ? @object.totalChildrenCount + 1 : @object.totalChildrenCount; - ExpiredCount = count.ToString(); - Message = "Updates available"; - _objectCount = count; - } - catch (Exception ex) - { - SpeckleLog.Logger.Error( - ex, - "Swallowing exception in {methodName}: {exceptionMessage}", - nameof(GetExpiredObjectCount), - ex.Message - ); - } + return; } - private void ExpireNode() + try { - OnNodeModified(true); + var @object = Client.ObjectGet(Stream.StreamId, objectId).Result; + //quick fix for the scenario in which a single base is sent, we don't want to show 0! + var count = @object.totalChildrenCount == 0 ? @object.totalChildrenCount + 1 : @object.totalChildrenCount; + ExpiredCount = count.ToString(); + Message = "Updates available"; + _objectCount = count; } + catch (Exception ex) + { + SpeckleLog.Logger.Error( + ex, + "Swallowing exception in {methodName}: {exceptionMessage}", + nameof(GetExpiredObjectCount), + ex.Message + ); + } + } - /// - /// Reset the node UI - /// - /// If true, resets enabled status and subscriptions too - private void ResetNode(bool hardReset = false) + private void ExpireNode() + { + OnNodeModified(true); + } + + /// + /// Reset the node UI + /// + /// If true, resets enabled status and subscriptions too + private void ResetNode(bool hardReset = false) + { + Transmitting = false; + ExpiredCount = ""; + Progress = 0; + _hasOutput = false; + if (hardReset) { - Transmitting = false; - ExpiredCount = ""; - Progress = 0; - _hasOutput = false; - if (hardReset) - { - Name = "Receive"; - Stream = null; - ReceiveEnabled = false; - Message = ""; - Client?.Dispose(); - ClearErrorsAndWarnings(); - } + Name = "Receive"; + Stream = null; + ReceiveEnabled = false; + Message = ""; + Client?.Dispose(); + ClearErrorsAndWarnings(); } + } - #region events + #region events - internal event Action OnNewDataAvail; - internal event Action OnInputsChanged; + internal event Action OnNewDataAvail; + internal event Action OnInputsChanged; - /// - /// Node inputs have changed, trigger load of new inputs - /// - protected virtual void RequestNewInputs() + /// + /// Node inputs have changed, trigger load of new inputs + /// + protected virtual void RequestNewInputs() + { + OnInputsChanged?.Invoke(); + } + + private void OnCommitChange(object sender, CommitInfo e) + { + if (e.branchName != (Stream.BranchName ?? "main")) { - OnInputsChanged?.Invoke(); + return; } - private void OnCommitChange(object sender, CommitInfo e) + Task.Run(async () => GetExpiredObjectCount(e.objectId)); + if (AutoUpdate) { - if (e.branchName != (Stream.BranchName ?? "main")) return; - - Task.Run(async () => GetExpiredObjectCount(e.objectId)); - if (AutoUpdate) - OnNewDataAvail?.Invoke(); + OnNewDataAvail?.Invoke(); } + } - void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "CachedValue") { - if (e.PropertyName != "CachedValue") - return; - - if (!InPorts[0].IsConnected) - { - ResetNode(true); - return; - } - - RequestNewInputs(); + return; } - #endregion - - #region overrides - - /// - /// - /// - /// - /// - public override IEnumerable BuildOutputAst(List inputAstNodes) + if (!InPorts[0].IsConnected) { + ResetNode(true); + return; + } - if (!InPorts[0].IsConnected || !_hasOutput || string.IsNullOrEmpty(LastCommitId)) - { - return OutPorts.Enumerate().Select(output => - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); - } - - _hasOutput = false; - var associativeNodes = new List(); - var primitiveNode = AstFactory.BuildStringNode(LastCommitId); - var dataFunctionCall = AstFactory.BuildFunctionCall( - new Func(Functions.Functions.ReceiveData), - new List { primitiveNode }); + RequestNewInputs(); + } - var infoFunctionCall = AstFactory.BuildFunctionCall( - new Func(Functions.Functions.ReceiveInfo), - new List { primitiveNode }); + #endregion - associativeNodes.Add(AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), dataFunctionCall)); - associativeNodes.Add(AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(1), infoFunctionCall)); - return associativeNodes; - } + #region overrides - /// - /// Dispose node and Client - /// - public override void Dispose() + /// + /// + /// + /// + /// + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + if (!InPorts[0].IsConnected || !_hasOutput || string.IsNullOrEmpty(LastCommitId)) { - Client?.Dispose(); - base.Dispose(); + return OutPorts + .Enumerate() + .Select(output => AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); } - #endregion + _hasOutput = false; + var associativeNodes = new List(); + var primitiveNode = AstFactory.BuildStringNode(LastCommitId); + var dataFunctionCall = AstFactory.BuildFunctionCall( + new Func(Functions.Functions.ReceiveData), + new List { primitiveNode } + ); + + var infoFunctionCall = AstFactory.BuildFunctionCall( + new Func(Functions.Functions.ReceiveInfo), + new List { primitiveNode } + ); + + associativeNodes.Add(AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), dataFunctionCall)); + associativeNodes.Add(AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(1), infoFunctionCall)); + return associativeNodes; + } + + /// + /// Dispose node and Client + /// + public override void Dispose() + { + Client?.Dispose(); + base.Dispose(); } + + #endregion } diff --git a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveUi.xaml.cs b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveUi.xaml.cs index bc157ca587..b40114dd20 100644 --- a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveUi.xaml.cs +++ b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveUi.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,16 +13,15 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace Speckle.ConnectorDynamo.ReceiveNode +namespace Speckle.ConnectorDynamo.ReceiveNode; + +/// +/// Interaction logic for SendUi.xaml +/// +public partial class ReceiveUi : UserControl { - /// - /// Interaction logic for SendUi.xaml - /// - public partial class ReceiveUi : UserControl + public ReceiveUi() { - public ReceiveUi() - { - InitializeComponent(); - } + InitializeComponent(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveViewCustomization.cs b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveViewCustomization.cs index fbfcfe0b45..a051576a5f 100644 --- a/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveViewCustomization.cs +++ b/ConnectorDynamo/ConnectorDynamo/ReceiveNode/ReceiveViewCustomization.cs @@ -1,4 +1,4 @@ -using Dynamo.Configuration; +using Dynamo.Configuration; using Dynamo.Controls; using Dynamo.Models; using Dynamo.Scheduler; @@ -10,104 +10,109 @@ using System.Windows.Controls; using System.Windows.Threading; -namespace Speckle.ConnectorDynamo.ReceiveNode +namespace Speckle.ConnectorDynamo.ReceiveNode; + +public class ReceiveViewCustomization : INodeViewCustomization { - public class ReceiveViewCustomization : INodeViewCustomization + private DynamoViewModel dynamoViewModel; + private DispatcherSynchronizationContext syncContext; + private Receive receiveNode; + private NodeView _nodeView; + private DynamoModel dynamoModel; + private MenuItem viewStreamMenuItem; + + public void CustomizeView(Receive model, NodeView nodeView) { - private DynamoViewModel dynamoViewModel; - private DispatcherSynchronizationContext syncContext; - private Receive receiveNode; - private NodeView _nodeView; - private DynamoModel dynamoModel; - private MenuItem viewStreamMenuItem; - - public void CustomizeView(Receive model, NodeView nodeView) - { - _nodeView = nodeView; - dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; - dynamoViewModel = nodeView.ViewModel.DynamoViewModel; - syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); - receiveNode = model; + _nodeView = nodeView; + dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; + dynamoViewModel = nodeView.ViewModel.DynamoViewModel; + syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); + receiveNode = model; - receiveNode.OnInputsChanged += InputsChanged; - receiveNode.OnNewDataAvail += NewDataAvail; + receiveNode.OnInputsChanged += InputsChanged; + receiveNode.OnNewDataAvail += NewDataAvail; - var ui = new ReceiveUi(); - nodeView.inputGrid.Children.Add(ui); + var ui = new ReceiveUi(); + nodeView.inputGrid.Children.Add(ui); - //bindings - ui.DataContext = model; + //bindings + ui.DataContext = model; - ui.Loaded += Loaded; - ui.ReceiveStreamButton.Click += ReceiveStreamButtonClick; - ui.CancelReceiveStreamButton.Click += CancelReceiveStreamButtonClick; + ui.Loaded += Loaded; + ui.ReceiveStreamButton.Click += ReceiveStreamButtonClick; + ui.CancelReceiveStreamButton.Click += CancelReceiveStreamButtonClick; - //nodeView.grid.ContextMenu.Items.Add(new Separator()); - } + //nodeView.grid.ContextMenu.Items.Add(new Separator()); + } - private void Loaded(object o, RoutedEventArgs a) + private void Loaded(object o, RoutedEventArgs a) + { + Task.Run(async () => { - Task.Run(async () => { receiveNode.InitializeReceiver(); }); - } + receiveNode.InitializeReceiver(); + }); + } - private DebounceTimer debounceTimer = new DebounceTimer(); + private DebounceTimer debounceTimer = new(); - private void InputsChanged() - { - debounceTimer.Debounce(300, - () => + private void InputsChanged() + { + debounceTimer.Debounce( + 300, + () => + { + Task.Run(async () => { - Task.Run(async () => - { - receiveNode.LoadInputs(dynamoModel.EngineController); - UpdateContextMenu(); - }); + receiveNode.LoadInputs(dynamoModel.EngineController); + UpdateContextMenu(); }); - } - + } + ); + } - private void NewDataAvail() + private void NewDataAvail() + { + Task.Run(async () => { - Task.Run(async () => { receiveNode.DoReceive(); }); - } + receiveNode.DoReceive(); + }); + } - private void ReceiveStreamButtonClick(object sender, RoutedEventArgs e) - { - NewDataAvail(); - } + private void ReceiveStreamButtonClick(object sender, RoutedEventArgs e) + { + NewDataAvail(); + } - private void UpdateContextMenu() + private void UpdateContextMenu() + { + receiveNode.DispatchOnUIThread(() => { - receiveNode.DispatchOnUIThread(() => + if (viewStreamMenuItem != null) { - if (viewStreamMenuItem != null) - { - _nodeView.grid.ContextMenu.Items.Remove(viewStreamMenuItem); - } + _nodeView.grid.ContextMenu.Items.Remove(viewStreamMenuItem); + } - viewStreamMenuItem = null; + viewStreamMenuItem = null; - if (receiveNode.Stream != null) + if (receiveNode.Stream != null) + { + viewStreamMenuItem = new MenuItem { + Header = $"View stream {receiveNode.Stream.StreamId} @ {receiveNode.Stream.ServerUrl} online ↗" + }; + viewStreamMenuItem.Click += (a, e) => + { + System.Diagnostics.Process.Start($"{receiveNode.Stream.ServerUrl}/streams/{receiveNode.Stream.StreamId}"); + }; + _nodeView.grid.ContextMenu.Items.Add(viewStreamMenuItem); + } + }); + } - viewStreamMenuItem = new MenuItem { Header = $"View stream {receiveNode.Stream.StreamId} @ {receiveNode.Stream.ServerUrl} online ↗" }; - viewStreamMenuItem.Click += (a, e) => - { - System.Diagnostics.Process.Start($"{receiveNode.Stream.ServerUrl}/streams/{receiveNode.Stream.StreamId}"); - }; - _nodeView.grid.ContextMenu.Items.Add(viewStreamMenuItem); - - } - }); - } - - private void CancelReceiveStreamButtonClick(object sender, RoutedEventArgs e) - { - receiveNode.CancelReceive(); - } - - public void Dispose() - { - } + private void CancelReceiveStreamButtonClick(object sender, RoutedEventArgs e) + { + receiveNode.CancelReceive(); } + + public void Dispose() { } } diff --git a/ConnectorDynamo/ConnectorDynamo/SendNode/Send.cs b/ConnectorDynamo/ConnectorDynamo/SendNode/Send.cs index 2d7cf89f85..a254820695 100644 --- a/ConnectorDynamo/ConnectorDynamo/SendNode/Send.cs +++ b/ConnectorDynamo/ConnectorDynamo/SendNode/Send.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; @@ -17,532 +17,550 @@ using Speckle.Core.Models.Extensions; using Speckle.Core.Transports; -namespace Speckle.ConnectorDynamo.SendNode +namespace Speckle.ConnectorDynamo.SendNode; + +/// +/// Send data to Speckle +/// +[NodeName("Send")] +[NodeCategory("Speckle 2")] +[NodeDescription("Send data to a Speckle server")] +[NodeSearchTags("send", "speckle")] +[IsDesignScriptCompatible] +public class Send : NodeModel { - /// - /// Send data to Speckle - /// - [NodeName("Send")] - [NodeCategory("Speckle 2")] - [NodeDescription("Send data to a Speckle server")] - [NodeSearchTags("send", "speckle")] - [IsDesignScriptCompatible] - public class Send : NodeModel - { - #region fields & props + #region fields & props - #region private fields + #region private fields - private bool _transmitting = false; - private string _message = ""; - private double _progress = 0; - private string _expiredCount = ""; - private bool _sendEnabled = false; - private int _objectCount = 0; - private bool _hasOutput = false; - private string _outputInfo = ""; - private bool _autoUpdate = false; - private CancellationTokenSource _cancellationToken; + private bool _transmitting = false; + private string _message = ""; + private double _progress = 0; + private string _expiredCount = ""; + private bool _sendEnabled = false; + private int _objectCount = 0; + private bool _hasOutput = false; + private string _outputInfo = ""; + private bool _autoUpdate = false; + private CancellationTokenSource _cancellationToken; - //cached inputs - private object _data { get; set; } - private List _transports { get; set; } - private Dictionary _branchNames { get; set; } - private string _commitMessage { get; set; } + //cached inputs + private object _data { get; set; } + private List _transports { get; set; } + private Dictionary _branchNames { get; set; } + private string _commitMessage { get; set; } - internal List _streamWrappers { get; set; } + internal List _streamWrappers { get; set; } - #endregion + #endregion - #region ui bindings + #region ui bindings - //PUBLIC PROPERTIES - //NOT to be saved with the file + //PUBLIC PROPERTIES + //NOT to be saved with the file - /// - /// UI Binding - /// - [JsonIgnore] - public bool Transmitting + /// + /// UI Binding + /// + [JsonIgnore] + public bool Transmitting + { + get => _transmitting; + set { - get => _transmitting; - set - { - _transmitting = value; - RaisePropertyChanged("Transmitting"); - } + _transmitting = value; + RaisePropertyChanged("Transmitting"); } + } - /// - /// UI Binding - /// - [JsonIgnore] - public string Message + /// + /// UI Binding + /// + [JsonIgnore] + public string Message + { + get => _message; + set { - get => _message; - set - { - _message = value; - RaisePropertyChanged("Message"); - } + _message = value; + RaisePropertyChanged("Message"); } + } - /// - /// UI Binding - /// - [JsonIgnore] - public double Progress + /// + /// UI Binding + /// + [JsonIgnore] + public double Progress + { + get => _progress; + set { - get => _progress; - set - { - _progress = value; - RaisePropertyChanged("Progress"); - } + _progress = value; + RaisePropertyChanged("Progress"); } + } - /// - /// UI Binding - /// - [JsonIgnore] - public bool SendEnabled + /// + /// UI Binding + /// + [JsonIgnore] + public bool SendEnabled + { + get => _sendEnabled; + set { - get => _sendEnabled; - set - { - _sendEnabled = value; - RaisePropertyChanged("SendEnabled"); - } + _sendEnabled = value; + RaisePropertyChanged("SendEnabled"); } + } - /// - /// UI Binding - /// - public bool AutoUpdate + /// + /// UI Binding + /// + public bool AutoUpdate + { + get => _autoUpdate; + set { - get => _autoUpdate; - set - { - _autoUpdate = value; - RaisePropertyChanged("AutoUpdate"); - } + _autoUpdate = value; + RaisePropertyChanged("AutoUpdate"); } + } - //properties TO SAVE - /// - /// UI Binding - /// - public string ExpiredCount + //properties TO SAVE + /// + /// UI Binding + /// + public string ExpiredCount + { + get => _expiredCount; + set { - get => _expiredCount; - set - { - _expiredCount = value; - RaisePropertyChanged("ExpiredCount"); - } + _expiredCount = value; + RaisePropertyChanged("ExpiredCount"); } + } - #endregion + #endregion - #endregion + #endregion - /// - /// JSON constructor, called on file open - /// - /// - /// - [JsonConstructor] - private Send(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) + /// + /// JSON constructor, called on file open + /// + /// + /// + [JsonConstructor] + private Send(IEnumerable inPorts, IEnumerable outPorts) + : base(inPorts, outPorts) + { + if (inPorts.Count() == 3) { - if (inPorts.Count() == 3) - { - //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 - //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; - } - else - { - // If information from json does not look correct, clear the default ports and add ones with default value - InPorts.Clear(); - AddInputs(); - } - - if (outPorts.Count() == 0) - AddOutputs(); - - ArgumentLacing = LacingStrategy.Disabled; - this.PropertyChanged += HandlePropertyChanged; + //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 + //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; } - - /// - /// Normal constructor, called when adding node to canvas - /// - public Send() + else { - + // If information from json does not look correct, clear the default ports and add ones with default value + InPorts.Clear(); AddInputs(); - AddOutputs(); - - RegisterAllPorts(); - ArgumentLacing = LacingStrategy.Disabled; - this.PropertyChanged += HandlePropertyChanged; } - private void AddInputs() + if (outPorts.Count() == 0) { - var defaultMessageValue = new StringNode { Value = "Automatic commit from Dynamo" }; - - InPorts.Add(new PortModel(PortType.Input, this, new PortData("data", "The data to send"))); - InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream", "The stream or streams to send to"))); - InPorts.Add(new PortModel(PortType.Input, this, - new PortData("message", "Commit message. If left blank, one will be generated for you.", defaultMessageValue))); + AddOutputs(); } - private void AddOutputs() + ArgumentLacing = LacingStrategy.Disabled; + this.PropertyChanged += HandlePropertyChanged; + } + + /// + /// Normal constructor, called when adding node to canvas + /// + public Send() + { + AddInputs(); + AddOutputs(); + + RegisterAllPorts(); + ArgumentLacing = LacingStrategy.Disabled; + this.PropertyChanged += HandlePropertyChanged; + } + + private void AddInputs() + { + var defaultMessageValue = new StringNode { Value = "Automatic commit from Dynamo" }; + + InPorts.Add(new PortModel(PortType.Input, this, new PortData("data", "The data to send"))); + InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream", "The stream or streams to send to"))); + InPorts.Add( + new PortModel( + PortType.Input, + this, + new PortData("message", "Commit message. If left blank, one will be generated for you.", defaultMessageValue) + ) + ); + } + + private void AddOutputs() + { + OutPorts.Add( + new PortModel(PortType.Output, this, new PortData("stream", "Stream or streams pointing to the created commit")) + ); + } + + internal void CancelSend() + { + _cancellationToken.Cancel(); + ResetNode(); + } + + /// + /// Takes care of actually sending the data + /// + /// + internal void DoSend(EngineController engine) + { + //double check, but can probably remove it + if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) { - OutPorts.Add(new PortModel(PortType.Output, this, - new PortData("stream", "Stream or streams pointing to the created commit"))); + ResetNode(true); + return; } - - internal void CancelSend() + //if already receiving, stop and start again + if (Transmitting) { - _cancellationToken.Cancel(); - ResetNode(); + CancelSend(); } - /// - /// Takes care of actually sending the data - /// - /// - internal void DoSend(EngineController engine) + Transmitting = true; + Message = "Converting..."; + _cancellationToken = new CancellationTokenSource(); + + try { - //double check, but can probably remove it - if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) + if (_transports == null) { - ResetNode(true); - return; + throw new SpeckleException("The stream provided is invalid"); } - //if already receiving, stop and start again - if (Transmitting) - CancelSend(); - - - Transmitting = true; - Message = "Converting..."; - _cancellationToken = new CancellationTokenSource(); + Base @base = null; + var converter = new BatchConverter(); + converter.OnError += (sender, args) => + { + Warning(args.Error.ToFormattedString()); + Message = "Conversion errors"; + }; try { - if (_transports == null) - throw new SpeckleException("The stream provided is invalid"); - - - Base @base = null; - var converter = new BatchConverter(); - converter.OnError += (sender, args) => - { - Warning(args.Error.ToFormattedString()); - Message = "Conversion errors"; - }; - - try - { - @base = converter.ConvertRecursivelyToSpeckle(_data); - } - catch (Exception e) - { - Message = "Conversion error"; - Warning(e.ToFormattedString()); - throw new SpeckleException("Conversion error", e); - } + @base = converter.ConvertRecursivelyToSpeckle(_data); + } + catch (Exception e) + { + Message = "Conversion error"; + Warning(e.ToFormattedString()); + throw new SpeckleException("Conversion error", e); + } - Message = "Sending..."; + Message = "Sending..."; - void ProgressAction(ConcurrentDictionary dict) - { - //NOTE: progress set to indeterminate until the TotalChildrenCount is correct - //var val = (double)dict.Values.Average() / totalCount; - //Message = val.ToString("0%"); - //Progress = val * 100; - - - //NOTE: remove when restoring % progress - Message = ""; - foreach (var kvp in dict) - { - Message += $"{kvp.Key}: {kvp.Value} "; - } - } + void ProgressAction(ConcurrentDictionary dict) + { + //NOTE: progress set to indeterminate until the TotalChildrenCount is correct + //var val = (double)dict.Values.Average() / totalCount; + //Message = val.ToString("0%"); + //Progress = val * 100; - var hasErrors = false; - void ErrorAction(string transportName, Exception e) + //NOTE: remove when restoring % progress + Message = ""; + foreach (var kvp in dict) { - hasErrors = true; - Message += e.ToFormattedString(); - - Message = Message.Contains("401") ? "You don't have enough permissions to send to this stream." : Message; - _cancellationToken.Cancel(); - ResetNode(); + Message += $"{kvp.Key}: {kvp.Value} "; } + } - var commitIds = Functions.Functions.Send(@base, _transports, _cancellationToken.Token, _branchNames, - _commitMessage, - ProgressAction, ErrorAction); + var hasErrors = false; - if (!hasErrors && commitIds != null) - { - _outputInfo = string.Join("|", commitIds.Select(x => x.ToString())); - Message = ""; - } - } - catch (Exception e) - { - if (!_cancellationToken.IsCancellationRequested) - { - _cancellationToken.Cancel(); - Message = e.InnerException != null ? e.InnerException.Message : e.Message; - throw new SpeckleException(e.Message, e); - } - } - finally + void ErrorAction(string transportName, Exception e) { + hasErrors = true; + Message += e.ToFormattedString(); + + Message = Message.Contains("401") ? "You don't have enough permissions to send to this stream." : Message; + _cancellationToken.Cancel(); ResetNode(); - if (!_cancellationToken.IsCancellationRequested) - { - _hasOutput = true; - ExpireNode(); - } } - } - /// - /// Reset the node UI - /// - /// If true, resets enabled status too - private void ResetNode(bool hardReset = false) - { - Transmitting = false; - ExpiredCount = ""; - Progress = 0; - _hasOutput = false; - if (hardReset) + var commitIds = Functions.Functions.Send( + @base, + _transports, + _cancellationToken.Token, + _branchNames, + _commitMessage, + ProgressAction, + ErrorAction + ); + + if (!hasErrors && commitIds != null) { - _transports = null; - _branchNames = null; - _data = null; - _objectCount = 0; - SendEnabled = false; + _outputInfo = string.Join("|", commitIds.Select(x => x.ToString())); Message = ""; - ClearErrorsAndWarnings(); } } - - /// - /// Triggered when the node inputs change - /// Caches a copy of the inputs - /// - /// - internal void LoadInputs(EngineController engine) + catch (Exception e) { - ResetNode(true); - - try + if (!_cancellationToken.IsCancellationRequested) { - _data = GetInputAs(engine, 0, true); + _cancellationToken.Cancel(); + Message = e.InnerException != null ? e.InnerException.Message : e.Message; + throw new SpeckleException(e.Message, e); } - catch + } + finally + { + ResetNode(); + if (!_cancellationToken.IsCancellationRequested) { - ResetNode(true); - Message = "Data input is invalid"; - return; + _hasOutput = true; + ExpireNode(); } + } + } - try - { - _transports = new List(); - _streamWrappers = new List(); // populated during TryConvertInputToTransport, not ideal but I'm lazy + /// + /// Reset the node UI + /// + /// If true, resets enabled status too + private void ResetNode(bool hardReset = false) + { + Transmitting = false; + ExpiredCount = ""; + Progress = 0; + _hasOutput = false; + if (hardReset) + { + _transports = null; + _branchNames = null; + _data = null; + _objectCount = 0; + SendEnabled = false; + Message = ""; + ClearErrorsAndWarnings(); + } + } - //this port accepts: - //a stream wrapper, a url, a list of stream wrappers or a list of urls - var inputTransport = GetInputAs(engine, 1); - var transportsDict = Utils.TryConvertInputToTransport(inputTransport); + /// + /// Triggered when the node inputs change + /// Caches a copy of the inputs + /// + /// + internal void LoadInputs(EngineController engine) + { + ResetNode(true); - foreach (var transport in transportsDict) - { - if (transport.Key is ServerTransport) - { - var st = transport.Key as ServerTransport; - _streamWrappers.Add(new StreamWrapper(st.StreamId, st.Account.userInfo.id, st.Account.serverInfo.url)); - } - } + try + { + _data = GetInputAs(engine, 0, true); + } + catch + { + ResetNode(true); + Message = "Data input is invalid"; + return; + } + try + { + _transports = new List(); + _streamWrappers = new List(); // populated during TryConvertInputToTransport, not ideal but I'm lazy - _transports = transportsDict.Keys.ToList(); - _branchNames = transportsDict; - } - catch (Exception e) - { - //ignored - ResetNode(true); - Warning(e.InnerException?.Message ?? e.Message); - Message = "Not authorized"; - return; - } + //this port accepts: + //a stream wrapper, a url, a list of stream wrappers or a list of urls + var inputTransport = GetInputAs(engine, 1); + var transportsDict = Utils.TryConvertInputToTransport(inputTransport); - if (_transports == null || !_transports.Any()) + foreach (var transport in transportsDict) { - ResetNode(true); - Message = "Stream is invalid"; - Warning("Input was neither a transport nor a stream."); - return; + if (transport.Key is ServerTransport) + { + var st = transport.Key as ServerTransport; + _streamWrappers.Add(new StreamWrapper(st.StreamId, st.Account.userInfo.id, st.Account.serverInfo.url)); + } } - try - { - _commitMessage = - InPorts[2].Connectors.Any() - ? GetInputAs(engine, 2) - : ""; //IsConnected not working because has default value - } - catch - { - Message = "Message is invalid, will skip it"; - } + _transports = transportsDict.Keys.ToList(); + _branchNames = transportsDict; + } + catch (Exception e) + { + //ignored + ResetNode(true); + Warning(e.InnerException?.Message ?? e.Message); + Message = "Not authorized"; + return; + } + if (_transports == null || !_transports.Any()) + { + ResetNode(true); + Message = "Stream is invalid"; + Warning("Input was neither a transport nor a stream."); + return; + } - InitializeSender(); + try + { + _commitMessage = InPorts[2].Connectors.Any() ? GetInputAs(engine, 2) : ""; //IsConnected not working because has default value + } + catch + { + Message = "Message is invalid, will skip it"; } + InitializeSender(); + } + private void InitializeSender() + { + SendEnabled = true; - private void InitializeSender() + if (_data is Base @base) { - SendEnabled = true; - - if (_data is Base @base) + //_objectCount is updated when the RecurseInput function loops through the data, not ideal but it works + //if we're dealing with a single Base (preconverted obj) use GetTotalChildrenCount to count its children + _objectCount = (int)@base.GetTotalChildrenCount(); + //exclude wrapper obj.... this is a bit of a hack... + if (_objectCount > 1) { - //_objectCount is updated when the RecurseInput function loops through the data, not ideal but it works - //if we're dealing with a single Base (preconverted obj) use GetTotalChildrenCount to count its children - _objectCount = (int)@base.GetTotalChildrenCount(); - //exclude wrapper obj.... this is a bit of a hack... - if (_objectCount > 1) _objectCount--; + _objectCount--; } + } - ExpiredCount = _objectCount.ToString(); - if (string.IsNullOrEmpty(Message)) - Message = "Updates ready"; + ExpiredCount = _objectCount.ToString(); + if (string.IsNullOrEmpty(Message)) + { + Message = "Updates ready"; } + } + private T GetInputAs(EngineController engine, int port, bool count = false) + { + var valuesNode = InPorts[port].Connectors[0].Start.Owner; + var valuesIndex = InPorts[port].Connectors[0].Start.Index; + var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; + var inputMirror = engine.GetMirror(astId); - private T GetInputAs(EngineController engine, int port, bool count = false) + if (inputMirror == null || inputMirror.GetData() == null) { - var valuesNode = InPorts[port].Connectors[0].Start.Owner; - var valuesIndex = InPorts[port].Connectors[0].Start.Index; - var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; - var inputMirror = engine.GetMirror(astId); - + return default(T); + } - if (inputMirror == null || inputMirror.GetData() == null) return default(T); + var data = inputMirror.GetData(); + var value = RecurseInput(data, count); - var data = inputMirror.GetData(); - var value = RecurseInput(data, count); + return (T)value; + } - return (T)value; + private object RecurseInput(MirrorData data, bool count) + { + object @object; + if (data.IsCollection) + { + var list = new List(); + var elements = data.GetElements(); + list.AddRange(elements.Select(x => RecurseInput(x, count))); + @object = list; } - - private object RecurseInput(MirrorData data, bool count) + else { - object @object; - if (data.IsCollection) + @object = data.Data; + if (count) { - var list = new List(); - var elements = data.GetElements(); - list.AddRange(elements.Select(x => RecurseInput(x, count))); - @object = list; + _objectCount++; } - else - { - @object = data.Data; - if (count) - _objectCount++; - } - - return @object; } + return @object; + } - private void ExpireNode() - { - OnNodeModified(true); - } + private void ExpireNode() + { + OnNodeModified(true); + } + + #region events - #region events + internal event Action OnInputsChanged; - internal event Action OnInputsChanged; + /// + /// Node inputs have changed, trigger load of new inputs + /// + protected virtual void RequestNewInputs() + { + OnInputsChanged?.Invoke(); + } - /// - /// Node inputs have changed, trigger load of new inputs - /// - protected virtual void RequestNewInputs() + void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "CachedValue") { - OnInputsChanged?.Invoke(); + return; } - void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) { - if (e.PropertyName != "CachedValue") - return; - - if (!InPorts[0].IsConnected || !InPorts[1].IsConnected) - { - ResetNode(true); - return; - } - - //prevent running when opening a saved file - // if (_firstRun) - // { - // _firstRun = false; - // return; - // } + ResetNode(true); + return; + } - //the node was expired manually just to output the commit info, no need to do anything! - if (_hasOutput) - { - _hasOutput = false; - return; - } + //prevent running when opening a saved file + // if (_firstRun) + // { + // _firstRun = false; + // return; + // } - RequestNewInputs(); + //the node was expired manually just to output the commit info, no need to do anything! + if (_hasOutput) + { + _hasOutput = false; + return; } - #endregion - - #region overrides + RequestNewInputs(); + } - /// - /// Sending is actually only happening when clicking the button on the node UI, this function is only used to check what ports are connected - /// could be done differently, but this is an easy way - /// - /// - /// - public override IEnumerable BuildOutputAst(List inputAstNodes) - { - if (!InPorts[0].IsConnected || !InPorts[1].IsConnected || !_hasOutput) - { - return OutPorts.Enumerate().Select(output => - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); - } + #endregion - var dataFunctionCall = AstFactory.BuildFunctionCall( - new Func(Functions.Functions.SendData), - new List { AstFactory.BuildStringNode(_outputInfo) }); + #region overrides - return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), dataFunctionCall) }; + /// + /// Sending is actually only happening when clicking the button on the node UI, this function is only used to check what ports are connected + /// could be done differently, but this is an easy way + /// + /// + /// + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + if (!InPorts[0].IsConnected || !InPorts[1].IsConnected || !_hasOutput) + { + return OutPorts + .Enumerate() + .Select(output => AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); } - #endregion + var dataFunctionCall = AstFactory.BuildFunctionCall( + new Func(Functions.Functions.SendData), + new List { AstFactory.BuildStringNode(_outputInfo) } + ); + + return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), dataFunctionCall) }; } + + #endregion } diff --git a/ConnectorDynamo/ConnectorDynamo/SendNode/SendUi.xaml.cs b/ConnectorDynamo/ConnectorDynamo/SendNode/SendUi.xaml.cs index 735bc50a52..d30d55182d 100644 --- a/ConnectorDynamo/ConnectorDynamo/SendNode/SendUi.xaml.cs +++ b/ConnectorDynamo/ConnectorDynamo/SendNode/SendUi.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,16 +13,15 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace Speckle.ConnectorDynamo.SendNode +namespace Speckle.ConnectorDynamo.SendNode; + +/// +/// Interaction logic for SendUi.xaml +/// +public partial class SendUi : UserControl { - /// - /// Interaction logic for SendUi.xaml - /// - public partial class SendUi : UserControl + public SendUi() { - public SendUi() - { - InitializeComponent(); - } + InitializeComponent(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/SendNode/SendViewCustomization.cs b/ConnectorDynamo/ConnectorDynamo/SendNode/SendViewCustomization.cs index 0350adb8a6..0992deb509 100644 --- a/ConnectorDynamo/ConnectorDynamo/SendNode/SendViewCustomization.cs +++ b/ConnectorDynamo/ConnectorDynamo/SendNode/SendViewCustomization.cs @@ -1,4 +1,4 @@ -using Dynamo.Configuration; +using Dynamo.Configuration; using Dynamo.Controls; using Dynamo.Models; using Dynamo.Scheduler; @@ -11,95 +11,96 @@ using System.Windows.Controls; using System.Windows.Threading; -namespace Speckle.ConnectorDynamo.SendNode +namespace Speckle.ConnectorDynamo.SendNode; + +public class SendViewCustomization : INodeViewCustomization { - public class SendViewCustomization : INodeViewCustomization + private DynamoViewModel dynamoViewModel; + private DispatcherSynchronizationContext syncContext; + private Send sendNode; + private DynamoModel dynamoModel; + private NodeView _nodeView; + private List customMenuItems = new(); + + public void CustomizeView(Send model, NodeView nodeView) { - private DynamoViewModel dynamoViewModel; - private DispatcherSynchronizationContext syncContext; - private Send sendNode; - private DynamoModel dynamoModel; - private NodeView _nodeView; - private List customMenuItems = new List(); - - public void CustomizeView(Send model, NodeView nodeView) - { - _nodeView = nodeView; - dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; - dynamoViewModel = nodeView.ViewModel.DynamoViewModel; - syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); - sendNode = model; + _nodeView = nodeView; + dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; + dynamoViewModel = nodeView.ViewModel.DynamoViewModel; + syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); + sendNode = model; - sendNode.OnInputsChanged += InputsChanged; + sendNode.OnInputsChanged += InputsChanged; - var ui = new SendUi(); - nodeView.inputGrid.Children.Add(ui); + var ui = new SendUi(); + nodeView.inputGrid.Children.Add(ui); - //bindings - ui.DataContext = model; - //ui.Loaded += model.AddedToDocument; - ui.SendStreamButton.Click += SendStreamButtonClick; - ui.CancelSendStreamButton.Click += CancelSendStreamButtonClick; + //bindings + ui.DataContext = model; + //ui.Loaded += model.AddedToDocument; + ui.SendStreamButton.Click += SendStreamButtonClick; + ui.CancelSendStreamButton.Click += CancelSendStreamButtonClick; + //nodeView.grid.ContextMenu.Items.Add(new Separator()); + } - //nodeView.grid.ContextMenu.Items.Add(new Separator()); - } - - private void CancelSendStreamButtonClick(object sender, RoutedEventArgs e) - { - sendNode.CancelSend(); - } + private void CancelSendStreamButtonClick(object sender, RoutedEventArgs e) + { + sendNode.CancelSend(); + } - private DebounceTimer debounceTimer = new DebounceTimer(); + private DebounceTimer debounceTimer = new(); - private void InputsChanged() - { - debounceTimer.Debounce(300, - () => + private void InputsChanged() + { + debounceTimer.Debounce( + 300, + () => + { + Task.Run(async () => { - Task.Run(async () => + sendNode.LoadInputs(dynamoModel.EngineController); + UpdateContextMenu(); + if (sendNode.AutoUpdate) { - sendNode.LoadInputs(dynamoModel.EngineController); - UpdateContextMenu(); - if (sendNode.AutoUpdate) - sendNode.DoSend(dynamoModel.EngineController); - }); + sendNode.DoSend(dynamoModel.EngineController); + } }); - } + } + ); + } - private void UpdateContextMenu() + private void UpdateContextMenu() + { + sendNode.DispatchOnUIThread(() => { - sendNode.DispatchOnUIThread(() => + foreach (var item in customMenuItems) { - foreach (var item in customMenuItems) - { - _nodeView.grid.ContextMenu.Items.Remove(item); - } + _nodeView.grid.ContextMenu.Items.Remove(item); + } - customMenuItems.Clear(); + customMenuItems.Clear(); - foreach (var stream in sendNode._streamWrappers) + foreach (var stream in sendNode._streamWrappers) + { + var viewStream = new MenuItem { Header = $"View stream {stream.StreamId} @ {stream.ServerUrl} online ↗" }; + viewStream.Click += (a, e) => { + System.Diagnostics.Process.Start($"{stream.ServerUrl}/streams/{stream.StreamId}"); + }; + customMenuItems.Add(viewStream); + _nodeView.grid.ContextMenu.Items.Add(viewStream); + } + }); + } - var viewStream = new MenuItem { Header = $"View stream {stream.StreamId} @ {stream.ServerUrl} online ↗" }; - viewStream.Click += (a, e) => - { - System.Diagnostics.Process.Start($"{stream.ServerUrl}/streams/{stream.StreamId}"); - }; - customMenuItems.Add(viewStream); - _nodeView.grid.ContextMenu.Items.Add(viewStream); - - } - }); - } - - private void SendStreamButtonClick(object sender, RoutedEventArgs e) - { - Task.Run(async () => { sendNode.DoSend(dynamoModel.EngineController); }); - } - - public void Dispose() + private void SendStreamButtonClick(object sender, RoutedEventArgs e) + { + Task.Run(async () => { - } + sendNode.DoSend(dynamoModel.EngineController); + }); } + + public void Dispose() { } } diff --git a/ConnectorDynamo/ConnectorDynamo/ValueConverters/BoolVisibConverter.cs b/ConnectorDynamo/ConnectorDynamo/ValueConverters/BoolVisibConverter.cs index a6f58ecdb4..d43069e214 100644 --- a/ConnectorDynamo/ConnectorDynamo/ValueConverters/BoolVisibConverter.cs +++ b/ConnectorDynamo/ConnectorDynamo/ValueConverters/BoolVisibConverter.cs @@ -1,35 +1,36 @@ -using System; +using System; using System.Windows; using System.Windows.Data; using System.Globalization; -namespace Speckle.ConnectorDynamo.ValueConverters +namespace Speckle.ConnectorDynamo.ValueConverters; + +/// +/// return visible if true. +/// can set second parameter to be "opposite" to reverse the functionality +/// +[ValueConversion(typeof(String), typeof(Visibility))] +public class BoolVisibConverter : IValueConverter { - /// - /// return visible if true. - /// can set second parameter to be "opposite" to reverse the functionality - /// - [ValueConversion(typeof(String), typeof(Visibility))] - public class BoolVisibConverter : IValueConverter + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + if (value == null) { - if (value == null) - value = false; - bool c = (bool)value; - - if (parameter != null && parameter.ToString() == "opposite") - c = !c; - - return (c) ? Visibility.Visible : Visibility.Collapsed; + value = false; } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { + bool c = (bool)value; - throw new NotImplementedException(); + if (parameter != null && parameter.ToString() == "opposite") + { + c = !c; } + return (c) ? Visibility.Visible : Visibility.Collapsed; + } + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/ViewNode/View.cs b/ConnectorDynamo/ConnectorDynamo/ViewNode/View.cs index bd47daca61..ccc962a1d4 100644 --- a/ConnectorDynamo/ConnectorDynamo/ViewNode/View.cs +++ b/ConnectorDynamo/ConnectorDynamo/ViewNode/View.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -10,196 +10,198 @@ using ProtoCore.AST.AssociativeAST; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.ViewNode +namespace Speckle.ConnectorDynamo.ViewNode; + +/// +/// Send data to Speckle +/// +[NodeName("View Online")] +[NodeCategory("Speckle 2.Stream")] +[NodeDescription("View Stream online")] +[NodeSearchTags("view", "speckle")] +[IsDesignScriptCompatible] +public class View : NodeModel { + public string Url { get; set; } + private bool _viewEnabled = false; + /// - /// Send data to Speckle + /// UI Binding /// - [NodeName("View Online")] - [NodeCategory("Speckle 2.Stream")] - [NodeDescription("View Stream online")] - [NodeSearchTags("view", "speckle")] - [IsDesignScriptCompatible] - public class View : NodeModel + [JsonIgnore] + public bool ViewEnabled { - public string Url { get; set; } - private bool _viewEnabled = false; - - - /// - /// UI Binding - /// - [JsonIgnore] - public bool ViewEnabled + get => _viewEnabled; + set { - get => _viewEnabled; - set - { - _viewEnabled = value; - RaisePropertyChanged("ViewEnabled"); - } + _viewEnabled = value; + RaisePropertyChanged("ViewEnabled"); } + } - - /// - /// JSON constructor, called on file open - /// - /// - /// - [JsonConstructor] - private View(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) + /// + /// JSON constructor, called on file open + /// + /// + /// + [JsonConstructor] + private View(IEnumerable inPorts, IEnumerable outPorts) + : base(inPorts, outPorts) + { + if (inPorts.Count() == 1) { - if (inPorts.Count() == 1) - { - //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 - //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; - } - else - { - // If information from json does not look correct, clear the default ports and add ones with default value - InPorts.Clear(); - AddInputs(); - } - - ArgumentLacing = LacingStrategy.Disabled; - this.PropertyChanged += HandlePropertyChanged; - foreach (var port in InPorts) - { - port.Connectors.CollectionChanged += Connectors_CollectionChanged; - } + //blocker: https://github.com/DynamoDS/Dynamo/issues/11118 + //inPorts.ElementAt(1).DefaultValue = endPortDefaultValue; } - - /// - /// Normal constructor, called when adding node to canvas - /// - public View() + else { + // If information from json does not look correct, clear the default ports and add ones with default value + InPorts.Clear(); AddInputs(); - - RegisterAllPorts(); - ArgumentLacing = LacingStrategy.Disabled; - this.PropertyChanged += HandlePropertyChanged; - foreach (var port in InPorts) - { - port.Connectors.CollectionChanged += Connectors_CollectionChanged; - } } - private void AddInputs() + ArgumentLacing = LacingStrategy.Disabled; + this.PropertyChanged += HandlePropertyChanged; + foreach (var port in InPorts) { - InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream or url", "The stream to view"))); + port.Connectors.CollectionChanged += Connectors_CollectionChanged; } + } + /// + /// Normal constructor, called when adding node to canvas + /// + public View() + { + AddInputs(); - /// - /// Takes care of actually sending the data - /// - /// - internal void ViewStream() + RegisterAllPorts(); + ArgumentLacing = LacingStrategy.Disabled; + this.PropertyChanged += HandlePropertyChanged; + foreach (var port in InPorts) { - if (!InPorts[0].IsConnected || string.IsNullOrEmpty(Url)) - { - ViewEnabled = false; - Url = ""; - return; - } + port.Connectors.CollectionChanged += Connectors_CollectionChanged; + } + } - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream View" } }); + private void AddInputs() + { + InPorts.Add(new PortModel(PortType.Input, this, new PortData("stream or url", "The stream to view"))); + } - Process.Start(Url); + /// + /// Takes care of actually sending the data + /// + /// + internal void ViewStream() + { + if (!InPorts[0].IsConnected || string.IsNullOrEmpty(Url)) + { + ViewEnabled = false; + Url = ""; + return; } - //Cache input value each time it comes available - internal void UpdateNode(EngineController engine) + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream View" } }); + + Process.Start(Url); + } + + //Cache input value each time it comes available + internal void UpdateNode(EngineController engine) + { + if (!InPorts[0].IsConnected) { - if (!InPorts[0].IsConnected) - { - ViewEnabled = false; - return; - } - - var url = GetInputAsString(engine, 0); - - if (string.IsNullOrEmpty(url)) - { - ViewEnabled = false; - Url = ""; - return; - } - - Uri uriResult; - bool result = Uri.TryCreate(url, UriKind.Absolute, out uriResult) - && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); - - if (!result) - { - ViewEnabled = false; - Url = ""; - return; - } - - ViewEnabled = true; - Url = url; + ViewEnabled = false; + return; } + var url = GetInputAsString(engine, 0); - private string GetInputAsString(EngineController engine, int port, bool count = false) + if (string.IsNullOrEmpty(url)) { - var valuesNode = InPorts[port].Connectors[0].Start.Owner; - var valuesIndex = InPorts[port].Connectors[0].Start.Index; - var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; - var inputMirror = engine.GetMirror(astId); - - if (inputMirror == null || inputMirror.GetData() == null) return null; + ViewEnabled = false; + Url = ""; + return; + } - var data = inputMirror.GetData().Data?.ToString(); + Uri uriResult; + bool result = + Uri.TryCreate(url, UriKind.Absolute, out uriResult) + && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); - return data; + if (!result) + { + ViewEnabled = false; + Url = ""; + return; } + ViewEnabled = true; + Url = url; + } - #region events - - internal event Action OnRequestUpdates; + private string GetInputAsString(EngineController engine, int port, bool count = false) + { + var valuesNode = InPorts[port].Connectors[0].Start.Owner; + var valuesIndex = InPorts[port].Connectors[0].Start.Index; + var astId = valuesNode.GetAstIdentifierForOutputIndex(valuesIndex).Name; + var inputMirror = engine.GetMirror(astId); - protected virtual void RequestUpdates() + if (inputMirror == null || inputMirror.GetData() == null) { - OnRequestUpdates?.Invoke(); + return null; } - void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName != "CachedValue") - return; + var data = inputMirror.GetData().Data?.ToString(); + + return data; + } - if (!InPorts[0].IsConnected) - return; + #region events + internal event Action OnRequestUpdates; + + protected virtual void RequestUpdates() + { + OnRequestUpdates?.Invoke(); + } - RequestUpdates(); + void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "CachedValue") + { + return; } - void Connectors_CollectionChanged(object sender, - System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + if (!InPorts[0].IsConnected) { - RequestUpdates(); + return; } - #endregion + RequestUpdates(); + } - #region overrides + void Connectors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + RequestUpdates(); + } - /// - /// - /// - /// - /// - public override IEnumerable BuildOutputAst(List inputAstNodes) - { - return OutPorts.Enumerate().Select(output => - AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); - } + #endregion + + #region overrides - #endregion + /// + /// + /// + /// + /// + public override IEnumerable BuildOutputAst(List inputAstNodes) + { + return OutPorts + .Enumerate() + .Select(output => AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(output.Index), new NullNode())); } + + #endregion } diff --git a/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewUi.xaml.cs b/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewUi.xaml.cs index 3bcb108b68..3e353bdc73 100644 --- a/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewUi.xaml.cs +++ b/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewUi.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -13,16 +13,15 @@ using System.Windows.Navigation; using System.Windows.Shapes; -namespace Speckle.ConnectorDynamo.ViewNode +namespace Speckle.ConnectorDynamo.ViewNode; + +/// +/// Interaction logic for SendUi.xaml +/// +public partial class ViewUi : UserControl { - /// - /// Interaction logic for SendUi.xaml - /// - public partial class ViewUi : UserControl + public ViewUi() { - public ViewUi() - { - InitializeComponent(); - } + InitializeComponent(); } } diff --git a/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewViewCustomization.cs b/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewViewCustomization.cs index 287cbd6ffd..cc3f9cbe92 100644 --- a/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewViewCustomization.cs +++ b/ConnectorDynamo/ConnectorDynamo/ViewNode/ViewViewCustomization.cs @@ -1,4 +1,4 @@ -using Dynamo.Configuration; +using Dynamo.Configuration; using Dynamo.Controls; using Dynamo.Models; using Dynamo.Scheduler; @@ -8,46 +8,48 @@ using System.Windows; using System.Windows.Threading; -namespace Speckle.ConnectorDynamo.ViewNode -{ - public class ViewViewCustomization : INodeViewCustomization - { - private DynamoViewModel dynamoViewModel; - private DispatcherSynchronizationContext syncContext; - private View viewNode; - private DynamoModel dynamoModel; - - public void CustomizeView(View model, NodeView nodeView) - { - dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; - dynamoViewModel = nodeView.ViewModel.DynamoViewModel; - syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); - viewNode = model; +namespace Speckle.ConnectorDynamo.ViewNode; - viewNode.OnRequestUpdates += UpdateNode; +public class ViewViewCustomization : INodeViewCustomization +{ + private DynamoViewModel dynamoViewModel; + private DispatcherSynchronizationContext syncContext; + private View viewNode; + private DynamoModel dynamoModel; - var ui = new ViewUi(); - nodeView.inputGrid.Children.Add(ui); + public void CustomizeView(View model, NodeView nodeView) + { + dynamoModel = nodeView.ViewModel.DynamoViewModel.Model; + dynamoViewModel = nodeView.ViewModel.DynamoViewModel; + syncContext = new DispatcherSynchronizationContext(nodeView.Dispatcher); + viewNode = model; - //bindings - ui.DataContext = model; - //ui.Loaded += model.AddedToDocument; - ui.ViewStreamButton.Click += ViewStreamButtonClick; - } + viewNode.OnRequestUpdates += UpdateNode; + var ui = new ViewUi(); + nodeView.inputGrid.Children.Add(ui); - private void UpdateNode() - { - Task.Run(async () => { viewNode.UpdateNode(dynamoModel.EngineController); }); - } + //bindings + ui.DataContext = model; + //ui.Loaded += model.AddedToDocument; + ui.ViewStreamButton.Click += ViewStreamButtonClick; + } - private void ViewStreamButtonClick(object sender, RoutedEventArgs e) + private void UpdateNode() + { + Task.Run(async () => { - Task.Run(async () => { viewNode.ViewStream(); }); - } + viewNode.UpdateNode(dynamoModel.EngineController); + }); + } - public void Dispose() + private void ViewStreamButtonClick(object sender, RoutedEventArgs e) + { + Task.Run(async () => { - } + viewNode.ViewStream(); + }); } + + public void Dispose() { } } diff --git a/ConnectorDynamo/ConnectorDynamoExtension/SpeckleExtension.cs b/ConnectorDynamo/ConnectorDynamoExtension/SpeckleExtension.cs index aab42da1f3..b72d99cb70 100644 --- a/ConnectorDynamo/ConnectorDynamoExtension/SpeckleExtension.cs +++ b/ConnectorDynamo/ConnectorDynamoExtension/SpeckleExtension.cs @@ -1,4 +1,4 @@ -using System; +using System; using Dynamo.Applications.Models; using Dynamo.ViewModels; using Dynamo.Wpf.Extensions; @@ -7,54 +7,51 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.Extension +namespace Speckle.ConnectorDynamo.Extension; + +public class SpeckleExtension : IViewExtension { - public class SpeckleExtension : IViewExtension - { - public string UniqueId => "B8160241-CAC4-4189-BF79-87C92914B8EC"; + public string UniqueId => "B8160241-CAC4-4189-BF79-87C92914B8EC"; - public string Name => "Speckle Extension"; + public string Name => "Speckle Extension"; - public void Loaded(ViewLoadedParams viewLoadedParams) + public void Loaded(ViewLoadedParams viewLoadedParams) + { + try { + var dynamoViewModel = viewLoadedParams.DynamoWindow.DataContext as DynamoViewModel; + //var speckleWatchHandler = new SpeckleWatchHandler(dynamoViewModel.PreferenceSettings); - - try + if (dynamoViewModel.Model is RevitDynamoModel rdm) { - var dynamoViewModel = viewLoadedParams.DynamoWindow.DataContext as DynamoViewModel; - //var speckleWatchHandler = new SpeckleWatchHandler(dynamoViewModel.PreferenceSettings); - - if (dynamoViewModel.Model is RevitDynamoModel rdm) - { - rdm.RevitDocumentChanged += Rdm_RevitDocumentChanged; - Globals.RevitDocument = DocumentManager.Instance.GetType().GetProperty("CurrentDBDocument").GetValue(DocumentManager.Instance); - } - //sets a read-only property using reflection WatchHandler - //typeof(DynamoViewModel).GetProperty("WatchHandler").SetValue(dynamoViewModel, speckleWatchHandler); - - Setup.Init(HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit), HostApplications.Dynamo.Slug); + rdm.RevitDocumentChanged += Rdm_RevitDocumentChanged; + Globals.RevitDocument = DocumentManager.Instance + .GetType() + .GetProperty("CurrentDBDocument") + .GetValue(DocumentManager.Instance); } - catch (Exception e) - { + //sets a read-only property using reflection WatchHandler + //typeof(DynamoViewModel).GetProperty("WatchHandler").SetValue(dynamoViewModel, speckleWatchHandler); - } + Setup.Init(HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit), HostApplications.Dynamo.Slug); } + catch (Exception e) { } + } - private void Rdm_RevitDocumentChanged(object sender, EventArgs e) - { - - Globals.RevitDocument = DocumentManager.Instance.GetType().GetProperty("CurrentDBDocument").GetValue(DocumentManager.Instance); - } + private void Rdm_RevitDocumentChanged(object sender, EventArgs e) + { + Globals.RevitDocument = DocumentManager.Instance + .GetType() + .GetProperty("CurrentDBDocument") + .GetValue(DocumentManager.Instance); + } - public void Dispose() { } + public void Dispose() { } - public void Shutdown() - { - } + public void Shutdown() { } - public void Startup(ViewStartupParams p) - { - Setup.Init(HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox), HostApplications.Dynamo.Slug); - } + public void Startup(ViewStartupParams p) + { + Setup.Init(HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox), HostApplications.Dynamo.Slug); } } diff --git a/ConnectorDynamo/ConnectorDynamoExtension/SpeckleWatchHandler.cs b/ConnectorDynamo/ConnectorDynamoExtension/SpeckleWatchHandler.cs index f32515352d..1f2ca6a3ca 100644 --- a/ConnectorDynamo/ConnectorDynamoExtension/SpeckleWatchHandler.cs +++ b/ConnectorDynamo/ConnectorDynamoExtension/SpeckleWatchHandler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -8,60 +8,85 @@ using ProtoCore.Mirror; using Speckle.Core.Credentials; -namespace Speckle.ConnectorDynamo.Extension +namespace Speckle.ConnectorDynamo.Extension; + +public class SpeckleWatchHandler : IWatchHandler { - public class SpeckleWatchHandler : IWatchHandler + private readonly IWatchHandler baseHandler; + private readonly IPreferences preferences; + + public SpeckleWatchHandler(IPreferences prefs) { - private readonly IWatchHandler baseHandler; - private readonly IPreferences preferences; + baseHandler = new DefaultWatchHandler(prefs); + preferences = prefs; + } - public SpeckleWatchHandler(IPreferences prefs) - { - baseHandler = new DefaultWatchHandler(prefs); - preferences = prefs; - } + private WatchViewModel ProcessThing( + Account account, + List preferredDictionaryOrdering, + ProtoCore.RuntimeCore runtimeCore, + string tag, + bool showRawData, + WatchHandlerCallback callback + ) + { + var node = new WatchViewModel(account.userInfo.email, tag, RequestSelectGeometry); - private WatchViewModel ProcessThing(Account account, List preferredDictionaryOrdering, ProtoCore.RuntimeCore runtimeCore, string tag, bool showRawData, WatchHandlerCallback callback) + node.Clicked += () => { + System.Diagnostics.Process.Start(account.serverInfo.url); + }; - var node = new WatchViewModel(account.userInfo.email, tag, RequestSelectGeometry); - - node.Clicked += () => - { - System.Diagnostics.Process.Start(account.serverInfo.url); - }; - - node.Link = account.serverInfo.url; + node.Link = account.serverInfo.url; - return node; - } + return node; + } - //If no dispatch target is found, then invoke base watch handler. - private WatchViewModel ProcessThing(object obj, List preferredDictionaryOrdering, ProtoCore.RuntimeCore runtimeCore, string tag, bool showRawData, WatchHandlerCallback callback) - { - return baseHandler.Process(obj, preferredDictionaryOrdering, runtimeCore, tag, showRawData, callback); - } + //If no dispatch target is found, then invoke base watch handler. + private WatchViewModel ProcessThing( + object obj, + List preferredDictionaryOrdering, + ProtoCore.RuntimeCore runtimeCore, + string tag, + bool showRawData, + WatchHandlerCallback callback + ) + { + return baseHandler.Process(obj, preferredDictionaryOrdering, runtimeCore, tag, showRawData, callback); + } - private WatchViewModel ProcessThing(MirrorData data, List preferredDictionaryOrdering, ProtoCore.RuntimeCore runtimeCore, string tag, bool showRawData, WatchHandlerCallback callback) + private WatchViewModel ProcessThing( + MirrorData data, + List preferredDictionaryOrdering, + ProtoCore.RuntimeCore runtimeCore, + string tag, + bool showRawData, + WatchHandlerCallback callback + ) + { + try { - try - { - return baseHandler.Process(data, preferredDictionaryOrdering, runtimeCore, tag, showRawData, callback); - } - catch (Exception) - { - return callback(data.Data, preferredDictionaryOrdering, runtimeCore, tag, showRawData); - } + return baseHandler.Process(data, preferredDictionaryOrdering, runtimeCore, tag, showRawData, callback); } - - public WatchViewModel Process(dynamic value, IEnumerable preferredDictionaryOrdering, ProtoCore.RuntimeCore runtimeCore, string tag, bool showRawData, WatchHandlerCallback callback) + catch (Exception) { - return Object.ReferenceEquals(value, null) - ? new WatchViewModel("null", tag, RequestSelectGeometry) - : ProcessThing(value, preferredDictionaryOrdering?.ToList(), runtimeCore, tag, showRawData, callback); + return callback(data.Data, preferredDictionaryOrdering, runtimeCore, tag, showRawData); } + } - - public event Action RequestSelectGeometry; + public WatchViewModel Process( + dynamic value, + IEnumerable preferredDictionaryOrdering, + ProtoCore.RuntimeCore runtimeCore, + string tag, + bool showRawData, + WatchHandlerCallback callback + ) + { + return Object.ReferenceEquals(value, null) + ? new WatchViewModel("null", tag, RequestSelectGeometry) + : ProcessThing(value, preferredDictionaryOrdering?.ToList(), runtimeCore, tag, showRawData, callback); } + + public event Action RequestSelectGeometry; } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Account.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Account.cs index 077eef6bf6..c7f3e73113 100755 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Account.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Account.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using Autodesk.DesignScript.Runtime; @@ -6,59 +6,58 @@ using Speckle.Core.Credentials; using Speckle.Core.Logging; +namespace Speckle.ConnectorDynamo.Functions; -namespace Speckle.ConnectorDynamo.Functions +public static class Account { - public static class Account + [IsVisibleInDynamoLibrary(false)] + public static Core.Credentials.Account GetById(string id) { + var acc = AccountManager.GetAccounts().FirstOrDefault(x => x.userInfo.id == id); + Analytics.TrackEvent(acc, Analytics.Events.NodeRun, new Dictionary() { { "name", "Account Get" } }); + return acc; + } - [IsVisibleInDynamoLibrary(false)] - public static Core.Credentials.Account GetById(string id) + /// + /// Get an Account details + /// + [NodeCategory("Query")] + [MultiReturn(new[] { "isDefault", "serverInfo", "userInfo" })] + public static Dictionary Details(Core.Credentials.Account account) + { + if (account == null) { - var acc = AccountManager.GetAccounts().FirstOrDefault(x => x.userInfo.id == id); - Analytics.TrackEvent(acc, Analytics.Events.NodeRun, new Dictionary() { { "name", "Account Get" } }); - return acc; + Utils.HandleApiExeption(new WarningException("Provided account was invalid.")); } - /// - /// Get an Account details - /// - [NodeCategory("Query")] - [MultiReturn(new[] { "isDefault", "serverInfo", "userInfo" })] - public static Dictionary Details(Core.Credentials.Account account) - { - - - if (account == null) - { - - Utils.HandleApiExeption(new WarningException("Provided account was invalid.")); - } - - Analytics.TrackEvent(account, Analytics.Events.NodeRun, new Dictionary() { { "name", "Account Details" } }); + Analytics.TrackEvent( + account, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Account Details" } } + ); - return new Dictionary + return new Dictionary + { + { "isDefault", account.isDefault }, { - {"isDefault", account.isDefault}, + "serverInfo", + new Dictionary { - "serverInfo", - new Dictionary - { - {"name", account.serverInfo.name}, - {"company", account.serverInfo.company}, - {"url", account.serverInfo.url} - } - }, + { "name", account.serverInfo.name }, + { "company", account.serverInfo.company }, + { "url", account.serverInfo.url } + } + }, + { + "userInfo", + new Dictionary { - "userInfo", new Dictionary - { - {"id", account.userInfo.id}, - {"name", account.userInfo.name}, - {"email", account.userInfo.email}, - {"company", account.userInfo.company}, - } + { "id", account.userInfo.id }, + { "name", account.userInfo.name }, + { "email", account.userInfo.email }, + { "company", account.userInfo.company }, } - }; - } + } + }; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Auto.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Auto.cs index 61fd94962d..011bde7bf3 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Auto.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Auto.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -8,58 +8,72 @@ using Speckle.Core.Credentials; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +public static class Auto { - public static class Auto + /// + /// Send data to a Speckle server automatically, withiut having to click on a send button + /// + /// The data to send + /// The stream or streams to send to + /// Commit message. If left blank, one will be generated for you. + /// Enable or disable this node + /// + public static List AutoSend( + [ArbitraryDimensionArrayImport] object data, + object stream, + string message = "", + bool enabled = true + ) { - /// - /// Send data to a Speckle server automatically, withiut having to click on a send button - /// - /// The data to send - /// The stream or streams to send to - /// Commit message. If left blank, one will be generated for you. - /// Enable or disable this node - /// - public static List AutoSend([ArbitraryDimensionArrayImport] object data, object stream, string message = "", bool enabled = true) + var result = new List(); + if (!enabled) { - var result = new List(); - if (!enabled) - return result; + return result; + } - var converter = new BatchConverter(); - converter.OnError += (sender, args) => throw args.Error; + var converter = new BatchConverter(); + converter.OnError += (sender, args) => throw args.Error; - var @base = converter.ConvertRecursivelyToSpeckle(data); + var @base = converter.ConvertRecursivelyToSpeckle(data); - // .Result is Thread Blocking inRevit - Task.Run(() => + // .Result is Thread Blocking inRevit + Task.Run(() => { var transportsDict = Utils.TryConvertInputToTransport(stream); - result = Functions.Send(@base, transportsDict.Keys.ToList(), new System.Threading.CancellationToken(), transportsDict, message); - }).Wait(); - - return result; - } - - /// - /// Receive data from a Speckle server automatically, without having to click on a receive button - /// - /// The stream or streams to receive from - /// Enable or disable this node - /// - public static Dictionary AutoReceive(object stream, bool enabled = true) - { - var result = new Dictionary(); + result = Functions.Send( + @base, + transportsDict.Keys.ToList(), + new System.Threading.CancellationToken(), + transportsDict, + message + ); + }) + .Wait(); - if (!enabled) - return result; + return result; + } + /// + /// Receive data from a Speckle server automatically, without having to click on a receive button + /// + /// The stream or streams to receive from + /// Enable or disable this node + /// + public static Dictionary AutoReceive(object stream, bool enabled = true) + { + var result = new Dictionary(); - StreamWrapper sw = null; + if (!enabled) + { + return result; + } + StreamWrapper sw = null; - // .Result is Thread Blocking inRevit - Task.Run(() => + // .Result is Thread Blocking inRevit + Task.Run(() => { //try parse as streamWrapper if (stream is StreamWrapper) @@ -80,10 +94,9 @@ public static Dictionary AutoReceive(object stream, bool enabled } result = Functions.Receive(sw, new CancellationToken()); - }).Wait(); - - return result; - } + }) + .Wait(); + return result; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/BatchConverter.cs b/ConnectorDynamo/ConnectorDynamoFunctions/BatchConverter.cs index b2c5c12fbf..8742deb7a4 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/BatchConverter.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/BatchConverter.cs @@ -8,333 +8,360 @@ using System.Text.RegularExpressions; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +[IsVisibleInDynamoLibrary(false)] +public class BatchConverter { - [IsVisibleInDynamoLibrary(false)] - public class BatchConverter + private ISpeckleConverter _converter { get; set; } + private ISpeckleKit _kit { get; set; } + + public EventHandler OnError; + + public BatchConverter() { - private ISpeckleConverter _converter { get; set; } - private ISpeckleKit _kit { get; set; } + var kit = KitManager.GetDefaultKit(); + _kit = kit ?? throw new SpeckleException("Cannot find the Objects Kit. Has it been copied to the Kits folder?"); + _converter = kit.LoadConverter(Utils.GetAppName()); - public EventHandler OnError; + if (_converter == null) + { + throw new SpeckleException("Cannot find the Dynamo converter. Has it been copied to the Kits folder?"); + } - public BatchConverter() + // if in Revit, we have a doc, injected by the Extension + if (Globals.RevitDocument != null) { - var kit = KitManager.GetDefaultKit(); - _kit = kit ?? throw new SpeckleException("Cannot find the Objects Kit. Has it been copied to the Kits folder?"); - _converter = kit.LoadConverter(Utils.GetAppName()); + _converter.SetContextDocument(Globals.RevitDocument); + } + } - if (_converter == null) - throw new SpeckleException("Cannot find the Dynamo converter. Has it been copied to the Kits folder?"); + /// + /// Helper method to convert a tree-like structure (nested lists) to Speckle + /// + /// + /// + public Base ConvertRecursivelyToSpeckle(object @object) + { + if (@object is ProtoCore.DSASM.StackValue) + { + throw new SpeckleException("Invalid input"); + } + + var converted = RecurseTreeToSpeckle(@object); - // if in Revit, we have a doc, injected by the Extension - if (Globals.RevitDocument != null) - _converter.SetContextDocument(Globals.RevitDocument); + if (converted is null) + { + return null; } - /// - /// Helper method to convert a tree-like structure (nested lists) to Speckle - /// - /// - /// - public Base ConvertRecursivelyToSpeckle(object @object) + var @base = new Base(); + + //case 1: lists and basic types => add them to a wrapper Base object in a `data` prop + //case 2: Base => just use it as it is + if (IsList(converted) || converted.GetType().IsSimpleType()) { - if (@object is ProtoCore.DSASM.StackValue) - throw new SpeckleException("Invalid input"); + @base["@data"] = converted; + } + else if (converted is Base convertedBase) + { + @base = convertedBase; + } - var converted = RecurseTreeToSpeckle(@object); + return @base; + } - if (converted is null) - return null; - var @base = new Base(); + private object RecurseTreeToSpeckle(object @object) + { + if (IsList(@object)) + { + var list = ((IEnumerable)@object).Cast().ToList(); + return list.Select(RecurseTreeToSpeckle).ToList(); + } - //case 1: lists and basic types => add them to a wrapper Base object in a `data` prop - //case 2: Base => just use it as it is - if (IsList(converted) || converted.GetType().IsSimpleType()) - { - @base["@data"] = converted; - } - else if (converted is Base convertedBase) - { - @base = convertedBase; - } + if (@object is DesignScript.Builtin.Dictionary dsDic) + { + return DictionaryToBase(dsDic); + } - return @base; + if (@object is Dictionary dic) + { + return DictionaryToBase(dic); } - private object RecurseTreeToSpeckle(object @object) + //is item + return TryConvertItemToSpeckle(@object); + } + + private static Dictionary DynamoDictionaryToDictionary(DesignScript.Builtin.Dictionary dsDic) + { + var dict = new Dictionary(); + + dsDic.Keys + .ToList() + .ForEach(key => + { + dict[key] = dsDic.ValueAtKey(key); + }); + return dict; + } + + private Base DictionaryToBase(DesignScript.Builtin.Dictionary dsDic) + { + return DictionaryToBase(DynamoDictionaryToDictionary(dsDic)); + } + + private Base DictionaryToBase(Dictionary dic) + { + var hasSpeckleType = dic.Keys.Contains("speckle_type"); + var @base = new Base(); + var type = @base.GetType(); + if (hasSpeckleType) { - if (IsList(@object)) + // If the dictionary contains a `speckle_type` key, try to find and create an instance of that type + var s = dic["speckle_type"] as string; + + var baseType = typeof(Base); + type = _kit.Types.FirstOrDefault(t => t.FullName == s) ?? baseType; + if (type != baseType) { - var list = ((IEnumerable)@object).Cast().ToList(); - return list.Select(RecurseTreeToSpeckle).ToList(); + @base = Activator.CreateInstance(type) as Base; } + } + var regex = new Regex("//"); + foreach (var key in dic.Keys) + { + // Dynamo does not support `::` in dictionary keys. We use `//` instead. + // Upon send, any `//` must be replaced by `::` again. + var replacedKey = regex.Replace(key, "::"); + + var propInfo = type.GetProperty(key); + var convertedValue = RecurseTreeToSpeckle(dic[key]); - if (@object is DesignScript.Builtin.Dictionary dsDic) + if (propInfo == null) { - return DictionaryToBase(dsDic); + // Key is dynamic, just add it as is + @base[replacedKey] = convertedValue; + continue; } - - if (@object is Dictionary dic) + // It's an instance field, check if we can set it + if (!propInfo.CanWrite) { - return DictionaryToBase(dic); + continue; } - //is item - return TryConvertItemToSpeckle(@object); + // Check if it's a list, and if so, try to create the according typed instance. + if (IsList(convertedValue)) + { + var list = convertedValue as IList; + var genericTypeDefinition = propInfo.PropertyType; + var typedValue = Activator.CreateInstance(genericTypeDefinition) as IList; + foreach (var item in list) + { + typedValue.Add(item); + } + convertedValue = typedValue; + } + @base[replacedKey] = convertedValue; } - private static Dictionary DynamoDictionaryToDictionary(DesignScript.Builtin.Dictionary dsDic) + return @base; + } + + private object TryConvertItemToSpeckle(object value) + { + object result = null; + if (_converter.CanConvertToSpeckle(value)) { - var dict = new Dictionary(); + try + { + return _converter.ConvertToSpeckle(value); + } + catch (Exception ex) + { + var spcklEx = new SpeckleException($"Could not convert {value.GetType().Name} to Speckle:", ex); + OnError?.Invoke(this, new OnErrorEventArgs(spcklEx)); + return null; + } + } - dsDic.Keys - .ToList() - .ForEach(key => - { - dict[key] = dsDic.ValueAtKey(key); - }); - return dict; + if (value is Base || value is null || value.GetType().IsSimpleType()) + { + return value; } - private Base DictionaryToBase(DesignScript.Builtin.Dictionary dsDic) + return result; + } + + private static Regex dataTreePathRegex => new(@"^(@(\(\d+\))?)?(?\{\d+(;\d+)*\})$"); + + public static bool IsDataTree(Base @base) + { + var regex = dataTreePathRegex; + var members = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys.ToList(); + if (members.Count == 0) { - return DictionaryToBase(DynamoDictionaryToDictionary(dsDic)); + return false; } - private Base DictionaryToBase(Dictionary dic) + var isDataTree = members.All(el => regex.Match(el).Success); + return members.Count > 0 && isDataTree; + } + + public object ConvertDataTreeToNative(Base @base) + { + var names = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys.ToList(); + var list = new List(); + foreach (var name in names) { - var hasSpeckleType = dic.Keys.Contains("speckle_type"); - var @base = new Base(); - var type = @base.GetType(); - if (hasSpeckleType) + if (!dataTreePathRegex.Match(name).Success) { - // If the dictionary contains a `speckle_type` key, try to find and create an instance of that type - var s = dic["speckle_type"] as string; - - var baseType = typeof(Base); - type = _kit.Types.FirstOrDefault(t => t.FullName == s) ?? baseType; - if (type != baseType) - @base = Activator.CreateInstance(type) as Base; + continue; // Ignore non matching elements, done for extra safety. } - var regex = new Regex("//"); - foreach (var key in dic.Keys) - { - // Dynamo does not support `::` in dictionary keys. We use `//` instead. - // Upon send, any `//` must be replaced by `::` again. - var replacedKey = regex.Replace(key, "::"); - var propInfo = type.GetProperty(key); - var convertedValue = RecurseTreeToSpeckle(dic[key]); - - if (propInfo == null) + var parts = name.Split('{')[ + 1 + ] // Get everything after open curly brace + .Split('}')[0] // Get everything before close curly brace + .Split(';') // Split by ; + .Select(text => { - // Key is dynamic, just add it as is - @base[replacedKey] = convertedValue; - continue; - } - // It's an instance field, check if we can set it - if (!propInfo.CanWrite) - continue; + int.TryParse(text, out var num); + return num; + }) + .ToList(); - // Check if it's a list, and if so, try to create the according typed instance. - if (IsList(convertedValue)) + var currentList = list; + foreach (var p in parts) + { + while (currentList.Count < p + 1) { - var list = convertedValue as IList; - var genericTypeDefinition = propInfo.PropertyType; - var typedValue = Activator.CreateInstance(genericTypeDefinition) as IList; - foreach (var item in list) - { - typedValue.Add(item); - } - convertedValue = typedValue; + var newList = new List(); + currentList.Add(newList); } - @base[replacedKey] = convertedValue; + + currentList = currentList[p] as List; } - return @base; + var value = @base[name]; + var converted = RecurseTreeToNative(value) as List; + currentList.AddRange(converted); + Console.WriteLine(parts); } + return list; + } - private object TryConvertItemToSpeckle(object value) + /// + /// Helper method to convert a tree-like structure (nested lists) to Native + /// + /// + /// + public object ConvertRecursivelyToNative(Base @base) + { + if (@base == null) { - object result = null; - if (_converter.CanConvertToSpeckle(value)) - { - try - { - return _converter.ConvertToSpeckle(value); - } - catch (Exception ex) - { - var spcklEx = new SpeckleException($"Could not convert {value.GetType().Name} to Speckle:", ex); - OnError?.Invoke(this, new OnErrorEventArgs(spcklEx)); - return null; - } - } - - if (value is Base || value is null || value.GetType().IsSimpleType()) - return value; + return null; + } - return result; + // case 1: it's an item that has a direct conversion method, eg a point + if (_converter.CanConvertToNative(@base)) + { + return TryConvertItemToNative(@base); } - private static Regex dataTreePathRegex => new Regex(@"^(@(\(\d+\))?)?(?\{\d+(;\d+)*\})$"); + // case 2: it's a wrapper Base + // 2a: if there's only one member unpack it + // 2b: otherwise return dictionary of unpacked members + var members = @base + .GetMembers(DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaComputed) + .Keys.ToList(); - public static bool IsDataTree(Base @base) + if (members.Count == 1) { - var regex = dataTreePathRegex; - var members = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys.ToList(); - if (members.Count == 0) - return false; - var isDataTree = members.All(el => regex.Match(el).Success); - return members.Count > 0 && isDataTree; + var converted = RecurseTreeToNative(@base[members.ElementAt(0)]); + return converted; } - public object ConvertDataTreeToNative(Base @base) + var regex = new Regex("::"); + var dict = members.ToDictionary(x => regex.Replace(x, "//"), x => RecurseTreeToNative(@base[x])); + return dict; + } + + private object RecurseTreeToNative(object @object) + { + if (IsList(@object)) { - var names = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys.ToList(); - var list = new List(); - foreach (var name in names) - { - if (!dataTreePathRegex.Match(name).Success) - continue; // Ignore non matching elements, done for extra safety. - - var parts = name.Split('{')[ - 1 - ] // Get everything after open curly brace - .Split('}')[0] // Get everything before close curly brace - .Split(';') // Split by ; - .Select(text => - { - int.TryParse(text, out var num); - return num; - }) - .ToList(); - - var currentList = list; - foreach (var p in parts) - { - while (currentList.Count < p + 1) - { - var newList = new List(); - currentList.Add(newList); - } + var list = ((IEnumerable)@object).Cast(); + return list.Select(RecurseTreeToNative).ToList(); + } + if (@object is Base @base && IsDataTree(@base)) + { + return ConvertDataTreeToNative(@base); + } - currentList = currentList[p] as List; - } + return TryConvertItemToNative(@object); + } - var value = @base[name]; - var converted = RecurseTreeToNative(value) as List; - currentList.AddRange(converted); - Console.WriteLine(parts); - } - return list; + private object TryConvertItemToNative(object value) + { + if (value == null) + { + return null; } - /// - /// Helper method to convert a tree-like structure (nested lists) to Native - /// - /// - /// - public object ConvertRecursivelyToNative(Base @base) + //it's a simple type or not a Base + if (value.GetType().IsSimpleType() || !(value is Base)) { - if (@base == null) - return null; - - // case 1: it's an item that has a direct conversion method, eg a point - if (_converter.CanConvertToNative(@base)) - return TryConvertItemToNative(@base); + return value; + } - // case 2: it's a wrapper Base - // 2a: if there's only one member unpack it - // 2b: otherwise return dictionary of unpacked members - var members = @base + var @base = (Base)value; + //it's an unsupported Base, return a dictionary + if (!_converter.CanConvertToNative(@base)) + { + return @base .GetMembers( DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaComputed ) - .Keys.ToList(); - - if (members.Count == 1) - { - var converted = RecurseTreeToNative(@base[members.ElementAt(0)]); - return converted; - } - - var regex = new Regex("::"); - var dict = members.ToDictionary(x => regex.Replace(x, "//"), x => RecurseTreeToNative(@base[x])); - return dict; + .ToList() + .ToDictionary(pair => pair.Key, pair => RecurseTreeToNative(pair.Value)); } - private object RecurseTreeToNative(object @object) + try { - if (IsList(@object)) - { - var list = ((IEnumerable)@object).Cast(); - return list.Select(RecurseTreeToNative).ToList(); - } - if (@object is Base @base && IsDataTree(@base)) - { - return ConvertDataTreeToNative(@base); - } - - return TryConvertItemToNative(@object); + return _converter.ConvertToNative(@base); } - - private object TryConvertItemToNative(object value) + catch (Exception e) { - if (value == null) - return null; - - //it's a simple type or not a Base - if (value.GetType().IsSimpleType() || !(value is Base)) - { - return value; - } - - var @base = (Base)value; - //it's an unsupported Base, return a dictionary - if (!_converter.CanConvertToNative(@base)) - { - return @base - .GetMembers( - DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaComputed - ) - .ToList() - .ToDictionary(pair => pair.Key, pair => RecurseTreeToNative(pair.Value)); - } - - try - { - return _converter.ConvertToNative(@base); - } - catch (Exception e) - { - var spcklError = new Exception($"Could not convert {@base.GetType().Name}(id={@base.id}) to Dynamo.", e); - OnError?.Invoke(this, new OnErrorEventArgs(spcklError)); - return null; - } + var spcklError = new Exception($"Could not convert {@base.GetType().Name}(id={@base.id}) to Dynamo.", e); + OnError?.Invoke(this, new OnErrorEventArgs(spcklError)); + return null; } + } - public static bool IsList(object @object) + public static bool IsList(object @object) + { + if (@object == null) { - if (@object == null) - return false; - - var type = @object.GetType(); - return ( - typeof(IEnumerable).IsAssignableFrom(type) - && !typeof(IDictionary).IsAssignableFrom(type) - && type != typeof(string) - ); + return false; } - public static bool IsDictionary(object @object) - { - if (@object == null) - return false; + var type = @object.GetType(); + return ( + typeof(IEnumerable).IsAssignableFrom(type) + && !typeof(IDictionary).IsAssignableFrom(type) + && type != typeof(string) + ); + } - Type type = @object.GetType(); - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>); + public static bool IsDictionary(object @object) + { + if (@object == null) + { + return false; } + + Type type = @object.GetType(); + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>); } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Conversion.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Conversion.cs index 67ca784b91..7edfe687c3 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Conversion.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Conversion.cs @@ -1,36 +1,41 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Autodesk.DesignScript.Runtime; using Speckle.Core.Logging; using Speckle.Core.Models; -namespace Speckle.ConnectorDynamo.Functions.Developer +namespace Speckle.ConnectorDynamo.Functions.Developer; + +public static class Conversion { - public static class Conversion + /// + /// Convert data from Dynamo to their Speckle Base equivalent. + /// + /// Dynamo data + /// Base object + public static Base ToSpeckle([ArbitraryDimensionArrayImport] object data) { - /// - /// Convert data from Dynamo to their Speckle Base equivalent. - /// - /// Dynamo data - /// Base object - public static Base ToSpeckle([ArbitraryDimensionArrayImport] object data) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Convert To Speckle" } }); - var converter = new BatchConverter(); - converter.OnError += (sender, args) => throw args.Error; - return converter.ConvertRecursivelyToSpeckle(data); - } + Analytics.TrackEvent( + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Convert To Speckle" } } + ); + var converter = new BatchConverter(); + converter.OnError += (sender, args) => throw args.Error; + return converter.ConvertRecursivelyToSpeckle(data); + } - /// - /// Convert data from Speckle's Base object to it`s Dynamo equivalent. - /// - /// Base object - /// Dynamo data - public static object ToNative(Base @base) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Convert To Native" } }); - var converter = new BatchConverter(); - converter.OnError += (sender, args) => throw args.Error; - return converter.ConvertRecursivelyToNative(@base); - } + /// + /// Convert data from Speckle's Base object to it`s Dynamo equivalent. + /// + /// Base object + /// Dynamo data + public static object ToNative(Base @base) + { + Analytics.TrackEvent( + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Convert To Native" } } + ); + var converter = new BatchConverter(); + converter.OnError += (sender, args) => throw args.Error; + return converter.ConvertRecursivelyToNative(@base); } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Local.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Local.cs index 85a64b2762..539da13ee2 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Local.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Local.cs @@ -1,48 +1,47 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using Autodesk.DesignScript.Runtime; using Speckle.Core.Api; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.Functions.Developer +namespace Speckle.ConnectorDynamo.Functions.Developer; + +public static class Local { - public static class Local + /// + /// Sends data locally, without the need of a Speckle Server + /// + /// Data to send + /// ID of the local data sent + public static string Send([ArbitraryDimensionArrayImport] object data) { - /// - /// Sends data locally, without the need of a Speckle Server - /// - /// Data to send - /// ID of the local data sent - public static string Send([ArbitraryDimensionArrayImport] object data) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Send Local" } }); - - var converter = new BatchConverter(); - converter.OnError += (sender, args) => throw args.Error; - - var @base = converter.ConvertRecursivelyToSpeckle(data); - var objectId = Task.Run(async () => await Operations.Send(@base, disposeTransports: true)).Result; - - return objectId; - } - - /// - /// Receives data locally, without the need of a Speckle Server - /// NOTE: updates will not be automatically received. - /// - /// ID of the local data to receive - /// Data received - public static object Receive(string localDataId) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Receive Local" } }); - - var @base = Task.Run(async () => await Operations.Receive(localDataId, disposeTransports: true)).Result; - var converter = new BatchConverter(); - // If a conversion error occurs, throw error. - converter.OnError += (sender, args) => throw args.Error; - - var data = converter.ConvertRecursivelyToNative(@base); - return data; - } + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Send Local" } }); + + var converter = new BatchConverter(); + converter.OnError += (sender, args) => throw args.Error; + + var @base = converter.ConvertRecursivelyToSpeckle(data); + var objectId = Task.Run(async () => await Operations.Send(@base, disposeTransports: true)).Result; + + return objectId; + } + + /// + /// Receives data locally, without the need of a Speckle Server + /// NOTE: updates will not be automatically received. + /// + /// ID of the local data to receive + /// Data received + public static object Receive(string localDataId) + { + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Receive Local" } }); + + var @base = Task.Run(async () => await Operations.Receive(localDataId, disposeTransports: true)).Result; + var converter = new BatchConverter(); + // If a conversion error occurs, throw error. + converter.OnError += (sender, args) => throw args.Error; + + var data = converter.ConvertRecursivelyToNative(@base); + return data; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Serialization.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Serialization.cs index edb1ce1266..9355392359 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Serialization.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Serialization.cs @@ -1,32 +1,31 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Speckle.Core.Api; using Speckle.Core.Logging; using Speckle.Core.Models; -namespace Speckle.ConnectorDynamo.Functions.Developer +namespace Speckle.ConnectorDynamo.Functions.Developer; + +public static class Serialization { - public static class Serialization + /// + /// Serialize a Speckle Base object to JSON + /// + /// Speckle Base objects to serialize. + /// Serialized object in JSON format. + public static string Serialize(Base @base) { - /// - /// Serialize a Speckle Base object to JSON - /// - /// Speckle Base objects to serialize. - /// Serialized object in JSON format. - public static string Serialize(Base @base) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Serialize" } }); - return Operations.Serialize(@base); - } + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Serialize" } }); + return Operations.Serialize(@base); + } - /// - /// Deserialize JSON text to a Speckle Base object - /// - /// Serialized objects in JSON format. - /// Deserialized Speckle Base objects. - public static object Deserialize(string json) - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Deserialize" } }); - return Operations.Deserialize(json); - } + /// + /// Deserialize JSON text to a Speckle Base object + /// + /// Serialized objects in JSON format. + /// Deserialized Speckle Base objects. + public static object Deserialize(string json) + { + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Deserialize" } }); + return Operations.Deserialize(json); } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Transport.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Transport.cs index 7465188398..d3023025ca 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Transport.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Developer/Transport.cs @@ -10,94 +10,108 @@ using Speckle.Core.Logging; using Speckle.Core.Transports; -namespace Speckle.ConnectorDynamo.Functions.Developer +namespace Speckle.ConnectorDynamo.Functions.Developer; + +public static class Transport { - public static class Transport + /// + /// Creates a Disk Transport. + /// + /// The root folder where you want the data to be stored. Defaults to `%appdata%/Speckle/DiskTransportFiles`. + /// The Disk Transport you have created. + [NodeCategory("Transports")] + public static object DiskTransport(string basePath = "") { - /// - /// Creates a Disk Transport. - /// - /// The root folder where you want the data to be stored. Defaults to `%appdata%/Speckle/DiskTransportFiles`. - /// The Disk Transport you have created. - [NodeCategory("Transports")] - public static object DiskTransport(string basePath = "") + if (string.IsNullOrEmpty(basePath)) { - if (string.IsNullOrEmpty(basePath)) - basePath = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "DiskTransportFiles"); - - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Disk Transport" } }); - - return new DiskTransport.DiskTransport(basePath); + basePath = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "DiskTransportFiles"); } - /// - /// Creates an Memory Transport. - /// - /// The name of this Memory Transport. - /// The Memory Transport you have created. - [NodeCategory("Transports")] - public static object MemoryTransport(string name = "Memory") - { - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Memory Transport" } }); - return new MemoryTransport { TransportName = name }; - } + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Disk Transport" } }); - /// - /// Creates a Server Transport. - /// - /// The Stream you want to send data to. - /// The Server Transport you have created. - [NodeCategory("Transports")] - public static object ServerTransport(StreamWrapper stream) - { + return new DiskTransport.DiskTransport(basePath); + } + + /// + /// Creates an Memory Transport. + /// + /// The name of this Memory Transport. + /// The Memory Transport you have created. + [NodeCategory("Transports")] + public static object MemoryTransport(string name = "Memory") + { + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Memory Transport" } }); + return new MemoryTransport { TransportName = name }; + } - var userId = stream.UserId; - Core.Credentials.Account account; + /// + /// Creates a Server Transport. + /// + /// The Stream you want to send data to. + /// The Server Transport you have created. + [NodeCategory("Transports")] + public static object ServerTransport(StreamWrapper stream) + { + var userId = stream.UserId; + Core.Credentials.Account account; - account = AccountManager.GetAccounts().FirstOrDefault(a => a.userInfo.id == userId); - Exception error = null; + account = AccountManager.GetAccounts().FirstOrDefault(a => a.userInfo.id == userId); + Exception error = null; + if (account == null) + { + // Get the default account + account = AccountManager.GetAccounts(stream.ServerUrl).FirstOrDefault(); + error = new WarningException( + "Original account not found. Please make sure you have permissions to access this stream!" + ); if (account == null) { - // Get the default account - account = AccountManager.GetAccounts(stream.ServerUrl).FirstOrDefault(); - error = new WarningException( - "Original account not found. Please make sure you have permissions to access this stream!"); - if (account == null) - { - // No default - error = new WarningException( - $"No account found for {stream.ServerUrl}."); - } + // No default + error = new WarningException($"No account found for {stream.ServerUrl}."); } + } - if (error != null) throw error; + if (error != null) + { + throw error; + } - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Server Transport" } }); + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "Server Transport" } }); + return new ServerTransport(account, stream.StreamId); + } - return new ServerTransport(account, stream.StreamId); + /// + /// Creates an SQLite Transport. + /// + /// The root folder where you want the sqlite db to be stored. Defaults to `%appdata%`. + /// The subfolder you want the sqlite db to be stored. Defaults to `Speckle`. + /// The name of the actual database file. Defaults to `UserLocalDefaultDb`. + /// + [NodeCategory("Transports")] + public static object SQLiteTransport( + string basePath = "", + string applicationName = "Speckle", + string scope = "UserLocalDefaultDb" + ) + { + if (string.IsNullOrEmpty(basePath)) + { + basePath = null; } - /// - /// Creates an SQLite Transport. - /// - /// The root folder where you want the sqlite db to be stored. Defaults to `%appdata%`. - /// The subfolder you want the sqlite db to be stored. Defaults to `Speckle`. - /// The name of the actual database file. Defaults to `UserLocalDefaultDb`. - /// - [NodeCategory("Transports")] - public static object SQLiteTransport(string basePath = "", string applicationName = "Speckle", string scope = "UserLocalDefaultDb") + if (string.IsNullOrEmpty(applicationName)) { - if (string.IsNullOrEmpty(basePath)) - basePath = null; - if (string.IsNullOrEmpty(applicationName)) - applicationName = "Speckle"; - if (string.IsNullOrEmpty(scope)) - scope = "UserLocalDefaultDb"; - - Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "SQLite Transport" } }); + applicationName = "Speckle"; + } - return new SQLiteTransport(basePath, applicationName, scope); + if (string.IsNullOrEmpty(scope)) + { + scope = "UserLocalDefaultDb"; } + + Analytics.TrackEvent(Analytics.Events.NodeRun, new Dictionary() { { "name", "SQLite Transport" } }); + + return new SQLiteTransport(basePath, applicationName, scope); } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Functions.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Functions.cs index e8070350b2..493ab9b152 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Functions.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Functions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -15,246 +15,255 @@ using Speckle.Core.Transports; using static System.Resources.ResXFileRef; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +/// +/// Functions that are to be called by NodeModel nodes +/// +[IsVisibleInDynamoLibrary(false)] +public static class Functions { /// - /// Functions that are to be called by NodeModel nodes + /// Sends data to a Speckle Server by creating a commit on the master branch of a Stream /// - [IsVisibleInDynamoLibrary(false)] - public static class Functions + /// Data to send + /// Transports to send the data to + /// Log + public static List Send( + Base data, + List transports, + CancellationToken cancellationToken, + Dictionary branchNames = null, + string message = "", + Action> onProgressAction = null, + Action onErrorAction = null + ) { - /// - /// Sends data to a Speckle Server by creating a commit on the master branch of a Stream - /// - /// Data to send - /// Transports to send the data to - /// Log - public static List Send( - Base data, - List transports, - CancellationToken cancellationToken, - Dictionary branchNames = null, - string message = "", - Action> onProgressAction = null, - Action onErrorAction = null - ) - { - var commitWrappers = new List(); - var responses = new List(); + var commitWrappers = new List(); + var responses = new List(); - long totalCount = 0; - try - { - totalCount = data?.GetTotalChildrenCount() ?? 0; - } - catch (Exception e) { } + long totalCount = 0; + try + { + totalCount = data?.GetTotalChildrenCount() ?? 0; + } + catch (Exception e) { } - if (totalCount == 0) - throw new SpeckleException("Zero objects converted successfully. Send stopped."); + if (totalCount == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } - if (string.IsNullOrEmpty(message)) - { - var plural = (totalCount == 1) ? "" : "s"; - message = $"Sent {totalCount} object{plural} from Dynamo"; - } + if (string.IsNullOrEmpty(message)) + { + var plural = (totalCount == 1) ? "" : "s"; + message = $"Sent {totalCount} object{plural} from Dynamo"; + } - var objectId = Operations - .Send(data, cancellationToken, new List(transports), true, onProgressAction, onErrorAction) - .Result; + var objectId = Operations + .Send(data, cancellationToken, new List(transports), true, onProgressAction, onErrorAction) + .Result; - if (cancellationToken.IsCancellationRequested) - return null; + if (cancellationToken.IsCancellationRequested) + { + return null; + } - foreach (var t in transports) + foreach (var t in transports) + { + // Only create commits on ServerTransport instances (for now) + if (!(t is ServerTransport serverTransport)) { - // Only create commits on ServerTransport instances (for now) - if (!(t is ServerTransport serverTransport)) - { - //commitWrappers.Add(t + objectId); - continue; - } - var branchName = branchNames == null ? "main" : branchNames[t]; - var client = new Client(serverTransport.Account); - try - { - var res = client - .CommitCreate( - new CommitCreateInput - { - streamId = serverTransport.StreamId, - branchName = branchName, - objectId = objectId, - message = message, - sourceApplication = Utils.GetAppName(), - parents = new List { serverTransport.StreamId } - }, - cancellationToken - ) - .Result; - - responses.Add(res); - var wrapper = new StreamWrapper( - serverTransport.StreamId, - serverTransport.Account.userInfo.id, - serverTransport.BaseUri + //commitWrappers.Add(t + objectId); + continue; + } + var branchName = branchNames == null ? "main" : branchNames[t]; + var client = new Client(serverTransport.Account); + try + { + var res = client + .CommitCreate( + new CommitCreateInput + { + streamId = serverTransport.StreamId, + branchName = branchName, + objectId = objectId, + message = message, + sourceApplication = Utils.GetAppName(), + parents = new List { serverTransport.StreamId } + }, + cancellationToken ) - { - CommitId = res - }; - commitWrappers.Add(wrapper.ToString()); - Analytics.TrackEvent(client.Account, Analytics.Events.Send); - } - catch (Exception ex) + .Result; + + responses.Add(res); + var wrapper = new StreamWrapper( + serverTransport.StreamId, + serverTransport.Account.userInfo.id, + serverTransport.BaseUri + ) { - Utils.HandleApiExeption(ex); - return null; - } + CommitId = res + }; + commitWrappers.Add(wrapper.ToString()); + Analytics.TrackEvent(client.Account, Analytics.Events.Send); + } + catch (Exception ex) + { + Utils.HandleApiExeption(ex); + return null; } - - return commitWrappers; } - public static object SendData(string output) - { - var commits = output.Split('|').ToList(); - if (commits.Count == 1) - return commits[0]; + return commitWrappers; + } - return commits; + public static object SendData(string output) + { + var commits = output.Split('|').ToList(); + if (commits.Count == 1) + { + return commits[0]; } - /// - /// Receives data from a Speckle Server by getting the last commit on the master branch of a Stream - /// - /// Stream to receive from - /// - [MultiReturn(new[] { "data", "commit" })] - public static Dictionary Receive( - StreamWrapper stream, - CancellationToken cancellationToken, - Action> onProgressAction = null, - Action onErrorAction = null, - Action onTotalChildrenCountKnown = null - ) - { - var account = stream.GetAccount().Result; - // + return commits; + } - var client = new Client(account); - Commit commit = null; + /// + /// Receives data from a Speckle Server by getting the last commit on the master branch of a Stream + /// + /// Stream to receive from + /// + [MultiReturn(new[] { "data", "commit" })] + public static Dictionary Receive( + StreamWrapper stream, + CancellationToken cancellationToken, + Action> onProgressAction = null, + Action onErrorAction = null, + Action onTotalChildrenCountKnown = null + ) + { + var account = stream.GetAccount().Result; + // - if (stream.Type == StreamWrapperType.Stream || stream.Type == StreamWrapperType.Branch) - { - stream.BranchName = string.IsNullOrEmpty(stream.BranchName) ? "main" : stream.BranchName; + var client = new Client(account); + Commit commit = null; - try - { - var branch = client.BranchGet(stream.StreamId, stream.BranchName, 1, cancellationToken).Result; - if (!branch.commits.items.Any()) - { - throw new SpeckleException("No commits found."); - } + if (stream.Type == StreamWrapperType.Stream || stream.Type == StreamWrapperType.Branch) + { + stream.BranchName = string.IsNullOrEmpty(stream.BranchName) ? "main" : stream.BranchName; - commit = branch.commits.items[0]; - } - catch - { - throw new SpeckleException("No branch found with name " + stream.BranchName); - } - } - else if (stream.Type == StreamWrapperType.Commit) + try { - try - { - commit = client.CommitGet(stream.StreamId, stream.CommitId!, cancellationToken).Result; - } - catch (Exception ex) + var branch = client.BranchGet(stream.StreamId, stream.BranchName, 1, cancellationToken).Result; + if (!branch.commits.items.Any()) { - Utils.HandleApiExeption(ex); - return null; + throw new SpeckleException("No commits found."); } - } - else if (stream.Type == StreamWrapperType.Object) - { - commit = new Commit() { referencedObject = stream.ObjectId, id = Guid.NewGuid().ToString() }; - } - if (commit == null) - { - throw new SpeckleException("Could not get commit."); + commit = branch.commits.items[0]; } - - if (cancellationToken.IsCancellationRequested) - return null; - - var transport = new ServerTransport(account, stream.StreamId); - - var @base = Operations - .Receive( - commit.referencedObject, - cancellationToken, - remoteTransport: transport, - onProgressAction: onProgressAction, - onErrorAction: ((s, exception) => throw exception), - onTotalChildrenCountKnown: onTotalChildrenCountKnown, - disposeTransports: true - ) - .Result; - - if (@base == null) + catch { - throw new SpeckleException("Receive operation returned nothing"); + throw new SpeckleException("No branch found with name " + stream.BranchName); } + } + else if (stream.Type == StreamWrapperType.Commit) + { try { - client - .CommitReceived( - new CommitReceivedInput - { - streamId = stream.StreamId, - commitId = commit?.id, - message = commit?.message, - sourceApplication = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit) - } - ) - .Wait(); + commit = client.CommitGet(stream.StreamId, stream.CommitId!, cancellationToken).Result; } - catch + catch (Exception ex) { - // Do nothing! + Utils.HandleApiExeption(ex); + return null; } + } + else if (stream.Type == StreamWrapperType.Object) + { + commit = new Commit() { referencedObject = stream.ObjectId, id = Guid.NewGuid().ToString() }; + } - if (cancellationToken.IsCancellationRequested) - return null; + if (commit == null) + { + throw new SpeckleException("Could not get commit."); + } - var converter = new BatchConverter(); - converter.OnError += (sender, args) => onErrorAction?.Invoke("C", args.Error); + if (cancellationToken.IsCancellationRequested) + { + return null; + } - var data = converter.ConvertRecursivelyToNative(@base); + var transport = new ServerTransport(account, stream.StreamId); - Analytics.TrackEvent( - client.Account, - Analytics.Events.Receive, - new Dictionary() - { - { "sourceHostApp", HostApplications.GetHostAppFromString(commit.sourceApplication)?.Slug }, - { "sourceHostAppVersion", commit.sourceApplication }, - { "isMultiplayer", commit.authorId != client.Account.userInfo.id } - } - ); + var @base = Operations + .Receive( + commit.referencedObject, + cancellationToken, + remoteTransport: transport, + onProgressAction: onProgressAction, + onErrorAction: ((s, exception) => throw exception), + onTotalChildrenCountKnown: onTotalChildrenCountKnown, + disposeTransports: true + ) + .Result; - return new Dictionary { { "data", data }, { "commit", commit } }; + if (@base == null) + { + throw new SpeckleException("Receive operation returned nothing"); } - - public static object ReceiveData(string inMemoryDataId) + try + { + client + .CommitReceived( + new CommitReceivedInput + { + streamId = stream.StreamId, + commitId = commit?.id, + message = commit?.message, + sourceApplication = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit) + } + ) + .Wait(); + } + catch { - return InMemoryCache.Get(inMemoryDataId)["data"]; + // Do nothing! } - public static string ReceiveInfo(string inMemoryDataId) + if (cancellationToken.IsCancellationRequested) { - var commit = InMemoryCache.Get(inMemoryDataId)["commit"] as Commit; - return $"{commit.authorName} @ {commit.createdAt}: {commit.message} (id:{commit.id})"; + return null; } + + var converter = new BatchConverter(); + converter.OnError += (sender, args) => onErrorAction?.Invoke("C", args.Error); + + var data = converter.ConvertRecursivelyToNative(@base); + + Analytics.TrackEvent( + client.Account, + Analytics.Events.Receive, + new Dictionary() + { + { "sourceHostApp", HostApplications.GetHostAppFromString(commit.sourceApplication)?.Slug }, + { "sourceHostAppVersion", commit.sourceApplication }, + { "isMultiplayer", commit.authorId != client.Account.userInfo.id } + } + ); + + return new Dictionary { { "data", data }, { "commit", commit } }; + } + + public static object ReceiveData(string inMemoryDataId) + { + return InMemoryCache.Get(inMemoryDataId)["data"]; + } + + public static string ReceiveInfo(string inMemoryDataId) + { + var commit = InMemoryCache.Get(inMemoryDataId)["commit"] as Commit; + return $"{commit.authorName} @ {commit.createdAt}: {commit.message} (id:{commit.id})"; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Globals.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Globals.cs index 074d92d6fb..9f4a3ec07e 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Globals.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Globals.cs @@ -1,18 +1,17 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Autodesk.DesignScript.Runtime; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +[IsVisibleInDynamoLibrary(false)] +public static class Globals { - [IsVisibleInDynamoLibrary(false)] - public static class Globals - { - /// - /// Cached Revit Document, required to properly scale incoming / outcoming geometry - /// - public static object RevitDocument { get; set; } - } + /// + /// Cached Revit Document, required to properly scale incoming / outcoming geometry + /// + public static object RevitDocument { get; set; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Icon.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Icon.cs index 9fd217d228..2dc3873fce 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Icon.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Icon.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,25 +6,24 @@ using Autodesk.DesignScript.Geometry; using Autodesk.DesignScript.Runtime; -namespace Speckle.ConnectorDynamo.Functions.AAA +namespace Speckle.ConnectorDynamo.Functions.AAA; + +public static class ASpeckleBrick { - public static class ASpeckleBrick + public static List Brick() { - public static List Brick() + var points = new List(); + for (var x = 0; x < 10; x++) { - var points = new List(); - for (var x = 0; x < 10; x++) + for (var y = 0; y < 10; y++) { - for (var y = 0; y < 10; y++) + for (var z = 0; z < 10; z++) { - for (var z = 0; z < 10; z++) - { - points.Add(Point.ByCoordinates(x, y, z)); - } + points.Add(Point.ByCoordinates(x, y, z)); } } - - return points; } + + return points; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/InMemoryCache.cs b/ConnectorDynamo/ConnectorDynamoFunctions/InMemoryCache.cs index c68d3f1896..fc85569b73 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/InMemoryCache.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/InMemoryCache.cs @@ -1,30 +1,32 @@ -using Autodesk.DesignScript.Runtime; +using Autodesk.DesignScript.Runtime; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +/// +/// In memory cache to have the receive node return data that is not coming from the ASTfunction call +/// +[IsVisibleInDynamoLibrary(false)] +public static class InMemoryCache { - /// - /// In memory cache to have the receive node return data that is not coming from the ASTfunction call - /// - [IsVisibleInDynamoLibrary(false)] - public static class InMemoryCache - { - private static Dictionary> _cache = new Dictionary>(); + private static Dictionary> _cache = new(); - public static Dictionary Get(string id) + public static Dictionary Get(string id) + { + if (_cache.ContainsKey(id)) { - if (_cache.ContainsKey(id)) - return _cache[id]; - return null; + return _cache[id]; } - public static void Set(string id, Dictionary dic) - { - _cache[id] = dic; - } + return null; + } + + public static void Set(string id, Dictionary dic) + { + _cache[id] = dic; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/OnErrorEventArgs.cs b/ConnectorDynamo/ConnectorDynamoFunctions/OnErrorEventArgs.cs index d0ba4df3fa..93653fbbd7 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/OnErrorEventArgs.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/OnErrorEventArgs.cs @@ -1,16 +1,15 @@ -using System; +using System; using Autodesk.DesignScript.Runtime; -namespace Speckle.ConnectorDynamo +namespace Speckle.ConnectorDynamo; + +[IsVisibleInDynamoLibrary(false)] +public class OnErrorEventArgs { - [IsVisibleInDynamoLibrary(false)] - public class OnErrorEventArgs - { - public Exception Error; + public Exception Error; - public OnErrorEventArgs(Exception error) - { - Error = error; - } + public OnErrorEventArgs(Exception error) + { + Error = error; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Stream.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Stream.cs index bf18edc0e6..a8b7bf009a 100755 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Stream.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Stream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -8,180 +8,204 @@ using Speckle.Core.Credentials; using Speckle.Core.Logging; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +public static class Stream { - public static class Stream + /// + /// Get an existing Stream + /// + /// Stream to get with the specified account + /// Optional Speckle account to get the Stream with + /// A Stream + [NodeCategory("Create")] + public static object Get( + [ArbitraryDimensionArrayImport] object stream, + [DefaultArgument("null")] Core.Credentials.Account account + ) { - /// - /// Get an existing Stream - /// - /// Stream to get with the specified account - /// Optional Speckle account to get the Stream with - /// A Stream - [NodeCategory("Create")] - public static object Get([ArbitraryDimensionArrayImport] object stream, [DefaultArgument("null")] Core.Credentials.Account account) - { - - var streams = Utils.InputToStream(stream); - if (!streams.Any()) - { - throw new SpeckleException("Please provide one or more Stream Ids."); - } - else if (streams.Count > 20) - { - throw new SpeckleException("Please provide less than 20 Stream Ids."); - } + var streams = Utils.InputToStream(stream); + if (!streams.Any()) + { + throw new SpeckleException("Please provide one or more Stream Ids."); + } + else if (streams.Count > 20) + { + throw new SpeckleException("Please provide less than 20 Stream Ids."); + } - try + try + { + foreach (var s in streams) { - - foreach (var s in streams) + //lets ppl override the account for the specified stream + Core.Credentials.Account accountToUse = null; + if (account != null) { - //lets ppl override the account for the specified stream - Core.Credentials.Account accountToUse = null; - if (account != null) - accountToUse = account; - else - accountToUse = Task.Run(async () => await s.GetAccount()).Result; + accountToUse = account; + } + else + { + accountToUse = Task.Run(async () => await s.GetAccount()).Result; + } - var client = new Client(accountToUse); + var client = new Client(accountToUse); - //Exists? - Core.Api.Stream res = Task.Run(async () => await client.StreamGet(s.StreamId)).Result; - s.UserId = accountToUse.userInfo.id; + //Exists? + Core.Api.Stream res = Task.Run(async () => await client.StreamGet(s.StreamId)).Result; + s.UserId = accountToUse.userInfo.id; - Analytics.TrackEvent(accountToUse, Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream Get" } }); - } + Analytics.TrackEvent( + accountToUse, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Stream Get" } } + ); } - catch (Exception ex) - { - Utils.HandleApiExeption(ex); - } - + } + catch (Exception ex) + { + Utils.HandleApiExeption(ex); + } + if (streams.Count() == 1) + { + return streams[0]; + } - if (streams.Count() == 1) - return streams[0]; + return streams; + } - return streams; + /// + /// Update a Stream details, use is limited to 1 stream at a time + /// + /// Stream object to update + /// Name of the Stream + /// Description of the Stream + /// True if the stream is to be publicly available + /// Updated Stream object + public static StreamWrapper Update( + [DefaultArgument("null")] object stream, + [DefaultArgument("null")] string name, + [DefaultArgument("null")] string description, + [DefaultArgument("null")] bool? isPublic + ) + { + if (stream == null) + { + return null; } - /// - /// Update a Stream details, use is limited to 1 stream at a time - /// - /// Stream object to update - /// Name of the Stream - /// Description of the Stream - /// True if the stream is to be publicly available - /// Updated Stream object - public static StreamWrapper Update([DefaultArgument("null")] object stream, [DefaultArgument("null")] string name, [DefaultArgument("null")] string description, [DefaultArgument("null")] bool? isPublic) - { - if (stream == null) - { - return null; - } + var wrapper = Utils.ParseWrapper(stream); - var wrapper = Utils.ParseWrapper(stream); + if (wrapper == null) + { + throw new SpeckleException("Invalid stream."); + } - if (wrapper == null) - { - throw new SpeckleException("Invalid stream."); - } + if (name == null && description == null && isPublic == null) + { + return null; + } - if (name == null && description == null && isPublic == null) - return null; + Core.Credentials.Account account = null; + try + { + account = Task.Run(async () => await wrapper.GetAccount()).Result; + } + catch (Exception e) + { + throw e.InnerException ?? e; + } - Core.Credentials.Account account = null; - try - { - account = Task.Run(async () => await wrapper.GetAccount()).Result; - } - catch (Exception e) - { - throw e.InnerException ?? e; - } + var client = new Client(account); - var client = new Client(account); + var input = new StreamUpdateInput { id = wrapper.StreamId }; - var input = new StreamUpdateInput { id = wrapper.StreamId }; + if (name != null) + { + input.name = name; + } - if (name != null) - input.name = name; + if (description != null) + { + input.description = description; + } - if (description != null) - input.description = description; + if (isPublic != null) + { + input.isPublic = (bool)isPublic; + } - if (isPublic != null) - input.isPublic = (bool)isPublic; + Analytics.TrackEvent( + account, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Stream Update" } } + ); - Analytics.TrackEvent(account, Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream Update" } }); + try + { + var res = Task.Run(async () => await client.StreamUpdate(input)).Result; - try + if (res) { - var res = Task.Run(async () => await client.StreamUpdate(input)).Result; - - if (res) - return wrapper; + return wrapper; } - catch (Exception ex) - { - Utils.HandleApiExeption(ex); - } - - return null; } - - /// - /// Extracts the details of a given stream, use is limited to max 20 streams - /// - /// Stream object - [NodeCategory("Query")] - [MultiReturn(new[] - { - "id", - "name", - "description", - "createdAt", - "updatedAt", - "isPublic", - "collaborators", - "branches" - })] - public static object Details([ArbitraryDimensionArrayImport] object stream) + catch (Exception ex) { + Utils.HandleApiExeption(ex); + } + return null; + } - var streams = Utils.InputToStream(stream); + /// + /// Extracts the details of a given stream, use is limited to max 20 streams + /// + /// Stream object + [NodeCategory("Query")] + [MultiReturn( + new[] { "id", "name", "description", "createdAt", "updatedAt", "isPublic", "collaborators", "branches" } + )] + public static object Details([ArbitraryDimensionArrayImport] object stream) + { + var streams = Utils.InputToStream(stream); - if (!streams.Any()) - throw new SpeckleException("Please provide one or more Streams."); + if (!streams.Any()) + { + throw new SpeckleException("Please provide one or more Streams."); + } - if (streams.Count > 20) - throw new SpeckleException("Please provide less than 20 Streams."); + if (streams.Count > 20) + { + throw new SpeckleException("Please provide less than 20 Streams."); + } - var details = new List>(); + var details = new List>(); - foreach (var streamWrapper in streams) - { - Core.Credentials.Account account; + foreach (var streamWrapper in streams) + { + Core.Credentials.Account account; - try - { - account = Task.Run(async () => await streamWrapper.GetAccount()).Result; - } - catch (Exception e) - { - throw e.InnerException ?? e; - } + try + { + account = Task.Run(async () => await streamWrapper.GetAccount()).Result; + } + catch (Exception e) + { + throw e.InnerException ?? e; + } - var client = new Client(account); + var client = new Client(account); - try - { - Core.Api.Stream res = Task.Run(async () => await client.StreamGet(streamWrapper.StreamId)).Result; + try + { + Core.Api.Stream res = Task.Run(async () => await client.StreamGet(streamWrapper.StreamId)).Result; - details.Add(new Dictionary - { { "id", res.id }, + details.Add( + new Dictionary + { + { "id", res.id }, { "name", res.name }, { "description", res.description }, { "createdAt", res.createdAt }, @@ -189,59 +213,75 @@ public static object Details([ArbitraryDimensionArrayImport] object stream) { "isPublic", res.isPublic }, { "collaborators", res.collaborators }, { "branches", res.branches?.items } - }); - } - catch (Exception ex) - { - Utils.HandleApiExeption(ex); - return details; - } - Analytics.TrackEvent(account, Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream Details" } }); + } + ); } + catch (Exception ex) + { + Utils.HandleApiExeption(ex); + return details; + } + Analytics.TrackEvent( + account, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Stream Details" } } + ); + } + if (details.Count() == 1) + { + return details[0]; + } + return details; + } - if (details.Count() == 1) - return details[0]; - - return details; + /// + /// List all your Streams + /// + /// Speckle account to use, if not provided the default account will be used + /// Max number of streams to get + /// Your Streams + [NodeCategory("Query")] + public static List List( + [DefaultArgument("null")] Core.Credentials.Account account = null, + [DefaultArgument("10")] int limit = 10 + ) + { + if (account == null) + { + account = AccountManager.GetDefaultAccount(); } - /// - /// List all your Streams - /// - /// Speckle account to use, if not provided the default account will be used - /// Max number of streams to get - /// Your Streams - [NodeCategory("Query")] - public static List List([DefaultArgument("null")] Core.Credentials.Account account = null, [DefaultArgument("10")] int limit = 10) + if (account == null) { + Utils.HandleApiExeption( + new Exception("No accounts found. Please use the Speckle Manager to manage your accounts on this computer.") + ); + } - if (account == null) - account = AccountManager.GetDefaultAccount(); - - if (account == null) - { - Utils.HandleApiExeption(new Exception("No accounts found. Please use the Speckle Manager to manage your accounts on this computer.")); - } - - var client = new Client(account); - var streamWrappers = new List(); + var client = new Client(account); + var streamWrappers = new List(); - try - { - var res = Task.Run(async () => await client.StreamsGet(limit)).Result; - res.ForEach(x => { streamWrappers.Add(new StreamWrapper(x.id, account.userInfo.id, account.serverInfo.url)); }); - } - catch (Exception ex) + try + { + var res = Task.Run(async () => await client.StreamsGet(limit)).Result; + res.ForEach(x => { - Utils.HandleApiExeption(ex); - } - - Analytics.TrackEvent(account, Analytics.Events.NodeRun, new Dictionary() { { "name", "Stream List" } }); + streamWrappers.Add(new StreamWrapper(x.id, account.userInfo.id, account.serverInfo.url)); + }); + } + catch (Exception ex) + { + Utils.HandleApiExeption(ex); + } - return streamWrappers; + Analytics.TrackEvent( + account, + Analytics.Events.NodeRun, + new Dictionary() { { "name", "Stream List" } } + ); - } + return streamWrappers; } } diff --git a/ConnectorDynamo/ConnectorDynamoFunctions/Utils.cs b/ConnectorDynamo/ConnectorDynamoFunctions/Utils.cs index 2680ba49ec..32cb481a28 100644 --- a/ConnectorDynamo/ConnectorDynamoFunctions/Utils.cs +++ b/ConnectorDynamo/ConnectorDynamoFunctions/Utils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -6,123 +6,110 @@ using Speckle.Core.Kits; using Speckle.Core.Transports; -namespace Speckle.ConnectorDynamo.Functions +namespace Speckle.ConnectorDynamo.Functions; + +public static class Utils { - public static class Utils + public static Dictionary TryConvertInputToTransport(object o) { + var defaultBranch = "main"; + var transports = new Dictionary(); - public static Dictionary TryConvertInputToTransport(object o) + switch (o) { - var defaultBranch = "main"; - var transports = new Dictionary(); + case StreamWrapper s: + var wrapperTransport = new ServerTransport(s.GetAccount().Result, s.StreamId); + var branch = s.BranchName ?? defaultBranch; + transports.Add(wrapperTransport, branch); + + break; + case string s: + var streamWrapper = new StreamWrapper(s); + var transport = new ServerTransport(streamWrapper.GetAccount().Result, streamWrapper.StreamId); + var b = streamWrapper.BranchName ?? defaultBranch; + transports.Add(transport, b); + break; + case ITransport t: + transports.Add(t, defaultBranch); + break; + case List s: + transports = s.Select(TryConvertInputToTransport) + .Aggregate( + transports, + (current, t) => + new List> { current, t } + .SelectMany(dict => dict) + .ToDictionary(pair => pair.Key, pair => pair.Value) + ); + break; + default: + //Warning("Input was neither a transport nor a stream."); + break; + } - switch (o) - { - case StreamWrapper s: - var wrapperTransport = new ServerTransport(s.GetAccount().Result, s.StreamId); - var branch = s.BranchName ?? defaultBranch; - transports.Add(wrapperTransport, branch); - - break; - case string s: - var streamWrapper = new StreamWrapper(s); - var transport = new ServerTransport(streamWrapper.GetAccount().Result, streamWrapper.StreamId); - var b = streamWrapper.BranchName ?? defaultBranch; - transports.Add(transport, b); - break; - case ITransport t: - transports.Add(t, defaultBranch); - break; - case List s: - transports = s - .Select(TryConvertInputToTransport) - .Aggregate(transports, (current, t) => new List> { current, t } - .SelectMany(dict => dict) - .ToDictionary(pair => pair.Key, pair => pair.Value)); - break; - default: - //Warning("Input was neither a transport nor a stream."); - break; - } + return transports; + } - return transports; + /// Gets the App name from the injected Doc without requiring a dependency on the Revit dll + internal static string GetAppName() + { + if (Globals.RevitDocument == null) + { + return HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox); } - - /// Gets the App name from the injected Doc without requiring a dependency on the Revit dll - internal static string GetAppName() + else { - if (Globals.RevitDocument == null) - return HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox); - else + try { - try - { - System.Type type = Globals.RevitDocument.GetType(); - var app = (object)type.GetProperty("Application").GetValue(Globals.RevitDocument, null); - - System.Type type2 = app.GetType(); - var version = (string)type2.GetProperty("VersionNumber").GetValue(app, null); - - if (version.Contains("2024")) - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2024); - if (version.Contains("2023")) - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2023); - if (version.Contains("2022")) - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2022); - if (version.Contains("2021")) - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2021); - else - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); + System.Type type = Globals.RevitDocument.GetType(); + var app = (object)type.GetProperty("Application").GetValue(Globals.RevitDocument, null); - } - catch (Exception e) + System.Type type2 = app.GetType(); + var version = (string)type2.GetProperty("VersionNumber").GetValue(app, null); + + if (version.Contains("2024")) { - return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2024); } - } - } - //My god this function sucks. It took me 20 mins to understand. Why not one that simply deals with one stream wrapper, and then use linq to cast things around? - internal static List InputToStream(object input) - { - try - { - //it's a list - var array = (input as ArrayList)?.ToArray(); - - try + if (version.Contains("2023")) { - //list of stream wrappers - return array.Cast().ToList(); + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2023); } - catch + + if (version.Contains("2022")) { - //ignored + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2022); } - try + if (version.Contains("2021")) { - //list of urls - return array.Cast().Select(x => new StreamWrapper(x)).ToList(); + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2021); } - catch + else { - //ignored + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); } } - catch + catch (Exception e) { - // ignored + return HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); } + } + } + + //My god this function sucks. It took me 20 mins to understand. Why not one that simply deals with one stream wrapper, and then use linq to cast things around? + internal static List InputToStream(object input) + { + try + { + //it's a list + var array = (input as ArrayList)?.ToArray(); try { - //single stream wrapper - var sw = input as StreamWrapper; - if (sw != null) - { - return new List { sw }; - } + //list of stream wrappers + return array.Cast().ToList(); } catch { @@ -131,51 +118,79 @@ internal static List InputToStream(object input) try { - //single url - var s = input as string; - if (!string.IsNullOrEmpty(s)) - { - return new List { new StreamWrapper(s) }; - } + //list of urls + return array.Cast().Select(x => new StreamWrapper(x)).ToList(); } catch { //ignored } - - return null; + } + catch + { + // ignored } - internal static StreamWrapper ParseWrapper(object input) + try { - if (input is StreamWrapper w) + //single stream wrapper + var sw = input as StreamWrapper; + if (sw != null) { - return w; + return new List { sw }; } + } + catch + { + //ignored + } - if (input is string s) + try + { + //single url + var s = input as string; + if (!string.IsNullOrEmpty(s)) { - return new StreamWrapper(s); + return new List { new(s) }; } + } + catch + { + //ignored + } + + return null; + } - return null; + internal static StreamWrapper ParseWrapper(object input) + { + if (input is StreamWrapper w) + { + return w; } - internal static void HandleApiExeption(Exception ex) + if (input is string s) { - if (ex.InnerException != null && ex.InnerException.InnerException != null) - { - throw (ex.InnerException.InnerException); - } + return new StreamWrapper(s); + } - if (ex.InnerException != null) - { - throw (ex.InnerException); - } - else - { - throw (ex); - } + return null; + } + + internal static void HandleApiExeption(Exception ex) + { + if (ex.InnerException != null && ex.InnerException.InnerException != null) + { + throw (ex.InnerException.InnerException); + } + + if (ex.InnerException != null) + { + throw (ex.InnerException); + } + else + { + throw (ex); } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.AccountDetailsV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.AccountDetailsV2.cs index 1ca7c44c4f..e81a4481b2 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.AccountDetailsV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.AccountDetailsV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using ConnectorGrasshopper.Extras; using ConnectorGrasshopper.Properties; @@ -67,7 +67,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) // Only report on first iteration of the component. + { Tracker.TrackNodeRun(); + } //Params.Input[0].AddVolatileData(new GH_Path(0), 0, account); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.GetAccountToken.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.GetAccountToken.cs index 83826bd85a..d96689cd89 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.GetAccountToken.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.GetAccountToken.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using ConnectorGrasshopper.Properties; @@ -22,11 +22,16 @@ public Accounts_GetAccountToken() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -63,7 +68,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { var userId = ""; if (!DA.GetData(0, ref userId)) + { return; + } var acc = AccountManager.GetAccounts().FirstOrDefault(acc => acc.userInfo.id == userId); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ListAccounts.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ListAccounts.cs index a3894c8f86..815860b316 100755 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ListAccounts.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ListAccounts.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; @@ -73,7 +73,9 @@ private void SetAccountList() foreach (var account in accounts) { if (defaultAccount != null && account.userInfo.id == defaultAccount.userInfo.id) + { defaultAccountIndex = index + 1; + } ListItems.Add(new GH_ValueListItem(account.ToString(), $"\"{account.userInfo.id}\"")); index++; @@ -166,7 +168,9 @@ protected override void CollectVolatileData_Custom() m_data.ClearData(); if (FirstSelectedItem.Value != null) + { m_data.Append(FirstSelectedItem.Value, new GH_Path(0)); + } } public override void AddedToDocument(GH_Document document) @@ -175,6 +179,8 @@ public override void AddedToDocument(GH_Document document) SetAccountList(); // If the node is new (i.e. GH has not called Read(...) ) we log the node creation event. if (IsNew) + { Tracker.TrackNodeCreation("Accounts list"); + } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ServerAccount.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ServerAccount.cs index 4eec3d6ccf..bfb15bba1b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ServerAccount.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Accounts.ServerAccount.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; @@ -24,11 +24,16 @@ public ServerAccountComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -74,9 +79,15 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) string sw = null; string token = null; if (!DA.GetData(0, ref sw)) + { return; + } + if (!DA.GetData(1, ref token)) + { return; + } + Uri url = null; try { @@ -104,9 +115,13 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (!GetSolveResults(DA, out var account)) + { return; + } if (account != null) + { DA.SetData(0, account); + } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/Accounts.AccountDetails.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/Accounts.AccountDetails.cs index d51d60414f..bb77d94267 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/Accounts.AccountDetails.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/Accounts.AccountDetails.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using ConnectorGrasshopper.Properties; @@ -52,10 +52,14 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { string userId = null; if (!DA.GetData(0, ref userId)) + { return; + } if (string.IsNullOrEmpty(userId)) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No account provided. Trying with default account."); + } var account = string.IsNullOrEmpty(userId) ? AccountManager.GetDefaultAccount() @@ -71,7 +75,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) // Only report on first iteration of the component. + { Tracker.TrackNodeRun(); + } Params.Input[0].AddVolatileData(new GH_Path(0), 0, account.userInfo.id); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/AccountsV2Upgrader.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/AccountsV2Upgrader.cs index 10ec0770e4..76c0271ef3 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/AccountsV2Upgrader.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Accounts/Obsolete/AccountsV2Upgrader.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Extras; using ConnectorGrasshopper.UpgradeUtilities; using Grasshopper.Kernel; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ComponentTracker.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ComponentTracker.cs index ebe1fa2b91..323f6da3a5 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ComponentTracker.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ComponentTracker.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Grasshopper.Kernel; using Speckle.Core.Credentials; @@ -30,7 +30,10 @@ public void TrackNodeRun(string? name = null, string? node = null) { var customProperties = new Dictionary { { "name", name ?? Parent?.Name ?? "unset" } }; if (node != null) + { customProperties.Add("node", node); + } + Speckle.Core.Logging.Analytics.TrackEvent(Speckle.Core.Logging.Analytics.Events.NodeRun, customProperties); } @@ -38,9 +41,15 @@ public void TrackNodeSend(Account acc, bool auto, bool sync = false) { var customProperties = new Dictionary(); if (auto) + { customProperties.Add("auto", auto); + } + if (sync) + { customProperties.Add("sync", sync); + } + Speckle.Core.Logging.Analytics.TrackEvent(acc, Speckle.Core.Logging.Analytics.Events.Send, customProperties); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleAsyncComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleAsyncComponent.cs index d70732ed4b..a5488e79d0 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleAsyncComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleAsyncComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Extras; using GH_IO.Serialization; using Grasshopper.Kernel; @@ -57,6 +57,8 @@ protected override void SolveInstance(IGH_DataAccess DA) using (LogContext.PushProperty("hostApplication", Utilities.GetVersionedAppName())) using (LogContext.PushProperty("grasshopperComponent", GetType().Name)) using (LogContext.PushProperty("traceId", guid)) + { base.SolveInstance(DA); + } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleComponent.cs index 1f212474ba..0d9296518d 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Extras; using GH_IO.Serialization; using Grasshopper.Kernel; @@ -56,6 +56,8 @@ protected sealed override void SolveInstance(IGH_DataAccess DA) using (LogContext.PushProperty("hostApplication", Utilities.GetVersionedAppName())) using (LogContext.PushProperty("grasshopperComponent", GetType().Name)) using (LogContext.PushProperty("traceId", guid)) + { SolveInstanceWithLogContext(DA); + } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleTaskCapableComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleTaskCapableComponent.cs index 153278a98b..456ebe2ee4 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleTaskCapableComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/GH_SpeckleTaskCapableComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Extras; using GH_IO.Serialization; using Grasshopper.Kernel; @@ -58,6 +58,8 @@ protected sealed override void SolveInstance(IGH_DataAccess DA) using (LogContext.PushProperty("hostApplication", Utilities.GetVersionedAppName())) using (LogContext.PushProperty("grasshopperComponent", GetType().Name)) using (LogContext.PushProperty("traceId", guid)) + { SolveInstanceWithLogContext(DA); + } } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ISpeckleTrackingComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ISpeckleTrackingComponent.cs index 2fbee9d026..831065c269 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ISpeckleTrackingComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/ISpeckleTrackingComponent.cs @@ -1,4 +1,4 @@ -using Grasshopper.Kernel; +using Grasshopper.Kernel; namespace ConnectorGrasshopper; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitAsyncComponentBase.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitAsyncComponentBase.cs index fd5f78fa27..6b5a81cc0e 100755 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitAsyncComponentBase.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitAsyncComponentBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Windows.Forms; using ConnectorGrasshopper.Extras; @@ -34,7 +34,9 @@ public override void AddedToDocument(GH_Document document) { base.AddedToDocument(document); if (SelectedKitName == null) + { SelectedKitName = SpeckleGHSettings.SelectedKitName; + } SetConverter(); } @@ -88,6 +90,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) Menu_AppendSeparator(menu); Menu_AppendItem(menu, "Select the converter you want to use:", null, false); if (CanDisableConversion) + { Menu_AppendItem( menu, "Do Not Convert", @@ -100,8 +103,10 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, Kit == null ); + } foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -114,6 +119,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, kit.Name == Kit?.Name ); + } Menu_AppendSeparator(menu); } @@ -126,7 +132,10 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) public virtual void SetConverterFromKit(string kitName) { if (kitName == Kit?.Name) + { return; + } + Kit = KitManager.Kits.FirstOrDefault(k => k.Name == kitName); SelectedKitName = Kit.Name; Converter = Kit.LoadConverter(Utilities.GetVersionedAppName()); @@ -157,7 +166,10 @@ protected override void SolveInstance(IGH_DataAccess DA) { //Ensure converter document is up to date if (Converter == null) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No converter was provided. Conversions are disabled."); + } + base.SolveInstance(DA); } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitComponentBase.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitComponentBase.cs index 0a8522599c..e3a1a7f8cf 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitComponentBase.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitComponentBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Windows.Forms; using ConnectorGrasshopper.Extras; @@ -31,6 +31,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) Menu_AppendSeparator(menu); Menu_AppendItem(menu, "Select the converter you want to use:", null, false); foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -41,6 +42,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, kit.Name == Kit.Name ); + } Menu_AppendSeparator(menu); } @@ -54,7 +56,9 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) public void SetConverterFromKit(string kitName) { if (kitName == Kit.Name) + { return; + } try { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitTaskCapableComponentBase.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitTaskCapableComponentBase.cs index cd2f6a52e3..2373cc2f2c 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitTaskCapableComponentBase.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/BaseComponents/SelectKitTaskCapableComponentBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Windows.Forms; using ConnectorGrasshopper.Extras; @@ -39,7 +39,10 @@ public override void AddedToDocument(GH_Document document) { base.AddedToDocument(document); if (SelectedKitName == null) + { SelectedKitName = SpeckleGHSettings.SelectedKitName; + } + SetConverter(); } @@ -86,6 +89,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) Menu_AppendSeparator(menu); Menu_AppendItem(menu, "Select the converter you want to use:", null, false); if (CanDisableConversion) + { Menu_AppendItem( menu, "Do Not Convert", @@ -98,8 +102,10 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, Kit == null ); + } foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -112,6 +118,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, kit.Name == Kit?.Name ); + } Menu_AppendSeparator(menu); } @@ -124,7 +131,10 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) public virtual void SetConverterFromKit(string kitName) { if (kitName == Kit?.Name) + { return; + } + Kit = KitManager.Kits.FirstOrDefault(k => k.Name == kitName); SelectedKitName = Kit.Name; Converter = Kit.LoadConverter(Utilities.GetVersionedAppName()); @@ -162,7 +172,10 @@ public override void ComputeData() { //Ensure converter document is up to date if (Converter == null) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No converter was provided. Conversions are disabled."); + } + base.ComputeData(); } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/FlattenCollectionComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/FlattenCollectionComponent.cs index 3cddb24847..3ecafa5250 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/FlattenCollectionComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/FlattenCollectionComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -20,7 +20,7 @@ public FlattenCollectionComponent() "Collections" ) { } - public override Guid ComponentGuid => new Guid("9E1F4A6B-201C-4E91-AFC2-5F28031E97C1"); + public override Guid ComponentGuid => new("9E1F4A6B-201C-4E91-AFC2-5F28031E97C1"); protected override Bitmap Icon => Properties.Resources.FlattenSpeckleCollection; protected override void RegisterInputParams(GH_InputParamManager pManager) @@ -37,7 +37,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { Collection collection = null; if (!DA.GetData(0, ref collection)) + { return; + } var excludeTypeFromFullName = new List { "rhino model" }; var flattened = FlattenCollection(collection, null, excludeTypeFromFullName); @@ -58,9 +60,13 @@ private static IEnumerable FlattenCollection( foreach (Base e in collection.elements) { if (e is Collection c) + { innerCollections.AddRange(FlattenCollection(c, nextPrefix, excludeTypeFromFullName)); + } else + { elements.Add(e); + } } var newCollection = new Collection(collection.name, collection.collectionType) @@ -80,9 +86,14 @@ IReadOnlyCollection excludeTypeFromFullName { var nameParts = new List(); if (!string.IsNullOrEmpty(fullNamePrefix)) + { nameParts.Add(fullNamePrefix); + } + if (excludeTypeFromFullName == null || !excludeTypeFromFullName.Contains(collection.collectionType)) + { nameParts.Add(collection.name); + } var nextPrefix = string.Join("::", nameParts); return nextPrefix; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/GH_SpeckleCollection.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/GH_SpeckleCollection.cs index 915585745f..07001c49e5 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/GH_SpeckleCollection.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/GH_SpeckleCollection.cs @@ -1,4 +1,4 @@ -using ConnectorGrasshopper.Extras; +using ConnectorGrasshopper.Extras; using Grasshopper.Kernel.Types; using Speckle.Core.Models; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/SpeckleCollectionParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/SpeckleCollectionParam.cs index 2c8bfa33a2..77873466f9 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/SpeckleCollectionParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Collections/SpeckleCollectionParam.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using Grasshopper.Kernel; @@ -9,7 +9,7 @@ public class SpeckleCollectionParam : GH_Param public SpeckleCollectionParam() : base("Speckle Collection", "SC", "A Speckle collection object", "Params", "Primitive", GH_ParamAccess.item) { } - public override Guid ComponentGuid => new Guid("96F52497-6E5B-4941-9350-D6C87F0EA1E3"); + public override Guid ComponentGuid => new("96F52497-6E5B-4941-9350-D6C87F0EA1E3"); protected override Bitmap Icon => Properties.Resources.SpeckleCollection; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/ComponentCategories.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/ComponentCategories.cs index 06524a5c1d..216bd4535f 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/ComponentCategories.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/ComponentCategories.cs @@ -1,4 +1,4 @@ -namespace ConnectorGrasshopper; +namespace ConnectorGrasshopper; // NOTE: // The number of spaces determines the order in which they display in the ribbon (nice hack) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/ConnectorGrasshopperInfo.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/ConnectorGrasshopperInfo.cs index a5b05035b7..2a5520c410 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/ConnectorGrasshopperInfo.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/ConnectorGrasshopperInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using ConnectorGrasshopper.Properties; using Grasshopper.Kernel; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/DeserialiseTaskCapableComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/DeserialiseTaskCapableComponent.cs index bcd6eeaf2a..e75450e148 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/DeserialiseTaskCapableComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/DeserialiseTaskCapableComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading; @@ -22,11 +22,16 @@ static DeserializeTaskCapableComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -63,7 +68,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (InPreSolve) { if (RunCount == 1) + { source = new CancellationTokenSource(); + } string item = null; DA.GetData(0, ref item); @@ -84,7 +91,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) private Base DoWork(string item, IGH_DataAccess DA) { if (string.IsNullOrEmpty(item)) + { return null; + } try { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/SerialiseTaskCapableComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/SerialiseTaskCapableComponent.cs index 6d5a0931b5..4dfbe90d71 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/SerialiseTaskCapableComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/SerialiseTaskCapableComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading; @@ -21,11 +21,16 @@ static SerializeTaskCapableComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -64,12 +69,17 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) // You must place "RunCount == 1" here, // because RunCount is reset when "InPreSolve" becomes "false" if (RunCount == 1) + { source = new CancellationTokenSource(); + } GH_SpeckleBase item = null; DA.GetData(0, ref item); if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } + var task = Task.Run(() => DoWork(item, DA), source.Token); TaskList.Add(task); return; @@ -87,6 +97,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) private string DoWork(GH_SpeckleBase item, IGH_DataAccess DA) { if (item?.Value != null) + { try { return Operations.Serialize(item.Value); @@ -96,6 +107,7 @@ private string DoWork(GH_SpeckleBase item, IGH_DataAccess DA) AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, e.ToFormattedString()); return null; } + } AddRuntimeMessage( GH_RuntimeMessageLevel.Warning, diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToNativeTaskCapableComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToNativeTaskCapableComponent.cs index b2542779fb..ded9182274 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToNativeTaskCapableComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToNativeTaskCapableComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; @@ -20,11 +20,16 @@ static ToNativeTaskCapableComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = SpeckleGHSettings.ShowDevComponents ? GH_Exposure.primary : GH_Exposure.hidden; }; } @@ -66,7 +71,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) object item = null; DA.GetData(0, ref item); if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } + var task = Task.Run(() => DoWork(item, DA), CancelToken); TaskList.Add(task); return; @@ -96,7 +104,9 @@ private IGH_Goo DoWork(object item, IGH_DataAccess DA) { // If we reach this, something happened that we weren't expecting... if (ex is AggregateException aggregateException) + { ex = aggregateException.Flatten(); + } SpeckleLog.Logger.Error(ex, "Failed during execution of {componentName}", this.GetType()); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, ex.ToFormattedString()); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToSpeckleTaskCapableComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToSpeckleTaskCapableComponent.cs index 57e63b4813..63175e58bb 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToSpeckleTaskCapableComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Conversion/ToSpeckleTaskCapableComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -30,11 +30,16 @@ static ToSpeckleTaskCapableComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -76,12 +81,17 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) // You must place "RunCount == 1" here, // because RunCount is reset when "InPreSolve" becomes "false" if (RunCount == 1) + { source = new CancellationTokenSource(); + } object item = null; DA.GetData(0, ref item); if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } + var task = Task.Run(() => DoWork(item, DA), source.Token); TaskList.Add(task); return; @@ -125,7 +135,9 @@ private IGH_Goo DoWork(object item, IGH_DataAccess DA) } if (converted.GetType().IsSimpleType()) + { return Utilities.WrapInGhType(converted); + } return new GH_SpeckleBase { Value = converted as Base }; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/DebounceDispatcher.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/DebounceDispatcher.cs index 70bc739d09..e16d940395 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/DebounceDispatcher.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/DebounceDispatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows.Threading; namespace ConnectorGrasshopper.Extras; @@ -49,7 +49,9 @@ public void Debounce( timer = null; if (disp == null) + { disp = Dispatcher.CurrentDispatcher; + } // timer is recreated for each event and effectively // resets the timeout. Action only fires after timeout has fully @@ -60,7 +62,9 @@ public void Debounce( (s, e) => { if (timer == null) + { return; + } timer?.Stop(); timer = null; @@ -97,14 +101,18 @@ public void Throttle( timer = null; if (disp == null) + { disp = Dispatcher.CurrentDispatcher; + } var curTime = DateTime.UtcNow; // if timeout is not up yet - adjust timeout to fire // with potentially new Action parameters if (curTime.Subtract(timerStarted).TotalMilliseconds < interval) + { interval -= (int)curTime.Subtract(timerStarted).TotalMilliseconds; + } timer = new DispatcherTimer( TimeSpan.FromMilliseconds(interval), @@ -112,7 +120,9 @@ public void Throttle( (s, e) => { if (timer == null) + { return; + } timer?.Stop(); timer = null; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleAccount.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleAccount.cs index f5768b0d79..2ec9969f6d 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleAccount.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleAccount.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using ConnectorGrasshopper.Properties; @@ -39,6 +39,7 @@ public override string ToString() public override bool CastFrom(object source) { if (source is GH_String ghString) + { try { Value = AccountManager.GetAccounts().First(acc => acc.userInfo.id == ghString.Value); @@ -46,8 +47,10 @@ public override bool CastFrom(object source) } catch (Exception e) // TODO: Handle this exception instead of ignoring it { } + } if (source is string userId) + { try { Value = AccountManager.GetAccounts().First(acc => acc.id == userId); @@ -55,6 +58,7 @@ public override bool CastFrom(object source) } catch (Exception e) // TODO: Handle this exception instead of ignoring it { } + } if (source is Account account) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleBase.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleBase.cs index 97c5a83abf..b743650c8c 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleBase.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleBase.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using ConnectorGrasshopper.Collections; using Grasshopper.Kernel.Types; using Speckle.Core.Models; @@ -57,7 +57,10 @@ public override bool CastFrom(object source) foreach (DictionaryEntry kvp in dict) { if (kvp.Key is not string s) + { return false; + } + @base[s] = kvp.Value; } break; @@ -94,14 +97,20 @@ public override IGH_Goo Duplicate() public override string ToString() { if (Value == null) + { return ""; + } + var name = Value["Name"] ?? Value["name"]; if (Value.GetType().IsSubclassOf(typeof(Base))) { var baseString = $"Speckle {Value.GetType().Name}"; if (name != null) + { baseString += $" [{name}]"; + } + return baseString; } return "Speckle Object"; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleGoo.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleGoo.cs index a3c9d4452c..5b0338fa10 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleGoo.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GH_SpeckleGoo.cs @@ -1,4 +1,4 @@ -using System; +using System; using Grasshopper.Kernel.Types; namespace ConnectorGrashopper.Extras; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GenericAccessParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GenericAccessParam.cs index e3d4ec4a55..e1307b2bd0 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GenericAccessParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/GenericAccessParam.cs @@ -29,11 +29,15 @@ public GenericAccessParamAttributes(IGH_Param param, IGH_Attributes parent) public override GH_ObjectResponse RespondToMouseDoubleClick(GH_Canvas sender, GH_CanvasMouseEvent e) { if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) + { switch (Owner.Kind) { case GH_ParamKind.input: if (Owner.MutableNickName) + { (Owner as SpeckleStatefulParam)?.InheritNickname(); + } + return GH_ObjectResponse.Handled; case GH_ParamKind.output: Clipboard.SetText(DocObject.NickName); @@ -43,6 +47,7 @@ public override GH_ObjectResponse RespondToMouseDoubleClick(GH_Canvas sender, GH default: return base.RespondToMouseDoubleClick(sender, e); } + } return base.RespondToMouseDoubleClick(sender, e); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SendReceiveDataParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SendReceiveDataParam.cs index f721d7cb89..94a6704b5d 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SendReceiveDataParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SendReceiveDataParam.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows.Forms; using Grasshopper.Kernel; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleBaseParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleBaseParam.cs index 01d112121f..038d206715 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleBaseParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleBaseParam.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using ConnectorGrasshopper.Properties; using Grasshopper.Kernel; @@ -46,11 +46,19 @@ public override GH_StateTagList StateTags { var tags = base.StateTags; if (Kind != GH_ParamKind.output) + { return tags; + } + if (!IsSchemaBuilderOutput) + { return tags; + } + if (UseSchemaTag) + { tags.Add(new SchemaTagStateTag()); + } return tags; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStateTag.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStateTag.cs index 03b76eb5b2..8abd3bf792 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStateTag.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStateTag.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Drawing.Drawing2D; using ConnectorGrasshopper.Properties; @@ -57,12 +57,16 @@ public abstract class SpeckleStateTag : GH_StateTag public override void Render(Graphics graphics) { if (GH_Canvas.ZoomFadeLow < 5) + { return; + } RenderSpeckleTagBlankIcon(graphics); RenderSpeckleTagContents(graphics); if (Crossed) + { RenderRedDiagonalLine(graphics); + } } public void RenderSpeckleTagBlankIcon(Graphics graphics) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStatefulParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStatefulParam.cs index 2acde1a8bd..9be8c59c52 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStatefulParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStatefulParam.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -28,16 +28,26 @@ public override GH_StateTagList StateTags if (Kind == GH_ParamKind.input) { if (Optional) + { tags.Add(new OptionalStateTag()); + } + if (Detachable) + { tags.Add(new DetachedStateTag()); + } + if (Access == GH_ParamAccess.list) + { tags.Add(new ListAccesStateTag()); + } } else if (Kind == GH_ParamKind.output) { if (Detachable) + { tags.Add(new DetachedStateTag()); + } } return tags; } @@ -86,7 +96,9 @@ public override void AddSource(IGH_Param source, int index) { base.AddSource(source, index); if (MutableNickName && KeyWatcher.TabPressed) + { InheritNickname(); + } } public override void AppendAdditionalMenuItems(ToolStripDropDown menu) @@ -96,7 +108,10 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) // Append graft,flatten,etc... options to outputs. base.AppendAdditionalMenuItems(menu); if (Kind == GH_ParamKind.output) + { Menu_AppendExtractParameter(menu); + } + return; } @@ -134,12 +149,16 @@ public void InheritNickname() Name = fullname; NickName = fullname; if (Kind == GH_ParamKind.input || Kind == GH_ParamKind.output) + { // If it belongs to a component, expire the component solution // This will force a CSO component to update the object with it's new prop name. Attributes.Parent.DocObject.ExpireSolution(true); + } else + { // It could also be a standalone component, in which case just expire the preview. ExpirePreview(true); + } } protected new void Menu_AppendExtractParameter(ToolStripDropDown menu) @@ -207,7 +226,10 @@ protected void Menu_ExtractOutputParameterClicked(object sender, EventArgs e) { var ghDocumentObject = Instances.ComponentServer.EmitObject(ComponentGuid); if (ghDocumentObject == null) + { return; + } + var ghParam = (IGH_Param)ghDocumentObject; ghParam.CreateAttributes(); if (!ghArchive.ExtractObject(ghParam, "Parameter")) @@ -225,7 +247,10 @@ protected void Menu_ExtractOutputParameterClicked(object sender, EventArgs e) ); ghParam.MutableNickName = true; if (ghParam.Attributes is GH_FloatingParamAttributes floating) + { floating.PerformLayout(); + } + var ghDocument = OnPingDocument(); if (ghDocument == null) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStreamParam.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStreamParam.cs index b684aeb54d..a32a21e9b4 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStreamParam.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleStreamParam.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using ConnectorGrasshopper.Properties; using Grasshopper.Kernel; @@ -86,6 +86,7 @@ public override string ToString() public override bool CastFrom(object source) { if (source is GH_String ghStr) + { try { Value = new StreamWrapper(ghStr.Value); @@ -95,8 +96,10 @@ public override bool CastFrom(object source) { return false; } + } if (source is string str) // Not sure this is needed? + { try { Value = new StreamWrapper(str); @@ -106,6 +109,7 @@ public override bool CastFrom(object source) { return false; } + } if (source is StreamWrapper strWrapper) { @@ -115,7 +119,10 @@ public override bool CastFrom(object source) var stream = (source as GH_SpeckleStream)?.Value; if (stream == null) + { return false; + } + Value = stream; return true; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleUpgradeObject.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleUpgradeObject.cs index f502c31662..336bcd32de 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleUpgradeObject.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/SpeckleUpgradeObject.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.UpgradeUtilities; using Grasshopper.Kernel; @@ -11,13 +11,17 @@ public abstract class SpeckleUpgradeObject : IGH_UpgradeObject public virtual IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document document) { if (!(target is T1 component)) + { return null; // Ensure the type of the target is correct + } // Upgrade the component var upgraded = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); if (!(upgraded is T2 upgradedComponent)) + { return null; // Ensure the type of the upgraded component is correct + } // Run any custom upgrade steps here, such as swapping access type, updating nicknames... etc. CustomUpgrade(component, upgradedComponent, document); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/TreeBuilder.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/TreeBuilder.cs index ea8918a389..1ef42db8df 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/TreeBuilder.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/TreeBuilder.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Linq; using Grasshopper.Kernel.Data; @@ -24,7 +24,9 @@ public GH_Structure Build(object data) _path = new List(); var tree = new GH_Structure(); if (data == null) + { return tree; + } RecurseNestedLists(data, tree); return tree; @@ -33,6 +35,7 @@ public GH_Structure Build(object data) private void RecurseNestedLists(object data, GH_Structure tree) { if (data is IList list) + { for (var i = 0; i < list.Count; i++) { var item = list[i]; @@ -41,27 +44,38 @@ private void RecurseNestedLists(object data, GH_Structure tree) //add list index to path _path.Add(i); if (subList.Any()) + { RecurseNestedLists(item, tree); + } else + { tree.EnsurePath(_path.ToArray()); + } //reached the bottom of a sublist, step back one level if (_path.Any()) + { _path.RemoveAt(_path.Count - 1); + } } else { AddLeaf(item, tree); } } + } else + { AddLeaf(data, tree); + } } private void AddLeaf(object data, GH_Structure tree) { //paths must have at least one element if (!_path.Any()) + { _path.Add(0); + } var path = new GH_Path(_path.ToArray()); tree.Append( diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/Utilities.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/Utilities.cs index 965152c338..3e45cf2cbb 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/Utilities.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Extras/Utilities.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; @@ -31,7 +31,10 @@ public static string GetVersionedAppName() { var version = HostApplications.Grasshopper.GetVersion(HostAppVersion.v6); if (RhinoApp.Version.Major >= 7) + { version = HostApplications.Grasshopper.GetVersion(HostAppVersion.v7); + } + return version; } @@ -89,7 +92,10 @@ public static Base DataTreeToSpeckle( foreach (var path in dataInput.Paths.ToList()) { if (cancellationToken.IsCancellationRequested) + { break; + } + var key = path.ToString(); //TODO: Rolled back chunking due to issue with detaching children. Revisit this once done. var chunkingPrefix = "@"; @@ -98,11 +104,17 @@ public static Base DataTreeToSpeckle( foreach (var item in value) { if (cancellationToken.IsCancellationRequested) + { break; + } + converted.Add(TryConvertItemToSpeckle(item, converter, true, onConversionProgress)); } if (cancellationToken.IsCancellationRequested) + { break; + } + @base[chunkingPrefix + key] = converted; } return @base; @@ -132,11 +144,17 @@ public static GH_Structure DataTreeToNative( var pattern = new Regex(dataTreePathPattern); // Match for the dynamic detach magic "@(DETACH_INT)PATH" var matchRes = pattern.Match(key); if (matchRes.Length == 0) + { return; + } + var pathKey = matchRes.Groups["path"].Value; var res = path.FromString(pathKey); if (!res) + { return; + } + var converted = value.Select(item => TryConvertItemToNative(item, converter)); dataTree.AppendRange(converted, path); }); @@ -157,7 +175,10 @@ public static bool CanConvertToDataTree(Base @base) var regex = new Regex(dataTreePathPattern); var dynamicMembers = @base.GetDynamicMembers().ToList(); if (dynamicMembers.Count == 0) + { return false; + } + var isDataTree = dynamicMembers.All(el => regex.Match(el).Success); return isDataTree; } @@ -182,7 +203,9 @@ public static List DataTreeToNestedLists( for (var i = 0; i < dataInput.Branches.Count; i++) { if (cancellationToken.IsCancellationRequested) + { return output; + } var path = dataInput.Paths[i].Indices.ToList(); var leaves = new List(); @@ -190,7 +213,10 @@ public static List DataTreeToNestedLists( foreach (var goo in dataInput.Branches[i]) { if (cancellationToken.IsCancellationRequested) + { return output; + } + OnConversionProgress?.Invoke(); leaves.Add(TryConvertItemToSpeckle(goo, converter, true)); } @@ -255,10 +281,16 @@ public static IGH_Goo WrapInGhType(object obj) private static List EnsureHasSublistAtIndex(List parent, int index) { while (parent.Count <= index || !(parent[index] is List)) + { if (parent.Count > index) + { parent.Insert(index, new List()); + } else + { parent.Add(new List()); + } + } return parent; } @@ -294,7 +326,10 @@ public static Base TraverseAndConvertToNative(Base @base, ISpeckleConverter conv { var converted = new Dictionary(); foreach (DictionaryEntry kvp in keyval.Value as IDictionary) + { converted[kvp.Key.ToString()] = TryConvertItemToNative(kvp.Value, converter, true); + } + copy[keyval.Key] = converted; } else @@ -322,7 +357,10 @@ public static Base TraverseAndConvertToSpeckle( { var subclass = @base.GetType().IsSubclassOf(typeof(Base)); if (subclass) + { return @base; + } + var copy = @base.ShallowCopy(); var keyValuePairs = copy.GetMembers().ToList(); keyValuePairs.ForEach(keyval => @@ -350,7 +388,10 @@ public static Base TraverseAndConvertToSpeckle( { var converted = new Dictionary(); foreach (DictionaryEntry kvp in value as IDictionary) + { converted[kvp.Key.ToString()] = TryConvertItemToSpeckle(kvp.Value, converter, true); + } + copy[keyval.Key] = converted; } else @@ -371,16 +412,24 @@ public static Base TraverseAndConvertToSpeckle( public static IGH_Goo TryConvertItemToNative(object value, ISpeckleConverter converter, bool recursive = false) { if (converter == null) + { return WrapInGhType(value); + } + if (value == null) + { return null; + } if (value is IGH_Goo) + { value = value.GetType().GetProperty("Value")?.GetValue(value); + } if (value is Base @base) { if (converter.CanConvertToNative(@base)) + { try { var converted = converter.ConvertToNative(@base); @@ -391,6 +440,7 @@ public static IGH_Goo TryConvertItemToNative(object value, ISpeckleConverter con converter.Report.ConversionErrors.Add(new Exception($"Could not convert {@base}", e)); return null; } + } if (recursive) { @@ -401,10 +451,14 @@ public static IGH_Goo TryConvertItemToNative(object value, ISpeckleConverter con } if (value is Base base2) + { return new GH_SpeckleBase { Value = base2 }; + } if (value.GetType().IsSimpleType()) + { return GH_Convert.ToGoo(value); + } if (value is Enum) { @@ -429,34 +483,49 @@ public static object TryConvertItemToSpeckle( ) { if (value is null) + { return value; + } string refId = GetRefId(value); if (value is IGH_Goo) + { value = value.GetType().GetProperty("Value").GetValue(value); + } if (value.GetType().IsSimpleType()) + { return value; + } if (converter != null && converter.CanConvertToSpeckle(value)) { var result = converter.ConvertToSpeckle(value); if (result != null) + { result.applicationId = refId; + } + return result; } var subclass = value.GetType().IsSubclassOf(typeof(Base)); if (subclass) + { // TODO: Traverse through dynamic props only. return value; + } if (recursive && value is Base @base) + { return TraverseAndConvertToSpeckle(@base, converter); + } if (value is Base base2) + { return base2; + } return null; } @@ -469,7 +538,9 @@ public static string GetRefId(object value) try { if (r.IsReferencedGeometry) + { refId = r.ReferenceID.ToString(); + } } catch (RuntimeBinderException) { @@ -584,7 +655,10 @@ public static GH_Structure ConvertToTree( else { if (onError != null) + { onError(GH_RuntimeMessageLevel.Remark, "This object needs to be expanded."); + } + data.Append(new GH_SpeckleBase(@base)); } return data; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Loader.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Loader.cs index bd3341dce6..bfe8118a4b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Loader.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Loader.cs @@ -40,7 +40,9 @@ public override GH_LoadingInstruction PriorityLoad() { var version = HostApplications.Grasshopper.GetVersion(HostAppVersion.v6); if (RhinoApp.Version.Major == 7) + { version = HostApplications.Grasshopper.GetVersion(HostAppVersion.v7); + } var logConfig = new SpeckleLogConfiguration(logToSentry: false); #if MAC @@ -113,18 +115,24 @@ private void OnCanvasCreated(GH_Canvas canvas) Instances.DocumentEditor.Load += OnDocumentEditorLoad; if (canvas == null) + { return; + } canvas.KeyDown += (s, e) => { if (e.KeyCode == Keys.Tab && !KeyWatcher.TabPressed) + { KeyWatcher.TabPressed = true; + } }; canvas.KeyUp += (s, e) => { if (KeyWatcher.TabPressed && e.KeyCode == Keys.Tab) + { KeyWatcher.TabPressed = false; + } }; } @@ -166,19 +174,27 @@ private void HandleKitSelectedEvent(object sender, EventArgs args) // Update the check status of all foreach (var item in kitMenuItems) + { if (item is ToolStripMenuItem menuItem) + { menuItem.CheckState = clickedItem.Text.Trim() == selectedKit.Name ? CheckState.Checked : CheckState.Unchecked; + } + } } private void AddSpeckleMenu(MenuStrip mainMenu) { if (MenuHasBeenAdded) + { return; + } // Double check that the menu does not exist. var menuName = "Speckle 2"; if (mainMenu.Items.ContainsKey(menuName)) + { mainMenu.Items.RemoveByKey(menuName); + } speckleMenu = new ToolStripMenuItem(menuName); @@ -242,9 +258,13 @@ private void AddSpeckleMenu(MenuStrip mainMenu) #endif if (File.Exists(path) || Directory.Exists(path)) + { Process.Start(path); + } else + { Process.Start(new ProcessStartInfo("https://speckle.systems/download") { UseShellExecute = true }); + } } catch (Exception ex) { @@ -259,7 +279,9 @@ private void AddSpeckleMenu(MenuStrip mainMenu) ); if (!MenuHasBeenAdded) + { mainMenu.Items.Add(speckleMenu); + } MenuHasBeenAdded = true; } @@ -290,7 +312,9 @@ private void CreateHeadlessTemplateMenu() var path = Path.Combine(SpecklePathProvider.InstallSpeckleFolderPath, "Templates"); if (!Directory.Exists(path)) + { Directory.CreateDirectory(path); + } #if MAC Process.Start("file://" + path); #else @@ -351,7 +375,10 @@ private void CreateKitSelectionMenu(ToolStripMenuItem menu) var current = 1; menu.DropDown.Items.Remove(loading); foreach (var item in kitMenuItems) + { menu.DropDown.Items.Insert(current++, item); + } + HandleKitSelectedEvent(kitMenuItems.FirstOrDefault(k => k.Text.Trim() == "Objects"), null); Instances.DocumentEditor.Refresh(); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectByKeyValueV2TaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectByKeyValueV2TaskComponent.cs index 6a8e65e8cc..51ffd17198 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectByKeyValueV2TaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectByKeyValueV2TaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -48,7 +48,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var keys = new List(); var values = new List(); if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Create Object By Key Value"); + } DA.GetDataList(0, keys); DA.GetDataList(1, values); @@ -59,17 +61,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out var result)) + { // Normal mode not supported return; + } if (result != null) + { DA.SetData(0, result); + } } } @@ -79,10 +87,14 @@ public Base DoWork(List keys, List values) { // 👉 Checking for cancellation! if (CancelToken.IsCancellationRequested) + { return null; + } if (keys.Count != values.Count) + { throw new Exception("Keys and Values list do not have the same number of items"); + } var speckleObj = new Base(); for (var i = 0; i < keys.Count; i++) @@ -92,12 +104,16 @@ public Base DoWork(List keys, List values) try { if (value is SpeckleObjectGroup group) + { speckleObj[key] = Converter != null ? group.Value.Select(item => Utilities.TryConvertItemToSpeckle(item, Converter)).ToList() : group.Value; + } else + { speckleObj[key] = Converter != null ? Utilities.TryConvertItemToSpeckle(value, Converter) : value; + } } catch (Exception e) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectTaskComponent.cs index a8976d0774..66d853664f 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/CreateSpeckleObjectTaskComponent.cs @@ -89,7 +89,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) Dictionary inputData = new(); if (Params.Input.Count == 0) + { return; + } + var hasErrors = false; var duplicateKeys = Params.Input.Select(p => p.NickName).GroupBy(x => x).Count(group => group.Count() > 1); @@ -108,7 +111,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) //TODO: Original node if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Create Object"); + } Params.Input.ForEach(ighParam => { @@ -137,6 +142,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var values = new List(); DA.GetDataList(index, values); if (!param.Optional) + { if (values.Count == 0) { AddRuntimeMessage( @@ -145,6 +151,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) ); hasErrors = true; } + } inputData[key] = values; break; @@ -168,16 +175,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out Base result)) + { // Not running on multi threaded, handle this properly return; + } if (result != null) + { DA.SetData(0, result); + } } public async Task DoWork(Dictionary inputData) @@ -187,7 +201,9 @@ public async Task DoWork(Dictionary inputData) var @base = new Base(); var hasErrors = false; if (inputData == null) + { @base = null; + } inputData?.Keys .ToList() @@ -195,7 +211,10 @@ public async Task DoWork(Dictionary inputData) { var value = inputData[key]; if (value is SpeckleObjectGroup group) + { value = group.Value; + } + if (value is List list) { // Value is a list of items, iterate and convert. @@ -234,9 +253,13 @@ public async Task DoWork(Dictionary inputData) try { if (Converter != null) + { @base[key] = value == null ? null : Utilities.TryConvertItemToSpeckle(value, Converter); + } else + { @base[key] = value; + } } catch (Exception ex) { @@ -248,7 +271,9 @@ public async Task DoWork(Dictionary inputData) }); if (hasErrors) + { @base = null; + } return @base; } @@ -268,7 +293,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/DeconstructSpeckleObjectTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/DeconstructSpeckleObjectTaskComponent.cs index 372fabea3f..66c3991df8 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/DeconstructSpeckleObjectTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/DeconstructSpeckleObjectTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; @@ -138,7 +138,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Expand Object"); + } var task = Task.Run(() => DoWork(@base)); TaskList.Add(task); @@ -147,15 +149,21 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out Dictionary result)) + { // Normal mode not supported return; + } if (result != null) + { foreach (var key in result.Keys) { var isDetached = key.StartsWith("@"); @@ -188,6 +196,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } } } + } } private bool OutputMismatch() @@ -211,7 +220,9 @@ private bool HasSingleRename() { var equalLength = outputList.Count == Params.Output.Count; if (!equalLength) + { return false; + } var diffParams = Params.Output.Where( param => !outputList.Contains(param.NickName) && !outputList.Contains("@" + param.NickName) @@ -222,7 +233,9 @@ private bool HasSingleRename() private void AutoCreateOutputs() { if (!OutputMismatch()) + { return; + } RecordUndoEvent("Creating Outputs"); @@ -261,7 +274,9 @@ private void AutoCreateOutputs() remove.ForEach(b => { if (b != -1 && Params.Output[b].Recipients.Count == 0) + { Params.UnregisterOutputParameter(Params.Output[b]); + } }); outputList.Sort(); @@ -283,7 +298,9 @@ private void AutoCreateOutputs() Params.RegisterOutputParam(newParam); } if (param is GenericAccessParam srParam) + { srParam.Detachable = isDetached; + } }); } @@ -328,10 +345,16 @@ private List GetOutputList(GH_Structure speckleObjects) { object converted = null; if (ghGoo is GH_SpeckleBase ghBase) + { converted = ghBase.Value; + } else + { converted = Utilities.TryConvertItemToSpeckle(ghGoo, Converter); + } + if (converted is Base b) + { b.GetMembers( DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaComputed ) @@ -339,8 +362,11 @@ private List GetOutputList(GH_Structure speckleObjects) .ForEach(prop => { if (!fullProps.Contains(prop)) + { fullProps.Add(prop); + } }); + } } fullProps.Sort(); @@ -370,7 +396,10 @@ private Dictionary CreateOutputDictionary(Base @base) // Assign all values to it's corresponding dictionary entry and branch path. var obj = @base; if (obj == null) + { return new Dictionary(); + } + foreach ( var prop in obj.GetMembers( DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaComputed @@ -411,7 +440,9 @@ var prop in obj.GetMembers( { IGH_Goo wrapper = new GH_ObjectWrapper(); foreach (var b in kvp.Value) + { wrapper = Utilities.TryConvertItemToNative(b, Converter); + } outputDict[prop.Key] = wrapper; } @@ -419,9 +450,14 @@ var prop in obj.GetMembers( break; default: if (prop.Value is Base temp && Utilities.CanConvertToDataTree(temp)) + { outputDict[prop.Key] = Utilities.DataTreeToNative(temp, Converter); + } else + { outputDict[prop.Key] = Utilities.TryConvertItemToNative(prop.Value, Converter); + } + break; } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/CreateSpeckleObjectByKeyValueTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/CreateSpeckleObjectByKeyValueTaskComponent.cs index 00ff99ec42..b4e5bc4a3b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/CreateSpeckleObjectByKeyValueTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/CreateSpeckleObjectByKeyValueTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Threading.Tasks; @@ -48,7 +48,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var keys = new List(); var valueTree = new GH_Structure(); if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Create Object By Key Value"); + } DA.GetDataList(0, keys); DA.GetDataTree(1, out valueTree); @@ -59,16 +61,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out var result)) + { // Normal mode not supported return; + } if (result != null) + { DA.SetData(0, result); + } } public Base DoWork(List keys, GH_Structure valueTree) @@ -77,7 +86,9 @@ public Base DoWork(List keys, GH_Structure valueTree) { // 👉 Checking for cancellation! if (CancelToken.IsCancellationRequested) + { return null; + } // Create a path from the current iteration var searchPath = new GH_Path(RunCount - 1); @@ -95,23 +106,31 @@ public Base DoWork(List keys, GH_Structure valueTree) keys.ForEach(key => { if (ind < list.Count) + { try { if (Converter != null) + { speckleObj[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); + } else + { speckleObj[key] = list[ind]; + } } catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString()); hasErrors = true; } + } ind++; }); if (hasErrors) + { speckleObj = null; + } } else { @@ -129,12 +148,19 @@ public Base DoWork(List keys, GH_Structure valueTree) { var objs = new List(); foreach (var goo in branch) + { if (Converter != null) + { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); + } else + { objs.Add(goo); + } + } if (objs.Count > 0) + { try { speckleObj[key] = objs; @@ -144,13 +170,16 @@ public Base DoWork(List keys, GH_Structure valueTree) AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString()); hasErrors = true; } + } } index++; }); if (hasErrors) + { speckleObj = null; + } } return speckleObj; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExpandSpeckleObjectTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExpandSpeckleObjectTaskComponent.cs index 4b8d180b14..9ecaaa02c5 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExpandSpeckleObjectTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExpandSpeckleObjectTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Drawing; @@ -24,7 +24,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); var priorParam = upgradedComponent.Params.Input[0]; @@ -36,7 +38,10 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen Access = GH_ParamAccess.item }; foreach (var priorParamSource in priorParam.Sources) + { newParam.Sources.Add(priorParamSource); + } + newParam.DataMapping = priorParam.DataMapping; newParam.Simplify = priorParam.Simplify; newParam.Reverse = priorParam.Reverse; @@ -143,10 +148,12 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Speckle.Core.Logging.Analytics.TrackEvent( Speckle.Core.Logging.Analytics.Events.NodeRun, new Dictionary { { "name", "Expand Object" } } ); + } var task = Task.Run(() => DoWork(@base)); TaskList.Add(task); @@ -155,15 +162,21 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out Dictionary result)) + { // Normal mode not supported return; + } if (result != null) + { foreach (var key in result.Keys) { var isDetached = key.StartsWith("@"); @@ -197,6 +210,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } } } + } } private bool OutputMismatch() @@ -220,7 +234,9 @@ private bool HasSingleRename() { var equalLength = outputList.Count == Params.Output.Count; if (!equalLength) + { return false; + } var diffParams = Params.Output.Where( param => !outputList.Contains(param.NickName) && !outputList.Contains("@" + param.NickName) @@ -231,7 +247,9 @@ private bool HasSingleRename() private void AutoCreateOutputs() { if (!OutputMismatch()) + { return; + } RecordUndoEvent("Creating Outputs"); @@ -269,7 +287,9 @@ private void AutoCreateOutputs() remove.ForEach(b => { if (b != -1 && Params.Output[b].Recipients.Count == 0) + { Params.UnregisterOutputParameter(Params.Output[b]); + } }); outputList.Sort(); @@ -291,7 +311,9 @@ private void AutoCreateOutputs() Params.RegisterOutputParam(newParam); } if (param is GenericAccessParam srParam) + { srParam.Detachable = isDetached; + } }); var paramNames = Params.Output.Select(p => p.Name).ToList(); paramNames.Sort(); @@ -327,7 +349,9 @@ private List GetOutputList(GH_Structure speckleObjects) .ForEach(prop => { if (!fullProps.Contains(prop)) + { fullProps.Add(prop); + } }); } @@ -358,7 +382,10 @@ private Dictionary CreateOutputDictionary(Base @base) // Assign all values to it's corresponding dictionary entry and branch path. var obj = @base; if (obj == null) + { return new Dictionary(); + } + foreach (var prop in obj.GetMembers()) { // Convert and add to corresponding output structure @@ -395,7 +422,9 @@ private Dictionary CreateOutputDictionary(Base @base) { IGH_Goo wrapper = new GH_ObjectWrapper(); foreach (var b in kvp.Value) + { wrapper = Utilities.TryConvertItemToNative(b, Converter); + } outputDict[prop.Key] = wrapper; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExtendSpeckleObjectByKeyValueTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExtendSpeckleObjectByKeyValueTaskComponent.cs index b771197078..522964150c 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExtendSpeckleObjectByKeyValueTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ExtendSpeckleObjectByKeyValueTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Threading.Tasks; @@ -104,7 +104,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Extend Object By Key Value"); + } TaskList.Add(Task.Run(() => DoWork(@base.ShallowCopy(), keys, valueTree))); return; @@ -113,16 +115,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out var result)) + { // Normal mode not supported return; + } if (result != null) + { DA.SetData(0, result); + } } public Base DoWork(Base @base, List keys, GH_Structure valueTree) @@ -131,7 +140,9 @@ public Base DoWork(Base @base, List keys, GH_Structure valueTre { // 👉 Checking for cancellation! if (CancelToken.IsCancellationRequested) + { return null; + } // Create a path from the current iteration var searchPath = new GH_Path(RunCount - 1); @@ -148,23 +159,31 @@ public Base DoWork(Base @base, List keys, GH_Structure valueTre keys.ForEach(key => { if (ind < list.Count) + { try { if (Converter != null) + { @base[key] = Utilities.TryConvertItemToSpeckle(list[ind], Converter); + } else + { @base[key] = list[ind]; + } } catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString()); hasErrors = true; } + } ind++; }); if (hasErrors) + { @base = null; + } } else { @@ -182,12 +201,19 @@ public Base DoWork(Base @base, List keys, GH_Structure valueTre { var objs = new List(); foreach (var goo in branch) + { if (Converter != null) + { objs.Add(Utilities.TryConvertItemToSpeckle(goo, Converter)); + } else + { objs.Add(goo); + } + } if (objs.Count > 0) + { try { @base[key] = objs; @@ -197,13 +223,16 @@ public Base DoWork(Base @base, List keys, GH_Structure valueTre AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.ToFormattedString()); hasErrors = true; } + } } index++; }); if (hasErrors) + { @base = null; + } } return @base; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ObjectsV2Upgrader.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ObjectsV2Upgrader.cs index d5f1cffaa3..abdc64d1eb 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ObjectsV2Upgrader.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/Deprecated/ObjectsV2Upgrader.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.UpgradeUtilities; using Grasshopper.Kernel; @@ -11,13 +11,17 @@ public class CreateSpeckleObjectByKeyValueV2UpgradeObject : IGH_UpgradeObject public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document document) { if (!(target is CreateSpeckleObjectByKeyValueTaskComponent component)) + { return null; // Ensure the type of the target is correct + } // Upgrade the component var upgraded = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); if (!(upgraded is CreateSpeckleObjectByKeyValueV2TaskComponent upgradedComponent)) + { return null; // Ensure the type of the upgraded component is correct + } // Swap the groups this node belongs to. UpgradeUtils.SwapGroups(document, component, upgradedComponent); @@ -38,13 +42,17 @@ public class ExtendSpeckleObjectByKeyValueV2UpgradeObject : IGH_UpgradeObject public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document document) { if (!(target is ExtendSpeckleObjectByKeyValueTaskComponent component)) + { return null; // Ensure the type of the target is correct + } // Upgrade the component var upgraded = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); if (!(upgraded is ExtendSpeckleObjectByKeyValueV2TaskComponent upgradedComponent)) + { return null; // Ensure the type of the upgraded component is correct + } // Swap the groups this node belongs to. UpgradeUtils.SwapGroups(document, component, upgradedComponent); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectByKeyValueV2TaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectByKeyValueV2TaskComponent.cs index bbde30a419..e03b358f34 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectByKeyValueV2TaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectByKeyValueV2TaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -66,7 +66,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) DA.GetDataList(2, valueTree); if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Extend Object By Key Value"); + } TaskList.Add(Task.Run(() => DoWork(inputObj, keys, valueTree))); return; @@ -75,17 +77,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out var result)) + { // Normal mode not supported return; + } if (result != null) + { DA.SetData(0, result); + } } public Base DoWork(object inputObj, List keys, List values) @@ -135,10 +143,14 @@ public Base DoWork(object inputObj, List keys, List values) // 👉 Checking for cancellation! if (CancelToken.IsCancellationRequested) + { return null; + } if (keys.Count != values.Count) + { throw new Exception("Keys and Values list do not have the same number of items"); + } // We got a list of values @@ -150,12 +162,16 @@ public Base DoWork(object inputObj, List keys, List values) try { if (value is SpeckleObjectGroup group) + { @base[key] = Converter != null ? group.Value.Select(item => Utilities.TryConvertItemToSpeckle(item, Converter)).ToList() : group.Value; + } else + { @base[key] = Converter != null ? Utilities.TryConvertItemToSpeckle(value, Converter) : value; + } } catch (Exception e) { @@ -165,7 +181,9 @@ public Base DoWork(object inputObj, List keys, List values) } if (hasErrors) + { @base = null; + } return @base; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectTaskComponent.cs index 286deb7189..bed085ef7b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/ExtendSpeckleObjectTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -148,7 +148,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Extend Object"); + } var inputData = new Dictionary(); for (int i = 1; i < Params.Input.Count; i++) @@ -164,28 +166,37 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) key = param.NickName; willOverwrite = true; if (detachable) + { willChangeDetach = true; + } } else if (@base.GetMembers().ContainsKey("@" + param.NickName)) { key = "@" + param.NickName; willOverwrite = true; if (!detachable) + { willChangeDetach = true; + } } var targetIndex = DA.ParameterTargetIndex(0); var path = DA.ParameterTargetPath(0); if (willChangeDetach) + { AddRuntimeMessage( GH_RuntimeMessageLevel.Remark, $"Key {key} already exists in object at {path}[{targetIndex}] with different detach flag. The detach flag of this input will be ignored" ); + } + if (willOverwrite) + { AddRuntimeMessage( GH_RuntimeMessageLevel.Remark, $"Key {key} already exists in object at {path}[{targetIndex}], its value will be overwritten" ); + } switch (param.Access) { @@ -202,7 +213,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (value is SpeckleObjectGroup group) + { value = group.Value; + } inputData[key] = value; break; @@ -210,6 +223,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var values = new List(); DA.GetDataList(i, values); if (!param.Optional) + { if (values.Count == 0) { AddRuntimeMessage( @@ -218,6 +232,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) ); hasErrors = true; } + } inputData[key] = values; break; @@ -229,7 +244,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (hasErrors) + { inputData = null; + } var task = Task.Run(() => DoWork(@base, inputData)); TaskList.Add(task); @@ -240,16 +257,23 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } if (!GetSolveResults(DA, out Base result)) + { // Normal mode not supported return; + } if (result != null) + { DA.SetData(0, result); + } } public Base DoWork(Base @base, Dictionary inputData) @@ -301,9 +325,13 @@ public Base DoWork(Base @base, Dictionary inputData) try { if (Converter != null) + { @base[key] = value == null ? null : Utilities.TryConvertItemToSpeckle(value, Converter); + } else + { @base[key] = value; + } } catch (Exception ex) { @@ -315,7 +343,9 @@ public Base DoWork(Base @base, Dictionary inputData) }); if (hasErrors) + { @base = null; + } } catch (Exception ex) { @@ -333,7 +363,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input || args.ParameterIndex == 0) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectKeysComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectKeysComponent.cs index 2a4a3c1335..2c13e3ee44 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectKeysComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectKeysComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; @@ -55,10 +55,14 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { GH_SpeckleBase speckleObject = null; if (!DA.GetData(0, ref speckleObject)) + { return; + } if (speckleObject.Value == null) + { return; + } var keys = speckleObject.Value.GetMemberNames(); @@ -67,22 +71,32 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) else { if (!DA.GetDataTree(0, out GH_Structure objectTree)) + { return; + } var keys = new List(); foreach (var branch in objectTree.Branches) + { foreach (var item in branch) { var speckleObject = item?.Value; if (speckleObject == null) + { return; + } var objKeys = speckleObject.GetMemberNames(); foreach (var key in objKeys) + { if (!keys.Contains(key)) + { keys.Add(key); + } + } } + } DA.SetDataList(0, keys); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectValueByKeyTaskComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectValueByKeyTaskComponent.cs index 711424cc80..36be6b75c9 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectValueByKeyTaskComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/GetObjectValueByKeyTaskComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Drawing; using System.Linq; @@ -51,25 +51,35 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) DA.GetData(1, ref key); if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Object Value by Key"); + } var @base = speckleObj?.Value; if (@base == null) + { return; + } + var task = Task.Run(() => DoWork(@base, key, CancelToken)); TaskList.Add(task); return; } if (!GetSolveResults(DA, out object value)) + { // No result could be obtained. return; + } // Report all conversion errors as warnings if (Converter != null) { foreach (var error in Converter.Report.ConversionErrors) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, error.ToFormattedString()); + } + Converter.Report.ConversionErrors.Clear(); } @@ -96,7 +106,9 @@ private object DoWork(Base @base, string key, CancellationToken token) try { if (token.IsCancellationRequested) + { return null; + } var obj = @base[key] ?? @base["@" + key]; if (obj == null) @@ -104,7 +116,9 @@ private object DoWork(Base @base, string key, CancellationToken token) // Try check if it's a computed value var members = @base.GetMembers(DynamicBaseMemberType.SchemaComputed); if (members.TryGetValue(key, out object member)) + { obj = member; + } } switch (obj) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/SpeckleObjectGroup.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/SpeckleObjectGroup.cs index 606a7c8bd5..930d2321eb 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/SpeckleObjectGroup.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Objects/SpeckleObjectGroup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -62,7 +62,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { var values = new List(); if (!DA.GetDataList(0, values)) + { return; + } var hasGroups = values.Any(item => item is SpeckleObjectGroup); if (hasGroups) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponent.cs index 25e24c2a4b..9e3d21acaf 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -84,6 +84,7 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon { // Will execute every time a document becomes active (from background or opening file.). if (StreamWrapper != null) + { Task.Run(async () => { // Ensure fresh instance of client. @@ -96,10 +97,13 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon // Compare commit id's. If they don't match, notify user or fetch data if in auto mode if (b.commits.items[0].id != ReceivedCommitId) + { HandleNewCommit(); + } OnDisplayExpired(true); }); + } break; } @@ -125,9 +129,13 @@ private void HandleNewCommit() delegate { if (AutoReceive) + { ExpireSolution(true); + } else + { OnDisplayExpired(true); + } } ); } @@ -159,7 +167,10 @@ public override bool Read(GH_IReader reader) var swString = reader.GetString("StreamWrapper"); if (!string.IsNullOrEmpty(swString)) + { StreamWrapper = new StreamWrapper(swString); + } + JustPastedIn = true; return base.Read(reader); } @@ -241,6 +252,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) Menu_AppendSeparator(menu); if (CurrentComponentState == "receiving") + { Menu_AppendItem( menu, "Cancel Receive", @@ -250,16 +262,19 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) RequestCancellation(); } ); + } Menu_AppendSeparator(menu); if (StreamWrapper != null && !string.IsNullOrEmpty(ReceivedCommitId)) + { Menu_AppendItem( menu, $"View commit {ReceivedCommitId} @ {StreamWrapper.ServerUrl} online ↗", (s, e) => Process.Start($"{StreamWrapper.ServerUrl}/streams/{StreamWrapper.StreamId}/commits/{ReceivedCommitId}") ); + } } protected override void SolveInstance(IGH_DataAccess DA) @@ -315,7 +330,9 @@ protected override void SolveInstance(IGH_DataAccess DA) public override void DisplayProgress(object sender, ElapsedEventArgs e) { if (Workers.Count == 0) + { return; + } Message = ""; var total = 0.0; @@ -356,7 +373,9 @@ private void ParseInput(IGH_DataAccess DA) var ghGoo = DataInput.get_DataItem(0); if (ghGoo == null) + { return; + } var input = ghGoo.GetType().GetProperty("Value")?.GetValue(ghGoo); @@ -420,7 +439,9 @@ private void HandleInputType(StreamWrapper wrapper) } if (StreamWrapper != null && StreamWrapper.Equals(wrapper) && !JustPastedIn) + { return; + } StreamWrapper = wrapper; @@ -444,7 +465,9 @@ private void ApiClient_OnCommitCreated(object sender, CommitInfo e) { // Break if wrapper is branch type and branch name is not equal. if (StreamWrapper.Type == StreamWrapperType.Branch && e.branchName != StreamWrapper.BranchName) + { return; + } HandleNewCommit(); } @@ -490,7 +513,9 @@ public override void DoWork(Action ReportProgress, Action Done) //NOTE: progress set to indeterminate until the TotalChildrenCount is correct //foreach (var kvp in dict) ReportProgress(kvp.Key, (double)kvp.Value / (TotalObjectCount + 1)); foreach (var kvp in dict) + { ReportProgress(kvp.Key, kvp.Value); + } }; ErrorAction = (transportName, exception) => @@ -505,7 +530,9 @@ public override void DoWork(Action ReportProgress, Action Done) asyncParent.CancellationSources.ForEach(source => { if (source.Token != CancellationToken) + { source.Cancel(); + } }); }; @@ -530,7 +557,9 @@ public override void DoWork(Action ReportProgress, Action Done) { receiveComponent.JustPastedIn = false; if (!receiveComponent.ReceiveOnOpen) + { return; + } receiveComponent.CurrentComponentState = "receiving"; RhinoApp.InvokeOnUiThread( @@ -555,12 +584,16 @@ public override void DoWork(Action ReportProgress, Action Done) ); if (myCommit == null) + { throw new Exception("Failed to find a valid commit or object to get."); + } ReceivedCommit = myCommit; if (CancellationToken.IsCancellationRequested) + { return; + } ReceivedObject = await Operations.Receive( myCommit.referencedObject, @@ -591,7 +624,9 @@ await client.CommitReceived( } if (CancellationToken.IsCancellationRequested) + { return; + } Done(); }); @@ -634,13 +669,17 @@ CancellationToken CancellationToken case StreamWrapperType.Undefined: var mb = await client.BranchGet(InputWrapper.StreamId, "main", 1); if (mb.commits.totalCount == 0) + { // TODO: Warn that we're not pulling from the main branch OnFail( GH_RuntimeMessageLevel.Remark, "Main branch was empty. Defaulting to latest commit regardless of branch." ); + } else + { return mb.commits.items[0]; + } var cms = await client.StreamGetCommits(InputWrapper.StreamId, 1); if (cms.Count == 0) @@ -666,10 +705,14 @@ CancellationToken CancellationToken public override void SetData(IGH_DataAccess DA) { if (CancellationToken.IsCancellationRequested) + { return; + } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } var parent = (ReceiveComponent)Parent; @@ -688,7 +731,9 @@ public override void SetData(IGH_DataAccess DA) DA.SetData(1, parent.LastInfoMessage); if (ReceivedObject == null) + { return; + } //the active document may have changed var converter = parent.Converter; @@ -783,13 +828,19 @@ protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasCha public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e) { if (e.Button != MouseButtons.Left) + { return base.RespondToMouseDown(sender, e); + } if (!((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) + { return base.RespondToMouseDown(sender, e); + } if (((ReceiveComponent)Owner).CurrentComponentState == "receiving") + { return GH_ObjectResponse.Handled; + } if (((ReceiveComponent)Owner).AutoReceive) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponentSync.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponentSync.cs index 75d81f888f..db1c14ed00 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponentSync.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.ReceiveComponentSync.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Threading; @@ -75,12 +75,15 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon { // Will execute every time a document becomes active (from background or opening file.). if (StreamWrapper != null) + { Task.Run(async () => { // Ensure fresh instance of client. await ResetApiClient(StreamWrapper); if (source == null) + { CreateCancelationToken(); + } // Get last commit from the branch var b = ApiClient @@ -89,8 +92,12 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon // Compare commit id's. If they don't match, notify user or fetch data if in auto mode if (b.commits.items[0].id != ReceivedCommitId) + { HandleNewCommit(); + } }); + } + break; } case GH_DocumentContext.Unloaded: @@ -113,9 +120,13 @@ private void HandleNewCommit() delegate { if (AutoReceive) + { ExpireSolution(true); + } else + { OnDisplayExpired(true); + } } ); } @@ -138,7 +149,10 @@ private void ApiClient_OnCommitCreated(object sender, CommitInfo e) { // Break if wrapper is branch type and branch name is not equal. if (StreamWrapper.Type == StreamWrapperType.Branch && e.branchName != StreamWrapper.BranchName) + { return; + } + HandleNewCommit(); } @@ -155,6 +169,7 @@ protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown men var kits = KitManager.GetKitsWithConvertersForApp(Utilities.GetVersionedAppName()); foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -165,6 +180,7 @@ protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown men true, Kit != null ? kit.Name == Kit.Name : false ); + } Menu_AppendSeparator(menu); @@ -229,7 +245,9 @@ public override bool Read(GH_IReader reader) var swString = reader.GetString("StreamWrapper"); if (!string.IsNullOrEmpty(swString)) + { StreamWrapper = new StreamWrapper(swString); + } JustPastedIn = true; @@ -237,6 +255,7 @@ public override bool Read(GH_IReader reader) reader.TryGetString("KitName", ref kitName); if (kitName != "") + { try { SetConverterFromKit(kitName); @@ -249,8 +268,11 @@ public override bool Read(GH_IReader reader) ); SetDefaultKitAndConverter(); } + } else + { SetDefaultKitAndConverter(); + } //ConvertToNative = reader.GetBoolean(nameof(ConvertToNative)); @@ -309,7 +331,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) CreateCancelationToken(); ParseInput(DA); if (InputType == "Invalid") + { return; + } } if (InPreSolve) @@ -401,7 +425,10 @@ await client.CommitReceived( else { if (@base == null) + { return; + } + ReceivedObjectId = @base.id; //the active document may have changed @@ -424,7 +451,9 @@ private void ParseInput(IGH_DataAccess DA) var ghGoo = DataInput; if (ghGoo == null) + { return; + } var input = ghGoo.GetType().GetProperty("Value")?.GetValue(ghGoo); @@ -484,7 +513,10 @@ private void HandleInputType(StreamWrapper wrapper) } if (StreamWrapper != null && StreamWrapper.Equals(wrapper) && !JustPastedIn) + { return; + } + StreamWrapper = wrapper; //ResetApiClient(wrapper); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponent.cs index 82bd9d0f51..b8647b052b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -103,7 +103,9 @@ public override bool Read(GH_IReader reader) } if (OutputWrappers.Count != 0) + { JustPastedIn = true; + } } return base.Read(reader); @@ -172,15 +174,18 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { Menu_AppendSeparator(menu); foreach (var ow in OutputWrappers) + { Menu_AppendItem( menu, $"View commit {ow.CommitId} @ {ow.ServerUrl} online ↗", (s, e) => Process.Start($"{ow.ServerUrl}/streams/{ow.StreamId}/commits/{ow.CommitId}") ); + } } Menu_AppendSeparator(menu); if (CurrentComponentState == "sending") + { Menu_AppendItem( menu, "Cancel Send", @@ -190,6 +195,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) RequestCancellation(); } ); + } base.AppendAdditionalMenuItems(menu); } @@ -225,7 +231,9 @@ protected override void SolveInstance(IGH_DataAccess DA) public override void DisplayProgress(object sender, ElapsedEventArgs e) { if (Workers.Count == 0) + { return; + } Message = ""; var total = 0.0; @@ -387,6 +395,7 @@ public override void DoWork(Action ReportProgress, Action Done) var transport = data.GetType().GetProperty("Value").GetValue(data); if (transport is string s) + { try { transport = new StreamWrapper(s); @@ -396,6 +405,7 @@ public override void DoWork(Action ReportProgress, Action Done) // TODO: Check this with team. RuntimeMessages.Add((GH_RuntimeMessageLevel.Warning, e.ToFormattedString())); } + } if (transport is StreamWrapper sw) { @@ -453,9 +463,11 @@ public override void DoWork(Action ReportProgress, Action Done) InternalProgressAction = dict => { foreach (var kvp in dict) + { //NOTE: progress set to indeterminate until the TotalChildrenCount is correct //ReportProgress(kvp.Key, (double)kvp.Value / TotalObjectCount); ReportProgress(kvp.Key, kvp.Value); + } }; ErrorAction = (transportName, exception) => @@ -470,7 +482,9 @@ public override void DoWork(Action ReportProgress, Action Done) asyncParent.CancellationSources.ForEach(source => { if (source.Token != CancellationToken) + { source.Cancel(); + } }); }; @@ -506,7 +520,9 @@ public override void DoWork(Action ReportProgress, Action Done) var message = _MessageInput.get_FirstItem(true).Value; if (message == "") + { message = $"Pushed {TotalObjectCount} elements from Grasshopper."; + } var prevCommits = sendComponent.OutputWrappers; @@ -519,7 +535,9 @@ public override void DoWork(Action ReportProgress, Action Done) } if (!(transport is ServerTransport)) + { continue; // skip non-server transports (for now) + } try { @@ -540,7 +558,9 @@ public override void DoWork(Action ReportProgress, Action Done) c => c.ServerUrl == client.ServerUrl && c.StreamId == ((ServerTransport)transport).StreamId ); if (prevCommit != null) + { commitCreateInput.parents = new List { prevCommit.CommitId }; + } var commitId = await client.CommitCreate(commitCreateInput, CancellationToken); @@ -595,7 +615,9 @@ public override void SetData(IGH_DataAccess DA) } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } DA.SetDataList(0, OutputWrappers); @@ -620,7 +642,9 @@ public override void SetData(IGH_DataAccess DA) foreach (var t in Transports) { if (!(t is ServerTransport st)) + { continue; + } var mb = st.TotalSentBytes / 1e6; Parent.AddRuntimeMessage( @@ -713,6 +737,7 @@ protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasCha public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e) { if (e.Button == MouseButtons.Left) + { if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) { if (((SendComponent)Owner).AutoSend) @@ -722,12 +747,14 @@ public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_Canvas return GH_ObjectResponse.Handled; } if (((SendComponent)Owner).CurrentComponentState == "sending") + { return GH_ObjectResponse.Handled; - + } ((SendComponent)Owner).CurrentComponentState = "primed_to_send"; Owner.ExpireSolution(true); return GH_ObjectResponse.Handled; } + } return base.RespondToMouseDown(sender, e); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponentSync.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponentSync.cs index 0a847c1fcf..1dc6bee8b0 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponentSync.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.SendComponentSync.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; @@ -90,9 +90,14 @@ protected override void RegisterOutputParams(GH_OutputParamManager pManager) public void SetConverterFromKit(string kitName) { if (Kit == null) + { return; + } + if (kitName == Kit.Name) + { return; + } Kit = KitManager.Kits.FirstOrDefault(k => k.Name == kitName); Converter = Kit.LoadConverter(Utilities.GetVersionedAppName()); @@ -112,6 +117,7 @@ protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown men var kits = KitManager.GetKitsWithConvertersForApp(Utilities.GetVersionedAppName()); foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -122,20 +128,26 @@ protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown men true, kit.Name == Kit.Name ); + } Menu_AppendSeparator(menu); if (OutputWrappers != null) + { if (OutputWrappers.Count != 0) { Menu_AppendSeparator(menu); foreach (var ow in OutputWrappers) + { Menu_AppendItem( menu, $"View commit {ow.CommitId} @ {ow.ServerUrl} online ↗", (s, e) => Process.Start($"{ow.ServerUrl}/streams/{ow.StreamId}/commits/{ow.CommitId}") ); + } } + } + Menu_AppendSeparator(menu); base.AppendAdditionalComponentMenuItems(menu); @@ -157,6 +169,7 @@ public override bool Read(GH_IReader reader) var wrappersRaw = reader.GetString("OutputWrappers"); var wrapperLines = wrappersRaw.Split('\n'); if (wrapperLines != null && wrapperLines.Length != 0 && wrappersRaw != "") + { foreach (var line in wrapperLines) { var pieces = line.Split('\t'); @@ -169,11 +182,13 @@ public override bool Read(GH_IReader reader) } ); } + } var kitName = ""; reader.TryGetString("KitName", ref kitName); if (kitName != "") + { try { SetConverterFromKit(kitName); @@ -186,8 +201,11 @@ public override bool Read(GH_IReader reader) ); SetDefaultKitAndConverter(); } + } else + { SetDefaultKitAndConverter(); + } return base.Read(reader); } @@ -303,6 +321,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var transport = data.GetType().GetProperty("Value").GetValue(data); if (transport is string s) + { try { transport = new StreamWrapper(s); @@ -312,6 +331,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) // TODO: Check this with team. AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, e.ToFormattedString()); } + } if (transport is StreamWrapper sw) { @@ -389,7 +409,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var message = messageInput; //.get_FirstItem(true).Value; if (message == "") + { message = $"Pushed {TotalObjectCount} elements from Grasshopper."; + } var prevCommits = new List(); @@ -402,7 +424,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (!(transport is ServerTransport)) + { continue; // skip non-server transports (for now) + } try { @@ -423,7 +447,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) c => c.ServerUrl == client.ServerUrl && c.StreamId == ((ServerTransport)transport).StreamId ); if (prevCommit != null) + { commitCreateInput.parents = new List { prevCommit.CommitId }; + } var commitId = await client.CommitCreate(commitCreateInput, source.Token); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.UpgradeUtils.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.UpgradeUtils.cs index 27f1fa6886..cfc2c01038 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.UpgradeUtils.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.UpgradeUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Ops.Deprecated; using ConnectorGrasshopper.UpgradeUtilities; using Grasshopper.Kernel; @@ -11,7 +11,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); var attributes = new VariableInputSendComponentAttributes(upgradedComponent as GH_Component); @@ -35,7 +37,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); var attributes = new VariableInputReceiveComponentAttributes(upgradedComponent as GH_Component); @@ -59,7 +63,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); var attributes = new NewVariableInputSendComponentAttributes(upgradedComponent as GH_Component); @@ -81,7 +87,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); UpgradeUtils.SwapGroups(document, component, upgradedComponent); @@ -99,7 +107,9 @@ public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document documen { var component = target as IGH_Component; if (component == null) + { return null; + } var upgradedComponent = GH_UpgradeUtil.SwapComponents(component, UpgradeTo); UpgradeUtils.SwapGroups(document, component, upgradedComponent); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.VariableInputSendComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.VariableInputSendComponent.cs index 8dd8cc025e..391f278e10 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.VariableInputSendComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Deprecated/Operations.VariableInputSendComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -135,7 +135,9 @@ public override bool Read(GH_IReader reader) } if (OutputWrappers.Count != 0) + { JustPastedIn = true; + } } return base.Read(reader); @@ -210,15 +212,18 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { Menu_AppendSeparator(menu); foreach (var ow in OutputWrappers) + { Menu_AppendItem( menu, $"View commit {ow.CommitId} @ {ow.ServerUrl} online ↗", (s, e) => Process.Start($"{ow.ServerUrl}/streams/{ow.StreamId}/commits/{ow.CommitId}") ); + } } Menu_AppendSeparator(menu); if (CurrentComponentState == "sending") + { Menu_AppendItem( menu, "Cancel Send", @@ -228,6 +233,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) RequestCancellation(); } ); + } base.AppendAdditionalMenuItems(menu); } @@ -263,7 +269,9 @@ protected override void SolveInstance(IGH_DataAccess DA) public override void DisplayProgress(object sender, ElapsedEventArgs e) { if (Workers.Count == 0) + { return; + } Message = ""; var total = 0.0; @@ -308,7 +316,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: @@ -404,6 +415,7 @@ public override void DoWork(Action ReportProgress, Action Done) int convertedCount = 0; foreach (var d in DataInputs) + { try { var converted = Utilities.DataTreeToNestedLists( @@ -421,8 +433,13 @@ public override void DoWork(Action ReportProgress, Action Done) var param = Parent.Params.Input.Find(p => p.Name == d.Key || p.NickName == d.Key); var key = d.Key; if (param is SendReceiveDataParam srParam) + { if (srParam.Detachable && !key.StartsWith("@")) + { key = "@" + key; + } + } + ObjectToSend[key] = converted; TotalObjectCount += ObjectToSend.GetTotalChildrenCount(); } @@ -432,6 +449,7 @@ public override void DoWork(Action ReportProgress, Action Done) Done(); return; } + } if (convertedCount == 0) { @@ -461,6 +479,7 @@ public override void DoWork(Action ReportProgress, Action Done) var transport = data.GetType().GetProperty("Value").GetValue(data); if (transport is string s) + { try { transport = new StreamWrapper(s); @@ -470,6 +489,7 @@ public override void DoWork(Action ReportProgress, Action Done) // TODO: Check this with team. RuntimeMessages.Add((GH_RuntimeMessageLevel.Warning, e.ToFormattedString())); } + } if (transport is StreamWrapper sw) { @@ -527,9 +547,11 @@ public override void DoWork(Action ReportProgress, Action Done) InternalProgressAction = dict => { foreach (var kvp in dict) + { //NOTE: progress set to indeterminate until the TotalChildrenCount is correct //ReportProgress(kvp.Key, (double)kvp.Value / TotalObjectCount); ReportProgress(kvp.Key, kvp.Value); + } }; ErrorAction = (transportName, exception) => @@ -544,7 +566,9 @@ public override void DoWork(Action ReportProgress, Action Done) asyncParent.CancellationSources.ForEach(source => { if (source.Token != CancellationToken) + { source.Cancel(); + } }); }; @@ -580,7 +604,9 @@ public override void DoWork(Action ReportProgress, Action Done) var message = _MessageInput.get_FirstItem(true).Value; if (message == "") + { message = $"Pushed {TotalObjectCount} elements from Grasshopper."; + } var prevCommits = sendComponent.OutputWrappers; @@ -593,7 +619,9 @@ public override void DoWork(Action ReportProgress, Action Done) } if (!(transport is ServerTransport)) + { continue; // skip non-server transports (for now) + } try { @@ -614,7 +642,9 @@ public override void DoWork(Action ReportProgress, Action Done) c => c.ServerUrl == client.ServerUrl && c.StreamId == ((ServerTransport)transport).StreamId ); if (prevCommit != null) + { commitCreateInput.parents = new List { prevCommit.CommitId }; + } var commitId = await client.CommitCreate(commitCreateInput, CancellationToken); @@ -669,7 +699,9 @@ public override void SetData(IGH_DataAccess DA) } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } DA.SetDataList(0, OutputWrappers); @@ -694,7 +726,9 @@ public override void SetData(IGH_DataAccess DA) foreach (var t in Transports) { if (!(t is ServerTransport st)) + { continue; + } var mb = st.TotalSentBytes / 1e6; Parent.AddRuntimeMessage( @@ -785,6 +819,7 @@ protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasCha public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e) { if (e.Button == MouseButtons.Left) + { if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) { if (((VariableInputSendComponent)Owner).AutoSend) @@ -794,12 +829,14 @@ public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_Canvas return GH_ObjectResponse.Handled; } if (((VariableInputSendComponent)Owner).CurrentComponentState == "sending") + { return GH_ObjectResponse.Handled; - + } ((VariableInputSendComponent)Owner).CurrentComponentState = "primed_to_send"; Owner.ExpireSolution(true); return GH_ObjectResponse.Handled; } + } return base.RespondToMouseDown(sender, e); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.ReceiveLocalComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.ReceiveLocalComponent.cs index 85af60e580..6dc660377f 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.ReceiveLocalComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.ReceiveLocalComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -57,6 +57,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) var kits = KitManager.GetKitsWithConvertersForApp(Utilities.GetVersionedAppName()); foreach (var kit in kits) + { Menu_AppendItem( menu, $"{kit.Name} ({kit.Description})", @@ -67,6 +68,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) true, kit.Name == Kit.Name ); + } base.AppendAdditionalMenuItems(menu); } @@ -80,7 +82,9 @@ public override void AddedToDocument(GH_Document document) public void SetConverterFromKit(string kitName) { if (kitName == Kit.Name) + { return; + } Kit = KitManager.Kits.FirstOrDefault(k => k.Name == kitName); Converter = Kit.LoadConverter(Utilities.GetVersionedAppName()); @@ -120,7 +124,9 @@ protected override void SolveInstance(IGH_DataAccess DA) } base.SolveInstance(DA); if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } } } @@ -174,10 +180,14 @@ public override void DoWork(Action ReportProgress, Action Done) public override void SetData(IGH_DataAccess DA) { if (data != null) + { DA.SetDataTree(0, data); + } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } Parent.Message = "Done"; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SendLocalComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SendLocalComponent.cs index ba59a29ab1..4758799d80 100755 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SendLocalComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SendLocalComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using ConnectorGrasshopper.Objects; @@ -53,7 +53,9 @@ protected override void SolveInstance(IGH_DataAccess DA) { base.SolveInstance(DA); if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } } } @@ -98,7 +100,10 @@ public override void SetData(IGH_DataAccess DA) { DA.SetData(0, sentObjectId); foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } + data = null; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncReceiveComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncReceiveComponent.cs index 67fecfcb80..ce15a8adc1 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncReceiveComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncReceiveComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Threading.Tasks; @@ -51,6 +51,7 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon { // Will execute every time a document becomes active (from background or opening file.). if (StreamWrapper != null) + { Task.Run(async () => { // Ensure fresh instance of client. @@ -63,8 +64,12 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon // Compare commit id's. If they don't match, notify user or fetch data if in auto mode if (b.commits.items[0].id != ReceivedCommitId) + { HandleNewCommit(); + } }); + } + break; } case GH_DocumentContext.Unloaded: @@ -87,9 +92,13 @@ private void HandleNewCommit() delegate { if (AutoReceive) + { ExpireSolution(true); + } else + { OnDisplayExpired(true); + } } ); } @@ -112,7 +121,10 @@ private void ApiClient_OnCommitCreated(object sender, CommitInfo e) { // Break if wrapper is branch type and branch name is not equal. if (StreamWrapper.Type == StreamWrapperType.Branch && e.branchName != StreamWrapper.BranchName) + { return; + } + HandleNewCommit(); } @@ -181,7 +193,9 @@ public override bool Read(GH_IReader reader) var swString = reader.GetString("StreamWrapper"); if (!string.IsNullOrEmpty(swString)) + { StreamWrapper = new StreamWrapper(swString); + } JustPastedIn = true; return base.Read(reader); @@ -209,7 +223,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { ParseInput(DA); if (InputType == "Invalid") + { return; + } } if (InPreSolve) @@ -301,7 +317,10 @@ await client.CommitReceived( else { if (@base == null) + { return; + } + ReceivedObjectId = @base.id; //the active document may have changed @@ -317,7 +336,9 @@ private void ParseInput(IGH_DataAccess DA) { IGH_Goo ghGoo = null; if (!DA.GetData(0, ref ghGoo)) + { return; + } var input = ghGoo.GetType().GetProperty("Value")?.GetValue(ghGoo); @@ -335,7 +356,9 @@ private void ParseInput(IGH_DataAccess DA) } if (newWrapper != null) + { inputType = GetStreamTypeMessage(newWrapper); + } InputType = inputType; HandleInputType(newWrapper); @@ -371,7 +394,10 @@ private void HandleInputType(StreamWrapper wrapper) } if (StreamWrapper != null && StreamWrapper.Equals(wrapper) && !JustPastedIn) + { return; + } + StreamWrapper = wrapper; Task.Run(async () => diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncSendComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncSendComponent.cs index f69b181ee4..b560cc2a22 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncSendComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.SyncSendComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; @@ -81,11 +81,13 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { Menu_AppendSeparator(menu); foreach (var ow in OutputWrappers) + { Menu_AppendItem( menu, $"View commit {ow.CommitId} @ {ow.ServerUrl} online ↗", (s, e) => Process.Start($"{ow.ServerUrl}/streams/{ow.StreamId}/commits/{ow.CommitId}") ); + } } } @@ -103,6 +105,7 @@ public override bool Read(GH_IReader reader) var wrappersRaw = reader.GetString("OutputWrappers"); var wrapperLines = wrappersRaw.Split('\n'); if (wrapperLines.Length != 0 && wrappersRaw != "") + { foreach (var line in wrapperLines) { var pieces = line.Split('\t'); @@ -115,6 +118,7 @@ public override bool Read(GH_IReader reader) } ); } + } return base.Read(reader); } @@ -173,6 +177,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var transport = data.GetType().GetProperty("Value").GetValue(data); if (transport is string s) + { try { transport = new StreamWrapper(s); @@ -182,6 +187,7 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) // TODO: Check this with team. AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, e.ToFormattedString()); } + } if (transport is StreamWrapper sw) { @@ -254,7 +260,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var message = messageInput; //.get_FirstItem(true).Value; if (message == "") + { message = $"Pushed {totalObjectCount} elements from Grasshopper."; + } var prevCommits = new List(); @@ -267,7 +275,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (!(transport is ServerTransport)) + { continue; // skip non-server transports (for now) + } try { @@ -288,7 +298,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) c => c.ServerUrl == client.ServerUrl && c.StreamId == ((ServerTransport)transport).StreamId ); if (prevCommit != null) + { commitCreateInput.parents = new List { prevCommit.CommitId }; + } var commitId = await client.CommitCreate(commitCreateInput, CancelToken); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs index df532bda5a..1fab11f6b3 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -120,6 +120,7 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon { // Will execute every time a document becomes active (from background or opening file.). if (StreamWrapper != null) + { Task.Run(async () => { // Ensure fresh instance of client. @@ -133,10 +134,13 @@ public override void DocumentContextChanged(GH_Document document, GH_DocumentCon // Compare commit id's. If they don't match, notify user or fetch data if in auto mode if (b.commits.items[0].id != ReceivedCommitId) + { HandleNewCommit(); + } OnDisplayExpired(true); }); + } break; } @@ -162,9 +166,13 @@ private void HandleNewCommit() delegate { if (AutoReceive) + { ExpireSolution(true); + } else + { OnDisplayExpired(true); + } } ); } @@ -199,7 +207,10 @@ public override bool Read(GH_IReader reader) ExpandOutput = expand; var swString = reader.GetString("StreamWrapper"); if (!string.IsNullOrEmpty(swString)) + { StreamWrapper = new StreamWrapper(swString); + } + JustPastedIn = true; return base.Read(reader); } @@ -311,6 +322,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) Menu_AppendSeparator(menu); if (CurrentComponentState == "receiving") + { Menu_AppendItem( menu, "Cancel Receive", @@ -320,16 +332,19 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) RequestCancellation(); } ); + } Menu_AppendSeparator(menu); if (StreamWrapper != null && !string.IsNullOrEmpty(ReceivedCommitId)) + { Menu_AppendItem( menu, $"View commit {ReceivedCommitId} @ {StreamWrapper.ServerUrl} online ↗", (s, e) => Process.Start($"{StreamWrapper.ServerUrl}/streams/{StreamWrapper.StreamId}/commits/{ReceivedCommitId}") ); + } } protected override void SolveInstance(IGH_DataAccess DA) @@ -390,7 +405,9 @@ protected override void SolveInstance(IGH_DataAccess DA) public override void DisplayProgress(object sender, ElapsedEventArgs e) { if (Workers.Count == 0) + { return; + } Message = ""; var total = 0.0; @@ -430,7 +447,9 @@ private void ParseInput(IGH_DataAccess DA) var ghGoo = DataInput.get_DataItem(0); if (ghGoo == null) + { return; + } var input = ghGoo.GetType().GetProperty("Value")?.GetValue(ghGoo); @@ -499,7 +518,9 @@ private void HandleInputType(StreamWrapper wrapper) } if (StreamWrapper != null && StreamWrapper.Equals(wrapper) && !JustPastedIn) + { return; + } StreamWrapper = wrapper; @@ -517,7 +538,9 @@ public async Task ResetApiClient(StreamWrapper wrapper) { var hasInternet = await Http.UserHasInternet(); if (!hasInternet) + { throw new Exception("You are not connected to the internet."); + } Account account; try @@ -551,7 +574,9 @@ private void ApiClient_OnCommitCreated(object sender, CommitInfo e) { // Break if wrapper is branch type and branch name is not equal. if (StreamWrapper.Type == StreamWrapperType.Branch && e.branchName != StreamWrapper.BranchName) + { return; + } HandleNewCommit(); } @@ -599,7 +624,9 @@ public override void DoWork(Action ReportProgress, Action Done) //NOTE: progress set to indeterminate until the TotalChildrenCount is correct //foreach (var kvp in dict) ReportProgress(kvp.Key, (double)kvp.Value / (TotalObjectCount + 1)); foreach (var kvp in dict) + { ReportProgress(kvp.Key, kvp.Value); + } }; ErrorAction = (transportName, exception) => @@ -614,12 +641,17 @@ public override void DoWork(Action ReportProgress, Action Done) asyncParent.CancellationSources.ForEach(source => { if (source.Token != CancellationToken) + { source.Cancel(); + } }); }; if (receiveComponent.ApiResetTask == null) + { receiveComponent.ApiResetTask = receiveComponent.ResetApiClient(InputWrapper); + } + receiveComponent.ApiResetTask.Wait(); Account acc = receiveComponent.ApiClient.Account; @@ -631,7 +663,9 @@ public override void DoWork(Action ReportProgress, Action Done) { receiveComponent.JustPastedIn = false; if (!receiveComponent.ReceiveOnOpen) + { return; + } receiveComponent.CurrentComponentState = "receiving"; RhinoApp.InvokeOnUiThread( @@ -647,7 +681,9 @@ public override void DoWork(Action ReportProgress, Action Done) { var hasInternet = await Http.UserHasInternet(); if (!hasInternet) + { throw new Exception("You are not connected to the internet."); + } receiveComponent.PrevReceivedData = null; var myCommit = await GetCommit( @@ -680,7 +716,9 @@ public override void DoWork(Action ReportProgress, Action Done) ); if (CancellationToken.IsCancellationRequested) + { return; + } ReceivedObject = await Operations.Receive( myCommit.referencedObject, @@ -711,9 +749,15 @@ await receiveComponent.ApiClient.CommitReceived( } if (CancellationToken.IsCancellationRequested) + { return; + } + if (ReceivedObject != null) + { AutoCreateOutputs(ReceivedObject); + } + Done(); }); t.Wait(); @@ -742,10 +786,13 @@ CancellationToken CancellationToken { myCommit = await client.CommitGet(InputWrapper.StreamId, InputWrapper.CommitId, CancellationToken); if (myCommit == null) + { OnFail( GH_RuntimeMessageLevel.Warning, $"Commit with id {InputWrapper.CommitId} was not found in stream {InputWrapper.StreamId}." ); + } + return myCommit; } catch (Exception e) @@ -760,13 +807,17 @@ CancellationToken CancellationToken case StreamWrapperType.Undefined: var mb = await client.BranchGet(InputWrapper.StreamId, "main", 1, CancellationToken); if (mb.commits.totalCount == 0) + { // TODO: Warn that we're not pulling from the main branch OnFail( GH_RuntimeMessageLevel.Remark, "Main branch was empty. Defaulting to latest commit regardless of branch." ); + } else + { return mb.commits.items[0]; + } var cms = await client.StreamGetCommits(InputWrapper.StreamId, 1, CancellationToken); if (cms.Count == 0) @@ -800,10 +851,14 @@ CancellationToken CancellationToken public override void SetData(IGH_DataAccess DA) { if (CancellationToken.IsCancellationRequested) + { return; + } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } var parent = (VariableInputReceiveComponent)Parent; @@ -824,7 +879,9 @@ public override void SetData(IGH_DataAccess DA) DA.SetData(infoIndex, parent.LastInfoMessage); if (ReceivedObject == null) + { return; + } //the active document may have changed var converter = parent.Converter; @@ -847,7 +904,9 @@ public override void SetData(IGH_DataAccess DA) var param = Parent.Params.Output.FindIndex(p => p.Name == name || p.Name == name.Substring(1)); var ighP = Parent.Params.Output[param]; if (ighP is SendReceiveDataParam srParam) + { srParam.Detachable = name.StartsWith("@"); + } GH_Structure dataTree; if (prop is Base b && Utilities.CanConvertToDataTree(b)) @@ -872,7 +931,9 @@ private List GetOutputList(Base b) !receiveComponent.ExpandOutput || receiveComponent.Converter != null && receiveComponent.Converter.CanConvertToNative(b) ) + { return new List { "Data" }; + } // Get the full list of output parameters var fullProps = new List(); @@ -881,7 +942,9 @@ private List GetOutputList(Base b) .ForEach(prop => { if (!fullProps.Contains(prop)) + { fullProps.Add(prop); + } }); fullProps.Sort(); return fullProps; @@ -897,7 +960,9 @@ private bool HasSingleRename() { var equalLength = outputList.Count == Parent?.Params.Output.Count; if (!equalLength) + { return false; + } var diffParams = Parent?.Params.Output.Where( param => !outputList.Contains(param.Name) && !outputList.Contains("@" + param.Name) @@ -910,7 +975,9 @@ private void AutoCreateOutputs(Base @base) outputList = GetOutputList(@base); outputList.Insert(0, "Info"); if (!OutputMismatch()) + { return; + } Parent.RecordUndoEvent("Creating Outputs"); if (HasSingleRename()) @@ -943,7 +1010,9 @@ private void AutoCreateOutputs(Base @base) remove.ForEach(b => { if (b != -1 && Parent.Params.Output[b].Recipients.Count == 0) + { Parent.Params.UnregisterOutputParameter(Parent.Params.Output[b]); + } }); outputList.ForEach(s => @@ -965,7 +1034,9 @@ private void AutoCreateOutputs(Base @base) Parent.Params.RegisterOutputParam(newParam, Parent.Params.Output.Count); } if (param is SendReceiveDataParam srParam) + { srParam.Detachable = isDetached; + } }); var paramNames = Parent.Params.Output.Select(p => p.Name).ToList(); @@ -1059,13 +1130,19 @@ protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasCha public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e) { if (e.Button != MouseButtons.Left) + { return base.RespondToMouseDown(sender, e); + } if (!((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) + { return base.RespondToMouseDown(sender, e); + } if (((VariableInputReceiveComponent)Owner).CurrentComponentState == "receiving") + { return GH_ObjectResponse.Handled; + } if (((VariableInputReceiveComponent)Owner).AutoReceive) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputSendComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputSendComponent.cs index 95c09ce605..0c6fccab83 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputSendComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputSendComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -147,7 +147,9 @@ public override bool Read(GH_IReader reader) } if (OutputWrappers.Count != 0) + { JustPastedIn = true; + } } return base.Read(reader); @@ -222,15 +224,18 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { Menu_AppendSeparator(menu); foreach (var ow in OutputWrappers) + { Menu_AppendItem( menu, $"View commit {ow.CommitId} @ {ow.ServerUrl} online ↗", (s, e) => Process.Start($"{ow.ServerUrl}/streams/{ow.StreamId}/commits/{ow.CommitId}") ); + } } Menu_AppendSeparator(menu); if (CurrentComponentState == "sending") + { Menu_AppendItem( menu, "Cancel Send", @@ -240,6 +245,7 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) RequestCancellation(); } ); + } base.AppendAdditionalMenuItems(menu); } @@ -283,7 +289,9 @@ protected override void SolveInstance(IGH_DataAccess DA) public override void DisplayProgress(object sender, ElapsedEventArgs e) { if (Workers.Count == 0) + { return; + } Message = ""; var total = 0.0; @@ -328,7 +336,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: @@ -420,13 +431,16 @@ public override void DoWork(Action ReportProgress, Action Done) sendComponent.Converter.SetContextDocument(Loader.GetCurrentDocument()); if (!Http.UserHasInternet().Result) + { throw new Exception("You are not connected to the internet."); + } // Note: this method actually converts the objects to speckle too ObjectToSend = new Base(); int convertedCount = 0; foreach (var d in DataInputs) + { try { var converted = Utilities.DataTreeToSpeckle( @@ -446,8 +460,13 @@ public override void DoWork(Action ReportProgress, Action Done) var param = Parent.Params.Input.Find(p => p.Name == d.Key || p.NickName == d.Key); var key = d.Key; if (param is SendReceiveDataParam srParam) + { if (srParam.Detachable && !key.StartsWith("@")) + { key = "@" + key; + } + } + ObjectToSend[key] = converted; TotalObjectCount += ObjectToSend.GetTotalChildrenCount(); } @@ -457,9 +476,12 @@ public override void DoWork(Action ReportProgress, Action Done) Done(); return; } + } foreach (var error in sendComponent.Converter.Report.ConversionErrors) + { RuntimeMessages.Add((GH_RuntimeMessageLevel.Warning, error.ToFormattedString())); + } if (convertedCount == 0) { @@ -489,6 +511,7 @@ public override void DoWork(Action ReportProgress, Action Done) var transport = data.GetType().GetProperty("Value").GetValue(data); if (transport is string s) + { try { transport = new StreamWrapper(s); @@ -498,6 +521,7 @@ public override void DoWork(Action ReportProgress, Action Done) // TODO: Check this with team. RuntimeMessages.Add((GH_RuntimeMessageLevel.Warning, e.ToFormattedString())); } + } if (transport is StreamWrapper sw) { @@ -555,9 +579,11 @@ public override void DoWork(Action ReportProgress, Action Done) InternalProgressAction = dict => { foreach (var kvp in dict) + { //NOTE: progress set to indeterminate until the TotalChildrenCount is correct //ReportProgress(kvp.Key, (double)kvp.Value / TotalObjectCount); ReportProgress(kvp.Key, kvp.Value); + } }; ErrorAction = (transportName, exception) => @@ -572,7 +598,9 @@ public override void DoWork(Action ReportProgress, Action Done) asyncParent.CancellationSources.ForEach(source => { if (source.Token != CancellationToken) + { source.Cancel(); + } }); }; @@ -616,7 +644,9 @@ public override void DoWork(Action ReportProgress, Action Done) var message = _MessageInput.get_FirstItem(true).Value; if (message == "") + { message = $"Pushed {TotalObjectCount} elements from Grasshopper."; + } var prevCommits = sendComponent.OutputWrappers; @@ -629,7 +659,9 @@ public override void DoWork(Action ReportProgress, Action Done) } if (!(transport is ServerTransport)) + { continue; // skip non-server transports (for now) + } try { @@ -650,7 +682,9 @@ public override void DoWork(Action ReportProgress, Action Done) c => c.ServerUrl == client.ServerUrl && c.StreamId == ((ServerTransport)transport).StreamId ); if (prevCommit != null) + { commitCreateInput.parents = new List { prevCommit.CommitId }; + } var commitId = await client.CommitCreate(commitCreateInput, CancellationToken); @@ -705,7 +739,9 @@ public override void SetData(IGH_DataAccess DA) } foreach (var (level, message) in RuntimeMessages) + { Parent.AddRuntimeMessage(level, message); + } DA.SetDataList(0, OutputWrappers); @@ -730,7 +766,9 @@ public override void SetData(IGH_DataAccess DA) foreach (var t in Transports) { if (!(t is ServerTransport st)) + { continue; + } var mb = st.TotalSentBytes / 1e6; Parent.AddRuntimeMessage( @@ -821,6 +859,7 @@ protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasCha public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_CanvasMouseEvent e) { if (e.Button == MouseButtons.Left) + { if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation)) { if (((NewVariableInputSendComponent)Owner).AutoSend) @@ -830,12 +869,14 @@ public override GH_ObjectResponse RespondToMouseDown(GH_Canvas sender, GH_Canvas return GH_ObjectResponse.Handled; } if (((NewVariableInputSendComponent)Owner).CurrentComponentState == "sending") + { return GH_ObjectResponse.Handled; - + } ((NewVariableInputSendComponent)Owner).CurrentComponentState = "primed_to_send"; Owner.ExpireSolution(true); return GH_ObjectResponse.Handled; } + } return base.RespondToMouseDown(sender, e); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CSOViewModel.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CSOViewModel.cs index 052ab09762..42cfbff49e 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CSOViewModel.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CSOViewModel.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Runtime.CompilerServices; using Eto.Forms; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs index d5416f1b54..8b0591e185 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs @@ -146,32 +146,47 @@ public override void AppendAdditionalMenuItems(ToolStripDropDown menu) public override void AddedToDocument(GH_Document document) { if (readFailed) + { return; + } // To ensure conversion strategy does not change, we record if the user has modified this schema tag and will keep it as is. // If not, schemaTag will be synchronised with the default value every time the document opens. if (!UserSetSchemaTag) + { UseSchemaTag = SpeckleGHSettings.UseSchemaTag; + } if (SelectedConstructor != null) { base.AddedToDocument(document); if (Instances.ActiveCanvas?.Document == null) + { return; + } + var otherSchemaBuilders = Instances.ActiveCanvas?.Document.FindObjects(new List { Name }, 10000); foreach (var comp in otherSchemaBuilders) { if (!(comp is CreateSchemaObject scb)) + { continue; + } + if (scb.Seed != Seed) + { continue; + } + Seed = GenerateSeed(); break; } (Params.Output[0] as SpeckleBaseParam).UseSchemaTag = UseSchemaTag; #if RHINO7 - if(!Instances.RunningHeadless) + if (!Instances.RunningHeadless) + { (Params.Output[0] as SpeckleBaseParam).ExpirePreview(true); + } #else (Params.Output[0] as SpeckleBaseParam).ExpirePreview(true); #endif @@ -198,7 +213,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: @@ -226,7 +244,9 @@ public void SwitchConstructor(ConstructorInfo constructor) var props = constructor.GetParameters(); foreach (var p in props) + { RegisterPropertyAsInputParameter(p, k++); + } UserInterfaceUtils.CreateCanvasDropdownForAllEnumInputs(this, props); @@ -250,7 +270,9 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) // get property name and value Type propType = param.ParameterType; if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { propType = Nullable.GetUnderlyingType(propType); + } string propName = param.Name; object propValue = param; @@ -260,7 +282,10 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) if (param.IsOptional) { if (!string.IsNullOrEmpty(d)) + { d += ", "; + } + var def = param.DefaultValue == null ? "null" : param.DefaultValue.ToString(); d += "default = " + def; } @@ -274,7 +299,9 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) newInputParam.Description = $"({propType.Name}) {d}"; newInputParam.Optional = param.IsOptional; if (param.IsOptional) + { newInputParam.SetPersistentData(param.DefaultValue); + } // check if input needs to be a list or item access bool isCollection = @@ -282,9 +309,13 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) && propType != typeof(string) && !propType.Name.ToLower().Contains("dictionary"); if (isCollection) + { newInputParam.Access = GH_ParamAccess.list; + } else + { newInputParam.Access = GH_ParamAccess.item; + } Params.RegisterInputParam(newInputParam, index); } @@ -300,7 +331,9 @@ public static GH_ValueList CreateDropDown(string name, List<(string name, int va valueList.ListItems.Clear(); for (int i = 0; i < values.Count; i++) + { valueList.ListItems.Add(new GH_ValueListItem(values[i].name, values[i].value.ToString())); + } valueList.Attributes.Pivot = new PointF(x - 200, y - 10); @@ -323,7 +356,9 @@ public override bool Read(GH_IReader reader) SelectedConstructor = CSOUtils.FindConstructor(constructorName, typeName); if (SelectedConstructor == null) + { readFailed = true; + } } catch { @@ -383,7 +418,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Create Schema Object", Name); + } var units = Units.GetUnitsFromString(Loader.GetCurrentDocument().ModelUnitSystem.ToString()); @@ -431,7 +468,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) ?.Where(o => o.AttributeType.IsEquivalentTo(typeof(SchemaMainParam))) ?.Count() > 0 ) + { mainSchemaObj = objectProp; + } } object schemaObject = null; @@ -496,7 +535,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) private object ExtractRealInputValue(object inputValue) { if (inputValue == null) + { return null; + } if (inputValue is IGH_Goo) { @@ -513,12 +554,16 @@ private object ExtractRealInputValue(object inputValue) private object GetObjectListProp(IGH_Param param, List values, Type t) { if (!values.Any()) + { return null; + } var list = (IList)Activator.CreateInstance(t); var listElementType = list.GetType().GetGenericArguments().Single(); foreach (var value in values) + { list.Add(ConvertType(listElementType, value, param.Name)); + } return list; } @@ -532,22 +577,29 @@ private object GetObjectProp(IGH_Param param, object value, Type t) private object ConvertType(Type type, object value, string name) { if (value == null) + { return null; + } var typeOfValue = value.GetType(); if (value == null || typeOfValue == type || type.IsAssignableFrom(typeOfValue)) + { return value; + } //needs to be before IsSimpleType if (type.IsEnum) + { try { return Enum.Parse(type, value.ToString()); } catch { } + } // int, doubles, etc if (value.GetType().IsSimpleType()) + { try { return Convert.ChangeType(value, type); @@ -556,6 +608,7 @@ private object ConvertType(Type type, object value, string name) { throw new Exception($"Cannot convert {value.GetType()} to {type}"); } + } if (Converter.CanConvertToSpeckle(value)) { @@ -565,6 +618,7 @@ private object ConvertType(Type type, object value, string name) //to convert the boxed type, it seems the only valid solution is to use Convert.ChangeType //currently, this is to support conversion of Polyline to Polycurve in Objects if (converted.GetType() != type && !type.IsAssignableFrom(converted.GetType())) + { try { return Convert.ChangeType(converted, type); @@ -573,6 +627,7 @@ private object ConvertType(Type type, object value, string name) { throw new Exception($"Cannot convert {converted.GetType()} to {type}"); } + } return converted; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectBase.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectBase.cs index 4d5827df9c..0fbeac8b56 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectBase.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectBase.cs @@ -154,7 +154,9 @@ public override bool Read(GH_IReader reader) SelectedConstructor = CSOUtils.FindConstructor(constructorName, typeName); if (SelectedConstructor == null) + { readFailed = true; + } } catch { @@ -197,10 +199,14 @@ protected override void RegisterOutputParams(GH_OutputParamManager pManager) public override void AddedToDocument(GH_Document document) { if (readFailed) + { return; + } if (!UserSetSchemaTag) + { UseSchemaTag = SpeckleGHSettings.UseSchemaTag; + } if (SelectedConstructor != null) { @@ -214,11 +220,13 @@ public override void AddedToDocument(GH_Document document) foreach (var comp in otherSchemaBuilders) { if (comp is CreateSchemaObject scb) + { if (scb.Seed == Seed) { Seed = GenerateSeed(); break; } + } var baseType = comp.GetType().BaseType; if (typeof(CreateSchemaObjectBase) == baseType) @@ -235,11 +243,16 @@ public override void AddedToDocument(GH_Document document) } if (Params.Input.Count == 0) + { SetupComponent(SelectedConstructor); + } + ((SpeckleBaseParam)Params.Output[0]).UseSchemaTag = UseSchemaTag; #if RHINO7 - if(!Instances.RunningHeadless) + if (!Instances.RunningHeadless) + { (Params.Output[0] as SpeckleBaseParam).ExpirePreview(true); + } #else (Params.Output[0] as SpeckleBaseParam).ExpirePreview(true); #endif @@ -247,7 +260,10 @@ public override void AddedToDocument(GH_Document document) Params.ParameterChanged += (sender, args) => { if (args.ParameterSide != GH_ParameterSide.Input) + { return; + } + switch (args.OriginalArguments.Type) { case GH_ObjectEventType.NickName: @@ -273,7 +289,9 @@ public void SetupComponent(ConstructorInfo constructor) var props = constructor.GetParameters(); foreach (var p in props) + { RegisterPropertyAsInputParameter(p, k++); + } UserInterfaceUtils.CreateCanvasDropdownForAllEnumInputs(this, props); @@ -294,7 +312,9 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) // get property name and value Type propType = param.ParameterType; if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { propType = Nullable.GetUnderlyingType(propType); + } string propName = param.Name; object propValue = param; @@ -304,7 +324,10 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) if (param.IsOptional) { if (!string.IsNullOrEmpty(d)) + { d += ", "; + } + var def = param.DefaultValue == null ? "null" : param.DefaultValue.ToString(); d += "default = " + def; } @@ -319,7 +342,9 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) newInputParam.Description = $"({propType.Name}) {d}"; newInputParam.Optional = param.IsOptional; if (param.IsOptional) + { newInputParam.SetPersistentData(param.DefaultValue); + } // check if input needs to be a list or item access bool isCollection = @@ -327,9 +352,13 @@ private void RegisterPropertyAsInputParameter(ParameterInfo param, int index) && propType != typeof(string) && !propType.Name.ToLower().Contains("dictionary"); if (isCollection) + { newInputParam.Access = GH_ParamAccess.list; + } else + { newInputParam.Access = GH_ParamAccess.item; + } Params.RegisterInputParam(newInputParam, index); } @@ -352,7 +381,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun("Create Schema Object", Name); + } var units = Units.GetUnitsFromString(Loader.GetCurrentDocument().ModelUnitSystem.ToString()); @@ -400,7 +431,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) ?.Where(o => o.AttributeType.IsEquivalentTo(typeof(SchemaMainParam))) ?.Count() > 0 ) + { mainSchemaObj = objectProp; + } } object schemaObject = null; @@ -409,7 +442,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) schemaObject = SelectedConstructor.Invoke(cParamsValues.ToArray()); ((Base)schemaObject).applicationId = $"{Seed}-{SelectedConstructor.DeclaringType.FullName}-{DA.Iteration}"; if (((Base)schemaObject)["units"] == null || ((Base)schemaObject)["units"] == "") + { ((Base)schemaObject)["units"] = units; + } } catch (Exception e) { @@ -434,7 +469,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) commitObj = ((Base)mainSchemaObj).ShallowCopy(); commitObj["@SpeckleSchema"] = schemaObject; if (commitObj["units"] == null || commitObj["units"] == "") + { commitObj["units"] = units; + } } catch (Exception e) { @@ -468,7 +505,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) private object ExtractRealInputValue(object inputValue) { if (inputValue == null) + { return null; + } if (inputValue is IGH_Goo) { @@ -485,12 +524,16 @@ private object ExtractRealInputValue(object inputValue) private object GetObjectListProp(IGH_Param param, List values, Type t) { if (!values.Any()) + { return null; + } var list = (IList)Activator.CreateInstance(t); var listElementType = list.GetType().GetGenericArguments().Single(); foreach (var value in values) + { list.Add(ConvertType(listElementType, value, param.Name)); + } return list; } @@ -504,22 +547,29 @@ private object GetObjectProp(IGH_Param param, object value, Type t) private object ConvertType(Type type, object value, string name) { if (value == null) + { return null; + } var typeOfValue = value.GetType(); if (value == null || typeOfValue == type || type.IsAssignableFrom(typeOfValue)) + { return value; + } //needs to be before IsSimpleType if (type.IsEnum) + { try { return Enum.Parse(type, value.ToString()); } catch { } + } // int, doubles, etc if (value.GetType().IsSimpleType()) + { try { return Convert.ChangeType(value, type); @@ -528,6 +578,7 @@ private object ConvertType(Type type, object value, string name) { throw new Exception($"Cannot convert {value.GetType()} to {type}"); } + } if (Converter.CanConvertToSpeckle(value)) { @@ -537,6 +588,7 @@ private object ConvertType(Type type, object value, string name) //to convert the boxed type, it seems the only valid solution is to use Convert.ChangeType //currently, this is to support conversion of Polyline to Polycurve in Objects if (converted.GetType() != type && !type.IsAssignableFrom(converted.GetType())) + { try { return Convert.ChangeType(converted, type); @@ -545,6 +597,7 @@ private object ConvertType(Type type, object value, string name) { throw new Exception($"Cannot convert {converted.GetType()} to {type}"); } + } return converted; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectDialog.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectDialog.cs index 877e5558b3..9d0f8e8ba2 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectDialog.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObjectDialog.cs @@ -115,7 +115,9 @@ private void RecurseNamespace(string[] ns, Dictionary tree, Type { var key = ns[0]; if (!tree.ContainsKey(ns[0])) + { tree[key] = new Dictionary(); + } if (ns.Length > 1) { @@ -128,10 +130,14 @@ private void RecurseNamespace(string[] ns, Dictionary tree, Type { var constructors = temp.ToDictionary(x => x.GetCustomAttribute().Name, x => (object)x); if (constructors.Values.Count > 1) + { ((Dictionary)tree[key])[t.Name] = constructors; + } else + { //simplify structure if only 1 constructor ((Dictionary)tree[key])[t.Name] = constructors.Values.First(); + } } catch (Exception e) { @@ -143,6 +149,7 @@ private void RecurseNamespace(string[] ns, Dictionary tree, Type private void RecurseTree(Dictionary tree, TreeGridItem item, string ns = "") { foreach (var key in tree.Keys) + { if (tree[key] is ConstructorInfo c) { var child = new TreeGridItem(c.GetCustomAttribute().Name); @@ -158,6 +165,7 @@ private void RecurseTree(Dictionary tree, TreeGridItem item, str RecurseTree(d, child, subNs); item.Children.Add(child); } + } } private void IncreaseCounts(string ns, int constrCount) @@ -167,9 +175,13 @@ private void IncreaseCounts(string ns, int constrCount) { var name = string.Join(".", parts.Take(i + 1)); if (!counts.ContainsKey(name)) + { counts[name] = constrCount; + } else + { counts[name] += constrCount; + } } } @@ -178,9 +190,13 @@ private void IncreaseCounts(string ns, int constrCount) private void Search_TextChanged(object sender, EventArgs e) { if (!string.IsNullOrEmpty(search.Text)) + { typesFiltered = types.Where(x => x.Name.ToLowerInvariant().Contains(search.Text.ToLowerInvariant())).ToList(); + } else + { typesFiltered = types; + } tree.DataStore = GenerateTree(); //list.DataStore = typesFiltered; @@ -189,14 +205,19 @@ private void Search_TextChanged(object sender, EventArgs e) private string GetDescription(TreeGridItem t) { if (t == null || (ConstructorInfo)t.Tag == null) + { return ""; + } + var constructor = (ConstructorInfo)t.Tag; var description = ""; var attr = constructor.GetCustomAttribute(); if (attr != null) + { description += attr.Description + "\n\n"; + } var props = constructor.GetParameters(); if (props.Any()) @@ -208,7 +229,10 @@ private string GetDescription(TreeGridItem t) var d = inputDesc != null ? $": {inputDesc.Description}" : ""; var type = p.ParameterType; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { type = Nullable.GetUnderlyingType(type); + } + description += $"\n- {p.Name} ({type.Name}){d}"; if (p.IsOptional) { diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/SchemaBuilderGen.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/SchemaBuilderGen.cs index 39019673e3..a7ada035e7 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/SchemaBuilderGen.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/SchemaBuilderGen.cs @@ -14,10 +14,16 @@ static AdaptiveComponentSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -60,10 +66,16 @@ static AdvanceSteelBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -106,10 +118,16 @@ static AdvanceSteelCircularBoltSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -152,10 +170,16 @@ static AdvanceSteelPlateSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -198,10 +222,16 @@ static AdvanceSteelRectangularBoltSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -244,10 +274,16 @@ static AdvanceSteelSpecialPartSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -290,10 +326,16 @@ static AngleSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -336,10 +378,16 @@ static ArchicadBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -376,10 +424,16 @@ static ArchicadColumnSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -422,10 +476,16 @@ static AreaSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -462,10 +522,16 @@ static AxisSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -508,10 +574,16 @@ static BeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -548,10 +620,16 @@ static BlockDefinitionSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -588,10 +666,16 @@ static BlockInstanceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -628,10 +712,16 @@ static BraceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -668,10 +758,16 @@ static CatalogueSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -714,10 +810,16 @@ static Catalogue1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -760,10 +862,16 @@ static CeilingSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -800,10 +908,16 @@ static ChannelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -846,10 +960,16 @@ static CircularSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -892,10 +1012,16 @@ static ColumnSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -932,10 +1058,16 @@ static ConcreteSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -978,10 +1110,16 @@ static CSIAreaSpringSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1018,10 +1156,16 @@ static CSIDiaphragmSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1058,10 +1202,16 @@ static CSIElement1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1104,10 +1254,16 @@ static CSIElement1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1150,10 +1306,16 @@ static CSIElement2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1196,10 +1358,16 @@ static CSILinearSpringSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1236,10 +1404,16 @@ static CSILinkPropertySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1276,10 +1450,16 @@ static CSINodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1322,10 +1502,16 @@ static CSIOpeningSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1362,10 +1548,16 @@ static CSISpringPropertySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1408,10 +1600,16 @@ static CSISpringProperty1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1454,10 +1652,16 @@ static DeckFilledSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1494,10 +1698,16 @@ static DeckSlabSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1534,10 +1744,16 @@ static DeckUnFilledSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1574,10 +1790,16 @@ static DetailCurveSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1614,10 +1836,16 @@ static DirectShapeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1660,10 +1888,16 @@ static DuctSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1699,10 +1933,16 @@ static Duct1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1739,10 +1979,16 @@ static Element1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1785,10 +2031,16 @@ static Element1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1831,10 +2083,16 @@ static Element2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1877,10 +2135,16 @@ static Element3DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1917,10 +2181,16 @@ static ExplicitSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -1963,10 +2233,16 @@ static FamilyInstanceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2003,10 +2279,16 @@ static FloorSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2043,10 +2325,16 @@ static FreeformElementSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2089,10 +2377,16 @@ static FreeformElement1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2134,10 +2428,16 @@ static FreeformElement2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2179,10 +2479,16 @@ static GridLineSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2218,10 +2524,16 @@ static GridLine1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2258,10 +2570,16 @@ static GSAAlignmentSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2304,10 +2622,16 @@ static GSAAnalysisCaseSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2350,10 +2674,16 @@ static GSAAssemblySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2396,10 +2726,16 @@ static GSAConcreteSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2442,10 +2778,16 @@ static GSAElement1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2488,10 +2830,16 @@ static GSAElement1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2534,10 +2882,16 @@ static GSAElement2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2580,10 +2934,16 @@ static GSAElement3DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2626,10 +2986,16 @@ static GSAGeneralisedRestraintSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2672,10 +3038,16 @@ static GSAGridLineSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2713,10 +3085,16 @@ static GSAGridPlaneSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2759,10 +3137,16 @@ static GSAGridSurfaceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2805,10 +3189,16 @@ static GSAInfluenceBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2851,10 +3241,16 @@ static GSAInfluenceNodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2897,10 +3293,16 @@ static GSALoadBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2943,10 +3345,16 @@ static GSALoadBeam1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -2989,10 +3397,16 @@ static GSALoadCaseSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3030,10 +3444,16 @@ static GSALoadCombinationSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3076,10 +3496,16 @@ static GSALoadFaceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3122,10 +3548,16 @@ static GSALoadGravitySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3168,10 +3600,16 @@ static GSALoadGravity1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3214,10 +3652,16 @@ static GSALoadGravity2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3260,10 +3704,16 @@ static GSALoadNodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3300,10 +3750,16 @@ static GSALoadNode1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3346,10 +3802,16 @@ static GSAMaterialSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3387,10 +3849,16 @@ static GSAMember1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3433,10 +3901,16 @@ static GSAMember1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3479,10 +3953,16 @@ static GSAMember2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3520,10 +4000,16 @@ static GSANodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3560,10 +4046,16 @@ static GSAPathSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3606,10 +4098,16 @@ static GSAPolylineSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3647,10 +4145,16 @@ static GSAProperty1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3693,10 +4197,16 @@ static GSAProperty2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3739,10 +4249,16 @@ static GSARigidConstraintSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3785,10 +4301,16 @@ static GSAStageSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3826,10 +4348,16 @@ static GSASteelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3872,10 +4400,16 @@ static GSAStoreySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3918,10 +4452,16 @@ static GSATaskSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -3964,10 +4504,16 @@ static GSAUserVehicleSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4010,10 +4556,16 @@ static ISectionSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4056,10 +4608,16 @@ static LevelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4096,10 +4654,16 @@ static LoadBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4142,10 +4706,16 @@ static LoadBeam1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4188,10 +4758,16 @@ static LoadCaseSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4228,10 +4804,16 @@ static LoadCombinationSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4274,10 +4856,16 @@ static LoadFaceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4320,10 +4908,16 @@ static LoadFace1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4366,10 +4960,16 @@ static LoadGravitySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4412,10 +5012,16 @@ static LoadGravity1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4458,10 +5064,16 @@ static LoadGravity2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4504,10 +5116,16 @@ static LoadNodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4544,10 +5162,16 @@ static LoadNode1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4590,10 +5214,16 @@ static MaterialSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4630,10 +5260,16 @@ static MaterialQuantitySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4676,10 +5312,16 @@ static ModelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4716,10 +5358,16 @@ static ModelCurveSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4756,10 +5404,16 @@ static ModelInfoSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4802,10 +5456,16 @@ static ModelSettingsSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4848,10 +5508,16 @@ static ModelUnitsSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4894,10 +5560,16 @@ static ModelUnits1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4940,10 +5612,16 @@ static NodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -4986,10 +5664,16 @@ static OpeningSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5026,10 +5710,16 @@ static ParameterSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5067,10 +5757,16 @@ static ParameterUpdaterSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5113,10 +5809,16 @@ static PerimeterSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5159,10 +5861,16 @@ static PipeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5199,10 +5907,16 @@ static PointcloudSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5239,10 +5953,16 @@ static PropertySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5279,10 +5999,16 @@ static Property1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5325,10 +6051,16 @@ static Property1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5371,10 +6103,16 @@ static Property2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5417,10 +6155,16 @@ static Property2D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5463,10 +6207,16 @@ static Property3DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5509,10 +6259,16 @@ static Property3D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5555,10 +6311,16 @@ static PropertyDamperSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5601,10 +6363,16 @@ static PropertyDamper1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5647,10 +6415,16 @@ static PropertyMassSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5693,10 +6467,16 @@ static PropertyMass1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5739,10 +6519,16 @@ static PropertySpringSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5785,10 +6571,16 @@ static PropertySpring1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5831,10 +6623,16 @@ static PropertySpring2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5877,10 +6675,16 @@ static RectangularSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5923,10 +6727,16 @@ static RenderMaterialSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -5963,10 +6773,16 @@ static RestraintSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6009,10 +6825,16 @@ static Restraint1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6055,10 +6877,16 @@ static Restraint2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6101,10 +6929,16 @@ static Result1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6147,10 +6981,16 @@ static Result1D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6193,10 +7033,16 @@ static Result2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6239,10 +7085,16 @@ static Result2D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6285,10 +7137,16 @@ static Result3DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6331,10 +7189,16 @@ static Result3D1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6377,10 +7241,16 @@ static ResultGlobalSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6423,10 +7293,16 @@ static ResultGlobal1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6469,10 +7345,16 @@ static ResultNodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6515,10 +7397,16 @@ static ResultNode1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6561,10 +7449,16 @@ static ResultSet1DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6607,10 +7501,16 @@ static ResultSet2DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6653,10 +7553,16 @@ static ResultSet3DSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6699,10 +7605,16 @@ static ResultSetAllSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6745,10 +7657,16 @@ static ResultSetNodeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6791,10 +7709,16 @@ static RevitBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6832,10 +7756,16 @@ static RevitBraceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6873,10 +7803,16 @@ static RevitCeilingSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6912,10 +7848,16 @@ static RevitCeiling1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6952,10 +7894,16 @@ static RevitColumnSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -6998,10 +7946,16 @@ static RevitColumn1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7043,10 +7997,16 @@ static RevitColumn2SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7089,10 +8049,16 @@ static RevitDuctSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7128,10 +8094,16 @@ static RevitDuct1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7168,10 +8140,16 @@ static RevitExtrusionRoofSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7214,10 +8192,16 @@ static RevitFaceWallSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7260,10 +8244,16 @@ static RevitFlexDuctSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7300,10 +8290,16 @@ static RevitFlexPipeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7340,10 +8336,16 @@ static RevitFloorSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7381,10 +8383,16 @@ static RevitFootprintRoofSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7427,10 +8435,16 @@ static RevitLevelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7473,10 +8487,16 @@ static RevitLevel1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7519,10 +8539,16 @@ static RevitMaterialSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7559,10 +8585,16 @@ static RevitPipeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7599,10 +8631,16 @@ static RevitProfileWallSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7645,10 +8683,16 @@ static RevitRailingSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7685,10 +8729,16 @@ static RevitShaftSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7731,10 +8781,16 @@ static RevitTopographySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7771,10 +8827,16 @@ static RevitWallSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7817,10 +8879,16 @@ static RevitWall1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7863,10 +8931,16 @@ static RevitWallOpeningSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7908,10 +8982,16 @@ static RevitWallOpening1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7954,10 +9034,16 @@ static RevitWireSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -7994,10 +9080,16 @@ static RibbedSlabSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8034,10 +9126,16 @@ static RoofSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8073,10 +9171,16 @@ static RoomSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8113,10 +9217,16 @@ static Room1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8153,10 +9263,16 @@ static RoomBoundaryLineSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8194,10 +9310,16 @@ static SlabSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8234,10 +9356,16 @@ static SpaceSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8274,10 +9402,16 @@ static Space1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8320,10 +9454,16 @@ static SpaceSeparationLineSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8366,10 +9506,16 @@ static SteelSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8412,10 +9558,16 @@ static StoreySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8458,10 +9610,16 @@ static StructuralMaterialSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8504,10 +9662,16 @@ static StructuralMaterial1SchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8550,10 +9714,16 @@ static TeeSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8591,10 +9761,16 @@ static TeklaBeamSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8631,10 +9807,16 @@ static TeklaContourPlateSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8672,10 +9854,16 @@ static TimberSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8718,10 +9906,16 @@ static TopographySchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8758,10 +9952,16 @@ static WaffleSlabSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8798,10 +9998,16 @@ static WallSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -8838,10 +10044,16 @@ static WireSchemaComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (!args.Key.StartsWith("Speckle2:tabs.")) + { return; + } + var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SpeckleGHSettings.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SpeckleGHSettings.cs index 25090f0135..dfa4691ba5 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SpeckleGHSettings.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SpeckleGHSettings.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using Grasshopper; using Grasshopper.GUI; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamCreateComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamCreateComponent.cs index 8385d669dc..abbaaf9b2b 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamCreateComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamCreateComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; @@ -60,7 +60,9 @@ public override bool Read(GH_IReader reader) public override bool Write(GH_IWriter writer) { if (stream == null) + { return base.Write(writer); + } var serialisedStreamWrapper = $"{stream.StreamId} {stream.ServerUrl} {stream.UserId}"; writer.SetString("stream", serialisedStreamWrapper); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamDetailsComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamDetailsComponent.cs index baca3ccf34..0d4884f3a4 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamDetailsComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamDetailsComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -88,10 +88,14 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (ghStreamTree.DataCount >= 20) + { tooManyItems = true; + } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } Task.Run(async () => { @@ -105,7 +109,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) .ForEach(path => { if (count >= 20) + { return; + } + var branch = ghStreamTree[path]; var itemCount = 0; branch.ForEach(item => diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamGetComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamGetComponent.cs index 0859ae083e..806813b2e0 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamGetComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamGetComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; @@ -64,7 +64,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) GH_SpeckleStream ghIdWrapper = null; DA.DisableGapLogic(); if (!DA.GetData(0, ref ghIdWrapper)) + { return; + } + DA.GetData(1, ref userId); var idWrapper = ghIdWrapper.Value; var account = string.IsNullOrEmpty(userId) @@ -101,7 +104,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } // Run Task.Run(async () => diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamListComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamListComponent.cs index 278deccc46..6e2918679e 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamListComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamListComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -80,7 +80,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) : AccountManager.GetAccounts().FirstOrDefault(a => a.userInfo.id == userId); if (userId == null) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No account was provided, using default."); + } if (account == null) { @@ -135,10 +137,14 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) DA.GetData(1, ref limit); // Has default value so will never be empty. if (limit > 50) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Max number of streams retrieved is 50."); + } if (streams != null) + { DA.SetDataList(0, streams.Select(item => new GH_SpeckleStream(item))); + } streams = null; } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamUpdateComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamUpdateComponent.cs index 59e723d701..3f509ebee5 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamUpdateComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Deprecated/StreamUpdateComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Threading.Tasks; using ConnectorGrasshopper.Extras; @@ -64,7 +64,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) bool isPublic = false; if (!DA.GetData(0, ref ghSpeckleStream)) + { return; + } + DA.GetData(1, ref name); DA.GetData(2, ref description); DA.GetData(3, ref isPublic); @@ -85,7 +88,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) return; } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } + Message = "Fetching"; Task.Run(async () => { @@ -101,7 +107,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) input.description = description ?? stream.description; if (stream.isPublic != isPublic) + { input.isPublic = isPublic; + } await client.StreamUpdate(input); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamCreateComponentV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamCreateComponentV2.cs index 53b442b223..ed305691cc 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamCreateComponentV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamCreateComponentV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Threading.Tasks; using ConnectorGrasshopper.Extras; @@ -54,7 +54,10 @@ public override bool Read(GH_IReader reader) public override bool Write(GH_IWriter writer) { if (stream != null) + { writer.SetString("stream", $"{stream.StreamId} {stream.ServerUrl} {stream.UserId}"); + } + return base.Write(writer); } @@ -66,7 +69,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) { Account account = null; if (!DA.GetData(0, ref account)) + { return; + } + if (account == null) { // Really last ditch effort - in case people delete accounts from the manager, and the selection dropdown is still using an outdated list. diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamDetailsComponentV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamDetailsComponentV2.cs index c8db50d6ca..67901359bc 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamDetailsComponentV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamDetailsComponentV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Threading.Tasks; using ConnectorGrasshopper.Extras; @@ -68,7 +68,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) StreamWrapper sw = null; if (!DA.GetData(0, ref sw)) + { return; + } TaskList.Add( Task.Run(() => @@ -83,7 +85,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (!GetSolveResults(DA, out var stream)) + { return; + } DA.SetData(0, stream.id); DA.SetData(1, stream.name); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetComponentV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetComponentV2.cs index 19b6c47a52..969983d771 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetComponentV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetComponentV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Threading.Tasks; using ConnectorGrasshopper.Extras; @@ -53,21 +53,34 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) Account account = null; GH_SpeckleStream ghIdWrapper = null; if (!DA.GetData(0, ref ghIdWrapper)) + { return; + } + if (!DA.GetData(1, ref account)) + { return; + } + var idWrapper = ghIdWrapper.Value; if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } TaskList.Add(Task.Run(() => AssignAccountToStream(idWrapper, account), CancelToken)); } if (!GetSolveResults(DA, out var data)) + { return; + } + if (data != null) + { DA.SetData(0, new GH_SpeckleStream(data)); + } } private async Task AssignAccountToStream(StreamWrapper idWrapper, Account account) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetWithTokenComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetWithTokenComponent.cs index 95d89dc632..1da4902f9a 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetWithTokenComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamGetWithTokenComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; @@ -25,11 +25,16 @@ public StreamGetWithTokenComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -69,9 +74,14 @@ protected override void SolveInstance(IGH_DataAccess DA) GH_SpeckleStream ssp = null; string token = null; if (!DA.GetData(0, ref ssp)) + { return; + } + if (!DA.GetData(1, ref token)) + { return; + } var sw = ssp.Value; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamListComponentV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamListComponentV2.cs index fa7ab5dcea..d9d905578c 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamListComponentV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamListComponentV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -44,7 +44,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) if (InPreSolve) { if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } Account account = null; var limit = 10; @@ -81,7 +83,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (!GetSolveResults(DA, out var data)) + { return; + } DA.SetDataList(0, data.Select(item => new GH_SpeckleStream(item))); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamUpdateComponentV2.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamUpdateComponentV2.cs index f661ec984e..d57a15550f 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamUpdateComponentV2.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/StreamUpdateComponentV2.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Threading.Tasks; using ConnectorGrasshopper.Extras; @@ -57,7 +57,10 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) bool? isPublic = null; if (!DA.GetData(0, ref ghSpeckleStream)) + { return; + } + DA.GetData(1, ref name); DA.GetData(2, ref description); DA.GetData(3, ref isPublic); @@ -71,13 +74,17 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } TaskList.Add(Task.Run(() => UpdateStream(streamWrapper, name, description, isPublic), CancelToken)); } if (!GetSolveResults(DA, out var success)) + { return; + } DA.SetData(0, success); } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Upgraders/V2Upgraders.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Upgraders/V2Upgraders.cs index d72636dd68..2b96b41867 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Upgraders/V2Upgraders.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Streams/Upgraders/V2Upgraders.cs @@ -1,4 +1,4 @@ -using System; +using System; using ConnectorGrasshopper.Extras; using ConnectorGrasshopper.UpgradeUtilities; using Grasshopper.Kernel; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/SendReceiveTransport.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/SendReceiveTransport.cs index 3810d17466..e93c90c33a 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/SendReceiveTransport.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/SendReceiveTransport.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -20,11 +20,16 @@ static SendReceiveTransport() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -93,10 +98,17 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var freshTransports = new List(); foreach (var tr in transports) + { if (tr is ICloneable cloneable) + { freshTransports.Add(cloneable.Clone() as ITransport); + } else + { freshTransports.Add(tr); + } + } + transports = freshTransports; var res = Task.Run(async () => await Operations.Send(obj.Value, transports, false, disposeTransports: true)).Result; @@ -111,11 +123,16 @@ static ReceiveFromTransport() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -172,10 +189,14 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) var transport = transportGoo.GetType().GetProperty("Value").GetValue(transportGoo) as ITransport; if (transport == null) + { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Transport is null."); + } if (transport is ICloneable disposedTwin) + { transport = disposedTwin.Clone() as ITransport; + } List results = new(); foreach (var id in ids) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Disk.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Disk.cs index 04a9d269ac..a24a21686e 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Disk.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Disk.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using ConnectorGrasshopper.Properties; @@ -14,11 +14,16 @@ static DiskTransportComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -71,7 +76,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } string basePath = null; DA.GetData(0, ref basePath); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Memory.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Memory.cs index 4b44d9e700..4938e0a065 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Memory.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Memory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.Linq; using ConnectorGrasshopper.Properties; @@ -15,11 +15,16 @@ static MemoryTransportComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == internalGuid); if (proxy == null) + { return; + } + proxy.Exposure = internalExposure; }; } @@ -67,7 +72,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } string name = null; DA.GetData(0, ref name); diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Sqlite.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Sqlite.cs index d4806d920b..c66a704070 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Sqlite.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Transports/Transports.Sqlite.cs @@ -23,11 +23,16 @@ public SqliteTransportComponent() SpeckleGHSettings.SettingsChanged += (_, args) => { if (args.Key != SpeckleGHSettings.SHOW_DEV_COMPONENTS) + { return; + } var proxy = Instances.ComponentServer.ObjectProxies.FirstOrDefault(p => p.Guid == ComponentGuid); if (proxy == null) + { return; + } + proxy.Exposure = Exposure; }; } @@ -90,7 +95,9 @@ public override void SolveInstanceWithLogContext(IGH_DataAccess DA) } if (DA.Iteration == 0) + { Tracker.TrackNodeRun(); + } string basePath = null, applicationName = null, diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/UpgradeUtilities.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/UpgradeUtilities.cs index 209ccbdba9..a57f43add3 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/UpgradeUtilities.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/UpgradeUtilities.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Grasshopper.Kernel; using Grasshopper.Kernel.Special; diff --git a/ConnectorGrasshopper/ConnectorGrasshopperUtils/CSOUtils.cs b/ConnectorGrasshopper/ConnectorGrasshopperUtils/CSOUtils.cs index ff3ba08a1e..4af0b6fe38 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperUtils/CSOUtils.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperUtils/CSOUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -29,7 +29,9 @@ public static ConstructorInfo FindConstructor(string ConstructorName, string Typ { var type = KitManager.Types.FirstOrDefault(x => x.FullName == TypeName); if (type == null) + { return null; + } var constructors = GetValidConstr(type); var constructor = constructors.FirstOrDefault(x => MethodFullName(x) == ConstructorName); @@ -40,10 +42,13 @@ public static string MethodFullName(MethodBase m) { var s = m.ReflectedType.FullName; if (!m.IsConstructor) + { s += "."; + } s += m.Name; if (m.GetParameters().Any()) + { //jamie rainfall bug, had to replace + with . s += "(" @@ -52,6 +57,8 @@ public static string MethodFullName(MethodBase m) m.GetParameters().Select(o => string.Format("{0}", o.ParameterType).Replace("+", ".")).ToArray() ) + ")"; + } + return s; } } diff --git a/ConnectorGrasshopper/ConnectorGrasshopperUtils/UserInterfaceUtils.cs b/ConnectorGrasshopper/ConnectorGrasshopperUtils/UserInterfaceUtils.cs index 0b36ef3b55..3df45670dc 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperUtils/UserInterfaceUtils.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperUtils/UserInterfaceUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.File.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.File.cs index 658d6e44bf..ac131b6d84 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.File.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.File.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using DesktopUI2.Models; using Speckle.ConnectorNavisworks.Storage; @@ -24,7 +24,10 @@ public override List GetStreamsInFile() { var streams = new List(); if (_doc != null) + { streams = SpeckleStreamManager.ReadState(_doc); + } + return streams; } @@ -42,9 +45,13 @@ public override string GetFileName() private static void IsFileAndModelsPresent() { if (_doc == null) + { throw (new FileNotFoundException("No active document found. Cannot Send.")); + } if (_doc.Models.Count == 0) + { throw (new FileNotFoundException("No models are appended. Nothing to Send.")); + } } } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Filters.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Filters.cs index 4e239776f4..ab6e72f268 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Filters.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Filters.cs @@ -24,7 +24,9 @@ public override List GetSelectionFilters() var manualFilter = new ManualSelectionFilter(); if (_doc == null) + { return filters; + } filters.Add(manualFilter); @@ -76,7 +78,7 @@ public override List GetSelectionFilters() // // if (groupedClashResults.Count >= 0) // { - // + // // // var clashReportFilter = new TreeSelectionFilter // { @@ -104,11 +106,15 @@ private static TreeNode GetSets(SavedItem savedItem) }; if (!savedItem.IsGroup) + { return treeNode; + } //iterate the children and output foreach (var childItem in ((GroupItem)savedItem).Children) + { treeNode.Elements.Add(GetSets(childItem)); + } return treeNode.Elements.Count > 0 ? treeNode : null; } @@ -150,15 +156,21 @@ private static TreeNode GetViews(SavedItem savedItem) private static TreeNode RemoveNullNodes(TreeNode node) { if (node == null) + { return null; + } if (!node.Elements.Any()) + { return node; + } var elements = node.Elements.Select(RemoveNullNodes).Where(childNode => childNode != null).ToList(); if (!elements.Any()) + { return null; + } node.Elements = elements; return node; @@ -177,7 +189,9 @@ private static TreeNode GetClashTestResults(SavedItem savedItem) //iterate the children and output only grouped clashes foreach (var result in clashTest.Children) + { if (result.IsGroup) + { treeNode.Elements.Add( new TreeNode { @@ -186,6 +200,8 @@ private static TreeNode GetClashTestResults(SavedItem savedItem) IndexWith = nameof(TreeNode.Guid) } ); + } + } return treeNode.Elements.Count > 0 ? treeNode : null; } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Receive.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Receive.cs index 923c6b0ba5..e5926c099d 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Receive.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Receive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; using DesktopUI2.Models; diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Send.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Send.cs index 4b5883fd3b..206d4806e5 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Send.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Send.cs @@ -110,13 +110,17 @@ public override async Task SendStream(StreamState state, ProgressViewMod { commitObject = _cachedCommit as Collection; if (commitObject != null) + { commitObject.elements = CachedConvertedElements; + } } var objectId = await SendConvertedObjectsToSpeckle(state, commitObject).ConfigureAwait(false); if (_progressViewModel.Report.OperationErrors.Any()) + { ConnectorHelpers.DefaultSendErrorHandler("", _progressViewModel.Report.OperationErrors.Last()); + } _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); @@ -159,9 +163,14 @@ private void InitializeManagerOptionsForSend(StreamState state) var internalPropertyNames = state.Settings.Find(x => x.Slug == "internal-property-names"); if (internalPropertySettings != null && ((CheckBoxSetting)internalPropertySettings).IsChecked) + { _settingsHandler.ShowInternalProperties(); + } + if (internalPropertyNames != null && ((CheckBoxSetting)internalPropertyNames).IsChecked) + { _settingsHandler.UseInternalPropertyNames(); + } } /// @@ -171,16 +180,24 @@ private void InitializeManagerOptionsForSend(StreamState state) private void ValidateBeforeSending(StreamState state) { if (_progressViewModel == null) + { throw new ArgumentException("No ProgressViewModel provided."); + } if (_doc.ActiveSheet == null) + { throw new InvalidOperationException("Your Document is empty. Nothing to Send."); + } if (state.Filter == null) + { throw new InvalidOperationException("No filter provided. Nothing to Send."); + } if (state.Filter.Slug == "all" || state.CommitMessage == "Sent everything") + { throw new InvalidOperationException("Everything Mode is not yet implemented. Send stopped."); + } } /// @@ -226,7 +243,9 @@ IReadOnlyList modelItemsToConvert for (int index = 0; index < modelItemsToConvert.Count; index++) { if (_progressBar.IsCanceled) + { _progressViewModel.CancellationTokenSource.Cancel(); + } _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); @@ -236,7 +255,9 @@ IReadOnlyList modelItemsToConvert conversions.Add(element, new Tuple(Constants.ConversionState.ToConvert, null)); if (index % objectInterval == 0 || index == modelItemsToConvert.Count - 1) + { _progressBar.Update((index + 1) * objectIncrement); + } } _progressBar.EndSubOperation(); @@ -333,8 +354,10 @@ private void HandleProgress(ConcurrentDictionary progressDict) { // If the "RemoteTransport" key exists in the dictionary and has a positive value if (progressDict.TryGetValue("RemoteTransport", out var rc) && rc > 0) + { // Update the progress bar proportionally to the remote conversion count _progressBar.Update(Math.Min((double)rc / 2 / _convertedCount, 1.0)); + } // Update the progress view model with the progress dictionary _progressViewModel.Update(progressDict); @@ -443,9 +466,11 @@ private List GetModelItemsForConversion(StreamState state) // Check if any items have been selected if (selectionBuilder.Count == 0) + { throw new InvalidOperationException( "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." ); + } try { @@ -459,9 +484,11 @@ private List GetModelItemsForConversion(StreamState state) modelItemsToConvert.AddRange(selectionBuilder.ModelItems); if (!modelItemsToConvert.Any()) + { throw new InvalidOperationException( "Zero objects visible for conversion; send stopped. Please select some objects, or check that your filter can actually select something." ); + } return modelItemsToConvert; } @@ -511,7 +538,9 @@ private void ConvertViews(StreamState state, DynamicBase commitObject) } if (views.Any()) + { commitObject["views"] = views; + } } /// @@ -534,7 +563,9 @@ private void ConvertViews(StreamState state, DynamicBase commitObject) for (var i = 0; i < conversions.Count; i++) { if (_progressBar.IsCanceled) + { _progressViewModel.CancellationTokenSource.Cancel(); + } _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); @@ -595,7 +626,9 @@ private void ConvertViews(StreamState state, DynamicBase commitObject) _progressViewModel.Report.Log(reportObject); if (i % conversionInterval != 0 && i != conversions.Count) + { continue; + } double progress = (i + 1) * conversionIncrement; _progressBar.Update(progress); diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Settings.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Settings.cs index 012fe5bab0..bc572766b7 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Settings.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.Settings.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Autodesk.Navisworks.Api; using DesktopUI2.Models.Settings; diff --git a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.cs b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.cs index d6a16087bf..12f6d257cf 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Bindings/ConnectorNavisworksBindings.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -78,8 +78,6 @@ public override string GetHostAppNameVersion() return HostAppNameVersion; } - - private static string GetDocPath() { return ""; @@ -118,10 +116,14 @@ public override List GetObjectsInView() // this returns all visible doc public async Task RetryLastConversionSend() { if (_doc == null) + { return; + } if (CachedConvertedElements == null || _cachedCommit == null) + { throw new SpeckleException("Cant retry last conversion: no cached conversion or commit found."); + } if (_cachedCommit is Collection commitObject) { @@ -134,14 +136,16 @@ public async Task RetryLastConversionSend() commitObject.elements = CachedConvertedElements; var state = _cachedState; - + _progressBar.BeginSubOperation(0.7, "Retrying cached conversion."); _progressBar.EndSubOperation(); - + var objectId = await SendConvertedObjectsToSpeckle(state, commitObject).ConfigureAwait(false); if (_progressViewModel.Report.OperationErrors.Any()) + { ConnectorHelpers.DefaultSendErrorHandler("", _progressViewModel.Report.OperationErrors.Last()); + } _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); @@ -162,7 +166,9 @@ public async Task RetryLastConversionSend() state.Settings.RemoveAll(x => x.Slug == "retrying"); if (string.IsNullOrEmpty(commitId)) + { return; + } } // nullify the cached conversion and commit on success. diff --git a/ConnectorNavisworks/ConnectorNavisworks/Entry/Commands.cs b/ConnectorNavisworks/ConnectorNavisworks/Entry/Commands.cs index 1de605cf3c..8536eb190a 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Entry/Commands.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Entry/Commands.cs @@ -1,4 +1,4 @@ -namespace Speckle.ConnectorNavisworks.Entry; +namespace Speckle.ConnectorNavisworks.Entry; public abstract class LaunchSpeckleConnector { diff --git a/ConnectorNavisworks/ConnectorNavisworks/Entry/Ribbon.xaml.cs b/ConnectorNavisworks/ConnectorNavisworks/Entry/Ribbon.xaml.cs index 68e1df183f..940b5f9dcc 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Entry/Ribbon.xaml.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Entry/Ribbon.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; @@ -70,7 +70,6 @@ internal sealed class RibbonHandler : CommandHandlerPlugin /// The state of the command. public override CommandState CanExecuteCommand(string commandId) { - return commandId switch { TurnPersistCacheOn.Command @@ -109,13 +108,20 @@ public override CommandState CanExecuteCommand(string commandId) private static void LoadPlugin(string plugin, bool notAutomatedCheck = true, string command = "") { if (ShouldSkipLoad(notAutomatedCheck)) + { return; + } + if (ShouldSkipPluginLoad(plugin, command)) + { return; + } var pluginRecord = NavisworksApp.Plugins.FindPlugin(plugin + ".Speckle"); if (pluginRecord is null) + { return; + } var loadedPlugin = pluginRecord.LoadedPlugin ?? pluginRecord.LoadPlugin(); @@ -229,6 +235,7 @@ public override int ExecuteCommand(string commandId, params string[] parameters) LoadedPlugins.TryGetValue(retryPlugin, out var loaded); if (loaded) + { try { var speckleCommand = retryPlugin as SpeckleNavisworksCommandPlugin; @@ -243,6 +250,7 @@ public override int ExecuteCommand(string commandId, params string[] parameters) { MessageBox.Show(ex.Message); } + } break; } @@ -259,7 +267,9 @@ public override int ExecuteCommand(string commandId, params string[] parameters) ConnectorBindingsNavisworks.PersistCache = !ConnectorBindingsNavisworks.PersistCache; if (ConnectorBindingsNavisworks.PersistCache == false) + { ConnectorBindingsNavisworks.CachedConvertedElements = null; + } break; } @@ -282,7 +292,9 @@ private static void ShowPluginInfoMessageBox() { var sb = new StringBuilder(); foreach (var pr in NavisworksApp.Plugins.PluginRecords) + { sb.AppendLine(pr.Name + ": " + pr.DisplayName + ", " + pr.Id); + } MessageBox.Show(sb.ToString()); } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleHostPane.xaml.cs b/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleHostPane.xaml.cs index 6e42d5f85f..24e6459b16 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleHostPane.xaml.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleHostPane.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using Autodesk.Navisworks.Api; using DesktopUI2.Views; @@ -30,7 +30,10 @@ private void Application_DocumentChanged(object sender, EventArgs e) private static IntPtr AvaloniaHost_MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg != WmGetDlgCode) + { return IntPtr.Zero; + } + handled = true; return new IntPtr(DlgcWantChars | DlgcWantarrows | DlgcHasSetSel); } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleNavisworksCommand.cs b/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleNavisworksCommand.cs index cc7e29d5df..dcea266677 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleNavisworksCommand.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Entry/SpeckleNavisworksCommand.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; using System.Windows.Forms; @@ -65,7 +65,9 @@ public override Control CreateControlPane() public override void DestroyControlPane(Control pane) { if (pane is UserControl control) + { control.Dispose(); + } } private static AppBuilder BuildAvaloniaApp() @@ -102,7 +104,9 @@ private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) var assemblyFile = Path.Combine(path ?? string.Empty, name + ".dll"); if (File.Exists(assemblyFile)) + { a = Assembly.LoadFrom(assemblyFile); + } return a; } diff --git a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Autosave.cs b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Autosave.cs index 96174c24e1..7d5d89d80f 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Autosave.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Autosave.cs @@ -1,4 +1,4 @@ -using Autodesk.Navisworks.Api.Interop; +using Autodesk.Navisworks.Api.Interop; using static Autodesk.Navisworks.Api.Interop.LcOpRegistry; using static Autodesk.Navisworks.Api.Interop.LcUOption; @@ -27,7 +27,7 @@ private void UpdateAutoSaveSetting(bool enable) case false when currentSetting == false: _autosaveSetting = false; return; - // Autosave was turned on at the time that the send operation was started + // Autosave was turned on at the time that the send operation was started case false: _autosaveSetting = true; rootOptions.SetBoolean("general.autosave.enable", false); diff --git a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Manager.cs b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Manager.cs index 740655eb7b..efeea8898b 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Manager.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Manager.cs @@ -1,4 +1,4 @@ -using Autodesk.Navisworks.Api.Interop; +using Autodesk.Navisworks.Api.Interop; using static Autodesk.Navisworks.Api.Interop.LcOpRegistry; using static Autodesk.Navisworks.Api.Interop.LcUOption; diff --git a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Properties.cs b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Properties.cs index c020a38bda..ee077c9aec 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Properties.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/NavisworksOptions/Properties.cs @@ -1,4 +1,4 @@ -using Autodesk.Navisworks.Api.Interop; +using Autodesk.Navisworks.Api.Interop; using static Autodesk.Navisworks.Api.Interop.LcOpRegistry; using static Autodesk.Navisworks.Api.Interop.LcUOption; @@ -25,7 +25,9 @@ private void UpdateOptionSetting(string optionName, ref bool optionSetting, bool var currentSetting = rootOptions.GetBoolean(optionName); if (currentSetting == enable) + { return; + } optionSetting = currentSetting; diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/Constants.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/Constants.cs index b21ecebe89..b28815df5a 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/Constants.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/Constants.cs @@ -1,4 +1,4 @@ -namespace Speckle.ConnectorNavisworks.Other; +namespace Speckle.ConnectorNavisworks.Other; public static class Constants { diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/Elements.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/Elements.cs index 72d9ae99e7..b3653cea84 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/Elements.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/Elements.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -65,7 +65,9 @@ public Element GetElement(ModelItem modelItem) private string GetPseudoId(ModelItem modelItem) { if (PseudoId != null) + { return PseudoId; + } var arrayData = ((Array)ComApiBridge.ToInwOaPath(modelItem).ArrayData).ToArray(); PseudoId = @@ -82,10 +84,14 @@ private string GetPseudoId(ModelItem modelItem) private ModelItem Resolve() { if (_modelItem != null) + { return _modelItem; + } if (PseudoId == Constants.RootNodePseudoId) + { return Application.ActiveDocument.Models.RootItems.First; + } if (PseudoId != null) { @@ -122,7 +128,9 @@ private int[] ParsePseudoIdToPathArray(string pseudoId) .Select(x => { if (int.TryParse(x, out var value)) + { return value; + } throw new ArgumentException("malformed path pseudoId"); }) @@ -210,14 +218,18 @@ StreamState streamState var type = baseNode?.GetType().Name; if (baseNode == null) + { continue; + } // Geometry Nodes can add all the properties to the FirstObject classification - this will help with the selection logic if ( streamState.Settings.Find(x => x.Slug == "coalesce-data") is CheckBoxSetting { IsChecked: true } && type == "GeometryNode" ) + { AddPropertyStackToGeometryNode(converted, modelItem, baseNode); + } string[] parts = pseudoId.Split('-'); string parentKey = string.Join("-", parts.Take(parts.Length - 1)); @@ -225,7 +237,9 @@ StreamState streamState lookupDictionary.Add(pseudoId, baseNode); if (!lookupDictionary.ContainsKey(parentKey)) + { potentialRootNodes.Add(pseudoId, baseNode); + } } // Second pass: Attach child nodes to their parents, and confirm root nodes @@ -238,12 +252,17 @@ StreamState streamState string parentKey = string.Join("-", parts.Take(parts.Length - 1)); if (!lookupDictionary.TryGetValue(parentKey, out Base value1)) + { continue; + } + if (value1 is Collection parent) { parent.elements ??= new List(); if (value != null) + { parent.elements.Add(value); + } } // This node has a parent, so it's not a root node @@ -253,7 +272,9 @@ StreamState streamState List rootNodes = potentialRootNodes.Values.ToList(); foreach (var rootNode in rootNodes.Where(rootNode => rootNode != null)) + { PruneEmptyCollections(rootNode); + } rootNodes.RemoveAll(node => node is Collection { elements: null }); @@ -369,9 +390,14 @@ DynamicBase baseNode private static void PruneEmptyCollections(IDynamicMetaObjectProvider node) { if (node is not Collection collection) + { return; + } + if (collection.elements == null) + { return; + } for (int i = collection.elements.Count - 1; i >= 0; i--) { @@ -381,10 +407,14 @@ private static void PruneEmptyCollections(IDynamicMetaObjectProvider node) collection.elements[i] is Collection childCollection && (childCollection.elements == null || childCollection.elements.Count == 0) ) + { collection.elements.RemoveAt(i); + } } if (collection.elements.Count == 0) + { collection.elements = null; + } } } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/FilterTypes.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/FilterTypes.cs index 27ddac88a8..4743276e1a 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/FilterTypes.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/FilterTypes.cs @@ -1,4 +1,4 @@ -namespace Speckle.ConnectorNavisworks.Other; +namespace Speckle.ConnectorNavisworks.Other; internal static class FilterTypes { diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/Invokers.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/Invokers.cs index feca8e13cc..25983c8239 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/Invokers.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/Invokers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Windows.Forms; using Autodesk.Navisworks.Api; @@ -28,7 +28,9 @@ internal object Invoke(Delegate method, params object[] args) private static object InvokeOnUIThreadWithException(Control control, Delegate method, object[] args) { if (control == null) + { return null; + } object result = null; @@ -88,7 +90,7 @@ internal void BeginSubOperation(double fractionOfRemainingTime, string message = /// internal void EndSubOperation() { - Update(1.0); + Update(1.0); Invoke(new Action(_progressBar.EndSubOperation)); } @@ -123,7 +125,9 @@ internal void Update(double fractionDone) public void Cancel() { if (!_progressBar.IsDisposed) + { Invoke(new Action(_progressBar.Cancel), null); + } } } diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/SelectionBuilder.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/SelectionBuilder.cs index c8b4764df7..ef0805b1de 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/SelectionBuilder.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/SelectionBuilder.cs @@ -107,7 +107,9 @@ private IEnumerable GetObjectsFromSavedViewpoint() // Get the selection from the filter var selection = _filter.Selection.FirstOrDefault(); if (string.IsNullOrEmpty(selection)) + { return Enumerable.Empty(); + } // Resolve the saved viewpoint based on the selection // Makes the view active on the main thread. @@ -120,7 +122,9 @@ private IEnumerable GetObjectsFromSavedViewpoint() { var savedViewpoint = ResolveSavedViewpoint(selection); if (savedViewpoint != null && !savedViewpoint.ContainsVisibilityOverrides) + { return; + } Application.ActiveDocument.SavedViewpoints.CurrentSavedViewpoint = savedViewpoint; success = true; @@ -129,7 +133,9 @@ private IEnumerable GetObjectsFromSavedViewpoint() ); if (!success) + { return Enumerable.Empty(); + } var models = Application.ActiveDocument.Models; Application.ActiveDocument.CurrentSelection.Clear(); @@ -139,7 +145,9 @@ private IEnumerable GetObjectsFromSavedViewpoint() var model = models.ElementAt(i); var rootItem = model.RootItem; if (!rootItem.IsHidden) + { _uniqueModelItems.Add(rootItem); + } ProgressBar.Update(i + 1 / (double)models.Count); } @@ -171,13 +179,20 @@ public SavedViewpoint ResolveSavedViewpoint(string savedViewReference) ); if (viewPointMatch != null) + { return ResolveSavedViewpointMatch(savedViewReference); + } + { foreach (var node in flattenedViewpointList) { if (node.Guid.ToString() != savedViewReference) + { if (node.Reference != savedViewReference) + { continue; + } + } viewPointMatch = node; break; @@ -197,9 +212,13 @@ public SavedViewpoint ResolveSavedViewpoint(string savedViewReference) private SavedViewpoint ResolveSavedViewpointMatch(string savedViewReference) { if (Guid.TryParse(savedViewReference, out var guid)) + { // Even though we may have already got a match, that could be to a generic Guid from earlier versions of Navisworks if (savedViewReference != Guid.Empty.ToString()) + { return (SavedViewpoint)Application.ActiveDocument.SavedViewpoints.ResolveGuid(guid); + } + } var savedRef = new SavedItemReference("LcOpSavedViewsElement", savedViewReference); @@ -266,10 +285,16 @@ private IEnumerable GetObjectsFromSavedSets() var savedItems = selections.Select(Application.ActiveDocument.SelectionSets.ResolveGuid).OfType(); foreach (var item in savedItems) + { if (item.HasExplicitModelItems) + { _uniqueModelItems.AddRange(item.ExplicitModelItems); + } else if (item.HasSearch) + { _uniqueModelItems.AddRange(item.Search.FindAll(Application.ActiveDocument, false)); + } + } return _uniqueModelItems; } @@ -281,7 +306,9 @@ private IEnumerable GetObjectsFromSavedSets() public void PopulateHierarchyAndOmitHidden() { if (_uniqueModelItems == null || !_uniqueModelItems.Any()) + { return; + } var startNodes = _uniqueModelItems.ToList(); @@ -301,7 +328,9 @@ public void PopulateHierarchyAndOmitHidden() || Equals(e, firstObjectAncestor) || _uniqueModelItems.Contains(firstObjectAncestor) ) + { return Enumerable.Empty(); + } var trimmedAncestors = targetFirstObjectChild.Ancestors .TakeWhile(ancestor => ancestor != firstObjectAncestor) @@ -337,7 +366,10 @@ public void PopulateHierarchyAndOmitHidden() ProgressBar.BeginSubOperation(0.1, "Validating descendants..."); foreach (var node in startNodes) + { TraverseDescendants(node, allDescendants); + } + ProgressBar.EndSubOperation(); } @@ -358,13 +390,19 @@ private void TraverseDescendants(ModelItem startNode, int totalDescendants) while (stack.Count > 0) { if (ProgressBar.IsCanceled) + { _progressViewModel.CancellationTokenSource.Cancel(); + } + _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); ModelItem currentNode = stack.Pop(); if (_visited.Contains(currentNode)) + { continue; + } + _visited.Add(currentNode); if (currentNode.IsHidden) @@ -379,14 +417,21 @@ private void TraverseDescendants(ModelItem startNode, int totalDescendants) } if (currentNode.Children.Any()) + { foreach (var child in currentNode.Children.Where(e => !e.IsHidden)) + { stack.Push(child); + } + } _uniqueModelItems.AddRange(validDescendants); int currentPercentile = (int)(_descendantProgress / descendantInterval); if (currentPercentile <= lastPercentile) + { continue; + } + double progress = _descendantProgress / (double)totalDescendants; ProgressBar.Update(progress); lastPercentile = currentPercentile; @@ -415,16 +460,23 @@ private void ProgressLooper( for (int i = 0; i < totalCount; i++) { if (ProgressBar.IsCanceled) + { _progressViewModel.CancellationTokenSource.Cancel(); + } + _progressViewModel.CancellationToken.ThrowIfCancellationRequested(); bool shouldContinue = fn(i); if (!shouldContinue) + { break; + } if (i % updateInterval != 0 && i != totalCount) + { continue; + } double progress = (i + 1) * increment; ProgressBar.Update(progress); diff --git a/ConnectorNavisworks/ConnectorNavisworks/Other/Utilities.cs b/ConnectorNavisworks/ConnectorNavisworks/Other/Utilities.cs index 295da6f0b9..730c405cbe 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Other/Utilities.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Other/Utilities.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.CompilerServices; using Autodesk.Navisworks.Api; using Speckle.Core.Kits; diff --git a/ConnectorNavisworks/ConnectorNavisworks/Storage/SpeckleStreamManager.cs b/ConnectorNavisworks/ConnectorNavisworks/Storage/SpeckleStreamManager.cs index e6805b28cb..deb4376943 100644 --- a/ConnectorNavisworks/ConnectorNavisworks/Storage/SpeckleStreamManager.cs +++ b/ConnectorNavisworks/ConnectorNavisworks/Storage/SpeckleStreamManager.cs @@ -18,11 +18,19 @@ public static List ReadState(Document doc) { var streams = new List(); if (doc == null) + { return streams; + } + if (doc.Database == null) + { return streams; + } + if (doc.ActiveSheet == null) + { return streams; + } var database = doc.Database; @@ -33,6 +41,7 @@ public static List ReadState(Document doc) database.Value ) ) + { try { dataAdapter.Fill(table); @@ -41,6 +50,7 @@ public static List ReadState(Document doc) { WarnLog("We didn't find the speckle data store. That's ok - we'll make one later"); } + } if (table.Rows.Count <= 0) { @@ -73,7 +83,9 @@ public static List ReadState(Document doc) int inserted = command.ExecuteNonQuery(); if (inserted > 0) + { ConsoleLog("Stream state stored."); + } transaction.Commit(); } @@ -88,19 +100,26 @@ public static List ReadState(Document doc) var speckleStreamsStore = row["value"]; if (speckleStreamsStore == null) + { return streams; + } + try { streams = JsonConvert.DeserializeObject>((string)speckleStreamsStore); if (streams == null || streams.Count <= 0) + { ErrorLog( "Something isn't right. " + $"{KeyName} was found but didn't deserialize into any streams:" + $"\n {speckleStreamsStore}" ); + } else + { ConsoleLog($"{streams.Count} saved streams found in file."); + } } catch (JsonException ex) { @@ -115,9 +134,14 @@ internal static void WriteStreamStateList(Document doc, List stream var documentDatabase = doc?.Database; if (documentDatabase == null) + { return; + } + if (doc.ActiveSheet == null) + { return; + } string streamStatesStore = JsonConvert.SerializeObject(streamStates); @@ -151,7 +175,10 @@ internal static void WriteStreamStateList(Document doc, List stream int inserted = command.ExecuteNonQuery(); if (inserted > 0) + { ConsoleLog($"{streamStates.Count} stream states stored."); + } + transaction.Commit(); } catch (SqlException ex) diff --git a/ConnectorRevit/ConnectorRevit/ConnectorRevitUtils.cs b/ConnectorRevit/ConnectorRevit/ConnectorRevitUtils.cs index e4a3afb632..14ff934f33 100644 --- a/ConnectorRevit/ConnectorRevit/ConnectorRevitUtils.cs +++ b/ConnectorRevit/ConnectorRevit/ConnectorRevitUtils.cs @@ -9,235 +9,228 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Speckle.ConnectorRevit +namespace Speckle.ConnectorRevit; + +public static class ConnectorRevitUtils { - public static class ConnectorRevitUtils - { #if REVIT2024 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2024); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2024); #elif REVIT2023 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2023); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2023); #elif REVIT2022 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2022); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2022); #elif REVIT2021 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2021); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2021); #elif REVIT2020 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2020); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2020); #elif REVIT2019 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2019); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2019); #endif - private static List _cachedViews = null; - private static List _cachedScheduleViews = null; - public static List ConversionErrors { get; set; } + private static List _cachedViews = null; + private static List _cachedScheduleViews = null; + public static List ConversionErrors { get; set; } - public static List GetFilters(Autodesk.Revit.DB.Document doc) - { - return new FilteredElementCollector(doc) - .OfClass(typeof(ParameterFilterElement)) - .OfType() - .OrderBy(x => x.Name) - .ToList(); - } + public static List GetFilters(Autodesk.Revit.DB.Document doc) + { + return new FilteredElementCollector(doc) + .OfClass(typeof(ParameterFilterElement)) + .OfType() + .OrderBy(x => x.Name) + .ToList(); + } - /// - /// We want to display a user-friendly category names when grouping objects - /// For this we are simplifying the BuiltIn one as otherwise, by using the display value, we'd be getting localized category names - /// which would make querying etc more difficult - /// TODO: deprecate this in favour of model collections - /// - /// - /// - public static string GetEnglishCategoryName(Category category) - { - var builtInCategory = (BuiltInCategory)category.Id.IntegerValue; - var builtInCategoryName = builtInCategory - .ToString() - .Replace("OST_IOS", "") //for OST_IOSModelGroups - .Replace("OST_MEP", "") //for OST_MEPSpaces - .Replace("OST_", "") //for any other OST_blablabla - .Replace("_", " "); - builtInCategoryName = Regex.Replace(builtInCategoryName, "([a-z])([A-Z])", "$1 $2", RegexOptions.Compiled).Trim(); - return builtInCategoryName; - } + /// + /// We want to display a user-friendly category names when grouping objects + /// For this we are simplifying the BuiltIn one as otherwise, by using the display value, we'd be getting localized category names + /// which would make querying etc more difficult + /// TODO: deprecate this in favour of model collections + /// + /// + /// + public static string GetEnglishCategoryName(Category category) + { + var builtInCategory = (BuiltInCategory)category.Id.IntegerValue; + var builtInCategoryName = builtInCategory + .ToString() + .Replace("OST_IOS", "") //for OST_IOSModelGroups + .Replace("OST_MEP", "") //for OST_MEPSpaces + .Replace("OST_", "") //for any other OST_blablabla + .Replace("_", " "); + builtInCategoryName = Regex.Replace(builtInCategoryName, "([a-z])([A-Z])", "$1 $2", RegexOptions.Compiled).Trim(); + return builtInCategoryName; + } - #region extension methods + #region extension methods - public static List GetSupportedElements(this Document doc, IRevitDocumentAggregateCache cache) - { - //get elements of supported categories - var categoryIds = cache - .GetOrInitializeWithDefaultFactory() - .GetAllObjects() - .Select(category => category.Id) - .ToList(); - - using var categoryFilter = new ElementMulticategoryFilter(categoryIds); - using var collector = new FilteredElementCollector(doc); - - var elements = collector - .WhereElementIsNotElementType() - .WhereElementIsViewIndependent() - .WherePasses(categoryFilter) - .ToList(); - - return elements; - } + public static List GetSupportedElements(this Document doc, IRevitDocumentAggregateCache cache) + { + //get elements of supported categories + var categoryIds = cache + .GetOrInitializeWithDefaultFactory() + .GetAllObjects() + .Select(category => category.Id) + .ToList(); + + using var categoryFilter = new ElementMulticategoryFilter(categoryIds); + using var collector = new FilteredElementCollector(doc); + + var elements = collector + .WhereElementIsNotElementType() + .WhereElementIsViewIndependent() + .WherePasses(categoryFilter) + .ToList(); + + return elements; + } - public static List GetSupportedTypes(this Document doc, IRevitDocumentAggregateCache cache) - { - //get element types of supported categories - var categoryIds = cache - .GetOrInitializeWithDefaultFactory() - .GetAllObjects() - .Select(category => category.Id) - .ToList(); - - using var categoryFilter = new ElementMulticategoryFilter(categoryIds); - using var collector = new FilteredElementCollector(doc); - - var elements = collector - .WhereElementIsElementType() - .WherePasses(categoryFilter) - .ToList(); - - return elements; - } + public static List GetSupportedTypes(this Document doc, IRevitDocumentAggregateCache cache) + { + //get element types of supported categories + var categoryIds = cache + .GetOrInitializeWithDefaultFactory() + .GetAllObjects() + .Select(category => category.Id) + .ToList(); - public static List Views2D(this Document doc) - { - List views = new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .OfCategory(BuiltInCategory.OST_Views) - .Cast() - .Where( - x => - x.ViewType == ViewType.CeilingPlan - || x.ViewType == ViewType.FloorPlan - || x.ViewType == ViewType.Elevation - || x.ViewType == ViewType.Section - ) - .ToList(); - - return views; - } + using var categoryFilter = new ElementMulticategoryFilter(categoryIds); + using var collector = new FilteredElementCollector(doc); - public static List Views3D(this Document doc) - { - List views = new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .OfCategory(BuiltInCategory.OST_Views) - .Cast() - .Where(x => x.ViewType == ViewType.ThreeD) - .ToList(); - - return views; - } + var elements = collector.WhereElementIsElementType().WherePasses(categoryFilter).ToList(); - public static List Levels(this Document doc) - { - List levels = new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .OfCategory(BuiltInCategory.OST_Levels) - .ToList(); + return elements; + } - return levels; - } + public static List Views2D(this Document doc) + { + List views = new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .OfCategory(BuiltInCategory.OST_Views) + .Cast() + .Where( + x => + x.ViewType == ViewType.CeilingPlan + || x.ViewType == ViewType.FloorPlan + || x.ViewType == ViewType.Elevation + || x.ViewType == ViewType.Section + ) + .ToList(); + + return views; + } - #endregion + public static List Views3D(this Document doc) + { + List views = new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .OfCategory(BuiltInCategory.OST_Views) + .Cast() + .Where(x => x.ViewType == ViewType.ThreeD) + .ToList(); + + return views; + } - public static List GetViewFilterNames(Document doc) - { - return GetFilters(doc).Select(x => x.Name).ToList(); - } + public static List Levels(this Document doc) + { + List levels = new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .OfCategory(BuiltInCategory.OST_Levels) + .ToList(); - public static List GetWorksets(Document doc) - { - return new FilteredWorksetCollector(doc) - .Where(x => x.Kind == WorksetKind.UserWorkset) - .Select(x => x.Name) - .ToList(); - } + return levels; + } - private static async Task> GetViewNamesAsync(Document doc) - { - using var scheduleExclusionFilter = new ElementClassFilter(typeof(ViewSchedule), true); - var els = new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .OfClass(typeof(View)) - .WherePasses(scheduleExclusionFilter) - .Cast() - .Where(x => !x.IsTemplate) - .ToList(); - _cachedViews = els.Select(x => x.Title).OrderBy(x => x).ToList(); - return _cachedViews; - } + #endregion - private static bool IsViewRevisionSchedule(string input) - { - string pattern = @"<.+>(\s*\d+)?"; - Regex rgx = new Regex(pattern); - return rgx.IsMatch(input); - } + public static List GetViewFilterNames(Document doc) + { + return GetFilters(doc).Select(x => x.Name).ToList(); + } - private static async Task> GetScheduleNamesAsync(Document doc) - { - var els = new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .OfClass(typeof(ViewSchedule)) - .Where(view => !IsViewRevisionSchedule(view.Name)) - .ToList(); + public static List GetWorksets(Document doc) + { + return new FilteredWorksetCollector(doc).Where(x => x.Kind == WorksetKind.UserWorkset).Select(x => x.Name).ToList(); + } - _cachedScheduleViews = els.Select(x => x.Name).OrderBy(x => x).ToList(); - return _cachedScheduleViews; - } + private static async Task> GetViewNamesAsync(Document doc) + { + using var scheduleExclusionFilter = new ElementClassFilter(typeof(ViewSchedule), true); + var els = new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .OfClass(typeof(View)) + .WherePasses(scheduleExclusionFilter) + .Cast() + .Where(x => !x.IsTemplate) + .ToList(); + _cachedViews = els.Select(x => x.Title).OrderBy(x => x).ToList(); + return _cachedViews; + } - /// - /// Each time it's called the cached parameters are return, and a new copy is cached - /// - /// - /// - public static List GetViewNames(Document doc) - { - if (_cachedViews != null) - { - //don't wait for it to finish - GetViewNamesAsync(doc); - return _cachedViews; - } - - return GetViewNamesAsync(doc).Result; - } + private static bool IsViewRevisionSchedule(string input) + { + string pattern = @"<.+>(\s*\d+)?"; + Regex rgx = new(pattern); + return rgx.IsMatch(input); + } - public static List GetScheduleNames(Document doc) - { - if (_cachedScheduleViews != null) - { - //don't wait for it to finish - GetScheduleNamesAsync(doc); - return _cachedScheduleViews; - } - - return GetScheduleNamesAsync(doc).Result; - } + private static async Task> GetScheduleNamesAsync(Document doc) + { + var els = new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .OfClass(typeof(ViewSchedule)) + .Where(view => !IsViewRevisionSchedule(view.Name)) + .ToList(); + + _cachedScheduleViews = els.Select(x => x.Name).OrderBy(x => x).ToList(); + return _cachedScheduleViews; + } - /// - /// Removes all inherited classes from speckle type string - /// - /// - /// - public static string SimplifySpeckleType(string type) + /// + /// Each time it's called the cached parameters are return, and a new copy is cached + /// + /// + /// + public static List GetViewNames(Document doc) + { + if (_cachedViews != null) { - return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + //don't wait for it to finish + GetViewNamesAsync(doc); + return _cachedViews; } - public static string ObjectDescriptor(Element obj) + return GetViewNamesAsync(doc).Result; + } + + public static List GetScheduleNames(Document doc) + { + if (_cachedScheduleViews != null) { - var simpleType = obj.GetType() - .ToString() - .Split(new string[] { "DB." }, StringSplitOptions.RemoveEmptyEntries) - .LastOrDefault(); - return string.IsNullOrEmpty(obj.Name) ? $"{simpleType}" : $"{simpleType} {obj.Name}"; + //don't wait for it to finish + GetScheduleNamesAsync(doc); + return _cachedScheduleViews; } + + return GetScheduleNamesAsync(doc).Result; + } + + /// + /// Removes all inherited classes from speckle type string + /// + /// + /// + public static string SimplifySpeckleType(string type) + { + return type.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + } + + public static string ObjectDescriptor(Element obj) + { + var simpleType = obj.GetType() + .ToString() + .Split(new string[] { "DB." }, StringSplitOptions.RemoveEmptyEntries) + .LastOrDefault(); + return string.IsNullOrEmpty(obj.Name) ? $"{simpleType}" : $"{simpleType} {obj.Name}"; } } diff --git a/ConnectorRevit/ConnectorRevit/Entry/App.cs b/ConnectorRevit/ConnectorRevit/Entry/App.cs index 31354f2e05..9b8c8a9a7e 100644 --- a/ConnectorRevit/ConnectorRevit/Entry/App.cs +++ b/ConnectorRevit/ConnectorRevit/Entry/App.cs @@ -14,238 +14,235 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Speckle.ConnectorRevit.Entry -{ - public class App : IExternalApplication - { - public static UIApplication AppInstance { get; set; } +namespace Speckle.ConnectorRevit.Entry; - public static UIControlledApplication UICtrlApp { get; set; } +public class App : IExternalApplication +{ + public static UIApplication AppInstance { get; set; } - public Result OnStartup(UIControlledApplication application) - { - //Always initialize RevitTask ahead of time within Revit API context - APIContext.Initialize(application); + public static UIControlledApplication UICtrlApp { get; set; } - UICtrlApp = application; - UICtrlApp.ControlledApplication.ApplicationInitialized += ControlledApplication_ApplicationInitialized; - string tabName = "Speckle"; + public Result OnStartup(UIControlledApplication application) + { + //Always initialize RevitTask ahead of time within Revit API context + APIContext.Initialize(application); - try - { - application.CreateRibbonTab(tabName); - } - catch { } + UICtrlApp = application; + UICtrlApp.ControlledApplication.ApplicationInitialized += ControlledApplication_ApplicationInitialized; + string tabName = "Speckle"; - var specklePanel = application.CreateRibbonPanel(tabName, "Speckle 2"); + try + { + application.CreateRibbonTab(tabName); + } + catch { } - string path = typeof(App).Assembly.Location; + var specklePanel = application.CreateRibbonPanel(tabName, "Speckle 2"); - //desktopui 2 - var speckleButton2 = - specklePanel.AddItem( - new PushButtonData( - "Speckle 2", - "Revit Connector", - typeof(App).Assembly.Location, - typeof(SpeckleRevitCommand).FullName - ) - ) as PushButton; + string path = typeof(App).Assembly.Location; - if (speckleButton2 != null) - { - speckleButton2.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo16.png", path); - speckleButton2.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); - speckleButton2.ToolTipImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); - speckleButton2.ToolTip = "Speckle Connector for Revit"; - speckleButton2.AvailabilityClassName = typeof(CmdAvailabilityViews).FullName; - speckleButton2.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, "https://speckle.systems")); - } + //desktopui 2 + var speckleButton2 = + specklePanel.AddItem( + new PushButtonData( + "Speckle 2", + "Revit Connector", + typeof(App).Assembly.Location, + typeof(SpeckleRevitCommand).FullName + ) + ) as PushButton; - var schedulerButton = - specklePanel.AddItem( - new PushButtonData("Scheduler", "Scheduler", typeof(App).Assembly.Location, typeof(SchedulerCommand).FullName) - ) as PushButton; + if (speckleButton2 != null) + { + speckleButton2.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo16.png", path); + speckleButton2.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); + speckleButton2.ToolTipImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); + speckleButton2.ToolTip = "Speckle Connector for Revit"; + speckleButton2.AvailabilityClassName = typeof(CmdAvailabilityViews).FullName; + speckleButton2.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, "https://speckle.systems")); + } - if (schedulerButton != null) - { - schedulerButton.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler16.png", path); - schedulerButton.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler32.png", path); - schedulerButton.ToolTipImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler32.png", path); - schedulerButton.ToolTip = "Scheduler for the Revit Connector"; - schedulerButton.AvailabilityClassName = typeof(CmdAvailabilityViews).FullName; - schedulerButton.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, "https://speckle.systems")); - } + var schedulerButton = + specklePanel.AddItem( + new PushButtonData("Scheduler", "Scheduler", typeof(App).Assembly.Location, typeof(SchedulerCommand).FullName) + ) as PushButton; - PulldownButton helpPulldown = - specklePanel.AddItem(new PulldownButtonData("Help&Resources", "Help & Resources")) as PulldownButton; - helpPulldown.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.help16.png", path); - helpPulldown.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.help32.png", path); - - PushButton forum = - helpPulldown.AddPushButton( - new PushButtonData("forum", "Community Forum", typeof(App).Assembly.Location, typeof(ForumCommand).FullName) - ) as PushButton; - forum.ToolTip = "Check out our Community Forum! Opens a page in your web browser."; - forum.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.forum16.png", path); - forum.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.forum32.png", path); - - PushButton tutorials = - helpPulldown.AddPushButton( - new PushButtonData("tutorials", "Tutorials", typeof(App).Assembly.Location, typeof(TutorialsCommand).FullName) - ) as PushButton; - tutorials.ToolTip = "Check out our tutorials! Opens a page in your web browser."; - tutorials.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.tutorials16.png", path); - tutorials.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.tutorials32.png", path); - - PushButton docs = - helpPulldown.AddPushButton( - new PushButtonData("docs", "Docs", typeof(App).Assembly.Location, typeof(DocsCommand).FullName) - ) as PushButton; - docs.ToolTip = "Check out our documentation! Opens a page in your web browser."; - docs.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.docs16.png", path); - docs.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.docs32.png", path); - - PushButton manager = - helpPulldown.AddPushButton( - new PushButtonData("manager", "Manager", typeof(App).Assembly.Location, typeof(ManagerCommand).FullName) - ) as PushButton; - manager.ToolTip = "Manage accounts and connectors. Opens SpeckleManager."; - manager.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo16.png", path); - manager.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); - - return Result.Succeeded; + if (schedulerButton != null) + { + schedulerButton.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler16.png", path); + schedulerButton.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler32.png", path); + schedulerButton.ToolTipImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.scheduler32.png", path); + schedulerButton.ToolTip = "Scheduler for the Revit Connector"; + schedulerButton.AvailabilityClassName = typeof(CmdAvailabilityViews).FullName; + schedulerButton.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, "https://speckle.systems")); } - private void ControlledApplication_ApplicationInitialized( - object sender, - Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e - ) + PulldownButton helpPulldown = + specklePanel.AddItem(new PulldownButtonData("Help&Resources", "Help & Resources")) as PulldownButton; + helpPulldown.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.help16.png", path); + helpPulldown.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.help32.png", path); + + PushButton forum = + helpPulldown.AddPushButton( + new PushButtonData("forum", "Community Forum", typeof(App).Assembly.Location, typeof(ForumCommand).FullName) + ) as PushButton; + forum.ToolTip = "Check out our Community Forum! Opens a page in your web browser."; + forum.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.forum16.png", path); + forum.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.forum32.png", path); + + PushButton tutorials = + helpPulldown.AddPushButton( + new PushButtonData("tutorials", "Tutorials", typeof(App).Assembly.Location, typeof(TutorialsCommand).FullName) + ) as PushButton; + tutorials.ToolTip = "Check out our tutorials! Opens a page in your web browser."; + tutorials.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.tutorials16.png", path); + tutorials.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.tutorials32.png", path); + + PushButton docs = + helpPulldown.AddPushButton( + new PushButtonData("docs", "Docs", typeof(App).Assembly.Location, typeof(DocsCommand).FullName) + ) as PushButton; + docs.ToolTip = "Check out our documentation! Opens a page in your web browser."; + docs.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.docs16.png", path); + docs.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.docs32.png", path); + + PushButton manager = + helpPulldown.AddPushButton( + new PushButtonData("manager", "Manager", typeof(App).Assembly.Location, typeof(ManagerCommand).FullName) + ) as PushButton; + manager.ToolTip = "Manage accounts and connectors. Opens SpeckleManager."; + manager.Image = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo16.png", path); + manager.LargeImage = LoadPngImgSource("Speckle.ConnectorRevit.Assets.logo32.png", path); + + return Result.Succeeded; + } + + private void ControlledApplication_ApplicationInitialized( + object sender, + Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e + ) + { + try { - try - { - // We need to hook into the AssemblyResolve event before doing anything else - // or we'll run into unresolved issues loading dependencies - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - System.Windows.Forms.Application.ThreadException += Application_ThreadException; + // We need to hook into the AssemblyResolve event before doing anything else + // or we'll run into unresolved issues loading dependencies + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + System.Windows.Forms.Application.ThreadException += Application_ThreadException; - AppInstance = new UIApplication(sender as Application); + AppInstance = new UIApplication(sender as Application); - Setup.Init(ConnectorBindingsRevit.HostAppNameVersion, ConnectorBindingsRevit.HostAppName); + Setup.Init(ConnectorBindingsRevit.HostAppNameVersion, ConnectorBindingsRevit.HostAppName); - //DUI2 - pre build app, so that it's faster to open up - SpeckleRevitCommand.InitAvalonia(); - var bindings = new ConnectorBindingsRevit(AppInstance); - bindings.RegisterAppEvents(); - SpeckleRevitCommand.Bindings = bindings; - SchedulerCommand.Bindings = bindings; + //DUI2 - pre build app, so that it's faster to open up + SpeckleRevitCommand.InitAvalonia(); + var bindings = new ConnectorBindingsRevit(AppInstance); + bindings.RegisterAppEvents(); + SpeckleRevitCommand.Bindings = bindings; + SchedulerCommand.Bindings = bindings; - BatchUploaderClient client = new(new Uri("http://localhost:5001")); - RevitApplicationController revitAppController = new(AppInstance); - BatchUploadOperationDriver batchUploadOperationDriver = new(client, revitAppController, bindings); + BatchUploaderClient client = new(new Uri("http://localhost:5001")); + RevitApplicationController revitAppController = new(AppInstance); + BatchUploadOperationDriver batchUploadOperationDriver = new(client, revitAppController, bindings); - batchUploadOperationDriver.ProcessAllJobs(); + batchUploadOperationDriver.ProcessAllJobs(); - //This is also called in DUI, adding it here to know how often the connector is loaded and used - Analytics.TrackEvent(Analytics.Events.Registered, null, false); + //This is also called in DUI, adding it here to know how often the connector is loaded and used + Analytics.TrackEvent(Analytics.Events.Registered, null, false); - SpeckleRevitCommand.RegisterPane(); + SpeckleRevitCommand.RegisterPane(); - //AppInstance.ViewActivated += new EventHandler(Application_ViewActivated); + //AppInstance.ViewActivated += new EventHandler(Application_ViewActivated); + } + catch (Exception ex) + { + SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle app"); + var td = new TaskDialog("Error loading Speckle"); + if (ex is KitException) + { + td.MainContent = ex.Message; } - catch (Exception ex) + else + { + td.MainContent = + $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n\n{ex.Message}"; + } + + td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Ask for help on our Community Forum"); + + TaskDialogResult tResult = td.Show(); + + if (TaskDialogResult.CommandLink1 == tResult) { - SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle app"); - var td = new TaskDialog("Error loading Speckle"); - if (ex is KitException) - { - td.MainContent = ex.Message; - } - else - { - td.MainContent = - $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n\n{ex.Message}"; - } - - td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Ask for help on our Community Forum"); - - TaskDialogResult tResult = td.Show(); - - if (TaskDialogResult.CommandLink1 == tResult) - { - Process.Start("https://speckle.community/"); - } + Process.Start("https://speckle.community/"); } } + } - private void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) + private void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) + { + SpeckleLog.Logger.Fatal( + e.Exception, + "Caught thread exception with message {exceptionMessage}", + e.Exception.Message + ); + } + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception ex) { SpeckleLog.Logger.Fatal( - e.Exception, - "Caught thread exception with message {exceptionMessage}", - e.Exception.Message + ex, + "Caught unhandled exception. Is terminating : {isTerminating}. Message : {exceptionMessage}", + e.IsTerminating, + ex.Message ); } - - private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + else { - if (e.ExceptionObject is Exception ex) - { - SpeckleLog.Logger.Fatal( - ex, - "Caught unhandled exception. Is terminating : {isTerminating}. Message : {exceptionMessage}", - e.IsTerminating, - ex.Message - ); - } - else - { - SpeckleLog.Logger.Fatal( - "Caught unhandled exception. Is terminating : {isTerminating}. Exception object is of type : {exceptionObjectType}. Exception object to string : {exceptionObjToString}", - e.IsTerminating, - e.ExceptionObject.GetType(), - e.ExceptionObject.ToString() - ); - } + SpeckleLog.Logger.Fatal( + "Caught unhandled exception. Is terminating : {isTerminating}. Exception object is of type : {exceptionObjectType}. Exception object to string : {exceptionObjToString}", + e.IsTerminating, + e.ExceptionObject.GetType(), + e.ExceptionObject.ToString() + ); } + } - public Result OnShutdown(UIControlledApplication application) - { - return Result.Succeeded; - } + public Result OnShutdown(UIControlledApplication application) + { + return Result.Succeeded; + } - private ImageSource LoadPngImgSource(string sourceName, string path) + private ImageSource LoadPngImgSource(string sourceName, string path) + { + try { - try - { - var assembly = Assembly.LoadFrom(Path.Combine(path)); - var icon = assembly.GetManifestResourceStream(sourceName); - PngBitmapDecoder m_decoder = new PngBitmapDecoder( - icon, - BitmapCreateOptions.PreservePixelFormat, - BitmapCacheOption.Default - ); - ImageSource m_source = m_decoder.Frames[0]; - return (m_source); - } - catch { } - - return null; + var assembly = Assembly.LoadFrom(Path.Combine(path)); + var icon = assembly.GetManifestResourceStream(sourceName); + PngBitmapDecoder m_decoder = new(icon, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); + ImageSource m_source = m_decoder.Frames[0]; + return (m_source); } + catch { } - static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) - { - Assembly a = null; - var name = args.Name.Split(',')[0]; - string path = Path.GetDirectoryName(typeof(App).Assembly.Location); + return null; + } - string assemblyFile = Path.Combine(path, name + ".dll"); + static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly a = null; + var name = args.Name.Split(',')[0]; + string path = Path.GetDirectoryName(typeof(App).Assembly.Location); - if (File.Exists(assemblyFile)) - a = Assembly.LoadFrom(assemblyFile); + string assemblyFile = Path.Combine(path, name + ".dll"); - return a; + if (File.Exists(assemblyFile)) + { + a = Assembly.LoadFrom(assemblyFile); } + + return a; } } diff --git a/ConnectorRevit/ConnectorRevit/Entry/CmdAvailabilityViews.cs b/ConnectorRevit/ConnectorRevit/Entry/CmdAvailabilityViews.cs index a3595de75f..1a8f3bf85f 100644 --- a/ConnectorRevit/ConnectorRevit/Entry/CmdAvailabilityViews.cs +++ b/ConnectorRevit/ConnectorRevit/Entry/CmdAvailabilityViews.cs @@ -1,20 +1,18 @@ -using Autodesk.Revit.DB; +using Autodesk.Revit.DB; using Autodesk.Revit.UI; -namespace Speckle.ConnectorRevit +namespace Speckle.ConnectorRevit; + +internal class CmdAvailabilityViews : IExternalCommandAvailability { - internal class CmdAvailabilityViews : IExternalCommandAvailability + /// + /// Command Availability - Views + /// + /// + /// + /// + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) { - - /// - /// Command Availability - Views - /// - /// - /// - /// - public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) - { - return applicationData?.ActiveUIDocument?.Document?.IsValidObject ?? false; - } + return applicationData?.ActiveUIDocument?.Document?.IsValidObject ?? false; } } diff --git a/ConnectorRevit/ConnectorRevit/Entry/HelpCommand.cs b/ConnectorRevit/ConnectorRevit/Entry/HelpCommand.cs index 69d4a170c3..6c1cdcf8c6 100644 --- a/ConnectorRevit/ConnectorRevit/Entry/HelpCommand.cs +++ b/ConnectorRevit/ConnectorRevit/Entry/HelpCommand.cs @@ -1,71 +1,77 @@ -using System; +using System; using System.Diagnostics; using System.IO; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI; -namespace Speckle.ConnectorRevit.Entry +namespace Speckle.ConnectorRevit.Entry; + +[Transaction(TransactionMode.Manual)] +public class ForumCommand : IExternalCommand { - [Transaction(TransactionMode.Manual)] - public class ForumCommand : IExternalCommand + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - Process.Start("https://speckle.community/"); - return Result.Succeeded; - } + Process.Start("https://speckle.community/"); + return Result.Succeeded; } - [Transaction(TransactionMode.Manual)] - public class DocsCommand : IExternalCommand +} + +[Transaction(TransactionMode.Manual)] +public class DocsCommand : IExternalCommand +{ + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - Process.Start("https://speckle.guide/user/revit.html"); - return Result.Succeeded; - } + Process.Start("https://speckle.guide/user/revit.html"); + return Result.Succeeded; } - [Transaction(TransactionMode.Manual)] - public class TutorialsCommand : IExternalCommand +} + +[Transaction(TransactionMode.Manual)] +public class TutorialsCommand : IExternalCommand +{ + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - Process.Start("https://speckle.systems/tutorials/"); - return Result.Succeeded; - } + Process.Start("https://speckle.systems/tutorials/"); + return Result.Succeeded; } +} - [Transaction(TransactionMode.Manual)] - public class ManagerCommand : IExternalCommand +[Transaction(TransactionMode.Manual)] +public class ManagerCommand : IExternalCommand +{ + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + var path = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "Speckle", + "Manager", + "Manager.exe" + ); + if (File.Exists(path)) { - var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Speckle", "Manager", "Manager.exe"); - if (File.Exists(path)) - Process.Start(path); - - else - TaskDialog.Show("No Manager found", "Seems like Manager is not installed on this pc."); - return Result.Succeeded; + Process.Start(path); + } + else + { + TaskDialog.Show("No Manager found", "Seems like Manager is not installed on this pc."); } + + return Result.Succeeded; } +} - [Transaction(TransactionMode.Manual)] - public class NewRibbonCommand : IExternalCommand +[Transaction(TransactionMode.Manual)] +public class NewRibbonCommand : IExternalCommand +{ + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - TaskDialog mainDialog = new TaskDialog("Speckle has moved!"); - mainDialog.MainInstruction = "Speckle has moved!"; - mainDialog.MainContent = - "The Speckle Connector for Revit has moved to its own Tab named 'Speckle' 👉"; - mainDialog.FooterText = - "" - + "Feedback?"; + TaskDialog mainDialog = new("Speckle has moved!"); + mainDialog.MainInstruction = "Speckle has moved!"; + mainDialog.MainContent = "The Speckle Connector for Revit has moved to its own Tab named 'Speckle' 👉"; + mainDialog.FooterText = "" + "Feedback?"; - mainDialog.Show(); - return Result.Succeeded; - } + mainDialog.Show(); + return Result.Succeeded; } - } diff --git a/ConnectorRevit/ConnectorRevit/Entry/SchedulerCommand.cs b/ConnectorRevit/ConnectorRevit/Entry/SchedulerCommand.cs index 288c248d47..f521f5811e 100644 --- a/ConnectorRevit/ConnectorRevit/Entry/SchedulerCommand.cs +++ b/ConnectorRevit/ConnectorRevit/Entry/SchedulerCommand.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Autodesk.Revit.Attributes; @@ -8,41 +8,40 @@ using DesktopUI2.Views; using Speckle.ConnectorRevit.UI; -namespace Speckle.ConnectorRevit.Entry +namespace Speckle.ConnectorRevit.Entry; + +[Transaction(TransactionMode.Manual)] +public class SchedulerCommand : IExternalCommand { - [Transaction(TransactionMode.Manual)] - public class SchedulerCommand : IExternalCommand - { - [DllImport("user32.dll", SetLastError = true)] - [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] - static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); + [DllImport("user32.dll", SetLastError = true)] + [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] + static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); - const int GWL_HWNDPARENT = -8; + const int GWL_HWNDPARENT = -8; - internal static UIApplication uiapp; + internal static UIApplication uiapp; - public static ConnectorBindingsRevit Bindings { get; set; } + public static ConnectorBindingsRevit Bindings { get; set; } - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) - { - uiapp = commandData.Application; - CreateOrFocusSpeckle(); + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + uiapp = commandData.Application; + CreateOrFocusSpeckle(); - return Result.Succeeded; - } + return Result.Succeeded; + } - public static void CreateOrFocusSpeckle() - { - var scheduler = new Scheduler { DataContext = new SchedulerViewModel(Bindings) }; + public static void CreateOrFocusSpeckle() + { + var scheduler = new Scheduler { DataContext = new SchedulerViewModel(Bindings) }; - scheduler.Show(); + scheduler.Show(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var parentHwnd = uiapp.MainWindowHandle; - var hwnd = scheduler.PlatformImpl.Handle.Handle; - SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var parentHwnd = uiapp.MainWindowHandle; + var hwnd = scheduler.PlatformImpl.Handle.Handle; + SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); } } } diff --git a/ConnectorRevit/ConnectorRevit/Entry/SpeckleRevitCommand.cs b/ConnectorRevit/ConnectorRevit/Entry/SpeckleRevitCommand.cs index bc3391d094..e7324e18d7 100644 --- a/ConnectorRevit/ConnectorRevit/Entry/SpeckleRevitCommand.cs +++ b/ConnectorRevit/ConnectorRevit/Entry/SpeckleRevitCommand.cs @@ -14,180 +14,182 @@ using Speckle.ConnectorRevit.UI; using Speckle.Core.Logging; -namespace Speckle.ConnectorRevit.Entry +namespace Speckle.ConnectorRevit.Entry; + +[Transaction(TransactionMode.Manual)] +public class SpeckleRevitCommand : IExternalCommand { - [Transaction(TransactionMode.Manual)] - public class SpeckleRevitCommand : IExternalCommand - { - public static bool UseDockablePanel = true; + public static bool UseDockablePanel = true; + + //window stuff + [DllImport("user32.dll", SetLastError = true)] + [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] + static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); + + const int GWL_HWNDPARENT = -8; + public static Window MainWindow { get; private set; } + private static Avalonia.Application AvaloniaApp { get; set; } - //window stuff - [DllImport("user32.dll", SetLastError = true)] - [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] - static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); + //end window stuff - const int GWL_HWNDPARENT = -8; - public static Window MainWindow { get; private set; } - private static Avalonia.Application AvaloniaApp { get; set; } + public static ConnectorBindingsRevit Bindings { get; set; } - //end window stuff + private static Panel _panel { get; set; } - public static ConnectorBindingsRevit Bindings { get; set; } + internal static DockablePaneId PanelId = new(new Guid("{0A866FB8-8FD5-4DE8-B24B-56F4FA5B0836}")); - private static Panel _panel { get; set; } + public static void InitAvalonia() + { + BuildAvaloniaApp().SetupWithoutStarting(); + } - internal static DockablePaneId PanelId = new DockablePaneId(new Guid("{0A866FB8-8FD5-4DE8-B24B-56F4FA5B0836}")); + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() + .UsePlatformDetect() + .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) + .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) + .LogToTrace() + .UseReactiveUI(); - public static void InitAvalonia() + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + if (UseDockablePanel) + { + try + { + RegisterPane(); + var panel = App.AppInstance.GetDockablePane(PanelId); + panel.Show(); + } + catch (Exception ex) + { + SpeckleLog.Logger.Error(ex, "Failed to show dockable panel"); + } + } + else { - BuildAvaloniaApp().SetupWithoutStarting(); + CreateOrFocusSpeckle(); } - public static AppBuilder BuildAvaloniaApp() => - AppBuilder - .Configure() - .UsePlatformDetect() - .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) - .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) - .LogToTrace() - .UseReactiveUI(); + return Result.Succeeded; + } - public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + internal static void RegisterPane() + { + try { - if (UseDockablePanel) + if (!UseDockablePanel) { - try - { - RegisterPane(); - var panel = App.AppInstance.GetDockablePane(PanelId); - panel.Show(); - } - catch (Exception ex) - { - SpeckleLog.Logger.Error(ex, "Failed to show dockable panel"); - } + return; } - else - CreateOrFocusSpeckle(); - return Result.Succeeded; - } + var registered = DockablePane.PaneIsRegistered(PanelId); + var created = DockablePane.PaneExists(PanelId); - internal static void RegisterPane() - { - try + if (registered && created) { - if (!UseDockablePanel) - return; + _panel.Init(); + return; + } - var registered = DockablePane.PaneIsRegistered(PanelId); - var created = DockablePane.PaneExists(PanelId); + if (!registered) + { + //Register dockable panel + var viewModel = new MainViewModel(Bindings); + _panel = new Panel { DataContext = viewModel }; + App.AppInstance.RegisterDockablePane(PanelId, "Speckle", _panel); + _panel.Init(); + } + created = DockablePane.PaneExists(PanelId); - if (registered && created) - { - _panel.Init(); - return; - } + //if revit was launched double-clicking on a Revit file, we're screwed + //could maybe show the old window? + if (!created && App.AppInstance.Application.Documents.Size > 0) + { + TaskDialog mainDialog = new("Dockable Panel Issue"); + mainDialog.MainInstruction = "Dockable Panel Issue"; + mainDialog.MainContent = + "Revit cannot properly register Dockable Panels when launched by double-clicking a Revit file. " + + "Please close and re-open Revit without launching a file OR open/create a new project to trigger the Speckle panel registration."; - if (!registered) - { - //Register dockable panel - var viewModel = new MainViewModel(Bindings); - _panel = new Panel { DataContext = viewModel }; - App.AppInstance.RegisterDockablePane(PanelId, "Speckle", _panel); - _panel.Init(); - } - created = DockablePane.PaneExists(PanelId); + // Set footer text. Footer text is usually used to link to the help document. + mainDialog.FooterText = + "" + "Click here for more info"; - //if revit was launched double-clicking on a Revit file, we're screwed - //could maybe show the old window? - if (!created && App.AppInstance.Application.Documents.Size > 0) - { - TaskDialog mainDialog = new TaskDialog("Dockable Panel Issue"); - mainDialog.MainInstruction = "Dockable Panel Issue"; - mainDialog.MainContent = - "Revit cannot properly register Dockable Panels when launched by double-clicking a Revit file. " - + "Please close and re-open Revit without launching a file OR open/create a new project to trigger the Speckle panel registration."; - - // Set footer text. Footer text is usually used to link to the help document. - mainDialog.FooterText = - "" - + "Click here for more info"; - - mainDialog.Show(); - } + mainDialog.Show(); } - catch (Exception ex) - { - SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle command for host app"); - var td = new TaskDialog("Error"); - td.MainContent = - $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}"; - td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum"); + } + catch (Exception ex) + { + SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle command for host app"); + var td = new TaskDialog("Error"); + td.MainContent = + $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}"; + td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum"); - TaskDialogResult tResult = td.Show(); + TaskDialogResult tResult = td.Show(); - if (TaskDialogResult.CommandLink1 == tResult) - { - Process.Start("https://speckle.community/"); - } + if (TaskDialogResult.CommandLink1 == tResult) + { + Process.Start("https://speckle.community/"); } } + } - public static void CreateOrFocusSpeckle(bool showWindow = true) + public static void CreateOrFocusSpeckle(bool showWindow = true) + { + try { - try + if (MainWindow == null) { - if (MainWindow == null) - { - var viewModel = new MainViewModel(Bindings); - MainWindow = new MainWindow { DataContext = viewModel }; - - //massive hack: we start the avalonia main loop and stop it immediately (since it's thread blocking) - //to avoid an annoying error when closing revit - var cts = new CancellationTokenSource(); - cts.CancelAfter(100); - AvaloniaApp.Run(cts.Token); - } + var viewModel = new MainViewModel(Bindings); + MainWindow = new MainWindow { DataContext = viewModel }; + + //massive hack: we start the avalonia main loop and stop it immediately (since it's thread blocking) + //to avoid an annoying error when closing revit + var cts = new CancellationTokenSource(); + cts.CancelAfter(100); + AvaloniaApp.Run(cts.Token); + } - if (showWindow) - { - MainWindow.Show(); - MainWindow.Activate(); + if (showWindow) + { + MainWindow.Show(); + MainWindow.Activate(); - //required to gracefully quit avalonia and the skia processes - //can also be used to manually do so - //https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes + //required to gracefully quit avalonia and the skia processes + //can also be used to manually do so + //https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var parentHwnd = App.AppInstance.MainWindowHandle; - var hwnd = MainWindow.PlatformImpl.Handle.Handle; - SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var parentHwnd = App.AppInstance.MainWindowHandle; + var hwnd = MainWindow.PlatformImpl.Handle.Handle; + SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd); } } - catch (Exception ex) - { - SpeckleLog.Logger.Fatal(ex, "Failed to create main window"); - var td = new TaskDialog("Error"); - td.MainContent = - $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}"; - td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum"); + } + catch (Exception ex) + { + SpeckleLog.Logger.Fatal(ex, "Failed to create main window"); + var td = new TaskDialog("Error"); + td.MainContent = + $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}"; + td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum"); - TaskDialogResult tResult = td.Show(); + TaskDialogResult tResult = td.Show(); - if (TaskDialogResult.CommandLink1 == tResult) - { - Process.Start("https://speckle.community/"); - } + if (TaskDialogResult.CommandLink1 == tResult) + { + Process.Start("https://speckle.community/"); } } + } - private static void AppMain(Avalonia.Application app, string[] args) - { - AvaloniaApp = app; - } + private static void AppMain(Avalonia.Application app, string[] args) + { + AvaloniaApp = app; } } diff --git a/ConnectorRevit/ConnectorRevit/Revit/FamilyLoadOption.cs b/ConnectorRevit/ConnectorRevit/Revit/FamilyLoadOption.cs index e03a1bfe3a..6613d1e5f4 100644 --- a/ConnectorRevit/ConnectorRevit/Revit/FamilyLoadOption.cs +++ b/ConnectorRevit/ConnectorRevit/Revit/FamilyLoadOption.cs @@ -1,24 +1,27 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using Autodesk.Revit.DB; -namespace ConnectorRevit.Revit +namespace ConnectorRevit.Revit; + +class FamilyLoadOption : IFamilyLoadOptions { - class FamilyLoadOption : IFamilyLoadOptions + public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues) { - public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues) - { - overwriteParameterValues = true; - return true; - } - + overwriteParameterValues = true; + return true; + } - public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues) - { - source = FamilySource.Family; - overwriteParameterValues = true; - return true; - } + public bool OnSharedFamilyFound( + Family sharedFamily, + bool familyInUse, + out FamilySource source, + out bool overwriteParameterValues + ) + { + source = FamilySource.Family; + overwriteParameterValues = true; + return true; } } diff --git a/ConnectorRevit/ConnectorRevit/RevitApplicationFunctionalityController.cs b/ConnectorRevit/ConnectorRevit/RevitApplicationFunctionalityController.cs index d235ca5742..21cbbc09db 100644 --- a/ConnectorRevit/ConnectorRevit/RevitApplicationFunctionalityController.cs +++ b/ConnectorRevit/ConnectorRevit/RevitApplicationFunctionalityController.cs @@ -3,25 +3,24 @@ using RevitSharedResources.Models; using Speckle.BatchUploader.Sdk.Interfaces; -namespace ConnectorRevit +namespace ConnectorRevit; + +internal class RevitApplicationController : IApplicationFunctionalityController { - internal class RevitApplicationController : IApplicationFunctionalityController - { - private readonly UIApplication application; + private readonly UIApplication application; - public RevitApplicationController(UIApplication application) - { - this.application = application; - } + public RevitApplicationController(UIApplication application) + { + this.application = application; + } - public async Task OpenDocument(string path) - { - await APIContext - .Run(() => - { - application.OpenAndActivateDocument(path); - }) - .ConfigureAwait(false); - } + public async Task OpenDocument(string path) + { + await APIContext + .Run(() => + { + application.OpenAndActivateDocument(path); + }) + .ConfigureAwait(false); } } diff --git a/ConnectorRevit/ConnectorRevit/RevitVersionHelper.cs b/ConnectorRevit/ConnectorRevit/RevitVersionHelper.cs index 88c338f283..6d0b9703a8 100644 --- a/ConnectorRevit/ConnectorRevit/RevitVersionHelper.cs +++ b/ConnectorRevit/ConnectorRevit/RevitVersionHelper.cs @@ -1,17 +1,15 @@ -using Autodesk.Revit.DB; +using Autodesk.Revit.DB; -namespace ConnectorRevit +namespace ConnectorRevit; + +public static class RevitVersionHelper { - public static class RevitVersionHelper + public static double ConvertFromInternalUnits(double val, Parameter parameter) { - - public static double ConvertFromInternalUnits(double val, Parameter parameter) - { #if REVIT2020 - return UnitUtils.ConvertFromInternalUnits(val, parameter.DisplayUnitType); + return UnitUtils.ConvertFromInternalUnits(val, parameter.DisplayUnitType); #else - return UnitUtils.ConvertFromInternalUnits(val, parameter.GetUnitTypeId()); + return UnitUtils.ConvertFromInternalUnits(val, parameter.GetUnitTypeId()); #endif - } } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/ConvertedObjectsCache.cs b/ConnectorRevit/ConnectorRevit/Storage/ConvertedObjectsCache.cs index 6ea86038a8..f207c294e1 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/ConvertedObjectsCache.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/ConvertedObjectsCache.cs @@ -4,72 +4,85 @@ using RevitSharedResources.Interfaces; using Speckle.Core.Models; -namespace ConnectorRevit.Storage +namespace ConnectorRevit.Storage; + +public sealed class ConvertedObjectsCache : IConvertedObjectsCache { - public sealed class ConvertedObjectsCache : IConvertedObjectsCache - { - private Dictionary)> convertedObjects = new(); + private Dictionary)> convertedObjects = new(); - public void AddConvertedObjects(Base converted, IList created) + public void AddConvertedObjects(Base converted, IList created) + { + if (string.IsNullOrEmpty(converted.applicationId)) { - if (string.IsNullOrEmpty(converted.applicationId)) return; - convertedObjects[converted.applicationId] = (converted, created.ToList()); + return; } - public IEnumerable GetConvertedObjects() + convertedObjects[converted.applicationId] = (converted, created.ToList()); + } + + public IEnumerable GetConvertedObjects() + { + foreach (var kvp in convertedObjects) { - foreach (var kvp in convertedObjects) - { - yield return kvp.Value.Item1; - } + yield return kvp.Value.Item1; } + } - public IEnumerable GetConvertedObjectsFromCreatedId(string id) + public IEnumerable GetConvertedObjectsFromCreatedId(string id) + { + foreach (var kvp in convertedObjects) { - foreach (var kvp in convertedObjects) + foreach (var obj in kvp.Value.Item2) { - foreach (var obj in kvp.Value.Item2) + if (obj.UniqueId != id) { - if (obj.UniqueId != id) continue; - - yield return kvp.Value.Item1; - yield break; + continue; } + + yield return kvp.Value.Item1; + yield break; } } + } - public bool HasConvertedObjectWithId(string id) - { - return convertedObjects.ContainsKey(id); - } + public bool HasConvertedObjectWithId(string id) + { + return convertedObjects.ContainsKey(id); + } - public IEnumerable GetCreatedObjects() + public IEnumerable GetCreatedObjects() + { + foreach (var kvp in convertedObjects) { - foreach (var kvp in convertedObjects) + foreach (var obj in kvp.Value.Item2) { - foreach (var obj in kvp.Value.Item2) - { - yield return obj; - } + yield return obj; } } + } - public IEnumerable GetCreatedObjectsFromConvertedId(string id) + public IEnumerable GetCreatedObjectsFromConvertedId(string id) + { + if (convertedObjects.TryGetValue(id, out var value)) { - if (convertedObjects.TryGetValue(id, out var value)) return value.Item2; - return Enumerable.Empty(); + return value.Item2; } - public bool HasCreatedObjectWithId(string id) + return Enumerable.Empty(); + } + + public bool HasCreatedObjectWithId(string id) + { + foreach (var kvp in convertedObjects) { - foreach (var kvp in convertedObjects) + foreach (var obj in kvp.Value.Item2) { - foreach (var obj in kvp.Value.Item2) + if (obj.UniqueId == id) { - if (obj.UniqueId == id) return true; + return true; } } - return false; } + return false; } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/RevitDocumentAggregateCache.cs b/ConnectorRevit/ConnectorRevit/Storage/RevitDocumentAggregateCache.cs index 111a958298..55fc346f56 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/RevitDocumentAggregateCache.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/RevitDocumentAggregateCache.cs @@ -4,69 +4,74 @@ using Autodesk.Revit.DB; using RevitSharedResources.Interfaces; -namespace ConnectorRevit.Storage +namespace ConnectorRevit.Storage; + +/// +/// Simple conversion cache to store elements that are retrieved and may be needed again throughout the conversion operation +/// +public sealed class RevitDocumentAggregateCache : IRevitDocumentAggregateCache { - /// - /// Simple conversion cache to store elements that are retrieved and may be needed again throughout the conversion operation - /// - public sealed class RevitDocumentAggregateCache : IRevitDocumentAggregateCache - { - private readonly Dictionary objectCaches; - private readonly UIDocumentProvider uiDocumentProvider; - public Document Document => uiDocumentProvider.Entity.Document; + private readonly Dictionary objectCaches; + private readonly UIDocumentProvider uiDocumentProvider; + public Document Document => uiDocumentProvider.Entity.Document; - public RevitDocumentAggregateCache(UIDocumentProvider uiDocumentProvider) - { - this.uiDocumentProvider = uiDocumentProvider; - this.objectCaches = new(); - } + public RevitDocumentAggregateCache(UIDocumentProvider uiDocumentProvider) + { + this.uiDocumentProvider = uiDocumentProvider; + this.objectCaches = new(); + } - public IRevitObjectCache GetOrInitializeEmptyCacheOfType(out bool isExistingCache) - { - return GetOrInitializeCacheOfTypeNullable(null, out isExistingCache); - } + public IRevitObjectCache GetOrInitializeEmptyCacheOfType(out bool isExistingCache) + { + return GetOrInitializeCacheOfTypeNullable(null, out isExistingCache); + } - public IRevitObjectCache GetOrInitializeCacheOfType(Action> initializer, out bool isExistingCache) - { - return GetOrInitializeCacheOfTypeNullable(initializer, out isExistingCache); - } + public IRevitObjectCache GetOrInitializeCacheOfType( + Action> initializer, + out bool isExistingCache + ) + { + return GetOrInitializeCacheOfTypeNullable(initializer, out isExistingCache); + } - private IRevitObjectCache GetOrInitializeCacheOfTypeNullable(Action>? initializer, out bool isExistingCache) + private IRevitObjectCache GetOrInitializeCacheOfTypeNullable( + Action>? initializer, + out bool isExistingCache + ) + { + if (!objectCaches.TryGetValue(typeof(T), out var singleCache)) { - if (!objectCaches.TryGetValue(typeof(T), out var singleCache)) + isExistingCache = false; + singleCache = new RevitObjectCache(this); + if (initializer != null) { - isExistingCache = false; - singleCache = new RevitObjectCache(this); - if (initializer != null) - { - initializer((IRevitObjectCache)singleCache); - } - objectCaches.Add(typeof(T), singleCache); + initializer((IRevitObjectCache)singleCache); } - else - { - isExistingCache = true; - } - return (IRevitObjectCache)singleCache; + objectCaches.Add(typeof(T), singleCache); } - - public IRevitObjectCache? TryGetCacheOfType() + else { - if (!objectCaches.TryGetValue(typeof(T), out var singleCache)) - { - return null; - } - return singleCache as IRevitObjectCache; + isExistingCache = true; } + return (IRevitObjectCache)singleCache; + } - public void Invalidate() - { - objectCaches.Remove(typeof(T)); - } - - public void InvalidateAll() + public IRevitObjectCache? TryGetCacheOfType() + { + if (!objectCaches.TryGetValue(typeof(T), out var singleCache)) { - objectCaches.Clear(); + return null; } + return singleCache as IRevitObjectCache; + } + + public void Invalidate() + { + objectCaches.Remove(typeof(T)); + } + + public void InvalidateAll() + { + objectCaches.Clear(); } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/RevitObjectCache.cs b/ConnectorRevit/ConnectorRevit/Storage/RevitObjectCache.cs index c4e604fce0..7f515abe76 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/RevitObjectCache.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/RevitObjectCache.cs @@ -4,89 +4,88 @@ using Autodesk.Revit.DB; using RevitSharedResources.Interfaces; -namespace ConnectorRevit.Storage +namespace ConnectorRevit.Storage; + +/// +/// Storage of a single type of object in the +/// +/// +internal class RevitObjectCache : IRevitObjectCache { - /// - /// Storage of a single type of object in the - /// - /// - internal class RevitObjectCache : IRevitObjectCache + private readonly Dictionary dataStorage; + public IRevitDocumentAggregateCache ParentCache { get; } + + public RevitObjectCache(IRevitDocumentAggregateCache parentCache) { - private readonly Dictionary dataStorage; - public IRevitDocumentAggregateCache ParentCache { get; } + ParentCache = parentCache; + dataStorage = new(); + } - public RevitObjectCache(IRevitDocumentAggregateCache parentCache) + public T GetOrAdd(string key, Func factory, out bool isExistingValue) + { + if (!dataStorage.TryGetValue(key, out var value)) { - ParentCache = parentCache; - dataStorage = new(); + isExistingValue = false; + value = factory(); + dataStorage.Add(key, value); } - - public T GetOrAdd(string key, Func factory, out bool isExistingValue) + else { - if (!dataStorage.TryGetValue(key, out var value)) - { - isExistingValue = false; - value = factory(); - dataStorage.Add(key, value); - } - else - { - isExistingValue = true; - } - - return value; + isExistingValue = true; } - public T? TryGet(string key) - { - if (!dataStorage.TryGetValue(key, out var value)) - { - return default(T); - } - - return value; - } + return value; + } - public bool ContainsKey(string key) + public T? TryGet(string key) + { + if (!dataStorage.TryGetValue(key, out var value)) { - return dataStorage.ContainsKey(key); + return default(T); } - public ICollection GetAllKeys() - { - return dataStorage.Keys; - } - - public ICollection GetAllObjects() - { - return dataStorage.Values; - } + return value; + } - public void Set(string key, T value) - { - dataStorage[key] = value; - } + public bool ContainsKey(string key) + { + return dataStorage.ContainsKey(key); + } - public void AddMany(IEnumerable elements, Func keyFactory) - { - foreach (var element in elements) - { - var key = keyFactory(element); - dataStorage[key] = element; - } - } + public ICollection GetAllKeys() + { + return dataStorage.Keys; + } + + public ICollection GetAllObjects() + { + return dataStorage.Values; + } - public void AddMany(Dictionary elementMap) + public void Set(string key, T value) + { + dataStorage[key] = value; + } + + public void AddMany(IEnumerable elements, Func keyFactory) + { + foreach (var element in elements) { - foreach (var kvp in elementMap) - { - dataStorage[kvp.Key] = kvp.Value; - } + var key = keyFactory(element); + dataStorage[key] = element; } + } - public void Remove(string key) + public void AddMany(Dictionary elementMap) + { + foreach (var kvp in elementMap) { - dataStorage.Remove(key); + dataStorage[kvp.Key] = kvp.Value; } } + + public void Remove(string key) + { + dataStorage.Remove(key); + } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/StreamStateCache.cs b/ConnectorRevit/ConnectorRevit/Storage/StreamStateCache.cs index 3636dbc7d7..716a8417c8 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/StreamStateCache.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/StreamStateCache.cs @@ -6,65 +6,67 @@ using RevitSharedResources.Interfaces; using Speckle.Core.Models; -namespace ConnectorRevit.Storage +namespace ConnectorRevit.Storage; + +public class StreamStateCache : IReceivedObjectIdMap { - public class StreamStateCache : IReceivedObjectIdMap - { - private StreamState streamState; - private Dictionary previousContextObjects; + private StreamState streamState; + private Dictionary previousContextObjects; - public StreamStateCache(StreamState state) + public StreamStateCache(StreamState state) + { + streamState = state; + var previousObjects = state.ReceivedObjects; + previousContextObjects = new(previousObjects.Count); + foreach (var ao in previousObjects) { - streamState = state; - var previousObjects = state.ReceivedObjects; - previousContextObjects = new(previousObjects.Count); - foreach (var ao in previousObjects) + var key = ao.applicationId ?? ao.OriginalId; + if (previousContextObjects.ContainsKey(key)) { - var key = ao.applicationId ?? ao.OriginalId; - if (previousContextObjects.ContainsKey(key)) - continue; - previousContextObjects.Add(key, ao); + continue; } + + previousContextObjects.Add(key, ao); } + } - public void AddConvertedElements(IConvertedObjectsCache convertedObjects) + public void AddConvertedElements(IConvertedObjectsCache convertedObjects) + { + var newContextObjects = new List(); + foreach (var @base in convertedObjects.GetConvertedObjects()) { - var newContextObjects = new List(); - foreach (var @base in convertedObjects.GetConvertedObjects()) - { - var elements = convertedObjects.GetCreatedObjectsFromConvertedId(@base.applicationId).ToList(); - var appObj = new ApplicationObject(@base.id, @base.speckle_type); + var elements = convertedObjects.GetCreatedObjectsFromConvertedId(@base.applicationId).ToList(); + var appObj = new ApplicationObject(@base.id, @base.speckle_type); - newContextObjects.Add( - new ApplicationObject(@base.id, @base.speckle_type) - { - applicationId = @base.applicationId, - CreatedIds = elements.Where(element => element.IsValidObject).Select(element => element.UniqueId).ToList(), - Converted = elements.Cast().ToList() - } - ); - } - streamState.ReceivedObjects = newContextObjects; + newContextObjects.Add( + new ApplicationObject(@base.id, @base.speckle_type) + { + applicationId = @base.applicationId, + CreatedIds = elements.Where(element => element.IsValidObject).Select(element => element.UniqueId).ToList(), + Converted = elements.Cast().ToList() + } + ); } + streamState.ReceivedObjects = newContextObjects; + } - public IEnumerable GetAllConvertedIds() - { - return previousContextObjects.Keys; - } + public IEnumerable GetAllConvertedIds() + { + return previousContextObjects.Keys; + } - public IEnumerable GetCreatedIdsFromConvertedId(string id) + public IEnumerable GetCreatedIdsFromConvertedId(string id) + { + if (previousContextObjects.TryGetValue(id, out var appObj) && appObj.CreatedIds.Count > 0) { - if (previousContextObjects.TryGetValue(id, out var appObj) && appObj.CreatedIds.Count > 0) - { - return appObj.CreatedIds; - } - return new[] { id }; + return appObj.CreatedIds; } + return new[] { id }; + } - public void RemoveConvertedId(string id) - { - // no need to remove as this cache get written over by a new one after each receive - //previousContextObjects.Remove(id); - } + public void RemoveConvertedId(string id) + { + // no need to remove as this cache get written over by a new one after each receive + //previousContextObjects.Remove(id); } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/StreamStateManager.cs b/ConnectorRevit/ConnectorRevit/Storage/StreamStateManager.cs index 63b3253e0e..fffb3baabe 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/StreamStateManager.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/StreamStateManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Autodesk.Revit.DB; @@ -6,148 +6,160 @@ using DesktopUI2.Models; using Speckle.Newtonsoft.Json; -namespace Speckle.ConnectorRevit.Storage +namespace Speckle.ConnectorRevit.Storage; + +/// +/// Manages the serialisation of speckle stream state +/// (stream info, account info, and filter type) in a revit document. +/// +public static class StreamStateManager { + readonly static Guid ID = new("4EF264B9-5AA0-4B99-A6E7-C82ACEB26DE2"); + /// - /// Manages the serialisation of speckle stream state - /// (stream info, account info, and filter type) in a revit document. + /// Returns all the speckle stream states present in the current document. /// - public static class StreamStateManager + /// + /// + public static List ReadState(Document doc) { - readonly static Guid ID = new Guid("4EF264B9-5AA0-4B99-A6E7-C82ACEB26DE2"); - - /// - /// Returns all the speckle stream states present in the current document. - /// - /// - /// - public static List ReadState(Document doc) + try { - try - { - var streamStatesEntity = GetSpeckleEntity(doc); - if (streamStatesEntity == null || !streamStatesEntity.IsValid()) - return new List(); - - var str = streamStatesEntity.Get("StreamStates"); - var states = JsonConvert.DeserializeObject>(str); - - return states; - } - catch (Exception e) + var streamStatesEntity = GetSpeckleEntity(doc); + if (streamStatesEntity == null || !streamStatesEntity.IsValid()) { return new List(); } - } - /// - /// Writes the stream states to the current document. - /// - /// - /// - public static void WriteStreamStateList(Document doc, List streamStates) + var str = streamStatesEntity.Get("StreamStates"); + var states = JsonConvert.DeserializeObject>(str); + + return states; + } + catch (Exception e) { - var ds = GetSettingsDataStorage(doc); + return new List(); + } + } - if (ds == null) - ds = DataStorage.Create(doc); + /// + /// Writes the stream states to the current document. + /// + /// + /// + public static void WriteStreamStateList(Document doc, List streamStates) + { + var ds = GetSettingsDataStorage(doc); - var streamStatesEntity = new Entity(StreamStateListSchema2.GetSchema()); + if (ds == null) + { + ds = DataStorage.Create(doc); + } - streamStatesEntity.Set("StreamStates", JsonConvert.SerializeObject(streamStates) as string); + var streamStatesEntity = new Entity(StreamStateListSchema2.GetSchema()); - var idEntity = new Entity(DSUniqueSchemaStreamStateStorage2.GetSchema()); - idEntity.Set("Id", ID); + streamStatesEntity.Set("StreamStates", JsonConvert.SerializeObject(streamStates) as string); - ds.SetEntity(idEntity); - ds.SetEntity(streamStatesEntity); - } + var idEntity = new Entity(DSUniqueSchemaStreamStateStorage2.GetSchema()); + idEntity.Set("Id", ID); - private static DataStorage GetSettingsDataStorage(Document doc) - { - // Retrieve all data storages from project - var collector = new FilteredElementCollector(doc); + ds.SetEntity(idEntity); + ds.SetEntity(streamStatesEntity); + } - var dataStorages = collector.OfClass(typeof(DataStorage)); + private static DataStorage GetSettingsDataStorage(Document doc) + { + // Retrieve all data storages from project + var collector = new FilteredElementCollector(doc); - // Find setting data storage - foreach (DataStorage dataStorage in dataStorages) - { - var settingIdEntity = dataStorage.GetEntity(DSUniqueSchemaStreamStateStorage2.GetSchema()); + var dataStorages = collector.OfClass(typeof(DataStorage)); - if (!settingIdEntity.IsValid()) - continue; + // Find setting data storage + foreach (DataStorage dataStorage in dataStorages) + { + var settingIdEntity = dataStorage.GetEntity(DSUniqueSchemaStreamStateStorage2.GetSchema()); - var id = settingIdEntity.Get("Id"); + if (!settingIdEntity.IsValid()) + { + continue; + } - if (!id.Equals(ID)) - continue; + var id = settingIdEntity.Get("Id"); - return dataStorage; + if (!id.Equals(ID)) + { + continue; } - return null; + + return dataStorage; } + return null; + } - private static Entity GetSpeckleEntity(Document doc) - { - FilteredElementCollector collector = new FilteredElementCollector(doc); + private static Entity GetSpeckleEntity(Document doc) + { + FilteredElementCollector collector = new(doc); - var dataStorages = collector.OfClass(typeof(DataStorage)); - foreach (DataStorage dataStorage in dataStorages) + var dataStorages = collector.OfClass(typeof(DataStorage)); + foreach (DataStorage dataStorage in dataStorages) + { + Entity settingEntity = dataStorage.GetEntity(StreamStateListSchema2.GetSchema()); + if (!settingEntity.IsValid()) { - Entity settingEntity = dataStorage.GetEntity(StreamStateListSchema2.GetSchema()); - if (!settingEntity.IsValid()) - continue; - - return settingEntity; + continue; } - return null; + + return settingEntity; } + return null; } +} - /// - /// Revit schema of the StreamStateWrapper class. - /// - public static class StreamStateListSchema2 - { - static readonly Guid schemaGuid = new Guid("C48D05AE-8068-4B9A-A790-B4B2F605126B"); +/// +/// Revit schema of the StreamStateWrapper class. +/// +public static class StreamStateListSchema2 +{ + static readonly Guid schemaGuid = new("C48D05AE-8068-4B9A-A790-B4B2F605126B"); - public static Schema GetSchema() + public static Schema GetSchema() + { + var schema = Schema.Lookup(schemaGuid); + if (schema != null) { - var schema = Schema.Lookup(schemaGuid); - if (schema != null) - return schema; + return schema; + } - var builder = new SchemaBuilder(schemaGuid); - builder.SetSchemaName("StreamStateWrapper"); - builder.AddSimpleField("StreamStates", typeof(string)); + var builder = new SchemaBuilder(schemaGuid); + builder.SetSchemaName("StreamStateWrapper"); + builder.AddSimpleField("StreamStates", typeof(string)); - return builder.Finish(); - } + return builder.Finish(); } +} +/// +/// Unique schema for... something ¯\_(ツ)_/¯ +/// +static class DSUniqueSchemaStreamStateStorage2 +{ + static readonly Guid schemaGuid = new("C0DA9F31-83A7-4775-807B-4430446E694F"); - /// - /// Unique schema for... something ¯\_(ツ)_/¯ - /// - static class DSUniqueSchemaStreamStateStorage2 + public static Schema GetSchema() { - static readonly Guid schemaGuid = new Guid("C0DA9F31-83A7-4775-807B-4430446E694F"); + Schema schema = Schema.Lookup(schemaGuid); - public static Schema GetSchema() + if (schema != null) { - Schema schema = Schema.Lookup(schemaGuid); - - if (schema != null) - return schema; + return schema; + } - SchemaBuilder schemaBuilder = new SchemaBuilder(schemaGuid); + SchemaBuilder schemaBuilder = new(schemaGuid); - schemaBuilder.SetSchemaName("DataStorageUniqueId"); + schemaBuilder.SetSchemaName("DataStorageUniqueId"); - schemaBuilder.AddSimpleField("Id", typeof(Guid)); + schemaBuilder.AddSimpleField("Id", typeof(Guid)); - return schemaBuilder.Finish(); - } + return schemaBuilder.Finish(); } } diff --git a/ConnectorRevit/ConnectorRevit/Storage/UIDocumentProvider.cs b/ConnectorRevit/ConnectorRevit/Storage/UIDocumentProvider.cs index 2e34dd7a60..55b7a63ae4 100644 --- a/ConnectorRevit/ConnectorRevit/Storage/UIDocumentProvider.cs +++ b/ConnectorRevit/ConnectorRevit/Storage/UIDocumentProvider.cs @@ -1,25 +1,24 @@ using UI = Autodesk.Revit.UI; -namespace ConnectorRevit.Storage +namespace ConnectorRevit.Storage; + +/// +/// Provides the current to any dependencies which may need it +/// +public class UIDocumentProvider { - /// - /// Provides the current to any dependencies which may need it - /// - public class UIDocumentProvider - { - private UI.UIApplication revitApplication; + private UI.UIApplication revitApplication; - public UIDocumentProvider(UI.UIApplication revitApplication) - { - this.revitApplication = revitApplication; - } + public UIDocumentProvider(UI.UIApplication revitApplication) + { + this.revitApplication = revitApplication; + } - private UI.UIDocument uiDocument; + private UI.UIDocument uiDocument; - public UI.UIDocument Entity - { - get => uiDocument ?? revitApplication.ActiveUIDocument; - set => uiDocument = value; - } + public UI.UIDocument Entity + { + get => uiDocument ?? revitApplication.ActiveUIDocument; + set => uiDocument = value; } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/ElementTypeMapper.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/ElementTypeMapper.cs index 90360074fe..e28b1ca96a 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/ElementTypeMapper.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/ElementTypeMapper.cs @@ -20,356 +20,429 @@ using DB = Autodesk.Revit.DB; using SHC = RevitSharedResources.Helpers.Categories; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +/// +/// Responsible for parsing data received from Speckle for necessary s, and then querying the current Revit document for s that exist in the Project. This class then stores all of the data that it finds in an object that can be passed to DUI for user mapping. +/// +internal sealed class ElementTypeMapper { + private readonly IAllRevitCategoriesExposer revitCategoriesExposer; + private readonly IRevitElementTypeRetriever typeRetriever; + private readonly IRevitDocumentAggregateCache revitDocumentAggregateCache; + private List speckleElements = new(); + private readonly Document document; + /// - /// Responsible for parsing data received from Speckle for necessary s, and then querying the current Revit document for s that exist in the Project. This class then stores all of the data that it finds in an object that can be passed to DUI for user mapping. + /// Initialize ElementTypeMapper. Will throw if the provided does not also implement and /// - internal sealed class ElementTypeMapper + /// + /// + /// + /// + /// + public ElementTypeMapper( + ISpeckleConverter converter, + IRevitDocumentAggregateCache revitDocumentAggregateCache, + List flattenedCommit, + Dictionary storedObjects, + Document doc + ) { - private readonly IAllRevitCategoriesExposer revitCategoriesExposer; - private readonly IRevitElementTypeRetriever typeRetriever; - private readonly IRevitDocumentAggregateCache revitDocumentAggregateCache; - private List speckleElements = new(); - private readonly Document document; - - /// - /// Initialize ElementTypeMapper. Will throw if the provided does not also implement and - /// - /// - /// - /// - /// - /// - public ElementTypeMapper(ISpeckleConverter converter, IRevitDocumentAggregateCache revitDocumentAggregateCache, List flattenedCommit, Dictionary storedObjects, Document doc) - { - document = doc; + document = doc; - if (converter is not IRevitElementTypeRetriever typeRetriever) - { - throw new ArgumentException($"Converter does not implement interface {nameof(IRevitElementTypeRetriever)}"); - } - else this.typeRetriever = typeRetriever; + if (converter is not IRevitElementTypeRetriever typeRetriever) + { + throw new ArgumentException($"Converter does not implement interface {nameof(IRevitElementTypeRetriever)}"); + } + else + { + this.typeRetriever = typeRetriever; + } - if (converter is not IAllRevitCategoriesExposer typeInfoExposer) - { - throw new ArgumentException($"Converter does not implement interface {nameof(IRevitElementTypeRetriever)}"); - } - else revitCategoriesExposer = typeInfoExposer; + if (converter is not IAllRevitCategoriesExposer typeInfoExposer) + { + throw new ArgumentException($"Converter does not implement interface {nameof(IRevitElementTypeRetriever)}"); + } + else + { + revitCategoriesExposer = typeInfoExposer; + } - this.revitDocumentAggregateCache = revitDocumentAggregateCache ?? throw new ArgumentException($"RevitDocumentAggregateCache cannot be null"); + this.revitDocumentAggregateCache = + revitDocumentAggregateCache ?? throw new ArgumentException($"RevitDocumentAggregateCache cannot be null"); - var traversalFunc = DefaultTraversal.CreateTraverseFunc(converter); - foreach (var appObj in flattenedCommit) - { - // add base and traverse nested elements - speckleElements.AddRange(traversalFunc.Traverse(storedObjects[appObj.OriginalId]) + var traversalFunc = DefaultTraversal.CreateTraverseFunc(converter); + foreach (var appObj in flattenedCommit) + { + // add base and traverse nested elements + speckleElements.AddRange( + traversalFunc + .Traverse(storedObjects[appObj.OriginalId]) .Select(c => c.current) .Where(converter.CanConvertToNative) .OfType() - ); - } + ); } - public async Task Map(ISetting mapOnReceiveSetting, ISetting directShapeStrategySetting) + } + + public async Task Map(ISetting mapOnReceiveSetting, ISetting directShapeStrategySetting) + { + // Get Settings for recieve on mapping + if ( + mapOnReceiveSetting is not MappingSetting mappingSetting + || mappingSetting.Selection == ConnectorBindingsRevit.noMapping + //skip mappings dialog always when DS fallback is set to always + || directShapeStrategySetting.Selection == ConnectorBindingsRevit.DsFallbackAways + ) { - // Get Settings for recieve on mapping - if (mapOnReceiveSetting is not MappingSetting mappingSetting - || mappingSetting.Selection == ConnectorBindingsRevit.noMapping - //skip mappings dialog always when DS fallback is set to always - || directShapeStrategySetting.Selection == ConnectorBindingsRevit.DsFallbackAways) - { - return; - } + return; + } - var masterTypeMap = DeserializeMapping(mappingSetting, out var previousMappingExists) ?? new TypeMap(); - var currentOperationTypeMap = new TypeMap(); + var masterTypeMap = DeserializeMapping(mappingSetting, out var previousMappingExists) ?? new TypeMap(); + var currentOperationTypeMap = new TypeMap(); - var hostTypesContainer = GetHostTypesAndAddIncomingTypes(currentOperationTypeMap, masterTypeMap, out var numNewTypes); + var hostTypesContainer = GetHostTypesAndAddIncomingTypes( + currentOperationTypeMap, + masterTypeMap, + out var numNewTypes + ); - if (await ShouldShowCustomMappingDialog(mappingSetting.Selection, numNewTypes).ConfigureAwait(false)) - { - // show custom mapping dialog if the settings correspond to what is being received - await ShowCustomMappingDialog(currentOperationTypeMap, hostTypesContainer, numNewTypes).ConfigureAwait(false); + if (await ShouldShowCustomMappingDialog(mappingSetting.Selection, numNewTypes).ConfigureAwait(false)) + { + // show custom mapping dialog if the settings correspond to what is being received + await ShowCustomMappingDialog(currentOperationTypeMap, hostTypesContainer, numNewTypes).ConfigureAwait(false); - // close the dialog - MainViewModel.CloseDialog(); + // close the dialog + MainViewModel.CloseDialog(); - masterTypeMap.AddTypeMap(currentOperationTypeMap); - mappingSetting.MappingJson = JsonConvert.SerializeObject(masterTypeMap); - } - else if (!previousMappingExists) - { - // if we're not showing the user the custom mapping dialog and the user doesn't have an existing mapping - // then we're done here - return; - } + masterTypeMap.AddTypeMap(currentOperationTypeMap); + mappingSetting.MappingJson = JsonConvert.SerializeObject(masterTypeMap); + } + else if (!previousMappingExists) + { + // if we're not showing the user the custom mapping dialog and the user doesn't have an existing mapping + // then we're done here + return; + } - // update the mapping object for the user mapped types - SetMappedValues(typeRetriever, currentOperationTypeMap); + // update the mapping object for the user mapped types + SetMappedValues(typeRetriever, currentOperationTypeMap); - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Type Map" }, { "method", "Mappings Set" } }); - } + Analytics.TrackEvent( + Analytics.Events.DUIAction, + new Dictionary { { "name", "Type Map" }, { "method", "Mappings Set" } } + ); + } - private async Task ShouldShowCustomMappingDialog(string listBoxSelection, int numNewTypes) + private async Task ShouldShowCustomMappingDialog(string listBoxSelection, int numNewTypes) + { + if (listBoxSelection == ConnectorBindingsRevit.everyReceive) { - if (listBoxSelection == ConnectorBindingsRevit.everyReceive) - { - return true; - } - else if (listBoxSelection == ConnectorBindingsRevit.forNewTypes - && numNewTypes > 0 - && await ShowMissingIncomingTypesDialog().ConfigureAwait(false) - ) - { - return true; - } - return false; + return true; } - - private static async Task ShowMissingIncomingTypesDialog() + else if ( + listBoxSelection == ConnectorBindingsRevit.forNewTypes + && numNewTypes > 0 + && await ShowMissingIncomingTypesDialog().ConfigureAwait(false) + ) { - var response = await Dispatcher.UIThread.InvokeAsync(() => + return true; + } + return false; + } + + private static async Task ShowMissingIncomingTypesDialog() + { + var response = await Dispatcher.UIThread + .InvokeAsync(() => { - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Type Map" }, { "method", "Missing Types Dialog" } }); + Analytics.TrackEvent( + Analytics.Events.DUIAction, + new Dictionary { { "name", "Type Map" }, { "method", "Missing Types Dialog" } } + ); var mappingView = new MissingIncomingTypesDialog(); - return mappingView.ShowDialog(); ; - }).ConfigureAwait(false); - - if (response) - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Type Map" }, { "method", "Dialog Accept" } }); - else - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Type Map" }, { "method", "Dialog Ignore" } }); - + return mappingView.ShowDialog(); + ; + }) + .ConfigureAwait(false); - return response; + if (response) + { + Analytics.TrackEvent( + Analytics.Events.DUIAction, + new Dictionary { { "name", "Type Map" }, { "method", "Dialog Accept" } } + ); } - - private async Task ShowCustomMappingDialog(TypeMap? currentMapping, HostTypeContainer hostTypesContainer, int numNewTypes) + else { - var vm = new TypeMappingOnReceiveViewModel(currentMapping, hostTypesContainer, numNewTypes == 0); - FamilyImporter familyImporter = null; + Analytics.TrackEvent( + Analytics.Events.DUIAction, + new Dictionary { { "name", "Type Map" }, { "method", "Dialog Ignore" } } + ); + } - await Dispatcher.UIThread.InvokeAsync(() => + return response; + } + + private async Task ShowCustomMappingDialog( + TypeMap? currentMapping, + HostTypeContainer hostTypesContainer, + int numNewTypes + ) + { + var vm = new TypeMappingOnReceiveViewModel(currentMapping, hostTypesContainer, numNewTypes == 0); + FamilyImporter familyImporter = null; + + await Dispatcher.UIThread + .InvokeAsync(() => { - var mappingView = new MappingViewDialog - { - DataContext = vm - }; + var mappingView = new MappingViewDialog { DataContext = vm }; return mappingView.ShowDialog(); - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - while (vm.DoneMapping == false) + while (vm.DoneMapping == false) + { + try { - try - { - familyImporter ??= new FamilyImporter(document, revitCategoriesExposer, typeRetriever, revitDocumentAggregateCache); - await familyImporter.ImportFamilyTypes(hostTypesContainer).ConfigureAwait(false); - } - catch (SpeckleException ex) - { - StreamViewModel.HandleCommandException(ex, false, "ImportTypesCommand"); - } - catch (Exception ex) - { - var speckleEx = new SpeckleException(ex.Message, ex); - StreamViewModel.HandleCommandException(speckleEx, false, "ImportTypesCommand"); - } + familyImporter ??= new FamilyImporter( + document, + revitCategoriesExposer, + typeRetriever, + revitDocumentAggregateCache + ); + await familyImporter.ImportFamilyTypes(hostTypesContainer).ConfigureAwait(false); + } + catch (SpeckleException ex) + { + StreamViewModel.HandleCommandException(ex, false, "ImportTypesCommand"); + } + catch (Exception ex) + { + var speckleEx = new SpeckleException(ex.Message, ex); + StreamViewModel.HandleCommandException(speckleEx, false, "ImportTypesCommand"); + } - vm = new TypeMappingOnReceiveViewModel(currentMapping, hostTypesContainer, numNewTypes == 0); - await Dispatcher.UIThread.InvokeAsync(() => + vm = new TypeMappingOnReceiveViewModel(currentMapping, hostTypesContainer, numNewTypes == 0); + await Dispatcher.UIThread + .InvokeAsync(() => { - var mappingView = new MappingViewDialog - { - DataContext = vm - }; + var mappingView = new MappingViewDialog { DataContext = vm }; return mappingView.ShowDialog(); - }).ConfigureAwait(false); - } + }) + .ConfigureAwait(false); } + } - private static void SetMappedValues(IRevitElementTypeRetriever typeRetriever, TypeMap currentMapping) + private static void SetMappedValues(IRevitElementTypeRetriever typeRetriever, TypeMap currentMapping) + { + foreach (var (@base, mappingValue) in currentMapping.GetAllBasesWithMappings()) { - foreach (var (@base, mappingValue) in currentMapping.GetAllBasesWithMappings()) + var mappedHostType = mappingValue.MappedHostType ?? mappingValue.InitialGuess; + if (mappedHostType == null) { - var mappedHostType = mappingValue.MappedHostType ?? mappingValue.InitialGuess; - if (mappedHostType == null) continue; + continue; + } - if (mappedHostType is RevitHostType revitHostType) - { - typeRetriever.SetElementFamily(@base, revitHostType.HostFamilyName); - } - typeRetriever.SetElementType(@base, mappedHostType.HostTypeName); + if (mappedHostType is RevitHostType revitHostType) + { + typeRetriever.SetElementFamily(@base, revitHostType.HostFamilyName); } + typeRetriever.SetElementType(@base, mappedHostType.HostTypeName); } + } - /// - /// Since an is a Revit concept, this method just hands the object to the Converter to figure out the . It also retrieves all possible s for a given category of element and then saves it in a . This container will be passed to DUI for user mapping. - /// - /// - /// - /// - /// - public HostTypeContainer GetHostTypesAndAddIncomingTypes(TypeMap currentTypeMap, TypeMap masterTypeMap, out int numNewTypes) - { - var hostTypes = new HostTypeContainer(); + /// + /// Since an is a Revit concept, this method just hands the object to the Converter to figure out the . It also retrieves all possible s for a given category of element and then saves it in a . This container will be passed to DUI for user mapping. + /// + /// + /// + /// + /// + public HostTypeContainer GetHostTypesAndAddIncomingTypes( + TypeMap currentTypeMap, + TypeMap masterTypeMap, + out int numNewTypes + ) + { + var hostTypes = new HostTypeContainer(); - numNewTypes = 0; - var groupedElementTypeCache = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory>(); - var elementTypeCache = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory(); + numNewTypes = 0; + var groupedElementTypeCache = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory>(); + var elementTypeCache = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory(); - foreach (var @base in speckleElements) + foreach (var @base in speckleElements) + { + var incomingType = typeRetriever.GetElementType(@base); + if (incomingType == null) { - var incomingType = typeRetriever.GetElementType(@base); - if (incomingType == null) - { - SpeckleLog.Logger.Warning("Could not find incoming type on Base of type {baseType} with speckle_type {speckleType}", @base.GetType(), @base.speckle_type); - continue; - } + SpeckleLog.Logger.Warning( + "Could not find incoming type on Base of type {baseType} with speckle_type {speckleType}", + @base.GetType(), + @base.speckle_type + ); + continue; + } - var incomingFamily = typeRetriever.GetElementFamily(@base); + var incomingFamily = typeRetriever.GetElementFamily(@base); - var typeInfo = revitCategoriesExposer.AllCategories.GetRevitCategoryInfo(@base); - //if (typeInfo.ElementTypeType == null) continue; + var typeInfo = revitCategoriesExposer.AllCategories.GetRevitCategoryInfo(@base); + //if (typeInfo.ElementTypeType == null) continue; - var elementTypes = groupedElementTypeCache.GetOrAddGroupOfTypes(typeInfo); - var exactTypeMatch = elementTypeCache.ContainsKey(typeInfo.GetCategorySpecificTypeName(incomingType)); + var elementTypes = groupedElementTypeCache.GetOrAddGroupOfTypes(typeInfo); + var exactTypeMatch = elementTypeCache.ContainsKey(typeInfo.GetCategorySpecificTypeName(incomingType)); - hostTypes.AddCategoryWithTypesIfCategoryIsNew(typeInfo.CategoryName, elementTypes.Select(type => new RevitHostType(type.FamilyName, type.Name))); + hostTypes.AddCategoryWithTypesIfCategoryIsNew( + typeInfo.CategoryName, + elementTypes.Select(type => new RevitHostType(type.FamilyName, type.Name)) + ); - var mappedValue = GetExistingMappedValue(masterTypeMap, incomingFamily, incomingType, typeInfo.CategoryName); + var mappedValue = GetExistingMappedValue(masterTypeMap, incomingFamily, incomingType, typeInfo.CategoryName); - if (mappedValue == null) - { - mappedValue = GetMappedValueGuess(elementTypes, typeInfo.CategoryName, incomingType); + if (mappedValue == null) + { + mappedValue = GetMappedValueGuess(elementTypes, typeInfo.CategoryName, incomingType); - // if the neither the document nor the masterTypeMap contain a matching type, then it is new - if (!exactTypeMatch) numNewTypes++; + // if the neither the document nor the masterTypeMap contain a matching type, then it is new + if (!exactTypeMatch) + { + numNewTypes++; } - - currentTypeMap.AddIncomingType(@base, incomingType, incomingFamily, typeInfo.CategoryName, mappedValue); } - hostTypes.SetAllTypes( - elementTypeCache - .GetAllObjects() - .Select(type => new RevitHostType(type.FamilyName, type.Name)) - ); - - return hostTypes; + currentTypeMap.AddIncomingType(@base, incomingType, incomingFamily, typeInfo.CategoryName, mappedValue); } - private static ISingleHostType? GetExistingMappedValue(TypeMap typeMap, string? incomingFamily, string incomingType, string category) - { - var existingMappingValue = typeMap.TryGetMappingValueInCategory(category, incomingFamily, incomingType); + hostTypes.SetAllTypes( + elementTypeCache.GetAllObjects().Select(type => new RevitHostType(type.FamilyName, type.Name)) + ); - if (existingMappingValue != null && existingMappingValue.InitialGuess != null) - { - return existingMappingValue.MappedHostType ?? existingMappingValue.InitialGuess; - } - return null; + return hostTypes; + } + + private static ISingleHostType? GetExistingMappedValue( + TypeMap typeMap, + string? incomingFamily, + string incomingType, + string category + ) + { + var existingMappingValue = typeMap.TryGetMappingValueInCategory(category, incomingFamily, incomingType); + + if (existingMappingValue != null && existingMappingValue.InitialGuess != null) + { + return existingMappingValue.MappedHostType ?? existingMappingValue.InitialGuess; } + return null; + } - public static TypeMap? DeserializeMapping(MappingSetting mappingSetting, out bool previousMappingExists) + public static TypeMap? DeserializeMapping(MappingSetting mappingSetting, out bool previousMappingExists) + { + if (mappingSetting.MappingJson != null) { - if (mappingSetting.MappingJson != null) + var settings = new JsonSerializerSettings { - var settings = new JsonSerializerSettings + Converters = { - Converters = { - new AbstractConverter(), - new AbstractConverter(), - }, - }; - try - { - previousMappingExists = true; - return JsonConvert.DeserializeObject(mappingSetting.MappingJson, settings); - } - catch - { - // couldn't deserialize so just return null - } + new AbstractConverter(), + new AbstractConverter(), + }, + }; + try + { + previousMappingExists = true; + return JsonConvert.DeserializeObject(mappingSetting.MappingJson, settings); + } + catch + { + // couldn't deserialize so just return null } - previousMappingExists = false; - return null; } + previousMappingExists = false; + return null; + } - /// - /// Gets the most similar host type of the same category for a single incoming type - /// - /// - /// - /// - /// - private static ISingleHostType GetMappedValueGuess(IEnumerable elementTypes, string category, string incomingType) - { - var shortestDistance = int.MaxValue; - var closestFamily = string.Empty; - var closestType = $"No families of the category \"{category}\" are loaded into the project"; + /// + /// Gets the most similar host type of the same category for a single incoming type + /// + /// + /// + /// + /// + private static ISingleHostType GetMappedValueGuess( + IEnumerable elementTypes, + string category, + string incomingType + ) + { + var shortestDistance = int.MaxValue; + var closestFamily = string.Empty; + var closestType = $"No families of the category \"{category}\" are loaded into the project"; - foreach (var elementType in elementTypes) + foreach (var elementType in elementTypes) + { + var distance = LevenshteinDistance(incomingType, elementType.Name); + if (distance < shortestDistance) { - var distance = LevenshteinDistance(incomingType, elementType.Name); - if (distance < shortestDistance) - { - shortestDistance = distance; - closestFamily = elementType.FamilyName; - closestType = elementType.Name; - } + shortestDistance = distance; + closestFamily = elementType.FamilyName; + closestType = elementType.Name; } + } - return new RevitHostType(closestFamily, closestType); + return new RevitHostType(closestFamily, closestType); + } + + /// + /// Returns the distance between two strings + /// + /// + /// + /// distance as an integer + private static int LevenshteinDistance(string s, string t) + { + // Default algorithim for computing the similarity between strings + int n = s.Length; + int m = t.Length; + int[,] d = new int[n + 1, m + 1]; + if (n == 0) + { + return m; + } + if (m == 0) + { + return n; + } + for (int i = 0; i <= n; d[i, 0] = i++) + { + ; } - /// - /// Returns the distance between two strings - /// - /// - /// - /// distance as an integer - private static int LevenshteinDistance(string s, string t) + for (int j = 0; j <= m; d[0, j] = j++) { - // Default algorithim for computing the similarity between strings - int n = s.Length; - int m = t.Length; - int[,] d = new int[n + 1, m + 1]; - if (n == 0) - { - return m; - } - if (m == 0) - { - return n; - } - for (int i = 0; i <= n; d[i, 0] = i++) - ; - for (int j = 0; j <= m; d[0, j] = j++) - ; - for (int i = 1; i <= n; i++) + ; + } + + for (int i = 1; i <= n; i++) + { + for (int j = 1; j <= m; j++) { - for (int j = 1; j <= m; j++) - { - int cost = (t[j - 1] == s[i - 1]) ? 0 : 1; - d[i, j] = Math.Min( - Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), - d[i - 1, j - 1] + cost); - } + int cost = (t[j - 1] == s[i - 1]) ? 0 : 1; + d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); } - return d[n, m]; } + return d[n, m]; } +} - public class AbstractConverter : JsonConverter where TReal : TAbstract - { - public override bool CanConvert(Type objectType) - => objectType == typeof(TAbstract); +public class AbstractConverter : JsonConverter + where TReal : TAbstract +{ + public override bool CanConvert(Type objectType) => objectType == typeof(TAbstract); - public override object ReadJson(JsonReader reader, Type type, Object value, JsonSerializer jser) - => jser.Deserialize(reader); + public override object ReadJson(JsonReader reader, Type type, Object value, JsonSerializer jser) => + jser.Deserialize(reader); - public override void WriteJson(JsonWriter writer, Object value, JsonSerializer jser) - => jser.Serialize(writer, value); - } + public override void WriteJson(JsonWriter writer, Object value, JsonSerializer jser) => jser.Serialize(writer, value); } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/FamilyImporter.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/FamilyImporter.cs index d339077d30..a34faec090 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/FamilyImporter.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/FamilyImporter.cs @@ -16,33 +16,39 @@ using static DesktopUI2.ViewModels.ImportFamiliesDialogViewModel; using SHC = RevitSharedResources.Helpers.Categories; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +internal sealed class FamilyImporter { - internal sealed class FamilyImporter + private readonly Document document; + private readonly IAllRevitCategoriesExposer revitCategoriesExposer; + private readonly IRevitElementTypeRetriever typeRetriever; + private readonly IRevitDocumentAggregateCache revitDocumentAggregateCache; + + public FamilyImporter( + Document document, + IAllRevitCategoriesExposer revitCategoriesExposer, + IRevitElementTypeRetriever typeRetriever, + IRevitDocumentAggregateCache revitDocumentAggregateCache + ) { - private readonly Document document; - private readonly IAllRevitCategoriesExposer revitCategoriesExposer; - private readonly IRevitElementTypeRetriever typeRetriever; - private readonly IRevitDocumentAggregateCache revitDocumentAggregateCache; - - public FamilyImporter(Document document, IAllRevitCategoriesExposer revitCategoriesExposer, IRevitElementTypeRetriever typeRetriever, IRevitDocumentAggregateCache revitDocumentAggregateCache) - { - this.document = document; - this.revitCategoriesExposer = revitCategoriesExposer; - this.typeRetriever = typeRetriever; - this.revitDocumentAggregateCache = revitDocumentAggregateCache; - } + this.document = document; + this.revitCategoriesExposer = revitCategoriesExposer; + this.typeRetriever = typeRetriever; + this.revitDocumentAggregateCache = revitDocumentAggregateCache; + } - /// - /// Imports new family types into Revit - /// - /// - /// - /// New host types dictionary with newly imported types added (if applicable) - /// - public async Task ImportFamilyTypes(HostTypeContainer hostTypesContainer) - { - var familyPaths = await Dispatcher.UIThread.InvokeAsync(() => + /// + /// Imports new family types into Revit + /// + /// + /// + /// New host types dictionary with newly imported types added (if applicable) + /// + public async Task ImportFamilyTypes(HostTypeContainer hostTypesContainer) + { + var familyPaths = await Dispatcher.UIThread + .InvokeAsync(() => { using var windowsDialog = new OpenFileDialog { @@ -52,39 +58,47 @@ public async Task ImportFamilyTypes(HostTypeContainer hostTypesContainer) }; var _ = windowsDialog.ShowDialog(); return windowsDialog.FileNames; - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - if (familyPaths.Length == 0) return; + if (familyPaths.Length == 0) + { + return; + } - var allSymbols = new Dictionary>(); - var familyInfo = new Dictionary(); - await PopulateSymbolAndFamilyInfo(familyPaths, allSymbols, familyInfo).ConfigureAwait(false); + var allSymbols = new Dictionary>(); + var familyInfo = new Dictionary(); + await PopulateSymbolAndFamilyInfo(familyPaths, allSymbols, familyInfo).ConfigureAwait(false); - var vm = new ImportFamiliesDialogViewModel(allSymbols); - await Dispatcher.UIThread.InvokeAsync(async () => + var vm = new ImportFamiliesDialogViewModel(allSymbols); + await Dispatcher.UIThread + .InvokeAsync(async () => { - var importFamilies = new ImportFamiliesDialog - { - DataContext = vm - }; + var importFamilies = new ImportFamiliesDialog { DataContext = vm }; await importFamilies.ShowDialog().ConfigureAwait(true); - }).ConfigureAwait(false); - - if (vm.selectedFamilySymbols.Count == 0) - { - //close current dialog body - MainViewModel.CloseDialog(); - return; - } - - await ImportTypesIntoDocument(hostTypesContainer, familyInfo, vm).ConfigureAwait(false); + }) + .ConfigureAwait(false); + if (vm.selectedFamilySymbols.Count == 0) + { + //close current dialog body + MainViewModel.CloseDialog(); return; } - private async Task ImportTypesIntoDocument(HostTypeContainer hostTypesContainer, Dictionary familyInfo, ImportFamiliesDialogViewModel vm) - { - await APIContext.Run(_ => + await ImportTypesIntoDocument(hostTypesContainer, familyInfo, vm).ConfigureAwait(false); + + return; + } + + private async Task ImportTypesIntoDocument( + HostTypeContainer hostTypesContainer, + Dictionary familyInfo, + ImportFamiliesDialogViewModel vm + ) + { + await APIContext + .Run(_ => { using var t = new Transaction(document, $"Import family types"); @@ -93,9 +107,16 @@ await APIContext.Run(_ => var familyNameToCategoryMap = new Dictionary>(); foreach (var symbol in vm.selectedFamilySymbols) { - bool successfullyImported = document.LoadFamilySymbol(familyInfo[symbol.FamilyName].Path, symbol.Name, out var importedSymbol); + bool successfullyImported = document.LoadFamilySymbol( + familyInfo[symbol.FamilyName].Path, + symbol.Name, + out var importedSymbol + ); - if (!successfullyImported) continue; + if (!successfullyImported) + { + continue; + } // get all possible speckle-defined mapping categories that the newly imported symbol may belong to. // cache the values per each family that is imported @@ -124,157 +145,182 @@ await APIContext.Run(_ => foreach (var kvp in symbolsToLoad) { hostTypesContainer.AddTypesToCategory(kvp.Key, kvp.Value); - revitDocumentAggregateCache - .TryGetCacheOfType>()? - .Remove(kvp.Key); + revitDocumentAggregateCache.TryGetCacheOfType>()?.Remove(kvp.Key); } t.Commit(); - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary() { - { "name", "Type Map" }, - { "method", "Import Types" }, - { "count", vm.selectedFamilySymbols.Count }}); + Analytics.TrackEvent( + Analytics.Events.DUIAction, + new Dictionary() + { + { "name", "Type Map" }, + { "method", "Import Types" }, + { "count", vm.selectedFamilySymbols.Count } + } + ); } else { t.RollBack(); } - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - //close current dialog body - MainViewModel.CloseDialog(); - } + //close current dialog body + MainViewModel.CloseDialog(); + } - private async Task PopulateSymbolAndFamilyInfo(string[] familyPaths, Dictionary> allSymbols, Dictionary familyInfo) + private async Task PopulateSymbolAndFamilyInfo( + string[] familyPaths, + Dictionary> allSymbols, + Dictionary familyInfo + ) + { + foreach (var path in familyPaths) { - foreach (var path in familyPaths) - { - var xmlPath = path.Replace(".rfa", ".xml"); - string pathClone = string.Copy(path); + var xmlPath = path.Replace(".rfa", ".xml"); + string pathClone = string.Copy(path); - //open family file as xml to extract all family symbols without loading all of them into the project - await APIContext.Run(() => document.Application.ExtractPartAtomFromFamilyFile(path, xmlPath)) - .ConfigureAwait(false); - var xmlDoc = new XmlDocument(); // Create an XML document object - xmlDoc.Load(xmlPath); + //open family file as xml to extract all family symbols without loading all of them into the project + await APIContext + .Run(() => document.Application.ExtractPartAtomFromFamilyFile(path, xmlPath)) + .ConfigureAwait(false); + var xmlDoc = new XmlDocument(); // Create an XML document object + xmlDoc.Load(xmlPath); - var nsman = new XmlNamespaceManager(xmlDoc.NameTable); - nsman.AddNamespace("ab", "http://www.w3.org/2005/Atom"); + var nsman = new XmlNamespaceManager(xmlDoc.NameTable); + nsman.AddNamespace("ab", "http://www.w3.org/2005/Atom"); - string familyName = pathClone.Split('\\').LastOrDefault().Split('.').FirstOrDefault(); - if (string.IsNullOrEmpty(familyName)) - continue; + string familyName = pathClone.Split('\\').LastOrDefault().Split('.').FirstOrDefault(); + if (string.IsNullOrEmpty(familyName)) + { + continue; + } - var typeInfo = GetTypeInfo(xmlDoc, nsman); - familyInfo.Add(familyName, new FamilyInfo(path)); + var typeInfo = GetTypeInfo(xmlDoc, nsman); + familyInfo.Add(familyName, new FamilyInfo(path)); - var elementTypes = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory>() - .GetOrAddGroupOfTypes(typeInfo); - AddSymbolToAllSymbols(allSymbols, xmlDoc, nsman, familyName, elementTypes); + var elementTypes = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory>() + .GetOrAddGroupOfTypes(typeInfo); + AddSymbolToAllSymbols(allSymbols, xmlDoc, nsman, familyName, elementTypes); - // delete the newly created xml file - try - { - System.IO.File.Delete(xmlPath); - } - catch (Exception ex) - { } + // delete the newly created xml file + try + { + System.IO.File.Delete(xmlPath); } - - //close current dialog body - MainViewModel.CloseDialog(); + catch (Exception ex) { } } - private static void AddSymbolToAllSymbols(Dictionary> allSymbols, XmlDocument xmlDoc, XmlNamespaceManager nsman, string familyName, IEnumerable elementTypes) + //close current dialog body + MainViewModel.CloseDialog(); + } + + private static void AddSymbolToAllSymbols( + Dictionary> allSymbols, + XmlDocument xmlDoc, + XmlNamespaceManager nsman, + string familyName, + IEnumerable elementTypes + ) + { + var familyRoot = xmlDoc.GetElementsByTagName("A:family"); + if (familyRoot.Count != 1) { - var familyRoot = xmlDoc.GetElementsByTagName("A:family"); - if (familyRoot.Count != 1) - { - throw new SpeckleException($"Incorrect assumption of how the partAtom family format works for family named {familyName}"); - } + throw new SpeckleException( + $"Incorrect assumption of how the partAtom family format works for family named {familyName}" + ); + } - nsman.AddNamespace("A", familyRoot[0].NamespaceURI); - nsman.AddNamespace("ab", "http://www.w3.org/2005/Atom"); - var familySymbols = familyRoot[0].SelectNodes("A:part/ab:title", nsman); + nsman.AddNamespace("A", familyRoot[0].NamespaceURI); + nsman.AddNamespace("ab", "http://www.w3.org/2005/Atom"); + var familySymbols = familyRoot[0].SelectNodes("A:part/ab:title", nsman); - if (familySymbols.Count == 0) return; + if (familySymbols.Count == 0) + { + return; + } - if (!allSymbols.TryGetValue(familyName, out var symbols)) - { - symbols = new List(); - allSymbols[familyName] = symbols; - } + if (!allSymbols.TryGetValue(familyName, out var symbols)) + { + symbols = new List(); + allSymbols[familyName] = symbols; + } - var loadedSymbols = new HashSet(StringComparer.OrdinalIgnoreCase); - foreach (var elementType in elementTypes) + var loadedSymbols = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var elementType in elementTypes) + { + if (elementType.FamilyName == familyName) { - if (elementType.FamilyName == familyName) - { - loadedSymbols.Add(elementType.Name); - } + loadedSymbols.Add(elementType.Name); } + } - foreach (var symbol in familySymbols) + foreach (var symbol in familySymbols) + { + if (symbol is not XmlElement el) { - if (symbol is not XmlElement el) - { - continue; - } - - var isAlreadyLoaded = loadedSymbols.Contains(el.InnerText); - symbols.Add(new Symbol(el.InnerText, familyName, isAlreadyLoaded)); + continue; } + + var isAlreadyLoaded = loadedSymbols.Contains(el.InnerText); + symbols.Add(new Symbol(el.InnerText, familyName, isAlreadyLoaded)); } + } - private IRevitCategoryInfo GetTypeInfo(XmlDocument xmlDoc, XmlNamespaceManager nsman) + private IRevitCategoryInfo GetTypeInfo(XmlDocument xmlDoc, XmlNamespaceManager nsman) + { + var catRoot = xmlDoc.GetElementsByTagName("category"); + IRevitCategoryInfo category = SHC.Undefined; + foreach (var node in catRoot) { - var catRoot = xmlDoc.GetElementsByTagName("category"); - IRevitCategoryInfo category = SHC.Undefined; - foreach (var node in catRoot) + if (node is not XmlElement xmlNode) { - if (node is not XmlElement xmlNode) continue; + continue; + } - var term = xmlNode.SelectSingleNode("ab:term", nsman); - if (term == null) continue; + var term = xmlNode.SelectSingleNode("ab:term", nsman); + if (term == null) + { + continue; + } - category = revitCategoriesExposer.AllCategories.GetRevitCategoryInfo(term.InnerText); + category = revitCategoriesExposer.AllCategories.GetRevitCategoryInfo(term.InnerText); - if (category != SHC.Undefined) - break; + if (category != SHC.Undefined) + { + break; } - - return category; } - public IEnumerable GetRevitCategoryInfoOfFamilySymbol(FamilySymbol familySymbol) - { - var allPotentialMatches = SHC.All.Values - .Where(info => info.ElementTypeType == typeof(FamilySymbol)) - .ToList(); + return category; + } - var narrowerMatches = allPotentialMatches - .Where(info => info.ContainsRevitCategory(familySymbol.Category)); + public IEnumerable GetRevitCategoryInfoOfFamilySymbol(FamilySymbol familySymbol) + { + var allPotentialMatches = SHC.All.Values.Where(info => info.ElementTypeType == typeof(FamilySymbol)).ToList(); - if (narrowerMatches.Any()) - { - return narrowerMatches; - } - else - { - // because we know that none of the categories contain the revit category that we're looking for - // then filter out every match that has any defined category - return allPotentialMatches - .Where(info => info.BuiltInCategories.Count == 0); - } + var narrowerMatches = allPotentialMatches.Where(info => info.ContainsRevitCategory(familySymbol.Category)); + + if (narrowerMatches.Any()) + { + return narrowerMatches; + } + else + { + // because we know that none of the categories contain the revit category that we're looking for + // then filter out every match that has any defined category + return allPotentialMatches.Where(info => info.BuiltInCategories.Count == 0); } + } + + public class FamilyInfo + { + public string Path { get; set; } - public class FamilyInfo + public FamilyInfo(string path) { - public string Path { get; set; } - public FamilyInfo(string path) - { - Path = path; - } + Path = path; } } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/HostTypeContainer.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/HostTypeContainer.cs index b39cc5cdf9..49e364da98 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/HostTypeContainer.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/HostTypeContainer.cs @@ -5,43 +5,47 @@ using DesktopUI2.Models.TypeMappingOnReceive; using DesktopUI2.ViewModels; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +public class HostTypeContainer : IHostTypeContainer { - public class HostTypeContainer : IHostTypeContainer - { - private readonly Dictionary> categoryToTypes = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary> categoryToTypes = new(StringComparer.OrdinalIgnoreCase); - public void AddTypesToCategory(string category, IEnumerable newTypes) + public void AddTypesToCategory(string category, IEnumerable newTypes) + { + if (!categoryToTypes.TryGetValue(category, out HashSet existingTypes)) { - if (!categoryToTypes.TryGetValue(category, out HashSet existingTypes)) - { - existingTypes = new HashSet(); - categoryToTypes.Add(category, existingTypes); - } - foreach (var type in newTypes) - { - existingTypes.Add(type); - } + existingTypes = new HashSet(); + categoryToTypes.Add(category, existingTypes); } - public void AddCategoryWithTypesIfCategoryIsNew(string category, IEnumerable types) + foreach (var type in newTypes) { - if (categoryToTypes.ContainsKey(category)) return; - - categoryToTypes[category] = types.ToHashSet(); + existingTypes.Add(type); } + } - public ICollection GetTypesInCategory(string category) + public void AddCategoryWithTypesIfCategoryIsNew(string category, IEnumerable types) + { + if (categoryToTypes.ContainsKey(category)) { - return categoryToTypes[category]; + return; } - public ICollection GetAllTypes() - { - return categoryToTypes[TypeMappingOnReceiveViewModel.TypeCatMisc]; - } - public void SetAllTypes(IEnumerable types) - { - categoryToTypes[TypeMappingOnReceiveViewModel.TypeCatMisc] = types.ToHashSet(); - } + categoryToTypes[category] = types.ToHashSet(); + } + + public ICollection GetTypesInCategory(string category) + { + return categoryToTypes[category]; + } + + public ICollection GetAllTypes() + { + return categoryToTypes[TypeMappingOnReceiveViewModel.TypeCatMisc]; + } + + public void SetAllTypes(IEnumerable types) + { + categoryToTypes[TypeMappingOnReceiveViewModel.TypeCatMisc] = types.ToHashSet(); } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/RevitHostType.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/RevitHostType.cs index 2727a8f8a9..4ac4317382 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/RevitHostType.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/RevitHostType.cs @@ -1,32 +1,36 @@ using System.Text; using DesktopUI2.Models.TypeMappingOnReceive; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +internal class RevitHostType : HostType { - internal class RevitHostType : HostType + public RevitHostType(string hostFamilyName, string hostTypeName) + : base(hostTypeName) { - public RevitHostType(string hostFamilyName, string hostTypeName) : base(hostTypeName) - { - HostFamilyName = hostFamilyName; - } - public string HostFamilyName { get; } - private string _hostTypeDisplayName; - public override string HostTypeDisplayName + HostFamilyName = hostFamilyName; + } + + public string HostFamilyName { get; } + private string _hostTypeDisplayName; + public override string HostTypeDisplayName + { + get { - get + if (_hostTypeDisplayName != null) { - if (_hostTypeDisplayName != null) return _hostTypeDisplayName; - - var sb = new StringBuilder(); - if (!string.IsNullOrEmpty(HostFamilyName)) - { - sb.Append(HostFamilyName); - sb.Append(' '); - } - sb.Append(HostTypeName); - _hostTypeDisplayName = sb.ToString(); return _hostTypeDisplayName; } + + var sb = new StringBuilder(); + if (!string.IsNullOrEmpty(HostFamilyName)) + { + sb.Append(HostFamilyName); + sb.Append(' '); + } + sb.Append(HostTypeName); + _hostTypeDisplayName = sb.ToString(); + return _hostTypeDisplayName; } } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/RevitMappingValue.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/RevitMappingValue.cs index 5fe14e867d..e6c56feb30 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/RevitMappingValue.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/RevitMappingValue.cs @@ -5,31 +5,32 @@ using DesktopUI2.Models.TypeMappingOnReceive; using ReactiveUI; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +[DataContract] +public class RevitMappingValue : MappingValue { - [DataContract] - public class RevitMappingValue : MappingValue + public RevitMappingValue(string inType, ISingleHostType inGuess, string inFamily = null, bool inNewType = false) + : base(inType, inGuess, inNewType) { - public RevitMappingValue(string inType, ISingleHostType inGuess, string inFamily = null, bool inNewType = false) : base(inType, inGuess, inNewType) - { - IncomingFamily = inFamily; - } - [DataMember] - public string IncomingFamily { get; set; } + IncomingFamily = inFamily; + } + + [DataMember] + public string IncomingFamily { get; set; } - public override string IncomingTypeDisplayName + public override string IncomingTypeDisplayName + { + get { - get + var sb = new StringBuilder(); + if (!string.IsNullOrEmpty(IncomingFamily)) { - var sb = new StringBuilder(); - if (!string.IsNullOrEmpty(IncomingFamily)) - { - sb.Append(IncomingFamily); - sb.Append(' '); - } - sb.Append(IncomingType); - return sb.ToString(); + sb.Append(IncomingFamily); + sb.Append(' '); } + sb.Append(IncomingType); + return sb.ToString(); } } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/SingleCategoryMap.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/SingleCategoryMap.cs index 89f43f872b..aaa2bff052 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/SingleCategoryMap.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/SingleCategoryMap.cs @@ -4,41 +4,43 @@ using DesktopUI2.Models.TypeMappingOnReceive; using Speckle.Newtonsoft.Json; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +internal class SingleCategoryMap { - internal class SingleCategoryMap - { - private readonly string _category; - [JsonProperty] - private Dictionary mappingValues = new(StringComparer.OrdinalIgnoreCase); + private readonly string _category; - public SingleCategoryMap(string CategoryName) - { - _category = CategoryName; - } + [JsonProperty] + private Dictionary mappingValues = new(StringComparer.OrdinalIgnoreCase); - public void AddMappingValue(ISingleValueToMap mappingValue) - { - if (mappingValue is not RevitMappingValue revitMappingValue) - { - throw new ArgumentException($"the {nameof(AddMappingValue)} function is expecting to be passed a {nameof(RevitMappingValue)}, but was passed a value of type {mappingValue.GetType()}"); - } - this.mappingValues[UniqueTypeName(revitMappingValue.IncomingFamily, revitMappingValue.IncomingType)] = mappingValue; - } + public SingleCategoryMap(string CategoryName) + { + _category = CategoryName; + } - public bool TryGetMappingValue(string? incomingFamily, string incomingType, out ISingleValueToMap singleValueToMap) + public void AddMappingValue(ISingleValueToMap mappingValue) + { + if (mappingValue is not RevitMappingValue revitMappingValue) { - return mappingValues.TryGetValue(UniqueTypeName(incomingFamily, incomingType), out singleValueToMap); + throw new ArgumentException( + $"the {nameof(AddMappingValue)} function is expecting to be passed a {nameof(RevitMappingValue)}, but was passed a value of type {mappingValue.GetType()}" + ); } + this.mappingValues[UniqueTypeName(revitMappingValue.IncomingFamily, revitMappingValue.IncomingType)] = mappingValue; + } - public IEnumerable GetMappingValues() - { - return mappingValues.Values; - } + public bool TryGetMappingValue(string? incomingFamily, string incomingType, out ISingleValueToMap singleValueToMap) + { + return mappingValues.TryGetValue(UniqueTypeName(incomingFamily, incomingType), out singleValueToMap); + } - private static string UniqueTypeName(string? family, string type) - { - return $"{family}{type}"; - } + public IEnumerable GetMappingValues() + { + return mappingValues.Values; + } + + private static string UniqueTypeName(string? family, string type) + { + return $"{family}{type}"; } } diff --git a/ConnectorRevit/ConnectorRevit/TypeMapping/TypeMap.cs b/ConnectorRevit/ConnectorRevit/TypeMapping/TypeMap.cs index e72c1ab61c..a7bef36b00 100644 --- a/ConnectorRevit/ConnectorRevit/TypeMapping/TypeMap.cs +++ b/ConnectorRevit/ConnectorRevit/TypeMapping/TypeMap.cs @@ -6,110 +6,130 @@ using Speckle.Core.Models; using Speckle.Newtonsoft.Json; -namespace ConnectorRevit.TypeMapping +namespace ConnectorRevit.TypeMapping; + +public class TypeMap : ITypeMap { - public class TypeMap : ITypeMap + public IEnumerable Categories => categoryToCategoryMap.Keys; + + [JsonProperty] + private Dictionary categoryToCategoryMap = new(); + + [JsonIgnore] + private Dictionary baseToMappingValue = new(); + + [JsonIgnore] + private HashSet baseIds = new(); + + public void AddIncomingType( + Base @base, + string incomingType, + string? incomingFamily, + string category, + ISingleHostType initialGuess + ) { - public IEnumerable Categories => categoryToCategoryMap.Keys; - [JsonProperty] - private Dictionary categoryToCategoryMap = new(); - [JsonIgnore] - private Dictionary baseToMappingValue = new(); - [JsonIgnore] - private HashSet baseIds = new(); - - public void AddIncomingType(Base @base, string incomingType, string? incomingFamily, string category, ISingleHostType initialGuess) + if (baseIds.Contains(@base.id)) { - if (baseIds.Contains(@base.id)) return; - baseIds.Add(@base.id); + return; + } - // add empty category if it isn't already present - if (!categoryToCategoryMap.TryGetValue(category, out var categoryMappingValues)) - { - categoryMappingValues = new SingleCategoryMap(category); - categoryToCategoryMap[category] = categoryMappingValues; - } + baseIds.Add(@base.id); - if (!categoryMappingValues.TryGetMappingValue(incomingFamily, incomingType, out var singleValueToMap)) - { - singleValueToMap = new RevitMappingValue(incomingType, initialGuess, incomingFamily, true); - categoryMappingValues.AddMappingValue(singleValueToMap); - } + // add empty category if it isn't already present + if (!categoryToCategoryMap.TryGetValue(category, out var categoryMappingValues)) + { + categoryMappingValues = new SingleCategoryMap(category); + categoryToCategoryMap[category] = categoryMappingValues; + } - baseToMappingValue.Add(@base, singleValueToMap); + if (!categoryMappingValues.TryGetMappingValue(incomingFamily, incomingType, out var singleValueToMap)) + { + singleValueToMap = new RevitMappingValue(incomingType, initialGuess, incomingFamily, true); + categoryMappingValues.AddMappingValue(singleValueToMap); + } + + baseToMappingValue.Add(@base, singleValueToMap); + } + + public bool HasCategory(string category) + { + return categoryToCategoryMap.ContainsKey(category); + } + + public IEnumerable GetValuesToMapOfCategory(string category) + { + if (!categoryToCategoryMap.TryGetValue(category, out var singleCategoryMap)) + { + return Enumerable.Empty(); } - public bool HasCategory(string category) + return singleCategoryMap.GetMappingValues(); + } + + public IEnumerable<(Base, ISingleValueToMap)> GetAllBasesWithMappings() + { + foreach (var kvp in baseToMappingValue) { - return categoryToCategoryMap.ContainsKey(category); + yield return (kvp.Key, kvp.Value); } + } - public IEnumerable GetValuesToMapOfCategory(string category) + public ISingleValueToMap? TryGetMappingValueInCategory(string category, string? incomingFamily, string incomingType) + { + if (!categoryToCategoryMap.TryGetValue(category, out var singleCategoryMap)) { - if (!categoryToCategoryMap.TryGetValue(category, out var singleCategoryMap)) - { - return Enumerable.Empty(); - } + return null; + } - return singleCategoryMap.GetMappingValues(); + if (!singleCategoryMap.TryGetMappingValue(incomingFamily, incomingType, out var singleValueToMap)) + { + return null; } - public IEnumerable<(Base,ISingleValueToMap)> GetAllBasesWithMappings() + return singleValueToMap; + } + + public void AddTypeMap(TypeMap typeMap) + { + foreach (var kvp in typeMap.categoryToCategoryMap) { - foreach (var kvp in baseToMappingValue) - { - yield return (kvp.Key, kvp.Value); - } + AddAllMappingValuesInCategory(kvp.Key, kvp.Value); } + } - public ISingleValueToMap? TryGetMappingValueInCategory(string category, string? incomingFamily, string incomingType) + private void AddAllMappingValuesInCategory(string category, SingleCategoryMap singleCategoryMap) + { + foreach (var mapping in singleCategoryMap.GetMappingValues()) { - if (!categoryToCategoryMap.TryGetValue(category, out var singleCategoryMap)) + if (mapping is not RevitMappingValue revitMappingValue) { - return null; + throw new ArgumentException( + $"expected a {nameof(RevitMappingValue)}, but was passed a value of type {mapping.GetType()}" + ); } - if (!singleCategoryMap.TryGetMappingValue(incomingFamily, incomingType, out var singleValueToMap)) + // add empty category if it isn't already present + if (!categoryToCategoryMap.TryGetValue(category, out var categoryMappingValues)) { - return null; + categoryMappingValues = new SingleCategoryMap(category); + categoryToCategoryMap[category] = categoryMappingValues; } - return singleValueToMap; - } - - public void AddTypeMap(TypeMap typeMap) - { - foreach (var kvp in typeMap.categoryToCategoryMap) + if ( + !categoryMappingValues.TryGetMappingValue( + revitMappingValue.IncomingFamily, + revitMappingValue.IncomingType, + out var existingMappingValue + ) + ) { - AddAllMappingValuesInCategory(kvp.Key, kvp.Value); + categoryMappingValues.AddMappingValue(revitMappingValue); } - } - - private void AddAllMappingValuesInCategory(string category, SingleCategoryMap singleCategoryMap) - { - foreach (var mapping in singleCategoryMap.GetMappingValues()) + else { - if (mapping is not RevitMappingValue revitMappingValue) - { - throw new ArgumentException($"expected a {nameof(RevitMappingValue)}, but was passed a value of type {mapping.GetType()}"); - } - - // add empty category if it isn't already present - if (!categoryToCategoryMap.TryGetValue(category, out var categoryMappingValues)) - { - categoryMappingValues = new SingleCategoryMap(category); - categoryToCategoryMap[category] = categoryMappingValues; - } - - if (!categoryMappingValues.TryGetMappingValue(revitMappingValue.IncomingFamily, revitMappingValue.IncomingType, out var existingMappingValue)) - { - categoryMappingValues.AddMappingValue(revitMappingValue); - } - else - { - existingMappingValue.InitialGuess = revitMappingValue.InitialGuess; - existingMappingValue.MappedHostType = revitMappingValue.MappedHostType; - } + existingMappingValue.InitialGuess = revitMappingValue.InitialGuess; + existingMappingValue.MappedHostType = revitMappingValue.MappedHostType; } } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Events.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Events.cs index 5bf28ceb53..ed0c95aa5e 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Events.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Events.cs @@ -16,369 +16,382 @@ using Speckle.Core.Logging; using Speckle.Core.Models; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit + private string _lastSyncComment { get; set; } + + public override async void WriteStreamsToFile(List streams) { - private string _lastSyncComment { get; set; } - public override async void WriteStreamsToFile(List streams) + try { - try - { - await APIContext.Run( - app => + await APIContext + .Run(app => + { + using (Transaction t = new(CurrentDoc.Document, "Speckle Write State")) { - using (Transaction t = new Transaction(CurrentDoc.Document, "Speckle Write State")) - { - t.Start(); - StreamStateManager.WriteStreamStateList(CurrentDoc.Document, streams); - t.Commit(); - } - - }).ConfigureAwait(false); - } - catch (Exception ex) - { - SpeckleLog.Logger.Fatal( - ex, - "Swallowing exception in {methodName}: {exceptionMessage}", - nameof(WriteStreamsToFile), - ex.Message - ); - } + t.Start(); + StreamStateManager.WriteStreamStateList(CurrentDoc.Document, streams); + t.Commit(); + } + }) + .ConfigureAwait(false); } - - /// - /// Sets the revit external event handler and initialises the rocket engines. - /// - /// - public void RegisterAppEvents() + catch (Exception ex) { - - //// GLOBAL EVENT HANDLERS - RevitApp.ViewActivated += RevitApp_ViewActivated; - //RevitApp.Application.DocumentChanged += Application_DocumentChanged; - RevitApp.Application.DocumentCreated += Application_DocumentCreated; - RevitApp.Application.DocumentCreating += Application_DocumentCreating; - RevitApp.Application.DocumentOpened += Application_DocumentOpened; - RevitApp.Application.DocumentOpening += Application_DocumentOpening; ; - RevitApp.Application.DocumentClosed += Application_DocumentClosed; - RevitApp.Application.DocumentSaved += Application_DocumentSaved; - RevitApp.Application.DocumentSynchronizingWithCentral += Application_DocumentSynchronizingWithCentral; - RevitApp.Application.DocumentSynchronizedWithCentral += Application_DocumentSynchronizedWithCentral; - RevitApp.Application.FileExported += Application_FileExported; - RevitApp.ApplicationClosing += RevitApp_ApplicationClosing; - //RevitApp.Application.FileExporting += Application_FileExporting; - //RevitApp.Application.FileImporting += Application_FileImporting; - //SelectionTimer = new Timer(1400) { AutoReset = true, Enabled = true }; - //SelectionTimer.Elapsed += SelectionTimer_Elapsed; - // TODO: Find a way to handle when document is closed via middle mouse click - // thus triggering the focus on a new project + SpeckleLog.Logger.Fatal( + ex, + "Swallowing exception in {methodName}: {exceptionMessage}", + nameof(WriteStreamsToFile), + ex.Message + ); } + } - private void RevitApp_ApplicationClosing(object sender, Autodesk.Revit.UI.Events.ApplicationClosingEventArgs e) - { - if (HomeViewModel.Instance == null) - return; - - - ///ensure WS connections etc are disposed, otherwise it might throw - HomeViewModel.Instance.SavedStreams.ForEach(s => s.Dispose()); - } + /// + /// Sets the revit external event handler and initialises the rocket engines. + /// + /// + public void RegisterAppEvents() + { + //// GLOBAL EVENT HANDLERS + RevitApp.ViewActivated += RevitApp_ViewActivated; + //RevitApp.Application.DocumentChanged += Application_DocumentChanged; + RevitApp.Application.DocumentCreated += Application_DocumentCreated; + RevitApp.Application.DocumentCreating += Application_DocumentCreating; + RevitApp.Application.DocumentOpened += Application_DocumentOpened; + RevitApp.Application.DocumentOpening += Application_DocumentOpening; + ; + RevitApp.Application.DocumentClosed += Application_DocumentClosed; + RevitApp.Application.DocumentSaved += Application_DocumentSaved; + RevitApp.Application.DocumentSynchronizingWithCentral += Application_DocumentSynchronizingWithCentral; + RevitApp.Application.DocumentSynchronizedWithCentral += Application_DocumentSynchronizedWithCentral; + RevitApp.Application.FileExported += Application_FileExported; + RevitApp.ApplicationClosing += RevitApp_ApplicationClosing; + //RevitApp.Application.FileExporting += Application_FileExporting; + //RevitApp.Application.FileImporting += Application_FileImporting; + //SelectionTimer = new Timer(1400) { AutoReset = true, Enabled = true }; + //SelectionTimer.Elapsed += SelectionTimer_Elapsed; + // TODO: Find a way to handle when document is closed via middle mouse click + // thus triggering the focus on a new project + } - //DISABLED - private void Application_FileExporting(object sender, FileExportingEventArgs e) + private void RevitApp_ApplicationClosing(object sender, Autodesk.Revit.UI.Events.ApplicationClosingEventArgs e) + { + if (HomeViewModel.Instance == null) { - ShowImportExportAlert(); + return; } - //DISABLED - private void Application_FileImporting(object sender, FileImportingEventArgs e) - { - ShowImportExportAlert(); - } + ///ensure WS connections etc are disposed, otherwise it might throw + HomeViewModel.Instance.SavedStreams.ForEach(s => s.Dispose()); + } + + //DISABLED + private void Application_FileExporting(object sender, FileExportingEventArgs e) + { + ShowImportExportAlert(); + } - private void ShowImportExportAlert() + //DISABLED + private void Application_FileImporting(object sender, FileImportingEventArgs e) + { + ShowImportExportAlert(); + } + + private void ShowImportExportAlert() + { + var config = ConfigManager.Load(); + if (config.ShowImportExportAlert) { - var config = ConfigManager.Load(); - if (config.ShowImportExportAlert) + Analytics.TrackEvent(Analytics.Events.ImportExportAlert, new Dictionary() { { "name", "Show" } }); + var dialog = new ImportExportAlert(); + dialog.LaunchAction = () => { - Analytics.TrackEvent(Analytics.Events.ImportExportAlert, new Dictionary() { { "name", "Show" } }); - var dialog = new ImportExportAlert(); - dialog.LaunchAction = () => + try { - try - { - SpeckleRevitCommand.RegisterPane(); - var panel = App.AppInstance.GetDockablePane(SpeckleRevitCommand.PanelId); - panel.Show(); - } - catch (Exception ex) - { - SpeckleLog.Logger.Fatal( - ex, - "Swallowing exception in {methodName}: {exceptionMessage}", - nameof(ShowImportExportAlert), - ex.Message - ); - } - }; - dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen; - dialog.Show(); - dialog.Topmost = true; - } + SpeckleRevitCommand.RegisterPane(); + var panel = App.AppInstance.GetDockablePane(SpeckleRevitCommand.PanelId); + panel.Show(); + } + catch (Exception ex) + { + SpeckleLog.Logger.Fatal( + ex, + "Swallowing exception in {methodName}: {exceptionMessage}", + nameof(ShowImportExportAlert), + ex.Message + ); + } + }; + dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen; + dialog.Show(); + dialog.Topmost = true; } + } - private void Application_DocumentOpening(object sender, Autodesk.Revit.DB.Events.DocumentOpeningEventArgs e) - { - - } + private void Application_DocumentOpening(object sender, Autodesk.Revit.DB.Events.DocumentOpeningEventArgs e) { } - private void Application_DocumentCreating(object sender, Autodesk.Revit.DB.Events.DocumentCreatingEventArgs e) - { - } + private void Application_DocumentCreating(object sender, Autodesk.Revit.DB.Events.DocumentCreatingEventArgs e) { } - private void Application_FileExported(object sender, Autodesk.Revit.DB.Events.FileExportedEventArgs e) - { - SendScheduledStream("export"); - } + private void Application_FileExported(object sender, Autodesk.Revit.DB.Events.FileExportedEventArgs e) + { + SendScheduledStream("export"); + } - private void Application_DocumentSynchronizingWithCentral(object sender, Autodesk.Revit.DB.Events.DocumentSynchronizingWithCentralEventArgs e) - { - _lastSyncComment = e.Comments; - } + private void Application_DocumentSynchronizingWithCentral( + object sender, + Autodesk.Revit.DB.Events.DocumentSynchronizingWithCentralEventArgs e + ) + { + _lastSyncComment = e.Comments; + } - private void Application_DocumentSynchronizedWithCentral(object sender, Autodesk.Revit.DB.Events.DocumentSynchronizedWithCentralEventArgs e) - { - SendScheduledStream("sync", _lastSyncComment); - } + private void Application_DocumentSynchronizedWithCentral( + object sender, + Autodesk.Revit.DB.Events.DocumentSynchronizedWithCentralEventArgs e + ) + { + SendScheduledStream("sync", _lastSyncComment); + } - private void Application_DocumentSaved(object sender, Autodesk.Revit.DB.Events.DocumentSavedEventArgs e) - { - SendScheduledStream("save"); - } + private void Application_DocumentSaved(object sender, Autodesk.Revit.DB.Events.DocumentSavedEventArgs e) + { + SendScheduledStream("save"); + } - private async void SendScheduledStream(string slug, string message = "") + private async void SendScheduledStream(string slug, string message = "") + { + try { - try + var stream = GetStreamsInFile().FirstOrDefault(x => x.SchedulerEnabled && x.SchedulerTrigger == slug); + if (stream == null) { - var stream = GetStreamsInFile().FirstOrDefault(x => x.SchedulerEnabled && x.SchedulerTrigger == slug); - if (stream == null) return; - - var progress = new ProgressViewModel(); - progress.ProgressTitle = "Sending to Speckle 🚀"; - progress.IsProgressing = true; - - var dialog = new QuickOpsDialog(); - dialog.DataContext = progress; - dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen; - dialog.Topmost = true; - dialog.Show(); - - if (message != null) - stream.CommitMessage = message; - - await Task.Run(() => SendStream(stream, progress)); - progress.IsProgressing = false; - dialog.Close(); - if (!progress.CancellationToken.IsCancellationRequested) - { - Analytics.TrackEvent(stream.Client.Account, Analytics.Events.Send, new Dictionary() { { "method", "Schedule" }, { "filter", stream.Filter.Name } }); - } - + return; } - catch (Exception ex) + + var progress = new ProgressViewModel(); + progress.ProgressTitle = "Sending to Speckle 🚀"; + progress.IsProgressing = true; + + var dialog = new QuickOpsDialog(); + dialog.DataContext = progress; + dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen; + dialog.Topmost = true; + dialog.Show(); + + if (message != null) { + stream.CommitMessage = message; + } + await Task.Run(() => SendStream(stream, progress)); + progress.IsProgressing = false; + dialog.Close(); + if (!progress.CancellationToken.IsCancellationRequested) + { + Analytics.TrackEvent( + stream.Client.Account, + Analytics.Events.Send, + new Dictionary() { { "method", "Schedule" }, { "filter", stream.Filter.Name } } + ); } } + catch (Exception ex) { } + } - - //checks whether to refresh the stream list in case the user changes active view and selects a different document - private void RevitApp_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e) + //checks whether to refresh the stream list in case the user changes active view and selects a different document + private void RevitApp_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e) + { + try { - try + if ( + e.Document == null + || e.PreviousActiveView == null + || e.Document.GetHashCode() == e.PreviousActiveView.Document.GetHashCode() + ) { - if (e.Document == null || e.PreviousActiveView == null || e.Document.GetHashCode() == e.PreviousActiveView.Document.GetHashCode()) - return; - - // if the dialog body is open, then avalonia will freak out and crash Revit when trying to re-initialize - // so we need to close the dialog and cancel any ongoing send / receive operation. (Maybe we can somehow - // save the operation state and let the user come back to it later) - if (MainViewModel.Instance.DialogBody != null) - { - CurrentOperationCancellation?.Cancel(); - MainViewModel.CloseDialog(); - } - - // invalidate all revit elements in the cache - revitDocumentAggregateCache.InvalidateAll(); + return; + } - SpeckleRevitCommand.RegisterPane(); + // if the dialog body is open, then avalonia will freak out and crash Revit when trying to re-initialize + // so we need to close the dialog and cancel any ongoing send / receive operation. (Maybe we can somehow + // save the operation state and let the user come back to it later) + if (MainViewModel.Instance.DialogBody != null) + { + CurrentOperationCancellation?.Cancel(); + MainViewModel.CloseDialog(); + } - var streams = GetStreamsInFile(); - UpdateSavedStreams(streams); + // invalidate all revit elements in the cache + revitDocumentAggregateCache.InvalidateAll(); - MainViewModel.Instance.NavigateToDefaultScreen(); - } - catch (Exception ex) - { + SpeckleRevitCommand.RegisterPane(); - } + var streams = GetStreamsInFile(); + UpdateSavedStreams(streams); + MainViewModel.Instance.NavigateToDefaultScreen(); } + catch (Exception ex) { } + } - private void Application_DocumentClosed(object sender, Autodesk.Revit.DB.Events.DocumentClosedEventArgs e) + private void Application_DocumentClosed(object sender, Autodesk.Revit.DB.Events.DocumentClosedEventArgs e) + { + try { - try + // the DocumentClosed event is triggered AFTER ViewActivated + // is both doc A and B are open and B is closed, this would result in wiping the list of streams retrieved for A + // only proceed if it's the last document open (the current is null) + if (CurrentDoc != null) { - // the DocumentClosed event is triggered AFTER ViewActivated - // is both doc A and B are open and B is closed, this would result in wiping the list of streams retrieved for A - // only proceed if it's the last document open (the current is null) - if (CurrentDoc != null) - return; - - //if (SpeckleRevitCommand2.MainWindow != null) - // SpeckleRevitCommand2.MainWindow.Hide(); + return; + } - //clear saved streams if closig a doc - if (UpdateSavedStreams != null) - UpdateSavedStreams(new List()); + //if (SpeckleRevitCommand2.MainWindow != null) + // SpeckleRevitCommand2.MainWindow.Hide(); - MainViewModel.Instance.NavigateToDefaultScreen(); - } - catch (Exception ex) + //clear saved streams if closig a doc + if (UpdateSavedStreams != null) { - + UpdateSavedStreams(new List()); } + + MainViewModel.Instance.NavigateToDefaultScreen(); } + catch (Exception ex) { } + } - // this method is triggered when there are changes in the active document - private void Application_DocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs e) - { } - private void Application_DocumentCreated(object sender, Autodesk.Revit.DB.Events.DocumentCreatedEventArgs e) - { - SpeckleRevitCommand.RegisterPane(); + // this method is triggered when there are changes in the active document + private void Application_DocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs e) { } - //clear saved streams if opening a new doc - if (UpdateSavedStreams != null) - UpdateSavedStreams(new List()); - } + private void Application_DocumentCreated(object sender, Autodesk.Revit.DB.Events.DocumentCreatedEventArgs e) + { + SpeckleRevitCommand.RegisterPane(); - private void Application_DocumentOpened(object sender, Autodesk.Revit.DB.Events.DocumentOpenedEventArgs e) + //clear saved streams if opening a new doc + if (UpdateSavedStreams != null) { + UpdateSavedStreams(new List()); + } + } - var streams = GetStreamsInFile(); - if (streams != null && streams.Count != 0) + private void Application_DocumentOpened(object sender, Autodesk.Revit.DB.Events.DocumentOpenedEventArgs e) + { + var streams = GetStreamsInFile(); + if (streams != null && streams.Count != 0) + { + if (SpeckleRevitCommand.UseDockablePanel) { - if (SpeckleRevitCommand.UseDockablePanel) - { - SpeckleRevitCommand.RegisterPane(); - var panel = App.AppInstance.GetDockablePane(SpeckleRevitCommand.PanelId); - panel.Show(); - } - else - SpeckleRevitCommand.CreateOrFocusSpeckle(); + SpeckleRevitCommand.RegisterPane(); + var panel = App.AppInstance.GetDockablePane(SpeckleRevitCommand.PanelId); + panel.Show(); } - if (UpdateSavedStreams != null) - UpdateSavedStreams(streams); - - //exit "stream view" when changing documents - MainViewModel.Instance.NavigateToDefaultScreen(); + else + { + SpeckleRevitCommand.CreateOrFocusSpeckle(); + } + } + if (UpdateSavedStreams != null) + { + UpdateSavedStreams(streams); } + //exit "stream view" when changing documents + MainViewModel.Instance.NavigateToDefaultScreen(); + } - public override bool CanOpen3DView => true; + public override bool CanOpen3DView => true; - public override async Task Open3DView(List viewCoordinates, string viewName = "") + public override async Task Open3DView(List viewCoordinates, string viewName = "") + { + try { - try + var views = new FilteredElementCollector(CurrentDoc.Document).OfClass(typeof(View3D)).ToElements().Cast(); + var viewtypes = new FilteredElementCollector(CurrentDoc.Document) + .OfClass(typeof(ViewFamilyType)) + .ToElements() + .Cast() + .Where(x => x.ViewFamily == ViewFamily.ThreeDimensional); + + //hacky but the current comments camera is not a Base object + //so it cannot be passed automatically to the converter + //making a dummy one here + var speckleCamera = new Base(); + speckleCamera["isHackySpeckleCamera"] = true; + speckleCamera["coordinates"] = viewCoordinates; + + //when in a perspective view, it's not possible to open any transaction (txs adsk) + //so we're switching to any other non perspective view here + if (CurrentDoc.ActiveView.ViewType == ViewType.ThreeD) { - var views = new FilteredElementCollector(CurrentDoc.Document).OfClass(typeof(View3D)).ToElements().Cast(); - var viewtypes = new FilteredElementCollector(CurrentDoc.Document).OfClass(typeof(ViewFamilyType)) - .ToElements() - .Cast() - .Where(x => x.ViewFamily == ViewFamily.ThreeDimensional); - - //hacky but the current comments camera is not a Base object - //so it cannot be passed automatically to the converter - //making a dummy one here - var speckleCamera = new Base(); - speckleCamera["isHackySpeckleCamera"] = true; - speckleCamera["coordinates"] = viewCoordinates; - - - //when in a perspective view, it's not possible to open any transaction (txs adsk) - //so we're switching to any other non perspective view here - if (CurrentDoc.ActiveView.ViewType == ViewType.ThreeD) + var activeView = CurrentDoc.ActiveView as View3D; + if (activeView.IsPerspective) { - var activeView = CurrentDoc.ActiveView as View3D; - if (activeView.IsPerspective) + var nonPerspectiveView = views.FirstOrDefault(x => !x.IsPerspective); + if (nonPerspectiveView != null) { - var nonPerspectiveView = views.FirstOrDefault(x => !x.IsPerspective); - if (nonPerspectiveView != null) - CurrentDoc.ActiveView = nonPerspectiveView; + CurrentDoc.ActiveView = nonPerspectiveView; } - } + } - var perspView = views.FirstOrDefault(o => o.Name == "SpeckleCommentView"); + var perspView = views.FirstOrDefault(o => o.Name == "SpeckleCommentView"); - await APIContext.Run(app => + await APIContext.Run(app => + { + using (var t = new Transaction(CurrentDoc.Document, $"Open Comment View")) { + t.Start(); - using (var t = new Transaction(CurrentDoc.Document, $"Open Comment View")) - { - t.Start(); - - var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); - converter.SetContextDocument(CurrentDoc.Document); - var viewOrientation3D = converter.ConvertToNative(speckleCamera) as ViewOrientation3D; + var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); + converter.SetContextDocument(CurrentDoc.Document); + var viewOrientation3D = converter.ConvertToNative(speckleCamera) as ViewOrientation3D; - //txs bcfier - if (perspView == null) - { - perspView = View3D.CreatePerspective(CurrentDoc.Document, viewtypes.First().Id); - perspView.Name = "SpeckleCommentView"; - } - perspView.SetOrientation(viewOrientation3D); - perspView.CropBoxActive = false; - perspView.CropBoxVisible = false; - perspView.DisplayStyle = DisplayStyle.Shading; + //txs bcfier + if (perspView == null) + { + perspView = View3D.CreatePerspective(CurrentDoc.Document, viewtypes.First().Id); + perspView.Name = "SpeckleCommentView"; + } + perspView.SetOrientation(viewOrientation3D); + perspView.CropBoxActive = false; + perspView.CropBoxVisible = false; + perspView.DisplayStyle = DisplayStyle.Shading; - // the default phase was not looking good, picking the one of the View3D - if (views.Any()) + // the default phase was not looking good, picking the one of the View3D + if (views.Any()) + { + var viewPhase = views.First().get_Parameter(BuiltInParameter.VIEW_PHASE); + if (viewPhase != null) { - var viewPhase = views.First().get_Parameter(BuiltInParameter.VIEW_PHASE); - if (viewPhase != null) - { - perspView.get_Parameter(BuiltInParameter.VIEW_PHASE).Set(viewPhase.AsElementId()); - } + perspView.get_Parameter(BuiltInParameter.VIEW_PHASE).Set(viewPhase.AsElementId()); } - - t.Commit(); } - // needs to be outside the transaction - CurrentDoc.ActiveView = perspView; - // "refresh" the active view, txs Connor - var uiView = CurrentDoc.GetOpenUIViews().FirstOrDefault(uv => uv.ViewId.Equals(perspView.Id)); - uiView.Zoom(1); - }); - //needed to force refresh the active view - - - } - catch (Exception ex) - { - SpeckleLog.Logger.Error(ex, "Failed to open view"); - MainUserControl.NotificationManager.Show(new PopUpNotificationViewModel() + t.Commit(); + } + // needs to be outside the transaction + CurrentDoc.ActiveView = perspView; + // "refresh" the active view, txs Connor + var uiView = CurrentDoc.GetOpenUIViews().FirstOrDefault(uv => uv.ViewId.Equals(perspView.Id)); + uiView.Zoom(1); + }); + + //needed to force refresh the active view + } + catch (Exception ex) + { + SpeckleLog.Logger.Error(ex, "Failed to open view"); + MainUserControl.NotificationManager.Show( + new PopUpNotificationViewModel() { Title = "📷 Open View Error", Message = $"Could not open the view: {ex.Message}", Type = Avalonia.Controls.Notifications.NotificationType.Error - }); - } + } + ); } } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Previews.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Previews.cs index d81e4cdcc1..dbd90b3eb0 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Previews.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Previews.cs @@ -17,153 +17,169 @@ using RevitSharedResources.Models; using ConnectorRevit.Revit; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit - { - public override bool CanPreviewReceive => false; - private string SelectedReceiveCommit { get; set; } - List m_servers = new List(); + public override bool CanPreviewReceive => false; + private string SelectedReceiveCommit { get; set; } + List m_servers = new(); - public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + { + try { - try + // first check if commit is the same and preview objects have already been generated + Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + progress.Report = new ProgressReport(); + + if (commit.id != SelectedReceiveCommit) { - // first check if commit is the same and preview objects have already been generated - Commit commit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - progress.Report = new ProgressReport(); + // check for converter + var converter = KitManager.GetDefaultKit().LoadConverter(ConnectorRevitUtils.RevitAppName); + converter.SetContextDocument(CurrentDoc.Document); - if (commit.id != SelectedReceiveCommit) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - // check for converter - var converter = KitManager.GetDefaultKit().LoadConverter(ConnectorRevitUtils.RevitAppName); - converter.SetContextDocument(CurrentDoc.Document); - - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - - settings["preview"] = "true"; - converter.SetConverterSettings(settings); + settings.Add(setting.Slug, setting.Selection); + } - var commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); + settings["preview"] = "true"; + converter.SetConverterSettings(settings); - Preview.Clear(); - StoredObjects.Clear(); + var commitObject = await ConnectorHelpers.ReceiveCommit(commit, state, progress); - Preview = FlattenCommitObject(commitObject, converter); - foreach (var previewObj in Preview) - progress.Report.Log(previewObj); + Preview.Clear(); + StoredObjects.Clear(); - IConvertedObjectsCache convertedObjects = null; - await APIContext - .Run(app => - { - using (var t = new Transaction(CurrentDoc.Document, $"Baking stream {state.StreamId}")) - { - t.Start(); - convertedObjects = ConvertReceivedObjects(converter, progress, new TransactionManager(null, null)); - t.Commit(); - } - - AddMultipleRevitElementServers(convertedObjects); - }) - .ConfigureAwait(false); - } - else // just generate the log + Preview = FlattenCommitObject(commitObject, converter); + foreach (var previewObj in Preview) { - foreach (var previewObj in Preview) - progress.Report.Log(previewObj); + progress.Report.Log(previewObj); } + + IConvertedObjectsCache convertedObjects = null; + await APIContext + .Run(app => + { + using (var t = new Transaction(CurrentDoc.Document, $"Baking stream {state.StreamId}")) + { + t.Start(); + convertedObjects = ConvertReceivedObjects(converter, progress, new TransactionManager(null, null)); + t.Commit(); + } + + AddMultipleRevitElementServers(convertedObjects); + }) + .ConfigureAwait(false); } - catch (Exception ex) + else // just generate the log { - SpeckleLog.Logger.Error(ex, "Failed to preview receive: {exceptionMessage}", ex.Message); + foreach (var previewObj in Preview) + { + progress.Report.Log(previewObj); + } } - - return null; } - - public override void ResetDocument() + catch (Exception ex) { - UnregisterServers(); + SpeckleLog.Logger.Error(ex, "Failed to preview receive: {exceptionMessage}", ex.Message); } - public void AddMultipleRevitElementServers(IConvertedObjectsCache convertedObjects) - { - ExternalService directContext3DService = ExternalServiceRegistry.GetService( - ExternalServices.BuiltInExternalServices.DirectContext3DService - ); - MultiServerService msDirectContext3DService = directContext3DService as MultiServerService; - IList serverIds = msDirectContext3DService.GetActiveServerIds(); + return null; + } - foreach (var obj in convertedObjects.GetConvertedObjects()) - { - if (obj is not IDirectContext3DServer server) - continue; + public override void ResetDocument() + { + UnregisterServers(); + } - directContext3DService.AddServer(server); - m_servers.Add(server); - serverIds.Add(server.GetServerId()); - //RefreshView(); - } + public void AddMultipleRevitElementServers(IConvertedObjectsCache convertedObjects) + { + ExternalService directContext3DService = ExternalServiceRegistry.GetService( + ExternalServices.BuiltInExternalServices.DirectContext3DService + ); + MultiServerService msDirectContext3DService = directContext3DService as MultiServerService; + IList serverIds = msDirectContext3DService.GetActiveServerIds(); - msDirectContext3DService.SetActiveServers(serverIds); + foreach (var obj in convertedObjects.GetConvertedObjects()) + { + if (obj is not IDirectContext3DServer server) + { + continue; + } - //m_documents.Add(uidoc.Document); - CurrentDoc.UpdateAllOpenViews(); + directContext3DService.AddServer(server); + m_servers.Add(server); + serverIds.Add(server.GetServerId()); + //RefreshView(); } - public void UnregisterServers() + msDirectContext3DService.SetActiveServers(serverIds); + + //m_documents.Add(uidoc.Document); + CurrentDoc.UpdateAllOpenViews(); + } + + public void UnregisterServers() + { + ExternalServiceId externalDrawerServiceId = ExternalServices.BuiltInExternalServices.DirectContext3DService; + var externalDrawerService = ExternalServiceRegistry.GetService(externalDrawerServiceId) as MultiServerService; + if (externalDrawerService == null) { - ExternalServiceId externalDrawerServiceId = ExternalServices.BuiltInExternalServices.DirectContext3DService; - var externalDrawerService = ExternalServiceRegistry.GetService(externalDrawerServiceId) as MultiServerService; - if (externalDrawerService == null) - return; + return; + } - foreach (var registeredServerId in externalDrawerService.GetRegisteredServerIds()) + foreach (var registeredServerId in externalDrawerService.GetRegisteredServerIds()) + { + var externalDrawServer = externalDrawerService.GetServer(registeredServerId) as IDirectContext3DServer; + if (externalDrawServer == null) { - var externalDrawServer = externalDrawerService.GetServer(registeredServerId) as IDirectContext3DServer; - if (externalDrawServer == null) - continue; - //if (document != null && !document.Equals(externalDrawServer.Document)) - // continue; - externalDrawerService.RemoveServer(registeredServerId); + continue; } - - m_servers.Clear(); - CurrentDoc.UpdateAllOpenViews(); + //if (document != null && !document.Equals(externalDrawServer.Document)) + // continue; + externalDrawerService.RemoveServer(registeredServerId); } - public override bool CanPreviewSend => true; + m_servers.Clear(); + CurrentDoc.UpdateAllOpenViews(); + } + + public override bool CanPreviewSend => true; - public override void PreviewSend(StreamState state, ProgressViewModel progress) + public override void PreviewSend(StreamState state, ProgressViewModel progress) + { + try { - try + var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); + var filterObjs = GetSelectionFilterObjects(converter, state.Filter); + foreach (var filterObj in filterObjs) { - var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); - var filterObjs = GetSelectionFilterObjects(converter, state.Filter); - foreach (var filterObj in filterObjs) + var descriptor = ConnectorRevitUtils.ObjectDescriptor(filterObj); + var reportObj = new ApplicationObject(filterObj.UniqueId, descriptor); + if (!converter.CanConvertToSpeckle(filterObj)) + { + reportObj.Update( + status: ApplicationObject.State.Skipped, + logItem: $"Sending this object type is not supported in Revit" + ); + } + else { - var descriptor = ConnectorRevitUtils.ObjectDescriptor(filterObj); - var reportObj = new ApplicationObject(filterObj.UniqueId, descriptor); - if (!converter.CanConvertToSpeckle(filterObj)) - reportObj.Update( - status: ApplicationObject.State.Skipped, - logItem: $"Sending this object type is not supported in Revit" - ); - else - reportObj.Update(status: ApplicationObject.State.Created); - progress.Report.Log(reportObj); + reportObj.Update(status: ApplicationObject.State.Created); } - SelectClientObjects(filterObjs.Select(o => o.UniqueId).ToList(), true); - } - catch (Exception ex) - { - SpeckleLog.Logger.Error(ex, "Failed to preview send: {exceptionMessage}", ex.Message); + progress.Report.Log(reportObj); } + + SelectClientObjects(filterObjs.Select(o => o.UniqueId).ToList(), true); + } + catch (Exception ex) + { + SpeckleLog.Logger.Error(ex, "Failed to preview send: {exceptionMessage}", ex.Message); } } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Receive.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Receive.cs index 76d5d7b5e5..19f7e9d36f 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Receive.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Receive.cs @@ -24,373 +24,379 @@ using Speckle.Core.Models.GraphTraversal; using Speckle.Core.Transports; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit + public List Preview { get; set; } = new List(); + public Dictionary StoredObjects = new(); + + public CancellationTokenSource CurrentOperationCancellation { get; set; } + + /// + /// Receives a stream and bakes into the existing revit file. + /// + /// + /// + /// + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) { - public List Preview { get; set; } = new List(); - public Dictionary StoredObjects = new Dictionary(); - - public CancellationTokenSource CurrentOperationCancellation { get; set; } - - /// - /// Receives a stream and bakes into the existing revit file. - /// - /// - /// - /// - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + CurrentOperationCancellation = progress.CancellationTokenSource; + //make sure to instance a new copy so all values are reset correctly + var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); + converter.SetContextDocument(CurrentDoc.Document); + + // set converter settings as tuples (setting slug, setting selection) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - CurrentOperationCancellation = progress.CancellationTokenSource; - //make sure to instance a new copy so all values are reset correctly - var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); - converter.SetContextDocument(CurrentDoc.Document); - - // set converter settings as tuples (setting slug, setting selection) - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); - - Commit myCommit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - state.LastCommit = myCommit; - Base commitObject = await ConnectorHelpers.ReceiveCommit(myCommit, state, progress); - await ConnectorHelpers.TryCommitReceived( - state, - myCommit, - ConnectorRevitUtils.RevitAppName, - progress.CancellationToken - ); + settings.Add(setting.Slug, setting.Selection); + } + + converter.SetConverterSettings(settings); + + Commit myCommit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + state.LastCommit = myCommit; + Base commitObject = await ConnectorHelpers.ReceiveCommit(myCommit, state, progress); + await ConnectorHelpers.TryCommitReceived( + state, + myCommit, + ConnectorRevitUtils.RevitAppName, + progress.CancellationToken + ); - Preview.Clear(); - StoredObjects.Clear(); + Preview.Clear(); + StoredObjects.Clear(); - Preview = FlattenCommitObject(commitObject, converter); - foreach (var previewObj in Preview) - progress.Report.Log(previewObj); + Preview = FlattenCommitObject(commitObject, converter); + foreach (var previewObj in Preview) + { + progress.Report.Log(previewObj); + } - converter.ReceiveMode = state.ReceiveMode; - // needs to be set for editing to work - var previousObjects = new StreamStateCache(state); - converter.SetContextDocument(previousObjects); - // needs to be set for openings in floors and roofs to work - converter.SetContextObjects(Preview); + converter.ReceiveMode = state.ReceiveMode; + // needs to be set for editing to work + var previousObjects = new StreamStateCache(state); + converter.SetContextDocument(previousObjects); + // needs to be set for openings in floors and roofs to work + converter.SetContextObjects(Preview); - // share the same revit element cache between the connector and converter - converter.SetContextDocument(revitDocumentAggregateCache); + // share the same revit element cache between the connector and converter + converter.SetContextDocument(revitDocumentAggregateCache); #pragma warning disable CA1031 // Do not catch general exception types - try - { - var elementTypeMapper = new ElementTypeMapper( - converter, - revitDocumentAggregateCache, - Preview, - StoredObjects, - CurrentDoc.Document - ); - await elementTypeMapper - .Map( - state.Settings.FirstOrDefault(x => x.Slug == "receive-mappings"), - state.Settings.FirstOrDefault(x => x.Slug == DsFallbackSlug) - ) - .ConfigureAwait(false); - } - catch (Exception ex) - { - var speckleEx = new SpeckleException($"Failed to map incoming types to Revit types. Reason: {ex.Message}", ex); - StreamViewModel.HandleCommandException(speckleEx, false, "MapIncomingTypesCommand"); - progress.Report.LogOperationError( - new Exception("Could not update receive object with user types. Using default mapping.", ex) - ); - } - finally - { - MainViewModel.CloseDialog(); - } + try + { + var elementTypeMapper = new ElementTypeMapper( + converter, + revitDocumentAggregateCache, + Preview, + StoredObjects, + CurrentDoc.Document + ); + await elementTypeMapper + .Map( + state.Settings.FirstOrDefault(x => x.Slug == "receive-mappings"), + state.Settings.FirstOrDefault(x => x.Slug == DsFallbackSlug) + ) + .ConfigureAwait(false); + } + catch (Exception ex) + { + var speckleEx = new SpeckleException($"Failed to map incoming types to Revit types. Reason: {ex.Message}", ex); + StreamViewModel.HandleCommandException(speckleEx, false, "MapIncomingTypesCommand"); + progress.Report.LogOperationError( + new Exception("Could not update receive object with user types. Using default mapping.", ex) + ); + } + finally + { + MainViewModel.CloseDialog(); + } #pragma warning restore CA1031 // Do not catch general exception types - var (success, exception) = await APIContext - .Run(_ => + var (success, exception) = await APIContext + .Run(_ => + { + using var transactionManager = new TransactionManager(state.StreamId, CurrentDoc.Document); + transactionManager.Start(); + + try { - using var transactionManager = new TransactionManager(state.StreamId, CurrentDoc.Document); - transactionManager.Start(); + converter.SetContextDocument(transactionManager); - try - { - converter.SetContextDocument(transactionManager); + var convertedObjects = ConvertReceivedObjects(converter, progress, transactionManager); - var convertedObjects = ConvertReceivedObjects(converter, progress, transactionManager); + if (state.ReceiveMode == ReceiveMode.Update) + { + DeleteObjects(previousObjects, convertedObjects); + } - if (state.ReceiveMode == ReceiveMode.Update) - DeleteObjects(previousObjects, convertedObjects); + previousObjects.AddConvertedElements(convertedObjects); + transactionManager.Finish(); + return (true, null); + } + catch (Exception ex) + { + SpeckleLog.Logger.Error(ex, "Rolling back connector transaction"); - previousObjects.AddConvertedElements(convertedObjects); - transactionManager.Finish(); - return (true, null); - } - catch (Exception ex) + string message = $"Fatal Error: {ex.Message}"; + if (ex is OperationCanceledException) { - SpeckleLog.Logger.Error(ex, "Rolling back connector transaction"); + message = "Receive cancelled"; + } - string message = $"Fatal Error: {ex.Message}"; - if (ex is OperationCanceledException) - message = "Receive cancelled"; - progress.Report.LogOperationError(new Exception($"{message} - Changes have been rolled back", ex)); + progress.Report.LogOperationError(new Exception($"{message} - Changes have been rolled back", ex)); - transactionManager.RollbackAll(); - return (false, ex); //We can't throw exceptions in from RevitTask, but we can return it along with a success status - } - }) - .ConfigureAwait(false); + transactionManager.RollbackAll(); + return (false, ex); //We can't throw exceptions in from RevitTask, but we can return it along with a success status + } + }) + .ConfigureAwait(false); - revitDocumentAggregateCache.InvalidateAll(); - CurrentOperationCancellation = null; + revitDocumentAggregateCache.InvalidateAll(); + CurrentOperationCancellation = null; - if (!success) + if (!success) + { + switch (exception) { - switch (exception) - { - case OperationCanceledException when progress.CancellationToken.IsCancellationRequested: - case SpeckleNonUserFacingException: - throw exception; - default: - throw new SpeckleException(exception.Message, exception); - } + case OperationCanceledException when progress.CancellationToken.IsCancellationRequested: + case SpeckleNonUserFacingException: + throw exception; + default: + throw new SpeckleException(exception.Message, exception); } - - return state; } - //delete previously sent object that are no more in this stream - private void DeleteObjects( - IReceivedObjectIdMap previousObjects, - IConvertedObjectsCache convertedObjects - ) + return state; + } + + //delete previously sent object that are no more in this stream + private void DeleteObjects( + IReceivedObjectIdMap previousObjects, + IConvertedObjectsCache convertedObjects + ) + { + var previousAppIds = previousObjects.GetAllConvertedIds().ToList(); + for (var i = previousAppIds.Count - 1; i >= 0; i--) { - var previousAppIds = previousObjects.GetAllConvertedIds().ToList(); - for (var i = previousAppIds.Count - 1; i >= 0; i--) + var appId = previousAppIds[i]; + if (string.IsNullOrEmpty(appId) || convertedObjects.HasConvertedObjectWithId(appId)) { - var appId = previousAppIds[i]; - if (string.IsNullOrEmpty(appId) || convertedObjects.HasConvertedObjectWithId(appId)) - continue; + continue; + } - var elementIdToDelete = previousObjects.GetCreatedIdsFromConvertedId(appId); + var elementIdToDelete = previousObjects.GetCreatedIdsFromConvertedId(appId); - foreach (var elementId in elementIdToDelete) - { - var elementToDelete = CurrentDoc.Document.GetElement(elementId); + foreach (var elementId in elementIdToDelete) + { + var elementToDelete = CurrentDoc.Document.GetElement(elementId); - if (elementToDelete != null && !elementToDelete.Pinned && elementToDelete.IsValidObject) + if (elementToDelete != null && !elementToDelete.Pinned && elementToDelete.IsValidObject) + { + try { - try - { - CurrentDoc.Document.Delete(elementToDelete.Id); - } - catch - { - // unable to delete previously recieved object - } + CurrentDoc.Document.Delete(elementToDelete.Id); + } + catch + { + // unable to delete previously recieved object } - - previousObjects.RemoveConvertedId(appId); } + + previousObjects.RemoveConvertedId(appId); } } + } - private IConvertedObjectsCache ConvertReceivedObjects( - ISpeckleConverter converter, - ProgressViewModel progress, - TransactionManager transactionManager - ) + private IConvertedObjectsCache ConvertReceivedObjects( + ISpeckleConverter converter, + ProgressViewModel progress, + TransactionManager transactionManager + ) + { + // Traverses through the `elements` property of the given base + void ConvertNestedElements(Base @base, ApplicationObject appObj, bool receiveDirectMesh) { - // Traverses through the `elements` property of the given base - void ConvertNestedElements(Base @base, ApplicationObject appObj, bool receiveDirectMesh) + if (@base == null) { - if (@base == null) - return; + return; + } - var nestedElements = @base["elements"] ?? @base["@elements"]; + var nestedElements = @base["elements"] ?? @base["@elements"]; - if (nestedElements == null) - return; + if (nestedElements == null) + { + return; + } - // set host in converter state. - // assumes host is the first converted object of the appObject - var host = appObj == null || !appObj.Converted.Any() ? null : appObj.Converted.First() as Element; - using var ctx = RevitConverterState.Push(); - ctx.CurrentHostElement = host; + // set host in converter state. + // assumes host is the first converted object of the appObject + var host = appObj == null || !appObj.Converted.Any() ? null : appObj.Converted.First() as Element; + using var ctx = RevitConverterState.Push(); + ctx.CurrentHostElement = host; - // traverse each element member and convert - foreach (var obj in GraphTraversal.TraverseMember(nestedElements)) + // traverse each element member and convert + foreach (var obj in GraphTraversal.TraverseMember(nestedElements)) + { + // create the application object and log to reports + var nestedAppObj = Preview.Where(o => o.OriginalId == obj.id)?.FirstOrDefault(); + if (nestedAppObj == null) { - // create the application object and log to reports - var nestedAppObj = Preview.Where(o => o.OriginalId == obj.id)?.FirstOrDefault(); - if (nestedAppObj == null) + nestedAppObj = new ApplicationObject(obj.id, ConnectorRevitUtils.SimplifySpeckleType(obj.speckle_type)) { - nestedAppObj = new ApplicationObject(obj.id, ConnectorRevitUtils.SimplifySpeckleType(obj.speckle_type)) - { - applicationId = obj.applicationId, - Convertible = converter.CanConvertToNative(obj) - }; - progress.Report.Log(nestedAppObj); - converter.Report.Log(nestedAppObj); - } + applicationId = obj.applicationId, + Convertible = converter.CanConvertToNative(obj) + }; + progress.Report.Log(nestedAppObj); + converter.Report.Log(nestedAppObj); + } - // convert - var converted = ConvertObject(nestedAppObj, obj, receiveDirectMesh, converter, progress, transactionManager); + // convert + var converted = ConvertObject(nestedAppObj, obj, receiveDirectMesh, converter, progress, transactionManager); - // Check if parent conversion succeeded before attempting the children - if ( - receiveDirectMesh || converted?.Status is ApplicationObject.State.Created or ApplicationObject.State.Updated - ) - // recurse and convert nested elements - ConvertNestedElements(obj, nestedAppObj, receiveDirectMesh); + // Check if parent conversion succeeded before attempting the children + if ( + receiveDirectMesh || converted?.Status is ApplicationObject.State.Created or ApplicationObject.State.Updated + ) + { + // recurse and convert nested elements + ConvertNestedElements(obj, nestedAppObj, receiveDirectMesh); } } + } - var convertedObjectsCache = new ConvertedObjectsCache(); - converter.SetContextDocument(convertedObjectsCache); + var convertedObjectsCache = new ConvertedObjectsCache(); + converter.SetContextDocument(convertedObjectsCache); - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 1; + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 1; - // Get setting to skip linked model elements if necessary - var receiveLinkedModelsSetting = - CurrentSettings?.FirstOrDefault(x => x.Slug == "linkedmodels-receive") as CheckBoxSetting; - var receiveLinkedModels = receiveLinkedModelsSetting?.IsChecked ?? false; + // Get setting to skip linked model elements if necessary + var receiveLinkedModelsSetting = + CurrentSettings?.FirstOrDefault(x => x.Slug == "linkedmodels-receive") as CheckBoxSetting; + var receiveLinkedModels = receiveLinkedModelsSetting?.IsChecked ?? false; - var receiveDirectMesh = false; - var fallbackToDirectShape = false; - var directShapeStrategySetting = - CurrentSettings?.FirstOrDefault(x => x.Slug == "direct-shape-strategy") as ListBoxSetting; - switch (directShapeStrategySetting!.Selection) - { - case "Always": - receiveDirectMesh = true; - break; - case "On Error": - fallbackToDirectShape = true; - break; - case "Never": - case null: - // Do nothing, default values will do. - break; - } + var receiveDirectMesh = false; + var fallbackToDirectShape = false; + var directShapeStrategySetting = + CurrentSettings?.FirstOrDefault(x => x.Slug == "direct-shape-strategy") as ListBoxSetting; + switch (directShapeStrategySetting!.Selection) + { + case "Always": + receiveDirectMesh = true; + break; + case "On Error": + fallbackToDirectShape = true; + break; + case "Never": + case null: + // Do nothing, default values will do. + break; + } - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); - using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); + using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); - // convert - var index = -1; - while (++index < Preview.Count) - { - var obj = Preview[index]; - progress.CancellationToken.ThrowIfCancellationRequested(); + // convert + var index = -1; + while (++index < Preview.Count) + { + var obj = Preview[index]; + progress.CancellationToken.ThrowIfCancellationRequested(); - var @base = StoredObjects[obj.OriginalId]; + var @base = StoredObjects[obj.OriginalId]; - // skip if this object has already been converted from a nested elements loop - if (obj.Status != ApplicationObject.State.Unknown) - continue; + // skip if this object has already been converted from a nested elements loop + if (obj.Status != ApplicationObject.State.Unknown) + { + continue; + } - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); - //skip element if is from a linked file and setting is off - if ( - !receiveLinkedModels - && @base["isRevitLinkedModel"] != null - && bool.Parse(@base["isRevitLinkedModel"].ToString()) - ) - continue; - - var converted = ConvertObject(obj, @base, receiveDirectMesh, converter, progress, transactionManager); - // Determine if we should use the fallback DirectShape conversion - // Should only happen when receiveDirectMesh is OFF, fallback is ON and object failed normal conversion. - bool usingFallback = - !receiveDirectMesh && fallbackToDirectShape && converted.Status == ApplicationObject.State.Failed; - if (usingFallback) + //skip element if is from a linked file and setting is off + if ( + !receiveLinkedModels + && @base["isRevitLinkedModel"] != null + && bool.Parse(@base["isRevitLinkedModel"].ToString()) + ) + { + continue; + } + + var converted = ConvertObject(obj, @base, receiveDirectMesh, converter, progress, transactionManager); + // Determine if we should use the fallback DirectShape conversion + // Should only happen when receiveDirectMesh is OFF, fallback is ON and object failed normal conversion. + bool usingFallback = + !receiveDirectMesh && fallbackToDirectShape && converted.Status == ApplicationObject.State.Failed; + if (usingFallback) + { + obj.Log.Add("Conversion to native Revit object failed. Retrying conversion with displayable geometry."); + converted = ConvertObject(obj, @base, true, converter, progress, transactionManager); + if (converted == null) { - obj.Log.Add("Conversion to native Revit object failed. Retrying conversion with displayable geometry."); - converted = ConvertObject(obj, @base, true, converter, progress, transactionManager); - if (converted == null) - obj.Update(status: ApplicationObject.State.Failed, logItem: "Conversion returned null."); + obj.Update(status: ApplicationObject.State.Failed, logItem: "Conversion returned null."); } + } - RefreshView(); - if (index % 50 == 0) - transactionManager.Commit(); - - // Check if parent conversion succeeded or fallback is enabled before attempting the children - if ( - usingFallback - || receiveDirectMesh - || converted?.Status is ApplicationObject.State.Created or ApplicationObject.State.Updated - ) - // continue traversing for hosted elements - // use DirectShape conversion if the parent was converted using fallback or if the global setting is active. - ConvertNestedElements(@base, converted, usingFallback || receiveDirectMesh); + RefreshView(); + if (index % 50 == 0) + { + transactionManager.Commit(); } - return convertedObjectsCache; + // Check if parent conversion succeeded or fallback is enabled before attempting the children + if ( + usingFallback + || receiveDirectMesh + || converted?.Status is ApplicationObject.State.Created or ApplicationObject.State.Updated + ) + { + // continue traversing for hosted elements + // use DirectShape conversion if the parent was converted using fallback or if the global setting is active. + ConvertNestedElements(@base, converted, usingFallback || receiveDirectMesh); + } } - private ApplicationObject ConvertObject( - ApplicationObject obj, - Base @base, - bool receiveDirectMesh, - ISpeckleConverter converter, - ProgressViewModel progress, - TransactionManager transactionManager - ) + return convertedObjectsCache; + } + + private ApplicationObject ConvertObject( + ApplicationObject obj, + Base @base, + bool receiveDirectMesh, + ISpeckleConverter converter, + ProgressViewModel progress, + TransactionManager transactionManager + ) + { + progress.CancellationToken.ThrowIfCancellationRequested(); + + if (obj == null || @base == null) { - progress.CancellationToken.ThrowIfCancellationRequested(); + return obj; + } - if (obj == null || @base == null) - return obj; + using var _d3 = LogContext.PushProperty("speckleType", @base.speckle_type); + transactionManager.StartSubtransaction(); - using var _d3 = LogContext.PushProperty("speckleType", @base.speckle_type); - transactionManager.StartSubtransaction(); + try + { + var s = new CancellationTokenSource(); + DispatcherTimer.RunOnce(() => s.Cancel(), TimeSpan.FromMilliseconds(10)); + Dispatcher.UIThread.MainLoop(s.Token); - try + ApplicationObject convRes; + if (converter.CanConvertToNative(@base)) { - var s = new CancellationTokenSource(); - DispatcherTimer.RunOnce(() => s.Cancel(), TimeSpan.FromMilliseconds(10)); - Dispatcher.UIThread.MainLoop(s.Token); - - ApplicationObject convRes; - if (converter.CanConvertToNative(@base)) - { - if (receiveDirectMesh) - { - convRes = converter.ConvertToNativeDisplayable(@base) as ApplicationObject; - if (convRes == null) - { - obj.Update(status: ApplicationObject.State.Failed, logItem: "Conversion returned null."); - return obj; - } - } - else - { - convRes = converter.ConvertToNative(@base) as ApplicationObject; - if (convRes == null || convRes.Status == ApplicationObject.State.Failed) - { - var logItem = - convRes == null - ? "Conversion returned null" - : "Conversion failed with errors: " + string.Join("/n", convRes.Log); - obj.Update(status: ApplicationObject.State.Failed, logItem: logItem); - return obj; - } - } - } - else if (converter.CanConvertToNativeDisplayable(@base)) + if (receiveDirectMesh) { - obj.Log.Add("No direct conversion exists. Converting displayable geometry."); convRes = converter.ConvertToNativeDisplayable(@base) as ApplicationObject; if (convRes == null) { @@ -400,116 +406,145 @@ TransactionManager transactionManager } else { - obj.Update( - status: ApplicationObject.State.Skipped, - logItem: "No direct conversion or displayable values can be converted." - ); - return obj; + convRes = converter.ConvertToNative(@base) as ApplicationObject; + if (convRes == null || convRes.Status == ApplicationObject.State.Failed) + { + var logItem = + convRes == null + ? "Conversion returned null" + : "Conversion failed with errors: " + string.Join("/n", convRes.Log); + obj.Update(status: ApplicationObject.State.Failed, logItem: logItem); + return obj; + } } - - obj.Update( - status: convRes.Status, - createdIds: convRes.CreatedIds, - converted: convRes.Converted, - log: convRes.Log - ); - - progress.Report.UpdateReportObject(obj); - RefreshView(); - transactionManager.CommitSubtransaction(); } - catch (ConversionNotReadyException ex) + else if (converter.CanConvertToNativeDisplayable(@base)) { - transactionManager.RollbackSubTransaction(); - var notReadyDataCache = - revitDocumentAggregateCache.GetOrInitializeEmptyCacheOfType(out _); - var notReadyData = notReadyDataCache.GetOrAdd(@base.id, () => new ConversionNotReadyCacheData(), out _); - - if (++notReadyData.NumberOfTimesCaught > 2) + obj.Log.Add("No direct conversion exists. Converting displayable geometry."); + convRes = converter.ConvertToNativeDisplayable(@base) as ApplicationObject; + if (convRes == null) { - SpeckleLog.Logger.Warning( - ex, - $"Speckle object of type {@base.GetType()} was waiting for an object to convert that never did" - ); - obj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); - progress.Report.UpdateReportObject(obj); - } - else - { - Preview.Add(obj); + obj.Update(status: ApplicationObject.State.Failed, logItem: "Conversion returned null."); + return obj; } - // the struct must be saved to the cache again or the "numberOfTimesCaught" increment will not persist - notReadyDataCache.Set(@base.id, notReadyData); } - catch (Exception ex) + else { - transactionManager.RollbackSubTransaction(); - SpeckleLog.Logger.Warning(ex, "Failed to convert due to unexpected error."); - obj.Update(status: ApplicationObject.State.Failed, logItem: "Failed to convert due to unexpected error."); - obj.Log.Add($"{ex.Message}"); - progress.Report.UpdateReportObject(obj); + obj.Update( + status: ApplicationObject.State.Skipped, + logItem: "No direct conversion or displayable values can be converted." + ); + return obj; } - return obj; - } + obj.Update( + status: convRes.Status, + createdIds: convRes.CreatedIds, + converted: convRes.Converted, + log: convRes.Log + ); - private void RefreshView() + progress.Report.UpdateReportObject(obj); + RefreshView(); + transactionManager.CommitSubtransaction(); + } + catch (ConversionNotReadyException ex) { - //regenerate the document and then implement a hack to "refresh" the view - CurrentDoc.Document.Regenerate(); + transactionManager.RollbackSubTransaction(); + var notReadyDataCache = revitDocumentAggregateCache.GetOrInitializeEmptyCacheOfType( + out _ + ); + var notReadyData = notReadyDataCache.GetOrAdd(@base.id, () => new ConversionNotReadyCacheData(), out _); - // get the active ui view - var view = CurrentDoc.ActiveGraphicalView ?? CurrentDoc.Document.ActiveView; - if (view is TableView) + if (++notReadyData.NumberOfTimesCaught > 2) { - return; + SpeckleLog.Logger.Warning( + ex, + $"Speckle object of type {@base.GetType()} was waiting for an object to convert that never did" + ); + obj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); + progress.Report.UpdateReportObject(obj); + } + else + { + Preview.Add(obj); } + // the struct must be saved to the cache again or the "numberOfTimesCaught" increment will not persist + notReadyDataCache.Set(@base.id, notReadyData); + } + catch (Exception ex) + { + transactionManager.RollbackSubTransaction(); + SpeckleLog.Logger.Warning(ex, "Failed to convert due to unexpected error."); + obj.Update(status: ApplicationObject.State.Failed, logItem: "Failed to convert due to unexpected error."); + obj.Log.Add($"{ex.Message}"); + progress.Report.UpdateReportObject(obj); + } - var uiView = CurrentDoc.GetOpenUIViews().FirstOrDefault(uv => uv.ViewId.Equals(view.Id)); + return obj; + } + + private void RefreshView() + { + //regenerate the document and then implement a hack to "refresh" the view + CurrentDoc.Document.Regenerate(); - // "refresh" the active view - uiView.Zoom(1); + // get the active ui view + var view = CurrentDoc.ActiveGraphicalView ?? CurrentDoc.Document.ActiveView; + if (view is TableView) + { + return; } - /// - /// Traverses the object graph, returning objects to be converted. - /// - /// The root object to traverse - /// The converter instance, used to define what objects are convertable - /// A flattened list of objects to be converted ToNative - private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + var uiView = CurrentDoc.GetOpenUIViews().FirstOrDefault(uv => uv.ViewId.Equals(view.Id)); + + // "refresh" the active view + uiView.Zoom(1); + } + + /// + /// Traverses the object graph, returning objects to be converted. + /// + /// The root object to traverse + /// The converter instance, used to define what objects are convertable + /// A flattened list of objects to be converted ToNative + private List FlattenCommitObject(Base obj, ISpeckleConverter converter) + { + ApplicationObject CreateApplicationObject(Base current) { - ApplicationObject CreateApplicationObject(Base current) - { - // determine if this object is displayable - var isDisplayable = DefaultTraversal.displayValuePropAliases.Any(o => current[o] != null); + // determine if this object is displayable + var isDisplayable = DefaultTraversal.displayValuePropAliases.Any(o => current[o] != null); - // skip if this object was already stored, if it's not convertible and has no displayables - if (StoredObjects.ContainsKey(current.id)) - return null; - if (!converter.CanConvertToNative(current) && !isDisplayable) - return null; + // skip if this object was already stored, if it's not convertible and has no displayables + if (StoredObjects.ContainsKey(current.id)) + { + return null; + } - // create application object and store - var appObj = new ApplicationObject(current.id, ConnectorRevitUtils.SimplifySpeckleType(current.speckle_type)) - { - applicationId = current.applicationId, - Convertible = converter.CanConvertToNative(current) - }; - StoredObjects.Add(current.id, current); - return appObj; + if (!converter.CanConvertToNative(current) && !isDisplayable) + { + return null; } - var traverseFunction = DefaultTraversal.CreateRevitTraversalFunc(converter); + // create application object and store + var appObj = new ApplicationObject(current.id, ConnectorRevitUtils.SimplifySpeckleType(current.speckle_type)) + { + applicationId = current.applicationId, + Convertible = converter.CanConvertToNative(current) + }; + StoredObjects.Add(current.id, current); + return appObj; + } - var objectsToConvert = traverseFunction - .Traverse(obj) - .Select(tc => CreateApplicationObject(tc.current)) - .Where(appObject => appObject != null) - .Reverse() - .ToList(); + var traverseFunction = DefaultTraversal.CreateRevitTraversalFunc(converter); - return objectsToConvert; - } + var objectsToConvert = traverseFunction + .Traverse(obj) + .Select(tc => CreateApplicationObject(tc.current)) + .Where(appObject => appObject != null) + .Reverse() + .ToList(); + + return objectsToConvert; } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Selection.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Selection.cs index a6ee20f194..8eeac3c409 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Selection.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Selection.cs @@ -10,597 +10,625 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit + public override List GetSelectionFilters() { - public override List GetSelectionFilters() + var categories = new List(); + var viewFilters = new List(); + + var views = new List(); + var schedules = new List(); + var worksets = new List(); + var projectInfo = new List { "Project Info", "Levels", "Views 2D", "Views 3D", "Families & Types" }; + + if (CurrentDoc != null) { - var categories = new List(); - var viewFilters = new List(); + //selectionCount = CurrentDoc.Selection.GetElementIds().Count(); + categories = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetAllKeys() + .OrderBy(x => x) + .ToList(); - var views = new List(); - var schedules = new List(); - var worksets = new List(); - var projectInfo = new List { "Project Info", "Levels", "Views 2D", "Views 3D", "Families & Types" }; + //categories = ConnectorRevitUtils.GetCategoryNames(CurrentDoc.Document); + viewFilters = ConnectorRevitUtils.GetViewFilterNames(CurrentDoc.Document); + views = ConnectorRevitUtils.GetViewNames(CurrentDoc.Document); + schedules = ConnectorRevitUtils.GetScheduleNames(CurrentDoc.Document); + worksets = ConnectorRevitUtils.GetWorksets(CurrentDoc.Document); + } - if (CurrentDoc != null) + var filters = new List + { + new AllSelectionFilter { - //selectionCount = CurrentDoc.Selection.GetElementIds().Count(); - categories = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetAllKeys() - .OrderBy(x => x) - .ToList(); - - //categories = ConnectorRevitUtils.GetCategoryNames(CurrentDoc.Document); - viewFilters = ConnectorRevitUtils.GetViewFilterNames(CurrentDoc.Document); - views = ConnectorRevitUtils.GetViewNames(CurrentDoc.Document); - schedules = ConnectorRevitUtils.GetScheduleNames(CurrentDoc.Document); - worksets = ConnectorRevitUtils.GetWorksets(CurrentDoc.Document); - } - - var filters = new List + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Sends all supported elements and project information." + }, + new ManualSelectionFilter(), + new ListSelectionFilter { - new AllSelectionFilter - { - Slug = "all", - Name = "Everything", - Icon = "CubeScan", - Description = "Sends all supported elements and project information." - }, - new ManualSelectionFilter(), + Slug = "category", + Name = "Category", + Icon = "Category", + Values = categories, + Description = "Adds all elements belonging to the selected categories" + }, + new ListSelectionFilter + { + Slug = "view", + Name = "View", + Icon = "RemoveRedEye", + Values = views, + Description = "Adds all objects visible in the selected views" + }, + }; + + if (schedules.Any()) + { + filters.Add( new ListSelectionFilter { - Slug = "category", - Name = "Category", - Icon = "Category", - Values = categories, - Description = "Adds all elements belonging to the selected categories" - }, + Slug = "schedule", + Name = "Schedule", + Icon = "Table", + Values = schedules, + Description = "Sends the selected schedule as a DataTable" + } + ); + } + + if (viewFilters.Any()) + { + filters.Add( new ListSelectionFilter { - Slug = "view", - Name = "View", - Icon = "RemoveRedEye", - Values = views, - Description = "Adds all objects visible in the selected views" - }, - }; - - if (schedules.Any()) - filters.Add( - new ListSelectionFilter - { - Slug = "schedule", - Name = "Schedule", - Icon = "Table", - Values = schedules, - Description = "Sends the selected schedule as a DataTable" - } - ); - - if (viewFilters.Any()) - filters.Add( - new ListSelectionFilter - { - Slug = "filter", - Name = "Filters", - Icon = "FilterList", - Values = viewFilters, - Description = "Adds all elements that pass the selected filters" - } - ); - - if (worksets.Any()) - filters.Add( - new ListSelectionFilter - { - Slug = "workset", - Name = "Workset", - Icon = "Group", - Values = worksets, - Description = "Adds all elements belonging to the selected workset" - } - ); + Slug = "filter", + Name = "Filters", + Icon = "FilterList", + Values = viewFilters, + Description = "Adds all elements that pass the selected filters" + } + ); + } + if (worksets.Any()) + { filters.Add( new ListSelectionFilter { - Slug = "project-info", - Name = "Project Information", - Icon = "Information", - Values = projectInfo, - Description = "Adds the selected project information such as levels, views and family names to the stream" + Slug = "workset", + Name = "Workset", + Icon = "Group", + Values = worksets, + Description = "Adds all elements belonging to the selected workset" } ); - - return filters; } - public override List GetSelectedObjects() - { - if (CurrentDoc == null) + filters.Add( + new ListSelectionFilter { - return new List(); + Slug = "project-info", + Name = "Project Information", + Icon = "Information", + Values = projectInfo, + Description = "Adds the selected project information such as levels, views and family names to the stream" } + ); - var selectedObjects = CurrentDoc.Selection - .GetElementIds() - .Select(id => CurrentDoc.Document.GetElement(id).UniqueId) - .ToList(); - return selectedObjects; - } + return filters; + } - public override List GetObjectsInView() + public override List GetSelectedObjects() + { + if (CurrentDoc == null) { - if (CurrentDoc == null) - { - return new List(); - } + return new List(); + } - var collector = new FilteredElementCollector( - CurrentDoc.Document, - CurrentDoc.Document.ActiveView.Id - ).WhereElementIsNotElementType(); - var elementIds = collector.ToElements().Select(el => el.UniqueId).ToList(); + var selectedObjects = CurrentDoc.Selection + .GetElementIds() + .Select(id => CurrentDoc.Document.GetElement(id).UniqueId) + .ToList(); + return selectedObjects; + } - return elementIds; + public override List GetObjectsInView() + { + if (CurrentDoc == null) + { + return new List(); } - public override void SelectClientObjects(List args, bool deselect = false) - { - var selection = args.Select(x => CurrentDoc.Document.GetElement(x)) - .Where(x => x != null && x.IsPhysicalElement()) - .Select(x => x.Id) - ?.ToList(); - if (!selection.Any()) - return; + var collector = new FilteredElementCollector( + CurrentDoc.Document, + CurrentDoc.Document.ActiveView.Id + ).WhereElementIsNotElementType(); + var elementIds = collector.ToElements().Select(el => el.UniqueId).ToList(); - //merge two lists - if (!deselect) - { - var currentSelection = CurrentDoc.Selection.GetElementIds().ToList(); - selection = currentSelection.Union(selection).ToList(); - } + return elementIds; + } - CurrentDoc.Selection.SetElementIds(selection); - CurrentDoc.ShowElements(selection); + public override void SelectClientObjects(List args, bool deselect = false) + { + var selection = args.Select(x => CurrentDoc.Document.GetElement(x)) + .Where(x => x != null && x.IsPhysicalElement()) + .Select(x => x.Id) + ?.ToList(); + if (!selection.Any()) + { + return; } - private Dictionary GetLinkedDocuments() + //merge two lists + if (!deselect) { - var linkedDocs = new Dictionary(); + var currentSelection = CurrentDoc.Selection.GetElementIds().ToList(); + selection = currentSelection.Union(selection).ToList(); + } - // Get settings and return empty list if we should not send linked models - var sendLinkedModels = CurrentSettings?.FirstOrDefault(x => x.Slug == "linkedmodels-send") as CheckBoxSetting; - if (sendLinkedModels == null || !sendLinkedModels.IsChecked) - return linkedDocs; + CurrentDoc.Selection.SetElementIds(selection); + CurrentDoc.ShowElements(selection); + } - var linkedRVTs = new FilteredElementCollector(CurrentDoc.Document) - .OfCategory(BuiltInCategory.OST_RvtLinks) - .OfClass(typeof(RevitLinkInstance)) - .ToElements() - .Cast(); - foreach (var linkedRVT in linkedRVTs) - { - linkedDocs.Add(linkedRVT.Id, linkedRVT.GetLinkDocument()); - } + private Dictionary GetLinkedDocuments() + { + var linkedDocs = new Dictionary(); + // Get settings and return empty list if we should not send linked models + var sendLinkedModels = CurrentSettings?.FirstOrDefault(x => x.Slug == "linkedmodels-send") as CheckBoxSetting; + if (sendLinkedModels == null || !sendLinkedModels.IsChecked) + { return linkedDocs; } - private static List FilterHiddenDesignOptions(List selection) + var linkedRVTs = new FilteredElementCollector(CurrentDoc.Document) + .OfCategory(BuiltInCategory.OST_RvtLinks) + .OfClass(typeof(RevitLinkInstance)) + .ToElements() + .Cast(); + foreach (var linkedRVT in linkedRVTs) { - using var collector = new FilteredElementCollector(CurrentDoc.Document); - var designOptionsExist = collector - .OfClass(typeof(DesignOption)) - .Cast() - .Where(option => option.IsPrimary == false) - .Any(); - - if (!designOptionsExist) - { - return selection; - } + linkedDocs.Add(linkedRVT.Id, linkedRVT.GetLinkDocument()); + } - //Only include the Main Model objects and those part of a Primary Design Option - //https://speckle.community/t/revit-design-option-settings-are-ignored-in-everything-stream/3182/8 - var activeDesignOption = DesignOption.GetActiveDesignOptionId(CurrentDoc.Document); - if (activeDesignOption != ElementId.InvalidElementId) - { - selection = selection.Where(x => x.DesignOption == null || x.DesignOption.Id == activeDesignOption).ToList(); - } - else - { - selection = selection.Where(x => x.DesignOption == null || x.DesignOption.IsPrimary).ToList(); - } + return linkedDocs; + } + private static List FilterHiddenDesignOptions(List selection) + { + using var collector = new FilteredElementCollector(CurrentDoc.Document); + var designOptionsExist = collector + .OfClass(typeof(DesignOption)) + .Cast() + .Where(option => option.IsPrimary == false) + .Any(); + + if (!designOptionsExist) + { return selection; } - /// - /// Given the filter in use by a stream returns the document elements that match it. - /// - /// - /// - private List GetSelectionFilterObjects(ISpeckleConverter converter, ISelectionFilter filter) + //Only include the Main Model objects and those part of a Primary Design Option + //https://speckle.community/t/revit-design-option-settings-are-ignored-in-everything-stream/3182/8 + var activeDesignOption = DesignOption.GetActiveDesignOptionId(CurrentDoc.Document); + if (activeDesignOption != ElementId.InvalidElementId) + { + selection = selection.Where(x => x.DesignOption == null || x.DesignOption.Id == activeDesignOption).ToList(); + } + else { - var linkedDocs = GetLinkedDocuments(); + selection = selection.Where(x => x.DesignOption == null || x.DesignOption.IsPrimary).ToList(); + } + + return selection; + } - var allDocs = new List { CurrentDoc.Document }; - allDocs.AddRange(linkedDocs.Values); + /// + /// Given the filter in use by a stream returns the document elements that match it. + /// + /// + /// + private List GetSelectionFilterObjects(ISpeckleConverter converter, ISelectionFilter filter) + { + var linkedDocs = GetLinkedDocuments(); + + var allDocs = new List { CurrentDoc.Document }; + allDocs.AddRange(linkedDocs.Values); - var selection = new List(); - try + var selection = new List(); + try + { + switch (filter.Slug) { - switch (filter.Slug) - { - case "manual": - return GetManualSelection(filter, linkedDocs); + case "manual": + return GetManualSelection(filter, linkedDocs); - case "all": - selection = GetEverything(linkedDocs); - return FilterHiddenDesignOptions(selection); + case "all": + selection = GetEverything(linkedDocs); + return FilterHiddenDesignOptions(selection); - case "category": - selection = GetSelectionByCategory(filter, allDocs); - return FilterHiddenDesignOptions(selection); + case "category": + selection = GetSelectionByCategory(filter, allDocs); + return FilterHiddenDesignOptions(selection); - case "filter": - selection = GetSelectionByFilter(filter, allDocs); - return FilterHiddenDesignOptions(selection); + case "filter": + selection = GetSelectionByFilter(filter, allDocs); + return FilterHiddenDesignOptions(selection); - case "view": - var selectedViews = GetSelectedViews(filter); - selection = GetSelectionByView(selectedViews, linkedDocs); - if (selectedViews.Count == 1) - { - // if the user is sending a single view, then we pass it to the converter in order for the converter - // to retreive element meshes that are specific to that view - converter.SetContextDocument(selectedViews[0]); - return selection; - } - else - { - return FilterHiddenDesignOptions(selection); - } - - case "schedule": - return GetSelectionBySchedule(filter); - - case "project-info": - return GetSelectionByProjectInfo(filter); - - case "workset": - selection = GetSelectionByWorkset(filter, allDocs); + case "view": + var selectedViews = GetSelectedViews(filter); + selection = GetSelectionByView(selectedViews, linkedDocs); + if (selectedViews.Count == 1) + { + // if the user is sending a single view, then we pass it to the converter in order for the converter + // to retreive element meshes that are specific to that view + converter.SetContextDocument(selectedViews[0]); + return selection; + } + else + { return FilterHiddenDesignOptions(selection); + } - default: - throw new SpeckleException($"Unknown ISelectionFilterSlug, {filter.Slug}"); - } - } - catch (Exception ex) - { - throw new SpeckleException( - $"Method {nameof(GetSelectionFilterObjects)} threw an error of type {ex.GetType()}. Reason: {ex.Message}", - ex - ); + case "schedule": + return GetSelectionBySchedule(filter); + + case "project-info": + return GetSelectionByProjectInfo(filter); + + case "workset": + selection = GetSelectionByWorkset(filter, allDocs); + return FilterHiddenDesignOptions(selection); + + default: + throw new SpeckleException($"Unknown ISelectionFilterSlug, {filter.Slug}"); } } - - private static List GetManualSelection(ISelectionFilter filter, Dictionary linkedDocs) + catch (Exception ex) { - var selection = filter.Selection.Select(x => CurrentDoc.Document.GetElement(x)).Where(x => x != null).ToList(); - var selectedLinkedFiles = selection.Where(x => x is RevitLinkInstance).Cast().ToList(); + throw new SpeckleException( + $"Method {nameof(GetSelectionFilterObjects)} threw an error of type {ex.GetType()}. Reason: {ex.Message}", + ex + ); + } + } - foreach (var selectedLinkedFile in selectedLinkedFiles) + private static List GetManualSelection(ISelectionFilter filter, Dictionary linkedDocs) + { + var selection = filter.Selection.Select(x => CurrentDoc.Document.GetElement(x)).Where(x => x != null).ToList(); + var selectedLinkedFiles = selection.Where(x => x is RevitLinkInstance).Cast().ToList(); + + foreach (var selectedLinkedFile in selectedLinkedFiles) + { + if (linkedDocs.ContainsKey(selectedLinkedFile.Id)) { - if (linkedDocs.ContainsKey(selectedLinkedFile.Id)) - selection.AddRange(linkedDocs[selectedLinkedFile.Id].GetSupportedElements(revitDocumentAggregateCache)); + selection.AddRange(linkedDocs[selectedLinkedFile.Id].GetSupportedElements(revitDocumentAggregateCache)); } - - return selection; } - private static List GetEverything(Dictionary linkedDocs) + return selection; + } + + private static List GetEverything(Dictionary linkedDocs) + { + var currentDoc = CurrentDoc.Document; + var selection = new List(); + //add these only for the current doc + if (!currentDoc.IsFamilyDocument) { - var currentDoc = CurrentDoc.Document; - var selection = new List(); - //add these only for the current doc - if (!currentDoc.IsFamilyDocument) - { - selection.Add(currentDoc.ProjectInformation); - } - else + selection.Add(currentDoc.ProjectInformation); + } + else + { + //add for family document + IList filters = new List() { - //add for family document - IList filters = new List() - { - new ElementClassFilter(typeof(GenericForm)), - new ElementClassFilter(typeof(GeomCombination)), - }; - selection.AddRange( - new FilteredElementCollector(currentDoc).WherePasses(new LogicalOrFilter(filters)).ToElements() - ); - } - selection.AddRange(currentDoc.Views2D()); - selection.AddRange(currentDoc.Views3D()); + new ElementClassFilter(typeof(GenericForm)), + new ElementClassFilter(typeof(GeomCombination)), + }; + selection.AddRange( + new FilteredElementCollector(currentDoc).WherePasses(new LogicalOrFilter(filters)).ToElements() + ); + } + selection.AddRange(currentDoc.Views2D()); + selection.AddRange(currentDoc.Views3D()); + // We specifically exclude `TableView` elements (Schedules) until schedule extraction has been improved for performance. + var elements = currentDoc.GetSupportedElements(revitDocumentAggregateCache).Where(e => e is not TableView); + selection.AddRange(elements); + selection.AddRange(currentDoc.GetSupportedTypes(revitDocumentAggregateCache)); + + //and these for every linked doc + foreach (var linkedDoc in linkedDocs.Values) + { // We specifically exclude `TableView` elements (Schedules) until schedule extraction has been improved for performance. - var elements = currentDoc.GetSupportedElements(revitDocumentAggregateCache).Where(e => e is not TableView); - selection.AddRange(elements); - selection.AddRange(currentDoc.GetSupportedTypes(revitDocumentAggregateCache)); + var linkedElements = linkedDoc.GetSupportedElements(revitDocumentAggregateCache).Where(e => e is not TableView); + selection.AddRange(linkedElements); // includes levels + selection.AddRange(linkedDoc.GetSupportedTypes(revitDocumentAggregateCache)); + } - //and these for every linked doc - foreach (var linkedDoc in linkedDocs.Values) - { - // We specifically exclude `TableView` elements (Schedules) until schedule extraction has been improved for performance. - var linkedElements = linkedDoc.GetSupportedElements(revitDocumentAggregateCache).Where(e => e is not TableView); - selection.AddRange(linkedElements); // includes levels - selection.AddRange(linkedDoc.GetSupportedTypes(revitDocumentAggregateCache)); - } + return selection; + } - return selection; - } + private List GetSelectionByCategory(ISelectionFilter filter, List allDocs) + { + var selection = new List(); + var catFilter = filter as ListSelectionFilter; + var catIds = new List(); - private List GetSelectionByCategory(ISelectionFilter filter, List allDocs) + foreach (var cat in catFilter.Selection) { - var selection = new List(); - var catFilter = filter as ListSelectionFilter; - var catIds = new List(); - - foreach (var cat in catFilter.Selection) + var revitCategory = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory().TryGet(cat); + if (revitCategory == null) { - var revitCategory = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory().TryGet(cat); - if (revitCategory == null) - continue; - - catIds.Add(revitCategory.Id); + continue; } - using var categoryFilter = new ElementMulticategoryFilter(catIds); + catIds.Add(revitCategory.Id); + } - foreach (var doc in allDocs) - { - using var collector = new FilteredElementCollector(doc); - selection.AddRange( - collector.WhereElementIsNotElementType().WhereElementIsViewIndependent().WherePasses(categoryFilter).ToList() - ); - } - return selection; + using var categoryFilter = new ElementMulticategoryFilter(catIds); + + foreach (var doc in allDocs) + { + using var collector = new FilteredElementCollector(doc); + selection.AddRange( + collector.WhereElementIsNotElementType().WhereElementIsViewIndependent().WherePasses(categoryFilter).ToList() + ); } + return selection; + } - private static List GetSelectionByFilter(ISelectionFilter filter, List allDocs) + private static List GetSelectionByFilter(ISelectionFilter filter, List allDocs) + { + var selection = new List(); + var rvtFilters = filter as ListSelectionFilter; + foreach (Document doc in allDocs) { - var selection = new List(); - var rvtFilters = filter as ListSelectionFilter; - foreach (Document doc in allDocs) + List elements = new(); + var viewFilters = ConnectorRevitUtils.GetFilters(doc).Where(x => rvtFilters.Selection.Contains(x.Name)); + foreach (ParameterFilterElement filterElement in viewFilters) { - List elements = new List(); - var viewFilters = ConnectorRevitUtils.GetFilters(doc).Where(x => rvtFilters.Selection.Contains(x.Name)); - foreach (ParameterFilterElement filterElement in viewFilters) + ICollection cates = filterElement.GetCategories(); + IList eleFilters = new List(); + foreach (var cat in cates) { - ICollection cates = filterElement.GetCategories(); - IList eleFilters = new List(); - foreach (var cat in cates) - { - eleFilters.Add(new ElementCategoryFilter(cat)); - } - var cateFilter = new LogicalOrFilter(eleFilters); - ElementFilter elementFilter = filterElement.GetElementFilter(); - if (elementFilter != null) - { - elements.AddRange( - new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .WhereElementIsViewIndependent() - .WherePasses(cateFilter) - .WherePasses(elementFilter) - .ToList() - ); - } - else - { - elements.AddRange( - new FilteredElementCollector(doc) - .WhereElementIsNotElementType() - .WhereElementIsViewIndependent() - .WherePasses(cateFilter) - .ToList() - ); - } + eleFilters.Add(new ElementCategoryFilter(cat)); + } + var cateFilter = new LogicalOrFilter(eleFilters); + ElementFilter elementFilter = filterElement.GetElementFilter(); + if (elementFilter != null) + { + elements.AddRange( + new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .WhereElementIsViewIndependent() + .WherePasses(cateFilter) + .WherePasses(elementFilter) + .ToList() + ); } - if (elements.Count > 0) + else { - selection.AddRange(elements.GroupBy(x => x.Id.IntegerValue).Select(x => x.First()).ToList()); + elements.AddRange( + new FilteredElementCollector(doc) + .WhereElementIsNotElementType() + .WhereElementIsViewIndependent() + .WherePasses(cateFilter) + .ToList() + ); } } - return selection; + if (elements.Count > 0) + { + selection.AddRange(elements.GroupBy(x => x.Id.IntegerValue).Select(x => x.First()).ToList()); + } } + return selection; + } - private static List GetSelectionByView(List views, Dictionary linkedDocs) + private static List GetSelectionByView(List views, Dictionary linkedDocs) + { + var selection = new List(); + foreach (var view in views) { - var selection = new List(); - foreach (var view in views) - { - selection.Add(view); + selection.Add(view); + + using var docCollector = new FilteredElementCollector(CurrentDoc.Document, view.Id); + selection.AddRange( + docCollector + .WhereElementIsNotElementType() + .WhereElementIsViewIndependent() + .Where(x => !selection.Any(s => s.UniqueId == x.UniqueId)) //exclude elements already added from other views + .ToList() + ); - using var docCollector = new FilteredElementCollector(CurrentDoc.Document, view.Id); + foreach (var linkedDoc in linkedDocs) + { + if (linkedDoc.Value == null) + { + continue; + } + //from Revit 2024 onward we can query linked docs + //for earlier versions we can't: https://github.com/specklesystems/speckle-sharp/issues/2829 +#if !REVIT2020 && !REVIT2021 && !REVIT2022 && !REVIT2023 + using var linkedDocCollector = new FilteredElementCollector(CurrentDoc.Document, view.Id, linkedDoc.Key); selection.AddRange( - docCollector + linkedDocCollector .WhereElementIsNotElementType() .WhereElementIsViewIndependent() + //.Where(x => x.IsPhysicalElement()) .Where(x => !selection.Any(s => s.UniqueId == x.UniqueId)) //exclude elements already added from other views .ToList() ); - foreach (var linkedDoc in linkedDocs) +#else + //check if linked doc is visible in main doc + var linkedObject = CurrentDoc.Document.GetElement(linkedDoc.Key); + if (linkedObject.IsHidden(view)) { - if (linkedDoc.Value == null) - { - continue; - } - //from Revit 2024 onward we can query linked docs - //for earlier versions we can't: https://github.com/specklesystems/speckle-sharp/issues/2829 -#if !REVIT2020 && !REVIT2021 && !REVIT2022 && !REVIT2023 - using var linkedDocCollector = new FilteredElementCollector(CurrentDoc.Document, view.Id, linkedDoc.Key); - selection.AddRange( - linkedDocCollector - .WhereElementIsNotElementType() - .WhereElementIsViewIndependent() - //.Where(x => x.IsPhysicalElement()) - .Where(x => !selection.Any(s => s.UniqueId == x.UniqueId)) //exclude elements already added from other views - .ToList() - ); + continue; + } -#else - //check if linked doc is visible in main doc - var linkedObject = CurrentDoc.Document.GetElement(linkedDoc.Key); - if (linkedObject.IsHidden(view)) - continue; - - //get ALL the linked model objects - selection - .AddRange(linkedDoc.Value.GetSupportedElements(revitDocumentAggregateCache) - .Where(x => !selection.Any(s => s.UniqueId == x.UniqueId))); + //get ALL the linked model objects + selection + .AddRange(linkedDoc.Value.GetSupportedElements(revitDocumentAggregateCache) + .Where(x => !selection.Any(s => s.UniqueId == x.UniqueId))); #endif - } } - return selection; } + return selection; + } + + private static List GetSelectedViews(ISelectionFilter filter) + { + var selection = new List(); + var viewFilter = filter as ListSelectionFilter; + using var collector = new FilteredElementCollector(CurrentDoc.Document); + using var scheduleExclusionFilter = new ElementClassFilter(typeof(ViewSchedule), true); + return collector + .WhereElementIsNotElementType() + .OfClass(typeof(View)) + .WherePasses(scheduleExclusionFilter) + .Cast() + .Where(x => viewFilter.Selection.Contains(x.Title)) + .Where(x => !x.IsTemplate) + .ToList(); + } + + private static List GetSelectionBySchedule(ISelectionFilter filter) + { + var selection = new List(); + var scheduleFilter = filter as ListSelectionFilter; - private static List GetSelectedViews(ISelectionFilter filter) + using var collector = new FilteredElementCollector(CurrentDoc.Document); + var schedules = collector + .WhereElementIsNotElementType() + .OfClass(typeof(ViewSchedule)) + .Where(x => scheduleFilter.Selection.Contains(x.Name)); + + foreach (var schedule in schedules) { - var selection = new List(); - var viewFilter = filter as ListSelectionFilter; - using var collector = new FilteredElementCollector(CurrentDoc.Document); - using var scheduleExclusionFilter = new ElementClassFilter(typeof(ViewSchedule), true); - return collector - .WhereElementIsNotElementType() - .OfClass(typeof(View)) - .WherePasses(scheduleExclusionFilter) - .Cast() - .Where(x => viewFilter.Selection.Contains(x.Title)) - .Where(x => !x.IsTemplate) - .ToList(); + selection.Add(schedule); } + return selection; + } - private static List GetSelectionBySchedule(ISelectionFilter filter) - { - var selection = new List(); - var scheduleFilter = filter as ListSelectionFilter; + private static List GetSelectionByProjectInfo(ISelectionFilter filter) + { + var selection = new List(); + var projectInfoFilter = filter as ListSelectionFilter; - using var collector = new FilteredElementCollector(CurrentDoc.Document); - var schedules = collector - .WhereElementIsNotElementType() - .OfClass(typeof(ViewSchedule)) - .Where(x => scheduleFilter.Selection.Contains(x.Name)); + if (projectInfoFilter.Selection.Contains("Project Info")) + { + selection.Add(CurrentDoc.Document.ProjectInformation); + } - foreach (var schedule in schedules) - { - selection.Add(schedule); - } - return selection; + if (projectInfoFilter.Selection.Contains("Views 2D")) + { + selection.AddRange(CurrentDoc.Document.Views2D()); } - private static List GetSelectionByProjectInfo(ISelectionFilter filter) + if (projectInfoFilter.Selection.Contains("Views 3D")) { - var selection = new List(); - var projectInfoFilter = filter as ListSelectionFilter; + selection.AddRange(CurrentDoc.Document.Views3D()); + } - if (projectInfoFilter.Selection.Contains("Project Info")) - selection.Add(CurrentDoc.Document.ProjectInformation); + if (projectInfoFilter.Selection.Contains("Levels")) + { + selection.AddRange(CurrentDoc.Document.Levels()); + } - if (projectInfoFilter.Selection.Contains("Views 2D")) - selection.AddRange(CurrentDoc.Document.Views2D()); + if (projectInfoFilter.Selection.Contains("Families & Types")) + { + selection.AddRange(CurrentDoc.Document.GetSupportedTypes(revitDocumentAggregateCache)); + } - if (projectInfoFilter.Selection.Contains("Views 3D")) - selection.AddRange(CurrentDoc.Document.Views3D()); + return selection; + } - if (projectInfoFilter.Selection.Contains("Levels")) - selection.AddRange(CurrentDoc.Document.Levels()); + private static List GetSelectionByWorkset(ISelectionFilter filter, List allDocs) + { + var selection = new List(); + var worksetFilter = filter as ListSelectionFilter; + var worksets = new FilteredWorksetCollector(CurrentDoc.Document) + .Where(x => worksetFilter.Selection.Contains(x.Name)) + .Select(x => x.Id) + .ToList(); + foreach (var doc in allDocs) + { + using var collector = new FilteredElementCollector(doc); + var elementWorksetFilters = new List(); - if (projectInfoFilter.Selection.Contains("Families & Types")) - selection.AddRange(CurrentDoc.Document.GetSupportedTypes(revitDocumentAggregateCache)); + foreach (var w in worksets) + { + elementWorksetFilters.Add(new ElementWorksetFilter(w)); + } - return selection; + var worksetLogicalFilter = new LogicalOrFilter(elementWorksetFilters); + selection.AddRange(collector.WherePasses(worksetLogicalFilter).ToElements().ToList()); } + return selection; + } - private static List GetSelectionByWorkset(ISelectionFilter filter, List allDocs) + private static string GetStringValue(Parameter p) + { + string value = ""; + if (!p.HasValue) { - var selection = new List(); - var worksetFilter = filter as ListSelectionFilter; - var worksets = new FilteredWorksetCollector(CurrentDoc.Document) - .Where(x => worksetFilter.Selection.Contains(x.Name)) - .Select(x => x.Id) - .ToList(); - foreach (var doc in allDocs) - { - using var collector = new FilteredElementCollector(doc); - var elementWorksetFilters = new List(); - - foreach (var w in worksets) - { - elementWorksetFilters.Add(new ElementWorksetFilter(w)); - } + return value; + } - var worksetLogicalFilter = new LogicalOrFilter(elementWorksetFilters); - selection.AddRange(collector.WherePasses(worksetLogicalFilter).ToElements().ToList()); - } - return selection; + if (string.IsNullOrEmpty(p.AsValueString()) && string.IsNullOrEmpty(p.AsString())) + { + return value; } - private static string GetStringValue(Parameter p) + if (!string.IsNullOrEmpty(p.AsValueString())) { - string value = ""; - if (!p.HasValue) - { - return value; - } + return p.AsValueString().ToLowerInvariant(); + } + else + { + return p.AsString().ToLowerInvariant(); + } + } - if (string.IsNullOrEmpty(p.AsValueString()) && string.IsNullOrEmpty(p.AsString())) + /// Processes the provided list of elements, applying specific validations and transformations based on the element type. + /// + /// A collection of elements to process. + /// + /// A collection of elements after applying the respective validations and transformations. + /// + /// + /// Current Validations and Transformations: + /// - Zones are expanded into their constituent spaces. + /// - [Add additional validations here as they are implemented.] + /// + private static IEnumerable HandleSelectedObjectDescendants(IEnumerable selectedObjects) + { + // Handle the resolution of selected Elements to their convertable states here + foreach (var element in selectedObjects) + { + switch (element) { - return value; - } + case Autodesk.Revit.DB.Mechanical.Zone zone: + foreach (var space in zone.Spaces.OfType()) + { + yield return space; + } - if (!string.IsNullOrEmpty(p.AsValueString())) - { - return p.AsValueString().ToLowerInvariant(); - } - else - { - return p.AsString().ToLowerInvariant(); - } - } + break; - /// Processes the provided list of elements, applying specific validations and transformations based on the element type. - /// - /// A collection of elements to process. - /// - /// A collection of elements after applying the respective validations and transformations. - /// - /// - /// Current Validations and Transformations: - /// - Zones are expanded into their constituent spaces. - /// - [Add additional validations here as they are implemented.] - /// - private static IEnumerable HandleSelectedObjectDescendants(IEnumerable selectedObjects) - { - // Handle the resolution of selected Elements to their convertable states here - foreach (var element in selectedObjects) - { - switch (element) - { - case Autodesk.Revit.DB.Mechanical.Zone zone: - foreach (var space in zone.Spaces.OfType()) - yield return space; - break; - - default: - yield return element; - break; - } + default: + yield return element; + break; } } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Send.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Send.cs index 1c1871f5cf..5611ff5697 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Send.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Send.cs @@ -21,247 +21,258 @@ using Speckle.Core.Models; using Speckle.Core.Transports; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit + // used to store the Stream State settings when sending/receiving + private List? CurrentSettings { get; set; } + + /// + /// Converts the Revit elements that have been added to the stream by the user, sends them to + /// the Server and the local DB, and creates a commit with the objects. + /// + /// StreamState passed by the UI + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + public override async Task SendStream(StreamState state, ProgressViewModel progress) { - // used to store the Stream State settings when sending/receiving - private List? CurrentSettings { get; set; } - - /// - /// Converts the Revit elements that have been added to the stream by the user, sends them to - /// the Server and the local DB, and creates a commit with the objects. - /// - /// StreamState passed by the UI - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - public override async Task SendStream(StreamState state, ProgressViewModel progress) + using var ctx = RevitConverterState.Push(); + + //make sure to instance a new copy so all values are reset correctly + var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); + converter.SetContextDocument(CurrentDoc.Document); + converter.Report.ReportObjects.Clear(); + + // set converter settings as tuples (setting slug, setting selection) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - using var ctx = RevitConverterState.Push(); - - //make sure to instance a new copy so all values are reset correctly - var converter = (ISpeckleConverter)Activator.CreateInstance(Converter.GetType()); - converter.SetContextDocument(CurrentDoc.Document); - converter.Report.ReportObjects.Clear(); - - // set converter settings as tuples (setting slug, setting selection) - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); - - var streamId = state.StreamId; - var client = state.Client; - - // The selectedObjects needs to be collected inside the Revit API context or else, in rare cases, - // the filteredElementCollectors will throw a "modification forbidden" exception. This can be reproduced - // by opening Snowdon towers in R24 and immediately sending the default 3D view from the landing page - var selectedObjects = await APIContext - .Run(_ => GetSelectionFilterObjects(converter, state.Filter)) - .ConfigureAwait(false); - - selectedObjects = HandleSelectedObjectDescendants(selectedObjects).ToList(); - state.SelectedObjectIds = selectedObjects.Select(x => x.UniqueId).Distinct().ToList(); - - if (!selectedObjects.Any()) - throw new InvalidOperationException( - "There are zero objects to send. Please use a filter, or set some via selection." - ); - converter.SetContextDocument(revitDocumentAggregateCache); - converter.SetContextObjects( - selectedObjects - .Select(x => new ApplicationObject(x.UniqueId, x.GetType().ToString()) { applicationId = x.UniqueId }) - .ToList() + settings.Add(setting.Slug, setting.Selection); + } + + converter.SetConverterSettings(settings); + + var streamId = state.StreamId; + var client = state.Client; + + // The selectedObjects needs to be collected inside the Revit API context or else, in rare cases, + // the filteredElementCollectors will throw a "modification forbidden" exception. This can be reproduced + // by opening Snowdon towers in R24 and immediately sending the default 3D view from the landing page + var selectedObjects = await APIContext + .Run(_ => GetSelectionFilterObjects(converter, state.Filter)) + .ConfigureAwait(false); + + selectedObjects = HandleSelectedObjectDescendants(selectedObjects).ToList(); + state.SelectedObjectIds = selectedObjects.Select(x => x.UniqueId).Distinct().ToList(); + + if (!selectedObjects.Any()) + { + throw new InvalidOperationException( + "There are zero objects to send. Please use a filter, or set some via selection." ); - var commitObject = converter.ConvertToSpeckle(CurrentDoc.Document) ?? new Collection(); - IRevitCommitObjectBuilder commitObjectBuilder; + } - if (converter is not IRevitCommitObjectBuilderExposer builderExposer) - { - throw new Exception( - $"Converter {converter.Name} by {converter.Author} does not provide the necessary object, {nameof(IRevitCommitObjectBuilder)}, needed to build the Speckle commit object." - ); - } - else - { - commitObjectBuilder = builderExposer.commitObjectBuilder; - } + converter.SetContextDocument(revitDocumentAggregateCache); + converter.SetContextObjects( + selectedObjects + .Select(x => new ApplicationObject(x.UniqueId, x.GetType().ToString()) { applicationId = x.UniqueId }) + .ToList() + ); + var commitObject = converter.ConvertToSpeckle(CurrentDoc.Document) ?? new Collection(); + IRevitCommitObjectBuilder commitObjectBuilder; - progress.Report = new ProgressReport(); - progress.Max = selectedObjects.Count; + if (converter is not IRevitCommitObjectBuilderExposer builderExposer) + { + throw new Exception( + $"Converter {converter.Name} by {converter.Author} does not provide the necessary object, {nameof(IRevitCommitObjectBuilder)}, needed to build the Speckle commit object." + ); + } + else + { + commitObjectBuilder = builderExposer.commitObjectBuilder; + } - var conversionProgressDict = new ConcurrentDictionary { ["Conversion"] = 0 }; - var convertedCount = 0; + progress.Report = new ProgressReport(); + progress.Max = selectedObjects.Count; - await APIContext - .Run(() => - { - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); - using var d3 = LogContext.PushProperty("converterSettings", settings); + var conversionProgressDict = new ConcurrentDictionary { ["Conversion"] = 0 }; + var convertedCount = 0; + + await APIContext + .Run(() => + { + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); + using var d3 = LogContext.PushProperty("converterSettings", settings); - foreach (var revitElement in selectedObjects) + foreach (var revitElement in selectedObjects) + { + if (progress.CancellationToken.IsCancellationRequested) { - if (progress.CancellationToken.IsCancellationRequested) - break; + break; + } - bool isAlreadyConverted = GetOrCreateApplicationObject( - revitElement, - converter.Report, - out ApplicationObject reportObj - ); - if (isAlreadyConverted) - continue; + bool isAlreadyConverted = GetOrCreateApplicationObject( + revitElement, + converter.Report, + out ApplicationObject reportObj + ); + if (isAlreadyConverted) + { + continue; + } - progress.Report.Log(reportObj); + progress.Report.Log(reportObj); - //Add context to logger - using var _d3 = LogContext.PushProperty("fromType", revitElement.GetType()); - using var _d4 = LogContext.PushProperty("elementCategory", revitElement.Category?.Name); + //Add context to logger + using var _d3 = LogContext.PushProperty("fromType", revitElement.GetType()); + using var _d4 = LogContext.PushProperty("elementCategory", revitElement.Category?.Name); - try - { - converter.Report.Log(reportObj); // Log object so converter can access + try + { + converter.Report.Log(reportObj); // Log object so converter can access - Base result = ConvertToSpeckle(revitElement, converter); + Base result = ConvertToSpeckle(revitElement, converter); - reportObj.Update( - status: ApplicationObject.State.Created, - logItem: $"Sent as {ConnectorRevitUtils.SimplifySpeckleType(result.speckle_type)}" - ); - if (result.applicationId != reportObj.applicationId) - { - SpeckleLog.Logger.Information( - "Conversion result of type {elementType} has a different application Id ({actualId}) to the report object {expectedId}", - revitElement.GetType(), - result.applicationId, - reportObj.applicationId - ); - result.applicationId = reportObj.applicationId; - } - commitObjectBuilder.IncludeObject(result, revitElement); - convertedCount++; - } - catch (Exception ex) + reportObj.Update( + status: ApplicationObject.State.Created, + logItem: $"Sent as {ConnectorRevitUtils.SimplifySpeckleType(result.speckle_type)}" + ); + if (result.applicationId != reportObj.applicationId) { - ConnectorHelpers.LogConversionException(ex); - - var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); - reportObj.Update(status: failureStatus, logItem: ex.Message); + SpeckleLog.Logger.Information( + "Conversion result of type {elementType} has a different application Id ({actualId}) to the report object {expectedId}", + revitElement.GetType(), + result.applicationId, + reportObj.applicationId + ); + result.applicationId = reportObj.applicationId; } + commitObjectBuilder.IncludeObject(result, revitElement); + convertedCount++; + } + catch (Exception ex) + { + ConnectorHelpers.LogConversionException(ex); - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); - - YieldToUIThread(TimeSpan.FromMilliseconds(1)); + var failureStatus = ConnectorHelpers.GetAppObjectFailureState(ex); + reportObj.Update(status: failureStatus, logItem: ex.Message); } - }) - .ConfigureAwait(false); - revitDocumentAggregateCache.InvalidateAll(); + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); - progress.Report.Merge(converter.Report); + YieldToUIThread(TimeSpan.FromMilliseconds(1)); + } + }) + .ConfigureAwait(false); - progress.CancellationToken.ThrowIfCancellationRequested(); + revitDocumentAggregateCache.InvalidateAll(); - if (convertedCount == 0) - { - throw new SpeckleException("Zero objects converted successfully. Send stopped."); - } + progress.Report.Merge(converter.Report); - commitObjectBuilder.BuildCommitObject(commitObject); + progress.CancellationToken.ThrowIfCancellationRequested(); - var transports = new List() { new ServerTransport(client.Account, streamId) }; + if (convertedCount == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } - var objectId = await Operations - .Send( - @object: commitObject, - cancellationToken: progress.CancellationToken, - transports: transports, - onProgressAction: dict => progress.Update(dict), - onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, - disposeTransports: true - ) - .ConfigureAwait(true); + commitObjectBuilder.BuildCommitObject(commitObject); - progress.CancellationToken.ThrowIfCancellationRequested(); + var transports = new List() { new ServerTransport(client.Account, streamId) }; - var actualCommit = new CommitCreateInput() - { - streamId = streamId, - objectId = objectId, - branchName = state.BranchName, - message = state.CommitMessage ?? $"Sent {convertedCount} objects from {ConnectorRevitUtils.RevitAppName}.", - sourceApplication = ConnectorRevitUtils.RevitAppName, - }; + var objectId = await Operations + .Send( + @object: commitObject, + cancellationToken: progress.CancellationToken, + transports: transports, + onProgressAction: dict => progress.Update(dict), + onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, + disposeTransports: true + ) + .ConfigureAwait(true); - if (state.PreviousCommitId != null) - { - actualCommit.parents = new List() { state.PreviousCommitId }; - } + progress.CancellationToken.ThrowIfCancellationRequested(); - var commitId = await ConnectorHelpers - .CreateCommit(client, actualCommit, progress.CancellationToken) - .ConfigureAwait(false); - - return commitId; + var actualCommit = new CommitCreateInput() + { + streamId = streamId, + objectId = objectId, + branchName = state.BranchName, + message = state.CommitMessage ?? $"Sent {convertedCount} objects from {ConnectorRevitUtils.RevitAppName}.", + sourceApplication = ConnectorRevitUtils.RevitAppName, + }; + + if (state.PreviousCommitId != null) + { + actualCommit.parents = new List() { state.PreviousCommitId }; } - public static bool GetOrCreateApplicationObject( - Element revitElement, - ProgressReport report, - out ApplicationObject reportObj - ) - { - if (report.ReportObjects.TryGetValue(revitElement.UniqueId, out var applicationObject)) - { - reportObj = applicationObject; - return true; - } + var commitId = await ConnectorHelpers + .CreateCommit(client, actualCommit, progress.CancellationToken) + .ConfigureAwait(false); + + return commitId; + } - string descriptor = ConnectorRevitUtils.ObjectDescriptor(revitElement); - reportObj = new(revitElement.UniqueId, descriptor) { applicationId = revitElement.UniqueId }; - return false; + public static bool GetOrCreateApplicationObject( + Element revitElement, + ProgressReport report, + out ApplicationObject reportObj + ) + { + if (report.ReportObjects.TryGetValue(revitElement.UniqueId, out var applicationObject)) + { + reportObj = applicationObject; + return true; } - private DateTime timerStarted = DateTime.MinValue; + string descriptor = ConnectorRevitUtils.ObjectDescriptor(revitElement); + reportObj = new(revitElement.UniqueId, descriptor) { applicationId = revitElement.UniqueId }; + return false; + } - private void YieldToUIThread(TimeSpan delay) - { - var currentTime = DateTime.UtcNow; + private DateTime timerStarted = DateTime.MinValue; - if (currentTime.Subtract(timerStarted) < TimeSpan.FromSeconds(.15)) - { - return; - } + private void YieldToUIThread(TimeSpan delay) + { + var currentTime = DateTime.UtcNow; - using CancellationTokenSource s = new(delay); - Dispatcher.UIThread.MainLoop(s.Token); - timerStarted = currentTime; + if (currentTime.Subtract(timerStarted) < TimeSpan.FromSeconds(.15)) + { + return; } - private static Base ConvertToSpeckle(Element revitElement, ISpeckleConverter converter) + using CancellationTokenSource s = new(delay); + Dispatcher.UIThread.MainLoop(s.Token); + timerStarted = currentTime; + } + + private static Base ConvertToSpeckle(Element revitElement, ISpeckleConverter converter) + { + if (!converter.CanConvertToSpeckle(revitElement)) { - if (!converter.CanConvertToSpeckle(revitElement)) + string skipMessage = revitElement switch { - string skipMessage = revitElement switch - { - RevitLinkInstance => "Enable linked model support from the settings to send this object", - _ => "Sending this object type is not supported yet" - }; - - throw new ConversionSkippedException(skipMessage, revitElement); - } + RevitLinkInstance => "Enable linked model support from the settings to send this object", + _ => "Sending this object type is not supported yet" + }; - Base conversionResult = converter.ConvertToSpeckle(revitElement); + throw new ConversionSkippedException(skipMessage, revitElement); + } - if (conversionResult == null) - throw new SpeckleException( - $"Conversion of {revitElement.GetType().Name} with id {revitElement.Id} (ToSpeckle) returned null" - ); + Base conversionResult = converter.ConvertToSpeckle(revitElement); - return conversionResult; + if (conversionResult == null) + { + throw new SpeckleException( + $"Conversion of {revitElement.GetType().Name} with id {revitElement.Id} (ToSpeckle) returned null" + ); } + + return conversionResult; } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Settings.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Settings.cs index e64228c404..6874127e1e 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Settings.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.Settings.cs @@ -3,137 +3,144 @@ using Autodesk.Revit.DB; using DesktopUI2.Models.Settings; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit { - public partial class ConnectorBindingsRevit - { - // CAUTION: these strings need to have the same values as in the converter - const string InternalOrigin = "Internal Origin (default)"; - const string ProjectBase = "Project Base"; - const string Survey = "Survey"; + // CAUTION: these strings need to have the same values as in the converter + const string InternalOrigin = "Internal Origin (default)"; + const string ProjectBase = "Project Base"; + const string Survey = "Survey"; - const string defaultValue = "Default"; - const string dxf = "DXF"; - const string familyDxf = "Family DXF"; + const string defaultValue = "Default"; + const string dxf = "DXF"; + const string familyDxf = "Family DXF"; - const string StructuralFraming = "Structural Framing"; - const string StructuralWalls = "Structural Walls"; - const string ArchitecturalWalls = "Achitectural Walls"; + const string StructuralFraming = "Structural Framing"; + const string StructuralWalls = "Structural Walls"; + const string ArchitecturalWalls = "Achitectural Walls"; - public const string noMapping = "Never"; - public const string everyReceive = "Always"; - public const string forNewTypes = "For New Types"; + public const string noMapping = "Never"; + public const string everyReceive = "Always"; + public const string forNewTypes = "For New Types"; - public const string DsFallbackSlug = "direct-shape-strategy"; - public const string DsFallbackOnError = "On Error"; - public const string DsFallbackAways = "Always"; - public const string DsFallbackNever = "Never"; + public const string DsFallbackSlug = "direct-shape-strategy"; + public const string DsFallbackOnError = "On Error"; + public const string DsFallbackAways = "Always"; + public const string DsFallbackNever = "Never"; - const string DetailLevelCoarse = "Coarse"; - const string DetailLevelMedium = "Medium"; - const string DetailLevelFine = "Fine"; + const string DetailLevelCoarse = "Coarse"; + const string DetailLevelMedium = "Medium"; + const string DetailLevelFine = "Fine"; + + public override List GetSettings() + { + List referencePoints = new() { InternalOrigin }; + List prettyMeshOptions = new() { defaultValue, dxf, familyDxf }; + List mappingOptions = new() { noMapping, everyReceive, forNewTypes }; - public override List GetSettings() + // find project base point and survey point. these don't always have name props, so store them under custom strings + var basePoint = new FilteredElementCollector(CurrentDoc.Document) + .OfClass(typeof(BasePoint)) + .Cast() + .FirstOrDefault(o => !o.IsShared); + if (basePoint != null) { - List referencePoints = new List() { InternalOrigin }; - List prettyMeshOptions = new List() { defaultValue, dxf, familyDxf }; - List mappingOptions = new List() { noMapping, everyReceive, forNewTypes }; + referencePoints.Add(ProjectBase); + } - // find project base point and survey point. these don't always have name props, so store them under custom strings - var basePoint = new FilteredElementCollector(CurrentDoc.Document) - .OfClass(typeof(BasePoint)) - .Cast() - .FirstOrDefault(o => !o.IsShared); - if (basePoint != null) - referencePoints.Add(ProjectBase); - var surveyPoint = new FilteredElementCollector(CurrentDoc.Document) - .OfClass(typeof(BasePoint)) - .Cast() - .FirstOrDefault(o => o.IsShared); - if (surveyPoint != null) - referencePoints.Add(Survey); + var surveyPoint = new FilteredElementCollector(CurrentDoc.Document) + .OfClass(typeof(BasePoint)) + .Cast() + .FirstOrDefault(o => o.IsShared); + if (surveyPoint != null) + { + referencePoints.Add(Survey); + } - return new List + return new List + { + new ListBoxSetting { - new ListBoxSetting - { - Slug = "reference-point", - Name = "Reference Point", - Icon = "LocationSearching", - Values = referencePoints, - Selection = InternalOrigin, - Description = "Sends or receives stream objects in relation to this document point" - }, - new CheckBoxSetting - { - Slug = "linkedmodels-send", - Name = "Send Linked Models", - Icon = "Link", - IsChecked = false, - Description = "Include Linked Models in the selection filters when sending" - }, - new CheckBoxSetting - { - Slug = "linkedmodels-receive", - Name = "Receive Linked Models", - Icon = "Link", - IsChecked = false, - Description = - "Include Linked Models when receiving NOTE: elements from linked models will be received in the current document" - }, - // new CheckBoxSetting - // { - // Slug = "recieve-objects-mesh", - // Name = "Receive Objects as DirectShape", - // Icon = "Link", - // IsChecked = false, - // Description = "Receive the stream as a Meshes only" - // }, - new ListBoxSetting - { - Slug = DsFallbackSlug, - Name = "Fallback to DirectShape on receive", - Icon = "Link", - Values = new List { DsFallbackAways, DsFallbackOnError, DsFallbackNever }, - Selection = DsFallbackOnError, - Description = "Determines when to fallback to DirectShape on receive.\n\nAways: all objects will be received as DirectShapes\nOn Error: only objects that fail or whose types are missing\nNever: disables the fallback behavior" - }, - new MultiSelectBoxSetting - { - Slug = "disallow-join", - Name = "Disallow Join For Elements", - Icon = "CallSplit", - Description = "Determines which objects should not be allowed to join by default when receiving", - Values = new List() { ArchitecturalWalls, StructuralWalls, StructuralFraming } - }, - new ListBoxSetting - { - Slug = "pretty-mesh", - Name = "Mesh Import Method", - Icon = "ChartTimelineVarient", - Values = prettyMeshOptions, - Selection = defaultValue, - Description = "Determines the display style of imported meshes" - }, - new MappingSetting - { - Slug = "receive-mappings", - Name = "Missing Type Mapping", - Icon = "LocationSearching", - Values = mappingOptions, - Selection = forNewTypes, - Description = "Determines when the missing types dialog is shown\n\nNever: the dialog is never shown\nAlways: the dialog is always shown, useful to edit existing mappings\nFor New Types: the dialog is only shown if there are new unmapped types\n\nNOTE: no dialog is shown if Fallback to DirectShape is set to Always" - }, - new ListBoxSetting - { - Slug = "detail-level", - Name = "Mesh Export Detail Level (alpha)", - Icon = "Link", - Values = new List() { DetailLevelCoarse, DetailLevelMedium, DetailLevelFine }, - Selection = DetailLevelFine, - Description = "Determines the level of detail in which meshes are sent to Speckle. \n\nThis feature is in alpha because primitive objects such as curves, \nwhich are commonly found in coarse or medium detail level element representations, are not supported yet." - }, - }; - } + Slug = "reference-point", + Name = "Reference Point", + Icon = "LocationSearching", + Values = referencePoints, + Selection = InternalOrigin, + Description = "Sends or receives stream objects in relation to this document point" + }, + new CheckBoxSetting + { + Slug = "linkedmodels-send", + Name = "Send Linked Models", + Icon = "Link", + IsChecked = false, + Description = "Include Linked Models in the selection filters when sending" + }, + new CheckBoxSetting + { + Slug = "linkedmodels-receive", + Name = "Receive Linked Models", + Icon = "Link", + IsChecked = false, + Description = + "Include Linked Models when receiving NOTE: elements from linked models will be received in the current document" + }, + // new CheckBoxSetting + // { + // Slug = "recieve-objects-mesh", + // Name = "Receive Objects as DirectShape", + // Icon = "Link", + // IsChecked = false, + // Description = "Receive the stream as a Meshes only" + // }, + new ListBoxSetting + { + Slug = DsFallbackSlug, + Name = "Fallback to DirectShape on receive", + Icon = "Link", + Values = new List { DsFallbackAways, DsFallbackOnError, DsFallbackNever }, + Selection = DsFallbackOnError, + Description = + "Determines when to fallback to DirectShape on receive.\n\nAways: all objects will be received as DirectShapes\nOn Error: only objects that fail or whose types are missing\nNever: disables the fallback behavior" + }, + new MultiSelectBoxSetting + { + Slug = "disallow-join", + Name = "Disallow Join For Elements", + Icon = "CallSplit", + Description = "Determines which objects should not be allowed to join by default when receiving", + Values = new List() { ArchitecturalWalls, StructuralWalls, StructuralFraming } + }, + new ListBoxSetting + { + Slug = "pretty-mesh", + Name = "Mesh Import Method", + Icon = "ChartTimelineVarient", + Values = prettyMeshOptions, + Selection = defaultValue, + Description = "Determines the display style of imported meshes" + }, + new MappingSetting + { + Slug = "receive-mappings", + Name = "Missing Type Mapping", + Icon = "LocationSearching", + Values = mappingOptions, + Selection = forNewTypes, + Description = + "Determines when the missing types dialog is shown\n\nNever: the dialog is never shown\nAlways: the dialog is always shown, useful to edit existing mappings\nFor New Types: the dialog is only shown if there are new unmapped types\n\nNOTE: no dialog is shown if Fallback to DirectShape is set to Always" + }, + new ListBoxSetting + { + Slug = "detail-level", + Name = "Mesh Export Detail Level (alpha)", + Icon = "Link", + Values = new List() { DetailLevelCoarse, DetailLevelMedium, DetailLevelFine }, + Selection = DetailLevelFine, + Description = + "Determines the level of detail in which meshes are sent to Speckle. \n\nThis feature is in alpha because primitive objects such as curves, \nwhich are commonly found in coarse or medium detail level element representations, are not supported yet." + }, + }; } } diff --git a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.cs b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.cs index 02735564db..044aca5d8a 100644 --- a/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.cs +++ b/ConnectorRevit/ConnectorRevit/UI/ConnectorBindingsRevit.cs @@ -10,76 +10,81 @@ using Speckle.Core.Kits; using Timer = System.Timers.Timer; -namespace Speckle.ConnectorRevit.UI +namespace Speckle.ConnectorRevit.UI; + +public partial class ConnectorBindingsRevit : ConnectorBindings { - public partial class ConnectorBindingsRevit : ConnectorBindings - { - public static UIApplication RevitApp; + public static UIApplication RevitApp; - public static UIDocument CurrentDoc => RevitApp.ActiveUIDocument; + public static UIDocument CurrentDoc => RevitApp.ActiveUIDocument; - public Timer SelectionTimer; + public Timer SelectionTimer; - //Only use an instance of the converter as a local variable to avoid conflicts if multiple sending/receiving - //operations are happening at the same time - public ISpeckleConverter Converter { get; set; } = KitManager.GetDefaultKit().LoadConverter(ConnectorRevitUtils.RevitAppName); + //Only use an instance of the converter as a local variable to avoid conflicts if multiple sending/receiving + //operations are happening at the same time + public ISpeckleConverter Converter { get; set; } = + KitManager.GetDefaultKit().LoadConverter(ConnectorRevitUtils.RevitAppName); - public List ConversionErrors { get; set; } = new List(); + public List ConversionErrors { get; set; } = new List(); - /// - /// Keeps track of errors in the operations of send/receive. - /// - public List OperationErrors { get; set; } = new List(); + /// + /// Keeps track of errors in the operations of send/receive. + /// + public List OperationErrors { get; set; } = new List(); - private static IRevitDocumentAggregateCache revitDocumentAggregateCache; - public ConnectorBindingsRevit(UIApplication revitApp) : base() - { - RevitApp = revitApp; - revitDocumentAggregateCache = new RevitDocumentAggregateCache(new UIDocumentProvider(revitApp)); - } + private static IRevitDocumentAggregateCache revitDocumentAggregateCache; - private void SelectionTimer_Elapsed(object sender, ElapsedEventArgs e) - { - var selectedObjects = GetSelectedObjects(); + public ConnectorBindingsRevit(UIApplication revitApp) + : base() + { + RevitApp = revitApp; + revitDocumentAggregateCache = new RevitDocumentAggregateCache(new UIDocumentProvider(revitApp)); + } - //TODO + private void SelectionTimer_Elapsed(object sender, ElapsedEventArgs e) + { + var selectedObjects = GetSelectedObjects(); - //NotifyUi(new UpdateSelectionCountEvent() { SelectionCount = selectedObjects.Count }); - //NotifyUi(new UpdateSelectionEvent() { ObjectIds = selectedObjects }); - } + //TODO - public static string HostAppNameVersion => ConnectorRevitUtils.RevitAppName.Replace("Revit", "Revit "); //hack for ADSK store - public static string HostAppName => HostApplications.Revit.Slug; + //NotifyUi(new UpdateSelectionCountEvent() { SelectionCount = selectedObjects.Count }); + //NotifyUi(new UpdateSelectionEvent() { ObjectIds = selectedObjects }); + } - public override string GetHostAppName() => HostAppName; - public override string GetHostAppNameVersion() => HostAppNameVersion; - - public override string GetDocumentId() => CurrentDoc?.Document?.GetHashCode().ToString(); + public static string HostAppNameVersion => ConnectorRevitUtils.RevitAppName.Replace("Revit", "Revit "); //hack for ADSK store + public static string HostAppName => HostApplications.Revit.Slug; - public override string GetDocumentLocation() => CurrentDoc.Document.PathName; + public override string GetHostAppName() => HostAppName; - public override string GetActiveViewName() => CurrentDoc.Document.ActiveView.Title; + public override string GetHostAppNameVersion() => HostAppNameVersion; - public override string GetFileName() => CurrentDoc.Document.Title; + public override string GetDocumentId() => CurrentDoc?.Document?.GetHashCode().ToString(); - public override List GetStreamsInFile() - { - var streams = new List(); - if (CurrentDoc != null) - streams = StreamStateManager.ReadState(CurrentDoc.Document); + public override string GetDocumentLocation() => CurrentDoc.Document.PathName; - return streams; - } + public override string GetActiveViewName() => CurrentDoc.Document.ActiveView.Title; - public override List GetReceiveModes() - { - return new List { ReceiveMode.Update, ReceiveMode.Create, ReceiveMode.Ignore }; - } + public override string GetFileName() => CurrentDoc.Document.Title; - //TODO - public override List GetCustomStreamMenuItems() + public override List GetStreamsInFile() + { + var streams = new List(); + if (CurrentDoc != null) { - return new List(); + streams = StreamStateManager.ReadState(CurrentDoc.Document); } + + return streams; + } + + public override List GetReceiveModes() + { + return new List { ReceiveMode.Update, ReceiveMode.Create, ReceiveMode.Ignore }; + } + + //TODO + public override List GetCustomStreamMenuItems() + { + return new List(); } } diff --git a/ConnectorRevit/ConnectorRevit/UI/Panel.xaml.cs b/ConnectorRevit/ConnectorRevit/UI/Panel.xaml.cs index 351e4f8dfd..5b7524c478 100644 --- a/ConnectorRevit/ConnectorRevit/UI/Panel.xaml.cs +++ b/ConnectorRevit/ConnectorRevit/UI/Panel.xaml.cs @@ -1,57 +1,55 @@ -using System; +using System; using System.Windows; using System.Windows.Controls; using Autodesk.Revit.UI; using DesktopUI2.Views; -namespace Speckle.ConnectorRevit +namespace Speckle.ConnectorRevit; + +/// +/// Interaction logic for Page1.xaml +/// +public partial class Panel : Page, Autodesk.Revit.UI.IDockablePaneProvider { - /// - /// Interaction logic for Page1.xaml - /// - public partial class Panel : Page, Autodesk.Revit.UI.IDockablePaneProvider + public Panel() { - public Panel() - { - InitializeComponent(); - AvaloniaHost.MessageHook += AvaloniaHost_MessageHook; - } - - private const UInt32 DLGC_WANTARROWS = 0x0001; - private const UInt32 DLGC_HASSETSEL = 0x0008; - private const UInt32 DLGC_WANTCHARS = 0x0080; - private const UInt32 WM_GETDLGCODE = 0x0087; - - /// - /// WPF was handling all the text input events and they where not being passed to the Avalonia control - /// This ensures they are passed, see: https://github.com/AvaloniaUI/Avalonia/issues/8198#issuecomment-1168634451 - /// - private IntPtr AvaloniaHost_MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - if (msg != WM_GETDLGCODE) return IntPtr.Zero; - handled = true; - return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL); - } - - - /// - /// Switching documents in Revit causes the Panel content to "reset", so we need to re-nitialize the avalonia host each time - /// - public void Init() - { - AvaloniaHost.Content = new MainUserControl(); - } + InitializeComponent(); + AvaloniaHost.MessageHook += AvaloniaHost_MessageHook; + } + private const UInt32 DLGC_WANTARROWS = 0x0001; + private const UInt32 DLGC_HASSETSEL = 0x0008; + private const UInt32 DLGC_WANTCHARS = 0x0080; + private const UInt32 WM_GETDLGCODE = 0x0087; - public void SetupDockablePane(Autodesk.Revit.UI.DockablePaneProviderData data) + /// + /// WPF was handling all the text input events and they where not being passed to the Avalonia control + /// This ensures they are passed, see: https://github.com/AvaloniaUI/Avalonia/issues/8198#issuecomment-1168634451 + /// + private IntPtr AvaloniaHost_MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (msg != WM_GETDLGCODE) { - data.FrameworkElement = this as FrameworkElement; - data.InitialState = new Autodesk.Revit.UI.DockablePaneState(); - data.InitialState.DockPosition = DockPosition.Tabbed; - data.InitialState.TabBehind = Autodesk.Revit.UI.DockablePanes.BuiltInDockablePanes.ProjectBrowser; + return IntPtr.Zero; } + handled = true; + return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL); } + /// + /// Switching documents in Revit causes the Panel content to "reset", so we need to re-nitialize the avalonia host each time + /// + public void Init() + { + AvaloniaHost.Content = new MainUserControl(); + } + public void SetupDockablePane(Autodesk.Revit.UI.DockablePaneProviderData data) + { + data.FrameworkElement = this as FrameworkElement; + data.InitialState = new Autodesk.Revit.UI.DockablePaneState(); + data.InitialState.DockPosition = DockPosition.Tabbed; + data.InitialState.TabBehind = Autodesk.Revit.UI.DockablePanes.BuiltInDockablePanes.ProjectBrowser; + } } diff --git a/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitDocumentAggregateCacheExtensions.cs b/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitDocumentAggregateCacheExtensions.cs index 66cd71ee72..4b8e901fa7 100644 --- a/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitDocumentAggregateCacheExtensions.cs +++ b/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitDocumentAggregateCacheExtensions.cs @@ -8,19 +8,23 @@ using RevitSharedResources.Interfaces; using SCH = RevitSharedResources.Helpers.Categories; -namespace RevitSharedResources.Extensions.SpeckleExtensions +namespace RevitSharedResources.Extensions.SpeckleExtensions; + +public static class IRevitDocumentAggregateCacheExtensions { - public static class IRevitDocumentAggregateCacheExtensions + public static IRevitObjectCache GetOrInitializeWithDefaultFactory(this IRevitDocumentAggregateCache cache) { - public static IRevitObjectCache GetOrInitializeWithDefaultFactory(this IRevitDocumentAggregateCache cache) - { - return cache.GetOrInitializeCacheOfType(singleCache => + return cache.GetOrInitializeCacheOfType( + singleCache => { MethodInfo cacheFactoryMethod = null; foreach (var method in typeof(IRevitDocumentAggregateCacheExtensions).GetMethods()) { var firstParam = method.GetParameters().FirstOrDefault(); - if (firstParam == null || firstParam.ParameterType != typeof(IRevitObjectCache)) continue; + if (firstParam == null || firstParam.ParameterType != typeof(IRevitObjectCache)) + { + continue; + } cacheFactoryMethod = method; break; @@ -28,58 +32,68 @@ public static IRevitObjectCache GetOrInitializeWithDefaultFactory(this IRe if (cacheFactoryMethod == null) { - throw new ArgumentException($"Cannot use {nameof(GetOrInitializeWithDefaultFactory)} with the generic parameter {typeof(T).Name} because there is no default factory defined for that object"); + throw new ArgumentException( + $"Cannot use {nameof(GetOrInitializeWithDefaultFactory)} with the generic parameter {typeof(T).Name} because there is no default factory defined for that object" + ); } cacheFactoryMethod.Invoke(null, new object[] { singleCache, cache.Document }); - }, out _); - } - - public static void CacheInitializer(IRevitObjectCache cache, Document doc) - { - var _categories = new Dictionary(); + }, + out _ + ); + } + public static void CacheInitializer(IRevitObjectCache cache, Document doc) + { + var _categories = new Dictionary(); - foreach (Category category in doc.Settings.Categories) + foreach (Category category in doc.Settings.Categories) + { + if (!Helpers.Extensions.Extensions.IsCategorySupported(category)) { - if (!Helpers.Extensions.Extensions.IsCategorySupported(category)) - continue; + continue; + } - //some categories, in other languages (eg DEU) have duplicated names #542 - if (_categories.ContainsKey(category.Name)) + //some categories, in other languages (eg DEU) have duplicated names #542 + if (_categories.ContainsKey(category.Name)) + { + var spec = category.Id.ToString(); + if (category.Parent != null) { - var spec = category.Id.ToString(); - if (category.Parent != null) - spec = category.Parent.Name; - _categories.Add($"{category.Name} ({spec})", category); + spec = category.Parent.Name; } - else - _categories.Add(category.Name, category); - } - cache.AddMany(_categories); + _categories.Add($"{category.Name} ({spec})", category); + } + else + { + _categories.Add(category.Name, category); + } } - public static void CacheInitializer(IRevitObjectCache cache, Document doc) + cache.AddMany(_categories); + } + + public static void CacheInitializer(IRevitObjectCache cache, Document doc) + { + var predefinedCategories = new List(); + foreach (var property in typeof(SCH).GetProperties(BindingFlags.Static | BindingFlags.Public)) { - var predefinedCategories = new List(); - foreach (var property in typeof(SCH).GetProperties(BindingFlags.Static | BindingFlags.Public)) + if (property.GetValue(null) is IRevitCategoryInfo categoryInfo) { - if (property.GetValue(null) is IRevitCategoryInfo categoryInfo) - { - predefinedCategories.Add(categoryInfo); - } + predefinedCategories.Add(categoryInfo); } - cache.AddMany(predefinedCategories, categoryInfo => categoryInfo.CategoryName); } + cache.AddMany(predefinedCategories, categoryInfo => categoryInfo.CategoryName); + } - public static void CacheInitializer(IRevitObjectCache cache, Document doc) - { - // don't do any default initialization - } - public static void CacheInitializer(IRevitObjectCache> cache, Document doc) - { - // don't do any default initialization - } + public static void CacheInitializer(IRevitObjectCache cache, Document doc) + { + // don't do any default initialization + } + + public static void CacheInitializer(IRevitObjectCache> cache, Document doc) + { + // don't do any default initialization } } diff --git a/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitObjectCacheExtensions.cs b/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitObjectCacheExtensions.cs index 2ad23e8f5d..2099593e16 100644 --- a/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitObjectCacheExtensions.cs +++ b/ConnectorRevit/RevitSharedResources/Extensions/SpeckleExtensions/IRevitObjectCacheExtensions.cs @@ -2,26 +2,28 @@ using Autodesk.Revit.DB; using RevitSharedResources.Interfaces; -namespace RevitSharedResources.Extensions.SpeckleExtensions +namespace RevitSharedResources.Extensions.SpeckleExtensions; + +public static class IRevitObjectCacheExtensions { - public static class IRevitObjectCacheExtensions + public static List GetOrAddGroupOfTypes( + this IRevitObjectCache> cache, + IRevitCategoryInfo categoryInfo + ) { - public static List GetOrAddGroupOfTypes(this IRevitObjectCache> cache, IRevitCategoryInfo categoryInfo) - { - var elementTypes = cache - .GetOrAdd( - categoryInfo.CategoryName, - () => categoryInfo.GetElementTypes(cache.ParentCache.Document - ), out bool isExistingValue); + var elementTypes = cache.GetOrAdd( + categoryInfo.CategoryName, + () => categoryInfo.GetElementTypes(cache.ParentCache.Document), + out bool isExistingValue + ); - // if type was added instead of retreived, add types to master cache to facilitate lookup later - if (!isExistingValue) - { - cache.ParentCache - .GetOrInitializeWithDefaultFactory() - .AddMany(elementTypes, type => categoryInfo.GetCategorySpecificTypeName(type.Name)); - } - return elementTypes; + // if type was added instead of retreived, add types to master cache to facilitate lookup later + if (!isExistingValue) + { + cache.ParentCache + .GetOrInitializeWithDefaultFactory() + .AddMany(elementTypes, type => categoryInfo.GetCategorySpecificTypeName(type.Name)); } + return elementTypes; } } diff --git a/ConnectorRevit/RevitSharedResources/Helpers/Categories.cs b/ConnectorRevit/RevitSharedResources/Helpers/Categories.cs index e2afebed0e..a9d9564747 100644 --- a/ConnectorRevit/RevitSharedResources/Helpers/Categories.cs +++ b/ConnectorRevit/RevitSharedResources/Helpers/Categories.cs @@ -10,7 +10,6 @@ namespace RevitSharedResources.Helpers; /// public static class Categories { - public static Dictionary All { get; } static Categories() @@ -27,7 +26,7 @@ static Categories() { nameof(Floor), Floor }, { nameof(Furniture), Furniture }, { nameof(Pipe), Pipe }, - { nameof(PlumbingFixture), PlumbingFixture}, + { nameof(PlumbingFixture), PlumbingFixture }, { nameof(Roof), Roof }, { nameof(Railing), Railing }, { nameof(StructuralFraming), StructuralFraming }, @@ -37,148 +36,112 @@ static Categories() { nameof(Undefined), Undefined }, }; } - public static RevitCategoryInfo CableTray { get; } = new( - nameof(CableTray), - typeof(DB.Electrical.CableTray), - typeof(DB.Electrical.CableTrayType), - new List() - ); - public static RevitCategoryInfo Ceiling { get; } = new( - nameof(Ceiling), - typeof(DB.Ceiling), - typeof(CeilingType), - new List() - ); - public static RevitCategoryInfo Column { get; } = new( - nameof(Column), - typeof(FamilyInstance), - typeof(FamilySymbol), - new List - { - BuiltInCategory.OST_Columns, - BuiltInCategory.OST_StructuralColumns - }); - public static RevitCategoryInfo Conduit { get; } = new( - nameof(Conduit), - typeof(DB.Electrical.Conduit), - typeof(DB.Electrical.ConduitType), - new List() - ); - public static RevitCategoryInfo Door { get; } = new( - nameof(Door), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List - { - BuiltInCategory.OST_Doors - }); - public static RevitCategoryInfo Duct { get; } = new( - nameof(Duct), - typeof(DB.Mechanical.Duct), - typeof(DB.MEPCurveType), - new List - { - BuiltInCategory.OST_DuctCurves, - BuiltInCategory.OST_FlexDuctCurves - }); - public static RevitCategoryInfo FamilyInstance { get; } = new( - nameof(FamilyInstance), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List() + + public static RevitCategoryInfo CableTray { get; } = + new( + nameof(CableTray), + typeof(DB.Electrical.CableTray), + typeof(DB.Electrical.CableTrayType), + new List() ); - public static RevitCategoryInfo Floor { get; } = new( - nameof(Floor), - typeof(DB.Floor), - typeof(DB.FloorType), - new List - { - BuiltInCategory.OST_Floors - }); - public static RevitCategoryInfo Furniture { get; } = new( - nameof(Furniture), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List - { - BuiltInCategory.OST_Furniture - }); + public static RevitCategoryInfo Ceiling { get; } = + new(nameof(Ceiling), typeof(DB.Ceiling), typeof(CeilingType), new List()); + public static RevitCategoryInfo Column { get; } = + new( + nameof(Column), + typeof(FamilyInstance), + typeof(FamilySymbol), + new List { BuiltInCategory.OST_Columns, BuiltInCategory.OST_StructuralColumns } + ); + public static RevitCategoryInfo Conduit { get; } = + new(nameof(Conduit), typeof(DB.Electrical.Conduit), typeof(DB.Electrical.ConduitType), new List()); + public static RevitCategoryInfo Door { get; } = + new( + nameof(Door), + typeof(DB.FamilyInstance), + typeof(DB.FamilySymbol), + new List { BuiltInCategory.OST_Doors } + ); + public static RevitCategoryInfo Duct { get; } = + new( + nameof(Duct), + typeof(DB.Mechanical.Duct), + typeof(DB.MEPCurveType), + new List { BuiltInCategory.OST_DuctCurves, BuiltInCategory.OST_FlexDuctCurves } + ); + public static RevitCategoryInfo FamilyInstance { get; } = + new(nameof(FamilyInstance), typeof(DB.FamilyInstance), typeof(DB.FamilySymbol), new List()); + public static RevitCategoryInfo Floor { get; } = + new( + nameof(Floor), + typeof(DB.Floor), + typeof(DB.FloorType), + new List { BuiltInCategory.OST_Floors } + ); + public static RevitCategoryInfo Furniture { get; } = + new( + nameof(Furniture), + typeof(DB.FamilyInstance), + typeof(DB.FamilySymbol), + new List { BuiltInCategory.OST_Furniture } + ); + //public static RevitCategoryInfo Material { get; } = new( - // nameof(Material), - // typeof(DB.Material), + // nameof(Material), + // typeof(DB.Material), // null, - // new List - // { - // BuiltInCategory.OST_Materials, + // new List + // { + // BuiltInCategory.OST_Materials, // BuiltInCategory.OST_PipeMaterials, // BuiltInCategory.OST_WireMaterials // }); - public static RevitCategoryInfo Pipe { get; } = new( - nameof(Pipe), - typeof(DB.Plumbing.Pipe), - typeof(DB.MEPCurveType), - new List - { - BuiltInCategory.OST_PipeCurves, - BuiltInCategory.OST_FlexPipeCurves - }); - public static RevitCategoryInfo PlumbingFixture { get; } = new( - nameof(PlumbingFixture), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List - { - BuiltInCategory.OST_PlumbingFixtures - }); - public static RevitCategoryInfo Roof { get; } = new( - nameof(Roof), - typeof(DB.RoofBase), - typeof(DB.RoofType), - new List - { - BuiltInCategory.OST_Roofs, - }); - public static RevitCategoryInfo Railing { get; } = new( - nameof(Railing), - typeof(DB.Architecture.Railing), - typeof(DB.Architecture.RailingType), - new List() + public static RevitCategoryInfo Pipe { get; } = + new( + nameof(Pipe), + typeof(DB.Plumbing.Pipe), + typeof(DB.MEPCurveType), + new List { BuiltInCategory.OST_PipeCurves, BuiltInCategory.OST_FlexPipeCurves } ); - public static RevitCategoryInfo StructuralFraming { get; } = new( - nameof(StructuralFraming), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List - { - BuiltInCategory.OST_StructuralFraming - }, - new List { "beam", "brace", "framing" }); - public static RevitCategoryInfo Wall { get; } = new( - nameof(Wall), - typeof(DB.Wall), - typeof(DB.WallType), - new List - { - BuiltInCategory.OST_Walls - }); - public static RevitCategoryInfo Window { get; } = new( - nameof(Window), - typeof(DB.FamilyInstance), - typeof(DB.FamilySymbol), - new List - { - BuiltInCategory.OST_Windows - }); - public static RevitCategoryInfo Wire { get; } = new( - nameof(Wire), - typeof(DB.Electrical.Wire), - typeof(DB.Electrical.WireType), - new List() + public static RevitCategoryInfo PlumbingFixture { get; } = + new( + nameof(PlumbingFixture), + typeof(DB.FamilyInstance), + typeof(DB.FamilySymbol), + new List { BuiltInCategory.OST_PlumbingFixtures } + ); + public static RevitCategoryInfo Roof { get; } = + new( + nameof(Roof), + typeof(DB.RoofBase), + typeof(DB.RoofType), + new List { BuiltInCategory.OST_Roofs, } + ); + public static RevitCategoryInfo Railing { get; } = + new( + nameof(Railing), + typeof(DB.Architecture.Railing), + typeof(DB.Architecture.RailingType), + new List() + ); + public static RevitCategoryInfo StructuralFraming { get; } = + new( + nameof(StructuralFraming), + typeof(DB.FamilyInstance), + typeof(DB.FamilySymbol), + new List { BuiltInCategory.OST_StructuralFraming }, + new List { "beam", "brace", "framing" } ); - public static RevitCategoryInfo Undefined { get; } = new( - nameof(Undefined), - null, - null, - new List() + public static RevitCategoryInfo Wall { get; } = + new(nameof(Wall), typeof(DB.Wall), typeof(DB.WallType), new List { BuiltInCategory.OST_Walls }); + public static RevitCategoryInfo Window { get; } = + new( + nameof(Window), + typeof(DB.FamilyInstance), + typeof(DB.FamilySymbol), + new List { BuiltInCategory.OST_Windows } ); + public static RevitCategoryInfo Wire { get; } = + new(nameof(Wire), typeof(DB.Electrical.Wire), typeof(DB.Electrical.WireType), new List()); + public static RevitCategoryInfo Undefined { get; } = new(nameof(Undefined), null, null, new List()); } diff --git a/ConnectorRevit/RevitSharedResources/Helpers/Extensions.cs b/ConnectorRevit/RevitSharedResources/Helpers/Extensions.cs index 399ff57f4b..b3b10a1ad9 100644 --- a/ConnectorRevit/RevitSharedResources/Helpers/Extensions.cs +++ b/ConnectorRevit/RevitSharedResources/Helpers/Extensions.cs @@ -20,13 +20,21 @@ public static class Extensions public static bool IsPhysicalElement(this Element e) { if (e.Category == null) + { return false; + } + if (e.ViewSpecific) + { return false; + } // TODO: Should this be filtering using the Supported categories list instead? // exclude specific unwanted categories if (((BuiltInCategory)e.Category.Id.IntegerValue) == BuiltInCategory.OST_HVAC_Zones) + { return false; + } + return e.Category.CategoryType == CategoryType.Model && e.Category.CanAddSubcategory; } @@ -57,11 +65,15 @@ public static bool HasCategory(this IEnumerable categories, Cat /// True if the CategoryType is Model, AnalyticalModel or Internal public static bool IsCategorySupported(this Category category) { - if (category.CategoryType == CategoryType.Model || - category.CategoryType == CategoryType.AnalyticalModel || - category.CategoryType == CategoryType.Internal || - category.Id.IntegerValue == -2000220) // Grids + if ( + category.CategoryType == CategoryType.Model + || category.CategoryType == CategoryType.AnalyticalModel + || category.CategoryType == CategoryType.Internal + || category.Id.IntegerValue == -2000220 + ) // Grids + { return true; + } return false; } @@ -73,10 +85,10 @@ public static bool IsCategorySupported(this Category category) /// True if the element's category is supported and if the element is not view dependent public static bool IsElementSupported(this Element e) { - if (e.Category == null || - e.ViewSpecific || - !IsCategorySupported(e.Category)) + if (e.Category == null || e.ViewSpecific || !IsCategorySupported(e.Category)) + { return false; + } return true; } diff --git a/ConnectorRevit/RevitSharedResources/Helpers/RevitCategoryInfo.cs b/ConnectorRevit/RevitSharedResources/Helpers/RevitCategoryInfo.cs index 4b59ea46fc..82caecc97a 100644 --- a/ConnectorRevit/RevitSharedResources/Helpers/RevitCategoryInfo.cs +++ b/ConnectorRevit/RevitSharedResources/Helpers/RevitCategoryInfo.cs @@ -4,54 +4,61 @@ using Autodesk.Revit.DB; using RevitSharedResources.Interfaces; -namespace RevitSharedResources.Helpers +namespace RevitSharedResources.Helpers; + +public class RevitCategoryInfo : IRevitCategoryInfo { - public class RevitCategoryInfo : IRevitCategoryInfo + public RevitCategoryInfo( + string name, + Type instanceType, + Type familyType, + List categories, + List categoryAliases = null + ) { - public RevitCategoryInfo(string name, Type instanceType, Type familyType, List categories, List categoryAliases = null) - { - CategoryName = name; - ElementInstanceType = instanceType; - ElementTypeType = familyType; - BuiltInCategories = categories; - CategoryAliases = categoryAliases ?? new List(); - } - public string CategoryName { get; } - public Type ElementInstanceType { get; } - public Type ElementTypeType { get; } - public ICollection BuiltInCategories { get; } - public List CategoryAliases { get; } + CategoryName = name; + ElementInstanceType = instanceType; + ElementTypeType = familyType; + BuiltInCategories = categories; + CategoryAliases = categoryAliases ?? new List(); + } - public bool ContainsRevitCategory(Category category) - { - return BuiltInCategories.Select(x => (int)x).Contains(category.Id.IntegerValue); - } + public string CategoryName { get; } + public Type ElementInstanceType { get; } + public Type ElementTypeType { get; } + public ICollection BuiltInCategories { get; } + public List CategoryAliases { get; } + + public bool ContainsRevitCategory(Category category) + { + return BuiltInCategories.Select(x => (int)x).Contains(category.Id.IntegerValue); + } - public List GetElementTypes(Document document) + public List GetElementTypes(Document document) + { + return GetElementTypes(document); + } + + public List GetElementTypes(Document document) + where T : ElementType + { + var collector = new FilteredElementCollector(document); + if (BuiltInCategories.Count > 0) { - return GetElementTypes(document); + using var filter = new ElementMulticategoryFilter(BuiltInCategories); + collector = collector.WherePasses(filter); } - public List GetElementTypes(Document document) - where T : ElementType + if (ElementTypeType != null) { - var collector = new FilteredElementCollector(document); - if (BuiltInCategories.Count > 0) - { - using var filter = new ElementMulticategoryFilter(BuiltInCategories); - collector = collector.WherePasses(filter); - } - if (ElementTypeType != null) - { - collector = collector.OfClass(ElementTypeType); - } - var elementTypes = collector.WhereElementIsElementType().Cast().ToList(); - collector.Dispose(); - return elementTypes; + collector = collector.OfClass(ElementTypeType); } + var elementTypes = collector.WhereElementIsElementType().Cast().ToList(); + collector.Dispose(); + return elementTypes; + } - public string GetCategorySpecificTypeName(string typeName) - { - return CategoryName + "_" + typeName; - } + public string GetCategorySpecificTypeName(string typeName) + { + return CategoryName + "_" + typeName; } } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategories.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategories.cs index 2470f241c6..7abb27d3ca 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategories.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategories.cs @@ -1,15 +1,14 @@ using System.Collections.Generic; using Speckle.Core.Models; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// Defines functionality to retreive from a object or a string of the category name. +/// +public interface IAllRevitCategories { - /// - /// Defines functionality to retreive from a object or a string of the category name. - /// - public interface IAllRevitCategories - { - public IRevitCategoryInfo GetRevitCategoryInfo(Base @base); - public IRevitCategoryInfo GetRevitCategoryInfo(Base @base); - public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName); - } + public IRevitCategoryInfo GetRevitCategoryInfo(Base @base); + public IRevitCategoryInfo GetRevitCategoryInfo(Base @base); + public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategoriesExposer.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategoriesExposer.cs index fd5fec8e13..e57a222f36 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategoriesExposer.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IAllRevitCategoriesExposer.cs @@ -1,10 +1,9 @@ -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// Enforces that the object that implements this interface (which should be the converter) has a bridge to . This allows the connector to gather from the converter without making the converter implement functionality that it isn't really supposed to implement. This is still a violation of the single responcibility principle, but it's a much smaller violation than having the converter implement directly. +/// +public interface IAllRevitCategoriesExposer { - /// - /// Enforces that the object that implements this interface (which should be the converter) has a bridge to . This allows the connector to gather from the converter without making the converter implement functionality that it isn't really supposed to implement. This is still a violation of the single responcibility principle, but it's a much smaller violation than having the converter implement directly. - /// - public interface IAllRevitCategoriesExposer - { - public IAllRevitCategories AllCategories { get; } - } + public IAllRevitCategories AllCategories { get; } } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IConvertedObjectsCache.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IConvertedObjectsCache.cs index a6f3938284..1974b82795 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IConvertedObjectsCache.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IConvertedObjectsCache.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// Objects that implement the IConvertedObjectsCache interface are responsible for +/// querying and mutating a cache of objects that have been converted during the current converion operation. +/// This object will then get passed into an IReceivedObjectsCache to be saved +/// +public interface IConvertedObjectsCache { - /// - /// Objects that implement the IConvertedObjectsCache interface are responsible for - /// querying and mutating a cache of objects that have been converted during the current converion operation. - /// This object will then get passed into an IReceivedObjectsCache to be saved - /// - public interface IConvertedObjectsCache - { - #region Add - public void AddConvertedObjects(TFrom converted, IList created); - #endregion + #region Add + public void AddConvertedObjects(TFrom converted, IList created); + #endregion - #region Query + #region Query - #region GetConverted - public IEnumerable GetConvertedObjects(); - public IEnumerable GetConvertedObjectsFromCreatedId(string id); - public bool HasConvertedObjectWithId(string id); - #endregion + #region GetConverted + public IEnumerable GetConvertedObjects(); + public IEnumerable GetConvertedObjectsFromCreatedId(string id); + public bool HasConvertedObjectWithId(string id); + #endregion - #region GetCreated - public IEnumerable GetCreatedObjects(); - public IEnumerable GetCreatedObjectsFromConvertedId(string id); - public bool HasCreatedObjectWithId(string id); - #endregion + #region GetCreated + public IEnumerable GetCreatedObjects(); + public IEnumerable GetCreatedObjectsFromConvertedId(string id); + public bool HasCreatedObjectWithId(string id); + #endregion - #endregion - } + #endregion } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IReceivedObjectIdMap.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IReceivedObjectIdMap.cs index 2848cb12c0..8ae2e48075 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IReceivedObjectIdMap.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IReceivedObjectIdMap.cs @@ -1,17 +1,16 @@ #nullable enable using System.Collections.Generic; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// Objects that implement the IReceivedObjectsCache interface are responsible for +/// reading, querying, mutating, and writing a cache of objects that have been previously received +/// +public interface IReceivedObjectIdMap { - /// - /// Objects that implement the IReceivedObjectsCache interface are responsible for - /// reading, querying, mutating, and writing a cache of objects that have been previously received - /// - public interface IReceivedObjectIdMap - { - public void AddConvertedElements(IConvertedObjectsCache convertedObjects); - public IEnumerable GetCreatedIdsFromConvertedId(string id); - public IEnumerable GetAllConvertedIds(); - public void RemoveConvertedId(string id); - } + public void AddConvertedElements(IConvertedObjectsCache convertedObjects); + public IEnumerable GetCreatedIdsFromConvertedId(string id); + public IEnumerable GetAllConvertedIds(); + public void RemoveConvertedId(string id); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCategoryInfo.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCategoryInfo.cs index 8db7edaa8f..f8cf8e57dc 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCategoryInfo.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCategoryInfo.cs @@ -2,22 +2,21 @@ using System.Collections.Generic; using Autodesk.Revit.DB; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// Defines the properties of a single, predefined, category that can be used to group objects that have similar characteristics or filter for objects of that category. +/// +public interface IRevitCategoryInfo { - /// - /// Defines the properties of a single, predefined, category that can be used to group objects that have similar characteristics or filter for objects of that category. - /// - public interface IRevitCategoryInfo - { - public string CategoryName { get; } - public List CategoryAliases { get; } - public Type ElementInstanceType { get; } - public Type ElementTypeType { get; } - public ICollection BuiltInCategories { get; } - public bool ContainsRevitCategory(Category category); - List GetElementTypes(Document document); - List GetElementTypes(Document document) - where T : ElementType; - string GetCategorySpecificTypeName(string typeName); - } + public string CategoryName { get; } + public List CategoryAliases { get; } + public Type ElementInstanceType { get; } + public Type ElementTypeType { get; } + public ICollection BuiltInCategories { get; } + public bool ContainsRevitCategory(Category category); + List GetElementTypes(Document document); + List GetElementTypes(Document document) + where T : ElementType; + string GetCategorySpecificTypeName(string typeName); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilder.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilder.cs index 447f709c7a..9530d2c5ef 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilder.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilder.cs @@ -4,11 +4,10 @@ using Autodesk.Revit.DB; using Speckle.Core.Models; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +public interface IRevitCommitObjectBuilder { - public interface IRevitCommitObjectBuilder - { - void BuildCommitObject(Base rootCommitObject); - void IncludeObject(Base conversionResult, Element nativeElement); - } + void BuildCommitObject(Base rootCommitObject); + void IncludeObject(Base conversionResult, Element nativeElement); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilderExposer.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilderExposer.cs index 7afa8f153d..b656c4c068 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilderExposer.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitCommitObjectBuilderExposer.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +public interface IRevitCommitObjectBuilderExposer { - public interface IRevitCommitObjectBuilderExposer - { - public IRevitCommitObjectBuilder commitObjectBuilder { get; } - } + public IRevitCommitObjectBuilder commitObjectBuilder { get; } } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitDocumentAggregateCache.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitDocumentAggregateCache.cs index 066202206c..36f9fdaf9e 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitDocumentAggregateCache.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitDocumentAggregateCache.cs @@ -4,15 +4,17 @@ using System.Text; using Autodesk.Revit.DB; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +public interface IRevitDocumentAggregateCache { - public interface IRevitDocumentAggregateCache - { - Document Document { get; } - IRevitObjectCache GetOrInitializeCacheOfType(Action> initializer, out bool isExistingCache); - IRevitObjectCache GetOrInitializeEmptyCacheOfType(out bool isExistingCache); - IRevitObjectCache? TryGetCacheOfType(); - void Invalidate(); - void InvalidateAll(); - } + Document Document { get; } + IRevitObjectCache GetOrInitializeCacheOfType( + Action> initializer, + out bool isExistingCache + ); + IRevitObjectCache GetOrInitializeEmptyCacheOfType(out bool isExistingCache); + IRevitObjectCache? TryGetCacheOfType(); + void Invalidate(); + void InvalidateAll(); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitElementTypeRetriever.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitElementTypeRetriever.cs index dc002a1eb6..8524e99afb 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitElementTypeRetriever.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitElementTypeRetriever.cs @@ -1,16 +1,15 @@ #nullable enable using Speckle.Core.Models; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +/// +/// This interface defines the functionality related to getting and setting the "type" and "family" values on Base objects. This functionality lives in the converter, because getting and setting the type of a specific Base object requires knowledge of the Objects kit. +/// +public interface IRevitElementTypeRetriever { - /// - /// This interface defines the functionality related to getting and setting the "type" and "family" values on Base objects. This functionality lives in the converter, because getting and setting the type of a specific Base object requires knowledge of the Objects kit. - /// - public interface IRevitElementTypeRetriever - { - public string? GetElementType(Base @base); - public void SetElementType(Base @base, string type); - public string? GetElementFamily(Base @base); - public void SetElementFamily(Base @base, string family); - } + public string? GetElementType(Base @base); + public void SetElementType(Base @base, string type); + public string? GetElementFamily(Base @base); + public void SetElementFamily(Base @base, string family); } diff --git a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitObjectCache.cs b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitObjectCache.cs index 955d29d8ec..af7931d18a 100644 --- a/ConnectorRevit/RevitSharedResources/Interfaces/IRevitObjectCache.cs +++ b/ConnectorRevit/RevitSharedResources/Interfaces/IRevitObjectCache.cs @@ -3,22 +3,22 @@ using System.Collections.Generic; using System.Text; -namespace RevitSharedResources.Interfaces +namespace RevitSharedResources.Interfaces; + +public interface IRevitObjectCache +{ + IRevitDocumentAggregateCache ParentCache { get; } + bool ContainsKey(string key); + ICollection GetAllKeys(); + void Remove(string key); +} + +public interface IRevitObjectCache : IRevitObjectCache { - public interface IRevitObjectCache - { - IRevitDocumentAggregateCache ParentCache { get; } - bool ContainsKey(string key); - ICollection GetAllKeys(); - void Remove(string key); - } - public interface IRevitObjectCache : IRevitObjectCache - { - T GetOrAdd(string key, Func factory, out bool isExistingValue); - public T? TryGet(string key); - ICollection GetAllObjects(); - void Set(string key, T value); - void AddMany(IEnumerable elements, Func keyFactory); - void AddMany(Dictionary elementMap); - } + T GetOrAdd(string key, Func factory, out bool isExistingValue); + public T? TryGet(string key); + ICollection GetAllObjects(); + void Set(string key, T value); + void AddMany(IEnumerable elements, Func keyFactory); + void AddMany(Dictionary elementMap); } diff --git a/ConnectorRevit/RevitSharedResources/Models/APIContext.cs b/ConnectorRevit/RevitSharedResources/Models/APIContext.cs index e5362dbae1..5738eba7dd 100644 --- a/ConnectorRevit/RevitSharedResources/Models/APIContext.cs +++ b/ConnectorRevit/RevitSharedResources/Models/APIContext.cs @@ -3,121 +3,127 @@ using System.Threading.Tasks; using System.Threading; -namespace RevitSharedResources.Models +namespace RevitSharedResources.Models; + +/// +/// This class gives access to the Revit API context from anywhere in your codebase. This is essentially a +/// lite version of the Revit.Async package from Kennan Chan. Most of the functionality was taken from that code. +/// The main difference is that this class does not subscribe to the applicationIdling event from revit +/// which the docs say will impact the performance of Revit +/// +public static class APIContext { + private static SemaphoreSlim semaphore = new(1, 1); + private static UIControlledApplication uiApplication; + private static ExternalEventHandler factoryExternalEventHandler; + private static ExternalEvent factoryExternalEvent; + /// - /// This class gives access to the Revit API context from anywhere in your codebase. This is essentially a - /// lite version of the Revit.Async package from Kennan Chan. Most of the functionality was taken from that code. - /// The main difference is that this class does not subscribe to the applicationIdling event from revit - /// which the docs say will impact the performance of Revit + /// Initialize that happens in a Revit context will make an ExternalEvent and ExternalEventHandler + /// whose jobs are to create external events that wrap the funcs passed into the Run method. /// - public static class APIContext + /// + public static void Initialize(UIControlledApplication application) { - private static SemaphoreSlim semaphore = new(1,1); - private static UIControlledApplication uiApplication; - private static ExternalEventHandler factoryExternalEventHandler; - private static ExternalEvent factoryExternalEvent; - - /// - /// Initialize that happens in a Revit context will make an ExternalEvent and ExternalEventHandler - /// whose jobs are to create external events that wrap the funcs passed into the Run method. - /// - /// - public static void Initialize(UIControlledApplication application) - { - uiApplication = application; - factoryExternalEventHandler = new(ExternalEvent.Create); - factoryExternalEvent = ExternalEvent.Create(factoryExternalEventHandler); - } + uiApplication = application; + factoryExternalEventHandler = new(ExternalEvent.Create); + factoryExternalEvent = ExternalEvent.Create(factoryExternalEventHandler); + } - public static async Task Run(Func func) + public static async Task Run(Func func) + { + await semaphore.WaitAsync().ConfigureAwait(false); + try { - await semaphore.WaitAsync().ConfigureAwait(false); - try - { - var handler = new ExternalEventHandler(func); - using var externalEvent = await Run(factoryExternalEventHandler, handler, factoryExternalEvent) - .ConfigureAwait(false); + var handler = new ExternalEventHandler(func); + using var externalEvent = await Run(factoryExternalEventHandler, handler, factoryExternalEvent) + .ConfigureAwait(false); - return await Run(handler, uiApplication, externalEvent).ConfigureAwait(false); - } - finally - { - semaphore.Release(); - } + return await Run(handler, uiApplication, externalEvent).ConfigureAwait(false); } - - public static async Task Run(Action action) + finally { - await Run(app => + semaphore.Release(); + } + } + + public static async Task Run(Action action) + { + await Run(app => { action(app); return null; - }).ConfigureAwait(false); - } - public static async Task Run(Action action) - { - await Run(_ => + }) + .ConfigureAwait(false); + } + + public static async Task Run(Action action) + { + await Run(_ => { action(); return null; - }).ConfigureAwait(false); - } + }) + .ConfigureAwait(false); + } - private static async Task Run( - ExternalEventHandler handler, - TParameter parameter, - ExternalEvent externalEvent) - { - var task = handler.GetTask(parameter); - externalEvent.Raise(); + private static async Task Run( + ExternalEventHandler handler, + TParameter parameter, + ExternalEvent externalEvent + ) + { + var task = handler.GetTask(parameter); + externalEvent.Raise(); - return await task.ConfigureAwait(false); - } + return await task.ConfigureAwait(false); } +} + +public enum HandlerStatus +{ + NotStarted, + Started, + IsCompleted, + IsFaulted, +} + +internal class ExternalEventHandler : IExternalEventHandler +{ + public TaskCompletionSource Result { get; private set; } - public enum HandlerStatus + public Task GetTask(TParameter parameter) { - NotStarted, - Started, - IsCompleted, - IsFaulted, + Parameter = parameter; + Result = new TaskCompletionSource(); + return Result.Task; } - internal class ExternalEventHandler : IExternalEventHandler + private Func func; + + public ExternalEventHandler(Func func) { - public TaskCompletionSource Result { get; private set; } - public Task GetTask(TParameter parameter) - { - Parameter = parameter; - Result = new TaskCompletionSource(); - return Result.Task; - } + this.func = func; + } + + public HandlerStatus Status { get; private set; } = HandlerStatus.NotStarted; + public TParameter Parameter { get; private set; } - private Func func; - public ExternalEventHandler(Func func) + public void Execute(UIApplication app) + { + Status = HandlerStatus.Started; + try { - this.func = func; + var r = func(Parameter); + Result.SetResult(r); + Status = HandlerStatus.IsCompleted; } - - public HandlerStatus Status { get; private set; } = HandlerStatus.NotStarted; - public TParameter Parameter { get; private set; } - public void Execute(UIApplication app) + catch (Exception ex) { - Status = HandlerStatus.Started; - try - { - var r = func(Parameter); - Result.SetResult(r); - Status = HandlerStatus.IsCompleted; - } - catch (Exception ex) - { - Status = HandlerStatus.IsFaulted; - Result.SetException(ex); - } + Status = HandlerStatus.IsFaulted; + Result.SetException(ex); } - - public string GetName() => "SpeckleRevitContextEventHandler"; } + + public string GetName() => "SpeckleRevitContextEventHandler"; } diff --git a/ConnectorRevit/RevitSharedResources/Models/ConversionNotReadyCacheData.cs b/ConnectorRevit/RevitSharedResources/Models/ConversionNotReadyCacheData.cs index 9e475836d0..05018a73ef 100644 --- a/ConnectorRevit/RevitSharedResources/Models/ConversionNotReadyCacheData.cs +++ b/ConnectorRevit/RevitSharedResources/Models/ConversionNotReadyCacheData.cs @@ -2,14 +2,14 @@ using System.Collections.Generic; using System.Text; -namespace RevitSharedResources.Models +namespace RevitSharedResources.Models; + +public struct ConversionNotReadyCacheData { - public struct ConversionNotReadyCacheData + public ConversionNotReadyCacheData(int numTimesCaught) { - public ConversionNotReadyCacheData(int numTimesCaught) - { - NumberOfTimesCaught = numTimesCaught; - } - public int NumberOfTimesCaught; + NumberOfTimesCaught = numTimesCaught; } + + public int NumberOfTimesCaught; } diff --git a/ConnectorRevit/RevitSharedResources/Models/ErrorEater.cs b/ConnectorRevit/RevitSharedResources/Models/ErrorEater.cs index 5475e60232..549ee848b6 100644 --- a/ConnectorRevit/RevitSharedResources/Models/ErrorEater.cs +++ b/ConnectorRevit/RevitSharedResources/Models/ErrorEater.cs @@ -5,82 +5,92 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace RevitSharedResources.Models +namespace RevitSharedResources.Models; + +public class ErrorEater : IFailuresPreprocessor { - public class ErrorEater : IFailuresPreprocessor - { - private List _exceptions = new(); - public Dictionary CommitErrorsDict = new(); + private List _exceptions = new(); + public Dictionary CommitErrorsDict = new(); - public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) + public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) + { + var resolvedFailures = 0; + var failedElements = new List(); + // Inside event handler, get all warnings + var failList = failuresAccessor.GetFailureMessages(); + foreach (FailureMessageAccessor failure in failList) { - var resolvedFailures = 0; - var failedElements = new List(); - // Inside event handler, get all warnings - var failList = failuresAccessor.GetFailureMessages(); - foreach (FailureMessageAccessor failure in failList) + // check FailureDefinitionIds against ones that you want to dismiss, + //FailureDefinitionId failID = failure.GetFailureDefinitionId(); + // prevent Revit from showing Unenclosed room warnings + //if (failID == BuiltInFailures.RoomFailures.RoomNotEnclosed) + //{ + var t = failure.GetDescriptionText(); + + var s = failure.GetSeverity(); + if (s == FailureSeverity.Warning) { - // check FailureDefinitionIds against ones that you want to dismiss, - //FailureDefinitionId failID = failure.GetFailureDefinitionId(); - // prevent Revit from showing Unenclosed room warnings - //if (failID == BuiltInFailures.RoomFailures.RoomNotEnclosed) - //{ - var t = failure.GetDescriptionText(); + // just delete the warnings for now + failuresAccessor.DeleteWarning(failure); + resolvedFailures++; + continue; + } - var s = failure.GetSeverity(); - if (s == FailureSeverity.Warning) - { - // just delete the warnings for now - failuresAccessor.DeleteWarning(failure); - resolvedFailures++; - continue; - } + try + { + failuresAccessor.ResolveFailure(failure); + resolvedFailures++; + } + catch + { + var idsToDelete = failure.GetFailingElementIds().ToList(); - try + if (failuresAccessor.IsElementsDeletionPermitted(idsToDelete)) { - failuresAccessor.ResolveFailure(failure); + failuresAccessor.DeleteElements(idsToDelete); resolvedFailures++; } - catch + else { - var idsToDelete = failure.GetFailingElementIds().ToList(); - - if (failuresAccessor.IsElementsDeletionPermitted(idsToDelete)) + if (CommitErrorsDict.ContainsKey(t)) { - failuresAccessor.DeleteElements(idsToDelete); - resolvedFailures++; + CommitErrorsDict[t]++; } else { - if (CommitErrorsDict.ContainsKey(t)) - CommitErrorsDict[t]++; - else - CommitErrorsDict.Add(t, 1); - // currently, the whole commit is rolled back. this should be investigated further at a later date - // to properly proceed with commit - failedElements.AddRange(failure.GetFailingElementIds()); - - // logging the error - var speckleEx = new SpeckleException($"Fatal Error: {t}"); - _exceptions.Add(speckleEx); - SpeckleLog.Logger.Fatal(speckleEx, "Fatal Error: {failureMessage}", t); + CommitErrorsDict.Add(t, 1); } + // currently, the whole commit is rolled back. this should be investigated further at a later date + // to properly proceed with commit + failedElements.AddRange(failure.GetFailingElementIds()); + + // logging the error + var speckleEx = new SpeckleException($"Fatal Error: {t}"); + _exceptions.Add(speckleEx); + SpeckleLog.Logger.Fatal(speckleEx, "Fatal Error: {failureMessage}", t); } } + } - if (resolvedFailures > 0) - return FailureProcessingResult.ProceedWithCommit; - else - return FailureProcessingResult.Continue; + if (resolvedFailures > 0) + { + return FailureProcessingResult.ProceedWithCommit; } + else + { + return FailureProcessingResult.Continue; + } + } - public SpeckleNonUserFacingException? GetException() + public SpeckleNonUserFacingException? GetException() + { + if (CommitErrorsDict.Count > 0 && _exceptions.Count > 0) { - if (CommitErrorsDict.Count > 0 && _exceptions.Count > 0) - { - return new SpeckleNonUserFacingException("Error eater was unable to resolve exceptions", new AggregateException(_exceptions)); - } - return null; + return new SpeckleNonUserFacingException( + "Error eater was unable to resolve exceptions", + new AggregateException(_exceptions) + ); } + return null; } } diff --git a/ConnectorRevit/RevitSharedResources/Models/RevitConverterState.cs b/ConnectorRevit/RevitSharedResources/Models/RevitConverterState.cs index ca50de316a..ac9651e657 100644 --- a/ConnectorRevit/RevitSharedResources/Models/RevitConverterState.cs +++ b/ConnectorRevit/RevitSharedResources/Models/RevitConverterState.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using Autodesk.Revit.DB; using Speckle.Core.Helpers; diff --git a/ConnectorRevit/RevitSharedResources/Models/TransactionManager.cs b/ConnectorRevit/RevitSharedResources/Models/TransactionManager.cs index fad2aad1a3..8ad3888c47 100644 --- a/ConnectorRevit/RevitSharedResources/Models/TransactionManager.cs +++ b/ConnectorRevit/RevitSharedResources/Models/TransactionManager.cs @@ -4,251 +4,258 @@ using RevitSharedResources.Interfaces; using Speckle.Core.Logging; -namespace RevitSharedResources.Models +namespace RevitSharedResources.Models; + +/// +/// Is responsible for all functionality regarding subtransactions, transactions, and transaction groups. +/// This includes starting, pausing, committing, and rolling back transactions +/// +public class TransactionManager : IDisposable { - /// - /// Is responsible for all functionality regarding subtransactions, transactions, and transaction groups. - /// This includes starting, pausing, committing, and rolling back transactions - /// - public class TransactionManager : IDisposable + private string streamId; + private Document document; + + public TransactionManager(string streamId, Document document) { - private string streamId; - private Document document; + this.streamId = streamId; + this.document = document; + } - public TransactionManager(string streamId, Document document) + private ErrorEater errorEater; + private bool isDisposed; + private TransactionGroup transactionGroup; + private Transaction transaction; + private SubTransaction subTransaction; + + public void Finish() + { + try { - this.streamId = streamId; - this.document = document; + Commit(); } - - private ErrorEater errorEater; - private bool isDisposed; - private TransactionGroup transactionGroup; - private Transaction transaction; - private SubTransaction subTransaction; - - public void Finish() + finally { - try - { - Commit(); - } - finally + if (transactionGroup.GetStatus() == TransactionStatus.Started) { - if (transactionGroup.GetStatus() == TransactionStatus.Started) - { - transactionGroup.Assimilate(); - } - transactionGroup?.Dispose(); + transactionGroup.Assimilate(); } + transactionGroup?.Dispose(); } + } - public void Start() + public void Start() + { + if (transactionGroup == null) { - if (transactionGroup == null) - { - transactionGroup = new TransactionGroup(document, $"Baking stream {streamId}"); - transactionGroup.Start(); - } + transactionGroup = new TransactionGroup(document, $"Baking stream {streamId}"); + transactionGroup.Start(); + } - if (transaction == null || !transaction.IsValidObject || transaction.GetStatus() != TransactionStatus.Started) - { - transaction = new Transaction(document, $"Baking stream {streamId}"); - var failOpts = transaction.GetFailureHandlingOptions(); - errorEater = new ErrorEater(); - failOpts.SetFailuresPreprocessor(errorEater); - failOpts.SetClearAfterRollback(true); - transaction.SetFailureHandlingOptions(failOpts); - transaction.Start(); - } + if (transaction == null || !transaction.IsValidObject || transaction.GetStatus() != TransactionStatus.Started) + { + transaction = new Transaction(document, $"Baking stream {streamId}"); + var failOpts = transaction.GetFailureHandlingOptions(); + errorEater = new ErrorEater(); + failOpts.SetFailuresPreprocessor(errorEater); + failOpts.SetClearAfterRollback(true); + transaction.SetFailureHandlingOptions(failOpts); + transaction.Start(); + } + } + + public TransactionStatus Commit() + { + if ( + subTransaction != null && subTransaction.IsValidObject && subTransaction.GetStatus() == TransactionStatus.Started + ) + { + HandleFailedCommit(subTransaction.Commit()); + subTransaction.Dispose(); + } + if (transaction != null && transaction.IsValidObject && transaction.GetStatus() == TransactionStatus.Started) + { + var status = transaction.Commit(); + HandleFailedCommit(status); + transaction.Dispose(); + return status; } + return TransactionStatus.Uninitialized; + } - public TransactionStatus Commit() + private void HandleFailedCommit(TransactionStatus status) + { + if (status == TransactionStatus.RolledBack) { - if ( - subTransaction != null - && subTransaction.IsValidObject - && subTransaction.GetStatus() == TransactionStatus.Started - ) + var numTotalErrors = errorEater.CommitErrorsDict.Sum(kvp => kvp.Value); + var numUniqueErrors = errorEater.CommitErrorsDict.Keys.Count; + + var exception = errorEater.GetException(); + if (exception == null) { - HandleFailedCommit(subTransaction.Commit()); - subTransaction.Dispose(); + SpeckleLog.Logger.Fatal( + "Revit commit failed with {numUniqueErrors} unique errors and {numTotalErrors} total errors, but the ErrorEater did not capture any exceptions", + numUniqueErrors, + numTotalErrors + ); } - if (transaction != null && transaction.IsValidObject && transaction.GetStatus() == TransactionStatus.Started) + else { - var status = transaction.Commit(); - HandleFailedCommit(status); - transaction.Dispose(); - return status; + SpeckleLog.Logger.Fatal( + exception, + "The Revit API could not resolve {numUniqueErrors} unique errors and {numTotalErrors} total errors when trying to commit the Speckle model. The whole transaction is being rolled back.", + numUniqueErrors, + numTotalErrors + ); } - return TransactionStatus.Uninitialized; + + throw exception + ?? new SpeckleException( + $"The Revit API could not resolve {numUniqueErrors} unique errors and {numTotalErrors} total errors when trying to commit the Speckle model. The whole transaction is being rolled back." + ); } + } - private void HandleFailedCommit(TransactionStatus status) + public void RollbackTransaction() + { + RollbackSubTransaction(); + if (transaction != null && transaction.IsValidObject && transaction.GetStatus() == TransactionStatus.Started) { - if (status == TransactionStatus.RolledBack) - { - var numTotalErrors = errorEater.CommitErrorsDict.Sum(kvp => kvp.Value); - var numUniqueErrors = errorEater.CommitErrorsDict.Keys.Count; - - var exception = errorEater.GetException(); - if (exception == null) - SpeckleLog.Logger.Fatal( - "Revit commit failed with {numUniqueErrors} unique errors and {numTotalErrors} total errors, but the ErrorEater did not capture any exceptions", - numUniqueErrors, - numTotalErrors - ); - else - SpeckleLog.Logger.Fatal( - exception, - "The Revit API could not resolve {numUniqueErrors} unique errors and {numTotalErrors} total errors when trying to commit the Speckle model. The whole transaction is being rolled back.", - numUniqueErrors, - numTotalErrors - ); - - throw exception - ?? new SpeckleException( - $"The Revit API could not resolve {numUniqueErrors} unique errors and {numTotalErrors} total errors when trying to commit the Speckle model. The whole transaction is being rolled back." - ); - } + transaction.RollBack(); } + } - public void RollbackTransaction() + public void RollbackSubTransaction() + { + if ( + subTransaction != null && subTransaction.IsValidObject && subTransaction.GetStatus() == TransactionStatus.Started + ) { - RollbackSubTransaction(); - if (transaction != null && transaction.IsValidObject && transaction.GetStatus() == TransactionStatus.Started) - { - transaction.RollBack(); - } + subTransaction.RollBack(); } + } - public void RollbackSubTransaction() + public void RollbackAll() + { + RollbackTransaction(); + if ( + transactionGroup != null + && transactionGroup.IsValidObject + && transactionGroup.GetStatus() == TransactionStatus.Started + ) { - if ( - subTransaction != null - && subTransaction.IsValidObject - && subTransaction.GetStatus() == TransactionStatus.Started - ) - { - subTransaction.RollBack(); - } + transactionGroup.Assimilate(); } + } - public void RollbackAll() + public void StartSubtransaction() + { + Start(); + if ( + subTransaction == null || !subTransaction.IsValidObject || subTransaction.GetStatus() != TransactionStatus.Started + ) { - RollbackTransaction(); - if ( - transactionGroup != null - && transactionGroup.IsValidObject - && transactionGroup.GetStatus() == TransactionStatus.Started - ) - { - transactionGroup.Assimilate(); - } + subTransaction = new SubTransaction(document); + subTransaction.Start(); } + } - public void StartSubtransaction() + public TransactionStatus CommitSubtransaction() + { + if (subTransaction != null && subTransaction.IsValidObject) { - Start(); - if ( - subTransaction == null - || !subTransaction.IsValidObject - || subTransaction.GetStatus() != TransactionStatus.Started - ) - { - subTransaction = new SubTransaction(document); - subTransaction.Start(); - } + var status = subTransaction.Commit(); + HandleFailedCommit(status); + subTransaction.Dispose(); + return status; } + return TransactionStatus.Uninitialized; + } + + public TResult ExecuteInTemporaryTransaction(Func function) + { + return ExecuteInTemporaryTransaction(function, document); + } - public TransactionStatus CommitSubtransaction() + public static TResult ExecuteInTemporaryTransaction(Func function, Document document) + { + TResult result = default; + if (!document.IsModifiable) { - if (subTransaction != null && subTransaction.IsValidObject) + using var t = new Transaction(document, "This Transaction Will Never Get Committed"); + try { - var status = subTransaction.Commit(); - HandleFailedCommit(status); - subTransaction.Dispose(); - return status; + t.Start(); + result = function(); + } + catch + { + // ignore because we're just going to rollback + } + finally + { + t.RollBack(); } - return TransactionStatus.Uninitialized; - } - - public TResult ExecuteInTemporaryTransaction(Func function) - { - return ExecuteInTemporaryTransaction(function, document); } - - public static TResult ExecuteInTemporaryTransaction(Func function, Document document) + else { - TResult result = default; - if (!document.IsModifiable) + using var t = new SubTransaction(document); + try { - using var t = new Transaction(document, "This Transaction Will Never Get Committed"); - try - { - t.Start(); - result = function(); - } - catch - { - // ignore because we're just going to rollback - } - finally - { - t.RollBack(); - } + t.Start(); + result = function(); } - else + catch { - using var t = new SubTransaction(document); - try - { - t.Start(); - result = function(); - } - catch - { - // ignore because we're just going to rollback - } - finally - { - t.RollBack(); - } + // ignore because we're just going to rollback + } + finally + { + t.RollBack(); } - - return result; } - #region disposal - public void Dispose() + return result; + } + + #region disposal + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (isDisposed) { - Dispose(true); - GC.SuppressFinalize(this); + return; } - protected virtual void Dispose(bool disposing) + if (disposing) { - if (isDisposed) - return; + // free managed resources + if (subTransaction != null && subTransaction.IsValidObject) + { + subTransaction.Dispose(); + } - if (disposing) + if (transaction != null && transaction.IsValidObject) { - // free managed resources - if (subTransaction != null && subTransaction.IsValidObject) - subTransaction.Dispose(); - if (transaction != null && transaction.IsValidObject) - transaction.Dispose(); - if (transactionGroup != null && transactionGroup.IsValidObject) - transactionGroup.Dispose(); + transaction.Dispose(); } - isDisposed = true; + if (transactionGroup != null && transactionGroup.IsValidObject) + { + transactionGroup.Dispose(); + } } - ~TransactionManager() - { - Dispose(false); - } - #endregion + isDisposed = true; + } + + ~TransactionManager() + { + Dispose(false); } + #endregion } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/Plugin.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/Plugin.cs index cf3b72b9a7..5d40abbe9c 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/Plugin.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/Plugin.cs @@ -50,7 +50,9 @@ public SpeckleRhinoConnectorPlugin() public void Init() { if (appBuilder != null) + { return; + } #if MAC InitAvaloniaMac(); #else @@ -122,8 +124,12 @@ private void RhinoDoc_EndOpenDocument(object sender, DocumentOpenEventArgs e) // remove any that don't already exist in the current active doc foreach (var incomingStream in incomingStreams) + { if (!ExistingStreams.Contains(incomingStream)) + { RhinoDoc.ActiveDoc.Strings.Delete(SpeckleKey, incomingStream); + } + } // skip binding return; @@ -150,8 +156,10 @@ private void RhinoDoc_EndOpenDocument(object sender, DocumentOpenEventArgs e) private void RhinoDoc_BeginOpenDocument(object sender, DocumentOpenEventArgs e) { if (e.Merge) // this is a paste or import event + { // get existing streams in doc before a paste or import operation to use for cleanup ExistingStreams = RhinoDoc.ActiveDoc.Strings.GetEntryNames(SpeckleKey).ToList(); + } } /// @@ -227,12 +235,16 @@ private void EnsureVersionSettings() var plugin_version = Settings.GetString("PlugInVersion", null); if (string.IsNullOrEmpty(plugin_version)) + { return; + } // If the version number of the plugin that was last used does not match the // version number of this plugin, proceed. if (0 == string.Compare(Version, plugin_version, StringComparison.OrdinalIgnoreCase)) + { return; + } // Build a path to the user's staged RUI file. var sb = new StringBuilder(); @@ -251,6 +263,7 @@ private void EnsureVersionSettings() SpeckleLog.Logger.Debug("Deleting and Updating RUI settings file"); if (File.Exists(path)) + { try { File.Delete(path); @@ -259,6 +272,7 @@ private void EnsureVersionSettings() { SpeckleLog.Logger.Warning(ex, "Failed to delete rui file {exceptionMessage}", ex.Message); } + } } // Save the version number of this plugin to our settings file. @@ -269,11 +283,15 @@ private void RhinoApp_Idle(object sender, EventArgs e) { //do not hog rhino, to be refractored a bit if (MappingsViewModel.Instance == null) + { return; + } #if !MAC if (!Panels.GetOpenPanelIds().Contains(typeof(MappingsPanel).GUID)) + { return; + } #else if (SpeckleMappingsCommandMac.MainWindow == null || !SpeckleMappingsCommandMac.MainWindow.IsVisible) return; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleCommandWin.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleCommandWin.cs index 03f74e42bb..9bbc2f5047 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleCommandWin.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleCommandWin.cs @@ -1,4 +1,4 @@ -using System; +using System; using Rhino; using Rhino.Commands; using Rhino.UI; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandMac.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandMac.cs index 7acddc6767..31cccf9b65 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandMac.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandMac.cs @@ -1,4 +1,4 @@ -#if MAC +#if MAC using System; using System.Runtime.InteropServices; using System.Threading; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandWin.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandWin.cs index fd2505336b..41e44cf13a 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandWin.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Entry/SpeckleMappingsCommandWin.cs @@ -1,4 +1,4 @@ -using System; +using System; using Rhino; using Rhino.Commands; using Rhino.UI; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/MacOSHelpers.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/MacOSHelpers.cs index de7eb99838..9ef988f26c 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/MacOSHelpers.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/MacOSHelpers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; namespace ConnectorRhinoShared; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.3DView.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.3DView.cs index 3254f70bfe..5e8c1ae2d5 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.3DView.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.3DView.cs @@ -40,18 +40,24 @@ await Task.Run(() => DisplayModeDescription shaded = DisplayModeDescription.FindByName("Shaded"); if (shaded != null) + { speckleCommentView.ActiveViewport.DisplayMode = shaded; + } // Minimized all maximized views. IEnumerable maximizedViews = Doc.Views.Where(v => v.Maximized); foreach (RhinoView view in maximizedViews) + { view.Maximized = false; + } // Maximized speckle comment view. speckleCommentView.Maximized = true; if (Doc.Views.ActiveView.ActiveViewport.Name != "SpeckleCommentView") + { Doc.Views.ActiveView = speckleCommentView; + } } Doc.Views.Redraw(); diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Events.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Events.cs index 087914c802..29b91dc4a5 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Events.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Events.cs @@ -9,14 +9,20 @@ public partial class ConnectorBindingsRhino : ConnectorBindings private void RhinoDoc_EndOpenDocument(object sender, DocumentOpenEventArgs e) { if (e.Merge) + { return; // prevents triggering this on copy pastes, imports, etc. + } if (e.Document == null) + { return; + } var streams = GetStreamsInFile(); if (UpdateSavedStreams != null) + { UpdateSavedStreams(streams); + } ClearStorage(); //if (streams.Count > 0) @@ -26,6 +32,8 @@ private void RhinoDoc_EndOpenDocument(object sender, DocumentOpenEventArgs e) private void RhinoDoc_LayerChange(object sender, LayerTableEventArgs e) { if (UpdateSelectedStream != null) + { UpdateSelectedStream(); + } } } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Previews.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Previews.cs index c574d8ad1e..67eb7e402f 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Previews.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Previews.cs @@ -30,6 +30,7 @@ public override void PreviewSend(StreamState state, ProgressViewModel progress) var idsToSelect = new List(); int successful = 0; foreach (var id in filterObjs) + { if (Utils.FindObjectBySelectedId(Doc, id, out object obj, out string descriptor)) { // create applicationObject @@ -40,12 +41,17 @@ public override void PreviewSend(StreamState state, ProgressViewModel progress) case RhinoObject o: applicationId = o.Attributes.GetUserString(ApplicationIdKey) ?? id; if (converter.CanConvertToSpeckle(obj)) + { reportObj.Update(status: ApplicationObject.State.Created); + } else + { reportObj.Update( status: ApplicationObject.State.Failed, logItem: "Object type conversion to Speckle not supported" ); + } + idsToSelect.Add(id); successful++; break; @@ -72,9 +78,12 @@ public override void PreviewSend(StreamState state, ProgressViewModel progress) } ); } + } if (successful == 0) + { throw new InvalidOperationException("No valid objects selected, nothing will be sent!"); + } // TODO: instead of selection, consider saving current visibility of objects in doc, hiding everything except selected, and restoring original states on cancel Doc.Objects.UnselectAll(false); @@ -134,27 +143,35 @@ public override async Task PreviewReceive(StreamState state, Progre } if (previewObj.Convertible) + { previewObj.Converted = ConvertObject(storedObj, converter); + } else + { foreach (var fallback in previewObj.Fallback) { var storedFallback = StoredObjects[fallback.OriginalId]; fallback.Converted = ConvertObject(storedFallback, converter); } + } if (previewObj.Converted == null || previewObj.Converted.Count == 0) { var convertedFallback = previewObj.Fallback.Where(o => o.Converted != null || o.Converted.Count > 0); if (convertedFallback != null && convertedFallback.Count() > 0) + { previewObj.Update( status: ApplicationObject.State.Created, logItem: $"Creating with {convertedFallback.Count()} fallback values" ); + } else + { previewObj.Update( status: ApplicationObject.State.Failed, logItem: "Couldn't convert object or any fallback values" ); + } } else { @@ -172,7 +189,9 @@ public override async Task PreviewReceive(StreamState state, Progre else // just generate the log { foreach (var previewObj in Preview) + { progress.Report.Log(previewObj); + } } // create display conduit diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Receive.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Receive.cs index 977307967f..29bbf0b3a7 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Receive.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Receive.cs @@ -95,7 +95,9 @@ public override async Task ReceiveStream(StreamState state, Progres isPreviewIgnore = IsPreviewIgnore(storedObj); if (!isPreviewIgnore) + { previewObj.Converted = ConvertObject(storedObj, converter); + } } else { @@ -112,17 +114,23 @@ public override async Task ReceiveStream(StreamState state, Progres .Where(o => o.Converted != null || o.Converted.Count > 0) .ToList(); if (convertedFallback.Any()) + { previewObj.Update(logItem: $"Creating with {convertedFallback.Count()} fallback values"); + } else + { previewObj.Update( status: ApplicationObject.State.Failed, logItem: "Couldn't convert object or any fallback values" ); + } } progress.Report.Log(previewObj); if (progress.CancellationToken.IsCancellationRequested) + { return; + } } progress.Report.Merge(converter.Report); @@ -132,7 +140,9 @@ public override async Task ReceiveStream(StreamState state, Progres Preview.ForEach(o => o.Status = ApplicationObject.State.Unknown); } if (progress.Report.OperationErrorsCount != 0) + { return; + } #region layer creation @@ -203,7 +213,9 @@ public override async Task ReceiveStream(StreamState state, Progres foreach (var previewObj in Preview) { if (previewObj.Status != ApplicationObject.State.Unknown) + { continue; // this has already been converted and baked + } var isUpdate = false; @@ -236,7 +248,9 @@ public override async Task ReceiveStream(StreamState state, Progres } } if (toRemove.Count() > 0) + { isUpdate = true; + } // find layer and bake previewObj.CreatedIds.Clear(); // clear created ids before bake because these may be speckle ids from the preview @@ -258,7 +272,10 @@ public override async Task ReceiveStream(StreamState state, Progres else { foreach (var fallback in previewObj.Fallback) + { BakeObject(fallback, converter, layer, previewObj); + } + previewObj.Status = previewObj.Fallback.Count(o => o.Status == ApplicationObject.State.Failed) == previewObj.Fallback.Count ? ApplicationObject.State.Failed @@ -270,7 +287,10 @@ public override async Task ReceiveStream(StreamState state, Progres progress.Report.Log(previewObj); if (progress.CancellationToken.IsCancellationRequested) + { return; + } + conversionProgressDict["Conversion"]++; progress.Update(conversionProgressDict); } @@ -295,20 +315,26 @@ public override async Task ReceiveStream(StreamState state, Progres private List GetObjectsByApplicationId(string applicationId) { if (string.IsNullOrEmpty(applicationId)) + { return new List(); + } // first try to find the object by app id user string var match = Doc.Objects.FindByUserString(ApplicationIdKey, applicationId, true).ToList(); // if nothing is found, look for the geom obj by its guid directly if (!match.Any()) + { try { RhinoObject obj = Doc.Objects.FindId(new Guid(applicationId)); if (obj != null) + { match.Add(obj); + } } catch { } + } return match; } @@ -324,10 +350,14 @@ private List FlattenCommitObject(Base obj, ISpeckleConverter void StoreObject(Base @base, ApplicationObject appObj, Base parameters = null) { if (!StoredObjects.ContainsKey(@base.id)) + { StoredObjects.Add(@base.id, @base); + } if (parameters != null && !StoredObjectParams.ContainsKey(@base.id)) + { StoredObjectParams.Add(@base.id, parameters); + } } ApplicationObject CreateApplicationObject(Base current, string containerId) @@ -347,7 +377,9 @@ ApplicationObject NewAppObj() // skip if it is the base commit collection if (current is Collection && string.IsNullOrEmpty(containerId)) + { return null; + } // get parameters var parameters = current["parameters"] as Base; @@ -385,7 +417,9 @@ ApplicationObject NewAppObj() StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) { if (context.propName == null) + { return stringBuilder; // this was probably the base commit collection + } // handle elements hosting case from Revit // WARNING: THIS IS REVIT-SPECIFIC CODE!! @@ -404,14 +438,21 @@ StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuild // handle collections case if (context.current is Collection coll && DefaultTraversal.elementsPropAliases.Contains(context.propName)) + { objectLayerName = coll.name; + } // handle default case else if (!DefaultTraversal.elementsPropAliases.Contains(context.propName)) + { objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; + } LayerIdRecurse(context.parent, stringBuilder); if (stringBuilder.Length != 0 && !string.IsNullOrEmpty(objectLayerName)) + { stringBuilder.Append(Layer.PathSeparator); + } + stringBuilder.Append(objectLayerName); return stringBuilder; @@ -436,16 +477,24 @@ private List ConvertObject(Base obj, ISpeckleConverter converter) var converted = converter.ConvertToNative(obj); if (converted == null) + { return convertedList; + } //Iteratively flatten any lists void FlattenConvertedObject(object item) { if (item is IList list) + { foreach (object child in list) + { FlattenConvertedObject(child); + } + } else + { convertedList.Add(item); + } } FlattenConvertedObject(converted); @@ -463,8 +512,12 @@ private void BakeObject( int bakedCount = 0; // check if this is a view or block - convert instead of bake if so (since these are "baked" during conversion) if (IsPreviewIgnore(obj)) + { appObj.Converted = ConvertObject(obj, converter); + } + foreach (var convertedItem in appObj.Converted) + { switch (convertedItem) { case GeometryBase o: @@ -472,9 +525,14 @@ private void BakeObject( { var invalidMessage = $"{log.Replace("\n", "").Replace("\r", "")}"; if (parent != null) + { parent.Update(logItem: $"fallback {appObj.applicationId}: {invalidMessage}"); + } else + { appObj.Update(logItem: invalidMessage); + } + continue; } var attributes = new ObjectAttributes(); @@ -524,9 +582,14 @@ private void BakeObject( { var bakeMessage = "Could not bake to document."; if (parent != null) + { parent.Update(logItem: $"fallback {appObj.applicationId}: {bakeMessage}"); + } else + { appObj.Update(logItem: bakeMessage); + } + continue; } @@ -560,9 +623,14 @@ private void BakeObject( SetUserInfo(obj, o.Attributes, parent); // handle user info, including application id o.CommitChanges(); if (parent != null) + { parent.Update(o.Id.ToString()); + } else + { appObj.Update(o.Id.ToString()); + } + bakedCount++; break; @@ -576,13 +644,18 @@ private void BakeObject( bakedCount++; break; } + } if (bakedCount == 0) { if (parent != null) + { parent.Update(logItem: $"fallback {appObj.applicationId}: could not bake object"); + } else + { appObj.Update(logItem: "Could not bake object"); + } } } @@ -590,8 +663,12 @@ private void SetUserInfo(Base obj, ObjectAttributes attributes, ApplicationObjec { // set user strings if (obj[UserStrings] is Base userStrings) + { foreach (var member in userStrings.GetMembers(DynamicBaseMemberType.Dynamic)) + { attributes.SetUserString(member.Key, member.Value as string); + } + } // set application id var appId = parent != null ? parent.applicationId : obj.applicationId; @@ -603,11 +680,15 @@ private void SetUserInfo(Base obj, ObjectAttributes attributes, ApplicationObjec // set user dictionaries if (obj[UserDictionary] is Base userDictionary) + { ParseDictionaryToArchivable(attributes.UserDictionary, userDictionary); + } var name = obj["name"] as string ?? obj["label"] as string; // gridlines have a "label" prop instead of name? if (name != null) + { attributes.Name = name; + } } // Clears the stored objects, params, and preview objects diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Selection.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Selection.cs index 5aaba92055..ddab48b1f5 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Selection.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Selection.cs @@ -16,11 +16,16 @@ public override List GetSelectedObjects() var Converter = KitManager.GetDefaultKit().LoadConverter(Utils.RhinoAppName); if (Converter == null || Doc == null) + { return objs; + } var selected = Doc.Objects.GetSelectedObjects(true, false).ToList(); if (selected.Count == 0) + { return objs; + } + var supportedObjs = selected.Where(o => Converter.CanConvertToSpeckle(o))?.ToList(); var unsupportedObjs = selected.Where(o => Converter.CanConvertToSpeckle(o) == false)?.ToList(); @@ -88,9 +93,13 @@ public override void SelectClientObjects(List objs, bool deselect = fals if (obj != null) { if (deselect) + { obj.Select(false, true, false, true, true, true); + } else + { obj.Select(true, true, true, true, true, true); + } } else if (isPreview) { @@ -126,17 +135,28 @@ private List GetObjectsFromFilter(ISelectionFilter filter) { var layerObjs = Doc.Objects.FindByLayer(layer)?.Select(o => o.Id.ToString()); if (layerObjs != null) + { objs.AddRange(layerObjs); + } } } break; case "project-info": if (filter.Selection.Contains("Standard Views")) + { objs.AddRange(Doc.StandardViews()); + } + if (filter.Selection.Contains("Named Views")) + { objs.AddRange(Doc.NamedViews()); + } + if (filter.Selection.Contains("Layers")) + { objs.AddRange(Doc.Layers.Select(o => o.Id.ToString())); + } + break; } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Send.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Send.cs index 625157eacd..5cd525365e 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Send.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Send.cs @@ -38,9 +38,11 @@ public override async Task SendStream(StreamState state, ProgressViewMod var commitObject = converter.ConvertToSpeckle(Doc) as Collection; // create a collection base obj if (state.SelectedObjectIds.Count == 0) + { throw new InvalidOperationException( "Zero objects selected: Please select some objects, or check that your filter can actually select something." ); + } progress.Report = new ProgressReport(); var conversionProgressDict = new ConcurrentDictionary(); @@ -86,11 +88,18 @@ public override async Task SendStream(StreamState state, ProgressViewMod { var objectLayer = Doc.Layers[o.Attributes.LayerIndex]; if (commitLayerObjects.ContainsKey(objectLayer.FullPath)) + { commitLayerObjects[objectLayer.FullPath].Add(converted); + } else + { commitLayerObjects.Add(objectLayer.FullPath, new List { converted }); + } + if (!commitLayers.ContainsKey(objectLayer.FullPath)) + { commitLayers.Add(objectLayer.FullPath, objectLayer); + } } break; case Layer o: @@ -105,7 +114,10 @@ public override async Task SendStream(StreamState state, ProgressViewMod case ViewInfo o: converted = converter.ConvertToSpeckle(o); if (converted != null) + { commitObject.elements.Add(converted); + } + break; } } @@ -144,6 +156,7 @@ public override async Task SendStream(StreamState state, ProgressViewMod #region layer handling // convert layers as collections and attach all layer objects foreach (var layerPath in commitLayerObjects.Keys) + { if (commitCollections.ContainsKey(layerPath)) { commitCollections[layerPath].elements = commitLayerObjects[layerPath]; @@ -157,13 +170,17 @@ public override async Task SendStream(StreamState state, ProgressViewMod commitCollections.Add(layerPath, collection); } } + } // generate all parent paths of commit collections and create ordered list by depth descending var allPaths = new HashSet(); foreach (var key in commitLayers.Keys) { if (!allPaths.Contains(key)) + { allPaths.Add(key); + } + AddParent(commitLayers[key]); void AddParent(Layer childLayer) @@ -209,7 +226,9 @@ void AddParent(Layer childLayer) progress.Report.Merge(converter.Report); if (objCount == 0) + { throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } progress.CancellationToken.ThrowIfCancellationRequested(); @@ -238,7 +257,9 @@ void AddParent(Layer childLayer) }; if (state.PreviousCommitId != null) + { actualCommit.parents = new List { state.PreviousCommitId }; + } var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); return commitId; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Settings.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Settings.cs index 694aa2b3fa..6fab551c68 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Settings.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.Settings.cs @@ -13,7 +13,7 @@ public partial class ConnectorBindingsRhino : ConnectorBindings public override List GetSettings() { - List meshImportOptions = new List() { defaultValue, mergeCoplanar }; + List meshImportOptions = new() { defaultValue, mergeCoplanar }; return new List { @@ -37,7 +37,10 @@ public Dictionary GetSettingsDict(List? currentSetting { var settings = new Dictionary(); foreach (var setting in currentSettings) + { settings.Add(setting.Slug, setting.Selection); + } + return settings; } } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.cs index 8e1201f74b..5f2f814f89 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/ConnectorBindingsRhino.cs @@ -47,7 +47,9 @@ public override List GetStreamsInFile() var strings = Doc?.Strings.GetEntryNames(SpeckleKey); if (strings == null) + { return new List(); + } var states = strings .Select(s => JsonConvert.DeserializeObject(Doc.Strings.GetValue(SpeckleKey, s))) @@ -59,7 +61,9 @@ public override void WriteStreamsToFile(List streams) { Doc.Strings.Delete(SpeckleKey); foreach (var s in streams) + { Doc.Strings.SetString(SpeckleKey, s.StreamId, JsonConvert.SerializeObject(s)); + } } #endregion @@ -110,21 +114,31 @@ private void LogUnsupportedObjects(List objs, ISpeckleConverter con { var type = obj.ObjectType.ToString(); if (reportLog.ContainsKey(type)) + { reportLog[type] = reportLog[type]++; + } else + { reportLog.Add(type, 1); + } } RhinoApp.WriteLine("Deselected unsupported objects:"); foreach (var entry in reportLog) + { RhinoApp.WriteLine($"{entry.Value} of type {entry.Key}"); + } } public override void ResetDocument() { if (PreviewConduit != null) + { PreviewConduit.Enabled = false; + } else + { Doc.Objects.UnselectAll(false); + } Doc.Views.Redraw(); } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/DuiPanel.xaml.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/DuiPanel.xaml.cs index e3a9401bce..1e5e51a768 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/DuiPanel.xaml.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/DuiPanel.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; using System.Windows.Controls; using DesktopUI2.ViewModels; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingBindingsRhino.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingBindingsRhino.cs index fe2319801a..e4eb11c24c 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingBindingsRhino.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingBindingsRhino.cs @@ -36,16 +36,22 @@ public override MappingSelectionInfo GetSelectionInfo() var schemas = GetObjectSchemas(obj); if (!result.Any()) + { result = schemas; + } else + { //intersect lists //TODO: if some elements already have a schema and values are different //we should default to an empty schema, instead of potentially restoring the one with values result = result.Where(x => schemas.Any(y => y.Name == x.Name)).ToList(); + } //incompatible selection if (!result.Any()) + { return new MappingSelectionInfo(new List(), selection.Count); + } } return new MappingSelectionInfo(result, selection.Count); @@ -70,7 +76,9 @@ private List GetObjectSchemas(RhinoObject obj) { var existingSchema = GetExistingObjectSchema(obj); if (existingSchema != null) + { result.Add(existingSchema); + } if (obj is InstanceObject) { @@ -78,18 +86,27 @@ private List GetObjectSchemas(RhinoObject obj) result.Add(new RevitFamilyInstanceViewModel()); } else + { switch (obj.Geometry) { case Mesh m: if (!result.Any(x => typeof(DirectShapeFreeformViewModel) == x.GetType())) + { result.Add(new DirectShapeFreeformViewModel()); + } + if (!m.IsClosed) + { result.Add(new RevitTopographyViewModel()); + } + break; case Brep b: if (!result.Any(x => typeof(DirectShapeFreeformViewModel) == x.GetType())) + { result.Add(new DirectShapeFreeformViewModel()); + } var brepSurfaceSchemas = EvaluateBrepSurfaceSchemas(b); result.AddRange(brepSurfaceSchemas); @@ -99,7 +116,10 @@ private List GetObjectSchemas(RhinoObject obj) result.Add(new DirectShapeFreeformViewModel()); if (e.ProfileCount > 1) + { break; + } + var extrusionBrp = e.ToBrep(false); var extrusionSurfaceSchemas = EvaluateBrepSurfaceSchemas(extrusionBrp, true); result.AddRange(extrusionSurfaceSchemas); @@ -136,6 +156,7 @@ private List GetObjectSchemas(RhinoObject obj) result.Add(new RevitFamilyInstanceViewModel()); break; } + } } catch (Exception ex) { @@ -153,7 +174,9 @@ public List EvaluateBrepSurfaceSchemas(Brep b, bool isExtrusion = false) { var schemas = new List(); if (b.Surfaces.Count != 1) + { return schemas; + } bool IsPlanar(Surface srf, out bool isHorizontal, out bool isVertical) { @@ -245,7 +268,9 @@ private Schema GetExistingObjectSchema(RhinoObject obj) var viewModel = obj.Attributes.GetUserString(SpeckleMappingViewKey); if (string.IsNullOrEmpty(viewModel)) + { return null; + } try { @@ -274,15 +299,20 @@ public override void SetMappings(string schema, string viewModel) public override void ClearMappings(List ids) { foreach (var id in ids) + { try { var obj = RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id)); if (obj == null) + { continue; + } + obj.Attributes.DeleteUserString(SpeckleMappingKey); obj.Attributes.DeleteUserString(SpeckleMappingViewKey); } catch { } + } SpeckleRhinoConnectorPlugin.Instance.ExistingSchemaLogExpired = true; } @@ -300,7 +330,9 @@ public override List GetExistingSchemaElements() //add the object id to the schema so we can easily highlight/clear them for (var i = 0; i < schemas.Count; i++) + { schemas[i].ApplicationId = objects[i].Id.ToString(); + } return schemas; } diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingsPanel.xaml.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingsPanel.xaml.cs index 2f1b901c81..89cdbe23ef 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingsPanel.xaml.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/UI/MappingsPanel.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; using System.Windows.Controls; using DesktopUI2.ViewModels.MappingTool; diff --git a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Utils.cs b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Utils.cs index c20e5b05cc..c3b4f8b8e9 100644 --- a/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Utils.cs +++ b/ConnectorRhino/ConnectorRhino/ConnectorRhinoShared/Utils.cs @@ -112,10 +112,16 @@ Layer MakeLayer(string name, Layer parentLayer = null) { Layer newLayer = new() { Color = Color.AliceBlue, Name = name }; if (parentLayer != null) + { newLayer.ParentLayerId = parentLayer.Id; + } + int newIndex = doc.Layers.Add(newLayer); if (newIndex < 0) + { return null; + } + return doc.Layers.FindIndex(newIndex); } catch (Exception e) @@ -139,9 +145,15 @@ Layer MakeLayer(string name, Layer parentLayer = null) currentLayerPath = i == 0 ? layerNames[i] : $"{currentLayerPath}{Layer.PathSeparator}{layerNames[i]}"; currentLayer = doc.GetLayer(currentLayerPath); if (currentLayer == null) + { currentLayer = MakeLayer(layerNames[i], parent); + } + if (currentLayer == null) + { break; + } + parent = currentLayer; } layer = currentLayer; @@ -216,7 +228,9 @@ public PreviewConduit(List preview) } if (!Preview.ContainsKey(previewObj.OriginalId)) + { Preview.Add(previewObj.OriginalId, converted); + } } } @@ -227,9 +241,13 @@ public void SelectPreviewObject(string id, bool unselect = false) if (Preview.ContainsKey(id)) { if (unselect) + { Selected.Remove(id); + } else if (!Selected.Contains(id)) + { Selected.Add(id); + } } } @@ -256,6 +274,7 @@ protected override void PreDrawObjects(DrawEventArgs e) var drawMaterial = material; drawMaterial.Diffuse = drawColor; foreach (var obj in previewobj.Value) + { switch (obj) { case Brep o: @@ -277,6 +296,7 @@ protected override void PreDrawObjects(DrawEventArgs e) display.DrawPointCloud(o, 5, drawColor); break; } + } } } } @@ -293,14 +313,19 @@ protected override void DrawOverlay(DrawEventArgs e) { base.DrawOverlay(e); if (!Enabled) + { return; + } //e.Display.ZBiasMode = ZBiasMode.TowardsCamera; foreach (var id in ObjectIds) { if (id == null) + { continue; + } + var obj = RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id)); switch (obj.ObjectType) { @@ -329,7 +354,10 @@ public static class Formatting public static string ObjectDescriptor(RhinoObject obj) { if (obj == null) + { return string.Empty; + } + var simpleType = obj.ObjectType.ToString(); return obj.HasName ? $"{simpleType}" : $"{simpleType} {obj.Name}"; } @@ -349,17 +377,34 @@ public static string TimeAgo(string timestamp) } if (timeAgo.TotalSeconds < 60) + { return "less than a minute ago"; + } + if (timeAgo.TotalMinutes < 60) + { return $"about {timeAgo.Minutes} minute{PluralS(timeAgo.Minutes)} ago"; + } + if (timeAgo.TotalHours < 24) + { return $"about {timeAgo.Hours} hour{PluralS(timeAgo.Hours)} ago"; + } + if (timeAgo.TotalDays < 7) + { return $"about {timeAgo.Days} day{PluralS(timeAgo.Days)} ago"; + } + if (timeAgo.TotalDays < 30) + { return $"about {timeAgo.Days / 7} week{PluralS(timeAgo.Days / 7)} ago"; + } + if (timeAgo.TotalDays < 365) + { return $"about {timeAgo.Days / 30} month{PluralS(timeAgo.Days / 30)} ago"; + } return $"over {timeAgo.Days / 356} year{PluralS(timeAgo.Days / 356)} ago"; } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainForm.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainForm.cs index a66ede69eb..f8c26d1478 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainForm.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainForm.cs @@ -15,94 +15,89 @@ using Tekla.Structures.Model; using Assembly = System.Reflection.Assembly; -namespace Speckle.ConnectorTeklaStructures -{ - public partial class MainForm : PluginFormBase - { - - //window owner call - [DllImport("user32.dll", SetLastError = true)] - [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] - static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); - const int GWL_HWNDPARENT = -8; - - private static Avalonia.Application AvaloniaApp { get; set; } - public Model Model { get; private set; } - public static Window MainWindow { get; private set; } - public static ConnectorBindingsTeklaStructures Bindings { get; set; } - public MainForm() - { - Load += MainForm_Load; - if (MainWindow == null) - { - // Link to model. - Model = new Model(); - Bindings = new ConnectorBindingsTeklaStructures(Model); +namespace Speckle.ConnectorTeklaStructures; - try - { - AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); +public partial class MainForm : PluginFormBase +{ + //window owner call + [DllImport("user32.dll", SetLastError = true)] + [SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")] + static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value); + const int GWL_HWNDPARENT = -8; - Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); - BuildAvaloniaApp().Start(AppMain, null); - var viewModel = new MainViewModel(Bindings); - MainWindow = new DesktopUI2.Views.MainWindow - { - DataContext = viewModel - }; + private static Avalonia.Application AvaloniaApp { get; set; } + public Model Model { get; private set; } + public static Window MainWindow { get; private set; } + public static ConnectorBindingsTeklaStructures Bindings { get; set; } + public MainForm() + { + Load += MainForm_Load; + if (MainWindow == null) + { + // Link to model. + Model = new Model(); + Bindings = new ConnectorBindingsTeklaStructures(Model); + try + { + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve); - Bindings.OpenTeklaStructures(); + Setup.Init(Bindings.GetHostAppNameVersion(), Bindings.GetHostAppName()); + BuildAvaloniaApp().Start(AppMain, null); + var viewModel = new MainViewModel(Bindings); + MainWindow = new DesktopUI2.Views.MainWindow { DataContext = viewModel }; - } - catch (Exception ex) - { - SpeckleLog.Logger.Fatal(ex, "Failed to create main form"); - } + Bindings.OpenTeklaStructures(); + } + catch (Exception ex) + { + SpeckleLog.Logger.Fatal(ex, "Failed to create main form"); } - - MainWindow.Show(); - MainWindow.Activate(); - MainWindow.Focus(); - - //set Tekla app as owner - var hwnd = MainWindow.PlatformImpl.Handle.Handle; - SetWindowLongPtr(hwnd, GWL_HWNDPARENT, Tekla.Structures.Dialog.MainWindow.Frame.Handle); } + MainWindow.Show(); + MainWindow.Activate(); + MainWindow.Focus(); - static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) - { - Assembly a = null; - var name = args.Name.Split(',')[0]; - string path = Path.GetDirectoryName(typeof(MainPlugin).Assembly.Location); + //set Tekla app as owner + var hwnd = MainWindow.PlatformImpl.Handle.Handle; + SetWindowLongPtr(hwnd, GWL_HWNDPARENT, Tekla.Structures.Dialog.MainWindow.Frame.Handle); + } - string assemblyFile = Path.Combine(path, name + ".dll"); + static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly a = null; + var name = args.Name.Split(',')[0]; + string path = Path.GetDirectoryName(typeof(MainPlugin).Assembly.Location); - if (File.Exists(assemblyFile)) - a = Assembly.LoadFrom(assemblyFile); + string assemblyFile = Path.Combine(path, name + ".dll"); - return a; - } - public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() - .UsePlatformDetect() - .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) - .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) - .LogToTrace() - .UseReactiveUI(); - - private static void AppMain(Application app, string[] args) + if (File.Exists(assemblyFile)) { - AvaloniaApp = app; + a = Assembly.LoadFrom(assemblyFile); } + return a; + } + + public static AppBuilder BuildAvaloniaApp() => + AppBuilder + .Configure() + .UsePlatformDetect() + .With(new SkiaOptions { MaxGpuResourceSizeBytes = 8096000 }) + .With(new Win32PlatformOptions { AllowEglInitialization = true, EnableMultitouch = false }) + .LogToTrace() + .UseReactiveUI(); - private void MainForm_Load(object sender, EventArgs e) - { - Close(); - } + private static void AppMain(Application app, string[] args) + { + AvaloniaApp = app; + } + private void MainForm_Load(object sender, EventArgs e) + { + Close(); } } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainPlugin.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainPlugin.cs index c1f68af879..93ce6c7b20 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainPlugin.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/MainPlugin.cs @@ -1,37 +1,30 @@ -using System; +using System; using System.Collections.Generic; using Tekla.Structures.Plugins; +namespace Speckle.ConnectorTeklaStructures; -namespace Speckle.ConnectorTeklaStructures +public class StructuresData { } + +[Plugin("Speckle.ConnectorTeklaStructures")] +[PluginUserInterface("Speckle.ConnectorTeklaStructures.MainForm")] +[InputObjectDependency(InputObjectDependency.NOT_DEPENDENT)] +public class MainPlugin : PluginBase { - public class StructuresData + public override List DefineInput() { + return new List(); + // Define input objects. } - [Plugin("Speckle.ConnectorTeklaStructures")] - [PluginUserInterface("Speckle.ConnectorTeklaStructures.MainForm")] - [InputObjectDependency(InputObjectDependency.NOT_DEPENDENT)] - - public class MainPlugin : PluginBase - { - public override List DefineInput() - { - return new List(); - // Define input objects. - } - // Enable retrieving of input values - private readonly StructuresData _data; + // Enable retrieving of input values + private readonly StructuresData _data; - public MainPlugin(StructuresData data) - { + public MainPlugin(StructuresData data) { } - } - - // This method is called upon execution of the plug-in and it´s the main method of the plug-in - public override bool Run(List input) - { - return true; - } + // This method is called upon execution of the plug-in and it´s the main method of the plug-in + public override bool Run(List input) + { + return true; } } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/PolygonMesherReferencer.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/PolygonMesherReferencer.cs index 0385847942..4266e65b82 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/PolygonMesherReferencer.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/PolygonMesherReferencer.cs @@ -1,19 +1,18 @@ using System; using StructuralUtilities.PolygonMesher; -namespace ConnectorTeklaStructuresShared +namespace ConnectorTeklaStructuresShared; + +[Obsolete("See comment within implementation of UnusedMethod", true)] +internal class PolygonMesherReferencer { - [Obsolete("See comment within implementation of UnusedMethod", true)] - internal class PolygonMesherReferencer + [Obsolete("See comment within implementation", true)] + public PolygonMesher UnusedMethod() { - [Obsolete("See comment within implementation", true)] - public PolygonMesher UnusedMethod() - { - // This class is only here to throw an error if the polygon mesher dependency is ever removed - // The dependency is needed for the converter, however the assembly resolve doesn't look in the kits - // folder for missing dlls, it looks in the connector folder. We should probably figure out a different - // method for dealing with converter dependencies - return null; - } + // This class is only here to throw an error if the polygon mesher dependency is ever removed + // The dependency is needed for the converter, however the assembly resolve doesn't look in the kits + // folder for missing dlls, it looks in the connector folder. We should probably figure out a different + // method for dealing with converter dependencies + return null; } } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/StreamStateManager/StreamStateManager.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/StreamStateManager/StreamStateManager.cs index a4e19487f9..0aadd517fd 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/StreamStateManager/StreamStateManager.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/StreamStateManager/StreamStateManager.cs @@ -1,127 +1,142 @@ -using DesktopUI2.Models; +using DesktopUI2.Models; using Speckle.Newtonsoft.Json; using System.Collections.Generic; using System.IO; using System.Text; using Tekla.Structures.Model; -namespace ConnectorTeklaStructures.Storage +namespace ConnectorTeklaStructures.Storage; + +public static class StreamStateManager { - public static class StreamStateManager + private static string _speckleFilePath; + + public static List ReadState(Model model) { + var strings = ReadSpeckleFile(model); + if (strings == "") + { + return new List(); + } + try + { + return JsonConvert.DeserializeObject>(strings); + } + catch + { + return new List(); + } + } - private static string _speckleFilePath; - public static List ReadState(Model model) + /// + /// Writes the stream states to the .txt file in speckle folder + /// that exists or is created in the folder where the TeklaStructures model exists. + /// + /// + /// + public static void WriteStreamStateList(Model model, List streamStates) + { + if (_speckleFilePath == null) { - var strings = ReadSpeckleFile(model); - if (strings == "") - { - return new List(); - } - try - { - return JsonConvert.DeserializeObject>(strings); - } - catch - { - return new List(); - } + GetOrCreateSpeckleFilePath(model); } - /// - /// Writes the stream states to the .txt file in speckle folder - /// that exists or is created in the folder where the TeklaStructures model exists. - /// - /// - /// - public static void WriteStreamStateList(Model model, List streamStates) + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + try { - if (_speckleFilePath == null) GetOrCreateSpeckleFilePath(model); - FileStream fileStream = new FileStream(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); - try + using (var streamWriter = new StreamWriter(fileStream)) { - using (var streamWriter = new StreamWriter(fileStream)) - { - streamWriter.Write(JsonConvert.SerializeObject(streamStates) as string); - streamWriter.Flush(); - } + streamWriter.Write(JsonConvert.SerializeObject(streamStates) as string); + streamWriter.Flush(); } - catch { } } + catch { } + } - public static void ClearStreamStateList(Model model) + public static void ClearStreamStateList(Model model) + { + if (_speckleFilePath == null) { - if (_speckleFilePath == null) GetOrCreateSpeckleFilePath(model); - FileStream fileStream = new FileStream(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); - try - { - fileStream.SetLength(0); - } - catch { } + GetOrCreateSpeckleFilePath(model); } - /// - /// We need a folder in TeklaStructures model folder named "speckle" and a file in it - /// called ".txt". This function create this file and folder if - /// they doesn't exists and returns it, otherwise just returns the file path - /// - /// - private static void GetOrCreateSpeckleFilePath(Model model) + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + try { - string TeklaStructuresModelfilePath = model.GetInfo().ModelPath; - if (TeklaStructuresModelfilePath == "") - { - // TeklaStructures model is probably not saved, so speckle shouldn't do much - _speckleFilePath = null; - return; - } - //string TeklaStructuresFileName = Path.GetFileNameWithoutExtension(TeklaStructuresModelfilePath); - //string TeklaStructuresModelFolder = Path.GetDirectoryName(TeklaStructuresModelfilePath); - //string speckleFolderPath = Path.Combine(TeklaStructuresModelFolder, "speckle"); - //string speckleFilePath = Path.Combine(TeklaStructuresModelFolder, "speckle", $"{TeklaStructuresFileName}.txt"); - string TeklaStructuresFileName = Path.GetFileNameWithoutExtension(model.GetInfo().ModelName); - string speckleFolderPath = Path.Combine(TeklaStructuresModelfilePath, "speckle"); - string speckleFilePath = Path.Combine(speckleFolderPath, $"{TeklaStructuresFileName}.txt"); + fileStream.SetLength(0); + } + catch { } + } + + /// + /// We need a folder in TeklaStructures model folder named "speckle" and a file in it + /// called ".txt". This function create this file and folder if + /// they doesn't exists and returns it, otherwise just returns the file path + /// + /// + private static void GetOrCreateSpeckleFilePath(Model model) + { + string TeklaStructuresModelfilePath = model.GetInfo().ModelPath; + if (TeklaStructuresModelfilePath == "") + { + // TeklaStructures model is probably not saved, so speckle shouldn't do much + _speckleFilePath = null; + return; + } + //string TeklaStructuresFileName = Path.GetFileNameWithoutExtension(TeklaStructuresModelfilePath); + //string TeklaStructuresModelFolder = Path.GetDirectoryName(TeklaStructuresModelfilePath); + //string speckleFolderPath = Path.Combine(TeklaStructuresModelFolder, "speckle"); + //string speckleFilePath = Path.Combine(TeklaStructuresModelFolder, "speckle", $"{TeklaStructuresFileName}.txt"); + string TeklaStructuresFileName = Path.GetFileNameWithoutExtension(model.GetInfo().ModelName); + string speckleFolderPath = Path.Combine(TeklaStructuresModelfilePath, "speckle"); + string speckleFilePath = Path.Combine(speckleFolderPath, $"{TeklaStructuresFileName}.txt"); - try + try + { + if (!Directory.Exists(speckleFolderPath)) { - if (!Directory.Exists(speckleFolderPath)) - { - Directory.CreateDirectory(speckleFolderPath); - } - if (!File.Exists(speckleFilePath)) - { - File.CreateText(speckleFilePath); - } - _speckleFilePath = speckleFilePath; + Directory.CreateDirectory(speckleFolderPath); } - catch + if (!File.Exists(speckleFilePath)) { - _speckleFilePath = null; - return; + File.CreateText(speckleFilePath); } + _speckleFilePath = speckleFilePath; + } + catch + { + _speckleFilePath = null; + return; + } + } + + /// + /// Reads the "/speckle/.txt" file and returns the string in it + /// + /// + private static string ReadSpeckleFile(Model model) + { + if (_speckleFilePath == null) + { + GetOrCreateSpeckleFilePath(model); } - /// - /// Reads the "/speckle/.txt" file and returns the string in it - /// - /// - private static string ReadSpeckleFile(Model model) + if (_speckleFilePath == null) { - if (_speckleFilePath == null) - GetOrCreateSpeckleFilePath(model); + return ""; + } - if (_speckleFilePath == null) return ""; - FileStream fileStream = new FileStream(_speckleFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - try + FileStream fileStream = new(_speckleFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + try + { + using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { - using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) - { - return streamReader.ReadToEnd(); - } + return streamReader.ReadToEnd(); } - catch { return ""; } } - + catch + { + return ""; + } } -} \ No newline at end of file +} diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Send.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Send.cs index 52ad61f17a..d1680f6250 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Send.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Send.cs @@ -1,4 +1,4 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models; using DesktopUI2.Models.Settings; using DesktopUI2.ViewModels; @@ -16,166 +16,169 @@ using Tekla.Structures.Model; using SCT = Speckle.Core.Transports; -namespace Speckle.ConnectorTeklaStructures.UI +namespace Speckle.ConnectorTeklaStructures.UI; + +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings { - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings - { - #region sending + #region sending - private List CurrentSettings { get; set; } + private List CurrentSettings { get; set; } - public override bool CanPreviewSend => false; + public override bool CanPreviewSend => false; - public override void PreviewSend(StreamState state, ProgressViewModel progress) - { - return; - } + public override void PreviewSend(StreamState state, ProgressViewModel progress) + { + return; + } - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - public override async System.Threading.Tasks.Task SendStream(StreamState state, ProgressViewModel progress) + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + public override async System.Threading.Tasks.Task SendStream(StreamState state, ProgressViewModel progress) + { + var kit = KitManager.GetDefaultKit(); + var converter = kit.LoadConverter(ConnectorTeklaStructuresUtils.TeklaStructuresAppName); + converter.SetContextDocument(Model); + Exceptions.Clear(); + + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - var kit = KitManager.GetDefaultKit(); - var converter = kit.LoadConverter(ConnectorTeklaStructuresUtils.TeklaStructuresAppName); - converter.SetContextDocument(Model); - Exceptions.Clear(); + settings.Add(setting.Slug, setting.Selection); + } - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); + converter.SetConverterSettings(settings); - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); - using var d3 = LogContext.PushProperty("converterSettings", settings); + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToSpeckle)); + using var d3 = LogContext.PushProperty("converterSettings", settings); - var commitObj = new Base(); - int objCount = 0; + var commitObj = new Base(); + int objCount = 0; - var selectedObjects = new List(); + var selectedObjects = new List(); - if (state.Filter != null) - { - selectedObjects = GetSelectionFilterObjects(state.Filter); - state.SelectedObjectIds = selectedObjects.Select(x => x.Identifier.GUID.ToString()).ToList(); - } + if (state.Filter != null) + { + selectedObjects = GetSelectionFilterObjects(state.Filter); + state.SelectedObjectIds = selectedObjects.Select(x => x.Identifier.GUID.ToString()).ToList(); + } - var totalObjectCount = state.SelectedObjectIds.Count(); + var totalObjectCount = state.SelectedObjectIds.Count(); - if (totalObjectCount == 0) - { - throw new InvalidOperationException( - "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." - ); - } + if (totalObjectCount == 0) + { + throw new InvalidOperationException( + "Zero objects selected; send stopped. Please select some objects, or check that your filter can actually select something." + ); + } - var conversionProgressDict = new ConcurrentDictionary(); - progress.Max = totalObjectCount; - conversionProgressDict["Conversion"] = 0; - progress.Update(conversionProgressDict); + var conversionProgressDict = new ConcurrentDictionary(); + progress.Max = totalObjectCount; + conversionProgressDict["Conversion"] = 0; + progress.Update(conversionProgressDict); - foreach (ModelObject obj in selectedObjects) + foreach (ModelObject obj in selectedObjects) + { + if (progress.CancellationToken.IsCancellationRequested) { - if (progress.CancellationToken.IsCancellationRequested) - { - return null; - } + return null; + } - Base converted = null; - string containerName = string.Empty; + Base converted = null; + string containerName = string.Empty; - //var selectedObjectType = ConnectorTeklaStructuresUtils.ObjectIDsTypesAndNames - // .Where(pair => pair.Key == applicationId) - // .Select(pair => pair.Value.Item1).FirstOrDefault(); + //var selectedObjectType = ConnectorTeklaStructuresUtils.ObjectIDsTypesAndNames + // .Where(pair => pair.Key == applicationId) + // .Select(pair => pair.Value.Item1).FirstOrDefault(); - if (!converter.CanConvertToSpeckle(obj)) - { - progress.Report.Log($"Skipped not supported type: ${obj.GetType()} are not supported"); - continue; - } + if (!converter.CanConvertToSpeckle(obj)) + { + progress.Report.Log($"Skipped not supported type: ${obj.GetType()} are not supported"); + continue; + } - //var typeAndName = ConnectorTeklaStructuresUtils.ObjectIDsTypesAndNames - // .Where(pair => pair.Key == applicationId) - // .Select(pair => pair.Value).FirstOrDefault(); + //var typeAndName = ConnectorTeklaStructuresUtils.ObjectIDsTypesAndNames + // .Where(pair => pair.Key == applicationId) + // .Select(pair => pair.Value).FirstOrDefault(); - using var d4 = LogContext.PushProperty("fromType", obj.GetType()); + using var d4 = LogContext.PushProperty("fromType", obj.GetType()); - try - { - converted = converter.ConvertToSpeckle(obj); - if (converted == null) - throw new ConversionException("Conversion returned null"); - } - catch (Exception ex) + try + { + converted = converter.ConvertToSpeckle(obj); + if (converted == null) { - ConnectorHelpers.LogConversionException(ex); - progress.Report.LogConversionError( - new ConversionException( - $"Failed to convert object ${obj.Identifier.GUID} of type ${obj.GetType()} {ex.Message}", - ex - ) - ); + throw new ConversionException("Conversion returned null"); } + } + catch (Exception ex) + { + ConnectorHelpers.LogConversionException(ex); + progress.Report.LogConversionError( + new ConversionException( + $"Failed to convert object ${obj.Identifier.GUID} of type ${obj.GetType()} {ex.Message}", + ex + ) + ); + } - if (converted != null) + if (converted != null) + { + if (commitObj["@Base"] == null) { - if (commitObj["@Base"] == null) - { - commitObj["@Base"] = new List(); - } - ((List)commitObj["@Base"]).Add(converted); + commitObj["@Base"] = new List(); } - - objCount++; - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); + ((List)commitObj["@Base"]).Add(converted); } - progress.Report.Merge(converter.Report); + objCount++; + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); + } - if (objCount == 0) - { - throw new SpeckleException("Zero objects converted successfully. Send stopped."); - } + progress.Report.Merge(converter.Report); - progress.CancellationToken.ThrowIfCancellationRequested(); + if (objCount == 0) + { + throw new SpeckleException("Zero objects converted successfully. Send stopped."); + } - var streamId = state.StreamId; - var client = state.Client; + progress.CancellationToken.ThrowIfCancellationRequested(); - var transports = new List() { new SCT.ServerTransport(client.Account, streamId) }; - progress.Max = totalObjectCount; - var objectId = await Operations.Send( - @object: commitObj, - cancellationToken: progress.CancellationToken, - transports: transports, - onProgressAction: dict => progress.Update(dict), - onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, - disposeTransports: true - ); + var streamId = state.StreamId; + var client = state.Client; - progress.CancellationToken.ThrowIfCancellationRequested(); + var transports = new List() { new SCT.ServerTransport(client.Account, streamId) }; + progress.Max = totalObjectCount; + var objectId = await Operations.Send( + @object: commitObj, + cancellationToken: progress.CancellationToken, + transports: transports, + onProgressAction: dict => progress.Update(dict), + onErrorAction: ConnectorHelpers.DefaultSendErrorHandler, + disposeTransports: true + ); - var actualCommit = new CommitCreateInput - { - streamId = streamId, - objectId = objectId, - branchName = state.BranchName, - message = - state.CommitMessage != null ? state.CommitMessage : $"Pushed {objCount} elements from TeklaStructures.", - sourceApplication = ConnectorTeklaStructuresUtils.TeklaStructuresAppName - }; - - if (state.PreviousCommitId != null) - { - actualCommit.parents = new List() { state.PreviousCommitId }; - } + progress.CancellationToken.ThrowIfCancellationRequested(); - var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); - return commitId; + var actualCommit = new CommitCreateInput + { + streamId = streamId, + objectId = objectId, + branchName = state.BranchName, + message = state.CommitMessage != null ? state.CommitMessage : $"Pushed {objCount} elements from TeklaStructures.", + sourceApplication = ConnectorTeklaStructuresUtils.TeklaStructuresAppName + }; + + if (state.PreviousCommitId != null) + { + actualCommit.parents = new List() { state.PreviousCommitId }; } - #endregion + var commitId = await ConnectorHelpers.CreateCommit(client, actualCommit, progress.CancellationToken); + return commitId; } + + #endregion } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Settings.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Settings.cs index 4d89514521..a88b21c5aa 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Settings.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructure.Settings.cs @@ -1,4 +1,4 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models; using DesktopUI2.ViewModels; using System.Collections.Generic; @@ -6,18 +6,22 @@ using DesktopUI2.Models.Settings; using System.Linq; -namespace Speckle.ConnectorTeklaStructures.UI +namespace Speckle.ConnectorTeklaStructures.UI; + +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings { - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings -{ - public override List GetSettings() + public override List GetSettings() + { + return new List { - - - return new List + new CheckBoxSetting { - new CheckBoxSetting {Slug = "recieve-objects-mesh", Name = "Receive Objects as Direct Mesh", Icon = "Link", IsChecked = false, Description = "Recieve the stream as a Meshes only"} - }; - } + Slug = "recieve-objects-mesh", + Name = "Receive Objects as Direct Mesh", + Icon = "Link", + IsChecked = false, + Description = "Recieve the stream as a Meshes only" + } + }; } } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.ClientOperations.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.ClientOperations.cs index 0973d46deb..7619de95ab 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.ClientOperations.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.ClientOperations.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using DesktopUI2; using DesktopUI2.Models; @@ -8,41 +8,42 @@ using System.Linq; using System.Threading.Tasks; -namespace Speckle.ConnectorTeklaStructures.UI +namespace Speckle.ConnectorTeklaStructures.UI; + +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings { - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings + #region Local stream I/O with local file + public override List GetCustomStreamMenuItems() { - #region Local stream I/O with local file - public override List GetCustomStreamMenuItems() - { - return new List(); - } + return new List(); + } - public override void WriteStreamsToFile(List streams) - { - StreamStateManager.ClearStreamStateList(Model); - StreamStateManager.WriteStreamStateList(Model, streams); - } + public override void WriteStreamsToFile(List streams) + { + StreamStateManager.ClearStreamStateList(Model); + StreamStateManager.WriteStreamStateList(Model, streams); + } - public override List GetStreamsInFile() + public override List GetStreamsInFile() + { + var streams = new List(); + if (Model != null) { - var streams = new List(); - if (Model != null) - streams = StreamStateManager.ReadState(Model); - - return streams; + streams = StreamStateManager.ReadState(Model); } - //public override void PersistAndUpdateStreamInFile(StreamState state) - //{ - // var index = DocumentStreams.FindIndex(b => b.Stream.id == state.Stream.id); - // if (index != -1) - // { - // DocumentStreams[index] = state; - // WriteStateToFile(); - // } - //} - - #endregion + return streams; } + + //public override void PersistAndUpdateStreamInFile(StreamState state) + //{ + // var index = DocumentStreams.FindIndex(b => b.Stream.id == state.Stream.id); + // if (index != -1) + // { + // DocumentStreams[index] = state; + // WriteStateToFile(); + // } + //} + + #endregion } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs index c363f3271d..44b0dfaf98 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs @@ -14,114 +14,116 @@ using Serilog.Context; using Speckle.Core.Models.GraphTraversal; -namespace Speckle.ConnectorTeklaStructures.UI +namespace Speckle.ConnectorTeklaStructures.UI; + +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings { - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings + #region receiving + public override bool CanPreviewReceive => false; + + public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + { + return null; + } + + public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) { - #region receiving - public override bool CanPreviewReceive => false; + Exceptions.Clear(); + + var kit = KitManager.GetDefaultKit(); + var converter = kit.LoadConverter(ConnectorTeklaStructuresUtils.TeklaStructuresAppName); + converter.SetContextDocument(Model); + //var previouslyRecieveObjects = state.ReceivedObjects; - public override async Task PreviewReceive(StreamState state, ProgressViewModel progress) + var settings = new Dictionary(); + CurrentSettings = state.Settings; + foreach (var setting in state.Settings) { - return null; + settings.Add(setting.Slug, setting.Selection); } - public override async Task ReceiveStream(StreamState state, ProgressViewModel progress) + converter.SetConverterSettings(settings); + + Exceptions.Clear(); + + Commit myCommit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); + state.LastCommit = myCommit; + Base commitObject = await ConnectorHelpers.ReceiveCommit(myCommit, state, progress); + await ConnectorHelpers.TryCommitReceived( + state, + myCommit, + ConnectorTeklaStructuresUtils.TeklaStructuresAppName, + progress.CancellationToken + ); + + var conversionProgressDict = new ConcurrentDictionary(); + conversionProgressDict["Conversion"] = 1; + //Execute.PostToUIThread(() => state.Progress.Maximum = state.SelectedObjectIds.Count()); + + Action updateProgressAction = () => { - Exceptions.Clear(); - - var kit = KitManager.GetDefaultKit(); - var converter = kit.LoadConverter(ConnectorTeklaStructuresUtils.TeklaStructuresAppName); - converter.SetContextDocument(Model); - //var previouslyRecieveObjects = state.ReceivedObjects; - - var settings = new Dictionary(); - CurrentSettings = state.Settings; - foreach (var setting in state.Settings) - settings.Add(setting.Slug, setting.Selection); - converter.SetConverterSettings(settings); - - Exceptions.Clear(); - - Commit myCommit = await ConnectorHelpers.GetCommitFromState(state, progress.CancellationToken); - state.LastCommit = myCommit; - Base commitObject = await ConnectorHelpers.ReceiveCommit(myCommit, state, progress); - await ConnectorHelpers.TryCommitReceived( - state, - myCommit, - ConnectorTeklaStructuresUtils.TeklaStructuresAppName, - progress.CancellationToken - ); + conversionProgressDict["Conversion"]++; + progress.Update(conversionProgressDict); + }; - var conversionProgressDict = new ConcurrentDictionary(); - conversionProgressDict["Conversion"] = 1; - //Execute.PostToUIThread(() => state.Progress.Maximum = state.SelectedObjectIds.Count()); - - Action updateProgressAction = () => - { - conversionProgressDict["Conversion"]++; - progress.Update(conversionProgressDict); - }; - - using var d0 = LogContext.PushProperty("converterName", converter.Name); - using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); - using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); - using var d3 = LogContext.PushProperty("conversionSettings", settings); - using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); - - foreach (var commitObj in FlattenCommitObject(commitObject, converter)) - { - BakeObject(commitObj, converter); - updateProgressAction?.Invoke(); - } - - Model.CommitChanges(); - progress.Report.Merge(converter.Report); - return state; - } + using var d0 = LogContext.PushProperty("converterName", converter.Name); + using var d1 = LogContext.PushProperty("converterAuthor", converter.Author); + using var d2 = LogContext.PushProperty("conversionDirection", nameof(ISpeckleConverter.ConvertToNative)); + using var d3 = LogContext.PushProperty("conversionSettings", settings); + using var d4 = LogContext.PushProperty("converterReceiveMode", converter.ReceiveMode); - /// - /// conversion to native - /// - /// - /// - /// - [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - private void BakeObject(Base obj, ISpeckleConverter converter) + foreach (var commitObj in FlattenCommitObject(commitObject, converter)) { - LogContext.PushProperty("fromType", obj.GetType()); - try - { - converter.ConvertToNative(obj); - } - catch (Exception ex) - { - var exception = new ConversionException( - $"Failed to convert object {obj.id} of type {obj.speckle_type} with error\n{ex}" - ); - converter.Report.LogOperationError(exception); - ConnectorHelpers.LogConversionException(ex); - } + BakeObject(commitObj, converter); + updateProgressAction?.Invoke(); } - /// - /// Traverses the object graph, returning objects to be converted. - /// - /// The root object to traverse - /// The converter instance, used to define what objects are convertable - /// A flattened list of objects to be converted ToNative - private static IEnumerable FlattenCommitObject(Base obj, ISpeckleConverter converter) + Model.CommitChanges(); + progress.Report.Merge(converter.Report); + return state; + } + + /// + /// conversion to native + /// + /// + /// + /// + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + private void BakeObject(Base obj, ISpeckleConverter converter) + { + LogContext.PushProperty("fromType", obj.GetType()); + try + { + converter.ConvertToNative(obj); + } + catch (Exception ex) { - var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); - - return traverseFunction - .Traverse(obj) - .Select(tc => tc.current) - .Where(b => b != null) - .Where(converter.CanConvertToNative) - .Reverse(); + var exception = new ConversionException( + $"Failed to convert object {obj.id} of type {obj.speckle_type} with error\n{ex}" + ); + converter.Report.LogOperationError(exception); + ConnectorHelpers.LogConversionException(ex); } + } - #endregion + /// + /// Traverses the object graph, returning objects to be converted. + /// + /// The root object to traverse + /// The converter instance, used to define what objects are convertable + /// A flattened list of objects to be converted ToNative + private static IEnumerable FlattenCommitObject(Base obj, ISpeckleConverter converter) + { + var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); + + return traverseFunction + .Traverse(obj) + .Select(tc => tc.current) + .Where(b => b != null) + .Where(converter.CanConvertToNative) + .Reverse(); } + + #endregion } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Recieve.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Recieve.cs index 4b868f468e..6ad9c5aea3 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Recieve.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Recieve.cs @@ -15,6 +15,7 @@ using Speckle.ConnectorTeklaStructures.Util; using DesktopUI2.ViewModels; using Tekla.Structures.Model; + namespace Speckle.ConnectorTeklaStructures.UI { public partial class ConnectorBindingsTeklaStructures : ConnectorBindings @@ -38,7 +39,6 @@ public override async Task ReceiveStream(StreamState state, Progres //return null; } - Tracker.TrackPageview(Tracker.STREAM_GET); var stream = await state.Client.StreamGet(state.StreamId); @@ -54,7 +54,12 @@ public override async Task ReceiveStream(StreamState state, Progres Commit commit = null; if (state.CommitId == "latest") { - var res = await state.Client.BranchGet(progress.CancellationTokenSource.Token, state.StreamId, state.BranchName, 1); + var res = await state.Client.BranchGet( + progress.CancellationTokenSource.Token, + state.StreamId, + state.BranchName, + 1 + ); commit = res.commits.items.FirstOrDefault(); } else @@ -64,18 +69,20 @@ public override async Task ReceiveStream(StreamState state, Progres string referencedObject = commit.referencedObject; var commitObject = await Operations.Receive( - referencedObject, - progress.CancellationTokenSource.Token, - transport, - onProgressAction: dict => progress.Update(dict), - onErrorAction: (Action)((s, e) => - { - progress.Report.LogOperationError(e); - progress.CancellationTokenSource.Cancel(); - }), - //onTotalChildrenCountKnown: count => Execute.PostToUIThread(() => state.Progress.Maximum = count), - disposeTransports: true - ); + referencedObject, + progress.CancellationTokenSource.Token, + transport, + onProgressAction: dict => progress.Update(dict), + onErrorAction: (Action)( + (s, e) => + { + progress.Report.LogOperationError(e); + progress.CancellationTokenSource.Cancel(); + } + ), + //onTotalChildrenCountKnown: count => Execute.PostToUIThread(() => state.Progress.Maximum = count), + disposeTransports: true + ); if (progress.Report.OperationErrorsCount != 0) { @@ -84,20 +91,21 @@ public override async Task ReceiveStream(StreamState state, Progres try { - await state.Client.CommitReceived(new CommitReceivedInput - { - streamId = stream?.id, - commitId = commit?.id, - message = commit?.message, - sourceApplication = ConnectorTeklaStructuresUtils.TeklaStructuresAppName - }); + await state.Client.CommitReceived( + new CommitReceivedInput + { + streamId = stream?.id, + commitId = commit?.id, + message = commit?.message, + sourceApplication = ConnectorTeklaStructuresUtils.TeklaStructuresAppName + } + ); } catch { // Do nothing! } - if (progress.Report.OperationErrorsCount != 0) { return state; @@ -118,7 +126,6 @@ await state.Client.CommitReceived(new CommitReceivedInput progress.Update(conversionProgressDict); }; - var commitObjs = FlattenCommitObject(commitObject, converter); foreach (var commitObj in commitObjs) { @@ -126,8 +133,6 @@ await state.Client.CommitReceived(new CommitReceivedInput updateProgressAction?.Invoke(); } - - try { //await state.RefreshStream(); @@ -144,11 +149,6 @@ await state.Client.CommitReceived(new CommitReceivedInput return state; } - - - - - /// /// conversion to native /// @@ -164,14 +164,16 @@ private void BakeObject(Base obj, StreamState state, ISpeckleConverter converter } catch (Exception e) { - var exception = new Exception($"Failed to convert object {obj.id} of type {obj.speckle_type}\n with error\n{e}"); + var exception = new Exception( + $"Failed to convert object {obj.id} of type {obj.speckle_type}\n with error\n{e}" + ); converter.Report.LogOperationError(exception); return; } } /// - /// Recurses through the commit object and flattens it. + /// Recurses through the commit object and flattens it. /// /// /// diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Selection.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Selection.cs index b808ce88fa..d9dd25857f 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Selection.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Selection.cs @@ -1,4 +1,4 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models; using DesktopUI2.Models.Filters; using DesktopUI2.ViewModels; @@ -7,117 +7,141 @@ using System.Collections.Generic; using Tekla.Structures.Model; -namespace Speckle.ConnectorTeklaStructures.UI -{ - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings +namespace Speckle.ConnectorTeklaStructures.UI; +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings +{ + public override List GetSelectedObjects() { - public override List GetSelectedObjects() + var names = new List(); + ModelObjectEnumerator myEnum = new Tekla.Structures.Model.UI.ModelObjectSelector().GetSelectedObjects(); + while (myEnum.MoveNext()) { - var names = new List(); - ModelObjectEnumerator myEnum = new Tekla.Structures.Model.UI.ModelObjectSelector().GetSelectedObjects(); - while (myEnum.MoveNext()) - names.Add(myEnum.Current.Identifier.GUID.ToString()); - - return names; + names.Add(myEnum.Current.Identifier.GUID.ToString()); } - public override List GetSelectionFilters() + return names; + } + + public override List GetSelectionFilters() + { + var categories = new List(); + var parameters = new List(); + var views = new List(); + var phases = new List(); + if (Model != null) { - var categories = new List(); - var parameters = new List(); - var views = new List(); - var phases = new List(); - if (Model != null) + var phaseCollection = Model.GetPhases(); + foreach (Phase p in phaseCollection) { - var phaseCollection = Model.GetPhases(); - foreach (Phase p in phaseCollection) - phases.Add(p.PhaseName); - - //selectionCount = Model.Selection.GetElementIds().Count(); - categories = ConnectorTeklaStructuresUtils.GetCategoryNames(Model); - //parameters = ConnectorTeklaStructuresUtils.GetParameterNames(Model); - //views = ConnectorTeklaStructuresUtils.GetViewNames(Model); + phases.Add(p.PhaseName); } - return new List() - { - new AllSelectionFilter {Slug="all", Name = "Everything", - Icon = "CubeScan", Description = "Selects all document objects." }, - - new ListSelectionFilter {Slug="type", Name = "Categories", - Icon = "Category", Values = categories, - Description="Adds all objects belonging to the selected types"}, - new ListSelectionFilter {Slug="phase", Name = "Phases", - Icon = "SelectGroup", Values = phases, - Description="Adds all objects belonging to the selected phase"}, - - new ManualSelectionFilter(), - }; - } - public override void ResetDocument() - { - // TODO! + //selectionCount = Model.Selection.GetElementIds().Count(); + categories = ConnectorTeklaStructuresUtils.GetCategoryNames(Model); + //parameters = ConnectorTeklaStructuresUtils.GetParameterNames(Model); + //views = ConnectorTeklaStructuresUtils.GetViewNames(Model); } - - public override void SelectClientObjects(List args, bool deselect = false) + return new List() { - // TODO! - } + new AllSelectionFilter + { + Slug = "all", + Name = "Everything", + Icon = "CubeScan", + Description = "Selects all document objects." + }, + new ListSelectionFilter + { + Slug = "type", + Name = "Categories", + Icon = "Category", + Values = categories, + Description = "Adds all objects belonging to the selected types" + }, + new ListSelectionFilter + { + Slug = "phase", + Name = "Phases", + Icon = "SelectGroup", + Values = phases, + Description = "Adds all objects belonging to the selected phase" + }, + new ManualSelectionFilter(), + }; + } - private List GetSelectionFilterObjects(ISelectionFilter filter) - { - var doc = Model; + public override void ResetDocument() + { + // TODO! + } - var selection = new List(); + public override void SelectClientObjects(List args, bool deselect = false) + { + // TODO! + } - switch (filter.Slug) - { - case "manual": - ModelObjectEnumerator myEnum = new Tekla.Structures.Model.UI.ModelObjectSelector().GetSelectedObjects(); - while (myEnum.MoveNext()) - selection.Add(myEnum.Current); - return selection; - // return GetSelectedObjects(); - case "all": - myEnum = Model.GetModelObjectSelector().GetAllObjects(); - while (myEnum.MoveNext()) - selection.Add(myEnum.Current); - return selection; - - - case "phase": - var phaseFilter = filter as ListSelectionFilter; - myEnum = Model.GetModelObjectSelector().GetAllObjects(); - while (myEnum.MoveNext()) + private List GetSelectionFilterObjects(ISelectionFilter filter) + { + var doc = Model; + + var selection = new List(); + + switch (filter.Slug) + { + case "manual": + ModelObjectEnumerator myEnum = new Tekla.Structures.Model.UI.ModelObjectSelector().GetSelectedObjects(); + while (myEnum.MoveNext()) + { + selection.Add(myEnum.Current); + } + + return selection; + // return GetSelectedObjects(); + case "all": + myEnum = Model.GetModelObjectSelector().GetAllObjects(); + while (myEnum.MoveNext()) + { + selection.Add(myEnum.Current); + } + + return selection; + + case "phase": + var phaseFilter = filter as ListSelectionFilter; + myEnum = Model.GetModelObjectSelector().GetAllObjects(); + while (myEnum.MoveNext()) + { + foreach (var phase in phaseFilter.Selection) { - foreach (var phase in phaseFilter.Selection) + Phase phaseTemp = new(); + myEnum.Current.GetPhase(out phaseTemp); + if (phaseTemp.PhaseName == phase) { - Phase phaseTemp = new Phase(); - myEnum.Current.GetPhase(out phaseTemp); - if (phaseTemp.PhaseName == phase) - selection.Add(myEnum.Current); + selection.Add(myEnum.Current); } } + } - return selection; - case "type": - var catFilter = filter as ListSelectionFilter; - var categories = ConnectorTeklaStructuresUtils.GetCategories(Model); + return selection; + case "type": + var catFilter = filter as ListSelectionFilter; + var categories = ConnectorTeklaStructuresUtils.GetCategories(Model); - foreach (var cat in catFilter.Selection) + foreach (var cat in catFilter.Selection) + { + if (categories.ContainsKey(cat)) { - if (categories.ContainsKey(cat)) + myEnum = Model.GetModelObjectSelector().GetAllObjectsWithType(categories[cat]); + while (myEnum.MoveNext()) { - myEnum = Model.GetModelObjectSelector().GetAllObjectsWithType(categories[cat]); - while (myEnum.MoveNext()) - selection.Add(myEnum.Current); + selection.Add(myEnum.Current); } } - return selection; - } - - return selection; + } + return selection; } + + return selection; } } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.cs index d8c00384da..5a2ccc3af6 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.cs @@ -8,54 +8,55 @@ using Tekla.Structures.Model; using Speckle.Core.Kits; -namespace Speckle.ConnectorTeklaStructures.UI +namespace Speckle.ConnectorTeklaStructures.UI; + +public partial class ConnectorBindingsTeklaStructures : ConnectorBindings { - public partial class ConnectorBindingsTeklaStructures : ConnectorBindings + public void OpenTeklaStructures() { - public void OpenTeklaStructures() + var streams = GetStreamsInFile(); + if (UpdateSavedStreams != null) { - var streams = GetStreamsInFile(); - if (UpdateSavedStreams != null) - UpdateSavedStreams(streams); + UpdateSavedStreams(streams); } + } - public static Model Model { get; set; } - public List Exceptions { get; set; } = new List(); //What is this? and can we get rid of it? - public List DocumentStreams { get; set; } = new List(); + public static Model Model { get; set; } + public List Exceptions { get; set; } = new List(); //What is this? and can we get rid of it? + public List DocumentStreams { get; set; } = new List(); - public ConnectorBindingsTeklaStructures(Model model) - { - Model = model; - } + public ConnectorBindingsTeklaStructures(Model model) + { + Model = model; + } - public override List GetReceiveModes() - { - return new List { ReceiveMode.Create }; - } + public override List GetReceiveModes() + { + return new List { ReceiveMode.Create }; + } - #region boilerplate - public override string GetActiveViewName() - { - throw new NotImplementedException(); - } + #region boilerplate + public override string GetActiveViewName() + { + throw new NotImplementedException(); + } - public override string GetDocumentId() => GetDocHash(); + public override string GetDocumentId() => GetDocHash(); - private string GetDocHash() => - Utilities.HashString(Model.GetInfo().ModelPath + Model.GetInfo().ModelName, Utilities.HashingFunctions.MD5); + private string GetDocHash() => + Utilities.HashString(Model.GetInfo().ModelPath + Model.GetInfo().ModelName, Utilities.HashingFunctions.MD5); - public override string GetDocumentLocation() => Model.GetInfo().ModelPath; + public override string GetDocumentLocation() => Model.GetInfo().ModelPath; - public override string GetFileName() => Model.GetInfo().ModelName; + public override string GetFileName() => Model.GetInfo().ModelName; - public override string GetHostAppNameVersion() => ConnectorTeklaStructuresUtils.TeklaStructuresAppName; + public override string GetHostAppNameVersion() => ConnectorTeklaStructuresUtils.TeklaStructuresAppName; - public override string GetHostAppName() => HostApplications.TeklaStructures.Slug; + public override string GetHostAppName() => HostApplications.TeklaStructures.Slug; - public override List GetObjectsInView() - { - throw new NotImplementedException(); - } - #endregion + public override List GetObjectsInView() + { + throw new NotImplementedException(); } + #endregion } diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/Util/ConnectorTeklaStructuresUtils.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/Util/ConnectorTeklaStructuresUtils.cs index 26486e67fc..505e5c0c12 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/Util/ConnectorTeklaStructuresUtils.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/Util/ConnectorTeklaStructuresUtils.cs @@ -1,4 +1,4 @@ -using Speckle.ConnectorTeklaStructures.UI; +using Speckle.ConnectorTeklaStructures.UI; using Speckle.Core.Kits; using Speckle.Core.Logging; using Speckle.Core.Models; @@ -8,54 +8,53 @@ using System.Text; using Tekla.Structures.Model; -namespace Speckle.ConnectorTeklaStructures.Util +namespace Speckle.ConnectorTeklaStructures.Util; + +class ConnectorTeklaStructuresUtils { - class ConnectorTeklaStructuresUtils - { #if TeklaStructures2020 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2020); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2020); #elif TeklaStructures2021 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2021); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2021); #elif TeklaStructures2022 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2022); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2022); #elif TeklaStructures2023 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2023); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2023); #endif - public static Dictionary ObjectIDsTypesAndNames { get; set; } + public static Dictionary ObjectIDsTypesAndNames { get; set; } - public List ConversionErrors { get; set; } + public List ConversionErrors { get; set; } - private static Dictionary _categories { get; set; } + private static Dictionary _categories { get; set; } - public static Dictionary GetCategories(Model model) + public static Dictionary GetCategories(Model model) + { + if (_categories == null) { - if (_categories == null) + _categories = new Dictionary(); + foreach (var bic in SupportedBuiltInCategories) { - _categories = new Dictionary(); - foreach (var bic in SupportedBuiltInCategories) + var category = model.GetModelObjectSelector().GetAllObjectsWithType(bic); + if (category == null) { - var category = model.GetModelObjectSelector().GetAllObjectsWithType(bic); - if (category == null) - continue; - _categories.Add(bic.ToString(), bic); + continue; } + + _categories.Add(bic.ToString(), bic); } - return _categories; } + return _categories; + } + #region Get List Names - #region Get List Names - - public static List GetCategoryNames(Model model) - { - return GetCategories(model).Keys.OrderBy(x => x).ToList(); - } - #endregion - - private static List SupportedBuiltInCategories = new List - { - ModelObject.ModelObjectEnum.BEAM - }; + public static List GetCategoryNames(Model model) + { + return GetCategories(model).Keys.OrderBy(x => x).ToList(); } + #endregion + + private static List SupportedBuiltInCategories = + new() { ModelObject.ModelObjectEnum.BEAM }; } diff --git a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.BranchOperations.cs b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.BranchOperations.cs index c3cadabecc..a371935a92 100644 --- a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.BranchOperations.cs +++ b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.BranchOperations.cs @@ -25,7 +25,8 @@ public async Task> StreamGetBranchesWithLimitRetry(string streamId, } catch (SpeckleGraphQLException) { - branches = await StreamGetBranches(streamId, ServerLimits.OLD_BRANCH_GET_LIMIT, commitsLimit).ConfigureAwait(true); + branches = await StreamGetBranches(streamId, ServerLimits.OLD_BRANCH_GET_LIMIT, commitsLimit) + .ConfigureAwait(true); } return branches; diff --git a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ObsoleteOperations.cs b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ObsoleteOperations.cs index d2688296dd..4148e1d1f8 100644 --- a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ObsoleteOperations.cs +++ b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ObsoleteOperations.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -25,7 +25,10 @@ public async Task _CheckStreamInvitesSupported(CancellationToken cancellat { var version = ServerVersion ?? await GetServerVersion(cancellationToken).ConfigureAwait(false); if (version < new System.Version("2.6.4")) + { throw new SpeckleException("Stream invites are only supported as of Speckle Server v2.6.4."); + } + return true; } #endregion diff --git a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ServerOperations.cs b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ServerOperations.cs index f45726b676..f7a5ec7bf7 100644 --- a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ServerOperations.cs +++ b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.ServerOperations.cs @@ -31,7 +31,9 @@ public partial class Client var res = await ExecuteGraphQLRequest(request, cancellationToken).ConfigureAwait(false); if (res.serverInfo.version.Contains("dev")) + { return new System.Version(999, 999, 999); + } ServerVersion = new System.Version(Regex.Replace(res.serverInfo.version, "[-a-zA-Z]+", "")); return ServerVersion; diff --git a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.StreamOperations.cs b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.StreamOperations.cs index 937a0d9c07..079821640b 100644 --- a/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.StreamOperations.cs +++ b/Core/Core/Api/GraphQL/Client.GraphqlCleintOperations/Client.StreamOperations.cs @@ -144,9 +144,12 @@ public async Task> StreamsGet(int limit = 10, CancellationToken can var res = await ExecuteGraphQLRequest(request, cancellationToken).ConfigureAwait(false); if (res?.activeUser == null) + { throw new SpeckleException( "User is not authenticated, or the credentials were not valid. Check the provided account is still valid, remove it from manager and add it again." ); + } + return res.activeUser.streams.items; } @@ -398,7 +401,10 @@ public async Task StreamInviteCreate( ) { if ((inviteCreateInput.email == null) & (inviteCreateInput.userId == null)) + { throw new ArgumentException("You must provide either an email or a user id to create a stream invite"); + } + var request = new GraphQLRequest { Query = diff --git a/Core/Core/Api/GraphQL/Client.cs b/Core/Core/Api/GraphQL/Client.cs index 65f395458f..65f147752b 100644 --- a/Core/Core/Api/GraphQL/Client.cs +++ b/Core/Core/Api/GraphQL/Client.cs @@ -31,7 +31,9 @@ internal Client() { } public Client(Account account) { if (account == null) + { throw new SpeckleException("Provided account is null."); + } Account = account; @@ -63,11 +65,15 @@ public Client(Account account) GQLClient.WebSocketReceiveErrors.Subscribe(e => { if (e is WebSocketException we) + { Console.WriteLine( $"WebSocketException: {we.Message} (WebSocketError {we.WebSocketErrorCode}, ErrorCode {we.ErrorCode}, NativeErrorCode {we.NativeErrorCode}" ); + } else + { Console.WriteLine($"Exception in websocket receive stream: {e}"); + } }); } @@ -155,7 +161,9 @@ public async Task ExecuteGraphQLRequest(GraphQLRequest request, Cancellati { var result = await ExecuteWithResiliencePolicies(async () => { - GraphQLResponse result = await GQLClient.SendMutationAsync(request, cancellationToken).ConfigureAwait(false); + GraphQLResponse result = await GQLClient + .SendMutationAsync(request, cancellationToken) + .ConfigureAwait(false); MaybeThrowFromGraphQLErrors(request, result); return result.Data; }) @@ -235,7 +243,9 @@ internal void MaybeThrowFromGraphQLErrors(GraphQLRequest request, GraphQLResp ) ) ) + { throw new SpeckleGraphQLForbiddenException(request, response); + } if ( errors.Any( @@ -244,7 +254,9 @@ internal void MaybeThrowFromGraphQLErrors(GraphQLRequest request, GraphQLResp && (e.Extensions.Contains(new KeyValuePair("code", "STREAM_NOT_FOUND"))) ) ) + { throw new SpeckleGraphQLStreamNotFoundException(request, response); + } if ( errors.Any( @@ -253,7 +265,9 @@ internal void MaybeThrowFromGraphQLErrors(GraphQLRequest request, GraphQLResp && e.Extensions.Contains(new KeyValuePair("code", "INTERNAL_SERVER_ERROR")) ) ) + { throw new SpeckleGraphQLInternalErrorException(request, response); + } throw new SpeckleGraphQLException("Request failed with errors", request, response); } @@ -266,9 +280,14 @@ internal void MaybeThrowFromGraphQLErrors(GraphQLRequest request, GraphQLResp { object value; if (kvp.Value is ExpandoObject ex) + { value = _convertExpandoToDict(ex); + } else + { value = kvp.Value; + } + variables[kvp.Key] = value; } return variables; @@ -292,6 +311,7 @@ private ILogEventEnricher[] _createEnrichers(GraphQLRequest request) internal IDisposable SubscribeTo(GraphQLRequest request, Action callback) { using (LogContext.Push(_createEnrichers(request))) + { try { var res = GQLClient.CreateSubscriptionStream(request); @@ -303,11 +323,15 @@ internal IDisposable SubscribeTo(GraphQLRequest request, Action ca MaybeThrowFromGraphQLErrors(request, response); if (response.Data != null) + { callback(this, response.Data); + } else + { SpeckleLog.Logger .ForContext("graphqlResponse", response) .Error("Cannot execute graphql callback for {resultType}, the response has no data.", typeof(T).Name); + } } // we catch forbidden to rethrow, making sure its not logged. catch (SpeckleGraphQLForbiddenException) @@ -365,5 +389,6 @@ internal IDisposable SubscribeTo(GraphQLRequest request, Action ca null ); } + } } } diff --git a/Core/Core/Api/GraphQL/Serializer/ConstantCaseEnumConverter.cs b/Core/Core/Api/GraphQL/Serializer/ConstantCaseEnumConverter.cs index 01ab102dee..e8d950f8a8 100644 --- a/Core/Core/Api/GraphQL/Serializer/ConstantCaseEnumConverter.cs +++ b/Core/Core/Api/GraphQL/Serializer/ConstantCaseEnumConverter.cs @@ -26,7 +26,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s if (string.IsNullOrEmpty(memberName)) { if (!AllowIntegerValues) + { throw new JsonSerializationException($"Integer value {value} is not allowed."); + } + writer.WriteValue(value); } else diff --git a/Core/Core/Api/GraphQL/Serializer/MapConverter.cs b/Core/Core/Api/GraphQL/Serializer/MapConverter.cs index db83d4d1b3..ee09aacb85 100644 --- a/Core/Core/Api/GraphQL/Serializer/MapConverter.cs +++ b/Core/Core/Api/GraphQL/Serializer/MapConverter.cs @@ -27,7 +27,10 @@ JsonSerializer serializer { var rootToken = JToken.ReadFrom(reader); if (rootToken is JObject) + { return (Map)ReadDictionary(rootToken, new Map()); + } + throw new ArgumentException("This converter can only parse when the root element is a JSON Object."); } @@ -44,13 +47,16 @@ private object ReadToken(JToken token) _ => throw new ArgumentOutOfRangeException(nameof(token), $"Invalid token type {token?.Type}") }; } - + private Dictionary ReadDictionary(JToken element, Dictionary to) { foreach (var property in ((JObject)element).Properties()) { if (IsUnsupportedJTokenType(property.Value.Type)) + { continue; + } + to[property.Name] = ReadToken(property.Value); } return to; @@ -61,7 +67,10 @@ private IEnumerable ReadArray(JArray element) foreach (var item in element) { if (IsUnsupportedJTokenType(item.Type)) + { continue; + } + yield return ReadToken(item); } } diff --git a/Core/Core/Api/GraphQL/Serializer/NewtonsoftJsonSerializer.cs b/Core/Core/Api/GraphQL/Serializer/NewtonsoftJsonSerializer.cs index b0a4fc3092..6eb97f00d3 100644 --- a/Core/Core/Api/GraphQL/Serializer/NewtonsoftJsonSerializer.cs +++ b/Core/Core/Api/GraphQL/Serializer/NewtonsoftJsonSerializer.cs @@ -54,9 +54,9 @@ public Task DeserializeToWebsocketResponseWrapperAsync( public GraphQLWebSocketResponse DeserializeToWebsocketResponse(byte[] bytes) { return JsonConvert.DeserializeObject>( - Encoding.UTF8.GetString(bytes), - JsonSerializerSettings - ); + Encoding.UTF8.GetString(bytes), + JsonSerializerSettings + ); } public Task> DeserializeFromUtf8StreamAsync( @@ -80,5 +80,4 @@ private Task DeserializeFromUtf8Stream(System.IO.Stream stream) var serializer = JsonSerializer.Create(JsonSerializerSettings); return Task.FromResult(serializer.Deserialize(reader)); } - } diff --git a/Core/Core/Api/Helpers.cs b/Core/Core/Api/Helpers.cs index a50b326fe1..a4c136b0e2 100644 --- a/Core/Core/Api/Helpers.cs +++ b/Core/Core/Api/Helpers.cs @@ -93,7 +93,9 @@ public static async Task Receive( catch (SpeckleException e) { if (string.IsNullOrEmpty(sw.StreamId)) + { throw; + } //Fallback to a non authed account account = new Account @@ -128,7 +130,9 @@ public static async Task Receive( var branch = await client.BranchGet(sw.StreamId, branchName, 1).ConfigureAwait(false); if (!branch.commits.items.Any()) + { throw new SpeckleException("The selected branch has no commits."); + } commit = branch.commits.items[0]; objectId = branch.commits.items[0].referencedObject; @@ -235,7 +239,9 @@ public static async Task IsConnectorUpdateAvailable(string slug) { #if DEBUG if (slug == "dui2") + { slug = "revit"; + } //when debugging the version is not correct, so don't bother return false; #endif @@ -248,19 +254,25 @@ public static async Task IsConnectorUpdateAvailable(string slug) var os = Os.Win; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { os = Os.OSX; + } var versions = connector.Versions.Where(x => x.Os == os).OrderByDescending(x => x.Date).ToList(); var stables = versions.Where(x => !x.Prerelease); if (!stables.Any()) + { return false; + } var latestVersion = new System.Version(stables.First().Number); var currentVersion = Assembly.GetAssembly(typeof(Helpers)).GetName().Version; if (latestVersion > currentVersion) + { return true; + } } catch (Exception ex) { @@ -297,17 +309,34 @@ public static string TimeAgo(DateTime timestamp) timeAgo = DateTime.UtcNow.Subtract(timestamp); if (timeAgo.TotalSeconds < 60) + { return "just now"; + } + if (timeAgo.TotalMinutes < 60) + { return $"{timeAgo.Minutes} minute{PluralS(timeAgo.Minutes)} ago"; + } + if (timeAgo.TotalHours < 24) + { return $"{timeAgo.Hours} hour{PluralS(timeAgo.Hours)} ago"; + } + if (timeAgo.TotalDays < 7) + { return $"{timeAgo.Days} day{PluralS(timeAgo.Days)} ago"; + } + if (timeAgo.TotalDays < 30) + { return $"{timeAgo.Days / 7} week{PluralS(timeAgo.Days / 7)} ago"; + } + if (timeAgo.TotalDays < 365) + { return $"{timeAgo.Days / 30} month{PluralS(timeAgo.Days / 30)} ago"; + } if (timestamp <= new DateTime(1800, 1, 1)) { diff --git a/Core/Core/Api/Operations/Operations.Receive.cs b/Core/Core/Api/Operations/Operations.Receive.cs index 8d60f001f8..f7759e818e 100644 --- a/Core/Core/Api/Operations/Operations.Receive.cs +++ b/Core/Core/Api/Operations/Operations.Receive.cs @@ -99,9 +99,13 @@ public static partial class Operations JsonSerializerSettings? settings = null; BaseObjectDeserializerV2? serializerV2 = null; if (serializerVersion == SerializerVersion.V1) + { (serializer, settings) = GetSerializerInstance(); + } else + { serializerV2 = new BaseObjectDeserializerV2(); + } var localProgressDict = new ConcurrentDictionary(); var internalProgressAction = GetInternalProgressAction(localProgressDict, onProgressAction); @@ -124,7 +128,9 @@ public static partial class Operations serializerV2.OnErrorAction = onErrorAction; serializerV2.CancellationToken = cancellationToken; if (remoteTransport is IBlobCapableTransport t) + { serializerV2.BlobStorageFolder = t.BlobStorageFolder; + } } // First we try and get the object from the local transport. If it's there, we assume all its children are there, and proceed with deserialisation. @@ -136,18 +142,28 @@ public static partial class Operations // Shoot out the total children count var partial = JsonConvert.DeserializeObject(objString); if (partial == null) + { throw new SpeckleDeserializeException( $"Failed to deserialize {nameof(objString)} into {nameof(Placeholder)}" ); + } + if (partial.__closure != null) + { onTotalChildrenCountKnown?.Invoke(partial.__closure.Count); + } Base? localRes = DeserializeStringToBase(serializerVersion, objString, settings, serializerV2); if ((disposeTransports || !hasUserProvidedLocalTransport) && localTransport is IDisposable dispLocal) + { dispLocal.Dispose(); + } + if (disposeTransports && remoteTransport != null && remoteTransport is IDisposable dispRemote) + { dispRemote.Dispose(); + } timer.Stop(); SpeckleLog.Logger @@ -198,9 +214,14 @@ public static partial class Operations Base? res = DeserializeStringToBase(serializerVersion, objString, settings, serializerV2); if ((disposeTransports || !hasUserProvidedLocalTransport) && localTransport is IDisposable dl) + { dl.Dispose(); + } + if (disposeTransports && remoteTransport is IDisposable dr) + { dr.Dispose(); + } SpeckleLog.Logger .ForContext("deserializerElapsed", serializerV2.Elapsed) @@ -235,8 +256,11 @@ public static partial class Operations { Base? localRes; if (serializerVersion == SerializerVersion.V1) + { localRes = JsonConvert.DeserializeObject(objString, settings); + } else + { try { localRes = serializerV2!.Deserialize(objString); @@ -249,13 +273,17 @@ public static partial class Operations { SpeckleLog.Logger.Error(ex, "A deserialization error has occurred {exceptionMessage}", ex.Message); if (serializerV2.OnErrorAction == null) + { throw; + } + serializerV2.OnErrorAction.Invoke( $"A deserialization error has occurred: {ex.Message}", new SpeckleDeserializeException("A deserialization error has occurred", ex) ); localRes = null; } + } return localRes; } @@ -269,8 +297,10 @@ public class SpeckleDeserializeException : SpeckleException { public SpeckleDeserializeException() { } - public SpeckleDeserializeException(string message, Exception? inner = null) : base(message, inner) { } + public SpeckleDeserializeException(string message, Exception? inner = null) + : base(message, inner) { } - public SpeckleDeserializeException(string message) : base(message) { } + public SpeckleDeserializeException(string message) + : base(message) { } } } diff --git a/Core/Core/Api/Operations/Operations.Send.cs b/Core/Core/Api/Operations/Operations.Send.cs index a10684818f..2f6fb4b030 100644 --- a/Core/Core/Api/Operations/Operations.Send.cs +++ b/Core/Core/Api/Operations/Operations.Send.cs @@ -76,10 +76,12 @@ public static async Task Send( using var sqLiteTransport = new SQLiteTransport { TransportName = "LC" }; if (transports.Count == 0 && useDefaultCache == false) + { throw new ArgumentException( "You need to provide at least one transport: cannot send with an empty transport list and no default cache.", nameof(transports) ); + } if (useDefaultCache) { @@ -99,9 +101,13 @@ public static async Task Send( JsonSerializerSettings? settings = null; BaseObjectSerializerV2? serializerV2 = null; if (serializerVersion == SerializerVersion.V1) + { (serializer, settings) = GetSerializerInstance(); + } else + { serializerV2 = new BaseObjectSerializerV2(); + } var localProgressDict = new ConcurrentDictionary(); var internalProgressAction = GetInternalProgressAction(localProgressDict, onProgressAction); @@ -127,9 +133,13 @@ public static async Task Send( t.BeginWrite(); if (serializerVersion == SerializerVersion.V1) + { serializer!.WriteTransports.Add(t); + } else + { serializerV2!.WriteTransports.Add(t); + } } string obj; @@ -165,7 +175,9 @@ public static async Task Send( continue; } if (disposeTransports && t is IDisposable disp) + { disp.Dispose(); + } } if (cancellationToken.IsCancellationRequested) @@ -176,7 +188,10 @@ public static async Task Send( var idToken = JObject.Parse(obj).GetValue("id"); if (idToken == null) + { throw new SpeckleException("Failed to get id of serialized object"); + } + var hash = idToken.ToString(); sendTimer.Stop(); diff --git a/Core/Core/Api/Operations/Operations.Serialize.cs b/Core/Core/Api/Operations/Operations.Serialize.cs index c604bcc2f2..4dab4c4191 100644 --- a/Core/Core/Api/Operations/Operations.Serialize.cs +++ b/Core/Core/Api/Operations/Operations.Serialize.cs @@ -145,7 +145,10 @@ public static List DeserializeArray( List deserialized = deserializer.DeserializeTransportObject(objectArr) as List; List ret = new(); foreach (object obj in deserialized) + { ret.Add((Base)obj); + } + return ret; } diff --git a/Core/Core/Api/Operations/Operations.cs b/Core/Core/Api/Operations/Operations.cs index 871b822cd0..701eb257fa 100644 --- a/Core/Core/Api/Operations/Operations.cs +++ b/Core/Core/Api/Operations/Operations.cs @@ -46,9 +46,14 @@ private static Action GetInternalProgressAction( return (name, processed) => { if (localProgressDict.ContainsKey(name)) + { localProgressDict[name] += processed; + } else + { localProgressDict[name] = processed; + } + onProgressAction?.Invoke(localProgressDict); }; } diff --git a/Core/Core/Core.csproj b/Core/Core/Core.csproj index fc1dac829f..2060364fdd 100644 --- a/Core/Core/Core.csproj +++ b/Core/Core/Core.csproj @@ -45,7 +45,8 @@ - + + diff --git a/Core/Core/Credentials/Account.cs b/Core/Core/Credentials/Account.cs index a0bc237ba7..7c5e802f20 100644 --- a/Core/Core/Credentials/Account.cs +++ b/Core/Core/Credentials/Account.cs @@ -23,7 +23,10 @@ public string id if (_id == null) { if (serverInfo == null || userInfo == null) + { throw new SpeckleException("Incomplete account info: cannot generate id."); + } + _id = Utilities.HashString(userInfo.email + serverInfo.url, Utilities.HashingFunctions.MD5).ToUpper(); } return _id; @@ -49,7 +52,10 @@ private static string CleanURL(string server) Uri NewUri; if (Uri.TryCreate(server, UriKind.Absolute, out NewUri)) + { server = NewUri.Authority; + } + return server; } diff --git a/Core/Core/Credentials/AccountManager.cs b/Core/Core/Credentials/AccountManager.cs index 4398475b6a..9df35fa9b3 100644 --- a/Core/Core/Credentials/AccountManager.cs +++ b/Core/Core/Credentials/AccountManager.cs @@ -54,7 +54,9 @@ public static async Task GetServerInfo(string server) var response = await gqlClient.SendQueryAsync(request).ConfigureAwait(false); if (response.Errors != null) + { return null; + } response.Data.serverInfo.url = server; @@ -83,7 +85,9 @@ public static async Task GetUserInfo(string token, string server) var response = await gqlClient.SendQueryAsync(request).ConfigureAwait(false); if (response.Errors != null) + { return null; + } return response.Data.activeUser; } @@ -116,7 +120,9 @@ private static async Task GetUserServerInfo(string var res = await client.SendQueryAsync(request).ConfigureAwait(false); if (res.Errors != null && res.Errors.Any()) + { throw new SpeckleException(res.Errors[0].Message, res.Errors); + } return res.Data; } @@ -137,19 +143,25 @@ public static string GetDefaultServerUrl() // first mechanism, check for local file var customServerFile = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "server"); if (File.Exists(customServerFile)) + { customServerUrl = File.ReadAllText(customServerFile); + } // second mechanism, check ENV VAR var customServerEnvVar = Environment.GetEnvironmentVariable("SPECKLE_SERVER"); if (!string.IsNullOrEmpty(customServerEnvVar)) + { customServerUrl = customServerEnvVar; + } if (!string.IsNullOrEmpty(customServerUrl)) { Uri url = null; Uri.TryCreate(customServerUrl, UriKind.Absolute, out url); if (url != null) + { serverUrl = customServerUrl.TrimEnd('/'); + } } return serverUrl; @@ -176,7 +188,10 @@ public static Account GetDefaultAccount() { var firstAccount = GetAccounts().FirstOrDefault(); if (firstAccount == null) + { SpeckleLog.Logger.Information("No Speckle accounts found. Visit the Speckle web app to create one."); + } + return firstAccount; } return defaultAccount; @@ -197,9 +212,13 @@ public static IEnumerable GetAccounts() foreach (var acc in sqlAccounts) { if (IsInvalid(acc)) + { RemoveAccount(acc.id); + } else + { yield return acc; + } } foreach (var acc in localAccounts) @@ -218,10 +237,13 @@ private static IEnumerable GetLocalAccounts() var accounts = new List(); var accountsDir = SpecklePathProvider.AccountsFolderPath; if (!Directory.Exists(accountsDir)) + { return accounts; + } var files = Directory.GetFiles(accountsDir, "*.json", SearchOption.AllDirectories); foreach (var file in files) + { try { var json = File.ReadAllText(file); @@ -236,12 +258,15 @@ account is not null && !string.IsNullOrEmpty(account.serverInfo.url) && !string.IsNullOrEmpty(account.serverInfo.name) ) + { accounts.Add(account); + } } catch { //ignore it } + } return accounts; } @@ -268,7 +293,9 @@ public static async Task UpdateAccounts() userServerInfo = await GetUserServerInfo(tokenResponse.token, url).ConfigureAwait(false); if (userServerInfo?.activeUser == null || userServerInfo.serverInfo == null) + { throw new SpeckleException("Could not refresh token"); + } account.token = tokenResponse.token; account.refreshToken = tokenResponse.refreshToken; @@ -301,7 +328,9 @@ public static void RemoveAccount(string id) var accounts = GetAccounts(); if (accounts.Any() && !accounts.Any(x => x.isDefault)) + { ChangeDefaultAccount(accounts.First().id); + } } /// @@ -313,9 +342,13 @@ public static void ChangeDefaultAccount(string id) foreach (var account in GetAccounts()) { if (account.id != id) + { account.isDefault = false; + } else + { account.isDefault = true; + } AccountStorage.UpdateObject(account.id, JsonConvert.SerializeObject(account)); } @@ -370,9 +403,13 @@ private static async Task _getAccessCode(string server, string challenge SpeckleLog.Logger.Debug("Got access code {accessCode}", accessCode); var message = ""; if (accessCode != null) + { message = "Success!

You can close this window now."; + } else + { message = "Oups, something went wrong...!"; + } var responseString = $"
{message}"; @@ -447,8 +484,10 @@ private static void _tryLockAccountAddFlow(TimeSpan timespan) // use a static variable to quickly // prevent launching this flow multiple times if (_isAddingAccount) + { // this should probably throw with an error message throw new SpeckleAccountFlowLockedException("The account add flow is already launched."); + } // this uses the SQLite transport to store locks var lockIds = AccountAddLockStorage.GetAllObjects().OrderByDescending(d => d).ToList(); @@ -484,7 +523,9 @@ private static void _unlockAccountAddFlow() _isAddingAccount = false; // make sure all old locks are removed foreach (var id in AccountAddLockStorage.GetAllObjects()) + { AccountAddLockStorage.DeleteObject(id); + } } /// @@ -511,7 +552,9 @@ public static async Task AddAccount(string server = "") { accessCode = await _getAccessCode(server, challenge, timeout).ConfigureAwait(false); if (string.IsNullOrEmpty(accessCode)) + { throw new SpeckleAccountManagerException("Access code is invalid"); + } var account = await _createAccount(accessCode, challenge, server).ConfigureAwait(false); diff --git a/Core/Core/Credentials/StreamWrapper.cs b/Core/Core/Credentials/StreamWrapper.cs index c26a8c6405..d42039387f 100644 --- a/Core/Core/Credentials/StreamWrapper.cs +++ b/Core/Core/Credentials/StreamWrapper.cs @@ -26,9 +26,13 @@ public StreamWrapper(string streamUrlOrId) OriginalInput = streamUrlOrId; if (!Uri.TryCreate(streamUrlOrId, UriKind.Absolute, out _)) + { StreamWrapperFromId(streamUrlOrId); + } else + { StreamWrapperFromUrl(streamUrlOrId); + } } /// @@ -67,13 +71,19 @@ public StreamWrapperType Type get { if (!string.IsNullOrEmpty(ObjectId)) + { return StreamWrapperType.Object; + } if (!string.IsNullOrEmpty(CommitId)) + { return StreamWrapperType.Commit; + } if (!string.IsNullOrEmpty(BranchName)) + { return StreamWrapperType.Branch; + } // If we reach here and there is no stream id, it means that the stream is invalid for some reason. return !string.IsNullOrEmpty(StreamId) ? StreamWrapperType.Stream : StreamWrapperType.Undefined; @@ -85,7 +95,9 @@ private void StreamWrapperFromId(string streamId) Account account = AccountManager.GetDefaultAccount(); if (account == null) + { throw new SpeckleException("You do not have any account. Please create one or add it to the Speckle Manager."); + } ServerUrl = account.serverInfo.url; UserId = account.userInfo.id; @@ -114,11 +126,19 @@ private void ParseFe2RegexMatch(Match match) var additionalModels = match.Groups["additionalModels"]; if (!projectId.Success) + { throw new SpeckleException("The provided url is not a valid Speckle url"); + } + if (!model.Success) + { throw new SpeckleException("The provided url is not pointing to any model in the project."); + } + if (additionalModels.Success || model.Value == "all") + { throw new NotSupportedException("Multi-model urls are not supported yet"); + } var modelRes = ParseFe2ModelValue(model.Value); @@ -141,9 +161,15 @@ private void ParseFe2RegexMatch(Match match) private static (string? branchId, string? commitId, string? objectId) ParseFe2ModelValue(string modelValue) { if (modelValue.Length == 32) + { return (null, null, modelValue); // Model value is an ObjectID + } + if (!modelValue.Contains('@')) + { return (modelValue, null, null); // Model has no version attached + } + var res = modelValue.Split('@'); return (res[0], res[1], null); // Model has version attached } @@ -182,9 +208,13 @@ private void StreamWrapperFromUrl(string streamUrl) { case 3: // ie http://speckle.server/streams/8fecc9aa6d if (uri.Segments[1].ToLowerInvariant() == "streams/") + { StreamId = uri.Segments[2].Replace("/", ""); + } else + { throw new SpeckleException($"Cannot parse {uri} into a stream wrapper class."); + } break; case 4: // ie https://speckle.server/streams/0c6ad366c4/globals/ @@ -246,7 +276,9 @@ public async Task GetAccount() Exception err = null; if (_account != null) + { return _account; + } // Step 1: check if direct account id (?u=) if (OriginalInput != null && OriginalInput.Contains("?u=")) @@ -277,9 +309,12 @@ public async Task GetAccount() // Step 3: all the rest var accs = AccountManager.GetAccounts(ServerUrl).ToList(); if (accs.Count == 0) + { throw new SpeckleException($"You don't have any accounts for {ServerUrl}."); + } foreach (var acc in accs) + { try { await ValidateWithAccount(acc).ConfigureAwait(false); @@ -290,6 +325,7 @@ public async Task GetAccount() { err = e; } + } throw err; } @@ -303,9 +339,15 @@ public void SetAccount(Account acc) public bool Equals(StreamWrapper? wrapper) { if (wrapper == null) + { return false; + } + if (Type != wrapper.Type) + { return false; + } + return Type == wrapper.Type && ServerUrl == wrapper.ServerUrl && UserId == wrapper.UserId @@ -319,11 +361,15 @@ public bool Equals(StreamWrapper? wrapper) public async Task ValidateWithAccount(Account acc) { if (ServerUrl != acc.serverInfo.url) + { throw new SpeckleException($"Account is not from server {ServerUrl}"); + } var hasInternet = await Http.UserHasInternet().ConfigureAwait(false); if (!hasInternet) + { throw new Exception("You are not connected to the internet."); + } using var client = new Client(acc); // First check if the stream exists @@ -343,9 +389,11 @@ public async Task ValidateWithAccount(Account acc) { var branch = await client.BranchGet(StreamId, BranchName!, 1).ConfigureAwait(false); if (branch == null) + { throw new SpeckleException( $"The branch with name '{BranchName}' doesn't exist in stream {StreamId} on server {ServerUrl}" ); + } } } diff --git a/Core/Core/Helpers/Constants.cs b/Core/Core/Helpers/Constants.cs index 75b1ef161d..a81d16582a 100644 --- a/Core/Core/Helpers/Constants.cs +++ b/Core/Core/Helpers/Constants.cs @@ -7,6 +7,6 @@ public static class Constants public const double Eps = 1e-5; public const double SmallEps = 1e-8; public const double Eps2 = Eps * Eps; - + public static readonly Regex ChunkPropertyNameRegex = new(@"^@\((\d*)\)"); //TODO: Experiment with compiled flag } diff --git a/Core/Core/Helpers/Crypt.cs b/Core/Core/Helpers/Crypt.cs index 0511911282..ef65ad6f8d 100644 --- a/Core/Core/Helpers/Crypt.cs +++ b/Core/Core/Helpers/Crypt.cs @@ -16,7 +16,10 @@ public static string Hash(string input) StringBuilder sb = new(); for (int i = 0; i < hashBytes.Length; i++) + { sb.Append(hashBytes[i].ToString("X2")); + } + return sb.ToString(); } } diff --git a/Core/Core/Helpers/Http.cs b/Core/Core/Helpers/Http.cs index 36ee1b2093..3fbb38a312 100644 --- a/Core/Core/Helpers/Http.cs +++ b/Core/Core/Helpers/Http.cs @@ -94,14 +94,18 @@ public static async Task UserHasInternet() //can ping cloudfare, skip further checks //this method should be the fastest if (await Ping("1.1.1.1").ConfigureAwait(false)) + { return true; + } //lastly, try getting the default Speckle server, in case this is a sandboxed environment string defaultServer = AccountManager.GetDefaultServerUrl(); bool hasInternet = await HttpPing(defaultServer).ConfigureAwait(false); if (!hasInternet) + { SpeckleLog.Logger.ForContext("defaultServer", defaultServer).Warning("Failed to ping internet"); + } return hasInternet; } @@ -142,12 +146,18 @@ public static async Task Ping(string hostnameOrAddress) PingOptions pingOptions = new(); PingReply reply = await myPing.SendPingAsync(hostname, timeout, buffer, pingOptions).ConfigureAwait(false); if (reply.Status != IPStatus.Success) + { throw new Exception($"The ping operation failed with status {reply.Status}"); + } + return true; }) .ConfigureAwait(false); if (policyResult.Outcome == OutcomeType.Successful) + { return true; + } + SpeckleLog.Logger.Warning( policyResult.FinalException, "Failed to ping {hostnameOrAddress} cause: {exceptionMessage}", @@ -260,11 +270,15 @@ CancellationToken cancellationToken retryCount ?? 0 ); if (policyResult.Outcome == OutcomeType.Successful) + { return policyResult.Result!; + } // if the policy failed due to a cancellation, AND it was our cancellation token, then don't wrap the exception, and rethrow an new cancellation if (policyResult.FinalException is OperationCanceledException) + { cancellationToken.ThrowIfCancellationRequested(); + } // should we wrap this exception into something Speckle specific? throw new Exception("Policy Failed", policyResult.FinalException); diff --git a/Core/Core/Helpers/Path.cs b/Core/Core/Helpers/Path.cs index b87f39afef..6175397ef4 100644 --- a/Core/Core/Helpers/Path.cs +++ b/Core/Core/Helpers/Path.cs @@ -116,7 +116,9 @@ public static string UserApplicationDataPath() // if we have an override, just return that var pathOverride = _path; if (pathOverride != null && !string.IsNullOrEmpty(pathOverride)) + { return pathOverride; + } // on desktop linux and macos we use the appdata. // but we might not have write access to the disk diff --git a/Core/Core/Helpers/State.cs b/Core/Core/Helpers/State.cs index ba6bd554d1..97187d148d 100644 --- a/Core/Core/Helpers/State.cs +++ b/Core/Core/Helpers/State.cs @@ -2,7 +2,8 @@ namespace Speckle.Core.Helpers; -public class State : IDisposable where T : State, new() +public class State : IDisposable + where T : State, new() { static T root; static T current; @@ -16,7 +17,9 @@ protected State() { current = (T)this; if (root == null) + { root = (T)this; + } } } @@ -25,16 +28,25 @@ void IDisposable.Dispose() lock (StateChangeLock) { if (previous == null) + { return; // Already disposed or root + } - if (current == this) current = previous; + if (current == this) + { + current = previous; + } else { // If this state is still in the stack is safe to pop it var state = this; do { - if (state == root) { current = previous; break; } + if (state == root) + { + current = previous; + break; + } state = state.previous; } while (state != null); diff --git a/Core/Core/Kits/Applications.cs b/Core/Core/Kits/Applications.cs index ebebcbe176..dc94dd4b84 100644 --- a/Core/Core/Kits/Applications.cs +++ b/Core/Core/Kits/Applications.cs @@ -94,70 +94,166 @@ public static class HostApplications public static HostApplication GetHostAppFromString(string appname) { if (appname == null) + { return Other; + } + appname = appname.ToLowerInvariant().Replace(" ", ""); if (appname.Contains("dynamo")) + { return Dynamo; + } + if (appname.Contains("revit")) + { return Revit; + } + if (appname.Contains("autocad")) + { return AutoCAD; + } + if (appname.Contains("civil")) + { return Civil; + } + if (appname.Contains("rhino")) + { return Rhino; + } + if (appname.Contains("grasshopper")) + { return Grasshopper; + } + if (appname.Contains("unity")) + { return Unity; + } + if (appname.Contains("gsa")) + { return GSA; + } + if (appname.Contains("microstation")) + { return MicroStation; + } + if (appname.Contains("openroads")) + { return OpenRoads; + } + if (appname.Contains("openrail")) + { return OpenRail; + } + if (appname.Contains("openbuildings")) + { return OpenBuildings; + } + if (appname.Contains("etabs")) + { return ETABS; + } + if (appname.Contains("sap")) + { return SAP2000; + } + if (appname.Contains("csibridge")) + { return CSiBridge; + } + if (appname.Contains("safe")) + { return SAFE; + } + if (appname.Contains("teklastructures")) + { return TeklaStructures; + } + if (appname.Contains("dxf")) + { return Dxf; + } + if (appname.Contains("excel")) + { return Excel; + } + if (appname.Contains("unreal")) + { return Unreal; + } + if (appname.Contains("powerbi")) + { return PowerBI; + } + if (appname.Contains("blender")) + { return Blender; + } + if (appname.Contains("qgis")) + { return QGIS; + } + if (appname.Contains("arcgis")) + { return ArcGIS; + } + if (appname.Contains("sketchup")) + { return SketchUp; + } + if (appname.Contains("archicad")) + { return Archicad; + } + if (appname.Contains("topsolid")) + { return TopSolid; + } + if (appname.Contains("python")) + { return Python; + } + if (appname.Contains("net")) + { return NET; + } + if (appname.Contains("navisworks")) + { return Navisworks; + } + if (appname.Contains("advancesteel")) + { return AdvanceSteel; + } + return new HostApplication(appname, appname); } } diff --git a/Core/Core/Kits/ConverterInterfaces/IFinalizable.cs b/Core/Core/Kits/ConverterInterfaces/IFinalizable.cs index 1c6d27cdbb..7f10c2fc29 100644 --- a/Core/Core/Kits/ConverterInterfaces/IFinalizable.cs +++ b/Core/Core/Kits/ConverterInterfaces/IFinalizable.cs @@ -1,7 +1,6 @@ -namespace Speckle.Core.Kits.ConverterInterfaces +namespace Speckle.Core.Kits.ConverterInterfaces; + +public interface IFinalizable { - public interface IFinalizable - { - void FinalizeConversion(); - } + void FinalizeConversion(); } diff --git a/Core/Core/Kits/Exceptions.cs b/Core/Core/Kits/Exceptions.cs index 3734926204..89b513b6e0 100644 --- a/Core/Core/Kits/Exceptions.cs +++ b/Core/Core/Kits/Exceptions.cs @@ -26,9 +26,11 @@ public KitException(string? message, ISpeckleKit? kit, Exception? innerException public KitException() { } - public KitException(string? message) : base(message) { } + public KitException(string? message) + : base(message) { } - public KitException(string? message, Exception? innerException) : base(message, innerException) { } + public KitException(string? message, Exception? innerException) + : base(message, innerException) { } } /// @@ -48,9 +50,11 @@ public ConversionException(string? message, object? objectToConvert, Exception? this.ObjectThatFailed = objectToConvert; } - public ConversionException(string? message, Exception? innerException) : base(message, innerException) { } + public ConversionException(string? message, Exception? innerException) + : base(message, innerException) { } - public ConversionException(string? message) : base(message) { } + public ConversionException(string? message) + : base(message) { } public ConversionException() { } } @@ -82,9 +86,11 @@ public class ConversionNotSupportedException : ConversionException public ConversionNotSupportedException(string? message, object? objectToConvert, Exception? innerException = null) : base(message, objectToConvert, innerException) { } - public ConversionNotSupportedException(string message, Exception innerException) : base(message, innerException) { } + public ConversionNotSupportedException(string message, Exception innerException) + : base(message, innerException) { } - public ConversionNotSupportedException(string message) : base(message) { } + public ConversionNotSupportedException(string message) + : base(message) { } public ConversionNotSupportedException() { } } @@ -108,9 +114,11 @@ public class ConversionSkippedException : ConversionException public ConversionSkippedException(string? message, object? objectToConvert, Exception? innerException = null) : base(message, objectToConvert, innerException) { } - public ConversionSkippedException(string message, Exception innerException) : base(message, innerException) { } + public ConversionSkippedException(string message, Exception innerException) + : base(message, innerException) { } - public ConversionSkippedException(string message) : base(message) { } + public ConversionSkippedException(string message) + : base(message) { } public ConversionSkippedException() { } } @@ -123,9 +131,11 @@ public class ConversionNotReadyException : ConversionException public ConversionNotReadyException(string? message, object? objectToConvert, Exception? innerException = null) : base(message, objectToConvert, innerException) { } - public ConversionNotReadyException(string message, Exception innerException) : base(message, innerException) { } + public ConversionNotReadyException(string message, Exception innerException) + : base(message, innerException) { } - public ConversionNotReadyException(string message) : base(message) { } + public ConversionNotReadyException(string message) + : base(message) { } public ConversionNotReadyException() { } } diff --git a/Core/Core/Kits/KitManager.cs b/Core/Core/Kits/KitManager.cs index c6a3ee7428..078cf97f11 100644 --- a/Core/Core/Kits/KitManager.cs +++ b/Core/Core/Kits/KitManager.cs @@ -96,8 +96,12 @@ public static ISpeckleKit GetDefaultKit() public static IEnumerable GetKitsWithConvertersForApp(string app) { foreach (var kit in Kits) + { if (kit.Converters.Contains(app)) + { yield return kit; + } + } } /// @@ -157,18 +161,27 @@ public static List GetReferencedAssemblies() var assemblyToCheck = assembliesToCheck.Dequeue(); if (assemblyToCheck == null) + { continue; + } foreach (var reference in assemblyToCheck.GetReferencedAssemblies()) { // filtering out system dlls if (reference.FullName.StartsWith("System.")) + { continue; + } + if (reference.FullName.StartsWith("Microsoft.")) + { continue; + } if (loadedAssemblies.Contains(reference.FullName)) + { continue; + } Assembly assembly; try @@ -197,25 +210,39 @@ private static void GetLoadedSpeckleReferencingAssemblies() foreach (var assembly in assemblies) { if (assembly.IsDynamic || assembly.ReflectionOnly) + { continue; + } + if (!assembly.IsReferencing(SpeckleAssemblyName)) + { continue; + } + if (_SpeckleKits.ContainsKey(assembly.FullName)) + { continue; + } var kitClass = GetKitClass(assembly); if (kitClass == null) + { continue; + } if (Activator.CreateInstance(kitClass) is ISpeckleKit speckleKit) + { _SpeckleKits.Add(assembly.FullName, speckleKit); + } } } private static void LoadSpeckleReferencingAssemblies() { if (!Directory.Exists(KitsFolder)) + { return; + } var directories = Directory.GetDirectories(KitsFolder); @@ -226,16 +253,24 @@ private static void LoadSpeckleReferencingAssemblies() var unloadedAssemblyName = SafeGetAssemblyName(assemblyPath); if (unloadedAssemblyName == null) + { continue; + } try { var assembly = Assembly.LoadFrom(assemblyPath); var kitClass = GetKitClass(assembly); if (assembly.IsReferencing(SpeckleAssemblyName) && kitClass != null) + { if (!_SpeckleKits.ContainsKey(assembly.FullName)) + { if (Activator.CreateInstance(kitClass) is ISpeckleKit speckleKit) + { _SpeckleKits.Add(assembly.FullName, speckleKit); + } + } + } } catch (FileLoadException) { } catch (BadImageFormatException) { } @@ -301,11 +336,17 @@ public static class AssemblyExtensions public static bool IsReferencing(this Assembly assembly, AssemblyName referenceName) { if (AssemblyName.ReferenceMatchesDefinition(assembly.GetName(), referenceName)) + { return true; + } foreach (var referencedAssemblyName in assembly.GetReferencedAssemblies()) + { if (AssemblyName.ReferenceMatchesDefinition(referencedAssemblyName, referenceName)) + { return true; + } + } return false; } diff --git a/Core/Core/Kits/Units.cs b/Core/Core/Kits/Units.cs index bbf7599e20..cc6a5b870d 100644 --- a/Core/Core/Kits/Units.cs +++ b/Core/Core/Kits/Units.cs @@ -237,7 +237,10 @@ public static double GetConversionFactor(string from, string to) public static string GetUnitsFromString(string unit) { if (unit == null) + { return null; + } + switch (unit.ToLower()) { case "mm": diff --git a/Core/Core/Logging/Analytics.cs b/Core/Core/Logging/Analytics.cs index d709bc8ef4..f1bf658aed 100644 --- a/Core/Core/Logging/Analytics.cs +++ b/Core/Core/Logging/Analytics.cs @@ -148,9 +148,13 @@ public static void TrackEvent( ) { if (account == null) + { TrackEvent(eventName, customProperties, isAction); + } else + { TrackEvent(account.GetHashedEmail(), account.GetHashedServer(), eventName, customProperties, isAction); + } } /// @@ -189,15 +193,23 @@ private static void TrackEvent( { "token", MixpanelToken }, { "hostApp", Setup.HostApplication }, { "hostAppVersion", Setup.VersionedHostApplication }, - { "core_version", FileVersionInfo.GetVersionInfo(executingAssembly.Location).ProductVersion ?? executingAssembly.GetName().Version.ToString()}, + { + "core_version", + FileVersionInfo.GetVersionInfo(executingAssembly.Location).ProductVersion + ?? executingAssembly.GetName().Version.ToString() + }, { "$os", GetOs() } }; if (isAction) + { properties.Add("type", "action"); + } if (customProperties != null) + { properties = properties.Concat(customProperties).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } string json = JsonConvert.SerializeObject(new { @event = eventName.ToString(), properties }); @@ -260,11 +272,20 @@ internal static void AddConnectorToProfile(string hashedEmail, string connector) private static string GetOs() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { return "Windows"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { return "Mac OS X"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { return "Linux"; + } + return "Unknown"; } } diff --git a/Core/Core/Logging/CumulativeTimer.cs b/Core/Core/Logging/CumulativeTimer.cs index 75e156be46..f6cfc2fad2 100644 --- a/Core/Core/Logging/CumulativeTimer.cs +++ b/Core/Core/Logging/CumulativeTimer.cs @@ -4,83 +4,84 @@ using System.Diagnostics; using System.Text; -namespace Speckle.Core.Logging +namespace Speckle.Core.Logging; + +public class CumulativeTimer { - public class CumulativeTimer + internal class Operation : IDisposable { - internal class Operation : IDisposable - { - private static readonly double StopwatchToTimeSpanTicks = Stopwatch.Frequency / 10000000.0; + private static readonly double StopwatchToTimeSpanTicks = Stopwatch.Frequency / 10000000.0; - private readonly CumulativeTimer _cumulativeTimer; - private readonly string _operationName; - private readonly long _start; - private long? _stop; + private readonly CumulativeTimer _cumulativeTimer; + private readonly string _operationName; + private readonly long _start; + private long? _stop; - internal Operation(CumulativeTimer cumulativeTimer, string operationName) - { - _cumulativeTimer = cumulativeTimer; - _operationName = operationName; - _start = GetTimestamp(); - } + internal Operation(CumulativeTimer cumulativeTimer, string operationName) + { + _cumulativeTimer = cumulativeTimer; + _operationName = operationName; + _start = GetTimestamp(); + } - public TimeSpan Elapsed + public TimeSpan Elapsed + { + get { - get + long num = (_stop ?? GetTimestamp()) - _start; + if (num < 0) { - long num = (_stop ?? GetTimestamp()) - _start; - if (num < 0) - { - return TimeSpan.Zero; - } - - return TimeSpan.FromTicks(num); + return TimeSpan.Zero; } - } - private static long GetTimestamp() - { - return (long)(Stopwatch.GetTimestamp() / StopwatchToTimeSpanTicks); + return TimeSpan.FromTicks(num); } + } - private void StopTiming() - { - if (!_stop.HasValue) - _stop = GetTimestamp(); - } + private static long GetTimestamp() + { + return (long)(Stopwatch.GetTimestamp() / StopwatchToTimeSpanTicks); + } - public void Dispose() + private void StopTiming() + { + if (!_stop.HasValue) { - StopTiming(); - _cumulativeTimer.AddTimer(_operationName, Elapsed); + _stop = GetTimestamp(); } } - private readonly Dictionary _operationTimings = new(); - - public IDisposable Begin(string operationNameTemplate, params object[] args) + public void Dispose() { - return new Operation(this, string.Format(operationNameTemplate, args)); + StopTiming(); + _cumulativeTimer.AddTimer(_operationName, Elapsed); } + } + + private readonly Dictionary _operationTimings = new(); + + public IDisposable Begin(string operationNameTemplate, params object[] args) + { + return new Operation(this, string.Format(operationNameTemplate, args)); + } - public void AddTimer(string operationName, TimeSpan time) + public void AddTimer(string operationName, TimeSpan time) + { + if (_operationTimings.TryGetValue(operationName, out TimeSpan prevTimings)) { - if (_operationTimings.TryGetValue(operationName, out TimeSpan prevTimings)) - { - _operationTimings[operationName] = prevTimings + time; - } - else - { - _operationTimings.Add(operationName, time); - } + _operationTimings[operationName] = prevTimings + time; + } + else + { + _operationTimings.Add(operationName, time); } + } - public void EnrichSerilogOperation(SerilogTimings.Operation operation) + public void EnrichSerilogOperation(SerilogTimings.Operation operation) + { + foreach (var timing in _operationTimings) { - foreach (var timing in _operationTimings) - { - operation.EnrichWith(timing.Key, timing.Value.TotalMilliseconds); - } + operation.EnrichWith(timing.Key, timing.Value.TotalMilliseconds); } } } diff --git a/Core/Core/Logging/LoggingHelpers.cs b/Core/Core/Logging/LoggingHelpers.cs index b1520e0b1a..58a18d2ebc 100644 --- a/Core/Core/Logging/LoggingHelpers.cs +++ b/Core/Core/Logging/LoggingHelpers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; namespace Speckle.Core.Logging; diff --git a/Core/Core/Logging/Setup.cs b/Core/Core/Logging/Setup.cs index 61294e2056..3704b1a35b 100644 --- a/Core/Core/Logging/Setup.cs +++ b/Core/Core/Logging/Setup.cs @@ -70,6 +70,8 @@ public static void Init( SpeckleLog.Initialize(hostApplication, versionedHostApplication, logConfiguration); foreach (var account in AccountManager.GetAccounts()) + { Analytics.AddConnectorToProfile(account.GetHashedEmail(), hostApplication); + } } } diff --git a/Core/Core/Logging/SpeckleException.cs b/Core/Core/Logging/SpeckleException.cs index dd58f78706..e88f9fca17 100644 --- a/Core/Core/Logging/SpeckleException.cs +++ b/Core/Core/Logging/SpeckleException.cs @@ -11,9 +11,11 @@ public class SpeckleException : Exception { public SpeckleException() { } - public SpeckleException(string? message) : base(message) { } + public SpeckleException(string? message) + : base(message) { } - public SpeckleException(string? message, Exception? inner = null) : base(message, inner) { } + public SpeckleException(string? message, Exception? inner = null) + : base(message, inner) { } #region obsolete [Obsolete("Use any other constructor", true)] @@ -28,10 +30,10 @@ public SpeckleException(string? message, GraphQLError[] errors, bool log = true, } [Obsolete("Use any other constructor", true)] - public SpeckleException(string message, bool log, SentryLevel level = SentryLevel.Info) : base(message) { } + public SpeckleException(string message, bool log, SentryLevel level = SentryLevel.Info) + : base(message) { } [Obsolete("Use any other constructor", true)] public List> GraphQLErrors { get; set; } #endregion } - diff --git a/Core/Core/Logging/SpeckleLog.cs b/Core/Core/Logging/SpeckleLog.cs index 001c50ce04..c2a3cf19a2 100644 --- a/Core/Core/Logging/SpeckleLog.cs +++ b/Core/Core/Logging/SpeckleLog.cs @@ -99,7 +99,10 @@ public static ILogger Logger get { if (_logger == null) + { Initialize("Core", "unknown"); + } + return _logger!; } } @@ -165,36 +168,41 @@ SpeckleLogConfiguration logConfiguration // show a warning about that... var canLogToFile = true; _logFolderPath = SpecklePathProvider.LogFolderPath(hostApplicationName, hostApplicationVersion); - var logFilePath = Path.Combine( - _logFolderPath, - "SpeckleCoreLog.txt" - ); + var logFilePath = Path.Combine(_logFolderPath, "SpeckleCoreLog.txt"); var serilogLogConfiguration = new LoggerConfiguration().MinimumLevel .Is(logConfiguration.minimumLevel) .Enrich.FromLogContext() .Enrich.FromGlobalLogContext(); if (logConfiguration.enhancedLogContext) + { serilogLogConfiguration = serilogLogConfiguration.Enrich .WithClientAgent() .Enrich.WithClientIp() .Enrich.WithExceptionDetails(); + } if (logConfiguration.logToFile && canLogToFile) + { serilogLogConfiguration = serilogLogConfiguration.WriteTo.File( logFilePath, rollingInterval: RollingInterval.Day, retainedFileCountLimit: 10 ); + } if (logConfiguration.logToConsole) + { serilogLogConfiguration = serilogLogConfiguration.WriteTo.Console(); + } if (logConfiguration.logToSeq) + { serilogLogConfiguration = serilogLogConfiguration.WriteTo.Seq( "https://seq.speckle.systems", apiKey: "agZqxG4jQELxQQXh0iZQ" ); + } if (logConfiguration.logToSentry) { @@ -226,7 +234,10 @@ SpeckleLogConfiguration logConfiguration var logger = serilogLogConfiguration.CreateLogger(); if (logConfiguration.logToFile && !canLogToFile) + { logger.Warning("Log to file is enabled, but cannot write to {LogFilePath}", logFilePath); + } + return logger; } @@ -251,7 +262,9 @@ private static void _addUserIdToGlobalContextFromDefaultAccount() { var defaultAccount = AccountManager.GetDefaultAccount(); if (defaultAccount != null) + { id = defaultAccount.GetHashedEmail(); + } } catch (Exception ex) { @@ -277,11 +290,20 @@ private static void _addVersionInfoToGlobalContext() private static string _deterimineHostOsSlug() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { return "Windows"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { return "MacOS"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { return "Linux"; + } + return RuntimeInformation.OSDescription; } diff --git a/Core/Core/Logging/SpeckleNonUserFacingException.cs b/Core/Core/Logging/SpeckleNonUserFacingException.cs index de853439d8..678703ee80 100644 --- a/Core/Core/Logging/SpeckleNonUserFacingException.cs +++ b/Core/Core/Logging/SpeckleNonUserFacingException.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; namespace Speckle.Core.Logging; @@ -10,7 +10,9 @@ public class SpeckleNonUserFacingException : SpeckleException { public SpeckleNonUserFacingException() { } - public SpeckleNonUserFacingException(string? message) : base(message) { } + public SpeckleNonUserFacingException(string? message) + : base(message) { } - public SpeckleNonUserFacingException(string? message, Exception? innerException) : base(message, innerException) { } + public SpeckleNonUserFacingException(string? message, Exception? innerException) + : base(message, innerException) { } } diff --git a/Core/Core/Models/Base.cs b/Core/Core/Models/Base.cs index ba763fd406..e75ecb3595 100644 --- a/Core/Core/Models/Base.cs +++ b/Core/Core/Models/Base.cs @@ -65,7 +65,10 @@ public virtual string speckle_type while (myType.Name != nameof(Base)) { if (!myType.IsAbstract) + { bases.Add(myType.FullName); + } + myType = myType.BaseType; } @@ -96,7 +99,10 @@ public string GetId(bool decompose = false, SerializerVersion serializerVersion { var (s, t) = Operations.GetSerializerInstance(); if (decompose) + { s.WriteTransports = new List { new MemoryTransport() }; + } + var obj = JsonConvert.SerializeObject(this, t); return JObject.Parse(obj).GetValue(nameof(id)).ToString(); } @@ -104,7 +110,10 @@ public string GetId(bool decompose = false, SerializerVersion serializerVersion { var s = new BaseObjectSerializerV2(); if (decompose) + { s.WriteTransports = new List { new MemoryTransport() }; + } + var obj = s.Serialize(this); return JObject.Parse(obj).GetValue(nameof(id)).ToString(); } @@ -123,7 +132,9 @@ public long GetTotalChildrenCount() private static long CountDescendants(Base @base, HashSet parsed) { if (parsed.Contains(@base.GetHashCode())) + { return 0; + } parsed.Add(@base.GetHashCode()); @@ -134,7 +145,9 @@ private static long CountDescendants(Base @base, HashSet parsed) bool isIgnored = prop.IsDefined(typeof(ObsoleteAttribute), true) || prop.IsDefined(typeof(JsonIgnoreAttribute), true); if (isIgnored) + { continue; + } var detachAttribute = prop.GetCustomAttribute(true); var chunkAttribute = prop.GetCustomAttribute(true); @@ -150,7 +163,9 @@ private static long CountDescendants(Base @base, HashSet parsed) // Simplified chunking count handling. var asList = value as IList; if (asList != null) + { count += asList.Count / chunkAttribute.MaxObjCountPerChunk; + } } } @@ -158,7 +173,9 @@ private static long CountDescendants(Base @base, HashSet parsed) foreach (var propName in dynamicProps) { if (!propName.StartsWith("@")) + { continue; + } // Simplfied dynamic prop chunking handling if (ChunkSyntax.IsMatch(propName)) @@ -192,6 +209,7 @@ private static long HandleObjectCount(object value, HashSet parsed) case IDictionary d: { foreach (DictionaryEntry kvp in d) + { if (kvp.Value is Base) { count++; @@ -201,12 +219,14 @@ private static long HandleObjectCount(object value, HashSet parsed) { count += HandleObjectCount(kvp.Value, parsed); } + } return count; } case IEnumerable e when !(value is string): { foreach (var arrValue in e) + { if (arrValue is Base) { count++; @@ -216,6 +236,7 @@ private static long HandleObjectCount(object value, HashSet parsed) { count += HandleObjectCount(arrValue, parsed); } + } return count; } @@ -244,7 +265,9 @@ var kvp in GetMembers( { var p = GetType().GetProperty(kvp.Key); if (p != null && !p.CanWrite) + { continue; + } try { @@ -282,7 +305,10 @@ public string filePath set { if (originalPath is null) + { originalPath = value; + } + _filePath = value; hashExpired = true; } @@ -302,7 +328,9 @@ public override string id public string GetFileHash() { if ((hashExpired || _hash == null) && filePath != null) + { _hash = Utilities.HashFile(filePath); + } return _hash; } diff --git a/Core/Core/Models/CommitObjectBuilder.cs b/Core/Core/Models/CommitObjectBuilder.cs index 6313ac44d6..295c6cf28f 100644 --- a/Core/Core/Models/CommitObjectBuilder.cs +++ b/Core/Core/Models/CommitObjectBuilder.cs @@ -134,16 +134,24 @@ protected void ApplyRelationship(Base current, Base rootCommitObject) foreach (var instruction in instructions) { if (instruction.ParentApplicationId is null) + { continue; + } Base? parent; if (instruction.ParentApplicationId == Root) + { parent = rootCommitObject; + } else + { converted.TryGetValue(instruction.ParentApplicationId, out parent); + } if (parent is null) + { continue; + } try { @@ -166,6 +174,7 @@ protected static void NestUnderElementsProperty(Base parent, Base child) { NestUnderProperty(parent, child, Elements); } + protected static void NestUnderProperty(Base parent, Base child, string property) { if (parent.GetDetachedProp(property) is not IList elements) diff --git a/Core/Core/Models/DynamicBase.cs b/Core/Core/Models/DynamicBase.cs index 2af9c5deb7..5cd8524c92 100644 --- a/Core/Core/Models/DynamicBase.cs +++ b/Core/Core/Models/DynamicBase.cs @@ -41,20 +41,26 @@ public object this[string key] get { if (properties.ContainsKey(key)) + { return properties[key]; + } PopulatePropInfoCache(GetType()); var prop = propInfoCache[GetType()].FirstOrDefault(p => p.Name == key); if (prop == null) + { return null; + } return prop.GetValue(this); } set { if (!IsPropNameValid(key, out string reason)) + { throw new InvalidPropNameException(key, reason); + } if (properties.ContainsKey(key)) { @@ -104,7 +110,10 @@ public override bool TrySetMember(SetMemberBinder binder, object value) { var valid = IsPropNameValid(binder.Name, out _); if (valid) + { properties[binder.Name] = value; + } + return valid; } @@ -140,9 +149,11 @@ public bool IsPropNameValid(string name, out string reason) private static void PopulatePropInfoCache(Type type) { if (!propInfoCache.ContainsKey(type)) + { propInfoCache[type] = type.GetProperties(BindingFlags.Instance | BindingFlags.Public) .Where(p => !p.IsDefined(typeof(IgnoreTheItemAttribute), true)) .ToList(); + } } /// @@ -156,9 +167,14 @@ public override IEnumerable GetDynamicMemberNames() var names = new List(properties.Count + pinfos.Count); foreach (var pinfo in pinfos) + { names.Add(pinfo.Name); + } + foreach (var kvp in properties) + { names.Add(kvp.Key); + } return names; } @@ -180,7 +196,9 @@ public static IEnumerable GetInstanceMembersNames(Type t) var names = new List(pinfos.Count); foreach (var pinfo in pinfos) + { names.Add(pinfo.Name); + } return names; } @@ -202,8 +220,12 @@ public static IEnumerable GetInstanceMembers(Type t) var names = new List(pinfos.Count); foreach (var pinfo in pinfos) + { if (pinfo.Name != "Item") + { names.Add(pinfo); + } + } return names; } @@ -230,7 +252,9 @@ public Dictionary GetMembers(DynamicBaseMemberType includeMember // Add dynamic members if (includeMembers.HasFlag(DynamicBaseMemberType.Dynamic)) + { dic = new Dictionary(properties); + } if (includeMembers.HasFlag(DynamicBaseMemberType.Instance)) { @@ -249,11 +273,16 @@ public Dictionary GetMembers(DynamicBaseMemberType includeMember ); }); foreach (var pi in pinfos) + { if (!dic.ContainsKey(pi.Name)) //todo This is a TEMP FIX FOR #1969, and should be reverted after a proper fix is made! + { dic.Add(pi.Name, pi.GetValue(this)); + } + } } if (includeMembers.HasFlag(DynamicBaseMemberType.SchemaComputed)) + { GetType() .GetMethods() .Where(e => e.IsDefined(typeof(SchemaComputedAttribute)) && !e.IsDefined(typeof(ObsoleteAttribute))) @@ -271,6 +300,7 @@ public Dictionary GetMembers(DynamicBaseMemberType includeMember dic[attr.Name] = null; } }); + } return dic; } diff --git a/Core/Core/Models/Extensions.cs b/Core/Core/Models/Extensions.cs index 9f3f0d1ff5..954b767a10 100644 --- a/Core/Core/Models/Extensions.cs +++ b/Core/Core/Models/Extensions.cs @@ -34,15 +34,21 @@ public static IEnumerable Flatten(this Base root, BaseRecursionBreaker? re b => { if (!cache.Add(b.id)) + { return true; + } return recursionBreaker.Invoke(b); } ); foreach (var b in traversal) + { if (!cache.Contains(b.id)) + { yield return b; + } + } //Recursion break will be called after the above } @@ -63,9 +69,12 @@ public static IEnumerable Traverse(this Base root, BaseRecursionBreaker re yield return current; if (recursionBreaker(current)) + { continue; + } foreach (string child in current.GetDynamicMemberNames()) + { switch (current[child]) { case Base o: @@ -74,18 +83,29 @@ public static IEnumerable Traverse(this Base root, BaseRecursionBreaker re case IDictionary dictionary: { foreach (object obj in dictionary.Keys) + { if (obj is Base b) + { stack.Push(b); + } + } + break; } case IList collection: { foreach (object obj in collection) + { if (obj is Base b) + { stack.Push(b); + } + } + break; } } + } } } @@ -104,11 +124,19 @@ private static IEnumerable GetAllExceptions(this Exception exception) yield return exception; if (exception is AggregateException aggrEx) + { foreach (var innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions())) + { yield return innerEx; + } + } else if (exception.InnerException != null) + { foreach (var innerEx in exception.InnerException.GetAllExceptions()) + { yield return innerEx; + } + } } /// diff --git a/Core/Core/Models/Extras.cs b/Core/Core/Models/Extras.cs index 47b9c7a85f..61ce43a5d1 100644 --- a/Core/Core/Models/Extras.cs +++ b/Core/Core/Models/Extras.cs @@ -178,26 +178,52 @@ public void Update( ) { if (createdIds != null) + { createdIds .Where(o => !string.IsNullOrEmpty(o) && !CreatedIds.Contains(o)) ?.ToList() .ForEach(o => CreatedIds.Add(o)); + } + if (createdId != null && !CreatedIds.Contains(createdId)) + { CreatedIds.Add(createdId); + } + if (status.HasValue) + { Status = status.Value; + } + if (log != null) + { log.Where(o => !string.IsNullOrEmpty(o) && !Log.Contains(o))?.ToList().ForEach(o => Log.Add(o)); + } + if (!string.IsNullOrEmpty(logItem) && !Log.Contains(logItem)) + { Log.Add(logItem); + } + if (convertedItem != null && !Converted.Contains(convertedItem)) + { Converted.Add(convertedItem); + } + if (converted != null) + { converted.Where(o => o != null && !Converted.Contains(o))?.ToList().ForEach(o => Converted.Add(o)); + } + if (!string.IsNullOrEmpty(container)) + { Container = container; + } + if (!string.IsNullOrEmpty(descriptor)) + { Descriptor = descriptor; + } } } @@ -211,7 +237,9 @@ public void Log(ApplicationObject obj) { var _reportObject = UpdateReportObject(obj); if (_reportObject == null) + { ReportObjects.Add(obj.OriginalId, obj); + } } public ApplicationObject UpdateReportObject(ApplicationObject obj) @@ -227,7 +255,10 @@ public ApplicationObject UpdateReportObject(ApplicationObject obj) ); if (obj.Status != ApplicationObject.State.Unknown) + { reportObject.Update(status: obj.Status); + } + return reportObject; } @@ -246,36 +277,62 @@ public bool GetReportObject(string id, out int index) public void Merge(ProgressReport report) { lock (OperationErrorsLock) + { OperationErrors.AddRange(report.OperationErrors); + } lock (ConversionLogLock) + { ConversionLog.AddRange(report.ConversionLog); + } // update report object notes foreach (var item in ReportObjects.Values) { var ids = new List { item.OriginalId }; if (item.Fallback.Count > 0) + { ids.AddRange(item.Fallback.Select(o => o.OriginalId)); + } if (item.Status == ApplicationObject.State.Unknown) + { if (report.ReportObjects.TryGetValue(item.OriginalId, out var reportObject)) + { item.Status = reportObject.Status; + } + } foreach (var id in ids) + { //if (report.GetReportObject(id, out int index)) if (report.ReportObjects.TryGetValue(id, out var reportObject)) { foreach (var logItem in reportObject.Log) + { if (!item.Log.Contains(logItem)) + { item.Log.Add(logItem); + } + } + foreach (var createdId in reportObject.CreatedIds) + { if (!item.CreatedIds.Contains(createdId)) + { item.CreatedIds.Add(createdId); + } + } + foreach (var convertedItem in reportObject.Converted) + { if (!item.Converted.Contains(convertedItem)) + { item.Converted.Add(convertedItem); + } + } } + } } } @@ -317,7 +374,9 @@ public void Log(string text) { var time = DateTime.Now.ToLocalTime().ToString("dd/MM/yy HH:mm:ss"); lock (ConversionLogLock) + { ConversionLog.Add(time + " " + text); + } } /// @@ -332,7 +391,9 @@ public string ConversionErrorsString get { lock (ConversionErrorsLock) + { return string.Join("\n", ConversionErrors.Select(x => x.Message).Distinct()); + } } } @@ -341,7 +402,10 @@ public string ConversionErrorsString public void LogConversionError(Exception exception) { lock (ConversionErrorsLock) + { ConversionErrors.Add(exception); + } + Log(exception.Message); } @@ -365,7 +429,9 @@ public string OperationErrorsString get { lock (OperationErrorsLock) + { return string.Join("\n", OperationErrors.Select(x => x.ToFormattedString()).Distinct()); + } } } @@ -374,7 +440,9 @@ public string OperationErrorsString public void LogOperationError(Exception exception) { lock (OperationErrorsLock) + { OperationErrors.Add(exception); + } } #endregion diff --git a/Core/Core/Models/GraphTraversal/GraphTraversal.cs b/Core/Core/Models/GraphTraversal/GraphTraversal.cs index 4b21e232c4..57d39eb5a8 100644 --- a/Core/Core/Models/GraphTraversal/GraphTraversal.cs +++ b/Core/Core/Models/GraphTraversal/GraphTraversal.cs @@ -81,7 +81,9 @@ public IEnumerable Traverse(Base root) var activeRule = GetActiveRuleOrDefault(current); foreach (string childProp in activeRule.MembersToTraverse(current)) + { TraverseMemberToStack(stack, current[childProp], childProp, head); + } } } @@ -101,13 +103,19 @@ private void TraverseMemberToStack( case IList list: { foreach (object? obj in list) + { TraverseMemberToStack(stack, obj, memberName, parent); + } + break; } case IDictionary dictionary: { foreach (object? obj in dictionary.Values) + { TraverseMemberToStack(stack, obj, memberName, parent); + } + break; } } @@ -133,7 +141,9 @@ public static IEnumerable TraverseMember(object? value) foreach (object? obj in list) { foreach (Base o in TraverseMember(obj)) + { yield return o; + } } break; } @@ -142,7 +152,9 @@ public static IEnumerable TraverseMember(object? value) foreach (object? obj in dictionary.Values) { foreach (Base o in TraverseMember(obj)) + { yield return o; + } } break; } @@ -157,8 +169,12 @@ private ITraversalRule GetActiveRuleOrDefault(Base o) private ITraversalRule? GetActiveRule(Base o) { foreach (var rule in rules) + { if (rule.DoesRuleHold(o)) + { return rule; + } + } return null; } diff --git a/Core/Core/Models/GraphTraversal/RuleBuilder.cs b/Core/Core/Models/GraphTraversal/RuleBuilder.cs index 3eb81b1f80..07a796cc98 100644 --- a/Core/Core/Models/GraphTraversal/RuleBuilder.cs +++ b/Core/Core/Models/GraphTraversal/RuleBuilder.cs @@ -34,8 +34,13 @@ public ITraversalBuilderTraverse When(WhenCondition condition) bool ITraversalRule.DoesRuleHold(Base o) { foreach (var condition in _conditions) + { if (condition.Invoke(o)) + { return true; + } + } + return false; } diff --git a/Core/Core/Models/NestingInstructions.cs b/Core/Core/Models/NestingInstructions.cs index 3ad2f7532d..e16508a7e5 100644 --- a/Core/Core/Models/NestingInstructions.cs +++ b/Core/Core/Models/NestingInstructions.cs @@ -1,21 +1,21 @@ #nullable enable -namespace Speckle.Core.Models +namespace Speckle.Core.Models; + +/// +/// Container for a reference to a parent's applicationId and an Action to +/// execute in order to nest the child on the parent +/// +public struct NestingInstructions { - /// - /// Container for a reference to a parent's applicationId and an Action to - /// execute in order to nest the child on the parent - /// - public struct NestingInstructions - { - public delegate void NestAction(Base parent, Base child); - public NestingInstructions(string? parentApplicationId, NestAction nestAction) - { - ParentApplicationId = parentApplicationId; - Nest = nestAction; - } + public delegate void NestAction(Base parent, Base child); - public string? ParentApplicationId { get; } - public NestAction Nest { get; } + public NestingInstructions(string? parentApplicationId, NestAction nestAction) + { + ParentApplicationId = parentApplicationId; + Nest = nestAction; } + + public string? ParentApplicationId { get; } + public NestAction Nest { get; } } diff --git a/Core/Core/Models/Utilities.cs b/Core/Core/Models/Utilities.cs index 2367e126d6..d07f506325 100644 --- a/Core/Core/Models/Utilities.cs +++ b/Core/Core/Models/Utilities.cs @@ -44,9 +44,13 @@ public static string HashFile(string filePath, HashingFunctions func = HashingFu { HashAlgorithm hashAlgorithm; if (func == HashingFunctions.MD5) + { hashAlgorithm = MD5.Create(); + } else + { hashAlgorithm = SHA256.Create(); + } using (var stream = File.OpenRead(filePath)) { @@ -59,18 +63,20 @@ public static string HashFile(string filePath, HashingFunctions func = HashingFu private static string Sha256(string input) { using MemoryStream ms = new(); - + new BinaryFormatter().Serialize(ms, input); using SHA256 sha = SHA256.Create(); - + var hash = sha.ComputeHash(ms.ToArray()); StringBuilder sb = new(); foreach (byte b in hash) + { sb.Append(b.ToString("X2")); + } return sb.ToString().ToLower(); } - + private static string Md5(string input) { using MD5 md5 = MD5.Create(); @@ -79,7 +85,10 @@ private static string Md5(string input) StringBuilder sb = new(); for (int i = 0; i < hashBytes.Length; i++) + { sb.Append(hashBytes[i].ToString("X2")); + } + return sb.ToString().ToLower(); } @@ -106,7 +115,12 @@ public static bool IsSimpleType(this Type type) /// Set to true to also retrieve simple props of direct parent type /// Names of props to ignore /// - public static Base GetApplicationProps(object o, Type t, bool getParentProps = false, IReadOnlyList ignore = null) + public static Base GetApplicationProps( + object o, + Type t, + bool getParentProps = false, + IReadOnlyList ignore = null + ) { var appProps = new Base(); appProps["class"] = t.Name; @@ -117,12 +131,18 @@ public static Base GetApplicationProps(object o, Type t, bool getParentProps = f foreach (var propInfo in t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) { if (ignore != null && ignore.Contains(propInfo.Name)) + { continue; + } + if (IsMeaningfulProp(propInfo, o, out object propValue)) + { appProps[propInfo.Name] = propValue; + } } if (getParentProps) + { foreach ( var propInfo in t.BaseType.GetProperties( BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public @@ -130,10 +150,16 @@ var propInfo in t.BaseType.GetProperties( ) { if (ignore != null && ignore.Contains(propInfo.Name)) + { continue; + } + if (IsMeaningfulProp(propInfo, o, out object propValue)) + { appProps[propInfo.Name] = propValue; + } } + } } catch (Exception ex) { @@ -149,9 +175,15 @@ private static bool IsMeaningfulProp(PropertyInfo propInfo, object o, out object if (propInfo.GetSetMethod() != null && value != null) { if (propInfo.PropertyType.IsPrimitive || propInfo.PropertyType == typeof(decimal)) + { return true; + } + if (propInfo.PropertyType == typeof(string) && !string.IsNullOrEmpty((string)value)) + { return true; + } + if (propInfo.PropertyType.BaseType.Name == "Enum") // for some reason "IsEnum" prop returns false { value = value.ToString(); @@ -172,17 +204,24 @@ public static void SetApplicationProps(object o, Type t, Base props) var propNames = props.GetDynamicMembers(); IEnumerable names = propNames.ToList(); if (o == null || names.Any()) + { return; + } var typeProperties = t.GetProperties().ToList(); typeProperties.AddRange(t.BaseType.GetProperties().ToList()); foreach (var propInfo in typeProperties) + { if (propInfo.CanWrite && names.Contains(propInfo.Name)) { var value = props[propInfo.Name]; if (propInfo.PropertyType.BaseType.Name == "Enum") + { value = Enum.Parse(propInfo.PropertyType, (string)value); + } + if (value != null) + { try { t.InvokeMember( @@ -194,7 +233,9 @@ public static void SetApplicationProps(object o, Type t, Base props) ); } catch { } + } } + } } /// @@ -207,7 +248,9 @@ public static void SetApplicationProps(object o, Type t, Base props) public static IEnumerable> SplitList(List list, int chunkSize = 50) { for (int i = 0; i < list.Count; i += chunkSize) + { yield return list.GetRange(i, Math.Min(chunkSize, list.Count - i)); + } } #region Deprecated Members diff --git a/Core/Core/Serialisation/BaseObjectDeserializerV2.cs b/Core/Core/Serialisation/BaseObjectDeserializerV2.cs index a063b37089..a668cb706f 100644 --- a/Core/Core/Serialisation/BaseObjectDeserializerV2.cs +++ b/Core/Core/Serialisation/BaseObjectDeserializerV2.cs @@ -53,9 +53,11 @@ public sealed class BaseObjectDeserializerV2 public Base Deserialize(string rootObjectJson) { if (_busy) + { throw new InvalidOperationException( "A deserializer instance can deserialize only 1 object at a time. Consider creating multiple deserializer instances" ); + } try { @@ -76,7 +78,9 @@ public Base Deserialize(string rootObjectJson) stopwatch.Start(); object? deserializedOrPromise = DeserializeTransportObjectProxy(objJson); lock (_deserializedObjects) + { _deserializedObjects[objId] = deserializedOrPromise; + } } object ret = DeserializeTransportObject(rootObjectJson); @@ -84,11 +88,15 @@ public Base Deserialize(string rootObjectJson) stopwatch.Stop(); Elapsed += stopwatch.Elapsed; if (ret is Base b) + { return b; + } else + { throw new Exception( $"Expected {nameof(rootObjectJson)} to be deserialized to type {nameof(Base)} but was {ret}" ); + } } finally { @@ -107,7 +115,10 @@ public Base Deserialize(string rootObjectJson) JObject doc1 = JObject.Parse(rootObjectJson); if (!doc1.ContainsKey("__closure")) + { return new List<(string, int)>(); + } + foreach (JToken prop in doc1["__closure"]) { string childId = ((JProperty)prop).Name; @@ -127,7 +138,9 @@ public Base Deserialize(string rootObjectJson) // Try background work Task bgResult = _workerThreads.TryStartTask(WorkerThreadTaskType.Deserialize, objectJson); //BUG: Because we don't guarantee this task will ever be awaited, this may lead to unobserved exceptions! if (bgResult != null) + { return bgResult; + } // SyncS return DeserializeTransportObject(objectJson); @@ -136,7 +149,9 @@ public Base Deserialize(string rootObjectJson) public object? DeserializeTransportObject(string objectJson) { if (objectJson is null) + { throw new ArgumentNullException(nameof(objectJson), $"Cannot deserialize {nameof(objectJson)}, value was null"); + } // Apparently this automatically parses DateTimes in strings if it matches the format: // JObject doc1 = JObject.Parse(objectJson); @@ -151,7 +166,10 @@ public Base Deserialize(string rootObjectJson) object? converted = ConvertJsonElement(doc1); lock (_callbackLock) + { OnProgressAction?.Invoke("DS", 1); + } + return converted; } @@ -204,10 +222,16 @@ public Base Deserialize(string rootObjectJson) List retList = new(retListCount); foreach (object jsonObj in jsonList) + { if (jsonObj is DataChunk chunk) + { retList.AddRange(chunk.data); + } else + { retList.Add(jsonObj); + } + } return retList; case JTokenType.Object: @@ -218,12 +242,17 @@ public Base Deserialize(string rootObjectJson) { JProperty prop = (JProperty)propJToken; if (prop.Name == "__closure") + { continue; + } + dict[prop.Name] = ConvertJsonElement(prop.Value); } if (!dict.ContainsKey(TypeDiscriminator)) + { return dict; + } if ( dict[TypeDiscriminator] as string == "reference" && dict.TryGetValue("referencedId", out object? referencedId) @@ -232,8 +261,13 @@ public Base Deserialize(string rootObjectJson) var objId = (string)referencedId!; object deserialized = null; lock (_deserializedObjects) + { if (_deserializedObjects.TryGetValue(objId, out object? o)) + { deserialized = o; + } + } + if (deserialized is Task task) { try @@ -245,20 +279,30 @@ public Base Deserialize(string rootObjectJson) throw new Exception("Failed to deserialize reference object", ex); } lock (_deserializedObjects) + { _deserializedObjects[objId] = deserialized; + } } if (deserialized != null) + { return deserialized; + } // This reference was not already deserialized. Do it now in sync mode string objectJson = ReadTransport.GetObject(objId); if (objectJson is null) + { throw new Exception($"Failed to fetch object id {objId} from {ReadTransport} "); + } + deserialized = DeserializeTransportObject(objectJson); lock (_deserializedObjects) + { _deserializedObjects[objId] = deserialized; + } + return deserialized; } @@ -291,16 +335,22 @@ private Base Dict2Base(Dictionary dictObj) // Check for JsonProperty(NullValueHandling = NullValueHandling.Ignore) attribute JsonPropertyAttribute attr = property.GetCustomAttribute(true); if (attr != null && attr.NullValueHandling == NullValueHandling.Ignore) + { continue; + } } Type targetValueType = property.PropertyType; bool conversionOk = ValueConverter.ConvertValue(targetValueType, entry.Value, out object? convertedValue); if (conversionOk) + { property.SetValue(baseObj, convertedValue); + } else + { // Cannot convert the value in the json to the static property type throw new Exception($"Cannot deserialize {entry.Value.GetType().FullName} to {targetValueType.FullName}"); + } } else { @@ -310,10 +360,14 @@ private Base Dict2Base(Dictionary dictObj) } if (baseObj is Blob bb && BlobStorageFolder != null) + { bb.filePath = bb.getLocalDestinationPath(BlobStorageFolder); + } foreach (MethodInfo onDeserialized in onDeserializedCallbacks) + { onDeserialized.Invoke(baseObj, new object?[] { null }); + } return baseObj; } diff --git a/Core/Core/Serialisation/BaseObjectSerializer.cs b/Core/Core/Serialisation/BaseObjectSerializer.cs index 913c85ceaa..2135738af4 100644 --- a/Core/Core/Serialisation/BaseObjectSerializer.cs +++ b/Core/Core/Serialisation/BaseObjectSerializer.cs @@ -74,10 +74,14 @@ public override bool CanConvert(Type objectType) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } if (reader.TokenType == JsonToken.Null) + { return null; + } // Check if we passed in an array, rather than an object. // TODO: Test the following branch. It's not used anywhere at the moment, and the default serializer prevents it from @@ -90,7 +94,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist foreach (var val in jarr) { if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } var whatever = SerializationUtilities.HandleValue(val, serializer, CancellationToken); list.Add(whatever as Base); @@ -99,12 +105,16 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } var jObject = JObject.Load(reader); if (jObject == null) + { return null; + } var objType = jObject.GetValue(TypeDiscriminator); @@ -116,7 +126,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist foreach (var val in jObject) { if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } dict[val.Key] = SerializationUtilities.HandleValue(val.Value, serializer, CancellationToken); } @@ -124,7 +136,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } var discriminator = objType.Value(); @@ -135,9 +149,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist string str = ""; if (ReadTransport != null) + { str = ReadTransport.GetObject(id); + } else + { throw new SpeckleException("Cannot resolve reference, no transport is defined."); + } if (str != null && !string.IsNullOrEmpty(str)) { @@ -161,15 +179,21 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist jObject.Remove("__closure"); if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } foreach (var jProperty in jObject.Properties()) { if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } if (used.Contains(jProperty.Name)) + { continue; + } used.Add(jProperty.Name); @@ -205,13 +229,17 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } if (CancellationToken.IsCancellationRequested) + { return null; // Check for cancellation + } TotalProcessedCount++; OnProgressAction?.Invoke("DS", 1); foreach (var callback in contract.OnDeserializedCallbacks) + { callback(obj, serializer.Context); + } return obj; } @@ -251,12 +279,18 @@ private void TrackReferenceInTree(string refId) var parent = Lineage[i]; if (!RefMinDepthTracker.ContainsKey(parent)) + { RefMinDepthTracker[parent] = new Dictionary(); + } if (!RefMinDepthTracker[parent].ContainsKey(refId)) + { RefMinDepthTracker[parent][refId] = Lineage.Count - i; + } else if (RefMinDepthTracker[parent][refId] > Lineage.Count - i) + { RefMinDepthTracker[parent][refId] = Lineage.Count - i; + } } } @@ -271,14 +305,18 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s { writer.Formatting = serializer.Formatting; if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } ///////////////////////////////////// // Path one: nulls ///////////////////////////////////// if (value == null) + { return; + } ///////////////////////////////////// // Path two: primitives (string, bool, int, etc) @@ -300,7 +338,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s if (value is Base && !(value is ObjectReference)) { if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } var obj = value as Base; @@ -319,41 +359,59 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s foreach (var prop in propertyNames) { if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } // Ignore properties starting with a double underscore. if (prop.StartsWith("__")) + { continue; + } if (prop == "id") + { continue; + } var property = contract.Properties.GetClosestMatchProperty(prop); // Ignore properties decorated with [JsonIgnore]. if (property != null && property.Ignored) + { continue; + } // Ignore nulls object propValue = obj[prop]; if (propValue == null) + { continue; + } // Check if this property is marked for detachment: either by the presence of "@" at the beginning of the name, or by the presence of a DetachProperty attribute on a typed property. if (property != null) { var detachableAttributes = property.AttributeProvider.GetAttributes(typeof(DetachProperty), true); if (detachableAttributes.Count > 0) + { DetachLineage.Add(((DetachProperty)detachableAttributes[0]).Detachable); + } else + { DetachLineage.Add(false); + } var chunkableAttributes = property.AttributeProvider.GetAttributes(typeof(Chunkable), true); if (chunkableAttributes.Count > 0) + { //DetachLineage.Add(true); // NOOPE serializer.Context = new StreamingContext(StreamingContextStates.Other, chunkableAttributes[0]); + } else + { //DetachLineage.Add(false); serializer.Context = new StreamingContext(); + } } else if (prop.StartsWith("@")) // Convention check for dynamically added properties. { @@ -392,10 +450,14 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s var what = JToken.FromObject(propValue, serializer); // Trigger next. if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } if (what == null) + { return; // HACK: Prevent nulls from borking our serialization on nested schema object refs. (i.e. Line has @SchemaObject, that has ref to line) + } var refHash = ((JObject)what).GetValue("id").ToString(); @@ -420,11 +482,16 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s && WriteTransports.Count != 0 && RefMinDepthTracker.ContainsKey(Lineage[Lineage.Count - 1]) ) + { jo.Add("__closure", JToken.FromObject(RefMinDepthTracker[Lineage[Lineage.Count - 1]])); + } var hash = Utilities.HashString(jo.ToString()); if (!jo.ContainsKey("id")) + { jo.Add("id", JToken.FromObject(hash)); + } + jo.WriteTo(writer); if ( @@ -441,7 +508,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s foreach (var transport in WriteTransports) { if (CancellationToken.IsCancellationRequested) + { continue; // Check for cancellation + } transport.SaveObject(objId, objString); } @@ -457,7 +526,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s ///////////////////////////////////// if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } var type = value.GetType(); @@ -494,7 +565,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s if (i == maxCount) { if (currChunk.data.Count != 0) + { chunkList.Add(currChunk); + } currChunk = new DataChunk(); i = 0; @@ -504,17 +577,24 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } if (currChunk.data.Count != 0) + { chunkList.Add(currChunk); + } + value = chunkList; } foreach (var arrValue in (IEnumerable)value) { if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } if (arrValue == null) + { continue; + } if ( WriteTransports != null @@ -538,18 +618,24 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } arr.WriteTo(writer); if (DetachLineage.Count == 1 && FirstEntryWasListOrDict) // are we in a list entry point case? + { DetachLineage.RemoveAt(0); + } return; } if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } if (typeof(IDictionary).IsAssignableFrom(type)) { @@ -565,10 +651,14 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s foreach (DictionaryEntry kvp in dict) { if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } if (kvp.Value == null) + { continue; + } JToken jToken; if ( @@ -594,10 +684,14 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s dictJo.WriteTo(writer); if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } if (DetachLineage.Count == 1 && FirstEntryWasListOrDict) // are we in a dictionary entry point case? + { DetachLineage.RemoveAt(0); + } return; } @@ -607,7 +701,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s ///////////////////////////////////// if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } FirstEntry = false; var lastCall = JToken.FromObject(value); // bypasses this converter as we do not pass in the serializer diff --git a/Core/Core/Serialisation/BaseObjectSerializerV2.cs b/Core/Core/Serialisation/BaseObjectSerializerV2.cs index 3858d3597e..83bcbe3431 100644 --- a/Core/Core/Serialisation/BaseObjectSerializerV2.cs +++ b/Core/Core/Serialisation/BaseObjectSerializerV2.cs @@ -51,9 +51,12 @@ public class BaseObjectSerializerV2 public string Serialize(Base baseObj) { if (_busy) + { throw new Exception( "A serializer instance can serialize only 1 object at a time. Consider creating multiple serializer instances" ); + } + try { _stopwatch.Start(); @@ -83,16 +86,22 @@ public object PreserializeObject( CancellationToken.ThrowIfCancellationRequested(); if (obj == null) + { return null; + } Type type = obj.GetType(); if (type.IsPrimitive || obj is string) + { return obj; + } if (obj is Base b) + { // Complex enough to deserve its own function return PreserializeBase(b, computeClosures, inheritedDetachInfo); + } if (obj is IDictionary d) { @@ -101,7 +110,9 @@ public object PreserializeObject( { object converted = PreserializeObject(kvp.Value, inheritedDetachInfo: inheritedDetachInfo); if (converted != null) + { ret[kvp.Key.ToString()] = converted; + } } return ret; } @@ -111,11 +122,19 @@ public object PreserializeObject( { List ret; if (e is IList list) + { ret = new List(list.Count); + } else + { ret = new List(); + } + foreach (object element in e) + { ret.Add(PreserializeObject(element, inheritedDetachInfo: inheritedDetachInfo)); + } + return ret; } @@ -128,16 +147,28 @@ public object PreserializeObject( } if (obj is Enum) + { return (int)obj; + } // Support for simple types if (obj is Guid g) + { return g.ToString(); + } + if (obj is Color c) + { return c.ToArgb(); + } + if (obj is DateTime t) + { return t.ToString("o", CultureInfo.InvariantCulture); + } + if (obj is Matrix4x4 md) + { return new List { md.M11, @@ -157,6 +188,8 @@ public object PreserializeObject( md.M43, md.M44 }; + } + if (obj is System.Numerics.Matrix4x4 ms) //BACKWARDS COMPATIBILITY: matrix4x4 changed from System.Numerics float to System.DoubleNumerics double in release 2.16 { SpeckleLog.Logger.Warning( @@ -195,13 +228,18 @@ public object PreserializeBase( { // handle circular references if (ParentObjects.Contains(baseObj)) + { return null; + } + ParentObjects.Add(baseObj); Dictionary convertedBase = new(); Dictionary closure = new(); if (computeClosures || inheritedDetachInfo.IsDetachable || baseObj is Blob) + { ParentClosures.Add(closure); + } List<(PropertyInfo, PropertyAttributeInfo)> typedProperties = GetTypedPropertiesWithCache(baseObj); IEnumerable dynamicProperties = baseObj.GetDynamicMembers(); @@ -220,7 +258,10 @@ public object PreserializeBase( foreach (string propName in dynamicProperties) { if (propName.StartsWith("__")) + { continue; + } + object baseValue = baseObj[propName]; bool isDetachable = propName.StartsWith("@"); bool isChunkable = false; @@ -244,20 +285,31 @@ public object PreserializeBase( && prop.Value.Item2.JsonPropertyInfo != null && prop.Value.Item2.JsonPropertyInfo.NullValueHandling == NullValueHandling.Ignore ) + { continue; + } convertedBase[prop.Key] = convertedValue; } if (baseObj is Blob blob) + { convertedBase["id"] = blob.id; + } else + { convertedBase["id"] = ComputeId(convertedBase); + } if (closure.Count > 0) + { convertedBase["__closure"] = closure; + } + if (computeClosures || inheritedDetachInfo.IsDetachable || baseObj is Blob) + { ParentClosures.RemoveAt(ParentClosures.Count - 1); + } ParentObjects.Remove(baseObj); @@ -289,7 +341,9 @@ private object PreserializeBasePropertyValue(object baseValue, PropertyAttribute // If there are no WriteTransports, keep everything attached. if (WriteTransports == null || WriteTransports.Count == 0) + { return PreserializeObject(baseValue, inheritedDetachInfo: detachInfo); + } if (baseValue is IEnumerable && detachInfo.IsChunkable) { @@ -307,7 +361,10 @@ private object PreserializeBasePropertyValue(object baseValue, PropertyAttribute } } if (crtChunk.data.Count > 0) + { chunks.Add(crtChunk); + } + return PreserializeObject(chunks, inheritedDetachInfo: new PropertyAttributeInfo(true, false, 0, null)); } @@ -320,7 +377,10 @@ private void UpdateParentClosures(string objectId) { int childDepth = ParentClosures.Count - parentLevel; if (!ParentClosures[parentLevel].ContainsKey(objectId)) + { ParentClosures[parentLevel][objectId] = childDepth; + } + ParentClosures[parentLevel][objectId] = Math.Min(ParentClosures[parentLevel][objectId], childDepth); } } @@ -341,33 +401,46 @@ private static string Dict2Json(Dictionary obj) private void StoreObject(string objectId, string objectJson) { if (WriteTransports == null) + { return; + } + _stopwatch.Stop(); foreach (var transport in WriteTransports) + { transport.SaveObject(objectId, objectJson); + } + _stopwatch.Start(); } private void StoreBlob(Blob obj) { if (WriteTransports == null) + { return; + } + bool hasBlobTransport = false; _stopwatch.Stop(); foreach (var transport in WriteTransports) + { if (transport is IBlobCapableTransport blobTransport) { hasBlobTransport = true; blobTransport.SaveBlob(obj); } + } _stopwatch.Start(); if (!hasBlobTransport) + { throw new InvalidOperationException( "Object tree contains a Blob (file), but the serialiser has no blob saving capable transports." ); + } } // (propertyInfo, isDetachable, isChunkable, chunkSize, JsonPropertyAttribute) @@ -377,26 +450,35 @@ private void StoreBlob(Blob obj) IEnumerable typedProperties = baseObj.GetInstanceMembers(); if (TypedPropertiesCache.ContainsKey(type.FullName)) + { return TypedPropertiesCache[type.FullName]; + } List<(PropertyInfo, PropertyAttributeInfo)> ret = new(); foreach (PropertyInfo typedProperty in typedProperties) { if (typedProperty.Name.StartsWith("__") || typedProperty.Name == "id") + { continue; + } // Check JsonIgnore like this to cover both Newtonsoft JsonIgnore and System.Text.Json JsonIgnore // TODO: replace JsonIgnore from newtonsoft with JsonIgnore from Sys, and check this more properly. bool jsonIgnore = false; foreach (object attr in typedProperty.GetCustomAttributes(true)) + { if (attr.GetType().Name.Contains("JsonIgnore")) { jsonIgnore = true; break; } + } + if (jsonIgnore) + { continue; + } object baseValue = typedProperty.GetValue(baseObj); diff --git a/Core/Core/Serialisation/BaseObjectSerialzerUtilities.cs b/Core/Core/Serialisation/BaseObjectSerialzerUtilities.cs index 8372963eb8..a109277b60 100644 --- a/Core/Core/Serialisation/BaseObjectSerialzerUtilities.cs +++ b/Core/Core/Serialisation/BaseObjectSerialzerUtilities.cs @@ -31,12 +31,12 @@ internal static class SerializationUtilities ) { cancellationToken.ThrowIfCancellationRequested(); - + if (jsonProperty is { PropertyType: null }) - throw new ArgumentException( - $"Expected {nameof(JsonProperty.PropertyType)} to be non-null", - nameof(jsonProperty)); - + { + throw new ArgumentException($"Expected {nameof(JsonProperty.PropertyType)} to be non-null", nameof(jsonProperty)); + } + switch (value) { case JValue jValue when jsonProperty != null: @@ -56,37 +56,49 @@ internal static class SerializationUtilities cancellationToken.ThrowIfCancellationRequested(); if (val == null) + { continue; + } var item = HandleValue(val, serializer, cancellationToken); if (item is DataChunk chunk) { foreach (var dataItem in chunk.data) + { if (hasGenericType && !jsonProperty.PropertyType.GenericTypeArguments[0].IsInterface) { if (jsonProperty.PropertyType.GenericTypeArguments[0].IsAssignableFrom(dataItem.GetType())) + { addMethod.Invoke(arr, new[] { dataItem }); + } else + { addMethod.Invoke( arr, new[] { Convert.ChangeType(dataItem, jsonProperty.PropertyType.GenericTypeArguments[0]) } ); + } } else { addMethod.Invoke(arr, new[] { dataItem }); } + } } else if (hasGenericType && !jsonProperty.PropertyType.GenericTypeArguments[0].IsInterface) { if (jsonProperty.PropertyType.GenericTypeArguments[0].IsAssignableFrom(item.GetType())) + { addMethod.Invoke(arr, new[] { item }); + } else + { addMethod.Invoke( arr, new[] { Convert.ChangeType(item, jsonProperty.PropertyType.GenericTypeArguments[0]) } ); + } } else { @@ -97,30 +109,43 @@ internal static class SerializationUtilities } case JArray array when jsonProperty != null: { - var arr = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(jsonProperty.PropertyType.GetElementType())); + var arr = (IList) + Activator.CreateInstance(typeof(List<>).MakeGenericType(jsonProperty.PropertyType.GetElementType())); foreach (var val in array) { cancellationToken.ThrowIfCancellationRequested(); - + if (val == null) + { continue; + } var item = HandleValue(val, serializer, cancellationToken); if (item is DataChunk chunk) { foreach (var dataItem in chunk.data) + { if (!jsonProperty.PropertyType.GetElementType()!.IsInterface) + { arr.Add(Convert.ChangeType(dataItem, jsonProperty.PropertyType.GetElementType()!)); + } else + { arr.Add(dataItem); + } + } } else { if (!jsonProperty.PropertyType.GetElementType()!.IsInterface) + { arr.Add(Convert.ChangeType(item, jsonProperty.PropertyType.GetElementType()!)); + } else + { arr.Add(item); + } } } var actualArr = Array.CreateInstance(jsonProperty.PropertyType.GetElementType()!, arr.Count); @@ -135,14 +160,20 @@ internal static class SerializationUtilities cancellationToken.ThrowIfCancellationRequested(); if (val == null) + { continue; + } var item = HandleValue(val, serializer, cancellationToken); if (item is DataChunk chunk) + { arr.AddRange(chunk.data); + } else + { arr.Add(item); + } } return arr; } @@ -150,16 +181,20 @@ internal static class SerializationUtilities return jObject.ToObject(serializer); case JObject jObject: { - var dict = jsonProperty != null - ? Activator.CreateInstance(jsonProperty.PropertyType) as IDictionary - : new Dictionary(); + var dict = + jsonProperty != null + ? Activator.CreateInstance(jsonProperty.PropertyType) as IDictionary + : new Dictionary(); foreach (var prop in jObject) { cancellationToken.ThrowIfCancellationRequested(); object key = prop.Key; if (jsonProperty != null) + { key = Convert.ChangeType(prop.Key, jsonProperty.PropertyType.GetGenericArguments()[0]); + } + dict[key] = HandleValue(prop.Value, serializer, cancellationToken); } return dict; @@ -184,7 +219,9 @@ internal static Type GetType(string objFullType) lock (_cachedTypes) { if (_cachedTypes.TryGetValue(objFullType, out Type? type1)) + { return type1; + } var type = GetAtomicType(objFullType); _cachedTypes[objFullType] = type; @@ -201,7 +238,9 @@ internal static Type GetAtomicType(string objFullType) //we get it from a specific Kit var type = KitManager.Types.FirstOrDefault(tp => tp.FullName == typeName); if (type != null) + { return type; + } //To allow for backwards compatibility saving deserialization target types. //We also check a ".Deprecated" prefixed namespace @@ -209,7 +248,9 @@ internal static Type GetAtomicType(string objFullType) var deprecatedType = KitManager.Types.FirstOrDefault(tp => tp.FullName == deprecatedTypeName); if (deprecatedType != null) + { return deprecatedType; + } } return typeof(Base); @@ -231,7 +272,10 @@ internal static Dictionary GetTypePropeties(string objFull Type type = GetType(objFullType); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo prop in properties) + { ret[prop.Name.ToLower()] = prop; + } + TypeProperties[objFullType] = ret; } return TypeProperties[objFullType]; @@ -255,7 +299,9 @@ internal static List GetOnDeserializedCallbacks(string objFullType) .GetCustomAttributes(true) .ToList(); if (onDeserializedAttributes.Count > 0) + { ret.Add(method); + } } OnDeserializedCallbacks[objFullType] = ret; } @@ -267,7 +313,10 @@ internal static Type GetSytemOrSpeckleType(string typeName) { var systemType = Type.GetType(typeName); if (systemType != null) + { return systemType; + } + return GetAtomicType(typeName); } @@ -295,17 +344,23 @@ JsonSerializer serializer ) { if (CachedAbstractTypes.TryGetValue(assemblyQualifiedName, out Type? type)) + { return jToken.ToObject(type); + } var pieces = assemblyQualifiedName.Split(',').Select(s => s.Trim()).ToArray(); var myAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(ass => ass.GetName().Name == pieces[1]); if (myAssembly == null) + { throw new SpeckleException("Could not load abstract object's assembly."); + } var myType = myAssembly.GetType(pieces[0]); if (myType == null) + { throw new SpeckleException("Could not load abstract object's assembly."); + } CachedAbstractTypes[assemblyQualifiedName] = myType; @@ -333,6 +388,7 @@ public static void SetValue(string propertyName, object target, object? value) CallSite> site; lock (Setters) + { if (!Setters.TryGetValue(propertyName, out site)) { var binder = Binder.SetMember( @@ -347,6 +403,7 @@ public static void SetValue(string propertyName, object target, object? value) ); Setters[propertyName] = site = CallSite>.Create(binder); } + } site.Target.Invoke(site, target, value); } diff --git a/Core/Core/Serialisation/DeserializationWorkerThreads.cs b/Core/Core/Serialisation/DeserializationWorkerThreads.cs index 527b606504..24dc5ba814 100644 --- a/Core/Core/Serialisation/DeserializationWorkerThreads.cs +++ b/Core/Core/Serialisation/DeserializationWorkerThreads.cs @@ -27,7 +27,10 @@ public DeserializationWorkerThreads(BaseObjectDeserializerV2 serializer, int thr public override void Dispose() { lock (_lockFreeThreads) + { _freeThreadCount -= NumThreads; + } + base.Dispose(); } @@ -37,10 +40,15 @@ protected override void ThreadMain() while (true) { lock (_lockFreeThreads) + { _freeThreadCount++; + } + var (taskType, inputValue, tcs) = Tasks.Take(); if (taskType == WorkerThreadTaskType.NoOp || tcs == null) + { return; + } try { @@ -86,7 +94,9 @@ BaseObjectDeserializerV2 serializer } if (!canStartTask) + { return null; + } TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously); Tasks.Add(new(taskType, inputValue, tcs)); diff --git a/Core/Core/Serialisation/OperationTask.cs b/Core/Core/Serialisation/OperationTask.cs index 72678323dd..1076322146 100644 --- a/Core/Core/Serialisation/OperationTask.cs +++ b/Core/Core/Serialisation/OperationTask.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -7,7 +7,8 @@ namespace Speckle.Core.Serialisation; -internal readonly struct OperationTask where T : struct +internal readonly struct OperationTask + where T : struct { public readonly T OperationType; public readonly object? InputValue; @@ -28,7 +29,8 @@ public void Deconstruct(out T operationType, out object? inputValue, out TaskCom } } -internal abstract class ParallelOperationExecutor : IDisposable where TOperation : struct +internal abstract class ParallelOperationExecutor : IDisposable + where TOperation : struct { protected BlockingCollection> Tasks { get; set; } = new(); @@ -42,18 +44,30 @@ internal abstract class ParallelOperationExecutor : IDisposable wher protected virtual void Stop() { if (!HasStarted) + { throw new InvalidOperationException($"Unable to {nameof(Stop)} {this} as it has not started!"); + } + foreach (Thread _ in Threads) + { Tasks.Add(default); + } + foreach (Thread t in Threads) + { t.Join(); + } + Threads = new List(); } public virtual void Start() { if (HasStarted) + { throw new InvalidOperationException($"{this}: Threads already started"); + } + for (int i = 0; i < NumThreads; i++) { Thread t = new(ThreadMain) { Name = ToString(), IsBackground = true }; @@ -65,7 +79,10 @@ public virtual void Start() public virtual void Dispose() { if (HasStarted) + { Stop(); + } + Tasks.Dispose(); } } diff --git a/Core/Core/Serialisation/ValueConverter.cs b/Core/Core/Serialisation/ValueConverter.cs index 5b5f02ff7e..9cf225b202 100644 --- a/Core/Core/Serialisation/ValueConverter.cs +++ b/Core/Core/Serialisation/ValueConverter.cs @@ -18,7 +18,10 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV convertedValue = null; if (value == null) + { return true; + } + Type valueType = value.GetType(); if (type.IsAssignableFrom(valueType)) @@ -41,7 +44,10 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV if (type.IsEnum) { if (valueType != typeof(long)) + { return false; + } + convertedValue = Enum.ToObject(type, (long)value); return true; } @@ -159,14 +165,20 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { if (!isList) + { return false; + } + Type listElementType = type.GenericTypeArguments[0]; IList ret = Activator.CreateInstance(type, valueList.Count) as IList; foreach (object inputListElement in valueList) { object convertedListElement; if (!ConvertValue(listElementType, inputListElement, out convertedListElement)) + { return false; + } + ret.Add(convertedListElement); } convertedValue = ret; @@ -177,17 +189,25 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { if (value is not Dictionary valueDict) + { return false; + } if (type.GenericTypeArguments[0] != typeof(string)) + { throw new ArgumentException("Dictionaries with non-string keys are not supported", nameof(type)); + } + Type dictValueType = type.GenericTypeArguments[1]; IDictionary ret = Activator.CreateInstance(type) as IDictionary; foreach (KeyValuePair kv in valueDict) { if (!ConvertValue(dictValueType, kv.Value, out object convertedDictValue)) + { return false; + } + ret[kv.Key] = convertedDictValue; } convertedValue = ret; @@ -198,7 +218,10 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV if (type.IsArray) { if (!isList) + { return false; + } + Type arrayElementType = type.GetElementType() ?? throw new ArgumentException("IsArray yet not valid element type", nameof(type)); @@ -207,7 +230,10 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV { object inputListElement = valueList[i]; if (!ConvertValue(arrayElementType, inputListElement, out object convertedListElement)) + { return false; + } + ret.SetValue(convertedListElement, i); } convertedValue = ret; @@ -236,7 +262,10 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV #region BACKWARDS COMPATIBILITY: matrix4x4 changed from System.Numerics float to System.DoubleNumerics double in release 2.16 if (type == typeof(Numerics.Matrix4x4) && value is IReadOnlyList lMatrix) { - SpeckleLog.Logger.Warning("This kept for backwards compatibility, no one should be using {this}", "ValueConverter deserialize to System.Numerics.Matrix4x4"); + SpeckleLog.Logger.Warning( + "This kept for backwards compatibility, no one should be using {this}", + "ValueConverter deserialize to System.Numerics.Matrix4x4" + ); float I(int index) => Convert.ToSingle(lMatrix[index]); convertedValue = new Numerics.Matrix4x4( I(0), diff --git a/Core/Core/Transports/Exceptions.cs b/Core/Core/Transports/Exceptions.cs index 05058a2633..95087780e8 100644 --- a/Core/Core/Transports/Exceptions.cs +++ b/Core/Core/Transports/Exceptions.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; namespace Speckle.Core.Transports; @@ -15,7 +15,9 @@ public TransportException(ITransport? transport, string? message, Exception? inn public TransportException() { } - public TransportException(string message) : base(message) { } + public TransportException(string message) + : base(message) { } - public TransportException(string message, Exception innerException) : base(message, innerException) { } + public TransportException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/Core/Core/Transports/Memory.cs b/Core/Core/Transports/Memory.cs index 3ec05a72e9..44b5324ae3 100644 --- a/Core/Core/Transports/Memory.cs +++ b/Core/Core/Transports/Memory.cs @@ -14,7 +14,8 @@ public sealed class MemoryTransport : ITransport, ICloneable { public IDictionary Objects { get; } - public MemoryTransport() : this(new Dictionary()) { } + public MemoryTransport() + : this(new Dictionary()) { } public MemoryTransport(IDictionary objects) { @@ -60,7 +61,9 @@ public void SaveObject(string id, string serializedObject) { var stopwatch = Stopwatch.StartNew(); if (CancellationToken.IsCancellationRequested) + { return; // Check for cancellation + } Objects[id] = serializedObject; @@ -77,10 +80,12 @@ public void SaveObject(string id, ITransport sourceTransport) var serializedObject = sourceTransport.GetObject(id); if (serializedObject is null) + { throw new TransportException( this, $"Cannot copy {id} from {sourceTransport.TransportName} to {TransportName} as source returned null" ); + } SaveObject(id, serializedObject); } @@ -112,7 +117,9 @@ public async Task> HasObjects(IReadOnlyList obj { Dictionary ret = new(); foreach (string objectId in objectIds) + { ret[objectId] = Objects.ContainsKey(objectId); + } return ret; } diff --git a/Core/Core/Transports/SQLite.cs b/Core/Core/Transports/SQLite.cs index 4c216c0410..0c5c11076a 100644 --- a/Core/Core/Transports/SQLite.cs +++ b/Core/Core/Transports/SQLite.cs @@ -139,7 +139,9 @@ public async Task> HasObjects(IReadOnlyList obj Dictionary ret = new(objectIds.Count); // Initialize with false so that canceled queries still return a dictionary item for every object id foreach (string objectId in objectIds) + { ret[objectId] = false; + } using var c = new SqliteConnection(_connectionString); c.Open(); @@ -179,7 +181,9 @@ content TEXT ) WITHOUT ROWID; "; using (var command = new SqliteCommand(commandText, c)) + { command.ExecuteNonQuery(); + } // Insert Optimisations @@ -300,7 +304,9 @@ private void WriteTimerElapsed(object sender, ElapsedEventArgs e) } if (!_isWriting && !_queue.IsEmpty) + { ConsumeQueue(); + } } private void ConsumeQueue() @@ -341,7 +347,9 @@ private void ConsumeQueue() CancellationToken.ThrowIfCancellationRequested(); if (!_queue.IsEmpty) + { ConsumeQueue(); + } } catch (OperationCanceledException) { @@ -375,10 +383,12 @@ public void SaveObject(string id, ITransport sourceTransport) var serializedObject = sourceTransport.GetObject(id); if (serializedObject is null) + { throw new TransportException( this, $"Cannot copy {id} from {sourceTransport.TransportName} to {TransportName} as source returned null" ); + } //Should this just call SaveObject... do we not want the write timers? _queue.Enqueue((id, serializedObject, Encoding.UTF8.GetByteCount(serializedObject))); @@ -421,10 +431,12 @@ public void SaveObjectSync(string hash, string serializedObject) { command.Parameters.AddWithValue("@hash", id); using (var reader = command.ExecuteReader()) + { while (reader.Read()) { return reader.GetString(1); } + } } Elapsed += LoggingHelpers.GetElapsedTime(startTime, Stopwatch.GetTimestamp()); } diff --git a/Core/Core/Transports/Server.cs b/Core/Core/Transports/Server.cs index b990c46e2c..a6079796c5 100644 --- a/Core/Core/Transports/Server.cs +++ b/Core/Core/Transports/Server.cs @@ -102,7 +102,10 @@ public void Dispose() public void BeginWrite() { if (!GetWriteCompletionStatus()) + { throw new SpeckleException("Transport is still writing."); + } + TotalSentBytes = 0; SavedObjectCount = 0; } @@ -221,7 +224,9 @@ private void WriteTimerElapsed(object sender, ElapsedEventArgs e) while (_queue.TryPeek(out queueElement) && payloadBufferSize < MaxBufferSize) { if (CancellationToken.IsCancellationRequested) + { return (queuedBatch.Count, null); + } _queue.TryDequeue(out queueElement); queuedBatch.Add(queueElement); @@ -245,8 +250,12 @@ private void WriteTimerElapsed(object sender, ElapsedEventArgs e) List<(string, string, int)> newBatch = new(); foreach (var queuedItem in queuedBatch) + { if (!hasObjects.ContainsKey(queuedItem.Item1) || !hasObjects[queuedItem.Item1]) + { newBatch.Add(queuedItem); + } + } return (queuedBatch.Count, newBatch); } @@ -261,7 +270,9 @@ private async Task ConsumeQueue() } if (_queue.Count == 0) + { return; + } _isWriting = true; using var message = new HttpRequestMessage @@ -304,7 +315,10 @@ private async Task ConsumeQueue() for (int i = 0; i < batch.Count; i++) { if (i > 0) + { _ctBuilder.Append(","); + } + _ctBuilder.Append(batch[i].Item2); TotalSentBytes += batch[i].Item3; } @@ -336,6 +350,7 @@ private async Task ConsumeQueue() } if (addedMpCount > 0) + { try { var response = await Client.SendAsync(message, CancellationToken).ConfigureAwait(false); @@ -352,6 +367,7 @@ private async Task ConsumeQueue() _queue = new ConcurrentQueue<(string, string, int)>(); return; } + } _isWriting = false; @@ -463,7 +479,10 @@ Action onTotalChildrenCountKnown List childrenIds = new(); var rootPartial = JsonConvert.DeserializeObject(rootObjectStr); if (rootPartial.__closure != null) + { childrenIds = new List(rootPartial.__closure.Keys); + } + onTotalChildrenCountKnown?.Invoke(childrenIds.Count); var childrenFoundMap = await targetTransport.HasObjects(childrenIds).ConfigureAwait(false); @@ -481,7 +500,10 @@ Action onTotalChildrenCountKnown { downloadBatchResult = await CopyObjects(childrenIdBatch, targetTransport).ConfigureAwait(false); if (!downloadBatchResult) + { return null; + } + childrenIdBatch = new List(DownloadBatchSize); } } @@ -489,7 +511,9 @@ Action onTotalChildrenCountKnown { downloadBatchResult = await CopyObjects(childrenIdBatch, targetTransport).ConfigureAwait(false); if (!downloadBatchResult) + { return null; + } } targetTransport.SaveObject(id, rootObjectStr); @@ -573,8 +597,12 @@ public GzipContent(HttpContent content) // Keep the original content's headers ... if (content != null) + { foreach (KeyValuePair> header in content.Headers) + { Headers.TryAddWithoutValidation(header.Key, header.Value); + } + } // ... and let the server know we've Gzip-compressed the body of this request. Headers.ContentEncoding.Add("gzip"); @@ -585,9 +613,13 @@ protected override async Task SerializeToStreamAsync(Stream stream, TransportCon // Open a GZipStream that writes to the specified output stream. using GZipStream gzip = new(stream, CompressionMode.Compress, true); if (_content != null) + { await _content.CopyToAsync(gzip).ConfigureAwait(false); + } else + { await new StringContent(string.Empty).CopyToAsync(gzip).ConfigureAwait(false); + } } protected override bool TryComputeLength(out long length) diff --git a/Core/Core/Transports/ServerUtils/GzipContent.cs b/Core/Core/Transports/ServerUtils/GzipContent.cs index b06c39f1d7..bb78764484 100644 --- a/Core/Core/Transports/ServerUtils/GzipContent.cs +++ b/Core/Core/Transports/ServerUtils/GzipContent.cs @@ -23,7 +23,9 @@ public GzipContent(HttpContent? content) if (content is not null) { foreach (KeyValuePair> header in content.Headers) + { Headers.TryAddWithoutValidation(header.Key, header.Value); + } } // ... and let the server know we've Gzip-compressed the body of this request. @@ -36,7 +38,9 @@ protected override async Task SerializeToStreamAsync(Stream stream, TransportCon using GZipStream gzip = new(stream, CompressionMode.Compress, true); // Copy all the input content to the GZip stream. if (_content != null) + { await _content.CopyToAsync(gzip).ConfigureAwait(false); + } else { using var emptyContent = new StringContent(string.Empty); diff --git a/Core/Core/Transports/ServerUtils/ParallelServerAPI.cs b/Core/Core/Transports/ServerUtils/ParallelServerAPI.cs index 9e65b4e878..c4b5faab38 100644 --- a/Core/Core/Transports/ServerUtils/ParallelServerAPI.cs +++ b/Core/Core/Transports/ServerUtils/ParallelServerAPI.cs @@ -67,14 +67,21 @@ public async Task> HasObjects(string streamId, IReadOnl List> tasks = new(); IReadOnlyList> splitObjectsIds; if (objectIds.Count <= 50) + { splitObjectsIds = new List> { objectIds }; + } else + { splitObjectsIds = SplitList(objectIds, NumThreads); + } for (int i = 0; i < NumThreads; i++) { if (splitObjectsIds.Count <= i || splitObjectsIds[i].Count == 0) + { continue; + } + var op = QueueOperation(ServerApiOperation.HasObjects, (streamId, splitObjectsIds[i])); tasks.Add(op); } @@ -83,7 +90,9 @@ public async Task> HasObjects(string streamId, IReadOnl { Dictionary taskResult = await task.ConfigureAwait(false) as Dictionary; foreach (KeyValuePair kv in taskResult) + { ret[kv.Key] = kv.Value; + } } return ret; @@ -111,13 +120,18 @@ CbObjectDownloaded onObjectCallback CbObjectDownloaded callbackWrapper = (id, json) => { lock (callbackLock) + { onObjectCallback(id, json); + } }; for (int i = 0; i < NumThreads; i++) { if (splitObjectsIds[i].Count == 0) + { continue; + } + Task op = QueueOperation( ServerApiOperation.DownloadObjects, (streamId, splitObjectsIds[i], callbackWrapper) @@ -139,7 +153,9 @@ public async Task UploadObjects(string streamId, IReadOnlyList<(string, string)> { totalSize += json.Length; if (totalSize >= 500_000) + { break; + } } splitObjects = totalSize >= 500_000 ? SplitList(objects, NumThreads) : new List> { objects }; @@ -147,7 +163,10 @@ public async Task UploadObjects(string streamId, IReadOnlyList<(string, string)> for (int i = 0; i < NumThreads; i++) { if (splitObjects.Count <= i || splitObjects[i].Count == 0) + { continue; + } + var op = QueueOperation(ServerApiOperation.UploadObjects, (streamId, splitObjects[i])); tasks.Add(op); } @@ -182,7 +201,9 @@ public async Task> HasBlobs(string streamId, IReadOnlyList<(string, public void EnsureStarted() { if (Threads.Count == 0) + { Start(); + } } [SuppressMessage("Design", "CA1031:Do not catch general exception types")] @@ -193,7 +214,9 @@ protected override void ThreadMain() serialApi.OnBatchSent = (num, size) => { lock (_callbackLock) + { OnBatchSent(num, size); + } }; serialApi.CancellationToken = CancellationToken; serialApi.CompressPayloads = CompressPayloads; @@ -202,7 +225,9 @@ protected override void ThreadMain() { var (operation, inputValue, tcs) = Tasks.Take(); if (operation == ServerApiOperation.NoOp || tcs == null) + { return; + } try { @@ -263,9 +288,15 @@ private static List> SplitList(IReadOnlyList list, int parts) { List> ret = new(parts); for (int i = 0; i < parts; i++) + { ret.Add(new List(list.Count / parts + 1)); + } + for (int i = 0; i < list.Count; i++) + { ret[i % parts].Add(list[i]); + } + return ret; } } diff --git a/Core/Core/Transports/ServerUtils/ServerAPI.cs b/Core/Core/Transports/ServerUtils/ServerAPI.cs index 3a06de8d1d..5032928a5a 100644 --- a/Core/Core/Transports/ServerUtils/ServerAPI.cs +++ b/Core/Core/Transports/ServerUtils/ServerAPI.cs @@ -74,9 +74,12 @@ public async Task DownloadSingleObject(string streamId, string objectId) HttpResponseMessage rootHttpResponse = null; while (ShouldRetry(rootHttpResponse)) + { rootHttpResponse = await _client .SendAsync(rootHttpMessage, HttpCompletionOption.ResponseContentRead, CancellationToken) .ConfigureAwait(false); + } + rootHttpResponse.EnsureSuccessStatusCode(); string rootObjectStr = await rootHttpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -90,7 +93,10 @@ CbObjectDownloaded onObjectCallback ) { if (objectIds.Count == 0) + { return; + } + if (objectIds.Count < BatchSizeGetObjects) { await DownloadObjectsImpl(streamId, objectIds, onObjectCallback).ConfigureAwait(false); @@ -113,7 +119,9 @@ CbObjectDownloaded onObjectCallback public async Task> HasObjects(string streamId, IReadOnlyList objectIds) { if (objectIds.Count <= BatchSizeHasObjects) + { return await HasObjectsImpl(streamId, objectIds).ConfigureAwait(false); + } Dictionary ret = new(); List crtBatch = new(BatchSizeHasObjects); @@ -124,7 +132,10 @@ public async Task> HasObjects(string streamId, IReadOnl { Dictionary batchResult = await HasObjectsImpl(streamId, crtBatch).ConfigureAwait(false); foreach (KeyValuePair kv in batchResult) + { ret[kv.Key] = kv.Value; + } + crtBatch = new List(BatchSizeHasObjects); } } @@ -132,7 +143,9 @@ public async Task> HasObjects(string streamId, IReadOnl { Dictionary batchResult = await HasObjectsImpl(streamId, crtBatch).ConfigureAwait(false); foreach (KeyValuePair kv in batchResult) + { ret[kv.Key] = kv.Value; + } } return ret; } @@ -140,7 +153,9 @@ public async Task> HasObjects(string streamId, IReadOnl public async Task UploadObjects(string streamId, IReadOnlyList<(string, string)> objects) { if (objects.Count == 0) + { return; + } // 1. Split into parts of MAX_MULTIPART_SIZE size (can be exceptions until a max of MAX_OBJECT_SIZE if a single obj is larger than MAX_MULTIPART_SIZE) List> multipartedObjects = new(); @@ -153,10 +168,12 @@ public async Task UploadObjects(string streamId, IReadOnlyList<(string, string)> { int objSize = Encoding.UTF8.GetByteCount(json); if (objSize > MaxObjectSize) + { throw new ArgumentException( $"Object {id} too large (size {objSize}, max size {MaxObjectSize}). Consider using detached/chunked properties", nameof(objects) ); + } if (crtMultipartSize + objSize <= MaxMultipartSize) { @@ -209,7 +226,9 @@ public async Task UploadBlobs(string streamId, IReadOnlyList<(string, string)> o { CancellationToken.ThrowIfCancellationRequested(); if (objects.Count == 0) + { return; + } var multipartFormDataContent = new MultipartFormDataContent(); var streams = new List(); @@ -235,16 +254,23 @@ public async Task UploadBlobs(string streamId, IReadOnlyList<(string, string)> o { HttpResponseMessage response = null; while (ShouldRetry(response)) //TODO: can we get rid of this now we have polly? + { response = await _client.SendAsync(message, CancellationToken).ConfigureAwait(false); + } + response.EnsureSuccessStatusCode(); foreach (var stream in streams) + { stream.Dispose(); + } } finally { foreach (var stream in streams) + { stream.Dispose(); + } } } @@ -271,7 +297,9 @@ public async Task DownloadBlobs(string streamId, IReadOnlyList blobIds, $"{blobId.Substring(0, Blob.LocalHashPrefixLength)}-{fileName}" ); using (var fs = new FileStream(fileLocation, FileMode.OpenOrCreate)) + { await response.Content.CopyToAsync(fs).ConfigureAwait(false); + } response.Dispose(); onBlobCallback(); @@ -307,9 +335,12 @@ CbObjectDownloaded onObjectCallback HttpResponseMessage childrenHttpResponse = null; while (ShouldRetry(childrenHttpResponse)) + { childrenHttpResponse = await _client .SendAsync(childrenHttpMessage, HttpCompletionOption.ResponseHeadersRead, CancellationToken) .ConfigureAwait(false); + } + childrenHttpResponse.EnsureSuccessStatusCode(); Stream childrenStream = await childrenHttpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); @@ -342,7 +373,10 @@ private async Task> HasObjectsImpl(string streamId, IRe HttpResponseMessage response = null; using StringContent stringContent = new(serializedPayload, Encoding.UTF8, "application/json"); while (ShouldRetry(response)) + { response = await _client.PostAsync(uri, stringContent, CancellationToken).ConfigureAwait(false); + } + response.EnsureSuccessStatusCode(); var hasObjectsJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -350,7 +384,9 @@ private async Task> HasObjectsImpl(string streamId, IRe JObject doc = JObject.Parse(hasObjectsJson); foreach (KeyValuePair prop in doc) + { hasObjects[prop.Key] = (bool)prop!.Value!; + } // Console.WriteLine($"ServerApi::HasObjects({objectIds.Count}) request in {sw.ElapsedMilliseconds / 1000.0} sec"); @@ -380,7 +416,10 @@ private async Task UploadObjectsImpl(string streamId, List 0) + { ctBuilder.Append(','); + } + ctBuilder.Append(mpData[i].Item2); } ctBuilder.Append(']'); @@ -400,7 +439,10 @@ private async Task UploadObjectsImpl(string streamId, List> HasBlobs(string streamId, IReadOnlyList using StringContent stringContent = new(payload, Encoding.UTF8, "application/json"); //TODO: can we get rid of this now we have polly? while (ShouldRetry(response)) + { response = await _client.PostAsync(uri, stringContent, CancellationToken).ConfigureAwait(false); + } response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var parsed = JsonConvert.DeserializeObject>(responseString); if (parsed is null) + { throw new Exception($"Failed to deserialize successful response {response.Content}"); + } + return parsed; } @@ -432,11 +479,20 @@ public async Task> HasBlobs(string streamId, IReadOnlyList private bool ShouldRetry(HttpResponseMessage? serverResponse) { if (serverResponse == null) + { return true; + } + if (!_retryCodes.Contains((int)serverResponse.StatusCode)) + { return false; + } + if (RetriedCount >= RetryCount) + { return false; + } + RetriedCount += 1; return true; } diff --git a/Core/Core/Transports/ServerV2.cs b/Core/Core/Transports/ServerV2.cs index 7ee506b0ae..e1aee845d2 100644 --- a/Core/Core/Transports/ServerV2.cs +++ b/Core/Core/Transports/ServerV2.cs @@ -62,13 +62,19 @@ public ServerTransportV2(Account account, string streamId, int timeoutSeconds = public void SaveBlob(Blob obj) { if (string.IsNullOrEmpty(StreamId)) + { throw new InvalidOperationException($"Invalid StreamID {StreamId}"); + } + var hash = obj.GetFileHash(); lock (_sendBufferLock) { if (IsInErrorState) + { return; + } + _sendBuffer.Add(($"blob:{hash}", obj.filePath)); } } @@ -118,7 +124,9 @@ public async Task CopyObjectAndChildren( ) { if (string.IsNullOrEmpty(StreamId) || string.IsNullOrEmpty(id) || targetTransport == null) + { throw new InvalidOperationException("Invalid parameters to CopyObjectAndChildren"); + } CancellationToken.ThrowIfCancellationRequested(); @@ -208,18 +216,27 @@ public string GetObject(string id) public async Task> HasObjects(IReadOnlyList objectIds) { if (string.IsNullOrEmpty(StreamId)) + { throw new InvalidOperationException($"Invalid StreamID {StreamId}"); + } + return await Api.HasObjects(StreamId, objectIds).ConfigureAwait(false); } public void SaveObject(string id, string serializedObject) { if (string.IsNullOrEmpty(StreamId)) + { throw new InvalidOperationException($"Invalid StreamID {StreamId}"); + } + lock (_sendBufferLock) { if (IsInErrorState) + { return; + } + _sendBuffer.Add((id, serializedObject)); _isWriteComplete = false; } @@ -228,15 +245,19 @@ public void SaveObject(string id, string serializedObject) public void SaveObject(string id, ITransport sourceTransport) { if (string.IsNullOrEmpty(StreamId)) + { throw new InvalidOperationException($"Invalid StreamID {StreamId}"); + } var objectData = sourceTransport.GetObject(id); if (objectData is null) + { throw new TransportException( this, $"Cannot copy {id} from {sourceTransport.TransportName} to {TransportName} as source returned null" ); + } SaveObject(id, objectData); } @@ -244,7 +265,10 @@ public void SaveObject(string id, ITransport sourceTransport) public void BeginWrite() { if (_shouldSendThreadRun || _sendingThread != null) + { throw new InvalidOperationException("ServerTransport already sending"); + } + TotalSentBytes = 0; SavedObjectCount = 0; @@ -259,15 +283,19 @@ public async Task WriteComplete() while (true) { lock (_sendBufferLock) + { if (_isWriteComplete || IsInErrorState) { CancellationToken.ThrowIfCancellationRequested(); if (_exception is not null) + { throw new TransportException(this, $"{TransportName} transport failed", _exception); + } return; } + } await Task.Delay(50).ConfigureAwait(false); } @@ -276,7 +304,10 @@ public async Task WriteComplete() public void EndWrite() { if (!_shouldSendThreadRun || _sendingThread == null) + { throw new InvalidOperationException("ServerTransport not sending"); + } + _shouldSendThreadRun = false; _sendingThread.Join(); _sendingThread = null; @@ -312,7 +343,9 @@ private static List ParseChildrenIds(string json) { JObject doc1 = JObject.Parse(json); foreach (JToken prop in doc1["__closure"]) + { childrenIds.Add(((JProperty)prop).Name); + } } catch (Exception) { @@ -328,9 +361,13 @@ private async void SendingThreadMain() { var stopwatch = Stopwatch.StartNew(); if (!_shouldSendThreadRun || CancellationToken.IsCancellationRequested) + { return; + } + List<(string id, string data)>? buffer = null; lock (_sendBufferLock) + { if (_sendBuffer.Count > 0) { buffer = _sendBuffer; @@ -340,6 +377,7 @@ private async void SendingThreadMain() { _isWriteComplete = true; } + } if (buffer is null) { @@ -354,14 +392,22 @@ private async void SendingThreadMain() List objectIds = new(bufferObjects.Count); foreach ((string id, _) in bufferObjects) + { if (id != "blob") + { objectIds.Add(id); + } + } Dictionary hasObjects = await Api.HasObjects(StreamId, objectIds).ConfigureAwait(false); List<(string, string)> newObjects = new(); foreach ((string id, object json) in bufferObjects) + { if (!hasObjects[id]) + { newObjects.Add((id, (string)json)); + } + } // Report the objects that are already on the server OnProgressAction?.Invoke(TransportName, hasObjects.Count - newObjects.Count); @@ -374,7 +420,9 @@ private async void SendingThreadMain() var formattedIds = blobIdsToUpload.Select(id => $"blob:{id}").ToList(); var newBlobs = bufferBlobs.Where(tuple => formattedIds.IndexOf(tuple.Item1) != -1).ToList(); if (newBlobs.Count != 0) + { await Api.UploadBlobs(StreamId, newBlobs).ConfigureAwait(false); + } } } catch (Exception ex) @@ -390,7 +438,9 @@ private async void SendingThreadMain() { stopwatch.Stop(); lock (_elapsedLock) + { Elapsed += stopwatch.Elapsed; + } } } } diff --git a/Core/Core/Transports/Utilities.cs b/Core/Core/Transports/Utilities.cs index f2df7d230c..b9d30bd8bc 100644 --- a/Core/Core/Transports/Utilities.cs +++ b/Core/Core/Transports/Utilities.cs @@ -19,10 +19,14 @@ public static async Task WaitUntil(Func condition, int frequency = 25, int var waitTask = Task.Run(async () => { while (!condition()) + { await Task.Delay(frequency).ConfigureAwait(false); + } }); if (waitTask != await Task.WhenAny(waitTask, Task.Delay(timeout)).ConfigureAwait(false)) + { throw new SpeckleException("Process timed out", new TimeoutException()); + } } } diff --git a/Core/IntegrationTests/Api.cs b/Core/IntegrationTests/Api.cs index 72d17798f3..16915ec873 100644 --- a/Core/IntegrationTests/Api.cs +++ b/Core/IntegrationTests/Api.cs @@ -330,7 +330,9 @@ public async Task CommitCreate() var myObject = new Base(); var ptsList = new List(); for (int i = 0; i < 100; i++) + { ptsList.Add(new Point(i, i, i)); + } myObject["@Points"] = ptsList; diff --git a/Core/IntegrationTests/Subscriptions/Commits.cs b/Core/IntegrationTests/Subscriptions/Commits.cs index 8e96041e15..07008ad4cb 100644 --- a/Core/IntegrationTests/Subscriptions/Commits.cs +++ b/Core/IntegrationTests/Subscriptions/Commits.cs @@ -58,7 +58,9 @@ public async Task SubscribeCommitCreated() var myObject = new Base(); var ptsList = new List(); for (int i = 0; i < 100; i++) + { ptsList.Add(new Point(i, i, i)); + } myObject["Points"] = ptsList; diff --git a/Core/Tests/BaseExtensionsTests.cs b/Core/Tests/BaseExtensionsTests.cs index d6a37929ac..6823c362ef 100644 --- a/Core/Tests/BaseExtensionsTests.cs +++ b/Core/Tests/BaseExtensionsTests.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; using Speckle.Core.Models; using Speckle.Core.Models.Extensions; @@ -7,19 +7,18 @@ namespace TestsUnit; [TestFixture, TestOf(nameof(BaseExtensions))] public class BaseExtensionsTests { - [Test] [TestCase("myDynamicProp")] [TestCase("elements")] public void GetDetachedPropName_Dynamic(string propertyName) { var data = new TestBase(); - + var result = data.GetDetachedPropName(propertyName); var expected = $"@{propertyName}"; Assert.That(result, Is.EqualTo(expected)); } - + [Test] [TestCase(nameof(TestBase.myProperty))] [TestCase(nameof(TestBase.myOtherProperty))] @@ -36,5 +35,4 @@ public class TestBase : Base public string myProperty { get; set; } public string myOtherProperty { get; set; } } - } diff --git a/Core/Tests/ClosureTests.cs b/Core/Tests/ClosureTests.cs index 905d0a0a05..5db79ae825 100644 --- a/Core/Tests/ClosureTests.cs +++ b/Core/Tests/ClosureTests.cs @@ -80,7 +80,10 @@ public void DescendantsCounting() // Primitives should not be counted! for (int i = 0; i < 10; i++) + { myList.Add(i); + } + myList.Add("Hello"); myList.Add(new { hai = "bai" }); diff --git a/Core/Tests/GraphQLClient.cs b/Core/Tests/GraphQLClient.cs index 2194ce21a1..c044ab0d18 100644 --- a/Core/Tests/GraphQLClient.cs +++ b/Core/Tests/GraphQLClient.cs @@ -108,7 +108,10 @@ public async Task TestExecuteWithResiliencePoliciesRetry() { counter++; if (counter < maxRetryCount) + { throw new SpeckleGraphQLInternalErrorException(new GraphQLRequest(), new GraphQLResponse()); + } + return expectedResult; }) .ConfigureAwait(false); diff --git a/Core/Tests/Hashing.cs b/Core/Tests/Hashing.cs index 53567cea1e..0b8abfed5f 100644 --- a/Core/Tests/Hashing.cs +++ b/Core/Tests/Hashing.cs @@ -38,7 +38,9 @@ public void HashingPerformance() var polyline = new Polyline(); for (int i = 0; i < 1000; i++) + { polyline.Points.Add(new Point { X = i * 2, Y = i % 2 }); + } var stopWatch = new Stopwatch(); stopWatch.Start(); diff --git a/Core/Tests/Models/ObjectModelDeprecationTests.cs b/Core/Tests/Models/ObjectModelDeprecationTests.cs index 8023794d48..c7b72c2b33 100644 --- a/Core/Tests/Models/ObjectModelDeprecationTests.cs +++ b/Core/Tests/Models/ObjectModelDeprecationTests.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; using Speckle.Core.Models; using Speckle.Core.Serialisation; using Speckle.Core.Serialisation.Deprecated; diff --git a/Core/Tests/Models/SerializerBreakingChanges.cs b/Core/Tests/Models/SerializerBreakingChanges.cs index 893661a923..531e3e499e 100644 --- a/Core/Tests/Models/SerializerBreakingChanges.cs +++ b/Core/Tests/Models/SerializerBreakingChanges.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; namespace TestsUnit.Models; diff --git a/Core/Tests/Models/SerializerNonBreakingChanges.cs b/Core/Tests/Models/SerializerNonBreakingChanges.cs index 606f6f16f4..08d2919d68 100644 --- a/Core/Tests/Models/SerializerNonBreakingChanges.cs +++ b/Core/Tests/Models/SerializerNonBreakingChanges.cs @@ -235,13 +235,15 @@ protected SerializerMock() public override string speckle_type => _speckle_type; - public void SerializeAs() where T : Base, new() + public void SerializeAs() + where T : Base, new() { T target = new(); _speckle_type = target.speckle_type; } - internal TTo SerializeAsTAndDeserialize() where TTo : Base, new() + internal TTo SerializeAsTAndDeserialize() + where TTo : Base, new() { SerializeAs(); diff --git a/Core/Tests/Models/TraversalTests.cs b/Core/Tests/Models/TraversalTests.cs index d2855fdca4..ee84ca8fce 100644 --- a/Core/Tests/Models/TraversalTests.cs +++ b/Core/Tests/Models/TraversalTests.cs @@ -54,7 +54,6 @@ public void TestBreakerFixed(int nestDepth, int flattenDepth) //Flatten int counter = 0; var ret = rootObject.Flatten(_ => ++counter >= flattenDepth).ToList(); - //Test Assert.That(ret, Has.Count.EqualTo(Math.Min(flattenDepth, nestDepth))); @@ -94,7 +93,6 @@ public void TestDuplicates() //Flatten var ret = objectA.Flatten().ToList(); - //Test Assert.That(ret, Is.Unique); diff --git a/Core/Tests/Path.cs b/Core/Tests/Path.cs index 7bfb16556e..9e7b11b9db 100644 --- a/Core/Tests/Path.cs +++ b/Core/Tests/Path.cs @@ -16,7 +16,10 @@ public void TestUserApplicationDataPath() string pattern; if (string.IsNullOrEmpty(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData))) + { pattern = @"\/root"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { pattern = @"C:\\Users\\.*\\AppData\\Roaming"; @@ -29,9 +32,13 @@ public void TestUserApplicationDataPath() { // if running under root user, the .config folder is in another location... if (userPath.StartsWith("/root")) + { pattern = @"\/root/\.config"; + } else + { pattern = @"\/home/.*/\.config"; + } } else { @@ -74,9 +81,13 @@ public void TestInstallApplicationDataPath() { // if running under root user, the .config folder is in another location... if (installPath.StartsWith("/root")) + { pattern = @"\/root/\.config"; + } else + { pattern = @"\/home/.*/\.config"; + } } else { diff --git a/Core/Tests/SendReceiveLocal.cs b/Core/Tests/SendReceiveLocal.cs index 94316b3dca..5fe5395e89 100644 --- a/Core/Tests/SendReceiveLocal.cs +++ b/Core/Tests/SendReceiveLocal.cs @@ -23,7 +23,9 @@ public void LocalUpload() myObject["@items"] = new List(); for (int i = 0; i < numObjects; i++) + { ((List)myObject["@items"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "-___/---" }); + } objId_01 = Operations.Send(myObject).Result; @@ -49,7 +51,9 @@ public void LocalUploadDownload() var rand = new Random(); for (int i = 0; i < numObjects; i++) + { ((List)myObject["@items"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "-___/---" }); + } objId_01 = Operations.Send(myObject).Result; @@ -68,7 +72,9 @@ public async Task LocalUploadDownloadSmall() var rand = new Random(); for (int i = 0; i < 30; i++) + { ((List)myObject["@items"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "-ugh/---" }); + } objId_01 = await Operations.Send(myObject).ConfigureAwait(false); @@ -83,7 +89,12 @@ public async Task LocalUploadDownloadSmall() public async Task LocalUploadDownloadListDic() { var myList = new List { 1, 2, 3, "ciao" }; - var myDic = new Dictionary { { "a", myList }, { "b", 2 }, { "c", "ciao" } }; + var myDic = new Dictionary + { + { "a", myList }, + { "b", 2 }, + { "c", "ciao" } + }; var myObject = new Base(); myObject["@dictionary"] = myDic; @@ -110,13 +121,19 @@ public async Task UploadDownloadNonCommitObject() var rand = new Random(); for (int i = 0; i < 30; i++) + { ((List)((dynamic)obj).LayerA).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "foo" }); + } for (int i = 0; i < 30; i++) + { ((List)((dynamic)obj).LayerB).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "bar" }); + } for (int i = 0; i < 30; i++) + { ((List)((dynamic)obj)["@LayerC"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "baz" }); + } objId_01 = await Operations.Send(obj).ConfigureAwait(false); @@ -150,7 +167,9 @@ public async Task UploadProgressReports() var rand = new Random(); for (int i = 0; i < 30; i++) + { ((List)myObject["items"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "-fab/---" }); + } ConcurrentDictionary progress = null; commitId_02 = await Operations diff --git a/Core/Tests/SerializationTests.cs b/Core/Tests/SerializationTests.cs index 23053ff215..f421823b42 100644 --- a/Core/Tests/SerializationTests.cs +++ b/Core/Tests/SerializationTests.cs @@ -21,7 +21,9 @@ public void SimpleSerialization() var polyline = new Polyline(); for (int i = 0; i < 100; i++) + { polyline.Points.Add(new Point { X = i * 2, Y = i % 2 }); + } var strPoly = Operations.Serialize(polyline); var dePoly = Operations.Deserialize(strPoly); @@ -35,7 +37,9 @@ public void DictionarySerialisation() // TODO var dict = new Dictionary(); for (int i = 0; i < 10; i++) + { dict[$"key{i}"] = new Point(i, i, i); + } var result = Operations.Serialize(dict); var test = Operations.DeserializeDictionary(result); @@ -120,7 +124,9 @@ public void ListDynamicProp() var test = new List(); for (var i = 0; i < 100; i++) + { test.Add(new SuperPoint { W = i }); + } point["test"] = test; @@ -136,15 +142,21 @@ public void ChunkSerialisation() { var baseBasedChunk = new DataChunk(); for (var i = 0; i < 200; i++) + { baseBasedChunk.data.Add(new SuperPoint { W = i }); + } var stringBasedChunk = new DataChunk(); for (var i = 0; i < 200; i++) + { stringBasedChunk.data.Add(i + "_hai"); + } var doubleBasedChunk = new DataChunk(); for (var i = 0; i < 200; i++) + { doubleBasedChunk.data.Add(i + 0.33); + } var baseChunkString = Operations.Serialize(baseBasedChunk); var stringChunkString = Operations.Serialize(stringBasedChunk); diff --git a/Core/Tests/TestKit.cs b/Core/Tests/TestKit.cs index 6a3d33688e..c733da3d97 100644 --- a/Core/Tests/TestKit.cs +++ b/Core/Tests/TestKit.cs @@ -160,7 +160,9 @@ public List Vertices set { for (int i = 0; i < value.Count; i += 3) + { Points.Add(new Point(value[i], value[i + 1], value[i + 2])); + } } } } @@ -184,7 +186,9 @@ public List Vertices set { for (int i = 0; i < value.Count; i += 3) + { Points.Add(new Point(value[i], value[i + 1], value[i + 2])); + } } } } diff --git a/Core/Tests/Transports/DiskTransportTests.cs b/Core/Tests/Transports/DiskTransportTests.cs index ccb02ce9b9..f0be3af714 100644 --- a/Core/Tests/Transports/DiskTransportTests.cs +++ b/Core/Tests/Transports/DiskTransportTests.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; using Speckle.Core.Transports; namespace TestsUnit.Transports; diff --git a/Core/Tests/Transports/MemoryTransportTests.cs b/Core/Tests/Transports/MemoryTransportTests.cs index 822d1779d9..5fd8e65d50 100644 --- a/Core/Tests/Transports/MemoryTransportTests.cs +++ b/Core/Tests/Transports/MemoryTransportTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using NUnit.Framework; using Speckle.Core.Transports; diff --git a/Core/Tests/Transports/SQLiteTransportTests.cs b/Core/Tests/Transports/SQLiteTransportTests.cs index 681e57bbe2..724d8c6709 100644 --- a/Core/Tests/Transports/SQLiteTransportTests.cs +++ b/Core/Tests/Transports/SQLiteTransportTests.cs @@ -1,4 +1,4 @@ -using Microsoft.Data.Sqlite; +using Microsoft.Data.Sqlite; using NUnit.Framework; using Speckle.Core.Transports; diff --git a/Core/Tests/Transports/TransportTests.cs b/Core/Tests/Transports/TransportTests.cs index 8d453d8530..d5c33494f2 100644 --- a/Core/Tests/Transports/TransportTests.cs +++ b/Core/Tests/Transports/TransportTests.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using NUnit.Framework; using Speckle.Core.Transports; diff --git a/Core/TestsPerformance/Api/Operations/ReceiveFromSQLite.cs b/Core/TestsPerformance/Api/Operations/ReceiveFromSQLite.cs index a65ecd7e58..32d5e4b3c9 100644 --- a/Core/TestsPerformance/Api/Operations/ReceiveFromSQLite.cs +++ b/Core/TestsPerformance/Api/Operations/ReceiveFromSQLite.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using BenchmarkDotNet.Attributes; using Speckle.Core.Models; diff --git a/Core/TestsPerformance/Api/Operations/TraverseCommit.cs b/Core/TestsPerformance/Api/Operations/TraverseCommit.cs index d7bf251d66..4d9caa14bf 100644 --- a/Core/TestsPerformance/Api/Operations/TraverseCommit.cs +++ b/Core/TestsPerformance/Api/Operations/TraverseCommit.cs @@ -1,11 +1,11 @@ -using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; namespace TestsPerformance.Api.Operations; [MemoryDiagnoser] -[RegressionTestConfig(1, 1, 20, nugetVersions:"2.15.2")] +[RegressionTestConfig(1, 1, 20, nugetVersions: "2.15.2")] public class TraverseCommit { [Params(0, 4, 9, 19)] diff --git a/Core/TestsPerformance/Program.cs b/Core/TestsPerformance/Program.cs index 71913a106f..639e00aed6 100644 --- a/Core/TestsPerformance/Program.cs +++ b/Core/TestsPerformance/Program.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Running; +using BenchmarkDotNet.Running; namespace TestsPerformance; diff --git a/Core/TestsPerformance/RegressionTestConfig.cs b/Core/TestsPerformance/RegressionTestConfig.cs index 06e02982a8..ae007fbdea 100644 --- a/Core/TestsPerformance/RegressionTestConfig.cs +++ b/Core/TestsPerformance/RegressionTestConfig.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Configs; using BenchmarkDotNet.Engines; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; diff --git a/Core/TestsPerformance/Serialisation/DeserializationWorkerThreads.cs b/Core/TestsPerformance/Serialisation/DeserializationWorkerThreads.cs index 931a6e243e..06ac7c7ba4 100644 --- a/Core/TestsPerformance/Serialisation/DeserializationWorkerThreads.cs +++ b/Core/TestsPerformance/Serialisation/DeserializationWorkerThreads.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; using Speckle.Core.Models; using Speckle.Core.Serialisation; using Speckle.Core.Transports; diff --git a/Core/TestsPerformance/TestDataHelper.cs b/Core/TestsPerformance/TestDataHelper.cs index 44a99b68f8..4a23f5aeea 100644 --- a/Core/TestsPerformance/TestDataHelper.cs +++ b/Core/TestsPerformance/TestDataHelper.cs @@ -1,4 +1,4 @@ -using System.Reactive; +using System.Reactive; using Microsoft.Data.Sqlite; using Speckle.Core.Api; using Speckle.Core.Credentials; diff --git a/Core/Transports/DiskTransport/DiskTransport.cs b/Core/Transports/DiskTransport/DiskTransport.cs index f203abd805..11cc8f191d 100644 --- a/Core/Transports/DiskTransport/DiskTransport.cs +++ b/Core/Transports/DiskTransport/DiskTransport.cs @@ -19,7 +19,9 @@ public class DiskTransport : ICloneable, ITransport public DiskTransport(string? basePath = null) { if (basePath == null) + { basePath = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "DiskTransportFiles"); + } RootPath = Path.Combine(basePath); @@ -43,7 +45,12 @@ public object Clone() public string TransportName { get; set; } = "Disk"; public Dictionary TransportContext => - new() { { "name", TransportName }, { "type", GetType().Name }, { "basePath", RootPath } }; + new() + { + { "name", TransportName }, + { "type", GetType().Name }, + { "basePath", RootPath } + }; public CancellationToken CancellationToken { get; set; } @@ -68,7 +75,9 @@ public void EndWrite() { } var filePath = Path.Combine(RootPath, id); if (File.Exists(filePath)) + { return File.ReadAllText(filePath, Encoding.UTF8); + } return null; } @@ -80,7 +89,9 @@ public void SaveObject(string id, string serializedObject) var filePath = Path.Combine(RootPath, id); if (File.Exists(filePath)) + { return; + } File.WriteAllText(filePath, serializedObject, Encoding.UTF8); SavedObjectCount++; @@ -96,10 +107,12 @@ public void SaveObject(string id, ITransport sourceTransport) var serializedObject = sourceTransport.GetObject(id); if (serializedObject is null) + { throw new TransportException( this, $"Cannot copy {id} from {sourceTransport.TransportName} to {TransportName} as source returned null" ); + } SaveObject(id, serializedObject); } @@ -116,14 +129,18 @@ public async Task CopyObjectAndChildren( var parent = GetObject(id); if (parent is null) + { throw new InvalidOperationException($"Requested id {id} was not found within this transport {TransportName}"); + } targetTransport.SaveObject(id, parent); var partial = JsonConvert.DeserializeObject(parent); if (partial?.__closure is null || partial.__closure.Count == 0) + { return parent; + } int i = 0; foreach (var kvp in partial.__closure) @@ -132,9 +149,11 @@ public async Task CopyObjectAndChildren( var child = GetObject(kvp.Key); if (child is null) + { throw new InvalidOperationException( $"Closure id {kvp.Key} was not found within this transport {TransportName}" ); + } targetTransport.SaveObject(kvp.Key, child); OnProgressAction?.Invoke($"{TransportName}", i++); diff --git a/Core/Transports/MongoDBTransport/MongoDB.cs b/Core/Transports/MongoDBTransport/MongoDB.cs index feb7f4caf2..b4281e26f7 100644 --- a/Core/Transports/MongoDBTransport/MongoDB.cs +++ b/Core/Transports/MongoDBTransport/MongoDB.cs @@ -107,7 +107,9 @@ private void Initialize() // Check if the connection is successful bool isMongoLive = Database.RunCommandAsync((Command)"{ping:1}").Wait(1000); if (!isMongoLive) + { OnErrorAction(TransportName, new Exception("The Mongo database could not be reached.")); + } } /// @@ -119,7 +121,10 @@ internal IEnumerable GetAllObjects() var documents = Collection.Find(new BsonDocument()).ToList(); List documentContents = new(); foreach (BsonDocument document in documents) + { documentContents.Add(document[Field.content.ToString()].AsString); + } + return documentContents; } @@ -171,7 +176,9 @@ private void WriteTimerElapsed(object sender, ElapsedEventArgs e) { WriteTimer.Enabled = false; if (!IS_WRITING && Queue.Count != 0) + { ConsumeQueue(); + } } private void ConsumeQueue() @@ -192,7 +199,9 @@ private void ConsumeQueue() } if (Queue.Count > 0) + { ConsumeQueue(); + } IS_WRITING = false; } @@ -241,7 +250,9 @@ public string GetObject(string hash) var filter = Builders.Filter.Eq(Field.hash.ToString(), hash); BsonDocument objectDocument = Collection.Find(filter).FirstOrDefault(); if (objectDocument != null) + { return objectDocument[Field.content.ToString()].AsString; + } // pass on the duty of null checks to consumers return null; diff --git a/DesktopUI2/AvaloniaHwndHost/AvaloniaHwndHost.cs b/DesktopUI2/AvaloniaHwndHost/AvaloniaHwndHost.cs index 58d367e1c6..f4b7424c40 100644 --- a/DesktopUI2/AvaloniaHwndHost/AvaloniaHwndHost.cs +++ b/DesktopUI2/AvaloniaHwndHost/AvaloniaHwndHost.cs @@ -25,7 +25,10 @@ private EmbeddableControlRoot root get { if (_root == null || _root.Renderer == null) + { _root = new EmbeddableControlRoot(); // TODO: this crashes rhino periodically! + } + return _root; } } @@ -37,14 +40,18 @@ public Control Content { root.Content = value; if (value != null) + { value.DataContext = DataContext; + } } } private void AvaloniaHwndHost_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { if (Content != null) + { Content.DataContext = e.NewValue; + } } protected override HandleRef BuildWindowCore(HandleRef hwndParent) @@ -59,8 +66,10 @@ protected override HandleRef BuildWindowCore(HandleRef hwndParent) _ = UnmanagedMethods.SetParent(handle, hwndParent.Handle); if (IsFocused) + { // Focus Avalonia, if host was focused before handle was created. FocusManager.Instance.Focus(null); + } return new HandleRef(root, handle); } diff --git a/DesktopUI2/DesktopUI2/App.xaml.cs b/DesktopUI2/DesktopUI2/App.xaml.cs index 1431188dc9..5407637de7 100644 --- a/DesktopUI2/DesktopUI2/App.xaml.cs +++ b/DesktopUI2/DesktopUI2/App.xaml.cs @@ -38,11 +38,13 @@ public override void OnFrameworkInitializationCompleted() themeBootstrap.CurrentTheme = theme; if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { //desktop.MainWindow = new MappingsWindow //{ // DataContext = new MappingsViewModel(), //}; desktop.MainWindow = new MainWindow { DataContext = new MainViewModel() }; + } //desktop.MainWindow = new Scheduler //{ // DataContext = new SchedulerViewModel(), diff --git a/DesktopUI2/DesktopUI2/ConnectorHelpers.cs b/DesktopUI2/DesktopUI2/ConnectorHelpers.cs index 2b811cb24d..b9e85d9878 100644 --- a/DesktopUI2/DesktopUI2/ConnectorHelpers.cs +++ b/DesktopUI2/DesktopUI2/ConnectorHelpers.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Linq; using System.Threading; @@ -50,7 +50,9 @@ public static async Task ReceiveCommit(Commit commit, StreamState state, P { //Don't wrap cancellation exceptions! if (ex is OperationCanceledException) + { throw ex; + } //HACK: Sometimes, the task was cancelled, and Operations.Receive doesn't fail in a reliable way. In this case, the exception is often simply a symptom of a cancel. if (progress.CancellationToken.IsCancellationRequested) @@ -68,9 +70,11 @@ public static async Task ReceiveCommit(Commit commit, StreamState state, P .ConfigureAwait(false); if (commitObject == null) + { throw new SpeckleException( $"Failed to receive commit: {commit.id} objects from server: {nameof(Operations.Receive)} returned null" ); + } return commitObject; } @@ -193,7 +197,9 @@ public static void DefaultSendErrorHandler(string error, Exception ex) { //Don't wrap cancellation exceptions! if (ex is OperationCanceledException cex) + { throw cex; + } //Treat all operation errors as fatal throw new SpeckleException($"Failed to send objects to server - {error}", ex); @@ -217,7 +223,9 @@ public static void LogConversionException(Exception ex) public static ApplicationObject.State GetAppObjectFailureState(Exception ex) { if (ex is null) + { throw new ArgumentNullException(nameof(ex)); + } return ex switch { diff --git a/DesktopUI2/DesktopUI2/DummyBindings.cs b/DesktopUI2/DesktopUI2/DummyBindings.cs index 0aab2c138c..d818645212 100644 --- a/DesktopUI2/DesktopUI2/DummyBindings.cs +++ b/DesktopUI2/DesktopUI2/DummyBindings.cs @@ -97,7 +97,9 @@ public override List GetSelectedObjects() var nums = rnd.Next(1000); var strs = new List(); for (int i = 0; i < nums; i++) + { strs.Add($"Object-{i}"); + } return strs; } @@ -334,7 +336,9 @@ public override List GetStreamsInFile() #endregion foreach (var stream in testStreams) + { collection.Add(new StreamState(AccountManager.GetDefaultAccount(), stream)); + } collection[0].SelectedObjectIds.Add("random_obj"); @@ -357,7 +361,9 @@ public override async Task PreviewReceive(StreamState state, Progre for (int i = 1; i < 100; i += 10) { if (progress.CancellationToken.IsCancellationRequested) + { return state; + } await Task.Delay(TimeSpan.FromMilliseconds(rnd.Next(200, 1000))).ConfigureAwait(true); pd["A1"] = i; @@ -368,9 +374,13 @@ public override async Task PreviewReceive(StreamState state, Progre try { if (i % 7 == 0) + { appObj.Update(status: ApplicationObject.State.Failed, logItem: "Something happened."); + } else + { appObj.Update(status: ApplicationObject.State.Created); + } } catch (Exception e) { @@ -382,6 +392,7 @@ public override async Task PreviewReceive(StreamState state, Progre // Mock some errors for (int i = 0; i < 10; i++) + { try { throw new Exception($"Number {i} fail"); @@ -390,6 +401,7 @@ public override async Task PreviewReceive(StreamState state, Progre { progress.Report.LogOperationError(e); } + } return state; } @@ -405,7 +417,9 @@ public override async Task ReceiveStream(StreamState state, Progres for (int i = 1; i < 100; i += 10) { if (progress.CancellationToken.IsCancellationRequested) + { return state; + } await Task.Delay(TimeSpan.FromMilliseconds(rnd.Next(200, 1000))).ConfigureAwait(true); pd["A1"] = i; @@ -416,9 +430,13 @@ public override async Task ReceiveStream(StreamState state, Progres try { if (i % 7 == 0) + { appObj.Update(status: ApplicationObject.State.Failed, logItem: "Something happened."); + } else + { appObj.Update(status: ApplicationObject.State.Created); + } } catch (Exception e) { @@ -433,6 +451,7 @@ public override async Task ReceiveStream(StreamState state, Progres { var r = new Random(i); if (r.NextDouble() > 0.5) + { try { //progress.Report.LogOperationError(new Exception($"Critical operation error!")); @@ -442,6 +461,7 @@ public override async Task ReceiveStream(StreamState state, Progres { progress.Report.LogOperationError(e); } + } } return state; @@ -461,8 +481,10 @@ public override async void PreviewSend(StreamState state, ProgressViewModel prog for (int i = 1; i < 100; i += 10) { if (progress.CancellationToken.IsCancellationRequested) + { //progress.Report.Log("Fake sending was cancelled"); return; + } progress.Report.Log("Done fake task " + i); await Task.Delay(TimeSpan.FromMilliseconds(rnd.Next(200, 1000))).ConfigureAwait(true); @@ -474,6 +496,7 @@ public override async void PreviewSend(StreamState state, ProgressViewModel prog // Mock "some" errors for (int i = 0; i < 10; i++) + { try { throw new Exception($"Number {i} failed"); @@ -484,6 +507,7 @@ public override async void PreviewSend(StreamState state, ProgressViewModel prog //TODO //state.Errors.Add(e); } + } } public override async Task SendStream(StreamState state, ProgressViewModel progress) @@ -500,8 +524,10 @@ public override async Task SendStream(StreamState state, ProgressViewMod for (int i = 1; i < 100; i += 10) { if (progress.CancellationToken.IsCancellationRequested) + { //progress.Report.Log("Fake sending was cancelled"); return null; + } var r = new Random(i); var status = (ApplicationObject.State)r.Next(5); @@ -521,6 +547,7 @@ public override async Task SendStream(StreamState state, ProgressViewMod // Mock "some" errors for (int i = 0; i < 10; i++) + { try { throw new Exception($"Number {i} failed"); @@ -531,6 +558,7 @@ public override async Task SendStream(StreamState state, ProgressViewMod //TODO //state.Errors.Add(e); } + } return ""; } diff --git a/DesktopUI2/DesktopUI2/Models/ConfigManager.cs b/DesktopUI2/DesktopUI2/Models/ConfigManager.cs index 7aefdc8e2b..e606549027 100644 --- a/DesktopUI2/DesktopUI2/Models/ConfigManager.cs +++ b/DesktopUI2/DesktopUI2/Models/ConfigManager.cs @@ -26,7 +26,9 @@ public static Config Load() var newConfig = ConfigStorage.GetObject("configDUI"); if (!string.IsNullOrEmpty(newConfig)) + { return JsonConvert.DeserializeObject(newConfig); + } return JsonConvert.DeserializeObject(oldConfig); } diff --git a/DesktopUI2/DesktopUI2/Models/Filters/ListSelectionFilter.cs b/DesktopUI2/DesktopUI2/Models/Filters/ListSelectionFilter.cs index 57deaa5724..00349d43af 100644 --- a/DesktopUI2/DesktopUI2/Models/Filters/ListSelectionFilter.cs +++ b/DesktopUI2/DesktopUI2/Models/Filters/ListSelectionFilter.cs @@ -20,7 +20,10 @@ public string Summary get { if (Selection.Count != 0) + { return string.Join(", ", Selection); + } + return "nothing"; } } diff --git a/DesktopUI2/DesktopUI2/Models/Filters/SelectionFilterConverter.cs b/DesktopUI2/DesktopUI2/Models/Filters/SelectionFilterConverter.cs index 687a3ec6e5..4d5d722f74 100644 --- a/DesktopUI2/DesktopUI2/Models/Filters/SelectionFilterConverter.cs +++ b/DesktopUI2/DesktopUI2/Models/Filters/SelectionFilterConverter.cs @@ -28,19 +28,31 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var type = jsonObject.Value("Type"); if (type == typeof(AllSelectionFilter).ToString()) + { filter = new AllSelectionFilter(); + } else if (type == typeof(ListSelectionFilter).ToString()) + { filter = new ListSelectionFilter(); + } else if (type == typeof(ManualSelectionFilter).ToString()) + { filter = new ManualSelectionFilter(); + } else if (type == typeof(PropertySelectionFilter).ToString()) + { filter = new PropertySelectionFilter(); + } else if (type == typeof(TreeSelectionFilter).ToString()) + { filter = new TreeSelectionFilter(); + } else + { throw new NotImplementedException( $"Unknown filter type: {type}. No case matching that type defined in {GetType().FullName}" ); + } serializer.Populate(jsonObject.CreateReader(), filter); return filter; diff --git a/DesktopUI2/DesktopUI2/Models/Filters/TreeSelectionFilter.cs b/DesktopUI2/DesktopUI2/Models/Filters/TreeSelectionFilter.cs index e0aad35c45..64d277d17f 100644 --- a/DesktopUI2/DesktopUI2/Models/Filters/TreeSelectionFilter.cs +++ b/DesktopUI2/DesktopUI2/Models/Filters/TreeSelectionFilter.cs @@ -66,7 +66,9 @@ private void Items_CollectionChanged(object sender, NotifyCollectionChangedEvent { Selection.Clear(); if (SelectedItems != null) + { Selection.AddRange(SelectedItems.Select(item => item.ToString()).ToList()); + } } } @@ -136,7 +138,10 @@ public List Flatten() { var result = new List { this }; foreach (var child in Elements.Where(child => child != null)) + { result.AddRange(child.Flatten()); + } + return result; } diff --git a/DesktopUI2/DesktopUI2/Models/NotificationManager.cs b/DesktopUI2/DesktopUI2/Models/NotificationManager.cs index 7aaafaf097..b7804f5466 100644 --- a/DesktopUI2/DesktopUI2/Models/NotificationManager.cs +++ b/DesktopUI2/DesktopUI2/Models/NotificationManager.cs @@ -87,7 +87,9 @@ public void Show(INotification content) public async void Show(object content) { if (_items == null) + { return; + } var notification = content as INotification; @@ -98,17 +100,21 @@ public async void Show(object content) }; if (notification != null) + { notificationControl.NotificationClosed += (sender, args) => { notification.OnClose?.Invoke(); _items.Remove(sender); }; + } notificationControl.PointerPressed += (sender, args) => { if (notification != null && notification.OnClick != null) + { notification.OnClick.Invoke(); + } (sender as NotificationCard)?.Close(); }; @@ -116,10 +122,14 @@ public async void Show(object content) _items.Add(notificationControl); if (_items.OfType().Count(i => !i.IsClosing) > MaxItems) + { _items.OfType().First(i => !i.IsClosing).Close(); + } if (notification != null && notification.Expiration == TimeSpan.Zero) + { return; + } await Task.Delay(notification?.Expiration ?? TimeSpan.FromSeconds(7)).ConfigureAwait(true); @@ -138,7 +148,9 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs base.OnPropertyChanged(change); if (change.Property == PositionProperty) + { UpdatePseudoClasses(change.NewValue.GetValueOrDefault()); + } } private void UpdatePseudoClasses(NotificationPosition position) diff --git a/DesktopUI2/DesktopUI2/Models/Settings/SettingsConverter.cs b/DesktopUI2/DesktopUI2/Models/Settings/SettingsConverter.cs index 9efd864fea..db36ab5725 100644 --- a/DesktopUI2/DesktopUI2/Models/Settings/SettingsConverter.cs +++ b/DesktopUI2/DesktopUI2/Models/Settings/SettingsConverter.cs @@ -33,19 +33,33 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var type = jsonObject.Value("Type"); if (type == typeof(CheckBoxSetting).ToString()) + { setting = new CheckBoxSetting(); + } else if (type == typeof(ListBoxSetting).ToString()) + { setting = new ListBoxSetting(); + } else if (type == typeof(MappingSetting).ToString()) + { setting = new MappingSetting(); + } else if (type == typeof(MultiSelectBoxSetting).ToString()) + { setting = new MultiSelectBoxSetting(); + } else if (type == typeof(NumericSetting).ToString()) + { setting = new NumericSetting(); + } else if (type == typeof(TextBoxSetting).ToString()) + { setting = new TextBoxSetting(); + } else + { continue; + } serializer.Populate(jsonObject.CreateReader(), setting); diff --git a/DesktopUI2/DesktopUI2/Models/StreamState.cs b/DesktopUI2/DesktopUI2/Models/StreamState.cs index 0face22688..0d9f282c69 100644 --- a/DesktopUI2/DesktopUI2/Models/StreamState.cs +++ b/DesktopUI2/DesktopUI2/Models/StreamState.cs @@ -43,7 +43,9 @@ public Client Client { var account = AccountManager.GetAccounts(ServerUrl).FirstOrDefault(x => x.userInfo.id == UserId); if (account != null) + { _client = new Client(account); + } } return _client; } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/HostType.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/HostType.cs index 80a26001dd..174a072b3f 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/HostType.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/HostType.cs @@ -1,14 +1,13 @@ -namespace DesktopUI2.Models.TypeMappingOnReceive -{ - public class HostType : ISingleHostType - { - public string HostTypeName { get; } +namespace DesktopUI2.Models.TypeMappingOnReceive; - public HostType(string hostTypeName) - { - HostTypeName = hostTypeName; - } +public class HostType : ISingleHostType +{ + public string HostTypeName { get; } - public virtual string HostTypeDisplayName => HostTypeName; + public HostType(string hostTypeName) + { + HostTypeName = hostTypeName; } + + public virtual string HostTypeDisplayName => HostTypeName; } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/IHostTypeContainer.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/IHostTypeContainer.cs index 05d7c1c7d5..40306181fe 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/IHostTypeContainer.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/IHostTypeContainer.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace DesktopUI2.Models.TypeMappingOnReceive +namespace DesktopUI2.Models.TypeMappingOnReceive; + +public interface IHostTypeContainer { - public interface IHostTypeContainer - { - public ICollection GetAllTypes(); - public ICollection GetTypesInCategory(string category); - } + public ICollection GetAllTypes(); + public ICollection GetTypesInCategory(string category); } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleHostType.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleHostType.cs index 4acb267c15..dd6d4e0781 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleHostType.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleHostType.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Text; -namespace DesktopUI2.Models.TypeMappingOnReceive +namespace DesktopUI2.Models.TypeMappingOnReceive; + +public interface ISingleHostType { - public interface ISingleHostType - { - string HostTypeName { get; } - string HostTypeDisplayName { get; } - } + string HostTypeName { get; } + string HostTypeDisplayName { get; } } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleValueToMap.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleValueToMap.cs index a6e5b4ac82..e088b78698 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleValueToMap.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ISingleValueToMap.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace DesktopUI2.Models.TypeMappingOnReceive +namespace DesktopUI2.Models.TypeMappingOnReceive; + +public interface ISingleValueToMap { - public interface ISingleValueToMap - { - public string IncomingType { get; set; } - public string IncomingTypeDisplayName { get; } - public ISingleHostType InitialGuess { get; set; } - public ISingleHostType MappedHostType { get; set; } - } + public string IncomingType { get; set; } + public string IncomingTypeDisplayName { get; } + public ISingleHostType InitialGuess { get; set; } + public ISingleHostType MappedHostType { get; set; } } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ITypeMap.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ITypeMap.cs index 4d1131723f..9f43b15b6b 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ITypeMap.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/ITypeMap.cs @@ -3,11 +3,10 @@ using System.Text; using Speckle.Core.Models; -namespace DesktopUI2.Models.TypeMappingOnReceive +namespace DesktopUI2.Models.TypeMappingOnReceive; + +public interface ITypeMap { - public interface ITypeMap - { - public IEnumerable Categories { get; } - public IEnumerable GetValuesToMapOfCategory(string category); - } + public IEnumerable Categories { get; } + public IEnumerable GetValuesToMapOfCategory(string category); } diff --git a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/MappingValue.cs b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/MappingValue.cs index 5cbd7bfd14..f8d5ee997b 100644 --- a/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/MappingValue.cs +++ b/DesktopUI2/DesktopUI2/Models/TypeMappingOnReceive/MappingValue.cs @@ -4,38 +4,39 @@ using System.Text; using ReactiveUI; -namespace DesktopUI2.Models.TypeMappingOnReceive +namespace DesktopUI2.Models.TypeMappingOnReceive; + +[DataContract] +public class MappingValue : ReactiveObject, ISingleValueToMap { - [DataContract] - public class MappingValue : ReactiveObject, ISingleValueToMap + public MappingValue(string inType, ISingleHostType inGuess, bool inNewType = false) + { + IncomingType = inType; + InitialGuess = inGuess; + NewType = inNewType; + } + + [DataMember] + public string IncomingType { get; set; } + public bool NewType { get; set; } + + private ISingleHostType _initialGuess; + + [DataMember] + public ISingleHostType InitialGuess { - public MappingValue(string inType, ISingleHostType inGuess, bool inNewType = false) - { - IncomingType = inType; - InitialGuess = inGuess; - NewType = inNewType; - } - - [DataMember] - public string IncomingType { get; set; } - public bool NewType { get; set; } - - private ISingleHostType _initialGuess; - [DataMember] - public ISingleHostType InitialGuess - { - get => _initialGuess; - set => this.RaiseAndSetIfChanged(ref _initialGuess, value); - } - - private ISingleHostType _mappedHostType; - [DataMember] - public ISingleHostType MappedHostType - { - get => _mappedHostType; - set => this.RaiseAndSetIfChanged(ref _mappedHostType, value); - } - - public virtual string IncomingTypeDisplayName => IncomingType; + get => _initialGuess; + set => this.RaiseAndSetIfChanged(ref _initialGuess, value); } + + private ISingleHostType _mappedHostType; + + [DataMember] + public ISingleHostType MappedHostType + { + get => _mappedHostType; + set => this.RaiseAndSetIfChanged(ref _mappedHostType, value); + } + + public virtual string IncomingTypeDisplayName => IncomingType; } diff --git a/DesktopUI2/DesktopUI2/Utils.cs b/DesktopUI2/DesktopUI2/Utils.cs index c02b22120e..7688549749 100644 --- a/DesktopUI2/DesktopUI2/Utils.cs +++ b/DesktopUI2/DesktopUI2/Utils.cs @@ -106,12 +106,16 @@ public static void ClearCache() private static async Task GetUser(string userId, Client client) { if (CachedUsers.ContainsKey(userId)) + { return CachedUsers[userId]; + } var user = await client.OtherUserGet(userId).ConfigureAwait(true); if (user != null) + { CachedUsers[userId] = user; + } return user; } @@ -119,12 +123,16 @@ private static async Task GetUser(string userId, Client client) public static async Task GetAccount(string userId, Client client) { if (CachedAccounts.ContainsKey(userId)) + { return CachedAccounts[userId]; + } var user = await GetUser(userId, client).ConfigureAwait(true); if (user == null) + { return null; + } var avm = new AccountViewModel(user); CachedAccounts[userId] = avm; @@ -139,8 +147,13 @@ public static bool IsValidEmail(string email) string expression = "\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; if (Regex.IsMatch(email, expression)) + { if (Regex.Replace(email, expression, string.Empty).Length == 0) + { return true; + } + } + return false; } @@ -158,7 +171,9 @@ public static Action Debounce(this Action func, int milliseconds = 300) t => { if (t.IsCompleted) + { func(); + } }, TaskScheduler.Default ); @@ -179,7 +194,9 @@ public static Action Debounce(this Action func, int milliseconds = 300) t => { if (t.IsCompleted) + { func(arg); + } }, TaskScheduler.Default ); @@ -194,20 +211,28 @@ public static void LaunchManager() Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Launch Manager" } }); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { path = @"/Applications/Manager for Speckle.app"; + } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { path = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Speckle", "Manager", "Manager.exe" ); + } if (File.Exists(path) || Directory.Exists(path)) + { Process.Start(path); + } else + { Process.Start(new ProcessStartInfo("https://speckle.systems/download") { UseShellExecute = true }); + } } catch (Exception ex) { diff --git a/DesktopUI2/DesktopUI2/ViewLocator.cs b/DesktopUI2/DesktopUI2/ViewLocator.cs index 79f978c700..3c17654e50 100644 --- a/DesktopUI2/DesktopUI2/ViewLocator.cs +++ b/DesktopUI2/DesktopUI2/ViewLocator.cs @@ -15,7 +15,10 @@ public IControl Build(object data) var type = Type.GetType(name); if (type != null) + { return (Control)Activator.CreateInstance(type)!; + } + return new TextBlock { Text = "Not Found: " + name }; } diff --git a/DesktopUI2/DesktopUI2/ViewModels/AccountViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/AccountViewModel.cs index 653f08beb1..68214064cf 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/AccountViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/AccountViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Net.Http; @@ -80,7 +80,10 @@ public string SimpleName get { if (HomeViewModel.Instance.Accounts.Any(x => x.Account.userInfo.id == Id)) + { return "You"; + } + return Name; } } @@ -97,6 +100,7 @@ public string AvatarUrl //if the user manually uploaded their avatar it'll be a base64 string of the image //otherwise if linked the account eg via google, it'll be a link if (value != null && value.StartsWith("data:")) + { try { SetImage(Convert.FromBase64String(value.Split(',')[1])); @@ -106,13 +110,18 @@ public string AvatarUrl { value = null; } + } // only use robohas if it's the first attempt // otherwise it'll end up in a loop if (value == null && Id != null && _firstDownload) + { this.RaiseAndSetIfChanged(ref _avatarUrl, $"https://robohash.org/{Id}.png?size=28x28"); + } else + { this.RaiseAndSetIfChanged(ref _avatarUrl, value); + } TrySetAvatarFromUrl(AvatarUrl); } @@ -127,7 +136,9 @@ public Bitmap AvatarImage private async void TrySetAvatarFromUrl(string url) { if (string.IsNullOrEmpty(url)) + { return; + } _firstDownload = false; diff --git a/DesktopUI2/DesktopUI2/ViewModels/ApplicationObjectViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/ApplicationObjectViewModel.cs index ec08d854db..9c87d04532 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/ApplicationObjectViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/ApplicationObjectViewModel.cs @@ -33,7 +33,9 @@ public ApplicationObjectViewModel(ApplicationObject item, bool isReceiver, Progr SearchText = $"{Id} {Name} {Status} {logString} {createdIdsString}"; if (ApplicationIds.Count == 0) + { PreviewEnabled = false; + } switch (item.Status) { @@ -93,8 +95,13 @@ public async void PreviewCommand() if (PreviewOn) { foreach (var applicationId in ApplicationIds) + { if (!_Progress.SelectedReportObjects.Contains(applicationId)) + { _Progress.SelectedReportObjects.Add(applicationId); + } + } + Bindings.SelectClientObjects(_Progress.SelectedReportObjects); Analytics.TrackEvent( Analytics.Events.DUIAction, @@ -104,7 +111,10 @@ public async void PreviewCommand() else { foreach (var applicationId in ApplicationIds) + { _Progress.SelectedReportObjects.Remove(applicationId); + } + Bindings.SelectClientObjects(ApplicationIds, true); } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/CollaboratorsViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/CollaboratorsViewModel.cs index 58dec2889b..91807be92e 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/CollaboratorsViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/CollaboratorsViewModel.cs @@ -46,13 +46,17 @@ internal void ReloadUsers() { AddedUsers = new ObservableCollection(); foreach (var collab in _stream.Stream.collaborators) - //skip myself - //if (_stream.StreamState.Client.Account.userInfo.id == collab.id) - // continue; + //skip myself + //if (_stream.StreamState.Client.Account.userInfo.id == collab.id) + // continue; + { AddedUsers.Add(new AccountViewModel(collab)); + } foreach (var collab in _stream.Stream.pendingCollaborators) + { AddedUsers.Add(new AccountViewModel(collab)); + } this.RaisePropertyChanged(nameof(AddedUsers)); } @@ -61,7 +65,9 @@ private async void Search() { Focus(); if (SearchQuery.Length < 3) + { return; + } if (!await Http.UserHasInternet().ConfigureAwait(true)) { @@ -116,14 +122,13 @@ SelectionModelSelectionChangedEventArgs e private async void SearchUsers() { - ShowProgress = true; try { //exclude existing ones var users = (await _stream.StreamState.Client.UserSearch(SearchQuery).ConfigureAwait(true)).Where( - x => !AddedUsers.Any(u => u.Id == x.id) - ); + x => !AddedUsers.Any(u => u.Id == x.id) + ); //exclude myself users = users.Where(x => _stream.StreamState.Client.Account.userInfo.id != x.id); @@ -134,7 +139,6 @@ private async void SearchUsers() //ignore } - ShowProgress = false; DropDownOpen = true; } @@ -147,25 +151,42 @@ private bool CanSaveCommand(object parameter) foreach (var user in AddedUsers) { if (Utils.IsValidEmail(user.Name) && !_stream.Stream.pendingCollaborators.Any(x => x.title == user.Name)) + { return true; + } + if ( - !_stream.Stream.collaborators.Any(x => x.id == user.Id) && - !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id) + !_stream.Stream.collaborators.Any(x => x.id == user.Id) + && !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id) ) + { return true; + } + if ( - !_stream.Stream.collaborators.Any(x => x.id == user.Id && x.role == user.Role) && - !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id && x.role == user.Role) + !_stream.Stream.collaborators.Any(x => x.id == user.Id && x.role == user.Role) + && !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id && x.role == user.Role) ) + { return true; + } } foreach (var user in _stream.Stream.collaborators) + { if (!AddedUsers.Any(x => x.Id == user.id)) + { return true; + } + } + foreach (var user in _stream.Stream.pendingCollaborators) + { if (!AddedUsers.Any(x => x.Id == user.id)) + { return true; + } + } } catch (Exception ex) { @@ -206,10 +227,13 @@ private async void SaveCommand() { //mismatch between roles set within the dropdown and existing ones if (!user.Role.StartsWith("stream:")) + { user.Role = "stream:" + user.Role; + } //invite users by email if (Utils.IsValidEmail(user.Name) && !_stream.Stream.pendingCollaborators.Any(x => x.title == user.Name)) + { try { await _stream.StreamState.Client @@ -226,22 +250,20 @@ await _stream.StreamState.Client Analytics.TrackEvent( _stream.StreamState.Client.Account, Analytics.Events.DUIAction, - new Dictionary - { - {"name", "Stream Share"}, - {"method", "Invite Email"} - } + new Dictionary { { "name", "Stream Share" }, { "method", "Invite Email" } } ); } catch (Exception ex) { SpeckleLog.Logger.Error(ex, "Failed to invite user {exceptionMessage}", ex.Message); } + } //add new collaborators else if ( - !_stream.Stream.collaborators.Any(x => x.id == user.Id) && - !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id) + !_stream.Stream.collaborators.Any(x => x.id == user.Id) + && !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id) ) + { try { await _stream.StreamState.Client @@ -258,22 +280,20 @@ await _stream.StreamState.Client Analytics.TrackEvent( _stream.StreamState.Client.Account, Analytics.Events.DUIAction, - new Dictionary - { - {"name", "Stream Share"}, - {"method", "Invite User"} - } + new Dictionary { { "name", "Stream Share" }, { "method", "Invite User" } } ); } catch (Exception ex) { SpeckleLog.Logger.Error(ex, "Failed to invite collaborator {exceptionMessage}", ex.Message); } + } //update permissions, only if changed else if ( - !_stream.Stream.collaborators.Any(x => x.id == user.Id && x.role == user.Role) && - !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id && x.role == user.Role) + !_stream.Stream.collaborators.Any(x => x.id == user.Id && x.role == user.Role) + && !_stream.Stream.pendingCollaborators.Any(x => x.id == user.Id && x.role == user.Role) ) + { try { await _stream.StreamState.Client @@ -289,51 +309,46 @@ await _stream.StreamState.Client Analytics.TrackEvent( _stream.StreamState.Client.Account, Analytics.Events.DUIAction, - new Dictionary - { - {"name", "Stream Share"}, - {"method", "Update Permissions"} - } + new Dictionary { { "name", "Stream Share" }, { "method", "Update Permissions" } } ); } catch (Exception ex) { SpeckleLog.Logger.Error(ex, "Failed to update permissions {exceptionMessage}", ex.Message); } + } } //remove collaborators foreach (var user in _stream.Stream.collaborators) + { if (!AddedUsers.Any(x => x.Id == user.id)) + { try { await _stream.StreamState.Client .StreamRevokePermission( - new StreamRevokePermissionInput - { - userId = user.id, - streamId = _stream.StreamState.StreamId - } + new StreamRevokePermissionInput { userId = user.id, streamId = _stream.StreamState.StreamId } ) .ConfigureAwait(true); Analytics.TrackEvent( _stream.StreamState.Client.Account, Analytics.Events.DUIAction, - new Dictionary - { - {"name", "Stream Share"}, - {"method", "Remove User"} - } + new Dictionary { { "name", "Stream Share" }, { "method", "Remove User" } } ); } catch (Exception ex) { SpeckleLog.Logger.Error(ex, "Failed to revoke permissions {exceptionMessage}", ex.Message); } + } + } //revoke invites foreach (var user in _stream.Stream.pendingCollaborators) + { if (!AddedUsers.Any(x => x.Id == user.id)) + { try { await _stream.StreamState.Client @@ -342,17 +357,15 @@ await _stream.StreamState.Client Analytics.TrackEvent( _stream.StreamState.Client.Account, Analytics.Events.DUIAction, - new Dictionary - { - {"name", "Stream Share"}, - {"method", "Cancel Invite"} - } + new Dictionary { { "name", "Stream Share" }, { "method", "Cancel Invite" } } ); } catch (Exception ex) { SpeckleLog.Logger.Error(ex, "Failed to revoke invites {exceptionMessage}", ex.Message); } + } + } try { @@ -376,9 +389,10 @@ await _stream.StreamState.Client } if (IsDialog) + { MainViewModel.RouterInstance.NavigateBack.Execute(); + } } - catch (Exception ex) { SpeckleLog.Logger.Error( @@ -405,7 +419,9 @@ private void ClearSearchCommand() private void RemoveSeletedUsersCommand() { foreach (var item in SelectionModel.SelectedItems.ToList()) + { AddedUsers.Remove(item); + } this.RaisePropertyChanged(nameof(HasSelectedUsers)); this.RaisePropertyChanged(nameof(AddedUsers)); @@ -417,8 +433,12 @@ private async void ChangeRoleSeletedUsersCommand() var result = await dialog.ShowDialog().ConfigureAwait(true); if (result != null) + { foreach (var item in SelectionModel.SelectedItems.ToList()) + { item.Role = "stream:" + result; + } + } this.RaisePropertyChanged(nameof(AddedUsers)); } diff --git a/DesktopUI2/DesktopUI2/ViewModels/CommentViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/CommentViewModel.cs index d391c8a24c..11637bc421 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/CommentViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/CommentViewModel.cs @@ -32,11 +32,13 @@ public CommentViewModel(CommentItem item, string streamId, Client client) Bindings = Locator.Current.GetService(); if (Comment.replies != null) + { foreach (var r in Comment.replies.items) { var reply = new CommentViewModel(r, streamId, client); Replies.Add(reply); } + } } public CommentItem Comment { get; set; } @@ -56,7 +58,10 @@ public string RepliesCount get { if (Comment == null) + { return "No replies"; + } + var s = Comment.replies.totalCount == 1 ? "y" : "ies"; var c = Comment.replies.totalCount == 0 ? "No" : Comment.replies.totalCount.ToString(); return $"{c} repl{s}"; @@ -112,18 +117,24 @@ public void OpenCommentView() public void OpenComment() { if (Comment.resources == null || !Comment.resources.Any()) + { return; + } var r0 = Comment.resources[0]; var overlay = ""; if (Comment.resources.Count > 1) + { overlay = "&overlay=" + string.Join(",", Comment.resources.Skip(1).Select(x => x.resourceId)); + } var url = $"{_client.Account.serverInfo.url}/streams/{StreamId}/{r0.resourceType}s/{r0.resourceId}?cId={Comment.id}{overlay}"; if (_client.Account.serverInfo.frontend2) + { url = $"{_client.Account.serverInfo.url}/projects/{StreamId}/"; + } Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Comment View" } }); diff --git a/DesktopUI2/DesktopUI2/ViewModels/DesignViewModels/DesignHomeViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/DesignViewModels/DesignHomeViewModel.cs index 16cfe208b1..d31b07f897 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/DesignViewModels/DesignHomeViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/DesignViewModels/DesignHomeViewModel.cs @@ -13,7 +13,10 @@ public DesignHomeViewModel() var acc = AccountManager.GetDefaultAccount(); Accounts = AccountManager.GetAccounts().Select(x => new AccountViewModel(x)).ToList(); if (acc == null) + { return; + } + using var client = new Client(acc); FilteredStreams = client.StreamsGet().Result.Select(x => new StreamAccountWrapper(x, acc)).ToList(); diff --git a/DesktopUI2/DesktopUI2/ViewModels/DialogViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/DialogViewModel.cs index 308c04a518..43b3aba467 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/DialogViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/DialogViewModel.cs @@ -4,18 +4,17 @@ using DesktopUI2.Models; using ReactiveUI; -namespace DesktopUI2.ViewModels +namespace DesktopUI2.ViewModels; + +public class DialogViewModel : ReactiveObject { - public class DialogViewModel : ReactiveObject + //UI Binding + public bool UseFe2 { - //UI Binding - public bool UseFe2 + get { - get - { - var config = ConfigManager.Load(); - return config.UseFe2; - } + var config = ConfigManager.Load(); + return config.UseFe2; } } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/FilterViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/FilterViewModel.cs index e8f416c691..8ae0d266c4 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/FilterViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/FilterViewModel.cs @@ -30,7 +30,9 @@ public FilterViewModel(ISelectionFilter filter) //TODO should clean up this logic a bit //maybe have a model, view and viewmodel for each filter if (filter is ListSelectionFilter l) + { _valuesList = SearchResults = new List(l.Values); + } //TODO: //FilterView.DataContext = this; @@ -71,18 +73,26 @@ public ISelectionFilter Filter public bool IsReady() { if (Filter is ManualSelectionFilter && !Filter.Selection.Any()) + { return false; + } if (Filter is ListSelectionFilter && !Filter.Selection.Any()) + { return false; + } if (Filter is PropertySelectionFilter p) + { if ( string.IsNullOrEmpty(p.PropertyName) || string.IsNullOrEmpty(p.PropertyOperator) || string.IsNullOrEmpty(p.PropertyValue) ) + { return false; + } + } return true; } @@ -96,10 +106,17 @@ private void SelectionChanged(object sender, SelectionModelSelectionChangedEvent if (!isSearching) { foreach (var a in e.SelectedItems) + { if (!Filter.Selection.Contains(a)) + { Filter.Selection.Add(a as string); + } + } + foreach (var r in e.DeselectedItems) + { Filter.Selection.Remove(r as string); + } this.RaisePropertyChanged(nameof(Summary)); } @@ -146,13 +163,20 @@ public void RestoreSelectedItems() foreach (var item in Filter.Selection) { if (!_valuesList.Contains(item)) + { itemsToRemove.Add(item); + } + if (!SelectionModel.SelectedItems.Contains(item)) + { SelectionModel.Select(SearchResults.IndexOf(item)); + } } foreach (var itemToRemove in itemsToRemove) + { Filter.Selection.Remove(itemToRemove); + } } this.RaisePropertyChanged(nameof(PropertyName)); @@ -183,8 +207,10 @@ public void SetObjectSelection() { var objIds = Bindings.GetSelectedObjects(); if (objIds == null || objIds.Count == 0) - //Globals.Notify("Could not get object selection."); + //Globals.Notify("Could not get object selection."); + { return; + } Filter.Selection = objIds; this.RaisePropertyChanged(nameof(Summary)); @@ -199,13 +225,17 @@ public void AddObjectSelection() { var objIds = Bindings.GetSelectedObjects(); if (objIds == null || objIds.Count == 0) - //Globals.Notify("Could not get object selection."); + //Globals.Notify("Could not get object selection."); + { return; + } objIds.ForEach(id => { if (Filter.Selection.FirstOrDefault(x => x == id) == null) + { Filter.Selection.Add(id); + } }); this.RaisePropertyChanged(nameof(Summary)); //Globals.Notify("Object added."); @@ -219,14 +249,18 @@ public void RemoveObjectSelection() { var objIds = Bindings.GetSelectedObjects(); if (objIds == null || objIds.Count == 0) - //Globals.Notify("Could not get object selection."); + //Globals.Notify("Could not get object selection."); + { return; + } var filtered = Filter.Selection.Where(o => objIds.IndexOf(o) == -1).ToList(); if (filtered.Count == Filter.Selection.Count) - //Globals.Notify("No objects removed."); + //Globals.Notify("No objects removed."); + { return; + } //Globals.Notify($"{Filter.Selection.Count - filtered.Count} objects removed."); Filter.Selection = filtered; diff --git a/DesktopUI2/DesktopUI2/ViewModels/HomeViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/HomeViewModel.cs index 35058323db..fc32883a22 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/HomeViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/HomeViewModel.cs @@ -89,7 +89,9 @@ internal void UpdateSavedStreams(List streams) ClearSavedStreams(); foreach (StreamState stream in streams) + { SavedStreams.Add(new StreamViewModel(stream, HostScreen, RemoveSavedStreamCommand)); + } this.RaisePropertyChanged(nameof(SavedStreams)); this.RaisePropertyChanged(nameof(HasSavedStreams)); @@ -117,7 +119,9 @@ internal void UpdateSelectedStream() try { if (_selectedSavedStream != null && !_selectedSavedStream.Progress.IsProgressing) + { _selectedSavedStream.GetBranchesAndRestoreState(); + } } catch (Exception ex) { @@ -138,10 +142,14 @@ internal void AddSavedStream(StreamViewModel stream) //saved stream has been edited var savedStream = SavedStreams.FirstOrDefault(x => x.StreamState.Id == stream.StreamState.Id); if (savedStream != null) + { savedStream = stream; + } //it's a new saved stream else + { SavedStreams.Add(stream); + } WriteStreamsToFile(); this.RaisePropertyChanged(nameof(HasSavedStreams)); @@ -157,7 +165,9 @@ private async Task GetStreams() try { if (!HasAccounts) + { return; + } InProgress = true; @@ -170,7 +180,9 @@ private async Task GetStreams() foreach (var account in Accounts) { if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } try { @@ -180,25 +192,34 @@ private async Task GetStreams() if (string.IsNullOrEmpty(SearchQuery)) { if (SelectedFilter == Filter.favorite) + { result = await account.Client .FavoriteStreamsGet(25, StreamGetCancelTokenSource.Token) .ConfigureAwait(true); + } else + { result = await account.Client.StreamsGet(25, StreamGetCancelTokenSource.Token).ConfigureAwait(true); + } } //SEARCH else { //do not search favorite streams, too much hassle if (SelectedFilter == Filter.favorite) + { SelectedFilter = Filter.all; + } + result = await account.Client .StreamSearch(SearchQuery, 25, StreamGetCancelTokenSource.Token) .ConfigureAwait(true); } if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } streams.AddRange(result.Select(x => new StreamAccountWrapper(x, account.Account))); } @@ -209,7 +230,9 @@ private async Task GetStreams() catch (Exception ex) { if (ex.InnerException is TaskCanceledException) + { return; + } SpeckleLog.Logger.Error(ex, "Could not fetch streams"); @@ -229,7 +252,9 @@ private async Task GetStreams() } } if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } Streams = streams.OrderByDescending(x => x.Stream.updatedAt).ToList(); } @@ -270,12 +295,16 @@ private async Task GetNotifications() { var result = await account.Client.GetAllPendingInvites().ConfigureAwait(true); foreach (var r in result) + { Notifications.Add(new NotificationViewModel(r, account.Client.ServerUrl)); + } } catch (Exception e) { if (e.InnerException is TaskCanceledException) + { return; + } SpeckleLog.Logger.Error(e, "Could not fetch invites"); } @@ -297,7 +326,9 @@ private async Task GetNotifications() private async void SearchStreams() { if (await CheckIsOffline().ConfigureAwait(true)) + { return; + } GetStreams().ConfigureAwait(true); this.RaisePropertyChanged(nameof(StreamsText)); @@ -335,7 +366,9 @@ internal async void Refresh() try { if (await CheckIsOffline().ConfigureAwait(true)) + { return; + } //prevent subscriptions from being registered multiple times //DISABLED: https://github.com/specklesystems/speckle-sharp/issues/2574 @@ -403,17 +436,26 @@ private void Client_OnUserStreamRemoved(object sender, StreamInfo e) { var streamName = Streams.FirstOrDefault(x => x.Stream.id == e.id)?.Stream?.name; if (streamName == null) + { streamName = SavedStreams.FirstOrDefault(x => x.Stream.id == e.id)?.Stream?.name; + } + if (streamName == null) + { return; + } var svm = MainViewModel.RouterInstance.NavigationStack.Last() as StreamViewModel; if (svm != null && svm.Stream.id == e.id) + { MainViewModel.GoHome(); + } //remove all saved streams matching this id foreach (var stateId in SavedStreams.Where(x => x.Stream.id == e.id).Select(y => y.StreamState.Id).ToList()) + { RemoveSavedStream(stateId); + } GetStreams().ConfigureAwait(true); @@ -436,11 +478,14 @@ private void GenerateMenuItems() MenuItemViewModel menu; if (Accounts.Count > 1) + { menu = new MenuItemViewModel { Header = new MaterialIcon { Kind = MaterialIconKind.AccountMultiple, Foreground = Brushes.White } }; + } else if (Accounts.Count == 1) + { menu = new MenuItemViewModel { Header = new Image @@ -452,15 +497,19 @@ private void GenerateMenuItems() Clip = new EllipseGeometry(new Rect(0, 0, 28, 28)) } }; + } else + { menu = new MenuItemViewModel { Header = new MaterialIcon { Kind = MaterialIconKind.AccountWarning, Foreground = Brushes.White } }; + } menu.Items = new List(); foreach (var account in Accounts) + { menu.Items.Add( new MenuItemViewModel { @@ -481,6 +530,7 @@ private void GenerateMenuItems() } } ); + } menu.Items.Add(new MenuItemViewModel(AddAccountCommand, "Add another account", MaterialIconKind.AccountPlus)); menu.Items.Add( @@ -512,7 +562,10 @@ private void RemoveSavedStream(string stateId) { var i = SavedStreams.FindIndex(x => x.StreamState.Id == stateId); if (i == -1) + { return; + } + SavedStreams[i].Dispose(); SavedStreams.RemoveAt(i); @@ -578,7 +631,9 @@ public void ViewOnlineCommand(object parameter) var url = $"{streamAcc.Account.serverInfo.url.TrimEnd('/')}/streams/{streamAcc.Stream.id}"; if (streamAcc.Account.serverInfo.frontend2) + { url = $"{streamAcc.Account.serverInfo.url.TrimEnd('/')}/projects/{streamAcc.Stream.id}"; + } Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); Analytics.TrackEvent( @@ -594,6 +649,7 @@ public async void NewStreamCommand() var result = await dialog.ShowDialog().ConfigureAwait(true); if (result) + { try { using var client = new Client(dialog.Account); @@ -627,6 +683,7 @@ public async void NewStreamCommand() SpeckleLog.Logger.Fatal(ex, "Failed to create new stream {exceptionMessage}", ex.Message); Dialogs.ShowDialog("Something went wrong...", ex.Message, DialogIconKind.Error); } + } } [DependsOn(nameof(InProgress))] @@ -642,13 +699,16 @@ public async void AddFromUrlCommand() Uri uri; string defaultText = ""; if (Uri.TryCreate(clipboard, UriKind.Absolute, out uri)) + { defaultText = clipboard; + } var dialog = new AddFromUrlDialog(defaultText); var result = await dialog.ShowDialog().ConfigureAwait(true); if (result != null) + { try { var sw = new StreamWrapper(result); @@ -683,6 +743,7 @@ public async void AddFromUrlCommand() SpeckleLog.Logger.Fatal(ex, "Failed to add from url {dialogResult} {exceptionMessage}", result, ex.Message); Dialogs.ShowDialog("Something went wrong...", ex.Message, DialogIconKind.Error); } + } } private Tuple ValidateUrl(string url) @@ -710,10 +771,14 @@ private Tuple ValidateUrl(string url) private Tuple ValidateName(string name) { if (string.IsNullOrEmpty(name)) + { return new Tuple(false, "Streams need a name too!"); + } if (name.Trim().Length < 3) + { return new Tuple(false, "Name is too short."); + } return new Tuple(true, ""); } @@ -727,7 +792,9 @@ public bool CanAddFromUrlCommand(object parameter) private async void OpenStreamCommand(object streamAccountWrapper) { if (await CheckIsOffline().ConfigureAwait(true)) + { return; + } if (streamAccountWrapper != null) { @@ -753,7 +820,9 @@ private async void OpenStreamCommand(object streamAccountWrapper) private async void OpenSavedStreamCommand(object streamViewModel) { if (await CheckIsOffline().ConfigureAwait(true)) + { return; + } if (streamViewModel != null && streamViewModel is StreamViewModel svm && !svm.NoAccess) { @@ -903,7 +972,10 @@ public bool ActiveFilter get { if (SelectedFilter == Filter.all) + { return false; + } + return true; } } @@ -916,7 +988,10 @@ private async void SetFilters(Filter oldValue, Filter newValue) { //do not search favourite streams, too much hassle if (newValue == Filter.favorite && !string.IsNullOrEmpty(SearchQuery)) + { SearchQuery = ""; + } + await GetStreams().ConfigureAwait(true); } @@ -930,7 +1005,10 @@ public List FilteredStreams get { if (SelectedFilter == Filter.all || SelectedFilter == Filter.favorite) + { return Streams; + } + return Streams.Where(x => x.Stream.role == $"stream:{SelectedFilter}").ToList(); } } @@ -955,12 +1033,17 @@ public string StreamsText if (string.IsNullOrEmpty(SearchQuery)) { if (UseFe2) + { return "ALL YOUR PROJECTS:"; + } + return "ALL YOUR STREAMS:"; } if (SearchQuery.Length <= 2) + { return "TYPE SOME MORE TO SEARCH..."; + } return "SEARCH RESULTS:"; } @@ -977,7 +1060,10 @@ public string SearchQuery { this.RaiseAndSetIfChanged(ref _searchQuery, value); if (!string.IsNullOrEmpty(SearchQuery) && SearchQuery.Length <= 2) + { return; + } + streamSearchDebouncer(); } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/ImportFamiliesDialogViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/ImportFamiliesDialogViewModel.cs index 624f12259a..aba15e891c 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/ImportFamiliesDialogViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/ImportFamiliesDialogViewModel.cs @@ -25,9 +25,14 @@ public ImportFamiliesDialogViewModel(Dictionary> allSymbols this.allSymbols = allSymbols; foreach (var symbol in allSymbols.Keys) + { LoadedFamilies.Add(symbol); + } + if (LoadedFamilies.Count > 0) + { SelectedFamily = LoadedFamilies[0]; + } } // this constructor is only for xaml design purposes @@ -69,9 +74,14 @@ public ImportFamiliesDialogViewModel() }; foreach (var symbol in allSymbols.Keys) + { LoadedFamilies.Add(symbol); + } + if (LoadedFamilies.Count > 0) + { SelectedFamily = LoadedFamilies[0]; + } } public static ImportFamiliesDialogViewModel Instance { get; private set; } @@ -108,13 +118,19 @@ public bool IsTopBoxChecked if (value) { foreach (var type in FamilyTypes) + { if (!type.isChecked && !type.isImported) + { type.isChecked = true; + } + } } else { foreach (var type in FamilyTypes) + { type.isChecked = false; + } } } } @@ -154,11 +170,13 @@ public void SetTopBox() { var allChecked = true; foreach (var type in FamilyTypes) + { if (!type.isChecked && !type.isImported) { allChecked = false; break; } + } _isTopBoxChecked = allChecked; this.RaisePropertyChanged(nameof(IsTopBoxChecked)); @@ -187,9 +205,13 @@ public bool isChecked this.RaiseAndSetIfChanged(ref _isChecked, value); Instance.SetTopBox(); if (value) + { Instance.selectedFamilySymbols.Add(this); + } else if (value == false && Instance.selectedFamilySymbols.Contains(this)) + { Instance.selectedFamilySymbols.Remove(this); + } } } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/MainViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/MainViewModel.cs index bdbe5d7ce2..a7dab4c346 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/MainViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/MainViewModel.cs @@ -122,11 +122,15 @@ private static void TaskScheduler_UnobservedTaskException(object sender, Unobser public static void GoHome() { if (RouterInstance == null) + { return; + } var config = ConfigManager.Load(); if (!config.OneClickMode) + { RouterInstance.Navigate.Execute(Home); + } } public static void CloseDialog() @@ -137,15 +141,21 @@ public static void CloseDialog() internal void ChangeTheme(bool isDark) { if (Application.Current == null) + { return; + } var materialTheme = Application.Current.LocateMaterialTheme(); var theme = materialTheme.CurrentTheme; if (isDark) + { theme.SetBaseTheme(Theme.Light); + } else + { theme.SetBaseTheme(Theme.Dark); + } materialTheme.CurrentTheme = theme; } diff --git a/DesktopUI2/DesktopUI2/ViewModels/MappingTool/MappingsViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/MappingTool/MappingsViewModel.cs index 8434ff27bd..4a7621723e 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/MappingTool/MappingsViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/MappingTool/MappingsViewModel.cs @@ -159,22 +159,35 @@ private void UpdateSelection(MappingSelectionInfo info) if (Schemas.Any()) { if (Schemas.Any(x => x.HasData)) + { SelectedSchema = Schemas.First(x => x.HasData); + } + SelectedSchema = Schemas.First(); if (SelectedStream == null || !AvailableRevitTypes.Any() || !AvailableRevitLevels.Any()) + { PromptMsg = "Try selecting a compatible mapping source for more options."; + } } else { if (SelectedStream == null) + { PromptMsg = "No options available for the current selection, try selecting a mapping data source."; + } else if (!AvailableRevitTypes.Any()) + { PromptMsg = "The selected branch does not contain any Revit types, try changing mapping data source."; + } else if (!AvailableRevitLevels.Any()) + { PromptMsg = "The selected branch does not contain any Revit levels, try changing mapping data source."; + } else + { PromptMsg = "Incompatible selection, try selecting objects of the same type or changing mapping source"; + } SelectedSchema = null; } @@ -192,7 +205,9 @@ internal async void OnBranchSelected() var model = await GetCommit().ConfigureAwait(true); if (model == null) + { return; + } GetTypesAndLevels(model); @@ -200,7 +215,9 @@ internal async void OnBranchSelected() //force an update if (_lastInfo != null) + { UpdateSelection(_lastInfo); + } } catch (Exception e) { } finally @@ -216,16 +233,20 @@ private async Task GetCommit() || StreamSelector.SelectedBranch.commits == null || StreamSelector.SelectedBranch.commits.items.Count == 0 ) + { return null; + } ShowProgress = true; using var client = new Client(StreamSelector.SelectedStream.Account); Commit commit = StreamSelector.SelectedBranch.commits.items.FirstOrDefault(); if (commit == null) + { throw new Exception( $"Branch {StreamSelector.SelectedBranch.name} in stream {StreamSelector.SelectedStream.Stream.id} has no commits" ); + } using var transport = new ServerTransport( StreamSelector.SelectedStream.Account, @@ -248,7 +269,9 @@ private void GetTypesAndLevels(Base model) { var elementTypes = ((IList)baseCategory.Value).Cast().ToList(); if (!elementTypes.Any()) + { continue; + } revitTypes.AddRange(elementTypes); } @@ -312,7 +335,8 @@ private void AddRevitInfoToSchema(List schemas) var updatedSchemas = new List(); foreach (var schema in schemas) - //no need to do extra stuff + //no need to do extra stuff + { if ( schema is DirectShapeFreeformViewModel || schema is BlockDefinitionViewModel @@ -327,15 +351,21 @@ schema is DirectShapeFreeformViewModel || schema is RevitDefaultPipeViewModel || schema is RevitDefaultDuctViewModel ) + { updatedSchemas.Add(schema); + } //add revit info else + { switch (schema) { case RevitWallViewModel o: var wallFamilies = AvailableRevitTypes.Where(x => x.category == "Walls").ToList(); if (!wallFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var wallFamiliesViewModels = wallFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -348,7 +378,10 @@ schema is DirectShapeFreeformViewModel case RevitProfileWallViewModel o: var profileWallFamilies = AvailableRevitTypes.Where(x => x.category == "Walls").ToList(); if (!profileWallFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var profileWallFamiliesViewModels = profileWallFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -361,7 +394,10 @@ schema is DirectShapeFreeformViewModel case RevitFaceWallViewModel o: var faceWallFamilies = AvailableRevitTypes.Where(x => x.family == "Basic Wall").ToList(); if (!faceWallFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var faceWallFamiliesViewModels = faceWallFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -374,7 +410,10 @@ schema is DirectShapeFreeformViewModel case RevitFloorViewModel o: var floorFamilies = AvailableRevitTypes.Where(x => x.category == "Floors").ToList(); if (!floorFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var floorFamiliesViewModels = floorFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -387,7 +426,10 @@ schema is DirectShapeFreeformViewModel case RevitCeilingViewModel o: var ceilingFamilies = AvailableRevitTypes.Where(x => x.category == "Ceilings").ToList(); if (!ceilingFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var ceilingFamiliesViewModels = ceilingFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -400,7 +442,10 @@ schema is DirectShapeFreeformViewModel case RevitFootprintRoofViewModel o: var roofFamilies = AvailableRevitTypes.Where(x => x.category == "Roofs").ToList(); if (!roofFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var roofFamiliesViewModels = roofFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -413,7 +458,10 @@ schema is DirectShapeFreeformViewModel case RevitBeamViewModel o: var beamFamilies = AvailableRevitTypes.Where(x => x.category == "Structural Framing").ToList(); if (!beamFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var beamFamiliesViewModels = beamFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -426,7 +474,10 @@ schema is DirectShapeFreeformViewModel case RevitBraceViewModel o: var braceFamilies = AvailableRevitTypes.Where(x => x.category == "Structural Framing").ToList(); if (!braceFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var braceFamiliesViewModels = braceFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -439,7 +490,10 @@ schema is DirectShapeFreeformViewModel case RevitColumnViewModel o: var columnFamilies = AvailableRevitTypes.Where(x => x.category == "Structural Columns").ToList(); if (!columnFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var columnFamiliesViewModels = columnFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -455,7 +509,10 @@ schema is DirectShapeFreeformViewModel .Cast() .ToList(); if (!pipeFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var pipeFamiliesViewModels = pipeFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList(), g.First().shape)) @@ -471,7 +528,10 @@ schema is DirectShapeFreeformViewModel .Cast() .ToList(); if (!ductFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var ductFamiliesViewModels = ductFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList(), g.First().shape)) @@ -486,7 +546,10 @@ schema is DirectShapeFreeformViewModel .Where(x => x is RevitSymbolElementType symbol && symbol.placementType == "OneLevelBased") .ToList(); if (!fiFamilies.Any() || !AvailableRevitLevels.Any()) + { break; + } + var fiFamiliesViewModels = fiFamilies .GroupBy(x => x.family) .Select(g => new RevitFamily(g.Key.ToString(), g.Select(y => y.type).ToList())) @@ -496,6 +559,8 @@ schema is DirectShapeFreeformViewModel updatedSchemas.Add(o); break; } + } + } //var revitMetadata = new List(); @@ -530,7 +595,9 @@ schema is DirectShapeFreeformViewModel public bool CanSetMappingsCommand(object parameter) { if (SelectedSchema == null) + { return false; + } //TODO: trigger refresh as any of these changes so we can check if schema is valid //var vals = SelectedSchema.GetType().GetProperties() // .Select(p => p.GetValue(SelectedSchema)).ToList(); @@ -565,7 +632,9 @@ private List GetCheckedBoxesIds() .OfType() .Where(x => x.Classes.Contains("ExistingMapping")); foreach (var lBox in lBoxes) + { ids.AddRange(lBox.SelectedItems.Cast().Where(x => x != null).Select(x => x.ApplicationId)); + } } catch (Exception ex) { diff --git a/DesktopUI2/DesktopUI2/ViewModels/MappingTool/Schemas.cs b/DesktopUI2/DesktopUI2/ViewModels/MappingTool/Schemas.cs index a191e8ed7f..9d9d254138 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/MappingTool/Schemas.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/MappingTool/Schemas.cs @@ -69,11 +69,15 @@ public List Families SelectedFamily = Families?.FirstOrDefault(x => x.Name == SelectedFamily?.Name); //fall back on first option if (SelectedFamily == null) + { SelectedFamily = Families?.FirstOrDefault(); + } SelectedType = SelectedFamily?.Types?.FirstOrDefault(x => x == SelectedType); if (SelectedType == null) + { SelectedType = SelectedFamily?.Types?.FirstOrDefault(); + } } } @@ -109,7 +113,9 @@ public List Levels //force the refresh of the dropdown after these lists have been updated SelectedLevel = Levels?.FirstOrDefault(x => x == SelectedLevel); if (SelectedLevel == null) + { SelectedLevel = Levels?.FirstOrDefault(); + } } } @@ -426,7 +432,9 @@ public override string GetSerializedSchema() { //TODO: look into supporting the category and name filed for freeform elements too if (Freeform) + { return Operations.Serialize(new FreeformElement()); + } var cat = RevitCategory.GenericModel; Enum.TryParse(SelectedCategory, out cat); @@ -479,7 +487,9 @@ public override string GetSerializedSchema() { var res = Enum.TryParse(SelectedCategory, out RevitCategory cat); if (!res) + { cat = RevitCategory.GenericModel; + } var ds = new MappedBlockWrapper(); //don't use the constructor ds.category = cat.ToString(); diff --git a/DesktopUI2/DesktopUI2/ViewModels/MenuItemViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/MenuItemViewModel.cs index 363db8ea8f..1cafc899c6 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/MenuItemViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/MenuItemViewModel.cs @@ -21,15 +21,21 @@ public MenuItemViewModel(MenuItem item, object commandParameter) MaterialIconKind icon; if (Enum.TryParse(item.Icon, out icon)) + { Icon = new MaterialIcon { Kind = icon, Foreground = Brushes.Gray }; + } if (item.Action != null) + { Command = ReactiveCommand.Create(item.Action); + } CommandParameter = commandParameter; if (item.Items != null) + { Items = item.Items.Select(x => new MenuItemViewModel(x, commandParameter)).ToList(); + } } //public MenuItemViewModel(ICommand command, object commandParameter, string header, MaterialIconKind icon) diff --git a/DesktopUI2/DesktopUI2/ViewModels/OneClickViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/OneClickViewModel.cs index e2cc665974..88795f6bb3 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/OneClickViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/OneClickViewModel.cs @@ -64,12 +64,17 @@ public async void Send() //filename is different, might have been renamed or be a different document if (_fileName != fileName) + { _fileStream = null; + } _fileName = fileName; if (_fileStream == null) + { _fileStream = await GetOrCreateStreamState().ConfigureAwait(true); + } + // check if objs are selected and set streamstate filter var filters = Bindings.GetSelectionFilters(); var selection = Bindings.GetSelectedObjects(); @@ -147,9 +152,11 @@ public async void Send() } if (HomeViewModel.Instance != null) + { HomeViewModel.Instance.AddSavedStream( new StreamViewModel(_fileStream, HostScreen, HomeViewModel.Instance.RemoveSavedStreamCommand) ); + } } private async Task GetOrCreateStreamState() @@ -163,12 +170,17 @@ private async Task GetOrCreateStreamState() .Where(o => o.CachedStream.name == _fileName && o.Client.Account == account) ?.FirstOrDefault(); if (fileStream != null) + { return fileStream; + } + // try to find stream in account var foundStream = await SearchStreams(client).ConfigureAwait(true); if (foundStream != null) + { return new StreamState(account, foundStream) { BranchName = "main" }; + } // create the stream string streamId = await client @@ -215,7 +227,10 @@ private void ShareCommand() private void CloseSendModal() { if (Progress.IsProgressing) + { Progress.CancelCommand(); + } + SendClicked = false; } @@ -286,7 +301,10 @@ private string Url { var commit = ""; if (!string.IsNullOrEmpty(Id)) + { commit = "commits/" + Id; + } + return $"{_fileStream.ServerUrl.TrimEnd('/')}/streams/{_fileStream.StreamId}/{commit}"; } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/ProgressViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/ProgressViewModel.cs index de98f66d30..61bd5386ed 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/ProgressViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/ProgressViewModel.cs @@ -46,7 +46,10 @@ public ConcurrentDictionary ProgressDict { ProgressSummary = ""; foreach (var kvp in value) + { ProgressSummary += $"{kvp.Key}: {kvp.Value} "; + } + //NOTE: progress set to indeterminate until the TotalChildrenCount is correct ProgressSummary += $"Total: {Max}"; @@ -96,7 +99,9 @@ public bool IsProgressing { this.RaiseAndSetIfChanged(ref _isProgressing, value); if (!IsProgressing && Value != 0) + { ProgressSummary = "Done!"; + } } } diff --git a/DesktopUI2/DesktopUI2/ViewModels/SchedulerViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/SchedulerViewModel.cs index 66bfbe994d..37f8a17578 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/SchedulerViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/SchedulerViewModel.cs @@ -82,7 +82,9 @@ public Trigger SelectedTrigger private bool CanSaveCommand(object parameter) { if (SelectedTrigger == null || SelectedTrigger == null) + { return false; + } return true; } @@ -107,6 +109,7 @@ private void SaveCommand() //updating the list of streams, in case stuff has changes in the mian DUI SavedStreams = Bindings.GetStreamsInFile(); foreach (var stream in SavedStreams) + { if (stream.Id == SelectedStream.Id && Enabled) { stream.SchedulerEnabled = true; @@ -116,13 +119,16 @@ private void SaveCommand() { stream.SchedulerEnabled = false; } + } Bindings.WriteStreamsToFile(SavedStreams.ToList()); Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Scheduler Set" } }); if (HomeViewModel.Instance != null) + { HomeViewModel.Instance.UpdateSavedStreams(SavedStreams.ToList()); + } Scheduler.Instance.Close(); } diff --git a/DesktopUI2/DesktopUI2/ViewModels/SettingsPageViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/SettingsPageViewModel.cs index ad5017c7b0..c993a3ad4e 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/SettingsPageViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/SettingsPageViewModel.cs @@ -39,11 +39,13 @@ public void SaveCommand() var settingData = new Dictionary { { "name", "Settings Save" } }; foreach (var setting in Settings) + { try { settingData.Add(setting.Setting.Slug, setting.Setting.Selection); } catch { } + } Analytics.TrackEvent(Analytics.Events.DUIAction, settingData); } diff --git a/DesktopUI2/DesktopUI2/ViewModels/StreamSelectorViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/StreamSelectorViewModel.cs index fb5946b9f6..0d01c176d9 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/StreamSelectorViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/StreamSelectorViewModel.cs @@ -37,7 +37,9 @@ private void SearchStreams() private async Task GetStreams() { if (!Accounts.Any()) + { return; + } ShowProgress = true; @@ -50,7 +52,9 @@ private async Task GetStreams() foreach (var account in Accounts) { if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } try { @@ -58,15 +62,21 @@ private async Task GetStreams() //NO SEARCH if (string.IsNullOrEmpty(SearchQuery)) + { result = await account.Client.StreamsGet(25, StreamGetCancelTokenSource.Token).ConfigureAwait(true); + } //SEARCH else + { result = await account.Client .StreamSearch(SearchQuery, 25, StreamGetCancelTokenSource.Token) .ConfigureAwait(true); + } if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } streams.AddRange(result.Select(x => new StreamAccountWrapper(x, account.Account))); } @@ -78,7 +88,9 @@ private async Task GetStreams() } } if (StreamGetCancelTokenSource.IsCancellationRequested) + { return; + } try { @@ -103,7 +115,9 @@ private async void GetBranches() .ToList(); if (Branches.Any()) + { SelectedBranch = Branches.FirstOrDefault(); + } } private void ClearSearchCommand() @@ -159,9 +173,14 @@ public string SearchQuery { this.RaiseAndSetIfChanged(ref _searchQuery, value); if (_noSearch) + { return; + } + if (!string.IsNullOrEmpty(SearchQuery) && SearchQuery.Length <= 2) + { return; + } streamSearchDebouncer(); } diff --git a/DesktopUI2/DesktopUI2/ViewModels/StreamViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/StreamViewModel.cs index b300eda3c1..a054a2a240 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/StreamViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/StreamViewModel.cs @@ -57,7 +57,9 @@ public StreamViewModel(StreamState streamState, IScreen hostScreen, ICommand rem //default to receive mode if no permission to send if (Stream.role == null || Stream.role == "stream:reviewer") + { IsReceiver = true; + } HostScreen = hostScreen; RemoveSavedStreamCommand = removeSavedStreamCommand; @@ -101,15 +103,22 @@ private string Url if (!IsReceiver) { if (SelectedBranch != null && SelectedBranch.Branch.name != "main") + { return $"{StreamState.ServerUrl.TrimEnd('/')}/projects/{StreamState.StreamId}/models/{SelectedBranch.Branch.id}"; + } } //receiver else { if (SelectedCommit != null && SelectedCommit.id != ConnectorHelpers.LatestCommitString) + { return $"{StreamState.ServerUrl.TrimEnd('/')}/projects/{StreamState.StreamId}/models/{SelectedBranch.Branch.id}@{SelectedCommit.id}"; + } + if (SelectedBranch != null) + { return $"{StreamState.ServerUrl.TrimEnd('/')}/projects/{StreamState.StreamId}/models/{SelectedBranch.Branch.id}"; + } } return $"{StreamState.ServerUrl.TrimEnd('/')}/projects/{StreamState.StreamId}"; @@ -119,15 +128,22 @@ private string Url if (!IsReceiver) { if (SelectedBranch != null && SelectedBranch.Branch.name != "main") + { return $"{StreamState.ServerUrl.TrimEnd('/')}/streams/{StreamState.StreamId}/branches/{Uri.EscapeDataString(SelectedBranch.Branch.name)}"; + } } //receiver else { if (SelectedCommit != null && SelectedCommit.id != ConnectorHelpers.LatestCommitString) + { return $"{StreamState.ServerUrl.TrimEnd('/')}/streams/{StreamState.StreamId}/commits/{SelectedCommit.id}"; + } + if (SelectedBranch != null) + { return $"{StreamState.ServerUrl.TrimEnd('/')}/streams/{StreamState.StreamId}/branches/{Uri.EscapeDataString(SelectedBranch.Branch.name)}"; + } } return $"{StreamState.ServerUrl.TrimEnd('/')}/streams/{StreamState.StreamId}"; @@ -186,7 +202,9 @@ private void GenerateMenuItems() }; var customMenues = Bindings.GetCustomStreamMenuItems(); if (customMenues != null) + { menu.Items.AddRange(customMenues.Select(x => new MenuItemViewModel(x, StreamState)).ToList()); + } //remove is added last //menu.Items.Add(new MenuItemViewModel(RemoveSavedStreamCommand, StreamState.Id, "Remove", MaterialIconKind.Bin)); MenuItems.Add(menu); @@ -233,7 +251,9 @@ internal async void GetBranchesAndRestoreState() ReceiveModes = Bindings.GetReceiveModes(); if (!ReceiveModes.Any()) + { throw new InvalidOperationException("No Receive Mode is available."); + } //by default the first available receive mode is selected SelectedReceiveMode = ReceiveModes.Contains(StreamState.ReceiveMode) @@ -276,7 +296,9 @@ internal async void GetBranchesAndRestoreState() { SelectedFilter = AvailableFilters.FirstOrDefault(x => x.Filter.Slug == StreamState.Filter.Slug); if (SelectedFilter != null) + { SelectedFilter.Filter = StreamState.Filter; + } } else { @@ -291,13 +313,19 @@ internal async void GetBranchesAndRestoreState() } } - if (StreamState.Settings != null) - foreach (var setting in Settings) + if (StreamState.Settings == null) + { + return; + } + + foreach (var setting in Settings) + { + var savedSetting = StreamState.Settings.FirstOrDefault(o => o.Slug == setting.Slug); + if (savedSetting != null) { - var savedSetting = StreamState.Settings.FirstOrDefault(o => o.Slug == setting.Slug); - if (savedSetting != null) - setting.Selection = savedSetting.Selection; + setting.Selection = savedSetting.Selection; } + } } catch (Exception ex) { @@ -387,7 +415,9 @@ private async void ScrollToBottom() { var scroller = StreamEditView.Instance.FindControl("activityScroller"); if (scroller != null) + { scroller.ScrollToEnd(); + } }); } } @@ -415,9 +445,15 @@ private void UpdateStreamState() StreamState.ReceiveMode = SelectedReceiveMode; if (IsReceiver) + { StreamState.CommitId = SelectedCommit.id; + } + if (!IsReceiver) + { StreamState.Filter = SelectedFilter.Filter; + } + StreamState.Settings = Settings.Select(o => o).ToList(); } catch (Exception ex) @@ -435,9 +471,13 @@ private async Task GetBranches() var index = Branches.FindIndex(x => x.name == prevBranchName); if (index != -1) + { SelectedBranch = BranchesViewModel[index]; + } else + { SelectedBranch = BranchesViewModel[0]; + } } catch (Exception ex) { @@ -465,9 +505,13 @@ private async Task GetCommits() var commit = Commits.FirstOrDefault(x => x.id == prevCommitId); if (commit != null) + { SelectedCommit = commit; + } else + { SelectedCommit = Commits[0]; + } } else { @@ -529,7 +573,9 @@ public async Task DownloadImage360(string url) //the default 360 image width is 34300 //this is a quick hack to see if the returned image is not an error image like "you do not have access" etc if (_previewImage360.Size.Width > 30000) + { PreviewImage360Loaded = true; + } } catch (Exception ex) { @@ -559,7 +605,10 @@ public bool PreviewOn if (value == false && value != _previewOn) { if (Progress.IsPreviewProgressing) + { Progress.IsPreviewProgressing = false; + } + Bindings.ResetDocument(); } @@ -601,7 +650,10 @@ public string LastUsed { var verb = StreamState.IsReceiver ? "Received" : "Sent"; if (StreamState.LastUsed == null) + { return $"Never {verb.ToLower()}"; + } + return $"{verb} {Formatting.TimeAgo(StreamState.LastUsed)}"; } } @@ -662,7 +714,10 @@ public void GoBack() Bindings.ResetDocument(); //if not a saved stream dispose client and subs if (!HomeViewModel.Instance.SavedStreams.Any(x => x._guid == _guid)) + { Client.Dispose(); + } + MainViewModel.GoHome(); } @@ -677,7 +732,10 @@ public bool IsReceiver set { if (value != _isReceiver) + { PreviewOn = false; + } + this.RaiseAndSetIfChanged(ref _isReceiver, value); this.RaisePropertyChanged(nameof(BranchesViewModel)); } @@ -709,12 +767,18 @@ public BranchViewModel SelectedBranch this.RaiseAndSetIfChanged(ref _selectedBranch, value); if (value == null) + { return; + } if (value.Branch.id == null) + { AddNewBranch(); + } else + { GetCommits(); + } } } @@ -738,17 +802,25 @@ public List BranchesViewModel get { if (Branches == null) + { return new List(); + } if (_branchesViewModel == null) + { _branchesViewModel = Branches.Select(x => new BranchViewModel(x)).ToList(); + } //start fresh, just in case if (_branchesViewModel.Last().Branch.id == null) + { _branchesViewModel.Remove(_branchesViewModel.Last()); + } if (!IsReceiver) + { _branchesViewModel.Add(new BranchViewModel(new Branch { name = "Add New Branch" }, "Plus")); + } return _branchesViewModel; } @@ -766,11 +838,16 @@ public Commit SelectedCommit if (_selectedCommit != null) { if (_selectedCommit.id == ConnectorHelpers.LatestCommitString) + { PreviewImageUrl = Client.Account.serverInfo.url + $"/preview/{Stream.id}/branches/{Uri.EscapeDataString(SelectedBranch.Branch.name)}"; + } else + { PreviewImageUrl = Client.Account.serverInfo.url + $"/preview/{Stream.id}/commits/{_selectedCommit.id}"; + } + PreviewImageUrl360 = $"{PreviewImageUrl}/all"; } } @@ -814,7 +891,9 @@ public List FilteredReport get { if (string.IsNullOrEmpty(SearchQuery) && !_reportSelectedFilterItems.Any()) + { return Report; + } var filterItems = _reportSelectedFilterItems.Any() ? Report.Where(o => _reportSelectedFilterItems.Any(a => o.Status == a)).ToList() @@ -857,11 +936,18 @@ public string SearchQuery { this.RaiseAndSetIfChanged(ref _searchQuery, value); if (string.IsNullOrEmpty(SearchQuery)) + { _searchQueryItems.Clear(); + } else if (!SearchQuery.Replace(" ", "").Any()) + { ClearSearchCommand(); + } else + { _searchQueryItems = _searchQuery.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + } + this.RaisePropertyChanged(nameof(FilteredReport)); } } @@ -883,11 +969,20 @@ private void ReportFilterSelectionChanged(object sender, SelectionModelSelection try { foreach (var a in e.SelectedItems) + { if (!_reportSelectedFilterItems.Contains(a as string)) + { _reportSelectedFilterItems.Add(a as string); + } + } + foreach (var r in e.DeselectedItems) + { if (_reportSelectedFilterItems.Contains(r as string)) + { _reportSelectedFilterItems.Remove(r as string); + } + } this.RaisePropertyChanged(nameof(FilteredReport)); } @@ -916,10 +1011,13 @@ public FilterViewModel SelectedFilter //trigger change when any property in the child model view changes //used for the CanSave etc button bindings if (value != null) + { value.PropertyChanged += (s, eo) => { this.RaisePropertyChanged(); }; + } + this.RaiseAndSetIfChanged(ref _selectedFilter, value); } } @@ -1044,15 +1142,21 @@ private async void Client_OnCommentActivity(object sender, CommentItem e) { var author = await Client.OtherUserGet(e.authorId).ConfigureAwait(true); if (author == null) + { authorName = "Unknown"; + } else + { authorName = author.name; + } } bool openStream = true; var svm = MainViewModel.RouterInstance.NavigationStack.Last() as StreamViewModel; if (svm != null && svm.Stream.id == Stream.id) + { openStream = false; + } Dispatcher.UIThread.Post(() => { @@ -1064,7 +1168,9 @@ private async void Client_OnCommentActivity(object sender, CommentItem e) OnClick = () => { if (openStream) + { MainViewModel.RouterInstance.Navigate.Execute(this); + } SelectedTab = 3; }, @@ -1083,13 +1189,17 @@ private async void Client_OnCommentActivity(object sender, CommentItem e) private async void Client_OnBranchChange(object sender, BranchInfo info) { if (!_isAddingBranches) + { await GetBranches().ConfigureAwait(true); + } } private async void Client_OnCommitChange(object sender, CommitInfo info) { if (info.branchName == SelectedBranch.Branch.name) + { await GetCommits().ConfigureAwait(true); + } } private async void Client_OnCommitCreated(object sender, CommitInfo info) @@ -1097,10 +1207,14 @@ private async void Client_OnCommitCreated(object sender, CommitInfo info) try { if (info.branchName == SelectedBranch.Branch.name) + { await GetCommits().ConfigureAwait(true); + } if (!IsReceiver) + { return; + } var authorName = "You"; if (info.authorId != Client.Account.userInfo.id) @@ -1114,7 +1228,9 @@ private async void Client_OnCommitCreated(object sender, CommitInfo info) //if in stream edit open online var svm = MainViewModel.RouterInstance.NavigationStack.Last() as StreamViewModel; if (svm != null && svm.Stream.id == Stream.id) + { openOnline = true; + } Dispatcher.UIThread.Post(() => { @@ -1127,10 +1243,14 @@ private async void Client_OnCommitCreated(object sender, CommitInfo info) { //if in stream edit open online if (openOnline) + { ViewOnlineSavedStreamCommand(); + } //if on home, open stream else + { MainViewModel.RouterInstance.Navigate.Execute(this); + } }, Type = NotificationType.Success, Expiration = TimeSpan.FromSeconds(10) @@ -1141,7 +1261,9 @@ private async void Client_OnCommitCreated(object sender, CommitInfo info) ScrollToBottom(); if (AutoReceive) + { ReceiveCommand(); + } } catch (Exception ex) { @@ -1176,6 +1298,7 @@ private async void AddNewBranch() var result = await dialog.ShowDialog().ConfigureAwait(true); if (result) + { try { _isAddingBranches = true; @@ -1193,7 +1316,9 @@ private async void AddNewBranch() var index = Branches.FindIndex(x => x.name == nbvm.BranchName); if (index != -1) + { SelectedBranch = BranchesViewModel[index]; + } Analytics.TrackEvent( Analytics.Events.DUIAction, @@ -1209,9 +1334,12 @@ private async void AddNewBranch() { _isAddingBranches = false; } + } else + { //make sure the a branch is selected if canceled SelectedBranch = BranchesViewModel[0]; + } } public async void CopyReportCommand() @@ -1273,7 +1401,9 @@ public async void SendCommand() Progress.IsProgressing = true; if (!await Http.UserHasInternet().ConfigureAwait(true)) + { throw new InvalidOperationException("Could not reach the internet, are you connected?"); + } Progress.CancellationToken.ThrowIfCancellationRequested(); @@ -1286,7 +1416,10 @@ public async void SendCommand() // This is a last ditch effort to display a semi-useful error to the user. string message = Progress?.Report?.OperationErrorsString; if (string.IsNullOrEmpty(message)) + { message = "Something went very wrong"; + } + throw new Exception(message); } @@ -1317,7 +1450,10 @@ public async void SendCommand() { var url = $"{StreamState.ServerUrl}/streams/{StreamState.StreamId}/commits/{commitId}"; if (Client.Account.serverInfo.frontend2) + { url = $"{StreamState.ServerUrl}/projects/{StreamState.StreamId}/models/{SelectedBranch.Branch.id}"; + } + OpenUrl(url); }, Type = NotificationType.Success, @@ -1367,10 +1503,14 @@ public async void PreviewCommand() Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", previewName } }); if (IsReceiver) + { await Task.Run(() => Bindings.PreviewReceive(StreamState, Progress)).ConfigureAwait(true); + } else + { //NOTE: do not wrap in a Task or it will crash Revit Bindings.PreviewSend(StreamState, Progress); + } GetReport(); SpeckleLog.Logger @@ -1399,7 +1539,9 @@ public async void ReceiveCommand() Progress.IsProgressing = true; if (!await Http.UserHasInternet().ConfigureAwait(true)) + { throw new InvalidOperationException("Could not reach the internet, are you connected?"); + } Progress.CancellationToken.ThrowIfCancellationRequested(); @@ -1412,7 +1554,10 @@ public async void ReceiveCommand() // This is a last ditch effort to display a semi-useful error to the user. string message = Progress?.Report?.OperationErrorsString; if (string.IsNullOrEmpty(message)) + { message = "Something went very wrong"; + } + throw new Exception(message); } @@ -1451,10 +1596,14 @@ public async void ReceiveCommand() var warningsCount = Progress.Report.OperationErrors.Count + Progress.Report.ConversionErrors.Count; if (warningsCount > 0) + { successMessage = $"There were {warningsCount} warning(s)"; + } else if (Progress.CancellationToken.IsCancellationRequested) - // User requested a cancel, but it was too late! + // User requested a cancel, but it was too late! + { successMessage = "It was too late to cancel"; + } DisplayPopupNotification( new PopUpNotificationViewModel @@ -1610,17 +1759,21 @@ private void SaveCommand() HomeViewModel.Instance.AddSavedStream(this); if (IsReceiver) + { Analytics.TrackEvent( Client.Account, Analytics.Events.DUIAction, new Dictionary { { "name", "Stream Receiver Add" } } ); + } else + { Analytics.TrackEvent( Client.Account, Analytics.Events.DUIAction, new Dictionary { { "name", "Stream Sender Add" } } ); + } MainUserControl.NotificationManager.Show( new PopUpNotificationViewModel @@ -1712,28 +1865,43 @@ private bool CanPreviewCommand(object parameter) { bool previewImplemented = IsReceiver ? Bindings.CanPreviewReceive : Bindings.CanPreviewSend; if (previewImplemented) + { return IsReady(); + } + return false; } private bool IsReady() { if (NoAccess) + { return false; + } + if (SelectedBranch == null) + { return false; + } if (!IsReceiver) { if (SelectedFilter == null) + { return false; + } + if (!SelectedFilter.IsReady()) + { return false; + } } else { if (SelectedCommit == null) + { return false; + } } return true; diff --git a/DesktopUI2/DesktopUI2/ViewModels/TypeMappingOnReceiveViewModel.cs b/DesktopUI2/DesktopUI2/ViewModels/TypeMappingOnReceiveViewModel.cs index ac0b132634..b29a181565 100644 --- a/DesktopUI2/DesktopUI2/ViewModels/TypeMappingOnReceiveViewModel.cs +++ b/DesktopUI2/DesktopUI2/ViewModels/TypeMappingOnReceiveViewModel.cs @@ -8,116 +8,113 @@ using ReactiveUI; using Speckle.Core.Logging; -namespace DesktopUI2.ViewModels +namespace DesktopUI2.ViewModels; + +public class TypeMappingOnReceiveViewModel : ReactiveObject, IRoutableViewModel { - public class TypeMappingOnReceiveViewModel : ReactiveObject, IRoutableViewModel - { - public const string UnmappedKey = "New Incoming Types"; - private string _searchQuery; + public const string UnmappedKey = "New Incoming Types"; + private string _searchQuery; - private string _selectedCategory; + private string _selectedCategory; - private ISingleValueToMap _selectedMappingValue; + private ISingleValueToMap _selectedMappingValue; - private List _visibleMappingValues; - public bool DoneMapping; + private List _visibleMappingValues; + public bool DoneMapping; - public const string TypeCatMisc = "Miscellaneous"; + public const string TypeCatMisc = "Miscellaneous"; - public TypeMappingOnReceiveViewModel( - ITypeMap typeMap, - IHostTypeContainer container, - bool newTypesExist = false - ) - { - Mapping = typeMap; - hostTypeContainer = container; - SelectedCategory = Mapping.Categories.First(); + public TypeMappingOnReceiveViewModel(ITypeMap typeMap, IHostTypeContainer container, bool newTypesExist = false) + { + Mapping = typeMap; + hostTypeContainer = container; + SelectedCategory = Mapping.Categories.First(); - Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Mappings Open" } }); - } + Analytics.TrackEvent(Analytics.Events.DUIAction, new Dictionary { { "name", "Mappings Open" } }); + } - public ReactiveCommand GoBack => MainViewModel.RouterInstance.NavigateBack; + public ReactiveCommand GoBack => MainViewModel.RouterInstance.NavigateBack; - private readonly IHostTypeContainer hostTypeContainer; + private readonly IHostTypeContainer hostTypeContainer; - public string SearchQuery + public string SearchQuery + { + get => _searchQuery; + set { - get => _searchQuery; - set - { - this.RaiseAndSetIfChanged(ref _searchQuery, value); + this.RaiseAndSetIfChanged(ref _searchQuery, value); - SearchResults = GetCategoryOrAll(SelectedCategory).Where(ht => ht.HostTypeDisplayName.ToLower().Contains(SearchQuery.ToLower())).ToList(); - this.RaisePropertyChanged(nameof(SearchResults)); - } + SearchResults = GetCategoryOrAll(SelectedCategory) + .Where(ht => ht.HostTypeDisplayName.ToLower().Contains(SearchQuery.ToLower())) + .ToList(); + this.RaisePropertyChanged(nameof(SearchResults)); } + } - private ISingleHostType _selectedType; - public ISingleHostType SelectedType + private ISingleHostType _selectedType; + public ISingleHostType SelectedType + { + get => _selectedType; + set { - get => _selectedType; - set + if (SelectedMappingValues.Count > 0) { - if (SelectedMappingValues.Count > 0) + foreach (var val in SelectedMappingValues) { - foreach (var val in SelectedMappingValues) - { - val.MappedHostType = value; - } + val.MappedHostType = value; } - this.RaiseAndSetIfChanged(ref _selectedType, value); } + this.RaiseAndSetIfChanged(ref _selectedType, value); } + } - public ITypeMap Mapping { get; set; } + public ITypeMap Mapping { get; set; } - public string SelectedCategory + public string SelectedCategory + { + get => _selectedCategory; + set { - get => _selectedCategory; - set - { - this.RaiseAndSetIfChanged(ref _selectedCategory, value); - VisibleMappingValues = Mapping.GetValuesToMapOfCategory(value).ToList(); - SearchQuery = ""; - SearchResults = GetCategoryOrAll(value).ToList(); - SelectedMappingValues.Clear(); - } + this.RaiseAndSetIfChanged(ref _selectedCategory, value); + VisibleMappingValues = Mapping.GetValuesToMapOfCategory(value).ToList(); + SearchQuery = ""; + SearchResults = GetCategoryOrAll(value).ToList(); + SelectedMappingValues.Clear(); } + } - public List VisibleMappingValues - { - get => _visibleMappingValues; - set => this.RaiseAndSetIfChanged(ref _visibleMappingValues, value); - } + public List VisibleMappingValues + { + get => _visibleMappingValues; + set => this.RaiseAndSetIfChanged(ref _visibleMappingValues, value); + } - public ObservableCollection SelectedMappingValues { get; } = new(); + public ObservableCollection SelectedMappingValues { get; } = new(); - private List _searchResults; - public List SearchResults - { - get => _searchResults; - set => this.RaiseAndSetIfChanged(ref _searchResults, value); - } + private List _searchResults; + public List SearchResults + { + get => _searchResults; + set => this.RaiseAndSetIfChanged(ref _searchResults, value); + } - private ICollection GetCategoryOrAll(string category) - { - return hostTypeContainer.GetTypesInCategory(category) ?? hostTypeContainer.GetAllTypes(); - } + private ICollection GetCategoryOrAll(string category) + { + return hostTypeContainer.GetTypesInCategory(category) ?? hostTypeContainer.GetAllTypes(); + } - public string UrlPathSegment => throw new NotImplementedException(); + public string UrlPathSegment => throw new NotImplementedException(); - public IScreen HostScreen => throw new NotImplementedException(); + public IScreen HostScreen => throw new NotImplementedException(); - public void ImportFamilyCommand() - { - MappingViewDialog.Instance.Close(Mapping); - } + public void ImportFamilyCommand() + { + MappingViewDialog.Instance.Close(Mapping); + } - public void Done() - { - DoneMapping = true; - MappingViewDialog.Instance.Close(Mapping); - } + public void Done() + { + DoneMapping = true; + MappingViewDialog.Instance.Close(Mapping); } } diff --git a/DesktopUI2/DesktopUI2/Views/AttachedProperties/BlockSelection.cs b/DesktopUI2/DesktopUI2/Views/AttachedProperties/BlockSelection.cs index a9ec1f2af2..f4c8807828 100644 --- a/DesktopUI2/DesktopUI2/Views/AttachedProperties/BlockSelection.cs +++ b/DesktopUI2/DesktopUI2/Views/AttachedProperties/BlockSelection.cs @@ -30,7 +30,9 @@ public static void SetIsSelectionBlocked(ListBoxItem item, bool value) private static void IsSelectionBlockedChanged(ListBoxItem item, AvaloniaPropertyChangedEventArgs e) { if (!(e.OldValue is bool oldValue) || !(e.NewValue is bool newValue) || oldValue == newValue) + { return; + } if (newValue) { diff --git a/DesktopUI2/DesktopUI2/Views/Controls/StreamEditControls/Receive.xaml.cs b/DesktopUI2/DesktopUI2/Views/Controls/StreamEditControls/Receive.xaml.cs index 85d1899281..e6ea7baa95 100644 --- a/DesktopUI2/DesktopUI2/Views/Controls/StreamEditControls/Receive.xaml.cs +++ b/DesktopUI2/DesktopUI2/Views/Controls/StreamEditControls/Receive.xaml.cs @@ -36,7 +36,10 @@ private void PreviewBox360_PointerEnter(object sender, PointerEventArgs e) { var svm = PreviewBox360.DataContext as StreamViewModel; if (!svm.PreviewImage360Loaded) + { return; + } + Image360.Opacity = 1; ImageBasic.IsVisible = false; } @@ -50,7 +53,10 @@ private void PreviewBox360_PointerLeave(object sender, PointerEventArgs e) private void SetMargin(double mouseX) { if (mouseX == 0) + { mouseX = 1; + } + var imageWidth = Image360.Bounds.Width == 0 ? 34300 : Image360.Bounds.Width; //34300 var imageStepWidth = imageWidth / 24.5; //1400 - WHY 24.5??? There seems to be some f* offset at the ends var imageOffset = (imageWidth - imageStepWidth * 24) / 2; @@ -60,7 +66,9 @@ private void SetMargin(double mouseX) var index = Math.Abs(Math.Round(mouseX / stepWidth)); if (index >= 24) + { index = 24 - 1; + } var centerOffset = (imageStepWidth - viewboxWidth) / 2; //since the image fram is wider, let's center the model diff --git a/DesktopUI2/DesktopUI2/Views/Converters/OpacityDoubleConverter.cs b/DesktopUI2/DesktopUI2/Views/Converters/OpacityDoubleConverter.cs index 50b14a9fca..7ac714d543 100644 --- a/DesktopUI2/DesktopUI2/Views/Converters/OpacityDoubleConverter.cs +++ b/DesktopUI2/DesktopUI2/Views/Converters/OpacityDoubleConverter.cs @@ -11,7 +11,10 @@ public object Convert(object value, Type targetType, object parameter, CultureIn double result = 0; double.TryParse(value.ToString(), out result); if (result > 0) + { return true; + } + return false; } diff --git a/DesktopUI2/DesktopUI2/Views/Converters/OpacityValueConverter.cs b/DesktopUI2/DesktopUI2/Views/Converters/OpacityValueConverter.cs index 8c426f9ae6..40ff67bce3 100644 --- a/DesktopUI2/DesktopUI2/Views/Converters/OpacityValueConverter.cs +++ b/DesktopUI2/DesktopUI2/Views/Converters/OpacityValueConverter.cs @@ -9,7 +9,10 @@ public class OpacityValueConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && (bool)value) + { return 0.5; + } + return 1; } diff --git a/DesktopUI2/DesktopUI2/Views/Converters/RoleValueConverter.cs b/DesktopUI2/DesktopUI2/Views/Converters/RoleValueConverter.cs index c6fe9d7c41..e165ab9b18 100644 --- a/DesktopUI2/DesktopUI2/Views/Converters/RoleValueConverter.cs +++ b/DesktopUI2/DesktopUI2/Views/Converters/RoleValueConverter.cs @@ -9,14 +9,20 @@ public class RoleValueConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) + { return "public stream"; + } + return value.ToString().Replace("stream:", ""); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) + { return null; + } + return "stream:" + value; } } diff --git a/DesktopUI2/DesktopUI2/Views/Converters/StringOpacityValueConverter.cs b/DesktopUI2/DesktopUI2/Views/Converters/StringOpacityValueConverter.cs index 46ca956b4b..cd30b6da81 100644 --- a/DesktopUI2/DesktopUI2/Views/Converters/StringOpacityValueConverter.cs +++ b/DesktopUI2/DesktopUI2/Views/Converters/StringOpacityValueConverter.cs @@ -9,7 +9,10 @@ public class StringOpacityValueConverter : IValueConverter public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || string.IsNullOrEmpty(value.ToString())) + { return 0; + } + return 1; } diff --git a/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/DialogUserControl.cs b/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/DialogUserControl.cs index ace55311c7..23bb7a9b75 100644 --- a/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/DialogUserControl.cs +++ b/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/DialogUserControl.cs @@ -26,7 +26,9 @@ public Task ShowDialog(IDialogHost host = null) _host = host; if (_host == null && MainViewModel.Instance != null) + { _host = MainViewModel.Instance; + } _host.DialogBody = this; diff --git a/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/IDialog.cs b/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/IDialog.cs index dbe6459a93..d4c7e14bc4 100644 --- a/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/IDialog.cs +++ b/DesktopUI2/DesktopUI2/Views/Windows/Dialogs/IDialog.cs @@ -3,14 +3,13 @@ using System.Text; using Avalonia.Controls; -namespace DesktopUI2.Views.Windows.Dialogs +namespace DesktopUI2.Views.Windows.Dialogs; + +public interface IDialogHost { - public interface IDialogHost - { - public bool DialogVisible { get; } + public bool DialogVisible { get; } - public double DialogOpacity { get; } + public double DialogOpacity { get; } - public UserControl DialogBody { get; set; } - } + public UserControl DialogBody { get; set; } } diff --git a/Directory.Build.props b/Directory.Build.props index 9efc8b90d9..6763f1030a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -74,9 +74,17 @@ + false + + + $(WarningsAsErrors); + IDE0011;IDE0090;IDE0161; + + + 2.0.999-local diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2023/ConverterAdvanceSteel2023.csproj b/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2023/ConverterAdvanceSteel2023.csproj index 4fd8c34678..b635c47860 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2023/ConverterAdvanceSteel2023.csproj +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2023/ConverterAdvanceSteel2023.csproj @@ -15,6 +15,12 @@ true + + 0 + false + false + + @@ -38,4 +44,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2024/ConverterAdvanceSteel2024.csproj b/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2024/ConverterAdvanceSteel2024.csproj index 8a12efce9f..ab318fc40f 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2024/ConverterAdvanceSteel2024.csproj +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAdvanceSteel2024/ConverterAdvanceSteel2024.csproj @@ -15,6 +15,12 @@ true + + 0 + false + false + + @@ -38,4 +44,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.ASGeometry.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.ASGeometry.cs index 20a1118c94..6b191fad19 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.ASGeometry.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.ASGeometry.cs @@ -34,374 +34,383 @@ using Autodesk.AutoCAD.PlottingServices; using Speckle.Newtonsoft.Json.Linq; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private Point PointToSpeckle(ASPoint3d point, string units = null) { - private Point PointToSpeckle(ASPoint3d point, string units = null) - { - //TODO: handle units.none? - var u = units ?? ModelUnits; - var extPt = ToExternalCoordinates(PointASToAcad(point)); - return new Point(extPt.X, extPt.Y, extPt.Z, u); - } + //TODO: handle units.none? + var u = units ?? ModelUnits; + var extPt = ToExternalCoordinates(PointASToAcad(point)); + return new Point(extPt.X, extPt.Y, extPt.Z, u); + } - private Point3d PointASToAcad(ASPoint3d point) - { - return new Point3d(point.x * FactorFromNative, point.y * FactorFromNative, point.z * FactorFromNative); - } + private Point3d PointASToAcad(ASPoint3d point) + { + return new Point3d(point.x * FactorFromNative, point.y * FactorFromNative, point.z * FactorFromNative); + } - private Point3D PointToMath(ASPoint3d point) - { - return new Point3D(point.x * FactorFromNative, point.y * FactorFromNative, point.z * FactorFromNative); - } + private Point3D PointToMath(ASPoint3d point) + { + return new Point3D(point.x * FactorFromNative, point.y * FactorFromNative, point.z * FactorFromNative); + } - public Vector VectorToSpeckle(ASVector3d vector, string units = null) + public Vector VectorToSpeckle(ASVector3d vector, string units = null) + { + var u = units ?? ModelUnits; + var extV = ToExternalCoordinates(VectorASToAcad(vector)); + return new Vector(extV.X, extV.Y, extV.Z, ModelUnits); + } + private Vector3d VectorASToAcad(ASVector3d vector) + { + return new Vector3d(vector.x * FactorFromNative, vector.y * FactorFromNative, vector.z * FactorFromNative); + } + + private Box BoxToSpeckle(ASBoundBlock3d bound) + { + try { - var u = units ?? ModelUnits; - var extV = ToExternalCoordinates(VectorASToAcad(vector)); - return new Vector(extV.X, extV.Y, extV.Z, ModelUnits); + bound.GetMinMaxPoints(out var point1, out var point2); + // convert min and max pts to speckle first + var min = PointToSpeckle(point1); + var max = PointToSpeckle(point2); + + // get dimension intervals + var xSize = new Interval(min.x, max.x); + var ySize = new Interval(min.y, max.y); + var zSize = new Interval(min.z, max.z); + + // get the base plane of the bounding box from extents and current UCS + var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; + var plane = new AcadGeo.Plane(PointASToAcad(point1), ucs.Xaxis, ucs.Yaxis); + + var box = new Box() + { + xSize = xSize, + ySize = ySize, + zSize = zSize, + basePlane = PlaneToSpeckle(plane), + volume = xSize.Length * ySize.Length * zSize.Length, + units = ModelUnits + }; + + return box; } - private Vector3d VectorASToAcad(ASVector3d vector) + catch { - return new Vector3d(vector.x * FactorFromNative, vector.y * FactorFromNative, vector.z * FactorFromNative); + return null; } - - private Box BoxToSpeckle(ASBoundBlock3d bound) + } + private Box BoxToSpeckle(ASExtents extents) + { + try { - try - { - bound.GetMinMaxPoints(out var point1, out var point2); - // convert min and max pts to speckle first - var min = PointToSpeckle(point1); - var max = PointToSpeckle(point2); - - // get dimension intervals - var xSize = new Interval(min.x, max.x); - var ySize = new Interval(min.y, max.y); - var zSize = new Interval(min.z, max.z); - - // get the base plane of the bounding box from extents and current UCS - var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - var plane = new AcadGeo.Plane(PointASToAcad(point1), ucs.Xaxis, ucs.Yaxis); - - var box = new Box() - { - xSize = xSize, - ySize = ySize, - zSize = zSize, - basePlane = PlaneToSpeckle(plane), - volume = xSize.Length * ySize.Length * zSize.Length, - units = ModelUnits - }; - - return box; - } - catch + // convert min and max pts to speckle first + var min = PointToSpeckle(extents.MinPoint); + var max = PointToSpeckle(extents.MaxPoint); + + // get dimension intervals + var xSize = new Interval(min.x, max.x); + var ySize = new Interval(min.y, max.y); + var zSize = new Interval(min.z, max.z); + + // get the base plane of the bounding box from extents and current UCS + var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; + var plane = new AcadGeo.Plane(PointASToAcad(extents.MinPoint), ucs.Xaxis, ucs.Yaxis); + + var box = new Box() { - return null; - } + xSize = xSize, + ySize = ySize, + zSize = zSize, + basePlane = PlaneToSpeckle(plane), + volume = xSize.Length * ySize.Length * zSize.Length, + units = ModelUnits + }; + + return box; } - private Box BoxToSpeckle(ASExtents extents) + catch { - try - { - // convert min and max pts to speckle first - var min = PointToSpeckle(extents.MinPoint); - var max = PointToSpeckle(extents.MaxPoint); - - // get dimension intervals - var xSize = new Interval(min.x, max.x); - var ySize = new Interval(min.y, max.y); - var zSize = new Interval(min.z, max.z); - - // get the base plane of the bounding box from extents and current UCS - var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - var plane = new AcadGeo.Plane(PointASToAcad(extents.MinPoint), ucs.Xaxis, ucs.Yaxis); - - var box = new Box() - { - xSize = xSize, - ySize = ySize, - zSize = zSize, - basePlane = PlaneToSpeckle(plane), - volume = xSize.Length * ySize.Length * zSize.Length, - units = ModelUnits - }; - - return box; - } - catch - { - return null; - } + return null; } + } + + private Polycurve PolycurveToSpeckle(ASPolyline3d polyline) + { + var units = ModelUnits; + Polycurve specklePolycurve = new(units) { closed = polyline.IsClosed }; - private Polycurve PolycurveToSpeckle(ASPolyline3d polyline) + polyline.GetCurves(out ASCurve3d[] foundPolyCurves); + for (int i = 0; i < foundPolyCurves.Length; i++) { - var units = ModelUnits; - Polycurve specklePolycurve = new Polycurve(units) { closed = polyline.IsClosed }; + ASCurve3d nextCurve = foundPolyCurves[i]; + if (nextCurve is ASLineSeg3d line) + { + specklePolycurve.segments.Add(LineToSpeckle(line)); + } - polyline.GetCurves(out ASCurve3d[] foundPolyCurves); - for (int i = 0; i < foundPolyCurves.Length; i++) + if (nextCurve is ASCircArc3d arc) { - ASCurve3d nextCurve = foundPolyCurves[i]; - if (nextCurve is ASLineSeg3d line) - { - specklePolycurve.segments.Add(LineToSpeckle(line)); - } - - if (nextCurve is ASCircArc3d arc) - { - specklePolycurve.segments.Add(ArcToSpeckle(arc)); - } + specklePolycurve.segments.Add(ArcToSpeckle(arc)); } - return specklePolycurve; } + return specklePolycurve; + } + + private Polycurve PolycurveToSpeckle(ASPoint3d[] pointsContour) + { + var units = ModelUnits; + var specklePolycurve = new Polycurve(units); - private Polycurve PolycurveToSpeckle(ASPoint3d[] pointsContour) + for (int i = 1; i < pointsContour.Length; i++) { - var units = ModelUnits; - var specklePolycurve = new Polycurve(units); + specklePolycurve.segments.Add(LineToSpeckle(pointsContour[i - 1], pointsContour[i])); + } - for (int i = 1; i < pointsContour.Length; i++) - { - specklePolycurve.segments.Add(LineToSpeckle(pointsContour[i - 1], pointsContour[i])); - } + specklePolycurve.segments.Add(LineToSpeckle(pointsContour.Last(), pointsContour.First())); - specklePolycurve.segments.Add(LineToSpeckle(pointsContour.Last(), pointsContour.First())); + return specklePolycurve; + } - return specklePolycurve; - } + private Line LineToSpeckle(ASPoint3d point1, ASPoint3d point2) + { + return new Line(PointToSpeckle(point1), PointToSpeckle(point2), ModelUnits); + } - private Line LineToSpeckle(ASPoint3d point1, ASPoint3d point2) + private Line LineToSpeckle(ASLineSeg3d line) + { + var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); + _line.length = line.GetLength(); + + if (line.HasStartParam(out var start) && line.HasEndParam(out var end)) { - return new Line(PointToSpeckle(point1), PointToSpeckle(point2), ModelUnits); + _line.domain = new Interval(start, end); } - private Line LineToSpeckle(ASLineSeg3d line) - { - var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); - _line.length = line.GetLength(); + _line.bbox = BoxToSpeckle(line.GetOrthoBoundBlock()); + return _line; + } - if (line.HasStartParam(out var start) && line.HasEndParam(out var end)) - { - _line.domain = new Interval(start, end); - } + private Arc ArcToSpeckle(ASCircArc3d arc) + { + Arc _arc; - _line.bbox = BoxToSpeckle(line.GetOrthoBoundBlock()); - return _line; + if (arc.IsPlanar(out var plane)) + { + _arc = new Arc(PlaneToSpeckle(plane), PointToSpeckle(arc.StartPoint), PointToSpeckle(arc.EndPoint), arc.IncludedAngle, ModelUnits); + } + else + { + _arc = new Arc(PointToSpeckle(arc.StartPoint), PointToSpeckle(arc.EndPoint), arc.IncludedAngle, ModelUnits); } - private Arc ArcToSpeckle(ASCircArc3d arc) + _arc.midPoint = PointToSpeckle(arc.MidPoint); + + if (arc.HasStartParam(out var start) && arc.HasEndParam(out var end)) { - Arc _arc; + _arc.domain = new Interval(start, end); + } - if (arc.IsPlanar(out var plane)) - { - _arc = new Arc(PlaneToSpeckle(plane), PointToSpeckle(arc.StartPoint), PointToSpeckle(arc.EndPoint), arc.IncludedAngle, ModelUnits); - } - else - { - _arc = new Arc(PointToSpeckle(arc.StartPoint), PointToSpeckle(arc.EndPoint), arc.IncludedAngle, ModelUnits); - } + _arc.length = arc.GetLength(); + _arc.bbox = BoxToSpeckle(arc.GetOrthoBoundBlock()); + return _arc; + } - _arc.midPoint = PointToSpeckle(arc.MidPoint); + private Plane PlaneToSpeckle(ASPlane plane) + { + plane.GetCoordSystem(out var origin, out var vectorX, out var vectorY, out var vectorZ); - if (arc.HasStartParam(out var start) && arc.HasEndParam(out var end)) - { - _arc.domain = new Interval(start, end); - } + return new Plane(PointToSpeckle(origin), VectorToSpeckle(plane.Normal), VectorToSpeckle(vectorX), VectorToSpeckle(vectorY), ModelUnits); + } - _arc.length = arc.GetLength(); - _arc.bbox = BoxToSpeckle(arc.GetOrthoBoundBlock()); - return _arc; + private object ConvertValueToSpeckle(object @object, eUnitType? unitType, out bool converted) + { + converted = true; + if (@object is ASPoint3d) + { + return PointToSpeckle(@object as ASPoint3d); } - - private Plane PlaneToSpeckle(ASPlane plane) + else if (@object is ASVector3d) { - plane.GetCoordSystem(out var origin, out var vectorX, out var vectorY, out var vectorZ); - - return new Plane(PointToSpeckle(origin), VectorToSpeckle(plane.Normal), VectorToSpeckle(vectorX), VectorToSpeckle(vectorY), ModelUnits); + return VectorToSpeckle(@object as ASVector3d); } - - private object ConvertValueToSpeckle(object @object, eUnitType? unitType, out bool converted) + else if (IsValueGenericList(@object)) { - converted = true; - if (@object is ASPoint3d) + IList list = @object as IList; + if (list.Count == 0) { - return PointToSpeckle(@object as ASPoint3d); + return null; } - else if (@object is ASVector3d) + + List listReturn = new(); + foreach (var item in list) { - return VectorToSpeckle(@object as ASVector3d); + listReturn.Add(ConvertValueToSpeckle(item, unitType, out _)); } - else if (IsValueGenericList(@object)) - { - IList list = @object as IList; - if (list.Count == 0) return null; - List listReturn = new List(); - foreach (var item in list) - listReturn.Add(ConvertValueToSpeckle(item, unitType, out _)); - - return listReturn; - } - else if (IsValueGenericDictionary(@object)) + return listReturn; + } + else if (IsValueGenericDictionary(@object)) + { + IDictionary dictionary = @object as IDictionary; + if (dictionary.Count == 0) { - IDictionary dictionary = @object as IDictionary; - if (dictionary.Count == 0) return null; - - Dictionary dictionaryReturn = new Dictionary(); - foreach (var key in dictionary.Keys) - dictionaryReturn.Add(key, ConvertValueToSpeckle(dictionary[key], unitType, out _)); - - return dictionaryReturn; + return null; } - else - { - if(unitType.HasValue && @object is double) - { - @object = FromInternalUnits((double)@object, unitType.Value); - } - converted = false; - return @object; + Dictionary dictionaryReturn = new(); + foreach (var key in dictionary.Keys) + { + dictionaryReturn.Add(key, ConvertValueToSpeckle(dictionary[key], unitType, out _)); } - } - private static bool IsValueGenericList(object value) + return dictionaryReturn; + } + else { - var type = value.GetType(); - return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>)); + if(unitType.HasValue && @object is double) + { + @object = FromInternalUnits((double)@object, unitType.Value); + } + + converted = false; + return @object; } + } + + private static bool IsValueGenericList(object value) + { + var type = value.GetType(); + return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>)); + } + + private static bool IsValueGenericDictionary(object value) + { + var type = value.GetType(); + return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Dictionary<,>)); + } + + private double FromInternalUnits(double value, eUnitType unitType) + { + double valueScaled = value * GetUnitScaleFromNative(unitType); - private static bool IsValueGenericDictionary(object value) + if (unitType == eUnitType.kWeight) { - var type = value.GetType(); - return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Dictionary<,>)); + valueScaled = RoundBigDecimalNumbers(valueScaled, 5); } - - private double FromInternalUnits(double value, eUnitType unitType) + else if (unitType == eUnitType.kVolume) { - double valueScaled = value * GetUnitScaleFromNative(unitType); - - if (unitType == eUnitType.kWeight) + if (valueScaled > 999) { - valueScaled = RoundBigDecimalNumbers(valueScaled, 5); + valueScaled = RoundBigDecimalNumbers(valueScaled, 3); } - else if (unitType == eUnitType.kVolume) + else { - if (valueScaled > 999) - { - valueScaled = RoundBigDecimalNumbers(valueScaled, 3); - } - else - { - valueScaled = RoundBigDecimalNumbers(valueScaled, 9); - } + valueScaled = RoundBigDecimalNumbers(valueScaled, 9); } - else if (unitType == eUnitType.kArea) + } + else if (unitType == eUnitType.kArea) + { + if (valueScaled > 999) { - if (valueScaled > 999) - { - valueScaled = RoundBigDecimalNumbers(valueScaled, 2); - } - else - { - valueScaled = RoundBigDecimalNumbers(valueScaled, 6); - } + valueScaled = RoundBigDecimalNumbers(valueScaled, 2); + } + else + { + valueScaled = RoundBigDecimalNumbers(valueScaled, 6); } - - return valueScaled; } - private static double RoundBigDecimalNumbers(double value, int digits) - { - return Math.Round(value, digits, MidpointRounding.AwayFromZero); - } + return valueScaled; + } - #region Units + private static double RoundBigDecimalNumbers(double value, int digits) + { + return Math.Round(value, digits, MidpointRounding.AwayFromZero); + } + +#region Units - private UnitsSet _unitsSet; + private UnitsSet _unitsSet; - private UnitsSet UnitsSet + private UnitsSet UnitsSet + { + get { - get + if (_unitsSet == null) { - if (_unitsSet == null) - { - _unitsSet = DocumentManager.GetCurrentDocument().CurrentDatabase.Units; - - //Workaround to fix strange beahaviour when we are using the modeler of some beams(lost some faces) - var unitOriginal = _unitsSet.UnitOfArea; - _unitsSet.UnitOfArea = new Unit(); - _unitsSet.UnitOfArea = unitOriginal; - } + _unitsSet = DocumentManager.GetCurrentDocument().CurrentDatabase.Units; - return _unitsSet; + //Workaround to fix strange beahaviour when we are using the modeler of some beams(lost some faces) + var unitOriginal = _unitsSet.UnitOfArea; + _unitsSet.UnitOfArea = new Unit(); + _unitsSet.UnitOfArea = unitOriginal; } - } - private double GetUnitScaleFromNative(eUnitType unitType) - { - return 1 / UnitsSet.GetUnit(unitType).Factor; + return _unitsSet; } + } - private double _factorFromNative; - private double FactorFromNative + private double GetUnitScaleFromNative(eUnitType unitType) + { + return 1 / UnitsSet.GetUnit(unitType).Factor; + } + + private double _factorFromNative; + private double FactorFromNative + { + get { - get + if (_factorFromNative.Equals(0.0)) { - if (_factorFromNative.Equals(0.0)) - { - _factorFromNative = 1 / DocumentManager.GetCurrentDocument().CurrentDatabase.Units.UnitOfDistance.Factor; - } - - return _factorFromNative; + _factorFromNative = 1 / DocumentManager.GetCurrentDocument().CurrentDatabase.Units.UnitOfDistance.Factor; } + + return _factorFromNative; } + } - private string unitWeight; - private string UnitWeight + private string unitWeight; + private string UnitWeight + { + get { - get + if (string.IsNullOrEmpty(unitWeight)) { - if (string.IsNullOrEmpty(unitWeight)) - { - unitWeight = UnitsSet.GetUnit(eUnitType.kWeight).Symbol; - } - return unitWeight; + unitWeight = UnitsSet.GetUnit(eUnitType.kWeight).Symbol; } + return unitWeight; } + } - private string unitVolume; - private string UnitVolume + private string unitVolume; + private string UnitVolume + { + get { - get + if (string.IsNullOrEmpty(unitVolume)) { - if (string.IsNullOrEmpty(unitVolume)) - { - unitVolume = UnitsSet.GetUnit(eUnitType.kVolume).Symbol; - } - return unitVolume; + unitVolume = UnitsSet.GetUnit(eUnitType.kVolume).Symbol; } + return unitVolume; } + } - private string unitArea; - private string UnitArea + private string unitArea; + private string UnitArea + { + get { - get + if (string.IsNullOrEmpty(unitArea)) { - if (string.IsNullOrEmpty(unitArea)) - { - unitArea = UnitsSet.GetUnit(eUnitType.kArea).Symbol; - } - return unitArea; + unitArea = UnitsSet.GetUnit(eUnitType.kArea).Symbol; } + return unitArea; } - - #endregion } + +#endregion } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.AdvanceSteel.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.AdvanceSteel.cs index c2fdc9c95e..f301d7fb71 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.AdvanceSteel.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.AdvanceSteel.cs @@ -25,260 +25,270 @@ using Autodesk.AdvanceSteel.DocumentManagement; using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + public bool CanConvertASToSpeckle(DBObject @object) { - public bool CanConvertASToSpeckle(DBObject @object) + switch (@object.ObjectId.ObjectClass.DxfName) { - switch (@object.ObjectId.ObjectClass.DxfName) - { - case DxfNames.BEAM: - case DxfNames.PLATE: - case DxfNames.BOLT2POINTS: - case DxfNames.BOLTCIRCULAR: - case DxfNames.BOLTCORNER: - case DxfNames.BOLTMID: - case DxfNames.SPECIALPART: - case DxfNames.GRATING: - case DxfNames.SLAB: - return true; - } - - return false; + case DxfNames.BEAM: + case DxfNames.PLATE: + case DxfNames.BOLT2POINTS: + case DxfNames.BOLTCIRCULAR: + case DxfNames.BOLTCORNER: + case DxfNames.BOLTMID: + case DxfNames.SPECIALPART: + case DxfNames.GRATING: + case DxfNames.SLAB: + return true; } - public Base ConvertASToSpeckle(DBObject @object, ApplicationObject reportObj, List notes) - { - ASFilerObject filerObject = GetFilerObjectByEntity(@object); + return false; + } - if (filerObject == null) - { - throw new System.Exception($"Failed to find Advance Steel object ${@object.Handle.ToString()}."); - } + public Base ConvertASToSpeckle(DBObject @object, ApplicationObject reportObj, List notes) + { + ASFilerObject filerObject = GetFilerObjectByEntity(@object); - reportObj.Update(descriptor: filerObject.GetType().Name); + if (filerObject == null) + { + throw new System.Exception($"Failed to find Advance Steel object ${@object.Handle.ToString()}."); + } - dynamic dynamicObject = filerObject; - IAsteelObject asteelObject = FilerObjectToSpeckle(dynamicObject, notes); + reportObj.Update(descriptor: filerObject.GetType().Name); - SetUserAttributesToSpeckle(filerObject as AtomicElement, asteelObject); + dynamic dynamicObject = filerObject; + IAsteelObject asteelObject = FilerObjectToSpeckle(dynamicObject, notes); - SetAsteelObjectPropertiesToSpeckle(asteelObject, filerObject); + SetUserAttributesToSpeckle(filerObject as AtomicElement, asteelObject); - //throw new System.Exception("Test"); + SetAsteelObjectPropertiesToSpeckle(asteelObject, filerObject); - Base @base = asteelObject as Base; + //throw new System.Exception("Test"); - SetUnits(@base); + Base @base = asteelObject as Base; - @base["weight unit"] = UnitWeight; - @base["area unit"] = UnitArea; - @base["volume unit"] = UnitVolume; + SetUnits(@base); - var objectHandleHierarchy = StructureUtils.GetObjectHandleHierarchy(); - if (objectHandleHierarchy.ContainsKey(filerObject.Handle)) - { - @base["hierarchy"] = objectHandleHierarchy[filerObject.Handle]; - } + @base["weight unit"] = UnitWeight; + @base["area unit"] = UnitArea; + @base["volume unit"] = UnitVolume; - return @base; + var objectHandleHierarchy = StructureUtils.GetObjectHandleHierarchy(); + if (objectHandleHierarchy.ContainsKey(filerObject.Handle)) + { + @base["hierarchy"] = objectHandleHierarchy[filerObject.Handle]; } - private void SetAsteelObjectPropertiesToSpeckle(IAsteelObject asteelObject, FilerObject filerObject) + return @base; + } + + private void SetAsteelObjectPropertiesToSpeckle(IAsteelObject asteelObject, FilerObject filerObject) + { + var propsAsteelObject = new Base(); + + try { - var propsAsteelObject = new Base(); + var type = filerObject.GetType(); + propsAsteelObject["advance steel type"] = type.Name; - try - { - var type = filerObject.GetType(); - propsAsteelObject["advance steel type"] = type.Name; + IEnumerable listPropertySets = ASPropertiesCache.Instance.GetPropertiesSetsByType(type); - IEnumerable listPropertySets = ASPropertiesCache.Instance.GetPropertiesSetsByType(type); + foreach (ASTypeData typeData in listPropertySets) + { + var propsSpecific = new Base(); + propsAsteelObject[$"{typeData.Description} props"] = propsSpecific; - foreach (ASTypeData typeData in listPropertySets) + foreach (var propItem in typeData.PropertiesSpecific) { - var propsSpecific = new Base(); - propsAsteelObject[$"{typeData.Description} props"] = propsSpecific; - - foreach (var propItem in typeData.PropertiesSpecific) + if (CheckProperty(propItem.Value, filerObject, out object propValue)) { - if (CheckProperty(propItem.Value, filerObject, out object propValue)) - propsSpecific[propItem.Key] = propValue; + propsSpecific[propItem.Key] = propValue; } } - - } - catch (System.Exception e) - { - return; } - asteelObject.asteelProperties = propsAsteelObject; - } - - private bool CheckProperty(ASProperty propInfo, object @object, out object value) + catch (System.Exception e) { - value = propInfo.EvaluateValue(@object); - if (value is null) return false; + return; + } - if (propInfo.ValueType.IsPrimitive || propInfo.ValueType == typeof(decimal)) - { - if(propInfo.UnitType.HasValue && value is double) - { - value = FromInternalUnits((double)value, propInfo.UnitType.Value); - } + asteelObject.asteelProperties = propsAsteelObject; - return true; - } + } - if (propInfo.ValueType == typeof(string)) - { - return !string.IsNullOrEmpty(value as string); - } + private bool CheckProperty(ASProperty propInfo, object @object, out object value) + { + value = propInfo.EvaluateValue(@object); + if (value is null) + { + return false; + } - if (propInfo.ValueType.IsEnum) + if (propInfo.ValueType.IsPrimitive || propInfo.ValueType == typeof(decimal)) + { + if(propInfo.UnitType.HasValue && value is double) { - value = value.ToString(); - return true; + value = FromInternalUnits((double)value, propInfo.UnitType.Value); } - - value = ConvertValueToSpeckle(value, propInfo.UnitType, out var converted); - return converted; + return true; } - private IAsteelObject FilerObjectToSpeckle(FilerObject filerObject, List notes) + if (propInfo.ValueType == typeof(string)) { - throw new System.Exception("Advance Steel Object type conversion to Speckle not implemented"); + return !string.IsNullOrEmpty(value as string); } - private void SetDisplayValue(Base @base, AtomicElement atomicElement) + if (propInfo.ValueType.IsEnum) { - var modelerBody = atomicElement.GetModeler(Autodesk.AdvanceSteel.Modeler.BodyContext.eBodyContext.kMaxDetailed); - - @base["volume"] = FromInternalUnits(modelerBody.Volume, eUnitType.kVolume); - @base["displayValue"] = new List { GetMeshFromModelerBody(modelerBody, atomicElement.GeomExtents) }; + value = value.ToString(); + return true; } + + value = ConvertValueToSpeckle(value, propInfo.UnitType, out var converted); - private Mesh GetMeshFromModelerBody(ModelerBody modelerBody, ASExtents extents) - { - modelerBody.getBrepInfo(out var verticesAS, out var facesInfo); + return converted; + } - IEnumerable vertices = verticesAS.Select(x => PointToMath(x)); + private IAsteelObject FilerObjectToSpeckle(FilerObject filerObject, List notes) + { + throw new System.Exception("Advance Steel Object type conversion to Speckle not implemented"); + } + + private void SetDisplayValue(Base @base, AtomicElement atomicElement) + { + var modelerBody = atomicElement.GetModeler(Autodesk.AdvanceSteel.Modeler.BodyContext.eBodyContext.kMaxDetailed); - List vertexList = new List { }; - List facesList = new List { }; + @base["volume"] = FromInternalUnits(modelerBody.Volume, eUnitType.kVolume); + @base["displayValue"] = new List { GetMeshFromModelerBody(modelerBody, atomicElement.GeomExtents) }; + } - foreach (var faceInfo in facesInfo) - { - int faceIndexOffset = vertexList.Count / 3; - var input = new Polygon(); + private Mesh GetMeshFromModelerBody(ModelerBody modelerBody, ASExtents extents) + { + modelerBody.getBrepInfo(out var verticesAS, out var facesInfo); + + IEnumerable vertices = verticesAS.Select(x => PointToMath(x)); + + List vertexList = new() { }; + List facesList = new() { }; - //Create coordinateSystemAligned with OuterContour - var outerList = faceInfo.OuterContour.Select(x => vertices.ElementAt(x)); + foreach (var faceInfo in facesInfo) + { + int faceIndexOffset = vertexList.Count / 3; + var input = new Polygon(); - if (outerList.Count() < 3) - continue; + //Create coordinateSystemAligned with OuterContour + var outerList = faceInfo.OuterContour.Select(x => vertices.ElementAt(x)); - CoordinateSystem coordinateSystemAligned = CreateCoordinateSystemAligned(outerList); + if (outerList.Count() < 3) + { + continue; + } - input.Add(CreateContour(outerList, coordinateSystemAligned)); + CoordinateSystem coordinateSystemAligned = CreateCoordinateSystemAligned(outerList); - if (faceInfo.InnerContours != null) + input.Add(CreateContour(outerList, coordinateSystemAligned)); + + if (faceInfo.InnerContours != null) + { + foreach (var listInnerContours in faceInfo.InnerContours) { - foreach (var listInnerContours in faceInfo.InnerContours) + var innerList = listInnerContours.Select(x => vertices.ElementAt(x)); + if (innerList.Count() < 3) { - var innerList = listInnerContours.Select(x => vertices.ElementAt(x)); - if (innerList.Count() < 3) - continue; - - input.Add(CreateContour(innerList, coordinateSystemAligned), true); + continue; } + + input.Add(CreateContour(innerList, coordinateSystemAligned), true); } + } - var triangleMesh = (TriangleMesh)input.Triangulate(); + var triangleMesh = (TriangleMesh)input.Triangulate(); - CoordinateSystem coordinateSystemInverted = coordinateSystemAligned.Invert(); - var verticesMesh = triangleMesh.Vertices.Select(x => new Point3D(x.X, x.Y, 0).TransformBy(coordinateSystemInverted)); + CoordinateSystem coordinateSystemInverted = coordinateSystemAligned.Invert(); + var verticesMesh = triangleMesh.Vertices.Select(x => new Point3D(x.X, x.Y, 0).TransformBy(coordinateSystemInverted)); - vertexList.AddRange(GetFlatCoordinates(verticesMesh)); - facesList.AddRange(GetFaceVertices(triangleMesh.Triangles, faceIndexOffset)); - } + vertexList.AddRange(GetFlatCoordinates(verticesMesh)); + facesList.AddRange(GetFaceVertices(triangleMesh.Triangles, faceIndexOffset)); + } - Mesh mesh = new Mesh(vertexList, facesList, units: ModelUnits); - mesh.bbox = BoxToSpeckle(extents); + Mesh mesh = new(vertexList, facesList, units: ModelUnits); + mesh.bbox = BoxToSpeckle(extents); - return mesh; - } + return mesh; + } - private Contour CreateContour(IEnumerable points, CoordinateSystem coordinateSystemAligned) - { - var listTriangleVertex = points.Select(x => x.TransformBy(coordinateSystemAligned)).Select(x => new TriangleVertex(x.X, x.Y)); - return new Contour(listTriangleVertex); - } + private Contour CreateContour(IEnumerable points, CoordinateSystem coordinateSystemAligned) + { + var listTriangleVertex = points.Select(x => x.TransformBy(coordinateSystemAligned)).Select(x => new TriangleVertex(x.X, x.Y)); + return new Contour(listTriangleVertex); + } - private IEnumerable GetFlatCoordinates(IEnumerable verticesMesh) + private IEnumerable GetFlatCoordinates(IEnumerable verticesMesh) + { + foreach (var vertice in verticesMesh) { - foreach (var vertice in verticesMesh) - { - yield return vertice.X; - yield return vertice.Y; - yield return vertice.Z; - } + yield return vertice.X; + yield return vertice.Y; + yield return vertice.Z; } + } - private IEnumerable GetFaceVertices(ICollection triangles, int faceIndexOffset) + private IEnumerable GetFaceVertices(ICollection triangles, int faceIndexOffset) + { + foreach (var triangle in triangles) { - foreach (var triangle in triangles) - { - yield return 3; - yield return triangle.GetVertex(0).ID + faceIndexOffset; - yield return triangle.GetVertex(1).ID + faceIndexOffset; - yield return triangle.GetVertex(2).ID + faceIndexOffset; - } + yield return 3; + yield return triangle.GetVertex(0).ID + faceIndexOffset; + yield return triangle.GetVertex(1).ID + faceIndexOffset; + yield return triangle.GetVertex(2).ID + faceIndexOffset; } + } - private CoordinateSystem CreateCoordinateSystemAligned(IEnumerable points) - { - var point1 = points.ElementAt(0); - var point2 = points.ElementAt(1); + private CoordinateSystem CreateCoordinateSystemAligned(IEnumerable points) + { + var point1 = points.ElementAt(0); + var point2 = points.ElementAt(1); - //Centroid calculated to avoid non-collinear points - var centroid = Point3D.Centroid(points); - var plane = MathPlane.FromPoints(centroid, point1, point2); + //Centroid calculated to avoid non-collinear points + var centroid = Point3D.Centroid(points); + var plane = MathPlane.FromPoints(centroid, point1, point2); - UnitVector3D vectorX = (centroid - point1).Normalize(); - UnitVector3D vectorZ = plane.Normal; - UnitVector3D vectorY = vectorZ.CrossProduct(vectorX); + UnitVector3D vectorX = (centroid - point1).Normalize(); + UnitVector3D vectorZ = plane.Normal; + UnitVector3D vectorY = vectorZ.CrossProduct(vectorX); - CoordinateSystem fromCs = new CoordinateSystem(point1, vectorX, vectorY, vectorZ); - CoordinateSystem toCs = new CoordinateSystem(Point3D.Origin, UnitVector3D.XAxis, UnitVector3D.YAxis, UnitVector3D.ZAxis); - return CoordinateSystem.CreateMappingCoordinateSystem(fromCs, toCs); - } + CoordinateSystem fromCs = new(point1, vectorX, vectorY, vectorZ); + CoordinateSystem toCs = new(Point3D.Origin, UnitVector3D.XAxis, UnitVector3D.YAxis, UnitVector3D.ZAxis); + return CoordinateSystem.CreateMappingCoordinateSystem(fromCs, toCs); + } - public static T GetFilerObjectByEntity(DBObject @object) where T : FilerObject + public static T GetFilerObjectByEntity(DBObject @object) where T : FilerObject + { + ASObjectId idCadEntity = new(@object.ObjectId.OldIdPtr); + ASObjectId idFilerObject = DatabaseManager.GetFilerObjectId(idCadEntity, false); + if (idFilerObject.IsNull()) { - ASObjectId idCadEntity = new ASObjectId(@object.ObjectId.OldIdPtr); - ASObjectId idFilerObject = DatabaseManager.GetFilerObjectId(idCadEntity, false); - if (idFilerObject.IsNull()) - return null; - - return DatabaseManager.Open(idFilerObject) as T; + return null; } - private void SetUserAttributesToSpeckle(AtomicElement atomicElement, IAsteelObject asteelObject) + return DatabaseManager.Open(idFilerObject) as T; + } + + private void SetUserAttributesToSpeckle(AtomicElement atomicElement, IAsteelObject asteelObject) + { + asteelObject.userAttributes = new Base(); + for (int i = 0; i < 10; i++) { - asteelObject.userAttributes = new Base(); - for (int i = 0; i < 10; i++) - { - string attribute = atomicElement.GetUserAttribute(i); + string attribute = atomicElement.GetUserAttribute(i); - if (!string.IsNullOrEmpty(attribute)) - { - asteelObject.userAttributes[(i + 1).ToString()] = attribute; - } + if (!string.IsNullOrEmpty(attribute)) + { + asteelObject.userAttributes[(i + 1).ToString()] = attribute; } } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Beams.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Beams.cs index 713734944b..1646396b3d 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Beams.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Beams.cs @@ -16,176 +16,185 @@ using Objects.Structural.Properties.Profiles; using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASPolyBeam polyBeam, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASPolyBeam polyBeam, List notes) - { - AsteelPolyBeam asteelPolyBeam = new AsteelPolyBeam(); + AsteelPolyBeam asteelPolyBeam = new(); - ASPolyline3d polyline3d = polyBeam.GetPolyline(true); - asteelPolyBeam.baseLine = PolycurveToSpeckle(polyline3d); + ASPolyline3d polyline3d = polyBeam.GetPolyline(true); + asteelPolyBeam.baseLine = PolycurveToSpeckle(polyline3d); - GetBeamPropertiesToSpeckle(asteelPolyBeam, polyBeam); + GetBeamPropertiesToSpeckle(asteelPolyBeam, polyBeam); - return asteelPolyBeam; - } + return asteelPolyBeam; + } - private IAsteelObject FilerObjectToSpeckle(ASBeam beam, List notes) - { - AsteelBeam asteelBeam = new AsteelBeam(); + private IAsteelObject FilerObjectToSpeckle(ASBeam beam, List notes) + { + AsteelBeam asteelBeam = new(); - var startPoint = beam.GetPointAtStart(); - var endPoint = beam.GetPointAtEnd(); - var units = ModelUnits; + var startPoint = beam.GetPointAtStart(); + var endPoint = beam.GetPointAtEnd(); + var units = ModelUnits; - Point speckleStartPoint = PointToSpeckle(startPoint, units); - Point speckleEndPoint = PointToSpeckle(endPoint, units); - asteelBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); + Point speckleStartPoint = PointToSpeckle(startPoint, units); + Point speckleEndPoint = PointToSpeckle(endPoint, units); + asteelBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); - GetBeamPropertiesToSpeckle(asteelBeam, beam); + GetBeamPropertiesToSpeckle(asteelBeam, beam); - return asteelBeam; - } + return asteelBeam; + } - private void GetBeamPropertiesToSpeckle(AsteelBeam asteelBeam, ASBeam beam) + private void GetBeamPropertiesToSpeckle(AsteelBeam asteelBeam, ASBeam beam) + { + asteelBeam.asteelProfile = new AsteelSectionProfile() { - asteelBeam.asteelProfile = new AsteelSectionProfile() - { - ProfSectionType = beam.ProfSectionType, - ProfSectionName = beam.ProfSectionName - }; + ProfSectionType = beam.ProfSectionType, + ProfSectionName = beam.ProfSectionName + }; - dynamic profType = beam.GetProfType(); - asteelBeam.profile = GetProfileSectionProperties(profType); + dynamic profType = beam.GetProfType(); + asteelBeam.profile = GetProfileSectionProperties(profType); - asteelBeam.asteelProfile.SectionProfileDB = GetProfileSectionDBProperties(beam.ProfSectionType, beam.ProfSectionName); + asteelBeam.asteelProfile.SectionProfileDB = GetProfileSectionDBProperties(beam.ProfSectionType, beam.ProfSectionName); - asteelBeam.area = FromInternalUnits(beam.GetPaintArea(), eUnitType.kArea); + asteelBeam.area = FromInternalUnits(beam.GetPaintArea(), eUnitType.kArea); - //There is a bug in some beams that some faces don't appears in ModelerBody (Bug_Polybeam_Speckle.dwg) - //Changing area unit using ASTORUNITS, bug doesn´t happen. - //https://speckle.xyz/streams/1a0090e6fc - SetDisplayValue(asteelBeam, beam); - } + //There is a bug in some beams that some faces don't appears in ModelerBody (Bug_Polybeam_Speckle.dwg) + //Changing area unit using ASTORUNITS, bug doesn´t happen. + //https://speckle.xyz/streams/1a0090e6fc + SetDisplayValue(asteelBeam, beam); + } - private SectionProfile GetProfileSectionProperties(ProfileTypeW profileType) - { - var depth = profileType.B; - var width = profileType.H; - var tf1 = profileType.Tf; - var tf2 = profileType.Tw; + private SectionProfile GetProfileSectionProperties(ProfileTypeW profileType) + { + var depth = profileType.B; + var width = profileType.H; + var tf1 = profileType.Tf; + var tf2 = profileType.Tw; - var speckleProfile = new Angle(FormatSectionName(profileType.RunName), depth, width, tf1, tf2); + var speckleProfile = new Angle(FormatSectionName(profileType.RunName), depth, width, tf1, tf2); - return speckleProfile; - } + return speckleProfile; + } - private SectionProfile GetProfileSectionProperties(ProfileTypeR profileType) - { - var diameter = profileType.D; + private SectionProfile GetProfileSectionProperties(ProfileTypeR profileType) + { + var diameter = profileType.D; - var speckleProfile = new Circular(FormatSectionName(profileType.RunName), diameter * 0.5); + var speckleProfile = new Circular(FormatSectionName(profileType.RunName), diameter * 0.5); - return speckleProfile; - } + return speckleProfile; + } - private SectionProfile GetProfileSectionProperties(ProfileTypeI profileType) - { - var depth = profileType.H; - var width = profileType.B; - var tw = profileType.Tw; - var tf = profileType.Tf; + private SectionProfile GetProfileSectionProperties(ProfileTypeI profileType) + { + var depth = profileType.H; + var width = profileType.B; + var tw = profileType.Tw; + var tf = profileType.Tf; - var speckleProfile = new ISection(FormatSectionName(profileType.RunName), depth, width, tw, tf); + var speckleProfile = new ISection(FormatSectionName(profileType.RunName), depth, width, tw, tf); - return speckleProfile; - } + return speckleProfile; + } - private SectionProfile GetProfileSectionProperties(ProfileTypeC profileType) - { - var depth = profileType.H; - var width = profileType.B; - var tw = profileType.Tw; - var tf = profileType.Tf; + private SectionProfile GetProfileSectionProperties(ProfileTypeC profileType) + { + var depth = profileType.H; + var width = profileType.B; + var tw = profileType.Tw; + var tf = profileType.Tf; - var speckleProfile = new Channel(FormatSectionName(profileType.RunName), depth, width, tw, tf); + var speckleProfile = new Channel(FormatSectionName(profileType.RunName), depth, width, tw, tf); - return speckleProfile; - } + return speckleProfile; + } - private SectionProfile GetProfileSectionProperties(ProfileTypeT profileType) - { - var depth = profileType.H; - var width = profileType.B; - var tw = profileType.Tw; - var tf = profileType.Tf; + private SectionProfile GetProfileSectionProperties(ProfileTypeT profileType) + { + var depth = profileType.H; + var width = profileType.B; + var tw = profileType.Tw; + var tf = profileType.Tf; - var speckleProfile = new Tee(FormatSectionName(profileType.RunName), depth, width, tw, tf); + var speckleProfile = new Tee(FormatSectionName(profileType.RunName), depth, width, tw, tf); - return speckleProfile; - } + return speckleProfile; + } - private SectionProfile GetProfileSectionProperties(ProfileType profileType) + private SectionProfile GetProfileSectionProperties(ProfileType profileType) + { + //Undefined + SectionProfile sectionProfile = new() { - //Undefined - SectionProfile sectionProfile = new SectionProfile() - { - name = profileType.GetType().Name - }; + name = profileType.GetType().Name + }; - return sectionProfile; - } + return sectionProfile; + } - private string FormatSectionName(string sectionName) - { - return sectionName.Replace(",", "."); - } + private string FormatSectionName(string sectionName) + { + return sectionName.Replace(",", "."); + } - /// - /// Get profile sections - /// - /// sectionType - /// - private AsteelSectionProfileDB GetProfileSectionDBProperties(string typeNameText, string sectionName) + /// + /// Get profile sections + /// + /// sectionType + /// + private AsteelSectionProfileDB GetProfileSectionDBProperties(string typeNameText, string sectionName) + { + AsteelSectionProfileDB sectionProfileDB = new(); + + if (string.IsNullOrEmpty(typeNameText) || string.IsNullOrEmpty(sectionName)) { - AsteelSectionProfileDB sectionProfileDB = new AsteelSectionProfileDB(); + return sectionProfileDB; + } - if (string.IsNullOrEmpty(typeNameText) || string.IsNullOrEmpty(sectionName)) - return sectionProfileDB; + AstorProfiles astorProfiles = AstorProfiles.Instance; + System.Data.DataTable table = astorProfiles.getProfileMasterTable(); - AstorProfiles astorProfiles = AstorProfiles.Instance; - System.Data.DataTable table = astorProfiles.getProfileMasterTable(); + var rowSectionType = table.Select(string.Format("TypeNameText='{0}'", typeNameText)).FirstOrDefault(); - var rowSectionType = table.Select(string.Format("TypeNameText='{0}'", typeNameText)).FirstOrDefault(); + if (rowSectionType == null) + { + return sectionProfileDB; + } - if (rowSectionType == null) - return sectionProfileDB; + var tableName = rowSectionType["TableName"].ToString(); + var tableProfiles = astorProfiles.getSectionsTable(tableName); - var tableName = rowSectionType["TableName"].ToString(); - var tableProfiles = astorProfiles.getSectionsTable(tableName); + if (tableProfiles == null) + { + return sectionProfileDB; + } - if (tableProfiles == null) - return sectionProfileDB; + var rowSection = tableProfiles.Select(string.Format("SectionName='{0}'", sectionName)).FirstOrDefault(); - var rowSection = tableProfiles.Select(string.Format("SectionName='{0}'", sectionName)).FirstOrDefault(); + if (rowSection == null) + { + return sectionProfileDB; + } - if (rowSection == null) - return sectionProfileDB; + foreach (var column in tableProfiles.Columns.Cast()) + { + var rowObject = rowSection[column]; - foreach (var column in tableProfiles.Columns.Cast()) + if (!(rowObject is System.DBNull)) { - var rowObject = rowSection[column]; - - if (!(rowObject is System.DBNull)) - sectionProfileDB[column.ColumnName] = rowObject; + sectionProfileDB[column.ColumnName] = rowObject; } - - return sectionProfileDB; } + return sectionProfileDB; } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Bolts.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Bolts.cs index 6f136bd1e6..d4acab7bff 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Bolts.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Bolts.cs @@ -5,18 +5,17 @@ using Autodesk.AdvanceSteel.Modelling; using ASBoltPattern = Autodesk.AdvanceSteel.Modelling.BoltPattern; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASBoltPattern bolt, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASBoltPattern bolt, List notes) - { - AsteelBolt asteelBolt = bolt is CircleScrewBoltPattern ? (AsteelBolt)new AsteelCircularBolt() : (AsteelBolt)new AsteelRectangularBolt(); + AsteelBolt asteelBolt = bolt is CircleScrewBoltPattern ? (AsteelBolt)new AsteelCircularBolt() : (AsteelBolt)new AsteelRectangularBolt(); - SetDisplayValue(asteelBolt, bolt); + SetDisplayValue(asteelBolt, bolt); - return asteelBolt; - } + return asteelBolt; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.DxfNames.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.DxfNames.cs index c164c5c4d2..ade6e2e2fd 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.DxfNames.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.DxfNames.cs @@ -3,24 +3,22 @@ using System.Collections.Generic; using System; -namespace Objects.Converter.AutocadCivil -{ - public static class DxfNames - { - public const string BEAM = "ASTBEAM"; - public const string PLATE = "ASTPLATE"; +namespace Objects.Converter.AutocadCivil; - public const string BOLT2POINTS = "ASTBOLT2POINTS"; - public const string BOLTCORNER = "ASTBOLTCORNER"; - public const string BOLTMID = "ASTBOLTMID"; - public const string BOLTCIRCULAR = "ASTBOLTCIRCULAR"; +public static class DxfNames +{ + public const string BEAM = "ASTBEAM"; + public const string PLATE = "ASTPLATE"; - public const string SPECIALPART = "ASTSPECIALPART"; + public const string BOLT2POINTS = "ASTBOLT2POINTS"; + public const string BOLTCORNER = "ASTBOLTCORNER"; + public const string BOLTMID = "ASTBOLTMID"; + public const string BOLTCIRCULAR = "ASTBOLTCIRCULAR"; - public const string GRATING = "ASTGRATING"; + public const string SPECIALPART = "ASTSPECIALPART"; - public const string SLAB = "ASTSLAB"; - } + public const string GRATING = "ASTGRATING"; + public const string SLAB = "ASTSLAB"; } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Gratings.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Gratings.cs index 76e0c2668c..8a07851181 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Gratings.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Gratings.cs @@ -3,18 +3,17 @@ using Objects.BuiltElements.AdvanceSteel; using ASGrating = Autodesk.AdvanceSteel.Modelling.Grating; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASGrating grating, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASGrating grating, List notes) - { - AsteelGrating asteelGrating = new AsteelGrating(); + AsteelGrating asteelGrating = new(); - SetDisplayValue(asteelGrating, grating); + SetDisplayValue(asteelGrating, grating); - return asteelGrating; - } + return asteelGrating; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Plates.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Plates.cs index 840dd66eb1..90ca218fbc 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Plates.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Plates.cs @@ -4,24 +4,23 @@ using ASPlate = Autodesk.AdvanceSteel.Modelling.Plate; using ASPoint3d = Autodesk.AdvanceSteel.Geometry.Point3d; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASPlate plate, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASPlate plate, List notes) - { - AsteelPlate asteelPlate = new AsteelPlate(); + AsteelPlate asteelPlate = new(); - plate.GetBaseContourPolygon(0, out ASPoint3d[] ptsContour); + plate.GetBaseContourPolygon(0, out ASPoint3d[] ptsContour); - asteelPlate.outline = PolycurveToSpeckle(ptsContour); + asteelPlate.outline = PolycurveToSpeckle(ptsContour); - asteelPlate.area = plate.GetPaintArea(); + asteelPlate.area = plate.GetPaintArea(); - SetDisplayValue(asteelPlate, plate); + SetDisplayValue(asteelPlate, plate); - return asteelPlate; - } + return asteelPlate; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Slabs.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Slabs.cs index 5a3688dd4b..3922d0a7de 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Slabs.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.Slabs.cs @@ -3,18 +3,17 @@ using Objects.BuiltElements.AdvanceSteel; using ASSlab = Autodesk.AdvanceSteel.Modelling.Slab; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASSlab slab, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASSlab slab, List notes) - { - AsteelSlab asteelSlab = new AsteelSlab(); + AsteelSlab asteelSlab = new(); - SetDisplayValue(asteelSlab, slab); + SetDisplayValue(asteelSlab, slab); - return asteelSlab; - } + return asteelSlab; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.SpecialParts.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.SpecialParts.cs index 79c2eaa555..5d7418b9f0 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.SpecialParts.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/ConverterAutocadCivil.SpecialParts.cs @@ -3,18 +3,17 @@ using Objects.BuiltElements.AdvanceSteel; using ASSpecialPart = Autodesk.AdvanceSteel.Modelling.SpecialPart; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private IAsteelObject FilerObjectToSpeckle(ASSpecialPart specialPart, List notes) { - private IAsteelObject FilerObjectToSpeckle(ASSpecialPart specialPart, List notes) - { - AsteelSpecialPart asteelSpecialPart = new AsteelSpecialPart(); + AsteelSpecialPart asteelSpecialPart = new(); - SetDisplayValue(asteelSpecialPart, specialPart); + SetDisplayValue(asteelSpecialPart, specialPart); - return asteelSpecialPart; - } + return asteelSpecialPart; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASBaseProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASBaseProperties.cs index 5ca6f6e49c..c4d51c0744 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASBaseProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASBaseProperties.cs @@ -13,49 +13,48 @@ using Speckle.Newtonsoft.Json.Linq; using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public abstract class ASBaseProperties : IASProperties where T : class { - public abstract class ASBaseProperties : IASProperties where T : class - { - public Type ObjectType { get => typeof(T); } + public Type ObjectType { get => typeof(T); } - public abstract Dictionary BuildedPropertyList(); + public abstract Dictionary BuildedPropertyList(); - /// - /// Insert item at properties dictionary - /// - /// - /// - /// Member name of AS Object - May be Get/Set property or Get Method(without parameter) - /// - protected void InsertProperty(Dictionary dictionary, string description, string memberName, eUnitType? unitType = null) - { - dictionary.Add(description, new ASProperty(ObjectType, description, memberName, unitType)); - } + /// + /// Insert item at properties dictionary + /// + /// + /// + /// Member name of AS Object - May be Get/Set property or Get Method(without parameter) + /// + protected void InsertProperty(Dictionary dictionary, string description, string memberName, eUnitType? unitType = null) + { + dictionary.Add(description, new ASProperty(ObjectType, description, memberName, unitType)); + } - /// - /// Insert item at properties dictionary - /// - /// - /// - /// Method name of Get Custom Function on properties class - /// Method name of Set Custom Function on properties class - /// - protected void InsertCustomProperty(Dictionary dictionary, string description, string methodInfoGet, string methodInfoSet, eUnitType? unitType = null) - { - ASPropertyMethods propertyMethods = new ASPropertyMethods(this.GetType(), methodInfoGet, methodInfoSet); - dictionary.Add(description, new ASProperty(ObjectType, description, propertyMethods, unitType)); - } + /// + /// Insert item at properties dictionary + /// + /// + /// + /// Method name of Get Custom Function on properties class + /// Method name of Set Custom Function on properties class + /// + protected void InsertCustomProperty(Dictionary dictionary, string description, string methodInfoGet, string methodInfoSet, eUnitType? unitType = null) + { + ASPropertyMethods propertyMethods = new(this.GetType(), methodInfoGet, methodInfoSet); + dictionary.Add(description, new ASProperty(ObjectType, description, propertyMethods, unitType)); + } - protected static double Round(double value) - { - return Math.Round(value, 4, MidpointRounding.AwayFromZero); - } + protected static double Round(double value) + { + return Math.Round(value, 4, MidpointRounding.AwayFromZero); + } - protected static double DegreeToRadian(double angle) - { - return (System.Math.PI / 180.0) * angle; - } + protected static double DegreeToRadian(double angle) + { + return (System.Math.PI / 180.0) * angle; } } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertiesCache.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertiesCache.cs index b0e22c0af1..c21720c56e 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertiesCache.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertiesCache.cs @@ -10,95 +10,94 @@ using Autodesk.AdvanceSteel.ConstructionTypes; using Autodesk.AdvanceSteel.Modelling; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class ASPropertiesCache { - public class ASPropertiesCache + private ASPropertiesCache() { - private ASPropertiesCache() - { - } + } - private static ASPropertiesCache instance; + private static ASPropertiesCache instance; - public static ASPropertiesCache Instance + public static ASPropertiesCache Instance + { + get { - get + if (instance == null) { - if (instance == null) - { - instance = new ASPropertiesCache(); - instance.LoadASTypeDictionary(); - } - - return instance; + instance = new ASPropertiesCache(); + instance.LoadASTypeDictionary(); } + return instance; } - private readonly Dictionary ASPropertiesSets = new Dictionary() - { - { typeof(AtomicElement), new ASTypeData ("assembly") }, - { typeof(Beam), new ASTypeData("beam") }, - { typeof(MainAlias), new ASTypeData("manufacturing") }, - { typeof(PolyBeam), new ASTypeData("poly beam") }, - { typeof(BoltPattern), new ASTypeData("bolt") }, - { typeof(ScrewBoltPattern), new ASTypeData("screw bolt") }, - { typeof(ConstructionElement), new ASTypeData("construction") }, - { typeof(FilerObject), new ASTypeData("asteel") } - }; - - /// - /// Get all properties sets that are subclasses or equivalents of the type - /// - /// - /// - /// - internal IEnumerable GetPropertiesSetsByType(Type objectType) - { - IEnumerable steelTypeDataList = ASPropertiesSets.Where(x => objectType.IsSubclassOf(x.Key) || objectType.IsEquivalentTo(x.Key)).Select(x => x.Value); + } - return steelTypeDataList; - } + private readonly Dictionary ASPropertiesSets = new() + { + { typeof(AtomicElement), new ASTypeData ("assembly") }, + { typeof(Beam), new ASTypeData("beam") }, + { typeof(MainAlias), new ASTypeData("manufacturing") }, + { typeof(PolyBeam), new ASTypeData("poly beam") }, + { typeof(BoltPattern), new ASTypeData("bolt") }, + { typeof(ScrewBoltPattern), new ASTypeData("screw bolt") }, + { typeof(ConstructionElement), new ASTypeData("construction") }, + { typeof(FilerObject), new ASTypeData("asteel") } + }; + + /// + /// Get all properties sets that are subclasses or equivalents of the type + /// + /// + /// + /// + internal IEnumerable GetPropertiesSetsByType(Type objectType) + { + IEnumerable steelTypeDataList = ASPropertiesSets.Where(x => objectType.IsSubclassOf(x.Key) || objectType.IsEquivalentTo(x.Key)).Select(x => x.Value); - #region Load dictionary + return steelTypeDataList; + } - /// - /// Load all properties of each Advance Steel object type - /// - private void LoadASTypeDictionary() - { - var assemblyTypes = System.Reflection.Assembly.GetExecutingAssembly().GetTypes(); - var listIASProperties = assemblyTypes.Where(x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IASProperties))).Select(x => Activator.CreateInstance(x) as IASProperties); +#region Load dictionary - //Set specific properties of each type - foreach (var item in ASPropertiesSets) - { - IASProperties asProperties = listIASProperties.FirstOrDefault(x => x.ObjectType.Equals(item.Key)); + /// + /// Load all properties of each Advance Steel object type + /// + private void LoadASTypeDictionary() + { + var assemblyTypes = System.Reflection.Assembly.GetExecutingAssembly().GetTypes(); + var listIASProperties = assemblyTypes.Where(x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IASProperties))).Select(x => Activator.CreateInstance(x) as IASProperties); - if (asProperties == null) - { - throw new NotImplementedException($"{item.Key.Name} not implemented"); - } + //Set specific properties of each type + foreach (var item in ASPropertiesSets) + { + IASProperties asProperties = listIASProperties.FirstOrDefault(x => x.ObjectType.Equals(item.Key)); - item.Value.SetPropertiesSpecific(asProperties.BuildedPropertyList()); - item.Value.OrderDictionaryPropertiesAll(); + if (asProperties == null) + { + throw new NotImplementedException($"{item.Key.Name} not implemented"); } - //Set all properties using parents classes (checking if all properties have unique name) - foreach (var item in ASPropertiesSets) - { - IEnumerable steelTypeDataList = GetPropertiesSetsByType(item.Key); - foreach (var steelTypeData in steelTypeDataList) - { - item.Value.AddPropertiesAll(steelTypeData.PropertiesSpecific); - } + item.Value.SetPropertiesSpecific(asProperties.BuildedPropertyList()); + item.Value.OrderDictionaryPropertiesAll(); + } - item.Value.OrderDictionaryPropertiesAll(); + //Set all properties using parents classes (checking if all properties have unique name) + foreach (var item in ASPropertiesSets) + { + IEnumerable steelTypeDataList = GetPropertiesSetsByType(item.Key); + foreach (var steelTypeData in steelTypeDataList) + { + item.Value.AddPropertiesAll(steelTypeData.PropertiesSpecific); } - } - #endregion + item.Value.OrderDictionaryPropertiesAll(); + } } + +#endregion } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASProperty.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASProperty.cs index 375ddc2f12..60b423d281 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASProperty.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASProperty.cs @@ -9,145 +9,144 @@ using Speckle.Newtonsoft.Json.Linq; using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class ASProperty { - public class ASProperty - { - private Type ObjectType { get; set; } - private string Description { get; set; } - private string MemberName { get; set; } - private MemberInfo MemberInfo { get; set; } - public Type ValueType { get; private set; } - private ASPropertyMethods PropertyMethods { get; set; } + private Type ObjectType { get; set; } + private string Description { get; set; } + private string MemberName { get; set; } + private MemberInfo MemberInfo { get; set; } + public Type ValueType { get; private set; } + private ASPropertyMethods PropertyMethods { get; set; } + + private bool Read { get; set; } + private bool Write { get; set; } - private bool Read { get; set; } - private bool Write { get; set; } + public eUnitType? UnitType { get; private set; } - public eUnitType? UnitType { get; private set; } + internal ASProperty(Type objectASType, string description, string memberName, eUnitType? unitType = null) + { + ObjectType = objectASType; + Description = description; + MemberName = memberName; + + UnitType = unitType; - internal ASProperty(Type objectASType, string description, string memberName, eUnitType? unitType = null) + PropertyInfo property = objectASType.GetProperty(memberName); + if (property != null) { - ObjectType = objectASType; - Description = description; - MemberName = memberName; - - UnitType = unitType; - - PropertyInfo property = objectASType.GetProperty(memberName); - if (property != null) - { - ValueType = property.PropertyType; - Read = property.CanRead; - Write = property.CanWrite; - - MemberInfo = property; - return; - } - - MethodInfo method = objectASType.GetMethod(memberName, new Type[] { }); - if (method != null) - { - ValueType = method.ReturnType; - Read = true; - Write = false; - - MemberInfo = method; - return; - } - - throw new Exception($"'{memberName}' is not a property nor return method with 0 arguments nor void method with 1 argument"); + ValueType = property.PropertyType; + Read = property.CanRead; + Write = property.CanWrite; + + MemberInfo = property; + return; } - internal ASProperty(Type objectType, string description, ASPropertyMethods propertyMethods, eUnitType? unitType = null) + MethodInfo method = objectASType.GetMethod(memberName, new Type[] { }); + if (method != null) { - ObjectType = objectType; - Description = description; - UnitType = unitType; - - PropertyMethods = propertyMethods; - Read = PropertyMethods.MethodInfoGet != null; - Write = PropertyMethods.MethodInfoSet != null; - - if (PropertyMethods.MethodInfoGet != null) - { - ValueType = PropertyMethods.MethodInfoGet.ReturnType; - } - - if (PropertyMethods.MethodInfoSet != null) - { - ValueType = PropertyMethods.MethodInfoSet.GetParameters()[1].ParameterType; - } - - //Same name for description and membername - MemberName = description; + ValueType = method.ReturnType; + Read = true; + Write = false; + + MemberInfo = method; + return; } - internal ASProperty(ASProperty existingProperty) + throw new Exception($"'{memberName}' is not a property nor return method with 0 arguments nor void method with 1 argument"); + } + + internal ASProperty(Type objectType, string description, ASPropertyMethods propertyMethods, eUnitType? unitType = null) + { + ObjectType = objectType; + Description = description; + UnitType = unitType; + + PropertyMethods = propertyMethods; + Read = PropertyMethods.MethodInfoGet != null; + Write = PropertyMethods.MethodInfoSet != null; + + if (PropertyMethods.MethodInfoGet != null) { - CopyProperty(existingProperty); + ValueType = PropertyMethods.MethodInfoGet.ReturnType; } - internal void CopyProperty(ASProperty existingProperty) + if (PropertyMethods.MethodInfoSet != null) { - Read = existingProperty.Read; - Write = existingProperty.Write; - ObjectType = existingProperty.ObjectType; - Description = existingProperty.Description; - MemberInfo = existingProperty.MemberInfo; - MemberName = existingProperty.MemberName; - ValueType = existingProperty.ValueType; - PropertyMethods = existingProperty.PropertyMethods; - - UnitType = existingProperty.UnitType; + ValueType = PropertyMethods.MethodInfoSet.GetParameters()[1].ParameterType; } - internal object EvaluateValue(object asObject) + //Same name for description and membername + MemberName = description; + } + + internal ASProperty(ASProperty existingProperty) + { + CopyProperty(existingProperty); + } + + internal void CopyProperty(ASProperty existingProperty) + { + Read = existingProperty.Read; + Write = existingProperty.Write; + ObjectType = existingProperty.ObjectType; + Description = existingProperty.Description; + MemberInfo = existingProperty.MemberInfo; + MemberName = existingProperty.MemberName; + ValueType = existingProperty.ValueType; + PropertyMethods = existingProperty.PropertyMethods; + + UnitType = existingProperty.UnitType; + } + + internal object EvaluateValue(object asObject) + { + if (asObject == null) { - if (asObject == null) - { - throw new System.Exception("Advance Steel object not found"); - } - - if (!asObject.GetType().IsSubclassOf(ObjectType) && !asObject.GetType().IsEquivalentTo(ObjectType)) - { - throw new System.Exception(string.Format("Not '{0}' object", ObjectType.Name)); - } - - try - { - object value = GetObjectPropertyValue(asObject); - return value; - } - catch (Exception) - { - throw new System.Exception($"Object has no property - {Description?.ToString()}"); - } + throw new System.Exception("Advance Steel object not found"); + } + if (!asObject.GetType().IsSubclassOf(ObjectType) && !asObject.GetType().IsEquivalentTo(ObjectType)) + { + throw new System.Exception(string.Format("Not '{0}' object", ObjectType.Name)); } - private object GetObjectPropertyValue(object asObject) + try { - if (MemberInfo is PropertyInfo) - { - PropertyInfo propertyInfo = MemberInfo as PropertyInfo; - return propertyInfo.GetValue(asObject); - } - else if (MemberInfo is MethodInfo) - { - MethodInfo methodInfo = MemberInfo as MethodInfo; - return methodInfo.Invoke(asObject, null); - } - else if (PropertyMethods?.MethodInfoGet != null) - { - return PropertyMethods.MethodInfoGet.Invoke(null, new object[] { asObject }); - } - else - { - throw new NotImplementedException(); - } + object value = GetObjectPropertyValue(asObject); + return value; } + catch (Exception) + { + throw new System.Exception($"Object has no property - {Description?.ToString()}"); + } + + } + private object GetObjectPropertyValue(object asObject) + { + if (MemberInfo is PropertyInfo) + { + PropertyInfo propertyInfo = MemberInfo as PropertyInfo; + return propertyInfo.GetValue(asObject); + } + else if (MemberInfo is MethodInfo) + { + MethodInfo methodInfo = MemberInfo as MethodInfo; + return methodInfo.Invoke(asObject, null); + } + else if (PropertyMethods?.MethodInfoGet != null) + { + return PropertyMethods.MethodInfoGet.Invoke(null, new object[] { asObject }); + } + else + { + throw new NotImplementedException(); + } } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertyMethods.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertyMethods.cs index a143d8eeef..7acec91e0e 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertyMethods.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASPropertyMethods.cs @@ -4,49 +4,48 @@ using System.Reflection; using System.Text; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class ASPropertyMethods { - public class ASPropertyMethods + internal ASPropertyMethods(Type typeProperties, string methodInfoGet, string methodInfoSet) { - internal ASPropertyMethods(Type typeProperties, string methodInfoGet, string methodInfoSet) + if (!string.IsNullOrEmpty(methodInfoGet)) { - if (!string.IsNullOrEmpty(methodInfoGet)) + MethodInfoGet = typeProperties.GetMethod(methodInfoGet, BindingFlags.Static | BindingFlags.NonPublic); + if (MethodInfoGet == null || MethodInfoGet.GetParameters().Length != 1 && MethodInfoGet.ReturnType == typeof(void)) { - MethodInfoGet = typeProperties.GetMethod(methodInfoGet, BindingFlags.Static | BindingFlags.NonPublic); - if (MethodInfoGet == null || MethodInfoGet.GetParameters().Length != 1 && MethodInfoGet.ReturnType == typeof(void)) - { - throw new Exception($"Method Get '{methodInfoGet}' must have 1 parameter, 1 return and be static"); - } + throw new Exception($"Method Get '{methodInfoGet}' must have 1 parameter, 1 return and be static"); } + } - if (!string.IsNullOrEmpty(methodInfoSet)) + if (!string.IsNullOrEmpty(methodInfoSet)) + { + MethodInfoSet = typeProperties.GetMethod(methodInfoSet, BindingFlags.Static | BindingFlags.NonPublic); + if (MethodInfoSet == null || MethodInfoSet.GetParameters().Length != 2 && MethodInfoSet.ReturnType != typeof(void)) { - MethodInfoSet = typeProperties.GetMethod(methodInfoSet, BindingFlags.Static | BindingFlags.NonPublic); - if (MethodInfoSet == null || MethodInfoSet.GetParameters().Length != 2 && MethodInfoSet.ReturnType != typeof(void)) - { - throw new Exception($"Method Set '{MethodInfoSet}' must have 2 parameters, void return and be static"); - } + throw new Exception($"Method Set '{MethodInfoSet}' must have 2 parameters, void return and be static"); } + } - if (MethodInfoGet == null && MethodInfoSet == null) - { - throw new Exception("Must have at least 1 get or set function"); - } + if (MethodInfoGet == null && MethodInfoSet == null) + { + throw new Exception("Must have at least 1 get or set function"); + } - if (MethodInfoGet != null && MethodInfoSet != null) + if (MethodInfoGet != null && MethodInfoSet != null) + { + //Compare set parameter with get return + if (MethodInfoGet.ReturnType != MethodInfoSet.GetParameters()[1].ParameterType) { - //Compare set parameter with get return - if (MethodInfoGet.ReturnType != MethodInfoSet.GetParameters()[1].ParameterType) - { - throw new Exception("The get return type must be the same second parameter of set method"); - } + throw new Exception("The get return type must be the same second parameter of set method"); } - } - internal MethodInfo MethodInfoGet { get; private set; } - - internal MethodInfo MethodInfoSet { get; private set; } } + + internal MethodInfo MethodInfoGet { get; private set; } + + internal MethodInfo MethodInfoSet { get; private set; } } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASTypeData.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASTypeData.cs index 5bf182e07a..e8004ce300 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASTypeData.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/ASTypeData.cs @@ -5,43 +5,44 @@ using System.Reflection; using System.Text; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class ASTypeData { - public class ASTypeData - { - internal string Description { get; private set; } + internal string Description { get; private set; } - internal Dictionary PropertiesSpecific { get; private set; } + internal Dictionary PropertiesSpecific { get; private set; } - internal Dictionary PropertiesAll { get; private set; } + internal Dictionary PropertiesAll { get; private set; } - internal ASTypeData(string description) - { - Description = description; + internal ASTypeData(string description) + { + Description = description; - PropertiesAll = new Dictionary(); - } + PropertiesAll = new Dictionary(); + } - internal void SetPropertiesSpecific(Dictionary properties) - { - PropertiesSpecific = properties; - } + internal void SetPropertiesSpecific(Dictionary properties) + { + PropertiesSpecific = properties; + } - internal void AddPropertiesAll(Dictionary properties) + internal void AddPropertiesAll(Dictionary properties) + { + foreach (var item in properties) { - foreach (var item in properties) + if (PropertiesAll.ContainsKey(item.Key)) { - if (PropertiesAll.ContainsKey(item.Key)) - throw new Exception($"Property '{item.Key}' already added"); - - PropertiesAll.Add(item.Key, new ASProperty(item.Value)); + throw new Exception($"Property '{item.Key}' already added"); } - } - internal void OrderDictionaryPropertiesAll() - { - PropertiesAll = (from entry in PropertiesAll orderby entry.Key ascending select entry).ToDictionary(x => x.Key, y => y.Value); + PropertiesAll.Add(item.Key, new ASProperty(item.Value)); } } + + internal void OrderDictionaryPropertiesAll() + { + PropertiesAll = (from entry in PropertiesAll orderby entry.Key ascending select entry).ToDictionary(x => x.Key, y => y.Value); + } } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/IASProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/IASProperties.cs index eb514ac8c7..ebfbba5b08 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/IASProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/IASProperties.cs @@ -3,13 +3,12 @@ using System.Collections.Generic; using System.Text; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public interface IASProperties { - public interface IASProperties - { - Type ObjectType { get; } + Type ObjectType { get; } - Dictionary BuildedPropertyList(); - } + Dictionary BuildedPropertyList(); } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/AtomicElementProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/AtomicElementProperties.cs index 4ac98afec8..575b7e765a 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/AtomicElementProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/AtomicElementProperties.cs @@ -10,141 +10,142 @@ using ASObjectId = Autodesk.AdvanceSteel.CADLink.Database.ObjectId; using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class AtomicElementProperties : ASBaseProperties, IASProperties { - public class AtomicElementProperties : ASBaseProperties, IASProperties + public override Dictionary BuildedPropertyList() { - public override Dictionary BuildedPropertyList() - { - Dictionary dictionary = new Dictionary(); - - InsertProperty(dictionary, "volume", nameof(AtomicElement.Volume)); - InsertProperty(dictionary, "numbering - assembly", nameof(AtomicElement.AssemblyUsedForNumbering)); - InsertProperty(dictionary, "numbering - note", nameof(AtomicElement.NoteUsedForNumbering)); - InsertProperty(dictionary, "numbering - role", nameof(AtomicElement.RoleUsedForNumbering)); - InsertProperty(dictionary, "BOM - single part", nameof(AtomicElement.SinglePartUsedForBOM)); - InsertProperty(dictionary, "BOM - main part", nameof(AtomicElement.MainPartUsedForBOM)); - InsertProperty(dictionary, "collision check - single part", nameof(AtomicElement.SinglePartUsedForCollisionCheck)); - InsertProperty(dictionary, "collision check - main part", nameof(AtomicElement.MainPartUsedForCollisionCheck)); - InsertProperty(dictionary, "structural member", nameof(AtomicElement.StructuralMember)); - InsertProperty(dictionary, "numbering - holes", nameof(AtomicElement.HolesUsedForNumbering)); - InsertProperty(dictionary, "mainPart number", nameof(AtomicElement.MainPartNumber)); - InsertProperty(dictionary, "singlePart number", nameof(AtomicElement.SinglePartNumber)); - InsertProperty(dictionary, "preliminary part prefix", nameof(AtomicElement.PreliminaryPartPrefix)); - InsertProperty(dictionary, "preliminary part number", nameof(AtomicElement.PreliminaryPartNumber)); - InsertProperty(dictionary, "preliminary part position number", nameof(AtomicElement.PreliminaryPartPositionNumber)); - InsertProperty(dictionary, "numbering - item number", nameof(AtomicElement.ItemNumberUsedForNumbering)); - InsertProperty(dictionary, "numbering - dennotation", nameof(AtomicElement.DennotationUsedForNumbering)); - InsertProperty(dictionary, "numbering - coating", nameof(AtomicElement.CoatingUsedForNumbering)); - InsertProperty(dictionary, "numbering - material", nameof(AtomicElement.MaterialUsedForNumbering)); - InsertProperty(dictionary, "unwind start factor", nameof(AtomicElement.UnwindStartFactor)); - InsertProperty(dictionary, "denotation", nameof(AtomicElement.Denotation)); - InsertProperty(dictionary, "assembly", nameof(AtomicElement.Assembly)); - InsertProperty(dictionary, "note", nameof(AtomicElement.Note)); - InsertProperty(dictionary, "item number", nameof(AtomicElement.ItemNumber)); - InsertProperty(dictionary, "specific gravity", nameof(AtomicElement.SpecificGravity)); - InsertProperty(dictionary, "coating", nameof(AtomicElement.Coating)); - InsertProperty(dictionary, "holes number", nameof(AtomicElement.NumberOfHoles)); - InsertProperty(dictionary, "is attached part", nameof(AtomicElement.IsAttachedPart)); - InsertProperty(dictionary, "is main part", nameof(AtomicElement.IsMainPart)); - InsertProperty(dictionary, "main part prefix", nameof(AtomicElement.MainPartPrefix)); - InsertProperty(dictionary, "single part prefix", nameof(AtomicElement.SinglePartPrefix)); - InsertProperty(dictionary, "numbering - single part", nameof(AtomicElement.SinglePartUsedForNumbering)); - InsertProperty(dictionary, "numbering - main part", nameof(AtomicElement.MainPartUsedForNumbering)); - InsertProperty(dictionary, "explicit quantity", nameof(AtomicElement.ExplicitQuantity)); - InsertProperty(dictionary, "material description", nameof(AtomicElement.MaterialDescription)); - InsertProperty(dictionary, "coating description", nameof(AtomicElement.CoatingDescription)); - InsertProperty(dictionary, "material", nameof(AtomicElement.Material)); - InsertProperty(dictionary, "unwind", nameof(AtomicElement.Unwind)); - - //Functions - - InsertProperty(dictionary, "mainPart position", nameof(AtomicElement.GetMainPartPositionNumber)); - InsertProperty(dictionary, "model quantity", nameof(AtomicElement.GetQuantityInModel)); - InsertProperty(dictionary, "singlePart position", nameof(AtomicElement.GetSinglePartPositionNumber)); - InsertProperty(dictionary, "features number", nameof(AtomicElement.NumFeatures)); - InsertCustomProperty(dictionary, "cuts number", nameof(AtomicElementProperties.GetCutsNumber), null); - InsertCustomProperty(dictionary, "balance point", nameof(AtomicElementProperties.GetBalancePoint), null); - InsertCustomProperty(dictionary, "holes", nameof(AtomicElementProperties.GetHoles), null, eUnitType.kDistance); - InsertCustomProperty(dictionary, "numbering - valid single part", nameof(AtomicElementProperties.HasValidSPNumber), null); - InsertCustomProperty(dictionary, "numbering - valid main part", nameof(AtomicElementProperties.HasValidMPNumber), null); - - return dictionary; - } + Dictionary dictionary = new(); + + InsertProperty(dictionary, "volume", nameof(AtomicElement.Volume)); + InsertProperty(dictionary, "numbering - assembly", nameof(AtomicElement.AssemblyUsedForNumbering)); + InsertProperty(dictionary, "numbering - note", nameof(AtomicElement.NoteUsedForNumbering)); + InsertProperty(dictionary, "numbering - role", nameof(AtomicElement.RoleUsedForNumbering)); + InsertProperty(dictionary, "BOM - single part", nameof(AtomicElement.SinglePartUsedForBOM)); + InsertProperty(dictionary, "BOM - main part", nameof(AtomicElement.MainPartUsedForBOM)); + InsertProperty(dictionary, "collision check - single part", nameof(AtomicElement.SinglePartUsedForCollisionCheck)); + InsertProperty(dictionary, "collision check - main part", nameof(AtomicElement.MainPartUsedForCollisionCheck)); + InsertProperty(dictionary, "structural member", nameof(AtomicElement.StructuralMember)); + InsertProperty(dictionary, "numbering - holes", nameof(AtomicElement.HolesUsedForNumbering)); + InsertProperty(dictionary, "mainPart number", nameof(AtomicElement.MainPartNumber)); + InsertProperty(dictionary, "singlePart number", nameof(AtomicElement.SinglePartNumber)); + InsertProperty(dictionary, "preliminary part prefix", nameof(AtomicElement.PreliminaryPartPrefix)); + InsertProperty(dictionary, "preliminary part number", nameof(AtomicElement.PreliminaryPartNumber)); + InsertProperty(dictionary, "preliminary part position number", nameof(AtomicElement.PreliminaryPartPositionNumber)); + InsertProperty(dictionary, "numbering - item number", nameof(AtomicElement.ItemNumberUsedForNumbering)); + InsertProperty(dictionary, "numbering - dennotation", nameof(AtomicElement.DennotationUsedForNumbering)); + InsertProperty(dictionary, "numbering - coating", nameof(AtomicElement.CoatingUsedForNumbering)); + InsertProperty(dictionary, "numbering - material", nameof(AtomicElement.MaterialUsedForNumbering)); + InsertProperty(dictionary, "unwind start factor", nameof(AtomicElement.UnwindStartFactor)); + InsertProperty(dictionary, "denotation", nameof(AtomicElement.Denotation)); + InsertProperty(dictionary, "assembly", nameof(AtomicElement.Assembly)); + InsertProperty(dictionary, "note", nameof(AtomicElement.Note)); + InsertProperty(dictionary, "item number", nameof(AtomicElement.ItemNumber)); + InsertProperty(dictionary, "specific gravity", nameof(AtomicElement.SpecificGravity)); + InsertProperty(dictionary, "coating", nameof(AtomicElement.Coating)); + InsertProperty(dictionary, "holes number", nameof(AtomicElement.NumberOfHoles)); + InsertProperty(dictionary, "is attached part", nameof(AtomicElement.IsAttachedPart)); + InsertProperty(dictionary, "is main part", nameof(AtomicElement.IsMainPart)); + InsertProperty(dictionary, "main part prefix", nameof(AtomicElement.MainPartPrefix)); + InsertProperty(dictionary, "single part prefix", nameof(AtomicElement.SinglePartPrefix)); + InsertProperty(dictionary, "numbering - single part", nameof(AtomicElement.SinglePartUsedForNumbering)); + InsertProperty(dictionary, "numbering - main part", nameof(AtomicElement.MainPartUsedForNumbering)); + InsertProperty(dictionary, "explicit quantity", nameof(AtomicElement.ExplicitQuantity)); + InsertProperty(dictionary, "material description", nameof(AtomicElement.MaterialDescription)); + InsertProperty(dictionary, "coating description", nameof(AtomicElement.CoatingDescription)); + InsertProperty(dictionary, "material", nameof(AtomicElement.Material)); + InsertProperty(dictionary, "unwind", nameof(AtomicElement.Unwind)); + + //Functions + + InsertProperty(dictionary, "mainPart position", nameof(AtomicElement.GetMainPartPositionNumber)); + InsertProperty(dictionary, "model quantity", nameof(AtomicElement.GetQuantityInModel)); + InsertProperty(dictionary, "singlePart position", nameof(AtomicElement.GetSinglePartPositionNumber)); + InsertProperty(dictionary, "features number", nameof(AtomicElement.NumFeatures)); + InsertCustomProperty(dictionary, "cuts number", nameof(AtomicElementProperties.GetCutsNumber), null); + InsertCustomProperty(dictionary, "balance point", nameof(AtomicElementProperties.GetBalancePoint), null); + InsertCustomProperty(dictionary, "holes", nameof(AtomicElementProperties.GetHoles), null, eUnitType.kDistance); + InsertCustomProperty(dictionary, "numbering - valid single part", nameof(AtomicElementProperties.HasValidSPNumber), null); + InsertCustomProperty(dictionary, "numbering - valid main part", nameof(AtomicElementProperties.HasValidMPNumber), null); + + return dictionary; + } - private static double GetCutsNumber(AtomicElement atomicElement) + private static double GetCutsNumber(AtomicElement atomicElement) + { + return atomicElement.NumFeatures() - atomicElement.NumberOfHoles; + } + + private static Point3d GetBalancePoint(AtomicElement atomicElement) + { + //it's necessary round the balance point because it has different returns at the last decimals + if(!atomicElement.GetBalancepoint(out var point, out var weigth)) { - return atomicElement.NumFeatures() - atomicElement.NumberOfHoles; + return Point3d.kOrigin; } - private static Point3d GetBalancePoint(AtomicElement atomicElement) - { - //it's necessary round the balance point because it has different returns at the last decimals - if(!atomicElement.GetBalancepoint(out var point, out var weigth)) - { - return Point3d.kOrigin; - } + return new Point3d(Round(point.x), Round(point.y), Round(point.z)); + } - return new Point3d(Round(point.x), Round(point.y), Round(point.z)); - } + private static bool HasValidSPNumber(AtomicElement atomicElement) + { + atomicElement.GetNumberingStatus(out bool hasValidSPNumber, out bool hasValidMPNumber); + return hasValidSPNumber; + } - private static bool HasValidSPNumber(AtomicElement atomicElement) - { - atomicElement.GetNumberingStatus(out bool hasValidSPNumber, out bool hasValidMPNumber); - return hasValidSPNumber; - } + private static bool HasValidMPNumber(AtomicElement atomicElement) + { + atomicElement.GetNumberingStatus(out bool hasValidSPNumber, out bool hasValidMPNumber); + return hasValidMPNumber; + } - private static bool HasValidMPNumber(AtomicElement atomicElement) - { - atomicElement.GetNumberingStatus(out bool hasValidSPNumber, out bool hasValidMPNumber); - return hasValidMPNumber; - } + private static List> GetHoles(AtomicElement atomicElement) + { + var holes = GetHolesFeatures(atomicElement); - private static List> GetHoles(AtomicElement atomicElement) - { - var holes = GetHolesFeatures(atomicElement); + List> listHolesDetails = new(); - List> listHolesDetails = new List>(); + foreach (var hole in holes) + { + hole.CS.GetCoordSystem(out var point, out _, out _, out var vectorZ); - foreach (var hole in holes) + Dictionary holeProperties = new() { - hole.CS.GetCoordSystem(out var point, out _, out _, out var vectorZ); + { "diameter", hole.Hole.Diameter}, + { "center", point }, + { "normal", vectorZ } + }; - Dictionary holeProperties = new Dictionary - { - { "diameter", hole.Hole.Diameter}, - { "center", point }, - { "normal", vectorZ } - }; + listHolesDetails.Add(holeProperties); + } - listHolesDetails.Add(holeProperties); - } + return listHolesDetails; + } - return listHolesDetails; - } + private static List GetHolesFeatures(AtomicElement pAtomicElement) + { + List holes = new(); - private static List GetHolesFeatures(AtomicElement pAtomicElement) + if (pAtomicElement == null) { - List holes = new List(); - - if (pAtomicElement == null) - return holes; + return holes; + } - var features = pAtomicElement.GetFeatures(true); + var features = pAtomicElement.GetFeatures(true); - foreach (ASObjectId objectIDASFeature in features) + foreach (ASObjectId objectIDASFeature in features) + { + FilerObject filerObject = DatabaseManager.Open(objectIDASFeature); + if (filerObject is ConnectionHoleFeature) { - FilerObject filerObject = DatabaseManager.Open(objectIDASFeature); - if (filerObject is ConnectionHoleFeature) - { - ConnectionHoleFeature connectionHoleFeature = (ConnectionHoleFeature)filerObject; - holes.Add(connectionHoleFeature); - } + ConnectionHoleFeature connectionHoleFeature = (ConnectionHoleFeature)filerObject; + holes.Add(connectionHoleFeature); } - - return holes; } + return holes; } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BeamProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BeamProperties.cs index 1961152075..feaff458ee 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BeamProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BeamProperties.cs @@ -12,133 +12,132 @@ using static Autodesk.AdvanceSteel.DotNetRoots.Units.Unit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class BeamProperties : ASBaseProperties, IASProperties { - public class BeamProperties : ASBaseProperties, IASProperties + public override Dictionary BuildedPropertyList() { - public override Dictionary BuildedPropertyList() - { - Dictionary dictionary = new Dictionary(); - - InsertProperty(dictionary, "profile section name", nameof(ASBeam.ProfSectionName)); - InsertProperty(dictionary, "profile section type", nameof(ASBeam.ProfSectionType)); - InsertProperty(dictionary, "systemline length", nameof(ASBeam.SysLength), eUnitType.kDistance); - InsertProperty(dictionary, "deviation", nameof(ASBeam.Deviation)); - InsertProperty(dictionary, "shrink value", nameof(ASBeam.ShrinkValue)); - InsertProperty(dictionary, "angle (radians)", nameof(ASBeam.Angle)); - InsertProperty(dictionary, "profile name", nameof(ASBeam.ProfName)); - InsertProperty(dictionary, "run name", nameof(ASBeam.Runname)); - InsertProperty(dictionary, "length", nameof(ASBeam.GetLength), eUnitType.kDistance); - InsertProperty(dictionary, "weight (per meter)", nameof(ASBeam.GetWeightPerMeter)); - InsertProperty(dictionary, "paint area", nameof(ASBeam.GetPaintArea), eUnitType.kArea); - InsertProperty(dictionary, "is cross section mirrored", nameof(ASBeam.IsCrossSectionMirrored)); - InsertProperty(dictionary, "reference axis description", nameof(ASBeam.RefAxis)); - - InsertCustomProperty(dictionary, "offsets", nameof(BeamProperties.GetOffsets), null, eUnitType.kDistance); - InsertCustomProperty(dictionary, "start point", nameof(BeamProperties.GetPointAtStart), null); - InsertCustomProperty(dictionary, "end point", nameof(BeamProperties.GetPointAtEnd), null); - InsertCustomProperty(dictionary, "weight", nameof(BeamProperties.GetWeightExact), null, eUnitType.kWeight); - //InsertCustomProperty(dictionary, "weight (exact)", nameof(BeamProperties.GetWeightExact), null, eUnitType.kWeight); - //InsertCustomProperty(dictionary, "weight (fast)", nameof(BeamProperties.GetWeightFast), null, eUnitType.kWeight); - InsertCustomProperty(dictionary, "profile type code", nameof(BeamProperties.GetProfileTypeCode), null); - InsertCustomProperty(dictionary, "profile type", nameof(BeamProperties.GetProfileType), null); - InsertCustomProperty(dictionary, "saw length", nameof(BeamProperties.GetSawLength), null); - InsertCustomProperty(dictionary, "flange angle at start", nameof(BeamProperties.GetFlangeAngleAtStart), null); - InsertCustomProperty(dictionary, "flange angle at end", nameof(BeamProperties.GetFlangeAngleAtEnd), null); - InsertCustomProperty(dictionary, "web angle at start", nameof(BeamProperties.GetWebAngleAtStart), null); - InsertCustomProperty(dictionary, "web angle at end", nameof(BeamProperties.GetWebAngleAtEnd), null); - - return dictionary; - } - - private static ASPoint3d GetPointAtStart(ASBeam beam) - { - return beam.GetPointAtStart(); - } + Dictionary dictionary = new(); + + InsertProperty(dictionary, "profile section name", nameof(ASBeam.ProfSectionName)); + InsertProperty(dictionary, "profile section type", nameof(ASBeam.ProfSectionType)); + InsertProperty(dictionary, "systemline length", nameof(ASBeam.SysLength), eUnitType.kDistance); + InsertProperty(dictionary, "deviation", nameof(ASBeam.Deviation)); + InsertProperty(dictionary, "shrink value", nameof(ASBeam.ShrinkValue)); + InsertProperty(dictionary, "angle (radians)", nameof(ASBeam.Angle)); + InsertProperty(dictionary, "profile name", nameof(ASBeam.ProfName)); + InsertProperty(dictionary, "run name", nameof(ASBeam.Runname)); + InsertProperty(dictionary, "length", nameof(ASBeam.GetLength), eUnitType.kDistance); + InsertProperty(dictionary, "weight (per meter)", nameof(ASBeam.GetWeightPerMeter)); + InsertProperty(dictionary, "paint area", nameof(ASBeam.GetPaintArea), eUnitType.kArea); + InsertProperty(dictionary, "is cross section mirrored", nameof(ASBeam.IsCrossSectionMirrored)); + InsertProperty(dictionary, "reference axis description", nameof(ASBeam.RefAxis)); + + InsertCustomProperty(dictionary, "offsets", nameof(BeamProperties.GetOffsets), null, eUnitType.kDistance); + InsertCustomProperty(dictionary, "start point", nameof(BeamProperties.GetPointAtStart), null); + InsertCustomProperty(dictionary, "end point", nameof(BeamProperties.GetPointAtEnd), null); + InsertCustomProperty(dictionary, "weight", nameof(BeamProperties.GetWeightExact), null, eUnitType.kWeight); + //InsertCustomProperty(dictionary, "weight (exact)", nameof(BeamProperties.GetWeightExact), null, eUnitType.kWeight); + //InsertCustomProperty(dictionary, "weight (fast)", nameof(BeamProperties.GetWeightFast), null, eUnitType.kWeight); + InsertCustomProperty(dictionary, "profile type code", nameof(BeamProperties.GetProfileTypeCode), null); + InsertCustomProperty(dictionary, "profile type", nameof(BeamProperties.GetProfileType), null); + InsertCustomProperty(dictionary, "saw length", nameof(BeamProperties.GetSawLength), null); + InsertCustomProperty(dictionary, "flange angle at start", nameof(BeamProperties.GetFlangeAngleAtStart), null); + InsertCustomProperty(dictionary, "flange angle at end", nameof(BeamProperties.GetFlangeAngleAtEnd), null); + InsertCustomProperty(dictionary, "web angle at start", nameof(BeamProperties.GetWebAngleAtStart), null); + InsertCustomProperty(dictionary, "web angle at end", nameof(BeamProperties.GetWebAngleAtEnd), null); + + return dictionary; + } - private static ASPoint3d GetPointAtEnd(ASBeam beam) - { - return beam.GetPointAtEnd(); - } + private static ASPoint3d GetPointAtStart(ASBeam beam) + { + return beam.GetPointAtStart(); + } - private static Dictionary GetOffsets(ASBeam beam) - { - Dictionary dictionary = new Dictionary - { - { "Y", beam.Offsets.x }, - { "Z", beam.Offsets.y } - }; + private static ASPoint3d GetPointAtEnd(ASBeam beam) + { + return beam.GetPointAtEnd(); + } - return dictionary; - } + private static Dictionary GetOffsets(ASBeam beam) + { + Dictionary dictionary = new() + { + { "Y", beam.Offsets.x }, + { "Z", beam.Offsets.y } + }; - //private static double GetWeight(ASBeam beam) - //{ - // //1 yields the weight, 2 the exact weight - // return beam.GetWeight(1); - //} + return dictionary; + } - private static double GetWeightExact(ASBeam beam) - { - //1 yields the weight, 2 the exact weight - return beam.GetWeight(2); - } + //private static double GetWeight(ASBeam beam) + //{ + // //1 yields the weight, 2 the exact weight + // return beam.GetWeight(1); + //} - //private static double GetWeightFast(ASBeam beam) - //{ - // //3 the fast weight - // return beam.GetWeight(3); - //} + private static double GetWeightExact(ASBeam beam) + { + //1 yields the weight, 2 the exact weight + return beam.GetWeight(2); + } - private static string GetProfileTypeCode(ASBeam beam) - { - return beam.GetProfType().GetDSTVValues().GetProfileTypeString(); - } + //private static double GetWeightFast(ASBeam beam) + //{ + // //3 the fast weight + // return beam.GetWeight(3); + //} - private static int GetProfileType(ASBeam beam) - { - return (int)beam.GetProfType().GetDSTVValues().DSTVType; - } + private static string GetProfileTypeCode(ASBeam beam) + { + return beam.GetProfType().GetDSTVValues().GetProfileTypeString(); + } - private static double GetSawLength(ASBeam beam) - { - GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); - return sawLength; - } + private static int GetProfileType(ASBeam beam) + { + return (int)beam.GetProfType().GetDSTVValues().DSTVType; + } - private static double GetFlangeAngleAtStart(ASBeam beam) - { - GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); - return DegreeToRadian(flangeAngleAtStart); - } + private static double GetSawLength(ASBeam beam) + { + GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); + return sawLength; + } - private static double GetWebAngleAtStart(ASBeam beam) - { - GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); - return DegreeToRadian(webAngleAtStart); - } + private static double GetFlangeAngleAtStart(ASBeam beam) + { + GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); + return DegreeToRadian(flangeAngleAtStart); + } - private static double GetFlangeAngleAtEnd(ASBeam beam) - { - GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); - return DegreeToRadian(flangeAngleAtEnd); - } + private static double GetWebAngleAtStart(ASBeam beam) + { + GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); + return DegreeToRadian(webAngleAtStart); + } - private static double GetWebAngleAtEnd(ASBeam beam) - { - GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); - return DegreeToRadian(webAngleAtEnd); - } + private static double GetFlangeAngleAtEnd(ASBeam beam) + { + GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); + return DegreeToRadian(flangeAngleAtEnd); + } - private static void GetSawInformation(ASBeam beam, out double sawLength, out double flangeAngleAtStart, out double webAngleAtStart, out double flangeAngleAtEnd, out double webAngleAtEnd) - { - int executed = beam.GetSawInformation(out sawLength, out flangeAngleAtStart, out webAngleAtStart, out flangeAngleAtEnd, out webAngleAtEnd); - //if (executed <= 0) - //{ - // throw new System.Exception("No values were found for this steel Beam from Function"); - //} - } + private static double GetWebAngleAtEnd(ASBeam beam) + { + GetSawInformation(beam, out var sawLength, out var flangeAngleAtStart, out var webAngleAtStart, out var flangeAngleAtEnd, out var webAngleAtEnd); + return DegreeToRadian(webAngleAtEnd); + } + private static void GetSawInformation(ASBeam beam, out double sawLength, out double flangeAngleAtStart, out double webAngleAtStart, out double flangeAngleAtEnd, out double webAngleAtEnd) + { + int executed = beam.GetSawInformation(out sawLength, out flangeAngleAtStart, out webAngleAtStart, out flangeAngleAtEnd, out webAngleAtEnd); + //if (executed <= 0) + //{ + // throw new System.Exception("No values were found for this steel Beam from Function"); + //} } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BoltPatternProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BoltPatternProperties.cs index dc51540c30..c69a6e5a3a 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BoltPatternProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/BoltPatternProperties.cs @@ -15,7 +15,7 @@ public class BoltPatternProperties : ASBaseProperties, IASPropertie { public override Dictionary BuildedPropertyList() { - Dictionary dictionary = new Dictionary(); + Dictionary dictionary = new(); InsertProperty(dictionary, "reference point", nameof(BoltPattern.RefPoint)); InsertProperty(dictionary, "number of screws", nameof(BoltPattern.NumberOfScrews)); diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ConstructionElementProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ConstructionElementProperties.cs index a083d1081b..5fe924865c 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ConstructionElementProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ConstructionElementProperties.cs @@ -15,7 +15,7 @@ public class ConstructionElementProperties : ASBaseProperties BuildedPropertyList() { - Dictionary dictionary = new Dictionary(); + Dictionary dictionary = new(); InsertProperty(dictionary, "role description", nameof(ConstructionElement.RoleDescription)); InsertProperty(dictionary, "pure role", nameof(ConstructionElement.PureRole)); @@ -32,9 +32,13 @@ public override Dictionary BuildedPropertyList() private static double GetNumberOfDrivenConObj(ConstructionElement constructionElement) { if (constructionElement is ActiveConstructionElement activeConstructionElement) + { return activeConstructionElement.NumberOfDrivenConObj; + } else + { return 0; + } } } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/FilerObjectProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/FilerObjectProperties.cs index f245927180..d3cad27f57 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/FilerObjectProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/FilerObjectProperties.cs @@ -16,7 +16,7 @@ public class FilerObjectProperties : ASBaseProperties, IASPropertie { public override Dictionary BuildedPropertyList() { - Dictionary dictionary = new Dictionary(); + Dictionary dictionary = new(); InsertProperty(dictionary, "layer", nameof(FilerObject.Layer)); InsertProperty(dictionary, "handle", nameof(FilerObject.Handle)); diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/MainAliasProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/MainAliasProperties.cs index 92523d5673..e0faacc685 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/MainAliasProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/MainAliasProperties.cs @@ -9,35 +9,34 @@ using ASPoint3d = Autodesk.AdvanceSteel.Geometry.Point3d; using System.Linq; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class MainAliasProperties : ASBaseProperties, IASProperties { - public class MainAliasProperties : ASBaseProperties, IASProperties + public override Dictionary BuildedPropertyList() { - public override Dictionary BuildedPropertyList() - { - Dictionary dictionary = new Dictionary(); - - InsertProperty(dictionary, "numbering - fabrication station", nameof(MainAlias.FabricationStationUsedForNumbering)); - InsertProperty(dictionary, "load number", nameof(MainAlias.LoadNumber)); - InsertProperty(dictionary, "carrier", nameof(MainAlias.Carrier)); - InsertProperty(dictionary, "fabrication station", nameof(MainAlias.FabricationStation)); - InsertProperty(dictionary, "supplier", nameof(MainAlias.Supplier)); - InsertProperty(dictionary, "PO number", nameof(MainAlias.PONumber)); - InsertProperty(dictionary, "requisition number", nameof(MainAlias.RequisitionNumber)); - InsertProperty(dictionary, "heat number", nameof(MainAlias.HeatNumber)); - InsertProperty(dictionary, "shipped date", nameof(MainAlias.ShippedDate)); - InsertProperty(dictionary, "delivery date", nameof(MainAlias.DeliveryDate)); - InsertProperty(dictionary, "numbering - supplier", nameof(MainAlias.SupplierUsedForNumbering)); - InsertProperty(dictionary, "numbering - requisition number", nameof(MainAlias.RequisitionNumberUsedForNumbering)); - InsertProperty(dictionary, "approval comment", nameof(MainAlias.ApprovalComment)); - InsertProperty(dictionary, "numbering - heat number", nameof(MainAlias.HeatNumberUsedForNumbering)); - InsertProperty(dictionary, "numbering - PO number", nameof(MainAlias.PONumberUsedForNumbering)); - InsertProperty(dictionary, "approval status code", nameof(MainAlias.ApprovalStatusCode)); - InsertProperty(dictionary, "standard weight", nameof(MainAlias.GetStandardWeight)); + Dictionary dictionary = new(); - return dictionary; - } + InsertProperty(dictionary, "numbering - fabrication station", nameof(MainAlias.FabricationStationUsedForNumbering)); + InsertProperty(dictionary, "load number", nameof(MainAlias.LoadNumber)); + InsertProperty(dictionary, "carrier", nameof(MainAlias.Carrier)); + InsertProperty(dictionary, "fabrication station", nameof(MainAlias.FabricationStation)); + InsertProperty(dictionary, "supplier", nameof(MainAlias.Supplier)); + InsertProperty(dictionary, "PO number", nameof(MainAlias.PONumber)); + InsertProperty(dictionary, "requisition number", nameof(MainAlias.RequisitionNumber)); + InsertProperty(dictionary, "heat number", nameof(MainAlias.HeatNumber)); + InsertProperty(dictionary, "shipped date", nameof(MainAlias.ShippedDate)); + InsertProperty(dictionary, "delivery date", nameof(MainAlias.DeliveryDate)); + InsertProperty(dictionary, "numbering - supplier", nameof(MainAlias.SupplierUsedForNumbering)); + InsertProperty(dictionary, "numbering - requisition number", nameof(MainAlias.RequisitionNumberUsedForNumbering)); + InsertProperty(dictionary, "approval comment", nameof(MainAlias.ApprovalComment)); + InsertProperty(dictionary, "numbering - heat number", nameof(MainAlias.HeatNumberUsedForNumbering)); + InsertProperty(dictionary, "numbering - PO number", nameof(MainAlias.PONumberUsedForNumbering)); + InsertProperty(dictionary, "approval status code", nameof(MainAlias.ApprovalStatusCode)); + InsertProperty(dictionary, "standard weight", nameof(MainAlias.GetStandardWeight)); + return dictionary; } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/PolybeamProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/PolybeamProperties.cs index 267a7e901d..413a2e9374 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/PolybeamProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/PolybeamProperties.cs @@ -10,26 +10,25 @@ using ASPoint3d = Autodesk.AdvanceSteel.Geometry.Point3d; using System.Linq; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public class PolybeamProperties : ASBaseProperties, IASProperties { - public class PolybeamProperties : ASBaseProperties, IASProperties + public override Dictionary BuildedPropertyList() { - public override Dictionary BuildedPropertyList() - { - Dictionary dictionary = new Dictionary(); - - InsertProperty(dictionary, "continuous", nameof(PolyBeam.IsContinuous)); + Dictionary dictionary = new(); - InsertCustomProperty(dictionary, "points", nameof(PolybeamProperties.GetListPoints), null); - return dictionary; - } + InsertProperty(dictionary, "continuous", nameof(PolyBeam.IsContinuous)); - private static List GetListPoints(ASPolyBeam beam) - { - var polyLine = beam.GetPolyline(true); - return polyLine.Vertices.ToList(); - } + InsertCustomProperty(dictionary, "points", nameof(PolybeamProperties.GetListPoints), null); + return dictionary; + } + private static List GetListPoints(ASPolyBeam beam) + { + var polyLine = beam.GetPolyline(true); + return polyLine.Vertices.ToList(); } + } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ScrewBoltPatternProperties.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ScrewBoltPatternProperties.cs index 3f0d9f8c18..dd559138d9 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ScrewBoltPatternProperties.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/PropertySets/ScrewBoltPatternProperties.cs @@ -16,7 +16,7 @@ public class ScrewBoltPatternProperties : ASBaseProperties, IA { public override Dictionary BuildedPropertyList() { - Dictionary dictionary = new Dictionary(); + Dictionary dictionary = new(); InsertProperty(dictionary, "top tool diameter", nameof(ScrewBoltPattern.TopToolDiameter), eUnitType.kDistance); InsertProperty(dictionary, "bottom tool diameter", nameof(ScrewBoltPattern.BottomToolDiameter), eUnitType.kDistance); diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/StructureUtils.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/StructureUtils.cs index dbec949937..c49c821dc7 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/StructureUtils.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/AdvanceSteel/Properties/StructureUtils.cs @@ -14,7 +14,7 @@ internal static class StructureUtils { private static Dictionary GetStructures() { - Dictionary dictionary = new Dictionary(); + Dictionary dictionary = new(); BuildingStructureManager buildStructMan = BuildingStructureManager.getBuildingStructureManager(); // get the list objects from the manager @@ -28,7 +28,9 @@ private static Dictionary GetStructures() string name = buildStructManListObject.GetStructureName(currBSO); if (dictionary.ContainsKey(name)) + { continue; + } dictionary.Add(name, currBSO); } @@ -38,14 +40,16 @@ private static Dictionary GetStructures() private static Dictionary GetObjectsGroup(BuildingStructureObject structure) { - Dictionary dictionaryGroup = new Dictionary(); + Dictionary dictionaryGroup = new(); BuildingStructureTreeObject groupsTreeObject = structure.GroupsTreeObject; foreach (BuildingStructureItem currentItem in groupsTreeObject.StructureItems) { if (!(currentItem is ObjectsGroup objectsGroup)) + { continue; + } BuildingStructureTreeObject parent = objectsGroup.Parent; string nameGroup = parent.GetStructureItemName(objectsGroup); @@ -70,7 +74,7 @@ public static Dictionary>> GetObjectHand private static Dictionary>> GetObjectHandleHierarchyIntern() { - Dictionary>> dictionaryHierarchy = new Dictionary>>(); + Dictionary>> dictionaryHierarchy = new(); var structures = GetStructures(); diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/Converter.AutocadCivil.Utils.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/Converter.AutocadCivil.Utils.cs index 520461acb2..b02fee4864 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/Converter.AutocadCivil.Utils.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/Converter.AutocadCivil.Utils.cs @@ -17,378 +17,403 @@ using Autodesk.Aec.ApplicationServices; #endif -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public static class Utils { - public static class Utils + public static BlockTableRecord GetModelSpace(this Database db) + { + return (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForWrite); + } + + public static ObjectId Append(this BlockTableRecord owner, Entity entity) { - public static BlockTableRecord GetModelSpace(this Database db) + if (!entity.IsNewObject) { - return (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForWrite); + return entity.Id; } - public static ObjectId Append(this BlockTableRecord owner, Entity entity) + var tr = owner.Database.TransactionManager.TopTransaction; + var id = owner.AppendEntity(entity); + tr.AddNewlyCreatedDBObject(entity, true); + return id; + } + + public static Base GetObjectExtensionDictionaryAsBase(this DBObject source) + { + if (source is null || source.ExtensionDictionary == ObjectId.Null) { - if (!entity.IsNewObject) - return entity.Id; - var tr = owner.Database.TransactionManager.TopTransaction; - var id = owner.AppendEntity(entity); - tr.AddNewlyCreatedDBObject(entity, true); - return id; + return null; } - public static Base GetObjectExtensionDictionaryAsBase(this DBObject source) + var extensionDictionaryBase = new Base(); + var tr = source.Database.TransactionManager.TopTransaction; + var extensionDictionary = tr.GetObject(source.ExtensionDictionary, OpenMode.ForRead, false) as DBDictionary; + foreach (var entry in extensionDictionary) { - if (source is null || source.ExtensionDictionary == ObjectId.Null) - return null; - - var extensionDictionaryBase = new Base(); - var tr = source.Database.TransactionManager.TopTransaction; - var extensionDictionary = tr.GetObject(source.ExtensionDictionary, OpenMode.ForRead, false) as DBDictionary; - foreach (var entry in extensionDictionary) + var xRecord = tr.GetObject(entry.Value, OpenMode.ForRead) as Xrecord; // sometimes these can be RXClass objects, in property sets + if (xRecord != null) { - var xRecord = tr.GetObject(entry.Value, OpenMode.ForRead) as Xrecord; // sometimes these can be RXClass objects, in property sets - if (xRecord != null) + var entryBase = new Base(); + foreach (var xEntry in xRecord.Data) { - var entryBase = new Base(); - foreach (var xEntry in xRecord.Data) - { - entryBase[xEntry.TypeCode.ToString()] = xEntry.Value; - } - try - { - extensionDictionaryBase[$"{entry.Key}"] = entryBase; - } - catch (Exception e) { } + entryBase[xEntry.TypeCode.ToString()] = xEntry.Value; + } + try + { + extensionDictionaryBase[$"{entry.Key}"] = entryBase; } + catch (Exception e) { } } - - return extensionDictionaryBase; } + + return extensionDictionaryBase; } +} - public partial class ConverterAutocadCivil - { - public static string invalidAutocadChars = @"<>/\:;""?*|=,‘"; +public partial class ConverterAutocadCivil +{ + public static string invalidAutocadChars = @"<>/\:;""?*|=,‘"; - private Dictionary _lineTypeDictionary = new Dictionary(); - public Dictionary LineTypeDictionary + private Dictionary _lineTypeDictionary = new(); + public Dictionary LineTypeDictionary + { + get { - get + if (_lineTypeDictionary.Values.Count == 0) { - if (_lineTypeDictionary.Values.Count == 0) + var lineTypeTable = (LinetypeTable)Trans.GetObject(Doc.Database.LinetypeTableId, OpenMode.ForRead); + foreach (ObjectId lineTypeId in lineTypeTable) { - var lineTypeTable = (LinetypeTable)Trans.GetObject(Doc.Database.LinetypeTableId, OpenMode.ForRead); - foreach (ObjectId lineTypeId in lineTypeTable) - { - var linetype = (LinetypeTableRecord)Trans.GetObject(lineTypeId, OpenMode.ForRead); - _lineTypeDictionary.Add(linetype.Name, lineTypeId); - } + var linetype = (LinetypeTableRecord)Trans.GetObject(lineTypeId, OpenMode.ForRead); + _lineTypeDictionary.Add(linetype.Name, lineTypeId); } - return _lineTypeDictionary; } + return _lineTypeDictionary; } + } - /// - /// Removes invalid characters for Autocad layer and block names - /// - /// - /// - public static string RemoveInvalidAutocadChars(string str) - { - // using this to handle rhino nested layer syntax - // replace "::" layer delimiter with "$" (acad standard) - string cleanDelimiter = str.Replace("::", "$"); + /// + /// Removes invalid characters for Autocad layer and block names + /// + /// + /// + public static string RemoveInvalidAutocadChars(string str) + { + // using this to handle rhino nested layer syntax + // replace "::" layer delimiter with "$" (acad standard) + string cleanDelimiter = str.Replace("::", "$"); - // remove all other invalid chars - return Regex.Replace(cleanDelimiter, $"[{invalidAutocadChars}]", string.Empty); - } + // remove all other invalid chars + return Regex.Replace(cleanDelimiter, $"[{invalidAutocadChars}]", string.Empty); + } - /// - /// Retrieves the handle from an input string - /// - /// - /// - public static bool GetHandle(string str, out Handle handle) + /// + /// Retrieves the handle from an input string + /// + /// + /// + public static bool GetHandle(string str, out Handle handle) + { + handle = new Handle(); + try { - handle = new Handle(); - try - { - handle = new Handle(Convert.ToInt64(str, 16)); - } - catch - { - return false; - } - return true; + handle = new Handle(Convert.ToInt64(str, 16)); } - - /// - /// Returns, if found, the corresponding doc element. - /// The doc object can be null if the user deleted it. - /// - /// Id of the application that originally created the element, in autocadcivil it's the handle - /// The element, if found, otherwise null - public List GetExistingElementsByApplicationId(string applicationId) + catch { - var ids = new List(); - - if (applicationId == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) - return ids; - - // first see if this appid is a handle (autocad appid) - if (GetHandle(applicationId, out Handle handle)) - if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) - return new List() { id }; + return false; + } + return true; + } - // Create a TypedValue array to define the filter criteria - TypedValue[] acTypValAr = new TypedValue[1]; - acTypValAr.SetValue(new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), 0); + /// + /// Returns, if found, the corresponding doc element. + /// The doc object can be null if the user deleted it. + /// + /// Id of the application that originally created the element, in autocadcivil it's the handle + /// The element, if found, otherwise null + public List GetExistingElementsByApplicationId(string applicationId) + { + var ids = new List(); - // Create a selection filter for the applicationID xdata entry and find all objs with this field - SelectionFilter acSelFtr = new SelectionFilter(acTypValAr); - var res = Doc.Editor.SelectAll(acSelFtr); - if (res.Status == PromptStatus.None || res.Status == PromptStatus.Error) - return ids; + if (applicationId == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) + { + return ids; + } - // loop through all obj with an appId - foreach (var appIdObj in res.Value.GetObjectIds()) + // first see if this appid is a handle (autocad appid) + if (GetHandle(applicationId, out Handle handle)) + { + if (Doc.Database.TryGetObjectId(handle, out ObjectId id)) { - if (appIdObj.IsErased) - continue; - - // get the db object from id - var obj = Trans.GetObject(appIdObj, OpenMode.ForRead); - if (obj != null) - foreach (var entry in obj.XData) - if (entry.Value as string == applicationId) - { - ids.Add(appIdObj); - break; - } + return new List() { id }; } + } + + // Create a TypedValue array to define the filter criteria + TypedValue[] acTypValAr = new TypedValue[1]; + acTypValAr.SetValue(new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationIdKey), 0); + // Create a selection filter for the applicationID xdata entry and find all objs with this field + SelectionFilter acSelFtr = new(acTypValAr); + var res = Doc.Editor.SelectAll(acSelFtr); + if (res.Status == PromptStatus.None || res.Status == PromptStatus.Error) + { return ids; } - public ObjectId GetFromObjectIdCollection(string name, ObjectIdCollection collection, bool useFirstIfNull = false) + // loop through all obj with an appId + foreach (var appIdObj in res.Value.GetObjectIds()) { - var id = ObjectId.Null; - if ((string.IsNullOrEmpty(name) && !useFirstIfNull) || (string.IsNullOrEmpty(name) && collection.Count == 0)) - return id; + if (appIdObj.IsErased) + { + continue; + } - foreach (ObjectId collectionId in collection) + // get the db object from id + var obj = Trans.GetObject(appIdObj, OpenMode.ForRead); + if (obj != null) { - var entity = Trans.GetObject(collectionId, OpenMode.ForRead); - if (entity != null) + foreach (var entry in obj.XData) { - var props = entity.GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.Public); - if (props != null && props.CanRead) + if (entry.Value as string == applicationId) { - var entityName = props.GetValue(entity) as string; - if (entityName == name) - { - id = collectionId; - break; - } + ids.Add(appIdObj); + break; } } } + } - if (id == ObjectId.Null && useFirstIfNull && collection.Count > 0) - id = collection[0]; + return ids; + } + public ObjectId GetFromObjectIdCollection(string name, ObjectIdCollection collection, bool useFirstIfNull = false) + { + var id = ObjectId.Null; + if ((string.IsNullOrEmpty(name) && !useFirstIfNull) || (string.IsNullOrEmpty(name) && collection.Count == 0)) + { return id; } - #region Reference Point - - // CAUTION: these strings need to have the same values as in the connector bindings - const string InternalOrigin = "Internal Origin (default)"; - const string UCS = "Current User Coordinate System"; - private Matrix3d _transform; - private Matrix3d ReferencePointTransform + foreach (ObjectId collectionId in collection) { - get + var entity = Trans.GetObject(collectionId, OpenMode.ForRead); + if (entity != null) { - if (_transform == null || _transform == new Matrix3d()) + var props = entity.GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.Public); + if (props != null && props.CanRead) { - // get from settings - var referencePointSetting = Settings.ContainsKey("reference-point") - ? Settings["reference-point"] - : string.Empty; - _transform = GetReferencePointTransform(referencePointSetting); + var entityName = props.GetValue(entity) as string; + if (entityName == name) + { + id = collectionId; + break; + } } - return _transform; } } - private Matrix3d GetReferencePointTransform(string type) + if (id == ObjectId.Null && useFirstIfNull && collection.Count > 0) { - var referencePointTransform = Matrix3d.Identity; + id = collection[0]; + } + + return id; + } + + #region Reference Point - switch (type) + // CAUTION: these strings need to have the same values as in the connector bindings + const string InternalOrigin = "Internal Origin (default)"; + const string UCS = "Current User Coordinate System"; + private Matrix3d _transform; + private Matrix3d ReferencePointTransform + { + get + { + if (_transform == null || _transform == new Matrix3d()) { - case InternalOrigin: - break; - case UCS: - var cs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - if (cs != null) + // get from settings + var referencePointSetting = Settings.ContainsKey("reference-point") + ? Settings["reference-point"] + : string.Empty; + _transform = GetReferencePointTransform(referencePointSetting); + } + return _transform; + } + } + + private Matrix3d GetReferencePointTransform(string type) + { + var referencePointTransform = Matrix3d.Identity; + + switch (type) + { + case InternalOrigin: + break; + case UCS: + var cs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; + if (cs != null) + { + referencePointTransform = Matrix3d.AlignCoordinateSystem( + Point3d.Origin, + Vector3d.XAxis, + Vector3d.YAxis, + Vector3d.ZAxis, + cs.Origin, + cs.Xaxis, + cs.Yaxis, + cs.Zaxis + ); + } + + break; + default: // try to see if this is a named UCS + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + var UCSTable = tr.GetObject(Doc.Database.UcsTableId, OpenMode.ForRead) as UcsTable; + if (UCSTable.Has(type)) + { + var ucsRecord = tr.GetObject(UCSTable[type], OpenMode.ForRead) as UcsTableRecord; referencePointTransform = Matrix3d.AlignCoordinateSystem( Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis, - cs.Origin, - cs.Xaxis, - cs.Yaxis, - cs.Zaxis + ucsRecord.Origin, + ucsRecord.XAxis, + ucsRecord.YAxis, + ucsRecord.XAxis.CrossProduct(ucsRecord.YAxis) ); - break; - default: // try to see if this is a named UCS - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - { - var UCSTable = tr.GetObject(Doc.Database.UcsTableId, OpenMode.ForRead) as UcsTable; - if (UCSTable.Has(type)) - { - var ucsRecord = tr.GetObject(UCSTable[type], OpenMode.ForRead) as UcsTableRecord; - referencePointTransform = Matrix3d.AlignCoordinateSystem( - Point3d.Origin, - Vector3d.XAxis, - Vector3d.YAxis, - Vector3d.ZAxis, - ucsRecord.Origin, - ucsRecord.XAxis, - ucsRecord.YAxis, - ucsRecord.XAxis.CrossProduct(ucsRecord.YAxis) - ); - } - tr.Commit(); } - break; - } - - return referencePointTransform; + tr.Commit(); + } + break; } - /// - /// For sending out of AutocadCivil, transforms a point relative to the reference point - /// - /// - /// - public Point3d ToExternalCoordinates(Point3d p) - { - return p.TransformBy(ReferencePointTransform.Inverse()); - } + return referencePointTransform; + } - /// - /// For sending out of AutocadCivil, transforms a vector relative to the reference point - /// - /// - /// - public Vector3d ToExternalCoordinates(Vector3d v) - { - return v.TransformBy(ReferencePointTransform.Inverse()); - } + /// + /// For sending out of AutocadCivil, transforms a point relative to the reference point + /// + /// + /// + public Point3d ToExternalCoordinates(Point3d p) + { + return p.TransformBy(ReferencePointTransform.Inverse()); + } - /// - /// For receiving in to AutocadCivil, transforms a point relative to the reference point - /// - /// - /// - public Point3d ToInternalCoordinates(Point3d p) - { - return p.TransformBy(ReferencePointTransform); - } + /// + /// For sending out of AutocadCivil, transforms a vector relative to the reference point + /// + /// + /// + public Vector3d ToExternalCoordinates(Vector3d v) + { + return v.TransformBy(ReferencePointTransform.Inverse()); + } - /// - /// For receiving in to AutocadCivil, transforms a vector relative to the reference point - /// - /// - /// - public Vector3d ToInternalCoordinates(Vector3d v) - { - return v.TransformBy(ReferencePointTransform); - } - #endregion + /// + /// For receiving in to AutocadCivil, transforms a point relative to the reference point + /// + /// + /// + public Point3d ToInternalCoordinates(Point3d p) + { + return p.TransformBy(ReferencePointTransform); + } + + /// + /// For receiving in to AutocadCivil, transforms a vector relative to the reference point + /// + /// + /// + public Vector3d ToInternalCoordinates(Vector3d v) + { + return v.TransformBy(ReferencePointTransform); + } + #endregion - #region app props - public static string AutocadPropName = "AutocadProps"; - public static string CivilPropName = "CivilProps"; - #endregion + #region app props + public static string AutocadPropName = "AutocadProps"; + public static string CivilPropName = "CivilProps"; + #endregion - #region units + #region units - private string _modelUnits; - public string ModelUnits + private string _modelUnits; + public string ModelUnits + { + get { - get + if (string.IsNullOrEmpty(_modelUnits)) { - if (string.IsNullOrEmpty(_modelUnits)) - { - _modelUnits = UnitToSpeckle(Doc.Database.Insunits); + _modelUnits = UnitToSpeckle(Doc.Database.Insunits); #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - if (_modelUnits == Units.None) + if (_modelUnits == Units.None) + { + // try to get the drawing unit instead + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - // try to get the drawing unit instead - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - { - var id = DrawingSetupVariables.GetInstance(Doc.Database, false); - var setupVariables = (DrawingSetupVariables)tr.GetObject(id, OpenMode.ForRead); - var linearUnit = setupVariables.LinearUnit; - _modelUnits = Units.GetUnitsFromString(linearUnit.ToString()); - tr.Commit(); - } + var id = DrawingSetupVariables.GetInstance(Doc.Database, false); + var setupVariables = (DrawingSetupVariables)tr.GetObject(id, OpenMode.ForRead); + var linearUnit = setupVariables.LinearUnit; + _modelUnits = Units.GetUnitsFromString(linearUnit.ToString()); + tr.Commit(); } -#endif } - return _modelUnits; +#endif } + return _modelUnits; } + } - private void SetUnits(Base geom) - { - geom["units"] = ModelUnits; - } + private void SetUnits(Base geom) + { + geom["units"] = ModelUnits; + } - private double ScaleToNative(double value, string units) - { - var f = Units.GetConversionFactor(units, ModelUnits); - return value * f; - } + private double ScaleToNative(double value, string units) + { + var f = Units.GetConversionFactor(units, ModelUnits); + return value * f; + } - // Note: Difference between International Foot and US Foot is ~ 0.0000006 as described in: https://www.pobonline.com/articles/98788-us-survey-feet-versus-international-feet - private string UnitToSpeckle(UnitsValue units) + // Note: Difference between International Foot and US Foot is ~ 0.0000006 as described in: https://www.pobonline.com/articles/98788-us-survey-feet-versus-international-feet + private string UnitToSpeckle(UnitsValue units) + { + switch (units) { - switch (units) - { - case UnitsValue.Millimeters: - return Units.Millimeters; - case UnitsValue.Centimeters: - return Units.Centimeters; - case UnitsValue.Meters: - return Units.Meters; - case UnitsValue.Kilometers: - return Units.Kilometers; - case UnitsValue.Inches: - case UnitsValue.USSurveyInch: - return Units.Inches; - case UnitsValue.Feet: - case UnitsValue.USSurveyFeet: - return Units.Feet; - case UnitsValue.Yards: - case UnitsValue.USSurveyYard: - return Units.Yards; - case UnitsValue.Miles: - case UnitsValue.USSurveyMile: - return Units.Miles; - case UnitsValue.Undefined: - return Units.None; - default: - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); - } + case UnitsValue.Millimeters: + return Units.Millimeters; + case UnitsValue.Centimeters: + return Units.Centimeters; + case UnitsValue.Meters: + return Units.Meters; + case UnitsValue.Kilometers: + return Units.Kilometers; + case UnitsValue.Inches: + case UnitsValue.USSurveyInch: + return Units.Inches; + case UnitsValue.Feet: + case UnitsValue.USSurveyFeet: + return Units.Feet; + case UnitsValue.Yards: + case UnitsValue.USSurveyYard: + return Units.Yards; + case UnitsValue.Miles: + case UnitsValue.USSurveyMile: + return Units.Miles; + case UnitsValue.Undefined: + return Units.None; + default: + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); } - - #endregion } + + #endregion } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs index 0db6cc3ffd..2b40be01a2 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs @@ -33,1103 +33,1260 @@ using Station = Objects.BuiltElements.Station; using Structure = Objects.BuiltElements.Structure; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + private bool GetCivilDocument(ApplicationObject appObj, out CivilDocument doc) { - private bool GetCivilDocument(ApplicationObject appObj, out CivilDocument doc) + BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); + doc = CivilApplication.ActiveDocument; + if (doc is null) { - BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); - doc = CivilApplication.ActiveDocument; - if (doc is null) - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not retrieve civil3d document"); - return doc is null ? false : true; + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not retrieve civil3d document"); } - // stations - public Station StationToSpeckle(CivilDB.Station station) + return doc is null ? false : true; + } + + // stations + public Station StationToSpeckle(CivilDB.Station station) + { + var _station = new Station(); + _station.location = PointToSpeckle(station.Location); + _station.type = station.StationType.ToString(); + _station.number = station.RawStation; + _station.units = ModelUnits; + + return _station; + } + + // alignments + public CivilAlignment AlignmentToSpeckle(CivilDB.Alignment alignment) + { + var _alignment = new CivilAlignment(); + + // get alignment props + _alignment.type = alignment.AlignmentType.ToString(); + _alignment.offset = alignment.IsOffsetAlignment ? alignment.OffsetAlignmentInfo.NominalOffset : 0; + if (alignment.SiteName != null) { - var _station = new Station(); - _station.location = PointToSpeckle(station.Location); - _station.type = station.StationType.ToString(); - _station.number = station.RawStation; - _station.units = ModelUnits; + _alignment.site = alignment.SiteName; + } - return _station; + if (alignment.StyleName != null) + { + _alignment.style = alignment.StyleName; } - // alignments - public CivilAlignment AlignmentToSpeckle(CivilDB.Alignment alignment) + if (alignment.Description != null) { - var _alignment = new CivilAlignment(); - - // get alignment props - _alignment.type = alignment.AlignmentType.ToString(); - _alignment.offset = alignment.IsOffsetAlignment ? alignment.OffsetAlignmentInfo.NominalOffset : 0; - if (alignment.SiteName != null) - _alignment.site = alignment.SiteName; - if (alignment.StyleName != null) - _alignment.style = alignment.StyleName; - if (alignment.Description != null) - _alignment["description"] = alignment.Description; - if (alignment.Name != null) - _alignment.name = alignment.Name; - - // get alignment stations - _alignment.startStation = alignment.StartingStation; - _alignment.endStation = alignment.EndingStation; - var stations = alignment.GetStationSet(CivilDB.StationTypes.All).ToList(); - List _stations = stations.Select(o => StationToSpeckle(o)).ToList(); - if (_stations.Count > 0) _alignment["@stations"] = _stations; - - // handle station equations - var equations = new List(); - var directions = new List(); - foreach (var stationEquation in alignment.StationEquations) - { - equations.AddRange(new List { stationEquation.RawStationBack, stationEquation.StationBack, stationEquation.StationAhead }); - bool equationIncreasing = (stationEquation.EquationType.Equals(CivilDB.StationEquationType.Increasing)) ? true : false; - directions.Add(equationIncreasing); - } - _alignment.stationEquations = equations; - _alignment.stationEquationDirections = directions; + _alignment["description"] = alignment.Description; + } - // get alignment profiles - var profiles = new List(); - foreach (ObjectId profileId in alignment.GetProfileIds()) + if (alignment.Name != null) + { + _alignment.name = alignment.Name; + } + + // get alignment stations + _alignment.startStation = alignment.StartingStation; + _alignment.endStation = alignment.EndingStation; + var stations = alignment.GetStationSet(CivilDB.StationTypes.All).ToList(); + List _stations = stations.Select(o => StationToSpeckle(o)).ToList(); + if (_stations.Count > 0) + { + _alignment["@stations"] = _stations; + } + + // handle station equations + var equations = new List(); + var directions = new List(); + foreach (var stationEquation in alignment.StationEquations) + { + equations.AddRange(new List { stationEquation.RawStationBack, stationEquation.StationBack, stationEquation.StationAhead }); + bool equationIncreasing = (stationEquation.EquationType.Equals(CivilDB.StationEquationType.Increasing)) ? true : false; + directions.Add(equationIncreasing); + } + _alignment.stationEquations = equations; + _alignment.stationEquationDirections = directions; + + // get alignment profiles + var profiles = new List(); + foreach (ObjectId profileId in alignment.GetProfileIds()) + { + var profile = Trans.GetObject(profileId, OpenMode.ForRead) as CivilDB.Profile; + var convertedProfile = ProfileToSpeckle(profile); + if (convertedProfile != null) { - var profile = Trans.GetObject(profileId, OpenMode.ForRead) as CivilDB.Profile; - var convertedProfile = ProfileToSpeckle(profile); - if (convertedProfile != null) - { - profiles.Add(convertedProfile); - } + profiles.Add(convertedProfile); } - _alignment.profiles = profiles; + } + _alignment.profiles = profiles; - // get the alignment subentity curves - List curves = new List(); - for (int i = 0; i < alignment.Entities.Count; i++) - { - var entity = alignment.Entities.GetEntityByOrder(i); + // get the alignment subentity curves + List curves = new(); + for (int i = 0; i < alignment.Entities.Count; i++) + { + var entity = alignment.Entities.GetEntityByOrder(i); - var polycurve = new Polycurve(units: ModelUnits, applicationId: entity.EntityId.ToString()); - var segments = new List(); - double length = 0; - for (int j = 0; j < entity.SubEntityCount; j++) + var polycurve = new Polycurve(units: ModelUnits, applicationId: entity.EntityId.ToString()); + var segments = new List(); + double length = 0; + for (int j = 0; j < entity.SubEntityCount; j++) + { + CivilDB.AlignmentSubEntity subEntity = entity[j]; + ICurve segment = null; + switch (subEntity.SubEntityType) { - CivilDB.AlignmentSubEntity subEntity = entity[j]; - ICurve segment = null; - switch (subEntity.SubEntityType) - { - case CivilDB.AlignmentSubEntityType.Arc: - var arc = subEntity as CivilDB.AlignmentSubEntityArc; - segment = AlignmentArcToSpeckle(arc); - break; - case CivilDB.AlignmentSubEntityType.Line: - var line = subEntity as CivilDB.AlignmentSubEntityLine; - segment = AlignmentLineToSpeckle(line); - break; - case CivilDB.AlignmentSubEntityType.Spiral: - var spiral = subEntity as CivilDB.AlignmentSubEntitySpiral; - segment = AlignmentSpiralToSpeckle(spiral, alignment); - break; - } - if (segment != null) - { - length += subEntity.Length; - segments.Add(segment); - } + case CivilDB.AlignmentSubEntityType.Arc: + var arc = subEntity as CivilDB.AlignmentSubEntityArc; + segment = AlignmentArcToSpeckle(arc); + break; + case CivilDB.AlignmentSubEntityType.Line: + var line = subEntity as CivilDB.AlignmentSubEntityLine; + segment = AlignmentLineToSpeckle(line); + break; + case CivilDB.AlignmentSubEntityType.Spiral: + var spiral = subEntity as CivilDB.AlignmentSubEntitySpiral; + segment = AlignmentSpiralToSpeckle(spiral, alignment); + break; } - if (segments.Count == 1) + if (segment != null) { - curves.Add(segments[0]); + length += subEntity.Length; + segments.Add(segment); } - else - { - polycurve.segments = segments; - polycurve.length = length; + } + if (segments.Count == 1) + { + curves.Add(segments[0]); + } + else + { + polycurve.segments = segments; + polycurve.length = length; - // add additional props like entity type - polycurve["alignmentType"] = entity.EntityType.ToString(); - curves.Add(polycurve); - } + // add additional props like entity type + polycurve["alignmentType"] = entity.EntityType.ToString(); + curves.Add(polycurve); } - _alignment.curves = curves; + } + _alignment.curves = curves; - // if offset alignment, also set parent and offset side - if (alignment.IsOffsetAlignment) + // if offset alignment, also set parent and offset side + if (alignment.IsOffsetAlignment) + { + _alignment["offsetSide"] = alignment.OffsetAlignmentInfo.Side.ToString(); + try { - _alignment["offsetSide"] = alignment.OffsetAlignmentInfo.Side.ToString(); - try + var parent = Trans.GetObject(alignment.OffsetAlignmentInfo.ParentAlignmentId, OpenMode.ForRead) as CivilDB.Alignment; + if (parent != null && parent.Name != null) { - var parent = Trans.GetObject(alignment.OffsetAlignmentInfo.ParentAlignmentId, OpenMode.ForRead) as CivilDB.Alignment; - if (parent != null && parent.Name != null) - _alignment.parent = parent.Name; + _alignment.parent = parent.Name; } - catch { } } + catch { } + } + + return _alignment; + } + public ApplicationObject AlignmentToNative(Alignment alignment) + { + var appObj = new ApplicationObject(alignment.id, alignment.speckle_type) { applicationId = alignment.applicationId }; + var existingObjs = GetExistingElementsByApplicationId(alignment.applicationId); + var civilAlignment = alignment as CivilAlignment; - return _alignment; + // get civil doc + if (!GetCivilDocument(appObj, out CivilDocument civilDoc)) + { + return appObj; } - public ApplicationObject AlignmentToNative(Alignment alignment) + + // create or retrieve alignment, and parent if it exists + CivilDB.Alignment _alignment = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.Alignment : null; + var parent = civilAlignment != null ? GetFromObjectIdCollection(civilAlignment.parent, civilDoc.GetAlignmentIds()) : ObjectId.Null; + bool isUpdate = true; + if (_alignment == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new alignment { - var appObj = new ApplicationObject(alignment.id, alignment.speckle_type) { applicationId = alignment.applicationId }; - var existingObjs = GetExistingElementsByApplicationId(alignment.applicationId); - var civilAlignment = alignment as CivilAlignment; - - // get civil doc - if (!GetCivilDocument(appObj, out CivilDocument civilDoc)) - return appObj; - - // create or retrieve alignment, and parent if it exists - CivilDB.Alignment _alignment = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.Alignment : null; - var parent = civilAlignment != null ? GetFromObjectIdCollection(civilAlignment.parent, civilDoc.GetAlignmentIds()) : ObjectId.Null; - bool isUpdate = true; - if (_alignment == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new alignment - { - isUpdate = false; + isUpdate = false; - // get civil props for creation + // get civil props for creation #region properties - var name = string.IsNullOrEmpty(alignment.name) ? alignment.applicationId : alignment.name; // names need to be unique on creation (but not send i guess??) - var layer = Doc.Database.LayerZero; - - // type - var type = CivilDB.AlignmentType.Centerline; - if (civilAlignment != null) - if (Enum.TryParse(civilAlignment.type, out CivilDB.AlignmentType civilType)) - type = civilType; - - // site - var site = civilAlignment != null ? - GetFromObjectIdCollection(civilAlignment.site, civilDoc.GetSiteIds()) : ObjectId.Null; - - // style - var docStyles = new ObjectIdCollection(); - foreach (ObjectId styleId in civilDoc.Styles.AlignmentStyles) docStyles.Add(styleId); - var style = civilAlignment != null ? - GetFromObjectIdCollection(civilAlignment.style, docStyles, true) : civilDoc.Styles.AlignmentStyles.First(); - - // label set style - var labelStyles = new ObjectIdCollection(); - foreach (ObjectId styleId in civilDoc.Styles.LabelSetStyles.AlignmentLabelSetStyles) labelStyles.Add(styleId); - var label = civilAlignment != null ? - GetFromObjectIdCollection(civilAlignment["label"] as string, labelStyles, true) : civilDoc.Styles.LabelSetStyles.AlignmentLabelSetStyles.First(); + var name = string.IsNullOrEmpty(alignment.name) ? alignment.applicationId : alignment.name; // names need to be unique on creation (but not send i guess??) + var layer = Doc.Database.LayerZero; + + // type + var type = CivilDB.AlignmentType.Centerline; + if (civilAlignment != null) + { + if (Enum.TryParse(civilAlignment.type, out CivilDB.AlignmentType civilType)) + { + type = civilType; + } + } + + // site + var site = civilAlignment != null ? + GetFromObjectIdCollection(civilAlignment.site, civilDoc.GetSiteIds()) : ObjectId.Null; + + // style + var docStyles = new ObjectIdCollection(); + foreach (ObjectId styleId in civilDoc.Styles.AlignmentStyles) + { + docStyles.Add(styleId); + } + + var style = civilAlignment != null ? + GetFromObjectIdCollection(civilAlignment.style, docStyles, true) : civilDoc.Styles.AlignmentStyles.First(); + + // label set style + var labelStyles = new ObjectIdCollection(); + foreach (ObjectId styleId in civilDoc.Styles.LabelSetStyles.AlignmentLabelSetStyles) + { + labelStyles.Add(styleId); + } + + var label = civilAlignment != null ? + GetFromObjectIdCollection(civilAlignment["label"] as string, labelStyles, true) : civilDoc.Styles.LabelSetStyles.AlignmentLabelSetStyles.First(); #endregion - try + try + { + // add new alignment to doc + // ⚠ this will throw if name is not unique!! + var id = ObjectId.Null; + switch (type) { - // add new alignment to doc - // ⚠ this will throw if name is not unique!! - var id = ObjectId.Null; - switch (type) - { - case CivilDB.AlignmentType.Offset: - // create only if parent exists in doc - if (parent == ObjectId.Null) goto default; - try - { - id = CivilDB.Alignment.CreateOffsetAlignment(name, parent, civilAlignment.offset, style); - } - catch - { - id = CivilDB.Alignment.CreateOffsetAlignment(CivilDB.Alignment.GetNextUniqueName(name), parent, civilAlignment.offset, style); - } - break; - default: - try - { - id = CivilDB.Alignment.Create(civilDoc, name, site, layer, style, label); - } - catch - { - id = CivilDB.Alignment.Create(civilDoc, CivilDB.Alignment.GetNextUniqueName(name), site, layer, style, label); - } - break; - } - if (!id.IsValid) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); - return appObj; - } - _alignment = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.Alignment; + case CivilDB.AlignmentType.Offset: + // create only if parent exists in doc + if (parent == ObjectId.Null) + { + goto default; + } + + try + { + id = CivilDB.Alignment.CreateOffsetAlignment(name, parent, civilAlignment.offset, style); + } + catch + { + id = CivilDB.Alignment.CreateOffsetAlignment(CivilDB.Alignment.GetNextUniqueName(name), parent, civilAlignment.offset, style); + } + break; + default: + try + { + id = CivilDB.Alignment.Create(civilDoc, name, site, layer, style, label); + } + catch + { + id = CivilDB.Alignment.Create(civilDoc, CivilDB.Alignment.GetNextUniqueName(name), site, layer, style, label); + } + break; } - catch (System.Exception e) + if (!id.IsValid) { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); return appObj; } + _alignment = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.Alignment; } - - if (_alignment == null) + catch (System.Exception e) { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"returned null after bake"); + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); return appObj; } + } - if (isUpdate) appObj.Container = _alignment.Layer; // set the appobj container to be the same layer as the existing alignment + if (_alignment == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"returned null after bake"); + return appObj; + } + + if (isUpdate) + { + appObj.Container = _alignment.Layer; // set the appobj container to be the same layer as the existing alignment + } - if (parent != ObjectId.Null) + if (parent != ObjectId.Null) + { + _alignment.OffsetAlignmentInfo.NominalOffset = civilAlignment.offset; // just update the offset + } + else + { + // create alignment entity curves + var entities = _alignment.Entities; + if (isUpdate) { - _alignment.OffsetAlignmentInfo.NominalOffset = civilAlignment.offset; // just update the offset + _alignment.Entities.Clear(); // remove existing curves } - else + + foreach (var curve in alignment.curves) { - // create alignment entity curves - var entities = _alignment.Entities; - if (isUpdate) _alignment.Entities.Clear(); // remove existing curves - foreach (var curve in alignment.curves) - AddAlignmentEntity(curve, ref entities); + AddAlignmentEntity(curve, ref entities); } + } - // set start station - _alignment.ReferencePointStation = alignment.startStation; + // set start station + _alignment.ReferencePointStation = alignment.startStation; - // update appobj - var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: status, createdId: _alignment.Handle.ToString(), convertedItem: _alignment); - return appObj; - } + // update appobj + var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: status, createdId: _alignment.Handle.ToString(), convertedItem: _alignment); + return appObj; + } #region helper methods - private SpiralType SpiralTypeToSpeckle(Civil.SpiralType type) + private SpiralType SpiralTypeToSpeckle(Civil.SpiralType type) + { + switch (type) { - switch (type) - { - case Civil.SpiralType.Clothoid: - return SpiralType.Clothoid; - case Civil.SpiralType.Bloss: - return SpiralType.Bloss; - case Civil.SpiralType.BiQuadratic: - return SpiralType.Biquadratic; - case Civil.SpiralType.CubicParabola: - return SpiralType.CubicParabola; - case Civil.SpiralType.Sinusoidal: - return SpiralType.Sinusoid; - default: - return SpiralType.Unknown; - } + case Civil.SpiralType.Clothoid: + return SpiralType.Clothoid; + case Civil.SpiralType.Bloss: + return SpiralType.Bloss; + case Civil.SpiralType.BiQuadratic: + return SpiralType.Biquadratic; + case Civil.SpiralType.CubicParabola: + return SpiralType.CubicParabola; + case Civil.SpiralType.Sinusoidal: + return SpiralType.Sinusoid; + default: + return SpiralType.Unknown; } - private Civil.SpiralType SpiralTypeToNative(SpiralType type) + } + private Civil.SpiralType SpiralTypeToNative(SpiralType type) + { + switch (type) { - switch (type) - { - case SpiralType.Clothoid: - return Civil.SpiralType.Clothoid; - case SpiralType.Bloss: - return Civil.SpiralType.Bloss; - case SpiralType.Biquadratic: - return Civil.SpiralType.BiQuadratic; - case SpiralType.CubicParabola: - return Civil.SpiralType.CubicParabola; - case SpiralType.Sinusoid: - return Civil.SpiralType.Sinusoidal; - default: - return Civil.SpiralType.Clothoid; - } + case SpiralType.Clothoid: + return Civil.SpiralType.Clothoid; + case SpiralType.Bloss: + return Civil.SpiralType.Bloss; + case SpiralType.Biquadratic: + return Civil.SpiralType.BiQuadratic; + case SpiralType.CubicParabola: + return Civil.SpiralType.CubicParabola; + case SpiralType.Sinusoid: + return Civil.SpiralType.Sinusoidal; + default: + return Civil.SpiralType.Clothoid; } - private void AddAlignmentEntity(ICurve curve, ref CivilDB.AlignmentEntityCollection entities) + } + private void AddAlignmentEntity(ICurve curve, ref CivilDB.AlignmentEntityCollection entities) + { + switch (curve) { - switch (curve) - { - case Line o: - entities.AddFixedLine(PointToNative(o.start), PointToNative(o.end)); + case Line o: + entities.AddFixedLine(PointToNative(o.start), PointToNative(o.end)); + break; + + case Arc o: + entities.AddFixedCurve(entities.LastEntity, PointToNative(o.startPoint), PointToNative(o.midPoint), PointToNative(o.endPoint)); + break; + + case Spiral o: + var start = PointToNative(o.startPoint); + var end = PointToNative(o.endPoint); + var intersectionPoints = o.displayValue.GetPoints(); // display poly points should be points of intersection for the spiral + if (intersectionPoints.Count == 0 ) + { break; + } - case Arc o: - entities.AddFixedCurve(entities.LastEntity, PointToNative(o.startPoint), PointToNative(o.midPoint), PointToNative(o.endPoint)); - break; + var intersectionPoint = PointToNative(intersectionPoints[intersectionPoints.Count / 2]); + entities.AddFixedSpiral(entities.LastEntity, start, intersectionPoint , end, SpiralTypeToNative(o.spiralType)); + break; - case Spiral o: - var start = PointToNative(o.startPoint); - var end = PointToNative(o.endPoint); - var intersectionPoints = o.displayValue.GetPoints(); // display poly points should be points of intersection for the spiral - if (intersectionPoints.Count == 0 ) - break; - var intersectionPoint = PointToNative(intersectionPoints[intersectionPoints.Count / 2]); - entities.AddFixedSpiral(entities.LastEntity, start, intersectionPoint , end, SpiralTypeToNative(o.spiralType)); - break; + case Polycurve o: + foreach (var segment in o.segments) + { + AddAlignmentEntity(segment, ref entities); + } - case Polycurve o: - foreach (var segment in o.segments) - AddAlignmentEntity(segment, ref entities); - break; + break; - default: - break; - } + default: + break; } - private Line AlignmentLineToSpeckle(CivilDB.AlignmentSubEntityLine line) - { - var _line = LineToSpeckle(new LineSegment2d(line.StartPoint, line.EndPoint)); - return _line; - } - private Arc AlignmentArcToSpeckle(CivilDB.AlignmentSubEntityArc arc) - { - // calculate midpoint of chord as between start and end point - Point2d chordMid = new Point2d((arc.StartPoint.X + arc.EndPoint.X) / 2, (arc.StartPoint.Y + arc.EndPoint.Y) / 2); + } + private Line AlignmentLineToSpeckle(CivilDB.AlignmentSubEntityLine line) + { + var _line = LineToSpeckle(new LineSegment2d(line.StartPoint, line.EndPoint)); + return _line; + } + private Arc AlignmentArcToSpeckle(CivilDB.AlignmentSubEntityArc arc) + { + // calculate midpoint of chord as between start and end point + Point2d chordMid = new((arc.StartPoint.X + arc.EndPoint.X) / 2, (arc.StartPoint.Y + arc.EndPoint.Y) / 2); - // calculate sagitta as radius minus distance between arc center and chord midpoint - var sagitta = arc.Radius - arc.CenterPoint.GetDistanceTo(chordMid); + // calculate sagitta as radius minus distance between arc center and chord midpoint + var sagitta = arc.Radius - arc.CenterPoint.GetDistanceTo(chordMid); - // get unit vector from arc center to chord mid - var midVector = arc.CenterPoint.GetVectorTo(chordMid); - var unitMidVector = midVector.DivideBy(midVector.Length); + // get unit vector from arc center to chord mid + var midVector = arc.CenterPoint.GetVectorTo(chordMid); + var unitMidVector = midVector.DivideBy(midVector.Length); - // get midpoint of arc by moving chord mid point the length of the sagitta along mid vector - // if greater than 180 >, move in other direction of distance radius + radius - sagitta - // in the case of an exactly perfect half circle arc...🤷‍♀️ - Point2d midPoint = chordMid.Add(unitMidVector.MultiplyBy(sagitta)); - try + // get midpoint of arc by moving chord mid point the length of the sagitta along mid vector + // if greater than 180 >, move in other direction of distance radius + radius - sagitta + // in the case of an exactly perfect half circle arc...🤷‍♀️ + Point2d midPoint = chordMid.Add(unitMidVector.MultiplyBy(sagitta)); + try + { + if (arc.GreaterThan180) // sometimes this prop throws an exception?? { - if (arc.GreaterThan180) // sometimes this prop throws an exception?? - midPoint = chordMid.Add(unitMidVector.Negate().MultiplyBy(2 * arc.Radius - sagitta)); + midPoint = chordMid.Add(unitMidVector.Negate().MultiplyBy(2 * arc.Radius - sagitta)); } - catch { } + } + catch { } - // create arc - var _arc = new CircularArc2d(arc.StartPoint, midPoint, arc.EndPoint); - return ArcToSpeckle(_arc); - } - private Spiral AlignmentSpiralToSpeckle(CivilDB.AlignmentSubEntitySpiral spiral, CivilDB.Alignment alignment) + // create arc + var _arc = new CircularArc2d(arc.StartPoint, midPoint, arc.EndPoint); + return ArcToSpeckle(_arc); + } + private Spiral AlignmentSpiralToSpeckle(CivilDB.AlignmentSubEntitySpiral spiral, CivilDB.Alignment alignment) + { + var _spiral = new Spiral(); + _spiral.startPoint = PointToSpeckle(spiral.StartPoint); + _spiral.endPoint = PointToSpeckle(spiral.EndPoint); + _spiral.length = spiral.Length; + _spiral.pitch = 0; + _spiral.spiralType = SpiralTypeToSpeckle(spiral.SpiralDefinition); + + // get plane + var vX = new Vector3d(System.Math.Cos(spiral.StartDirection) + spiral.StartPoint.X, System.Math.Sin(spiral.StartDirection) + spiral.StartPoint.Y, 0); + var vY = vX.RotateBy(System.Math.PI / 2, Vector3d.ZAxis); + var plane = new Acad.Plane(new Point3d(spiral.RadialPoint.X, spiral.RadialPoint.Y, 0), vX, vY); + _spiral.plane = PlaneToSpeckle(plane); + + // get turns + int turnDirection = (spiral.Direction == CivilDB.SpiralDirectionType.DirectionLeft) ? 1 : -1; + _spiral.turns = turnDirection * spiral.Delta / (System.Math.PI * 2); + + // create polyline display, default tessellation length is 1 + var tessellation = 1; + int spiralSegmentCount = System.Convert.ToInt32(System.Math.Ceiling(spiral.Length / tessellation)); + spiralSegmentCount = (spiralSegmentCount < 10) ? 10 : spiralSegmentCount; + double spiralSegmentLength = spiral.Length / spiralSegmentCount; + + List points = new(); + points.Add(spiral.StartPoint); + for (int i = 1; i < spiralSegmentCount; i++) { - var _spiral = new Spiral(); - _spiral.startPoint = PointToSpeckle(spiral.StartPoint); - _spiral.endPoint = PointToSpeckle(spiral.EndPoint); - _spiral.length = spiral.Length; - _spiral.pitch = 0; - _spiral.spiralType = SpiralTypeToSpeckle(spiral.SpiralDefinition); - - // get plane - var vX = new Vector3d(System.Math.Cos(spiral.StartDirection) + spiral.StartPoint.X, System.Math.Sin(spiral.StartDirection) + spiral.StartPoint.Y, 0); - var vY = vX.RotateBy(System.Math.PI / 2, Vector3d.ZAxis); - var plane = new Acad.Plane(new Point3d(spiral.RadialPoint.X, spiral.RadialPoint.Y, 0), vX, vY); - _spiral.plane = PlaneToSpeckle(plane); - - // get turns - int turnDirection = (spiral.Direction == CivilDB.SpiralDirectionType.DirectionLeft) ? 1 : -1; - _spiral.turns = turnDirection * spiral.Delta / (System.Math.PI * 2); - - // create polyline display, default tessellation length is 1 - var tessellation = 1; - int spiralSegmentCount = System.Convert.ToInt32(System.Math.Ceiling(spiral.Length / tessellation)); - spiralSegmentCount = (spiralSegmentCount < 10) ? 10 : spiralSegmentCount; - double spiralSegmentLength = spiral.Length / spiralSegmentCount; - - List points = new List(); - points.Add(spiral.StartPoint); - for (int i = 1; i < spiralSegmentCount; i++) - { - double x = 0; - double y = 0; - double z = 0; + double x = 0; + double y = 0; + double z = 0; - alignment.PointLocation(spiral.StartStation + (i * spiralSegmentLength), 0, tolerance, ref x, ref y, ref z); - points.Add(new Point2d(x, y)); - } - points.Add(spiral.EndPoint); - double length = 0; - for (int j = 1; j < points.Count; j++) - { - length += points[j].GetDistanceTo(points[j - 1]); - } - var poly = new Polyline(); - poly.value = points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - poly.units = ModelUnits; - poly.closed = (spiral.StartPoint != spiral.EndPoint) ? false : true; - poly.length = length; - _spiral.displayValue = poly; - - return _spiral; + alignment.PointLocation(spiral.StartStation + (i * spiralSegmentLength), 0, tolerance, ref x, ref y, ref z); + points.Add(new Point2d(x, y)); } + points.Add(spiral.EndPoint); + double length = 0; + for (int j = 1; j < points.Count; j++) + { + length += points[j].GetDistanceTo(points[j - 1]); + } + var poly = new Polyline(); + poly.value = points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); + poly.units = ModelUnits; + poly.closed = (spiral.StartPoint != spiral.EndPoint) ? false : true; + poly.length = length; + _spiral.displayValue = poly; + + return _spiral; + } #endregion - // profiles - public CivilProfile ProfileToSpeckle(CivilDB.Profile profile) + // profiles + public CivilProfile ProfileToSpeckle(CivilDB.Profile profile) + { + // TODO: get surface name of surface profiles from profile view + var _profile = new CivilProfile(); + + // get profile props + _profile.type = profile.ProfileType.ToString(); + _profile.offset = profile.Offset; + if (profile.StyleName != null) { - // TODO: get surface name of surface profiles from profile view - var _profile = new CivilProfile(); - - // get profile props - _profile.type = profile.ProfileType.ToString(); - _profile.offset = profile.Offset; - if (profile.StyleName != null) - _profile.style = profile.StyleName; - if (profile.Description != null) - _profile["description"] = profile.Description; - if (profile.Name != null) - _profile.name = profile.Name; - - // get profile stations - _profile.startStation = profile.StartingStation; - _profile.endStation = profile.EndingStation; - - // get the profile entity curves - List curves = new List(); - for (int i = 0; i < profile.Entities.Count; i++) - { - CivilDB.ProfileEntity entity = profile.Entities[i]; - switch (entity.EntityType) - { - case CivilDB.ProfileEntityType.Circular: - var circular = ProfileArcToSpeckle(entity as CivilDB.ProfileCircular); - if (circular != null) curves.Add(circular); - break; - case CivilDB.ProfileEntityType.Tangent: - var tangent = ProfileLineToSpeckle(entity as CivilDB.ProfileTangent); - if (tangent != null) curves.Add(tangent); - break; - case CivilDB.ProfileEntityType.ParabolaSymmetric: - case CivilDB.ProfileEntityType.ParabolaAsymmetric: - default: - var segment = ProfileGenericToSpeckle(entity.StartStation, entity.StartElevation, entity.EndStation, entity.EndElevation); - if (segment != null) curves.Add(segment); - break; - } - } - _profile.curves = curves; + _profile.style = profile.StyleName; + } - // if offset profile, get offset distance and parent - _profile.offset = profile.Offset; - try - { - if (profile.OffsetParameters.ParentProfileId != ObjectId.Null) - { - var parent = Trans.GetObject(profile.OffsetParameters.ParentProfileId, OpenMode.ForRead) as CivilDB.Profile; - if (parent != null && parent.Name != null) - _profile.parent = parent.Name; - - } - } - catch { } + if (profile.Description != null) + { + _profile["description"] = profile.Description; + } - // get points of vertical intersection (PVIs) - List pvisConverted = new List(); - var pvis = new Point3dCollection(); - foreach (CivilDB.ProfilePVI pvi in profile.PVIs) + if (profile.Name != null) + { + _profile.name = profile.Name; + } + + // get profile stations + _profile.startStation = profile.StartingStation; + _profile.endStation = profile.EndingStation; + + // get the profile entity curves + List curves = new(); + for (int i = 0; i < profile.Entities.Count; i++) + { + CivilDB.ProfileEntity entity = profile.Entities[i]; + switch (entity.EntityType) { - pvisConverted.Add(PointToSpeckle(new Point2d(pvi.Station, pvi.Elevation))); - pvis.Add(new Point3d(pvi.Station, pvi.Elevation, 0)); - } - _profile.pvis = pvisConverted; + case CivilDB.ProfileEntityType.Circular: + var circular = ProfileArcToSpeckle(entity as CivilDB.ProfileCircular); + if (circular != null) + { + curves.Add(circular); + } + break; + case CivilDB.ProfileEntityType.Tangent: + var tangent = ProfileLineToSpeckle(entity as CivilDB.ProfileTangent); + if (tangent != null) + { + curves.Add(tangent); + } - if (pvisConverted.Count > 1) _profile.displayValue = PolylineToSpeckle(pvis, profile.Closed); - _profile.units = ModelUnits; + break; + case CivilDB.ProfileEntityType.ParabolaSymmetric: + case CivilDB.ProfileEntityType.ParabolaAsymmetric: + default: + var segment = ProfileGenericToSpeckle(entity.StartStation, entity.StartElevation, entity.EndStation, entity.EndElevation); + if (segment != null) + { + curves.Add(segment); + } - return _profile; + break; + } } - private Line ProfileLineToSpeckle(CivilDB.ProfileTangent tangent) + _profile.curves = curves; + + // if offset profile, get offset distance and parent + _profile.offset = profile.Offset; + try { - var start = new Point2d(tangent.StartStation, tangent.StartElevation); - var end = new Point2d(tangent.EndStation, tangent.EndElevation); - return LineToSpeckle(new LineSegment2d(start, end)); + if (profile.OffsetParameters.ParentProfileId != ObjectId.Null) + { + var parent = Trans.GetObject(profile.OffsetParameters.ParentProfileId, OpenMode.ForRead) as CivilDB.Profile; + if (parent != null && parent.Name != null) + { + _profile.parent = parent.Name; + } + } } - private Arc ProfileArcToSpeckle(CivilDB.ProfileCircular circular) + catch { } + + // get points of vertical intersection (PVIs) + List pvisConverted = new(); + var pvis = new Point3dCollection(); + foreach (CivilDB.ProfilePVI pvi in profile.PVIs) { - var start = new Point2d(circular.StartStation, circular.StartElevation); - var end = new Point2d(circular.EndStation, circular.EndElevation); - var pvi = new Point2d(circular.PVIStation, circular.PVIElevation); - return ArcToSpeckle(new CircularArc2d(start, pvi, end)); + pvisConverted.Add(PointToSpeckle(new Point2d(pvi.Station, pvi.Elevation))); + pvis.Add(new Point3d(pvi.Station, pvi.Elevation, 0)); } - private Line ProfileGenericToSpeckle(double startStation, double startElevation, double endStation, double endElevation) // general approximation of segment as line + _profile.pvis = pvisConverted; + + + if (pvisConverted.Count > 1) { - var start = new Point2d(startStation, startElevation); - var end = new Point2d(endStation, endElevation); - return LineToSpeckle(new LineSegment2d(start, end)); + _profile.displayValue = PolylineToSpeckle(pvis, profile.Closed); } - /* - public ApplicationObject ProfileToNative(Profile profile) - { - var appObj = new ApplicationObject(profile.id, profile.speckle_type) { applicationId = profile.applicationId }; - var existingObjs = GetExistingElementsByApplicationId(profile.applicationId); - var civilProfile = profile as CivilProfile; + _profile.units = ModelUnits; - // get civil doc - if (!GetCivilDocument(out CivilDocument civilDoc)) - return appObj; + return _profile; + } + private Line ProfileLineToSpeckle(CivilDB.ProfileTangent tangent) + { + var start = new Point2d(tangent.StartStation, tangent.StartElevation); + var end = new Point2d(tangent.EndStation, tangent.EndElevation); + return LineToSpeckle(new LineSegment2d(start, end)); + } + private Arc ProfileArcToSpeckle(CivilDB.ProfileCircular circular) + { + var start = new Point2d(circular.StartStation, circular.StartElevation); + var end = new Point2d(circular.EndStation, circular.EndElevation); + var pvi = new Point2d(circular.PVIStation, circular.PVIElevation); + return ArcToSpeckle(new CircularArc2d(start, pvi, end)); + } + private Line ProfileGenericToSpeckle(double startStation, double startElevation, double endStation, double endElevation) // general approximation of segment as line + { + var start = new Point2d(startStation, startElevation); + var end = new Point2d(endStation, endElevation); + return LineToSpeckle(new LineSegment2d(start, end)); + } - // create or retrieve alignment, and parent if it exists - CivilDB.Profile _profile = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.Profile : null; - var parent = civilProfile != null ? GetFromObjectIdCollection(civilProfile.parent, civilDoc.get()) : ObjectId.Null; - bool isUpdate = true; - if (_profile == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new profile - { - isUpdate = false; + /* + public ApplicationObject ProfileToNative(Profile profile) + { + var appObj = new ApplicationObject(profile.id, profile.speckle_type) { applicationId = profile.applicationId }; + var existingObjs = GetExistingElementsByApplicationId(profile.applicationId); + var civilProfile = profile as CivilProfile; + + // get civil doc + if (!GetCivilDocument(out CivilDocument civilDoc)) + return appObj; - // get civil props for creation + // create or retrieve alignment, and parent if it exists + CivilDB.Profile _profile = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.Profile : null; + var parent = civilProfile != null ? GetFromObjectIdCollection(civilProfile.parent, civilDoc.get()) : ObjectId.Null; + bool isUpdate = true; + if (_profile == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new profile + { + isUpdate = false; + + // get civil props for creation #region properties - var name = string.IsNullOrEmpty(profile.name) ? profile.applicationId : profile.name; // names need to be unique on creation (but not send i guess??) - var layer = Doc.Database.LayerZero; + var name = string.IsNullOrEmpty(profile.name) ? profile.applicationId : profile.name; // names need to be unique on creation (but not send i guess??) + var layer = Doc.Database.LayerZero; - // type - var type = CivilDB.ProfileType.File; - if (civilProfile != null) - if (Enum.TryParse(civilProfile.type, out CivilDB.ProfileType civilType)) - type = civilType; + // type + var type = CivilDB.ProfileType.File; + if (civilProfile != null) + if (Enum.TryParse(civilProfile.type, out CivilDB.ProfileType civilType)) + type = civilType; - // style - var docStyles = new ObjectIdCollection(); - foreach (ObjectId styleId in civilDoc.Styles.ProfileStyles) docStyles.Add(styleId); - var style = civilProfile != null ? - GetFromObjectIdCollection(civilProfile.style, docStyles, true) : civilDoc.Styles.ProfileStyles.First(); + // style + var docStyles = new ObjectIdCollection(); + foreach (ObjectId styleId in civilDoc.Styles.ProfileStyles) docStyles.Add(styleId); + var style = civilProfile != null ? + GetFromObjectIdCollection(civilProfile.style, docStyles, true) : civilDoc.Styles.ProfileStyles.First(); #endregion - try + try + { + // add new profile to doc + // ⚠ this will throw if name is not unique!! + var id = ObjectId.Null; + switch (type) { - // add new profile to doc - // ⚠ this will throw if name is not unique!! - var id = ObjectId.Null; - switch (type) - { - // A surface profile—often called an existing ground (EG) profile—is extracted from a surface, showing the changes in elevation along a particular route - case CivilDB.ProfileType.EG: - - if (parent == ObjectId.Null) goto default; - try - { - id = CivilDB.Profile.CreateFromSurface(Doc, ); - } - catch - { - } - break; - default: - try - { - id = CivilDB.Profile.CreateFromGeCurve(); - } - catch - { - - } - break; - } - if (!id.IsValid) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); - return appObj; - } - _profile = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.Profile; + // A surface profile—often called an existing ground (EG) profile—is extracted from a surface, showing the changes in elevation along a particular route + case CivilDB.ProfileType.EG: + + if (parent == ObjectId.Null) goto default; + try + { + id = CivilDB.Profile.CreateFromSurface(Doc, ); + } + catch + { + } + break; + default: + try + { + id = CivilDB.Profile.CreateFromGeCurve(); + } + catch + { + + } + break; } - catch (System.Exception e) + if (!id.IsValid) { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); return appObj; } + _profile = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.Profile; } - - if (_profile == null) + catch (System.Exception e) { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"returned null after bake"); + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); return appObj; } + } + if (_profile == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"returned null after bake"); + return appObj; } - */ - // featurelines - public Featureline FeatureLineToSpeckle(CivilDB.FeatureLine featureline) + } + */ + + // featurelines + public Featureline FeatureLineToSpeckle(CivilDB.FeatureLine featureline) + { + // get all points + var points = new List(); + var _points = featureline.GetPoints(Civil.FeatureLinePointType.AllPoints); + foreach (Point3d point in _points) { - // get all points - var points = new List(); - var _points = featureline.GetPoints(Civil.FeatureLinePointType.AllPoints); - foreach (Point3d point in _points) points.Add(PointToSpeckle(point)); - - // get elevation points - var ePoints = new List(); - var _ePoints = featureline.GetPoints(Civil.FeatureLinePointType.ElevationPoint); - foreach (Point3d ePoint in _ePoints) ePoints.Add(_points.IndexOf(ePoint)); - - // get pi points - var piPoints = new List(); - var _piPoints = featureline.GetPoints(Civil.FeatureLinePointType.PIPoint); - foreach (Point3d piPoint in _piPoints) piPoints.Add(_points.IndexOf(piPoint)); - - /* - // get bulges at pi point indices - int count = (featureline.Closed) ? featureline.PointsCount : featureline.PointsCount - 1; - List bulges = new List(); - for (int i = 0; i < count; i++) bulges.Add(featureline.GetBulge(i)); - var piBulges = new List(); - foreach (var index in indices) piBulges.Add(bulges[index]); - */ - - // get displayvalue - var polyline = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, _piPoints, false)); - - // featureline - var _featureline = new Featureline(); - _featureline.curve = CurveToSpeckle(featureline.BaseCurve, ModelUnits); - _featureline.units = ModelUnits; - _featureline.displayValue = new List() { polyline }; - _featureline["@piPoints"] = piPoints; - _featureline["@elevationPoints"] = ePoints; - - if (!string.IsNullOrEmpty(featureline.Name)) { _featureline["name"] = featureline.Name; } - if (!string.IsNullOrEmpty(featureline.Description)) { _featureline["description"] = featureline.Description; } - if (featureline.SiteId != null) { _featureline["site"] = featureline.SiteId.ToString(); } - - return _featureline; + points.Add(PointToSpeckle(point)); } - private Featureline FeaturelineToSpeckle(CivilDB.CorridorFeatureLine featureline) + // get elevation points + var ePoints = new List(); + var _ePoints = featureline.GetPoints(Civil.FeatureLinePointType.ElevationPoint); + foreach (Point3d ePoint in _ePoints) { - // get all points, the basecurve (no breaks) and the display polylines - var points = new List(); - var polylines = new List(); + ePoints.Add(_points.IndexOf(ePoint)); + } - var polylinePoints = new Point3dCollection(); - var baseCurvePoints = new Point3dCollection(); - for (int i = 0; i < featureline.FeatureLinePoints.Count; i++) - { - var point = featureline.FeatureLinePoints[i]; - baseCurvePoints.Add(point.XYZ); - if (!point.IsBreak) { polylinePoints.Add(point.XYZ); } - if (polylinePoints.Count > 0 && (i == featureline.FeatureLinePoints.Count - 1 || point.IsBreak )) - { - var polyline = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, polylinePoints, false)); - polylines.Add(polyline); - polylinePoints.Clear(); + // get pi points + var piPoints = new List(); + var _piPoints = featureline.GetPoints(Civil.FeatureLinePointType.PIPoint); + foreach (Point3d piPoint in _piPoints) + { + piPoints.Add(_points.IndexOf(piPoint)); + } - } - points.Add(PointToSpeckle(point.XYZ)); - } - var baseCurve = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, baseCurvePoints, false)); + /* + // get bulges at pi point indices + int count = (featureline.Closed) ? featureline.PointsCount : featureline.PointsCount - 1; + List bulges = new List(); + for (int i = 0; i < count; i++) bulges.Add(featureline.GetBulge(i)); + var piBulges = new List(); + foreach (var index in indices) piBulges.Add(bulges[index]); + */ - // create featureline - var _featureline = new Featureline(); - _featureline.points = points; - _featureline.curve = baseCurve; - if (!string.IsNullOrEmpty(featureline.CodeName)) { _featureline.name = featureline.CodeName; } - _featureline.displayValue = polylines; - _featureline.units = ModelUnits; + // get displayvalue + var polyline = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, _piPoints, false)); - return _featureline; - } + // featureline + var _featureline = new Featureline(); + _featureline.curve = CurveToSpeckle(featureline.BaseCurve, ModelUnits); + _featureline.units = ModelUnits; + _featureline.displayValue = new List() { polyline }; + _featureline["@piPoints"] = piPoints; + _featureline["@elevationPoints"] = ePoints; + + if (!string.IsNullOrEmpty(featureline.Name)) { _featureline["name"] = featureline.Name; } + if (!string.IsNullOrEmpty(featureline.Description)) { _featureline["description"] = featureline.Description; } + if (featureline.SiteId != null) { _featureline["site"] = featureline.SiteId.ToString(); } - public CivilDB.FeatureLine FeatureLineToNative(Polycurve polycurve) + return _featureline; + } + + private Featureline FeaturelineToSpeckle(CivilDB.CorridorFeatureLine featureline) + { + // get all points, the basecurve (no breaks) and the display polylines + var points = new List(); + var polylines = new List(); + + var polylinePoints = new Point3dCollection(); + var baseCurvePoints = new Point3dCollection(); + for (int i = 0; i < featureline.FeatureLinePoints.Count; i++) { - return null; + var point = featureline.FeatureLinePoints[i]; + baseCurvePoints.Add(point.XYZ); + if (!point.IsBreak) { polylinePoints.Add(point.XYZ); } + if (polylinePoints.Count > 0 && (i == featureline.FeatureLinePoints.Count - 1 || point.IsBreak )) + { + var polyline = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, polylinePoints, false)); + polylines.Add(polyline); + polylinePoints.Clear(); + + } + points.Add(PointToSpeckle(point.XYZ)); } + var baseCurve = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, baseCurvePoints, false)); + + // create featureline + var _featureline = new Featureline(); + _featureline.points = points; + _featureline.curve = baseCurve; + if (!string.IsNullOrEmpty(featureline.CodeName)) { _featureline.name = featureline.CodeName; } + _featureline.displayValue = polylines; + _featureline.units = ModelUnits; + + return _featureline; + } + + public CivilDB.FeatureLine FeatureLineToNative(Polycurve polycurve) + { + return null; + } + + // surfaces + public Mesh SurfaceToSpeckle(CivilDB.TinSurface surface) + { + Mesh mesh = null; - // surfaces - public Mesh SurfaceToSpeckle(CivilDB.TinSurface surface) + // output vars + var _vertices = new List(); + var faces = new List(); + foreach (var triangle in surface.GetTriangles(false)) { - Mesh mesh = null; + var triangleVertices = new List { triangle.Vertex1.Location, triangle.Vertex2.Location, triangle.Vertex3.Location }; - // output vars - var _vertices = new List(); - var faces = new List(); - foreach (var triangle in surface.GetTriangles(false)) +#if CIVIL2023 || CIVIL2024 // skip any triangles that are hidden in the surface! + if (!triangle.IsVisible) { - var triangleVertices = new List { triangle.Vertex1.Location, triangle.Vertex2.Location, triangle.Vertex3.Location }; + triangle.Dispose(); + continue; + } +#endif -#if CIVIL2023 || CIVIL2024 // skip any triangles that are hidden in the surface! - if (!triangle.IsVisible) + // store vertices + var faceIndices = new List(); + foreach (var vertex in triangleVertices) + { + if (!_vertices.Contains(vertex)) { - triangle.Dispose(); - continue; + faceIndices.Add(_vertices.Count); + _vertices.Add(vertex); } -#endif - - // store vertices - var faceIndices = new List(); - foreach (var vertex in triangleVertices) + else { - if (!_vertices.Contains(vertex)) - { - faceIndices.Add(_vertices.Count); - _vertices.Add(vertex); - } - else - { - faceIndices.Add(_vertices.IndexOf(vertex)); - } + faceIndices.Add(_vertices.IndexOf(vertex)); } + } - // get face - faces.AddRange(new List { 3, faceIndices[0], faceIndices[1], faceIndices[2] }); + // get face + faces.AddRange(new List { 3, faceIndices[0], faceIndices[1], faceIndices[2] }); - triangle.Dispose(); - } + triangle.Dispose(); + } - var vertices = _vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); + var vertices = _vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - mesh = new Mesh(vertices, faces); - mesh.units = ModelUnits; - mesh.bbox = BoxToSpeckle(surface.GeometricExtents); + mesh = new Mesh(vertices, faces); + mesh.units = ModelUnits; + mesh.bbox = BoxToSpeckle(surface.GeometricExtents); - // add tin surface props - var props = Speckle.Core.Models.Utilities.GetApplicationProps(surface, typeof(CivilDB.TinSurface), false); - mesh[CivilPropName] = props; - - return mesh; - } + // add tin surface props + var props = Speckle.Core.Models.Utilities.GetApplicationProps(surface, typeof(CivilDB.TinSurface), false); + mesh[CivilPropName] = props; + + return mesh; + } - public Mesh SurfaceToSpeckle(CivilDB.GridSurface surface) - { - Mesh mesh = null; + public Mesh SurfaceToSpeckle(CivilDB.GridSurface surface) + { + Mesh mesh = null; - // output vars - var _vertices = new List(); - var faces = new List(); + // output vars + var _vertices = new List(); + var faces = new List(); - foreach (var cell in surface.GetCells(false)) + foreach (var cell in surface.GetCells(false)) + { + // get vertices + var faceIndices = new List(); + foreach (var vertex in new List() {cell.BottomLeftVertex, cell.BottomRightVertex, cell.TopLeftVertex, cell.TopRightVertex}) { - // get vertices - var faceIndices = new List(); - foreach (var vertex in new List() {cell.BottomLeftVertex, cell.BottomRightVertex, cell.TopLeftVertex, cell.TopRightVertex}) + if (!_vertices.Contains(vertex.Location)) { - if (!_vertices.Contains(vertex.Location)) - { - faceIndices.Add(_vertices.Count); - _vertices.Add(vertex.Location); - } - else - { - faceIndices.Add(_vertices.IndexOf(vertex.Location)); - } - vertex.Dispose(); + faceIndices.Add(_vertices.Count); + _vertices.Add(vertex.Location); } + else + { + faceIndices.Add(_vertices.IndexOf(vertex.Location)); + } + vertex.Dispose(); + } - // get face - faces.AddRange(new List { 4, faceIndices[0], faceIndices[1], faceIndices[2], faceIndices[3] }); + // get face + faces.AddRange(new List { 4, faceIndices[0], faceIndices[1], faceIndices[2], faceIndices[3] }); - cell.Dispose(); - } + cell.Dispose(); + } - var vertices = _vertices.Select(o => PointToSpeckle(o).ToList()).SelectMany(o => o).ToList(); - mesh = new Mesh(vertices, faces); - mesh.units = ModelUnits; - mesh.bbox = BoxToSpeckle(surface.GeometricExtents); + var vertices = _vertices.Select(o => PointToSpeckle(o).ToList()).SelectMany(o => o).ToList(); + mesh = new Mesh(vertices, faces); + mesh.units = ModelUnits; + mesh.bbox = BoxToSpeckle(surface.GeometricExtents); - // add grid surface props - if (!string.IsNullOrEmpty(surface.DisplayName)){ mesh["name"] = surface.DisplayName; } - if (!string.IsNullOrEmpty(surface.Description)){ mesh["description"] = surface.Description; } + // add grid surface props + if (!string.IsNullOrEmpty(surface.DisplayName)){ mesh["name"] = surface.DisplayName; } + if (!string.IsNullOrEmpty(surface.Description)){ mesh["description"] = surface.Description; } - return mesh; - } + return mesh; + } - public object CivilSurfaceToNative(Mesh mesh) + public object CivilSurfaceToNative(Mesh mesh) + { + var props = mesh[CivilPropName] as Base; + if (props == null) { - var props = mesh[CivilPropName] as Base; - if (props == null) return null; + return null; + } - switch (props["class"] as string) - { - case "TinSurface": - return TinSurfaceToNative(mesh, props); - default: - return MeshToNativeDB(mesh); - } + switch (props["class"] as string) + { + case "TinSurface": + return TinSurfaceToNative(mesh, props); + default: + return MeshToNativeDB(mesh); } - public ApplicationObject TinSurfaceToNative(Mesh mesh, Base props) + } + public ApplicationObject TinSurfaceToNative(Mesh mesh, Base props) + { + var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; + var existingObjs = GetExistingElementsByApplicationId(mesh.applicationId); + + // get civil doc + if (!GetCivilDocument(appObj, out CivilDocument civilDoc)) { - var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; - var existingObjs = GetExistingElementsByApplicationId(mesh.applicationId); + return appObj; + } - // get civil doc - if (!GetCivilDocument(appObj, out CivilDocument civilDoc)) - return appObj; + // create or retrieve tin surface + CivilDB.TinSurface _surface = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.TinSurface : null; + bool isUpdate = true; + if (_surface == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new surface + { + isUpdate = false; - // create or retrieve tin surface - CivilDB.TinSurface _surface = existingObjs.Any() ? Trans.GetObject(existingObjs.FirstOrDefault(), OpenMode.ForWrite) as CivilDB.TinSurface : null; - bool isUpdate = true; - if (_surface == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) // just create a new surface + // get civil props for creation + var name = string.IsNullOrEmpty(props["Name"] as string) ? mesh.applicationId : props["Name"] as string; + var layer = Doc.Database.LayerZero; + var docStyles = new ObjectIdCollection(); + foreach (ObjectId styleId in civilDoc.Styles.SurfaceStyles) { - isUpdate = false; - - // get civil props for creation - var name = string.IsNullOrEmpty(props["Name"] as string) ? mesh.applicationId : props["Name"] as string; - var layer = Doc.Database.LayerZero; - var docStyles = new ObjectIdCollection(); - foreach (ObjectId styleId in civilDoc.Styles.SurfaceStyles) docStyles.Add(styleId); - var style = props["style"] as string != null ? - GetFromObjectIdCollection(props["style"] as string, docStyles) : civilDoc.Styles.SurfaceStyles.First(); - - // add new surface to doc - // ⚠ this will throw if name is empty? - var id = ObjectId.Null; - try - { - id = CivilDB.TinSurface.Create(name, style); - } - catch (System.Exception e) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); - return appObj; - } - if (!id.IsValid) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); - return appObj; - } - _surface = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.TinSurface; + docStyles.Add(styleId); } - if (_surface == null) + var style = props["style"] as string != null ? + GetFromObjectIdCollection(props["style"] as string, docStyles) : civilDoc.Styles.SurfaceStyles.First(); + + // add new surface to doc + // ⚠ this will throw if name is empty? + var id = ObjectId.Null; + try { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"retrieved or baked surface was null"); + id = CivilDB.TinSurface.Create(name, style); + } + catch (System.Exception e) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{e.Message}"); return appObj; } + if (!id.IsValid) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Create method returned null"); + return appObj; + } + _surface = Trans.GetObject(id, OpenMode.ForWrite) as CivilDB.TinSurface; + } - if (isUpdate) + if (_surface == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"retrieved or baked surface was null"); + return appObj; + } + + if (isUpdate) + { + appObj.Container = _surface.Layer; // set the appobj container to be the same layer as the existing alignment + _surface.DeleteVertices(_surface.Vertices); // remove existing vertices + } + + // add all vertices + var vertices = new Point3dCollection(); + var meshVertices = mesh.GetPoints().Select(o => PointToNative(o)).ToList(); + meshVertices.ForEach(o => vertices.Add(o)); + _surface.AddVertices(vertices); + + // loop through faces to create an edge dictionary by vertex, which includes all other vertices this vertex is connected to + int i = 0; + var edges = new Dictionary>(); + foreach (var vertex in meshVertices) + { + edges.Add(vertex, new List()); + } + + while (i < mesh.faces.Count) + { + if (mesh.faces[i] == 3) // triangle { - appObj.Container = _surface.Layer; // set the appobj container to be the same layer as the existing alignment - _surface.DeleteVertices(_surface.Vertices); // remove existing vertices + var v1 = meshVertices[mesh.faces[i + 1]]; + var v2 = meshVertices[mesh.faces[i + 2]]; + var v3 = meshVertices[mesh.faces[i + 3]]; + edges[v1].Add(v2); + edges[v2].Add(v3); + edges[v3].Add(v1); + + i += 4; + } + else // this was not a triangulated surface! return null + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Mesh was not triangulated"); + return appObj; } + } - // add all vertices - var vertices = new Point3dCollection(); - var meshVertices = mesh.GetPoints().Select(o => PointToNative(o)).ToList(); - meshVertices.ForEach(o => vertices.Add(o)); - _surface.AddVertices(vertices); - - // loop through faces to create an edge dictionary by vertex, which includes all other vertices this vertex is connected to - int i = 0; - var edges = new Dictionary>(); - foreach (var vertex in meshVertices) - edges.Add(vertex, new List()); - - while (i < mesh.faces.Count) + // loop through each surface vertex edge and create any that don't exist + foreach (Point3d edgeStart in edges.Keys) + { + var vertex = _surface.FindVertexAtXY(edgeStart.X, edgeStart.Y); + var correctEdges = new List(); + foreach (CivilDB.TinSurfaceEdge currentEdge in vertex.Edges) { - if (mesh.faces[i] == 3) // triangle - { - var v1 = meshVertices[mesh.faces[i + 1]]; - var v2 = meshVertices[mesh.faces[i + 2]]; - var v3 = meshVertices[mesh.faces[i + 3]]; - edges[v1].Add(v2); - edges[v2].Add(v3); - edges[v3].Add(v1); - - i += 4; - } - else // this was not a triangulated surface! return null + if (edges[edgeStart].Contains(currentEdge.Vertex2.Location)) { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Mesh was not triangulated"); - return appObj; + correctEdges.Add(currentEdge.Vertex2.Location); } + + currentEdge.Dispose(); } + vertex.Dispose(); - // loop through each surface vertex edge and create any that don't exist - foreach (Point3d edgeStart in edges.Keys) + foreach (var vertexToAdd in edges[edgeStart]) { - var vertex = _surface.FindVertexAtXY(edgeStart.X, edgeStart.Y); - var correctEdges = new List(); - foreach (CivilDB.TinSurfaceEdge currentEdge in vertex.Edges) + if (correctEdges.Contains(vertexToAdd)) { - if (edges[edgeStart].Contains(currentEdge.Vertex2.Location)) - correctEdges.Add(currentEdge.Vertex2.Location); - currentEdge.Dispose(); + continue; } - vertex.Dispose(); - foreach (var vertexToAdd in edges[edgeStart]) - { - if (correctEdges.Contains(vertexToAdd)) continue; - var a1 = _surface.FindVertexAtXY(edgeStart.X, edgeStart.Y); - var a2 = _surface.FindVertexAtXY(vertexToAdd.X, vertexToAdd.Y); - _surface.AddLine(a1, a2); - a1.Dispose(); - a2.Dispose(); - } - } - - // loop through and delete any edges - var edgesToDelete = new List(); - foreach(CivilDB.TinSurfaceVertex vertex in _surface.Vertices) - { - if (vertex.Edges.Count > edges[vertex.Location].Count) - foreach (CivilDB.TinSurfaceEdge modifiedEdge in vertex.Edges) - if (!edges[vertex.Location].Contains(modifiedEdge.Vertex2.Location) && !edges[modifiedEdge.Vertex2.Location].Contains(vertex.Location)) - edgesToDelete.Add(modifiedEdge); - vertex.Dispose(); + var a1 = _surface.FindVertexAtXY(edgeStart.X, edgeStart.Y); + var a2 = _surface.FindVertexAtXY(vertexToAdd.X, vertexToAdd.Y); + _surface.AddLine(a1, a2); + a1.Dispose(); + a2.Dispose(); } - if (edgesToDelete.Count > 0) + } + + // loop through and delete any edges + var edgesToDelete = new List(); + foreach(CivilDB.TinSurfaceVertex vertex in _surface.Vertices) + { + if (vertex.Edges.Count > edges[vertex.Location].Count) { - _surface.DeleteLines(edgesToDelete); - _surface.Rebuild(); + foreach (CivilDB.TinSurfaceEdge modifiedEdge in vertex.Edges) + { + if (!edges[vertex.Location].Contains(modifiedEdge.Vertex2.Location) && !edges[modifiedEdge.Vertex2.Location].Contains(vertex.Location)) + { + edgesToDelete.Add(modifiedEdge); + } + } } - - // update appobj - var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: status, createdId: _surface.Handle.ToString(), convertedItem: _surface); - return appObj; + + vertex.Dispose(); + } + if (edgesToDelete.Count > 0) + { + _surface.DeleteLines(edgesToDelete); + _surface.Rebuild(); } + + // update appobj + var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: status, createdId: _surface.Handle.ToString(), convertedItem: _surface); + return appObj; + } - // structures - public Structure StructureToSpeckle(CivilDB.Structure structure) + // structures + public Structure StructureToSpeckle(CivilDB.Structure structure) + { + // get ids pipes that are connected to this structure + var pipeIds = new List(); + for (int i = 0; i < structure.ConnectedPipesCount; i++) { - // get ids pipes that are connected to this structure - var pipeIds = new List(); - for (int i = 0; i < structure.ConnectedPipesCount; i++) - pipeIds.Add(structure.get_ConnectedPipe(i).ToString()); - - var _structure = new Structure(); - - _structure.location = PointToSpeckle(structure.Location, ModelUnits); - _structure.pipeIds = pipeIds; - _structure.displayValue = new List() { SolidToSpeckle(structure.Solid3dBody, out List notes) }; - _structure.units = ModelUnits; - - // assign additional structure props - _structure["name"] = (structure.DisplayName != null) ? structure.DisplayName : ""; - _structure["description"] = (structure.Description != null) ? structure.Description : ""; - try{ _structure["grate"] = structure.Grate; } catch{ } - try{ _structure["station"] = structure.Station; } catch{ } - try{ _structure["network"] = structure.NetworkName; } catch{ } - - return _structure; + pipeIds.Add(structure.get_ConnectedPipe(i).ToString()); } - // pipes - // TODO: add pressure fittings - public Pipe PipeToSpeckle(CivilDB.Pipe pipe) + var _structure = new Structure(); + + _structure.location = PointToSpeckle(structure.Location, ModelUnits); + _structure.pipeIds = pipeIds; + _structure.displayValue = new List() { SolidToSpeckle(structure.Solid3dBody, out List notes) }; + _structure.units = ModelUnits; + + // assign additional structure props + _structure["name"] = (structure.DisplayName != null) ? structure.DisplayName : ""; + _structure["description"] = (structure.Description != null) ? structure.Description : ""; + try{ _structure["grate"] = structure.Grate; } catch{ } + try{ _structure["station"] = structure.Station; } catch{ } + try{ _structure["network"] = structure.NetworkName; } catch{ } + + return _structure; + } + + // pipes + // TODO: add pressure fittings + public Pipe PipeToSpeckle(CivilDB.Pipe pipe) + { + // get the pipe curve + ICurve curve = null; + switch (pipe.SubEntityType) { - // get the pipe curve - ICurve curve = null; - switch (pipe.SubEntityType) - { - case CivilDB.PipeSubEntityType.Straight: - var line = new Acad.LineSegment3d(pipe.StartPoint, pipe.EndPoint); - curve = LineToSpeckle(line); - break; - default: - curve = CurveToSpeckle(pipe.BaseCurve); - break; - } + case CivilDB.PipeSubEntityType.Straight: + var line = new Acad.LineSegment3d(pipe.StartPoint, pipe.EndPoint); + curve = LineToSpeckle(line); + break; + default: + curve = CurveToSpeckle(pipe.BaseCurve); + break; + } + + var _pipe = new Pipe(); + _pipe.baseCurve = curve; + _pipe.diameter = pipe.InnerDiameterOrWidth; + _pipe.length = pipe.Length3DToInsideEdge; + _pipe.displayValue = new List { SolidToSpeckle(pipe.Solid3dBody, out List notes) }; + _pipe.units = ModelUnits; - var _pipe = new Pipe(); - _pipe.baseCurve = curve; - _pipe.diameter = pipe.InnerDiameterOrWidth; - _pipe.length = pipe.Length3DToInsideEdge; - _pipe.displayValue = new List { SolidToSpeckle(pipe.Solid3dBody, out List notes) }; - _pipe.units = ModelUnits; - - // assign additional pipe props - if (pipe.Name != null) _pipe["name"] = pipe.Name; - if (pipe.Description != null) _pipe["description"] = pipe.Description; - try { _pipe["shape"] = pipe.CrossSectionalShape.ToString(); } catch { } - try { _pipe["slope"] = pipe.Slope; } catch { } - try { _pipe["flowDirection"] = pipe.FlowDirection.ToString(); } catch { } - try { _pipe["flowRate"] = pipe.FlowRate; } catch { } - try { _pipe["network"] = pipe.NetworkName; } catch { } - try { _pipe["startOffset"] = pipe.StartOffset; } catch { } - try { _pipe["endOffset"] = pipe.EndOffset; } catch { } - try { _pipe["startStation"] = pipe.StartStation; } catch { } - try { _pipe["endStation"] = pipe.EndStation; } catch { } - try { _pipe["startStructure"] = pipe.StartStructureId.ToString(); } catch { } - try { _pipe["endStructure"] = pipe.EndStructureId.ToString(); } catch { } - - return _pipe; + // assign additional pipe props + if (pipe.Name != null) + { + _pipe["name"] = pipe.Name; } - public Pipe PipeToSpeckle(CivilDB.PressurePipe pipe) + + if (pipe.Description != null) { - // get the pipe curve - ICurve curve = null; - switch (pipe.BaseCurve) - { - case AcadDB.Line o: - var line = new Acad.LineSegment3d(pipe.StartPoint, pipe.EndPoint); - curve = LineToSpeckle(line); - break; - default: - curve = CurveToSpeckle(pipe.BaseCurve); - break; - } + _pipe["description"] = pipe.Description; + } - var _pipe = new Pipe(); - _pipe.baseCurve = curve; - _pipe.diameter = pipe.InnerDiameter; - _pipe.length = pipe.Length3DCenterToCenter; - _pipe.displayValue = new List { SolidToSpeckle(pipe.Get3dBody(), out List notes) }; - _pipe.units = ModelUnits; - - // assign additional pipe props - if (pipe.Name != null) _pipe["name"] = pipe.Name; - _pipe["description"] = (pipe.Description != null) ? pipe.Description : ""; - _pipe["isPressurePipe"] = true; - try { _pipe["partType"] = pipe.PartType.ToString(); } catch { } - try { _pipe["slope"] = pipe.Slope; } catch { } - try { _pipe["network"] = pipe.NetworkName; } catch { } - try { _pipe["startOffset"] = pipe.StartOffset; } catch { } - try { _pipe["endOffset"] = pipe.EndOffset; } catch { } - try { _pipe["startStation"] = pipe.StartStation; } catch { } - try { _pipe["endStation"] = pipe.EndStation; } catch { } - - return _pipe; + try { _pipe["shape"] = pipe.CrossSectionalShape.ToString(); } catch { } + try { _pipe["slope"] = pipe.Slope; } catch { } + try { _pipe["flowDirection"] = pipe.FlowDirection.ToString(); } catch { } + try { _pipe["flowRate"] = pipe.FlowRate; } catch { } + try { _pipe["network"] = pipe.NetworkName; } catch { } + try { _pipe["startOffset"] = pipe.StartOffset; } catch { } + try { _pipe["endOffset"] = pipe.EndOffset; } catch { } + try { _pipe["startStation"] = pipe.StartStation; } catch { } + try { _pipe["endStation"] = pipe.EndStation; } catch { } + try { _pipe["startStructure"] = pipe.StartStructureId.ToString(); } catch { } + try { _pipe["endStructure"] = pipe.EndStructureId.ToString(); } catch { } + + return _pipe; + } + public Pipe PipeToSpeckle(CivilDB.PressurePipe pipe) + { + // get the pipe curve + ICurve curve = null; + switch (pipe.BaseCurve) + { + case AcadDB.Line o: + var line = new Acad.LineSegment3d(pipe.StartPoint, pipe.EndPoint); + curve = LineToSpeckle(line); + break; + default: + curve = CurveToSpeckle(pipe.BaseCurve); + break; } - // corridors - // this is composed of assemblies, alignments, and profiles, use point codes to generate featurelines (which will have the 3d curve) - public Base CorridorToSpeckle(CivilDB.Corridor corridor) + var _pipe = new Pipe(); + _pipe.baseCurve = curve; + _pipe.diameter = pipe.InnerDiameter; + _pipe.length = pipe.Length3DCenterToCenter; + _pipe.displayValue = new List { SolidToSpeckle(pipe.Get3dBody(), out List notes) }; + _pipe.units = ModelUnits; + + // assign additional pipe props + if (pipe.Name != null) { - var _corridor = new Base(); + _pipe["name"] = pipe.Name; + } - List alignments = new List(); - List profiles = new List(); - List featurelines = new List(); - foreach (var baseline in corridor.Baselines) + _pipe["description"] = (pipe.Description != null) ? pipe.Description : ""; + _pipe["isPressurePipe"] = true; + try { _pipe["partType"] = pipe.PartType.ToString(); } catch { } + try { _pipe["slope"] = pipe.Slope; } catch { } + try { _pipe["network"] = pipe.NetworkName; } catch { } + try { _pipe["startOffset"] = pipe.StartOffset; } catch { } + try { _pipe["endOffset"] = pipe.EndOffset; } catch { } + try { _pipe["startStation"] = pipe.StartStation; } catch { } + try { _pipe["endStation"] = pipe.EndStation; } catch { } + + return _pipe; + } + + // corridors + // this is composed of assemblies, alignments, and profiles, use point codes to generate featurelines (which will have the 3d curve) + public Base CorridorToSpeckle(CivilDB.Corridor corridor) + { + var _corridor = new Base(); + + List alignments = new(); + List profiles = new(); + List featurelines = new(); + foreach (var baseline in corridor.Baselines) + { + + // get the collection of featurelines for this baseline + foreach (var mainFeaturelineCollection in baseline.MainBaselineFeatureLines.FeatureLineCollectionMap) // main featurelines { + foreach (var featureline in mainFeaturelineCollection) + { + featurelines.Add(FeaturelineToSpeckle(featureline)); + } + } - // get the collection of featurelines for this baseline - foreach (var mainFeaturelineCollection in baseline.MainBaselineFeatureLines.FeatureLineCollectionMap) // main featurelines - foreach (var featureline in mainFeaturelineCollection) + foreach (var offsetFeaturelineCollection in baseline.OffsetBaselineFeatureLinesCol) // offset featurelines + { + foreach (var featurelineCollection in offsetFeaturelineCollection.FeatureLineCollectionMap) + { + foreach (var featureline in featurelineCollection) + { featurelines.Add(FeaturelineToSpeckle(featureline)); - foreach (var offsetFeaturelineCollection in baseline.OffsetBaselineFeatureLinesCol) // offset featurelines - foreach (var featurelineCollection in offsetFeaturelineCollection.FeatureLineCollectionMap) - foreach (var featureline in featurelineCollection) - featurelines.Add(FeaturelineToSpeckle(featureline)); + } + } + } - // get alignment - try + // get alignment + try + { + var alignmentId = baseline.AlignmentId; + var alignment = AlignmentToSpeckle(Trans.GetObject(alignmentId, OpenMode.ForRead) as CivilDB.Alignment); + if (alignment != null) { - var alignmentId = baseline.AlignmentId; - var alignment = AlignmentToSpeckle(Trans.GetObject(alignmentId, OpenMode.ForRead) as CivilDB.Alignment); - if (alignment != null) alignments.Add(alignment); + alignments.Add(alignment); } - catch { } + } + catch { } - // get profile - try + // get profile + try + { + var profileId = baseline.ProfileId; + var profile = ProfileToSpeckle(Trans.GetObject(profileId, OpenMode.ForRead) as CivilDB.Profile); + if (profile != null) { - var profileId = baseline.ProfileId; - var profile = ProfileToSpeckle(Trans.GetObject(profileId, OpenMode.ForRead) as CivilDB.Profile); - if (profile != null) profiles.Add(profile); + profiles.Add(profile); } - catch { } } + catch { } + } - // get corridor surfaces - List surfaces = new List(); - foreach (var corridorSurface in corridor.CorridorSurfaces) + // get corridor surfaces + List surfaces = new(); + foreach (var corridorSurface in corridor.CorridorSurfaces) + { + try { - try + var surface = Trans.GetObject(corridorSurface.SurfaceId, OpenMode.ForRead); + var mesh = ConvertToSpeckle(surface) as Mesh; + if (mesh != null) { - var surface = Trans.GetObject(corridorSurface.SurfaceId, OpenMode.ForRead); - var mesh = ConvertToSpeckle(surface) as Mesh; - if (mesh != null) surfaces.Add(mesh); + surfaces.Add(mesh); } - catch (Exception e) - { } } + catch (Exception e) + { } + } - _corridor["@alignments"] = alignments; - _corridor["@profiles"] = profiles; - _corridor["@featurelines"] = featurelines; - if (corridor.Name != null) _corridor["name"] = corridor.Name; - if (corridor.Description != null) _corridor["description"] = corridor.Description; - _corridor["units"] = ModelUnits; - if (surfaces.Count> 0) _corridor["@surfaces"] = surfaces; + _corridor["@alignments"] = alignments; + _corridor["@profiles"] = profiles; + _corridor["@featurelines"] = featurelines; + if (corridor.Name != null) + { + _corridor["name"] = corridor.Name; + } + + if (corridor.Description != null) + { + _corridor["description"] = corridor.Description; + } - return _corridor; + _corridor["units"] = ModelUnits; + if (surfaces.Count> 0) + { + _corridor["@surfaces"] = surfaces; } + + return _corridor; } } #endif diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Geometry.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Geometry.cs index d940c37572..473201c59d 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Geometry.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Geometry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.DoubleNumerics; using System.Linq; @@ -39,1025 +39,1301 @@ using Objects.Geometry; using Objects.Other; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + // tolerance for geometry: + public double tolerance = 0.000; + + // Points + public Point PointToSpeckle(Point3d point, string units = null) { - // tolerance for geometry: - public double tolerance = 0.000; + //TODO: handle units.none? + var u = units ?? ModelUnits; + var extPt = ToExternalCoordinates(point); + return new Point(extPt.X, extPt.Y, extPt.Z, u); + } - // Points - public Point PointToSpeckle(Point3d point, string units = null) - { - //TODO: handle units.none? - var u = units ?? ModelUnits; - var extPt = ToExternalCoordinates(point); - return new Point(extPt.X, extPt.Y, extPt.Z, u); - } - public Point PointToSpeckle(Point2d point, string units = null) - { - //TODO: handle units.none? - var u = units ?? ModelUnits; - var extPt = ToExternalCoordinates(new Point3d(point.X, point.Y, 0)); - return new Point(extPt.X, extPt.Y, extPt.Z, u); - } - public Point3d PointToNative(Point point) - { - var _point = new Point3d(ScaleToNative(point.x, point.units), - ScaleToNative(point.y, point.units), - ScaleToNative(point.z, point.units)); - var intPt = ToInternalCoordinates(_point); - return intPt; - } - - public List> ControlPointsToSpeckle(AcadGeo.NurbSurface surface, string units = null) - { - var u = units ?? ModelUnits; + public Point PointToSpeckle(Point2d point, string units = null) + { + //TODO: handle units.none? + var u = units ?? ModelUnits; + var extPt = ToExternalCoordinates(new Point3d(point.X, point.Y, 0)); + return new Point(extPt.X, extPt.Y, extPt.Z, u); + } - var points = new List>(); - int count = 0; - for (var i = 0; i < surface.NumControlPointsInU; i++) + public Point3d PointToNative(Point point) + { + var _point = new Point3d( + ScaleToNative(point.x, point.units), + ScaleToNative(point.y, point.units), + ScaleToNative(point.z, point.units) + ); + var intPt = ToInternalCoordinates(_point); + return intPt; + } + + public List> ControlPointsToSpeckle(AcadGeo.NurbSurface surface, string units = null) + { + var u = units ?? ModelUnits; + + var points = new List>(); + int count = 0; + for (var i = 0; i < surface.NumControlPointsInU; i++) + { + var row = new List(); + for (var j = 0; j < surface.NumControlPointsInV; j++) { - var row = new List(); - for (var j = 0; j < surface.NumControlPointsInV; j++) + var point = surface.ControlPoints[count]; + double weight = 1; + try { - var point = surface.ControlPoints[count]; - double weight = 1; - try - { - weight = surface.Weights[count]; - } - catch { } - row.Add(new ControlPoint(point.X, point.Y, point.Z, weight, u)); - count++; + weight = surface.Weights[count]; } - points.Add(row); + catch { } + row.Add(new ControlPoint(point.X, point.Y, point.Z, weight, u)); + count++; } - return points; + points.Add(row); } - public Point PointToSpeckle(DBPoint point, string units = null) - { - var u = units ?? ModelUnits; - return PointToSpeckle(point.Position, u); - } - public DBPoint PointToNativeDB(Point point) - { - var _point = PointToNative(point); - return new DBPoint(_point); - } - public List> ControlPointsToSpeckle(AcadDB.NurbSurface surface) + return points; + } + + public Point PointToSpeckle(DBPoint point, string units = null) + { + var u = units ?? ModelUnits; + return PointToSpeckle(point.Position, u); + } + + public DBPoint PointToNativeDB(Point point) + { + var _point = PointToNative(point); + return new DBPoint(_point); + } + + public List> ControlPointsToSpeckle(AcadDB.NurbSurface surface) + { + var points = new List>(); + for (var i = 0; i < surface.NumberOfControlPointsInU; i++) { - var points = new List>(); - for (var i = 0; i < surface.NumberOfControlPointsInU; i++) + var row = new List(); + for (var j = 0; j < surface.NumberOfControlPointsInV; j++) { - var row = new List(); - for (var j = 0; j < surface.NumberOfControlPointsInV; j++) - { - var point = PointToSpeckle(surface.GetControlPointAt(i, j)); - var weight = surface.GetWeight(i, j); - row.Add(new ControlPoint(point.x, point.y, point.z, weight, ModelUnits)); - } - points.Add(row); + var point = PointToSpeckle(surface.GetControlPointAt(i, j)); + var weight = surface.GetWeight(i, j); + row.Add(new ControlPoint(point.x, point.y, point.z, weight, ModelUnits)); } - return points; + points.Add(row); } + return points; + } - // Vectors - public Vector VectorToSpeckle(Vector3d vector, string units = null) - { - var u = units ?? ModelUnits; - var extV = ToExternalCoordinates(vector); - return new Vector(extV.X, extV.Y, extV.Z, ModelUnits); - } - public Vector3d VectorToNative(Vector vector) - { - var _vector = new Vector3d( - ScaleToNative(vector.x, vector.units), - ScaleToNative(vector.y, vector.units), - ScaleToNative(vector.z, vector.units)); - var intV = ToInternalCoordinates(_vector); - return intV; - } + // Vectors + public Vector VectorToSpeckle(Vector3d vector, string units = null) + { + var u = units ?? ModelUnits; + var extV = ToExternalCoordinates(vector); + return new Vector(extV.X, extV.Y, extV.Z, ModelUnits); + } - // Interval - public Interval IntervalToSpeckle(AcadGeo.Interval interval) - { - return new Interval(interval.LowerBound, interval.UpperBound); - } - public AcadGeo.Interval IntervalToNative(Interval interval) - { - return new AcadGeo.Interval((double)interval.start, (double)interval.end, tolerance); - } + public Vector3d VectorToNative(Vector vector) + { + var _vector = new Vector3d( + ScaleToNative(vector.x, vector.units), + ScaleToNative(vector.y, vector.units), + ScaleToNative(vector.z, vector.units) + ); + var intV = ToInternalCoordinates(_vector); + return intV; + } - // Plane - public Plane PlaneToSpeckle(AcadGeo.Plane plane) + // Interval + public Interval IntervalToSpeckle(AcadGeo.Interval interval) + { + return new Interval(interval.LowerBound, interval.UpperBound); + } + + public AcadGeo.Interval IntervalToNative(Interval interval) + { + return new AcadGeo.Interval((double)interval.start, (double)interval.end, tolerance); + } + + // Plane + public Plane PlaneToSpeckle(AcadGeo.Plane plane) + { + Vector xAxis = VectorToSpeckle(plane.GetCoordinateSystem().Xaxis); + Vector yAxis = VectorToSpeckle(plane.GetCoordinateSystem().Yaxis); + var _plane = new Plane(PointToSpeckle(plane.PointOnPlane), VectorToSpeckle(plane.Normal), xAxis, yAxis, ModelUnits); + return _plane; + } + + public AcadGeo.Plane PlaneToNative(Plane plane) + { + return new AcadGeo.Plane(PointToNative(plane.origin), VectorToNative(plane.normal)); + } + + //Matrix + + public Matrix3d TransformToNativeMatrix(Transform transform) + { + // transform + var scaledTransform = transform.ConvertToUnits(ModelUnits); + Matrix3d convertedTransform = new(scaledTransform); + + //Autocad is very picky about transform basis being perfectly perpendicular, if they are not, we can correct for this by re-calculating basis vectors + if (!convertedTransform.IsScaledOrtho()) { - Vector xAxis = VectorToSpeckle(plane.GetCoordinateSystem().Xaxis); - Vector yAxis = VectorToSpeckle(plane.GetCoordinateSystem().Yaxis); - var _plane = new Plane(PointToSpeckle(plane.PointOnPlane), VectorToSpeckle(plane.Normal), xAxis, yAxis, ModelUnits); - return _plane; + return new Matrix3d(MakePerpendicular(convertedTransform)); } - public AcadGeo.Plane PlaneToNative(Plane plane) + + return convertedTransform; + } + + // https://forums.autodesk.com/t5/net/set-blocktransform-values/m-p/6452121#M49479 + private static double[] MakePerpendicular(Matrix3d matrix) + { + // Get the basis vectors of the matrix + Vector3d right = new(matrix[0, 0], matrix[1, 0], matrix[2, 0]); + Vector3d up = new(matrix[0, 1], matrix[1, 1], matrix[2, 1]); + + Vector3d newForward = right.CrossProduct(up).GetNormal(); + ; + + Vector3d newUp = newForward.CrossProduct(right).GetNormal(); + + return new[] + { + right.X, + newUp.X, + newForward.X, + matrix[0, 3], + right.Y, + newUp.Y, + newForward.Y, + matrix[1, 3], + right.Z, + newUp.Z, + newForward.Z, + matrix[2, 3], + 0.0, + 0.0, + 0.0, + matrix[3, 3], + }; + } + + // Line + public Line LineToSpeckle(LineSegment2d line) + { + var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); + _line.length = line.Length; + _line.domain = IntervalToSpeckle(line.GetInterval()); + return _line; + } + + public Line LineToSpeckle(Line3d line, string units = null) + { + var u = units ?? ModelUnits; + + var startParam = line.GetParameterOf(line.StartPoint); + var endParam = line.GetParameterOf(line.EndPoint); + var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), u); + _line.length = line.GetLength(startParam, endParam, tolerance); + _line.domain = IntervalToSpeckle(line.GetInterval()); + _line.bbox = BoxToSpeckle(line.OrthoBoundBlock); + + return _line; + } + + public Line LineToSpeckle(LineSegment3d line) + { + var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); + _line.length = line.Length; + _line.domain = IntervalToSpeckle(line.GetInterval()); + _line.bbox = BoxToSpeckle(line.OrthoBoundBlock); + return _line; + } + + public Line3d LineToNative(Line line) + { + var _line = new Line3d(PointToNative(line.start), PointToNative(line.end)); + if (line.domain != null) { - return new AcadGeo.Plane(PointToNative(plane.origin), VectorToNative(plane.normal)); + try + { + _line.SetInterval(IntervalToNative(line.domain)); + } + catch { } } - - //Matrix - public Matrix3d TransformToNativeMatrix(Transform transform) - { - // transform - var scaledTransform = transform.ConvertToUnits(ModelUnits); - Matrix3d convertedTransform = new Matrix3d(scaledTransform); + return _line; + } + + public Line LineToSpeckle(AcadDB.Line line, string units = null) + { + var u = units ?? ModelUnits; + + var _line = new Line(PointToSpeckle(line.StartPoint, u), PointToSpeckle(line.EndPoint, u), u); + _line.domain = new Interval(line.StartParam, line.EndParam); + _line.length = line.Length; + _line.bbox = BoxToSpeckle(line.GeometricExtents); + return _line; + } + + public AcadDB.Line LineToNativeDB(Line line) + { + return new AcadDB.Line(PointToNative(line.start), PointToNative(line.end)); + } - //Autocad is very picky about transform basis being perfectly perpendicular, if they are not, we can correct for this by re-calculating basis vectors - if (!convertedTransform.IsScaledOrtho()) + // Rectangle + public Polyline RectangleToSpeckle(Rectangle3d rectangle) + { + var _points = new List() + { + rectangle.LowerLeft, + rectangle.LowerRight, + rectangle.UpperLeft, + rectangle.UpperRight + }; + var points = _points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); + return new Polyline(points, ModelUnits) { closed = true }; + } + + // Arc + public Arc ArcToSpeckle(CircularArc2d arc) + { + var interval = arc.GetInterval(); + + // find arc plane (normal is in clockwise dir) + var center3 = new Point3d(arc.Center.X, arc.Center.Y, 0); + AcadGeo.Plane plane = + (arc.IsClockWise) + ? new AcadGeo.Plane(center3, Vector3d.ZAxis.MultiplyBy(-1)) + : new AcadGeo.Plane(center3, Vector3d.ZAxis); + + // calculate total angle. TODO: This needs to be validated across all possible arc orientations + var totalAngle = + (arc.IsClockWise) ? Math.Abs(arc.EndAngle - arc.StartAngle) : Math.Abs(arc.EndAngle - arc.StartAngle); + + // create arc + var _arc = new Arc(PlaneToSpeckle(plane), arc.Radius, arc.StartAngle, arc.EndAngle, totalAngle, ModelUnits); + _arc.startPoint = PointToSpeckle(arc.StartPoint); + _arc.endPoint = PointToSpeckle(arc.EndPoint); + _arc.midPoint = PointToSpeckle(arc.EvaluatePoint((interval.UpperBound - interval.LowerBound) / 2)); + _arc.domain = IntervalToSpeckle(interval); + _arc.length = arc.GetLength(arc.GetParameterOf(arc.StartPoint), arc.GetParameterOf(arc.EndPoint)); + _arc.bbox = BoxToSpeckle(arc.BoundBlock); + return _arc; + } + + public Arc ArcToSpeckle(CircularArc3d arc) + { + var interval = arc.GetInterval(); + var _arc = new Arc( + PlaneToSpeckle(arc.GetPlane()), + arc.Radius, + arc.StartAngle, + arc.EndAngle, + Math.Abs(arc.EndAngle - arc.StartAngle), + ModelUnits + ); + _arc.startPoint = PointToSpeckle(arc.StartPoint); + _arc.endPoint = PointToSpeckle(arc.EndPoint); + _arc.midPoint = PointToSpeckle(arc.EvaluatePoint((interval.UpperBound - interval.LowerBound) / 2)); + _arc.domain = IntervalToSpeckle(arc.GetInterval()); + _arc.length = arc.GetLength(arc.GetParameterOf(arc.StartPoint), arc.GetParameterOf(arc.EndPoint), tolerance); + _arc.bbox = BoxToSpeckle(arc.OrthoBoundBlock); + return _arc; + } + + public CircularArc3d ArcToNative(Arc arc) + { + var _arc = new CircularArc3d( + PointToNative(arc.startPoint), + PointToNative(arc.midPoint), + PointToNative(arc.endPoint) + ); + + _arc.SetAxes(VectorToNative(arc.plane.normal), VectorToNative(arc.plane.xdir)); + _arc.SetAngles((double)arc.startAngle, (double)arc.endAngle); + + return _arc; + } + + public Arc ArcToSpeckle(AcadDB.Arc arc) + { + var _arc = new Arc( + PlaneToSpeckle(arc.GetPlane()), + arc.Radius, + arc.StartAngle, + arc.EndAngle, + arc.TotalAngle, + ModelUnits + ); + _arc.startPoint = PointToSpeckle(arc.StartPoint); + _arc.endPoint = PointToSpeckle(arc.EndPoint); + _arc.midPoint = PointToSpeckle(arc.GetPointAtDist(arc.Length / 2)); + _arc.domain = new Interval(arc.StartParam, arc.EndParam); + _arc.length = arc.Length; + _arc.bbox = BoxToSpeckle(arc.GeometricExtents); + return _arc; + } + + public AcadDB.Arc ArcToNativeDB(Arc arc) + { + // because of different plane & start/end angle conventions, most reliable method to convert to autocad convention is to calculate from start, end, and midpoint + var circularArc = ArcToNative(arc); + + // calculate adjusted start and end angles from circularArc reference + double angle = circularArc.ReferenceVector.AngleOnPlane(PlaneToNative(arc.plane)); + double startAngle = circularArc.StartAngle + angle; + double endAngle = circularArc.EndAngle + angle; + + var _arc = new AcadDB.Arc( + PointToNative(arc.plane.origin), + VectorToNative(arc.plane.normal), + ScaleToNative((double)arc.radius, arc.units), + startAngle, + endAngle + ); + + return _arc; + } + + // Circle + public Circle CircleToSpeckle(AcadDB.Circle circle) + { + var _circle = new Circle(PlaneToSpeckle(circle.GetPlane()), circle.Radius, ModelUnits); + _circle.length = circle.Circumference; + _circle.bbox = BoxToSpeckle(circle.GeometricExtents); + return _circle; + } + + public AcadDB.Circle CircleToNativeDB(Circle circle) + { + var normal = VectorToNative(circle.plane.normal); + var radius = ScaleToNative((double)circle.radius, circle.units); + return new AcadDB.Circle(PointToNative(circle.plane.origin), normal, radius); + } + + // Ellipse + public Ellipse EllipseToSpeckle(AcadDB.Ellipse ellipse) + { + var plane = new AcadGeo.Plane(ellipse.Center, ellipse.MajorAxis, ellipse.MinorAxis); + var _ellipse = new Ellipse(PlaneToSpeckle(plane), ellipse.MajorRadius, ellipse.MinorRadius, ModelUnits); + _ellipse.domain = new Interval(ellipse.StartParam, ellipse.EndParam); + _ellipse.length = ellipse.GetDistanceAtParameter(ellipse.EndParam); + _ellipse.bbox = BoxToSpeckle(ellipse.GeometricExtents); + return _ellipse; + } + + public AcadDB.Ellipse EllipseToNativeDB(Ellipse ellipse) + { + var normal = VectorToNative(ellipse.plane.normal); + var xAxisVector = VectorToNative(ellipse.plane.xdir); + var majorAxis = ScaleToNative((double)ellipse.firstRadius, ellipse.units) * xAxisVector.GetNormal(); + var radiusRatio = (double)ellipse.secondRadius / (double)ellipse.firstRadius; + return new AcadDB.Ellipse(PointToNative(ellipse.plane.origin), normal, majorAxis, radiusRatio, 0, 2 * Math.PI); + } + + // Spiral + + // Polyline + private Polyline PolylineToSpeckle(Point3dCollection points, bool closed) + { + double length = 0; + List vertices = new(); + foreach (Point3d point in points) + { + if (vertices.Count != 0) { - return new Matrix3d(MakePerpendicular(convertedTransform)); + length += point.DistanceTo(vertices.Last()); } - return convertedTransform; + vertices.Add(point); } - - // https://forums.autodesk.com/t5/net/set-blocktransform-values/m-p/6452121#M49479 - private static double[] MakePerpendicular(Matrix3d matrix) - { - // Get the basis vectors of the matrix - Vector3d right = new Vector3d(matrix[0,0], matrix[1,0], matrix[2,0]); - Vector3d up = new Vector3d(matrix[0,1], matrix[1,1], matrix[2,1]); + var _points = vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - - Vector3d newForward = right.CrossProduct(up).GetNormal();; - - Vector3d newUp = newForward.CrossProduct(right).GetNormal(); + var _polyline = new Polyline(_points, ModelUnits); + _polyline.closed = closed || vertices.First().IsEqualTo(vertices.Last()) ? true : false; + _polyline.length = length; - return new []{ - right.X, newUp.X, newForward.X, matrix[0,3], - right.Y, newUp.Y, newForward.Y, matrix[1,3], - right.Z, newUp.Z, newForward.Z, matrix[2,3], - 0.0, 0.0, 0.0, matrix[3,3], - }; + return _polyline; + } + public Polyline PolylineToSpeckle(AcadDB.Polyline polyline) // AcadDB.Polylines can have linear or arc segments. This will convert to linear + { + var points = new List(); + for (int i = 0; i < polyline.NumberOfVertices; i++) + { + points.AddRange(PointToSpeckle(polyline.GetPoint3dAt(i)).ToList()); } - // Line - public Line LineToSpeckle(LineSegment2d line) + + var _polyline = new Polyline(points, ModelUnits); + _polyline.closed = polyline.Closed || polyline.StartPoint.Equals(polyline.EndPoint) ? true : false; // hatch boundary polylines are not closed, cannot rely on .Closed prop + _polyline.length = polyline.Length; + _polyline.bbox = BoxToSpeckle(polyline.GeometricExtents); + + return _polyline; + } + + public Polyline PolylineToSpeckle(Polyline3d polyline) + { + var points = new List(); + + // if this polyline is a new object, retrieve approximate vertices from spline nurbs data (should only be used for curve display value so far) + if (polyline.IsNewObject) { - var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); - _line.length = line.Length; - _line.domain = IntervalToSpeckle(line.GetInterval()); - return _line; + foreach (Point3d vertex in polyline.Spline.NurbsData.GetControlPoints()) + { + points.AddRange(PointToSpeckle(vertex).ToList()); + } } - public Line LineToSpeckle(Line3d line, string units = null) + // otherwise retrieve actual vertices from transaction + else { - var u = units ?? ModelUnits; + foreach (ObjectId id in polyline) + { + var vertex = (PolylineVertex3d)Trans.GetObject(id, OpenMode.ForRead); + points.AddRange(PointToSpeckle(vertex.Position).ToList()); + } + } - var startParam = line.GetParameterOf(line.StartPoint); - var endParam = line.GetParameterOf(line.EndPoint); - var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), u); - _line.length = line.GetLength(startParam, endParam, tolerance); - _line.domain = IntervalToSpeckle(line.GetInterval()); - _line.bbox = BoxToSpeckle(line.OrthoBoundBlock); + var _polyline = new Polyline(points, ModelUnits); + _polyline.closed = polyline.Closed || polyline.StartPoint.Equals(polyline.EndPoint) ? true : false; + _polyline.length = polyline.Length; + _polyline.bbox = BoxToSpeckle(polyline.GeometricExtents); - return _line; - } - public Line LineToSpeckle(LineSegment3d line) + return _polyline; + } + + public Polyline3d PolylineToNativeDB(Polyline polyline) + { + var vertices = new Point3dCollection(); + for (int i = 0; i < polyline.points.Count; i++) { - var _line = new Line(PointToSpeckle(line.StartPoint), PointToSpeckle(line.EndPoint), ModelUnits); - _line.length = line.Length; - _line.domain = IntervalToSpeckle(line.GetInterval()); - _line.bbox = BoxToSpeckle(line.OrthoBoundBlock); - return _line; + vertices.Add(PointToNative(polyline.points[i])); } - public Line3d LineToNative(Line line) + + return new Polyline3d(Poly3dType.SimplePoly, vertices, polyline.closed); + } + + // Polycurve + public Polycurve PolycurveToSpeckle(Polyline2d polyline) // AC polyline2d can have linear, circlular, or elliptical segments + { + var polycurve = new Polycurve(units: ModelUnits) { closed = polyline.Closed }; + + // extract segment curves + var segments = new List(); + var exploded = new DBObjectCollection(); + polyline.Explode(exploded); + Point3d previousPoint = new(); + for (int i = 0; i < exploded.Count; i++) { - var _line = new Line3d(PointToNative(line.start), PointToNative(line.end)); - if (line.domain != null) - try + var segment = exploded[i] as AcadDB.Curve; + + if (i == 0 && exploded.Count > 1) + { + // get the connection point to the next segment - this is necessary since imported polycurves might have segments in different directions + var connectionPoint = new Point3d(); + var nextSegment = exploded[i + 1] as AcadDB.Curve; + if (nextSegment.StartPoint.IsEqualTo(segment.StartPoint) || nextSegment.StartPoint.IsEqualTo(segment.EndPoint)) { - _line.SetInterval(IntervalToNative(line.domain)); + connectionPoint = nextSegment.StartPoint; + } + else + { + connectionPoint = nextSegment.EndPoint; } - catch { } - return _line; - } - public Line LineToSpeckle(AcadDB.Line line, string units = null) - { - var u = units ?? ModelUnits; - var _line = new Line(PointToSpeckle(line.StartPoint, u), PointToSpeckle(line.EndPoint, u), u); - _line.domain = new Interval(line.StartParam, line.EndParam); - _line.length = line.Length; - _line.bbox = BoxToSpeckle(line.GeometricExtents); - return _line; - } - public AcadDB.Line LineToNativeDB(Line line) - { - return new AcadDB.Line(PointToNative(line.start), PointToNative(line.end)); + previousPoint = connectionPoint; + segment = GetCorrectSegmentDirection(segment, connectionPoint, true, out Point3d otherPoint); + } + else + { + segment = GetCorrectSegmentDirection(segment, previousPoint, false, out previousPoint); + } + segments.Add(CurveToSpeckle(segment)); } - // Rectangle - public Polyline RectangleToSpeckle(Rectangle3d rectangle) + if (segments.Count() == 0) { - var _points = new List() { rectangle.LowerLeft, rectangle.LowerRight, rectangle.UpperLeft, rectangle.UpperRight }; - var points = _points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - return new Polyline(points, ModelUnits) { closed = true }; + throw new Exception("Failed to convert Autocad Polyline2d to Speckle Polycurve"); } - // Arc - public Arc ArcToSpeckle(CircularArc2d arc) - { - var interval = arc.GetInterval(); + polycurve.segments = segments; - // find arc plane (normal is in clockwise dir) - var center3 = new Point3d(arc.Center.X, arc.Center.Y, 0); - AcadGeo.Plane plane = (arc.IsClockWise) ? new AcadGeo.Plane(center3, Vector3d.ZAxis.MultiplyBy(-1)) : new AcadGeo.Plane(center3, Vector3d.ZAxis); + polycurve.length = polyline.Length; + polycurve.bbox = BoxToSpeckle(polyline.GeometricExtents); - // calculate total angle. TODO: This needs to be validated across all possible arc orientations - var totalAngle = (arc.IsClockWise) ? Math.Abs(arc.EndAngle - arc.StartAngle) : Math.Abs(arc.EndAngle - arc.StartAngle); + return polycurve; + } - // create arc - var _arc = new Arc(PlaneToSpeckle(plane), arc.Radius, arc.StartAngle, arc.EndAngle, totalAngle, ModelUnits); - _arc.startPoint = PointToSpeckle(arc.StartPoint); - _arc.endPoint = PointToSpeckle(arc.EndPoint); - _arc.midPoint = PointToSpeckle(arc.EvaluatePoint((interval.UpperBound - interval.LowerBound) / 2)); - _arc.domain = IntervalToSpeckle(interval); - _arc.length = arc.GetLength(arc.GetParameterOf(arc.StartPoint), arc.GetParameterOf(arc.EndPoint)); - _arc.bbox = BoxToSpeckle(arc.BoundBlock); - return _arc; - } - public Arc ArcToSpeckle(CircularArc3d arc) - { - var interval = arc.GetInterval(); - var _arc = new Arc(PlaneToSpeckle(arc.GetPlane()), arc.Radius, arc.StartAngle, arc.EndAngle, Math.Abs(arc.EndAngle - arc.StartAngle), ModelUnits); - _arc.startPoint = PointToSpeckle(arc.StartPoint); - _arc.endPoint = PointToSpeckle(arc.EndPoint); - _arc.midPoint = PointToSpeckle(arc.EvaluatePoint((interval.UpperBound - interval.LowerBound) / 2)); - _arc.domain = IntervalToSpeckle(arc.GetInterval()); - _arc.length = arc.GetLength(arc.GetParameterOf(arc.StartPoint), arc.GetParameterOf(arc.EndPoint), tolerance); - _arc.bbox = BoxToSpeckle(arc.OrthoBoundBlock); - return _arc; - } - public CircularArc3d ArcToNative(Arc arc) + public Polycurve PolycurveToSpeckle(AcadDB.Polyline polyline) // AC polylines are polycurves with linear or arc segments + { + var polycurve = new Polycurve(units: ModelUnits) { closed = polyline.Closed }; + + // extract segments + var segments = new List(); + Point3d previousPoint = new(); + for (int i = 0; i < polyline.NumberOfVertices; i++) { - var _arc = new CircularArc3d(PointToNative(arc.startPoint), PointToNative(arc.midPoint), PointToNative(arc.endPoint)); + var segment = GetSegmentByType(polyline, i); + if (segment == null) + { + continue; + } - _arc.SetAxes(VectorToNative(arc.plane.normal), VectorToNative(arc.plane.xdir)); - _arc.SetAngles((double)arc.startAngle, (double)arc.endAngle); + if (i == 0 && polyline.NumberOfVertices > 1) + { + // get the connection point to the next segment + var connectionPoint = new Point3d(); + var nextSegment = GetSegmentByType(polyline, i + 1); + if (nextSegment == null) + { + if (polyline.GetSegmentType(i + 1) == SegmentType.Point) + { + connectionPoint = polyline.GetPoint3dAt(i + 1); + } + else + { + continue; + } + } + else + { + if ( + nextSegment.StartPoint.IsEqualTo(segment.StartPoint) || nextSegment.StartPoint.IsEqualTo(segment.EndPoint) + ) + { + connectionPoint = nextSegment.StartPoint; + } + else + { + connectionPoint = nextSegment.EndPoint; + } + } - return _arc; + previousPoint = connectionPoint; + segment = GetCorrectSegmentDirection(segment, connectionPoint, true, out Point3d otherPoint); + } + else + { + segment = GetCorrectSegmentDirection(segment, previousPoint, false, out previousPoint); + } + segments.Add(CurveToSpeckle(segment)); } - public Arc ArcToSpeckle(AcadDB.Arc arc) + + if (segments.Count() == 0) { - var _arc = new Arc(PlaneToSpeckle(arc.GetPlane()), arc.Radius, arc.StartAngle, arc.EndAngle, arc.TotalAngle, ModelUnits); - _arc.startPoint = PointToSpeckle(arc.StartPoint); - _arc.endPoint = PointToSpeckle(arc.EndPoint); - _arc.midPoint = PointToSpeckle(arc.GetPointAtDist(arc.Length / 2)); - _arc.domain = new Interval(arc.StartParam, arc.EndParam); - _arc.length = arc.Length; - _arc.bbox = BoxToSpeckle(arc.GeometricExtents); - return _arc; + throw new Exception("Failed to convert Autocad Polyline to Speckle Polycurve"); } - public AcadDB.Arc ArcToNativeDB(Arc arc) - { - // because of different plane & start/end angle conventions, most reliable method to convert to autocad convention is to calculate from start, end, and midpoint - var circularArc = ArcToNative(arc); - // calculate adjusted start and end angles from circularArc reference - double angle = circularArc.ReferenceVector.AngleOnPlane(PlaneToNative(arc.plane)); - double startAngle = circularArc.StartAngle + angle; - double endAngle = circularArc.EndAngle + angle; + polycurve.segments = segments; - var _arc = new AcadDB.Arc( - PointToNative(arc.plane.origin), - VectorToNative(arc.plane.normal), - ScaleToNative((double)arc.radius, arc.units), - startAngle, - endAngle); + polycurve.length = polyline.Length; + polycurve.bbox = BoxToSpeckle(polyline.GeometricExtents); - return _arc; - } + return polycurve; + } - // Circle - public Circle CircleToSpeckle(AcadDB.Circle circle) - { - var _circle = new Circle(PlaneToSpeckle(circle.GetPlane()), circle.Radius, ModelUnits); - _circle.length = circle.Circumference; - _circle.bbox = BoxToSpeckle(circle.GeometricExtents); - return _circle; - } - public AcadDB.Circle CircleToNativeDB(Circle circle) - { - var normal = VectorToNative(circle.plane.normal); - var radius = ScaleToNative((double)circle.radius, circle.units); - return new AcadDB.Circle(PointToNative(circle.plane.origin), normal, radius); + private Curve3d GetSegmentByType(AcadDB.Polyline polyline, int i) + { + SegmentType type = polyline.GetSegmentType(i); + switch (type) + { + case SegmentType.Line: + return polyline.GetLineSegmentAt(i); + case SegmentType.Arc: + return polyline.GetArcSegmentAt(i); + default: + return null; } + } + + private AcadDB.Curve GetCorrectSegmentDirection( + AcadDB.Curve segment, + Point3d connectionPoint, + bool isFirstSegment, + out Point3d nextPoint + ) // note sometimes curve3d may not have endpoints + { + nextPoint = segment.EndPoint; - // Ellipse - public Ellipse EllipseToSpeckle(AcadDB.Ellipse ellipse) + if (connectionPoint == null) { - var plane = new AcadGeo.Plane(ellipse.Center, ellipse.MajorAxis, ellipse.MinorAxis); - var _ellipse = new Ellipse(PlaneToSpeckle(plane), ellipse.MajorRadius, ellipse.MinorRadius, ModelUnits); - _ellipse.domain = new Interval(ellipse.StartParam, ellipse.EndParam); - _ellipse.length = ellipse.GetDistanceAtParameter(ellipse.EndParam); - _ellipse.bbox = BoxToSpeckle(ellipse.GeometricExtents); - return _ellipse; + return segment; } - public AcadDB.Ellipse EllipseToNativeDB(Ellipse ellipse) + + bool reverseDirection = false; + if (isFirstSegment) { - var normal = VectorToNative(ellipse.plane.normal); - var xAxisVector = VectorToNative(ellipse.plane.xdir); - var majorAxis = ScaleToNative((double)ellipse.firstRadius, ellipse.units) * xAxisVector.GetNormal(); - var radiusRatio = (double)ellipse.secondRadius / (double)ellipse.firstRadius; - return new AcadDB.Ellipse(PointToNative(ellipse.plane.origin), normal, majorAxis, radiusRatio, 0, 2 * Math.PI); + reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? true : false; + if (reverseDirection) + { + nextPoint = segment.StartPoint; + } } - - // Spiral - - // Polyline - private Polyline PolylineToSpeckle(Point3dCollection points, bool closed) + else { - double length = 0; - List vertices = new List(); - foreach (Point3d point in points) + reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? false : true; + if (reverseDirection) { - if (vertices.Count != 0) length += point.DistanceTo(vertices.Last()); - vertices.Add(point); + nextPoint = segment.StartPoint; } - var _points = vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - - var _polyline = new Polyline(_points, ModelUnits); - _polyline.closed = closed || vertices.First().IsEqualTo(vertices.Last()) ? true : false; - _polyline.length = length; - - return _polyline; } - public Polyline PolylineToSpeckle(AcadDB.Polyline polyline) // AcadDB.Polylines can have linear or arc segments. This will convert to linear + + if (reverseDirection) { - var points = new List(); - for (int i = 0; i < polyline.NumberOfVertices; i++) - points.AddRange(PointToSpeckle(polyline.GetPoint3dAt(i)).ToList()); + segment.ReverseCurve(); + } - var _polyline = new Polyline(points, ModelUnits); - _polyline.closed = polyline.Closed || polyline.StartPoint.Equals(polyline.EndPoint) ? true : false; // hatch boundary polylines are not closed, cannot rely on .Closed prop - _polyline.length = polyline.Length; - _polyline.bbox = BoxToSpeckle(polyline.GeometricExtents); + return segment; + } - return _polyline; - } - public Polyline PolylineToSpeckle(Polyline3d polyline) + private Curve3d GetCorrectSegmentDirection( + Curve3d segment, + Point3d connectionPoint, + bool isFirstSegment, + out Point3d nextPoint + ) // note sometimes curve3d may not have endpoints + { + nextPoint = segment.EndPoint; + + if (connectionPoint == null) { - var points = new List(); + return segment; + } - // if this polyline is a new object, retrieve approximate vertices from spline nurbs data (should only be used for curve display value so far) - if (polyline.IsNewObject) + bool reverseDirection = false; + if (isFirstSegment) + { + reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? true : false; + if (reverseDirection) { - foreach (Point3d vertex in polyline.Spline.NurbsData.GetControlPoints()) - points.AddRange(PointToSpeckle(vertex).ToList()); + nextPoint = segment.StartPoint; } - // otherwise retrieve actual vertices from transaction - else + } + else + { + reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? false : true; + if (reverseDirection) { - foreach (ObjectId id in polyline) - { - var vertex = (PolylineVertex3d)Trans.GetObject(id, OpenMode.ForRead); - points.AddRange(PointToSpeckle(vertex.Position).ToList()); - } + nextPoint = segment.StartPoint; } + } - var _polyline = new Polyline(points, ModelUnits); - _polyline.closed = polyline.Closed || polyline.StartPoint.Equals(polyline.EndPoint) ? true : false; - _polyline.length = polyline.Length; - _polyline.bbox = BoxToSpeckle(polyline.GeometricExtents); + return (reverseDirection) ? segment.GetReverseParameterCurve() : segment; + } - return _polyline; - } - public Polyline3d PolylineToNativeDB(Polyline polyline) + private bool IsPolycurvePlanar(Polycurve polycurve) + { + double? z = null; + foreach (var segment in polycurve.segments) { - var vertices = new Point3dCollection(); - for (int i = 0; i < polyline.points.Count; i++) - vertices.Add(PointToNative(polyline.points[i])); - return new Polyline3d(Poly3dType.SimplePoly, vertices, polyline.closed); - } + switch (segment) + { + case Line o: + if (z == null) + { + z = o.start.z; + } - // Polycurve - public Polycurve PolycurveToSpeckle(Polyline2d polyline) // AC polyline2d can have linear, circlular, or elliptical segments - { - var polycurve = new Polycurve(units: ModelUnits) { closed = polyline.Closed }; + if (o.start.z != z || o.end.z != z) + { + return false; + } - // extract segment curves - var segments = new List(); - var exploded = new DBObjectCollection(); - polyline.Explode(exploded); - Point3d previousPoint = new Point3d(); - for (int i = 0; i < exploded.Count; i++) - { - var segment = exploded[i] as AcadDB.Curve; + break; + case Arc o: + if (z == null) + { + z = o.startPoint.z; + } - if (i == 0 && exploded.Count > 1) - { - // get the connection point to the next segment - this is necessary since imported polycurves might have segments in different directions - var connectionPoint = new Point3d(); - var nextSegment = exploded[i + 1] as AcadDB.Curve; - if (nextSegment.StartPoint.IsEqualTo(segment.StartPoint) || nextSegment.StartPoint.IsEqualTo(segment.EndPoint)) - connectionPoint = nextSegment.StartPoint; - else - connectionPoint = nextSegment.EndPoint; - previousPoint = connectionPoint; - segment = GetCorrectSegmentDirection(segment, connectionPoint, true, out Point3d otherPoint); - } - else - { - segment = GetCorrectSegmentDirection(segment, previousPoint, false, out previousPoint); - } - segments.Add(CurveToSpeckle(segment)); - } + if (o.startPoint.z != z || o.midPoint.z != z || o.endPoint.z != z) + { + return false; + } - if (segments.Count() == 0) - throw new Exception("Failed to convert Autocad Polyline2d to Speckle Polycurve"); + break; + case Curve o: + if (z == null) + { + z = o.points[2]; + } - polycurve.segments = segments; + for (int i = 2; i < o.points.Count; i += 3) + { + if (o.points[i] != z) + { + return false; + } + } - polycurve.length = polyline.Length; - polycurve.bbox = BoxToSpeckle(polyline.GeometricExtents); + break; + case Spiral o: + if (z == null) + { + z = o.startPoint.z; + } + + if (o.startPoint.z != z || o.endPoint.z != z) + { + return false; + } - return polycurve; + break; + } } - public Polycurve PolycurveToSpeckle(AcadDB.Polyline polyline) // AC polylines are polycurves with linear or arc segments - { - var polycurve = new Polycurve(units: ModelUnits) { closed = polyline.Closed }; + return true; + } - // extract segments - var segments = new List(); - Point3d previousPoint = new Point3d(); - for (int i = 0; i < polyline.NumberOfVertices; i++) + // polylines can only support curve segments of type circular arc. + public AcadDB.Polyline PolycurveToNativeDB(Polycurve polycurve) + { + AcadDB.Polyline polyline = new() { Closed = polycurve.closed }; + var plane = new Autodesk.AutoCAD.Geometry.Plane( + Point3d.Origin, + Vector3d.ZAxis.TransformBy(Doc.Editor.CurrentUserCoordinateSystem) + ); // TODO: check this + + // add all vertices + int count = 0; + foreach (var segment in polycurve.segments) + { + switch (segment) { - var segment = GetSegmentByType(polyline, i); - if (segment == null) - continue; - if (i == 0 && polyline.NumberOfVertices > 1) - { - // get the connection point to the next segment - var connectionPoint = new Point3d(); - var nextSegment = GetSegmentByType(polyline, i + 1); - if (nextSegment == null) + case Line o: + polyline.AddVertexAt(count, PointToNative(o.start).Convert2d(plane), 0, 0, 0); + if (!polycurve.closed && count == polycurve.segments.Count - 1) { - if (polyline.GetSegmentType(i + 1) == SegmentType.Point) - { - connectionPoint = polyline.GetPoint3dAt(i + 1); - } - else - continue; + polyline.AddVertexAt(count + 1, PointToNative(o.end).Convert2d(plane), 0, 0, 0); } - else + + count++; + break; + case Arc o: + var angle = o.endAngle - o.startAngle; + angle = angle < 0 ? angle + 2 * Math.PI : angle; + var bulge = Math.Tan((double)angle / 4) * BulgeDirection(o.startPoint, o.midPoint, o.endPoint); // bulge + polyline.AddVertexAt(count, PointToNative(o.startPoint).Convert2d(plane), bulge, 0, 0); + if (!polycurve.closed && count == polycurve.segments.Count - 1) { - if (nextSegment.StartPoint.IsEqualTo(segment.StartPoint) || nextSegment.StartPoint.IsEqualTo(segment.EndPoint)) - connectionPoint = nextSegment.StartPoint; - else - connectionPoint = nextSegment.EndPoint; + polyline.AddVertexAt(count + 1, PointToNative(o.endPoint).Convert2d(plane), 0, 0, 0); } - previousPoint = connectionPoint; - segment = GetCorrectSegmentDirection(segment, connectionPoint, true, out Point3d otherPoint); - } - else - { - segment = GetCorrectSegmentDirection(segment, previousPoint, false, out previousPoint); - } - segments.Add(CurveToSpeckle(segment)); + count++; + break; + case Spiral o: + var vertices = o.displayValue.GetPoints().Select(p => PointToNative(p)).ToList(); + foreach (var vertex in vertices) + { + polyline.AddVertexAt(count, vertex.Convert2d(plane), 0, 0, 0); + count++; + } + break; + default: + return null; } + } - if (segments.Count() == 0) - throw new Exception("Failed to convert Autocad Polyline to Speckle Polycurve"); + return polyline; + } - polycurve.segments = segments; + // calculates bulge direction: (-) clockwise, (+) counterclockwise + private int BulgeDirection(Point start, Point mid, Point end) + { + // get vectors from points + double[] v1 = new double[] { end.x - start.x, end.y - start.y, end.z - start.z }; // vector from start to end point + double[] v2 = new double[] { mid.x - start.x, mid.y - start.y, mid.z - start.z }; // vector from start to mid point - polycurve.length = polyline.Length; - polycurve.bbox = BoxToSpeckle(polyline.GeometricExtents); + // calculate cross product z direction + double z = v1[0] * v2[1] - v2[0] * v1[1]; - return polycurve; + if (z > 0) + { + return -1; } - private Curve3d GetSegmentByType(AcadDB.Polyline polyline, int i) + else { - SegmentType type = polyline.GetSegmentType(i); - switch (type) - { - case SegmentType.Line: - return polyline.GetLineSegmentAt(i); - case SegmentType.Arc: - return polyline.GetArcSegmentAt(i); - default: - return null; - } + return 1; + } + } + + // Spline + public Curve SplineToSpeckle(Spline spline) + { + var curve = new Curve(); + + // get nurbs and geo data + var data = spline.NurbsData; + var _spline = spline.GetGeCurve() as NurbCurve3d; + + // hack: check for incorrectly closed periodic curves (this seems like acad bug, has resulted from receiving rhino curves) + bool periodicClosed = false; + if (_spline.Knots.Count < _spline.NumberOfControlPoints + _spline.Degree + 1 && spline.IsPeriodic) + { + periodicClosed = true; + } + + // handle the display polyline + try + { + var poly = spline.ToPolyline(false, true); + Polyline displayValue = CurveToSpeckle(poly) as Polyline; + curve.displayValue = displayValue; } - private AcadDB.Curve GetCorrectSegmentDirection(AcadDB.Curve segment, Point3d connectionPoint, bool isFirstSegment, out Point3d nextPoint) // note sometimes curve3d may not have endpoints + catch { } + + // get points + // NOTE: for closed periodic splines, autocad does not track last #degree points. Add the first #degree control points to the list if so. + var points = data.GetControlPoints().OfType().ToList(); + if (periodicClosed) { - nextPoint = segment.EndPoint; + points.AddRange(points.GetRange(0, spline.Degree)); + } - if (connectionPoint == null) - return segment; + // get knots + // NOTE: for closed periodic splines, autocad has #control points + 1 knots. Add #degree extra knots to beginning and end with #degree - 1 multiplicity for first and last + var knots = data.GetKnots().OfType().ToList(); + if (periodicClosed) + { + double interval = knots[1] - knots[0]; //knot interval - bool reverseDirection = false; - if (isFirstSegment) + for (int i = 0; i < data.Degree; i++) { - reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? true : false; - if (reverseDirection) nextPoint = segment.StartPoint; + if (i < 2) + { + knots.Insert(knots.Count, knots[knots.Count - 1] + interval); + knots.Insert(0, knots[0] - interval); + } + else + { + knots.Insert(knots.Count, knots[knots.Count - 1]); + knots.Insert(0, knots[0]); + } + } + } + + // get weights + // NOTE: autocad assigns unweighted points a value of -1, and will return an empty list in the spline's nurbsdata if no points are weighted + // NOTE: for closed periodic splines, autocad does not track last #degree points. Add the first #degree weights to the list if so. + var weights = new List(); + for (int i = 0; i < spline.NumControlPoints; i++) + { + double weight = spline.WeightAt(i); + if (weight <= 0) + { + weights.Add(1); } else { - reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? false : true; - if (reverseDirection) nextPoint = segment.StartPoint; + weights.Add(weight); } - - if (reverseDirection) segment.ReverseCurve(); - return segment; } - private Curve3d GetCorrectSegmentDirection(Curve3d segment, Point3d connectionPoint, bool isFirstSegment, out Point3d nextPoint) // note sometimes curve3d may not have endpoints + if (periodicClosed) { - nextPoint = segment.EndPoint; + weights.AddRange(weights.GetRange(0, spline.Degree)); + } - if (connectionPoint == null) - return segment; + // set nurbs curve info + curve.points = points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); + curve.knots = knots; + curve.weights = weights; + curve.degree = spline.Degree; + curve.periodic = spline.IsPeriodic; + curve.rational = spline.IsRational; + curve.closed = (periodicClosed) ? true : spline.Closed; + curve.length = _spline.GetLength(_spline.StartParameter, _spline.EndParameter, tolerance); + curve.domain = IntervalToSpeckle(_spline.GetInterval()); + curve.bbox = BoxToSpeckle(spline.GeometricExtents); + curve.units = ModelUnits; - bool reverseDirection = false; - if (isFirstSegment) - { - reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? true : false; - if (reverseDirection) nextPoint = segment.StartPoint; - } - else + return curve; + } + + // handles polycurves with spline segments: bakes segments individually and then joins + public ApplicationObject PolycurveSplineToNativeDB(Polycurve polycurve) + { + var appObj = new ApplicationObject(polycurve.id, polycurve.speckle_type) + { + applicationId = polycurve.applicationId + }; + + Entity first = null; + List others = new(); + BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); + for (int i = 0; i < polycurve.segments.Count; i++) + { + var segment = polycurve.segments[i]; + var converted = CurveToNativeDB(segment); + if (converted == null || converted.Count == 0) { - reverseDirection = (segment.StartPoint.IsEqualTo(connectionPoint)) ? false : true; - if (reverseDirection) nextPoint = segment.StartPoint; + appObj.Log.Add($"Could not create {(segment as Curve).speckle_type} segment {(segment as Curve).id}"); + continue; } - return (reverseDirection) ? segment.GetReverseParameterCurve() : segment; - } - private bool IsPolycurvePlanar(Polycurve polycurve) - { - double? z = null; - foreach (var segment in polycurve.segments) + foreach (var convertedItem in converted) { - switch (segment) + var newEntity = Trans.GetObject(modelSpaceRecord.Append(convertedItem), OpenMode.ForWrite) as Entity; + appObj.Update(createdId: newEntity.Handle.ToString(), convertedItem: newEntity); + + if (first == null) { - case Line o: - if (z == null) z = o.start.z; - if (o.start.z != z || o.end.z != z) return false; - break; - case Arc o: - if (z == null) z = o.startPoint.z; - if (o.startPoint.z != z || o.midPoint.z != z || o.endPoint.z != z) return false; - break; - case Curve o: - if (z == null) z = o.points[2]; - for (int i = 2; i < o.points.Count; i += 3) - if (o.points[i] != z) return false; - break; - case Spiral o: - if (z == null) z = o.startPoint.z; - if (o.startPoint.z != z || o.endPoint.z != z) return false; - break; + first = newEntity; + } + else + { + others.Add(newEntity); } } - return true; } - // polylines can only support curve segments of type circular arc. - public AcadDB.Polyline PolycurveToNativeDB(Polycurve polycurve) + if (first == null) { - AcadDB.Polyline polyline = new AcadDB.Polyline() { Closed = polycurve.closed }; - var plane = new Autodesk.AutoCAD.Geometry.Plane(Point3d.Origin, Vector3d.ZAxis.TransformBy(Doc.Editor.CurrentUserCoordinateSystem)); // TODO: check this + appObj.Update(status: ApplicationObject.State.Failed, logItem: "No segments were successfully converted"); + return appObj; + } - // add all vertices - int count = 0; - foreach (var segment in polycurve.segments) + if (others.Count > 0) + { + try { - switch (segment) - { - case Line o: - polyline.AddVertexAt(count, PointToNative(o.start).Convert2d(plane), 0, 0, 0); - if (!polycurve.closed && count == polycurve.segments.Count - 1) - polyline.AddVertexAt(count + 1, PointToNative(o.end).Convert2d(plane), 0, 0, 0); - count++; - break; - case Arc o: - var angle = o.endAngle - o.startAngle; - angle = angle < 0 ? angle + 2 * Math.PI : angle; - var bulge = Math.Tan((double)angle / 4) * BulgeDirection(o.startPoint, o.midPoint, o.endPoint); // bulge - polyline.AddVertexAt(count, PointToNative(o.startPoint).Convert2d(plane), bulge, 0, 0); - if (!polycurve.closed && count == polycurve.segments.Count - 1) - polyline.AddVertexAt(count + 1, PointToNative(o.endPoint).Convert2d(plane), 0, 0, 0); - count++; - break; - case Spiral o: - var vertices = o.displayValue.GetPoints().Select(p => PointToNative(p)).ToList(); - foreach (var vertex in vertices) - { - polyline.AddVertexAt(count, vertex.Convert2d(plane), 0, 0, 0); - count++; - } - break; - default: - return null; - } + first.JoinEntities(others.ToArray()); + // TODO: this always fails. Fix and edit the createdids and converted to only reflect the new joined entities + } + catch (Exception e) + { + appObj.Update(logItem: $"Could not create spline from segments: {e.Message}"); } - - return polyline; } - // calculates bulge direction: (-) clockwise, (+) counterclockwise - private int BulgeDirection(Point start, Point mid, Point end) + return appObj; + } + + // Curve + // TODO: NOT TESTED + public ICurve CurveToSpeckle(Curve3d curve, string units = null) + { + var u = units ?? ModelUnits; + + // note: some curve3ds may not have endpoints! Not sure what contexts this may occur in, might cause issues later. + switch (curve) { - // get vectors from points - double[] v1 = new double[] { end.x - start.x, end.y - start.y, end.z - start.z }; // vector from start to end point - double[] v2 = new double[] { mid.x - start.x, mid.y - start.y, mid.z - start.z }; // vector from start to mid point + case LineSegment3d line: + return LineToSpeckle(line); + case CircularArc3d arc: + return ArcToSpeckle(arc); + default: + return NurbsToSpeckle(curve as NurbCurve3d); + } + } - // calculate cross product z direction - double z = v1[0] * v2[1] - v2[0] * v1[1]; + public ICurve CurveToSpeckle(Curve2d curve, string units = null) + { + var u = units ?? ModelUnits; - if (z > 0) - return -1; - else - return 1; + // note: some curve2ds may not have endpoints! + switch (curve) + { + case LineSegment2d line: + return LineToSpeckle(line); + case CircularArc2d arc: + return ArcToSpeckle(arc); + default: + return NurbsToSpeckle(curve as NurbCurve2d); } + } + + public Curve NurbsToSpeckle(NurbCurve2d curve) + { + var _curve = new Curve(); - // Spline - public Curve SplineToSpeckle(Spline spline) + // get control points + var points = new List(); + for (int i = 0; i < curve.NumControlPoints; i++) { - var curve = new Curve(); + points.AddRange(PointToSpeckle(curve.GetControlPointAt(i)).ToList()); + } - // get nurbs and geo data - var data = spline.NurbsData; - var _spline = spline.GetGeCurve() as NurbCurve3d; + // get knots + var knots = new List(); + for (int i = 0; i < curve.NumKnots; i++) + { + knots.Add(curve.GetKnotAt(i)); + } - // hack: check for incorrectly closed periodic curves (this seems like acad bug, has resulted from receiving rhino curves) - bool periodicClosed = false; - if (_spline.Knots.Count < _spline.NumberOfControlPoints + _spline.Degree + 1 && spline.IsPeriodic) - periodicClosed = true; + // get weights + var weights = new List(); + for (int i = 0; i < curve.NumWeights; i++) + { + weights.Add(curve.GetWeightAt(i)); + } - // handle the display polyline - try - { - var poly = spline.ToPolyline(false, true); - Polyline displayValue = CurveToSpeckle(poly) as Polyline; - curve.displayValue = displayValue; - } - catch { } + // set nurbs curve info + _curve.points = points; + _curve.knots = knots; + _curve.weights = weights; + _curve.degree = curve.Degree; + _curve.periodic = curve.IsPeriodic(out double period); + _curve.rational = curve.IsRational; + _curve.closed = curve.IsClosed(); + _curve.length = curve.GetLength(curve.StartParameter, curve.EndParameter); + _curve.domain = IntervalToSpeckle(curve.GetInterval()); + _curve.units = ModelUnits; - // get points - // NOTE: for closed periodic splines, autocad does not track last #degree points. Add the first #degree control points to the list if so. - var points = data.GetControlPoints().OfType().ToList(); - if (periodicClosed) - points.AddRange(points.GetRange(0, spline.Degree)); + return _curve; + } - // get knots - // NOTE: for closed periodic splines, autocad has #control points + 1 knots. Add #degree extra knots to beginning and end with #degree - 1 multiplicity for first and last - var knots = data.GetKnots().OfType().ToList(); - if (periodicClosed) - { - double interval = knots[1] - knots[0]; //knot interval + public Curve NurbsToSpeckle(NurbCurve3d curve) + { + var _curve = new Curve(); - for (int i = 0; i < data.Degree; i++) - { - if (i < 2) - { - knots.Insert(knots.Count, knots[knots.Count - 1] + interval); - knots.Insert(0, knots[0] - interval); - } - else - { - knots.Insert(knots.Count, knots[knots.Count - 1]); - knots.Insert(0, knots[0]); - } - } - } + // get control points + var points = new List(); + for (int i = 0; i < curve.NumberOfControlPoints; i++) + { + points.AddRange(PointToSpeckle(curve.ControlPointAt(i)).ToList()); + } - // get weights - // NOTE: autocad assigns unweighted points a value of -1, and will return an empty list in the spline's nurbsdata if no points are weighted - // NOTE: for closed periodic splines, autocad does not track last #degree points. Add the first #degree weights to the list if so. - var weights = new List(); - for (int i = 0; i < spline.NumControlPoints; i++) - { - double weight = spline.WeightAt(i); - if (weight <= 0) - weights.Add(1); - else - weights.Add(weight); - } - if (periodicClosed) - weights.AddRange(weights.GetRange(0, spline.Degree)); - - // set nurbs curve info - curve.points = points.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - curve.knots = knots; - curve.weights = weights; - curve.degree = spline.Degree; - curve.periodic = spline.IsPeriodic; - curve.rational = spline.IsRational; - curve.closed = (periodicClosed) ? true : spline.Closed; - curve.length = _spline.GetLength(_spline.StartParameter, _spline.EndParameter, tolerance); - curve.domain = IntervalToSpeckle(_spline.GetInterval()); - curve.bbox = BoxToSpeckle(spline.GeometricExtents); - curve.units = ModelUnits; - - return curve; - } - // handles polycurves with spline segments: bakes segments individually and then joins - public ApplicationObject PolycurveSplineToNativeDB(Polycurve polycurve) - { - var appObj = new ApplicationObject(polycurve.id, polycurve.speckle_type) { applicationId = polycurve.applicationId }; - - Entity first = null; - List others = new List(); - BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); - for (int i = 0; i < polycurve.segments.Count; i++) - { - var segment = polycurve.segments[i]; - var converted = CurveToNativeDB(segment); - if (converted == null || converted.Count == 0) - { - appObj.Log.Add($"Could not create {(segment as Curve).speckle_type} segment {(segment as Curve).id}"); - continue; - } + // get knots + var knots = new List(); + for (int i = 0; i < curve.NumberOfKnots; i++) + { + knots.Add(curve.KnotAt(i)); + } - foreach (var convertedItem in converted) - { - var newEntity = Trans.GetObject(modelSpaceRecord.Append(convertedItem), OpenMode.ForWrite) as Entity; - appObj.Update(createdId: newEntity.Handle.ToString(), convertedItem: newEntity); + // get weights + var weights = new List(); + for (int i = 0; i < curve.NumWeights; i++) + { + weights.Add(curve.GetWeightAt(i)); + } - if (first == null) - first = newEntity; - else - others.Add(newEntity); - } - } + // set nurbs curve info + _curve.points = points; + _curve.knots = knots; + _curve.weights = weights; + _curve.degree = curve.Degree; + _curve.periodic = curve.IsPeriodic(out double period); + _curve.rational = curve.IsRational; + _curve.closed = curve.IsClosed(); + _curve.length = curve.GetLength(curve.StartParameter, curve.EndParameter, tolerance); + _curve.domain = IntervalToSpeckle(curve.GetInterval()); + _curve.bbox = BoxToSpeckle(curve.OrthoBoundBlock); + _curve.units = ModelUnits; - if (first == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "No segments were successfully converted"); - return appObj; - } + return _curve; + } - if (others.Count > 0) - { - try - { - first.JoinEntities(others.ToArray()); - // TODO: this always fails. Fix and edit the createdids and converted to only reflect the new joined entities - } - catch (Exception e) - { - appObj.Update(logItem: $"Could not create spline from segments: {e.Message}"); - } - } - return appObj; + // TODO: need to handle curves generated from polycurves with spline segments (this probably has to do with control points with varying # of knots associated with it) + public NurbCurve3d NurbcurveToNative(Curve curve) + { + // process control points + // NOTE: for **closed periodic** curves that have "n" control pts, curves sent from rhino will have n+degree points. Remove extra pts for autocad. + var _points = curve.GetPoints().Select(o => PointToNative(o)).ToList(); + if (curve.closed && curve.periodic) + { + _points = _points.GetRange(0, _points.Count - curve.degree); } - // Curve - // TODO: NOT TESTED - public ICurve CurveToSpeckle(Curve3d curve, string units = null) - { - var u = units ?? ModelUnits; + var points = new Point3dCollection(_points.ToArray()); - // note: some curve3ds may not have endpoints! Not sure what contexts this may occur in, might cause issues later. - switch (curve) - { - case LineSegment3d line: - return LineToSpeckle(line); - case CircularArc3d arc: - return ArcToSpeckle(arc); - default: - return NurbsToSpeckle(curve as NurbCurve3d); - } + // process knots + // NOTE: Autocad defines spline knots as a vector of size # control points + degree + 1. (# at start and end should match degree) + // Conversions for autocad need to make sure this is satisfied, otherwise will cause protected mem crash. + // NOTE: for **closed periodic** curves that have "n" control pts, # of knots should be n + 1. Remove degree = 3 knots from start and end. + var _knots = curve.knots; + if (curve.knots.Count == _points.Count + curve.degree - 1) // handles rhino format curves + { + _knots.Insert(0, _knots[0]); + _knots.Insert(_knots.Count - 1, _knots[_knots.Count - 1]); } - public ICurve CurveToSpeckle(Curve2d curve, string units = null) + if (curve.closed && curve.periodic) // handles closed periodic curves { - var u = units ?? ModelUnits; + _knots = _knots.GetRange(curve.degree, _knots.Count - curve.degree * 2); + } - // note: some curve2ds may not have endpoints! - switch (curve) - { - case LineSegment2d line: - return LineToSpeckle(line); - case CircularArc2d arc: - return ArcToSpeckle(arc); - default: - return NurbsToSpeckle(curve as NurbCurve2d); - } + var knots = new KnotCollection(); + foreach (var _knot in _knots) + { + knots.Add(_knot); } - public Curve NurbsToSpeckle(NurbCurve2d curve) - { - var _curve = new Curve(); - - // get control points - var points = new List(); - for (int i = 0; i < curve.NumControlPoints; i++) - points.AddRange(PointToSpeckle(curve.GetControlPointAt(i)).ToList()); - - // get knots - var knots = new List(); - for (int i = 0; i < curve.NumKnots; i++) - knots.Add(curve.GetKnotAt(i)); - - // get weights - var weights = new List(); - for (int i = 0; i < curve.NumWeights; i++) - weights.Add(curve.GetWeightAt(i)); - - // set nurbs curve info - _curve.points = points; - _curve.knots = knots; - _curve.weights = weights; - _curve.degree = curve.Degree; - _curve.periodic = curve.IsPeriodic(out double period); - _curve.rational = curve.IsRational; - _curve.closed = curve.IsClosed(); - _curve.length = curve.GetLength(curve.StartParameter, curve.EndParameter); - _curve.domain = IntervalToSpeckle(curve.GetInterval()); - _curve.units = ModelUnits; - - return _curve; - } - public Curve NurbsToSpeckle(NurbCurve3d curve) - { - var _curve = new Curve(); - - // get control points - var points = new List(); - for (int i = 0; i < curve.NumberOfControlPoints; i++) - points.AddRange(PointToSpeckle(curve.ControlPointAt(i)).ToList()); - - // get knots - var knots = new List(); - for (int i = 0; i < curve.NumberOfKnots; i++) - knots.Add(curve.KnotAt(i)); - - // get weights - var weights = new List(); - for (int i = 0; i < curve.NumWeights; i++) - weights.Add(curve.GetWeightAt(i)); - - // set nurbs curve info - _curve.points = points; - _curve.knots = knots; - _curve.weights = weights; - _curve.degree = curve.Degree; - _curve.periodic = curve.IsPeriodic(out double period); - _curve.rational = curve.IsRational; - _curve.closed = curve.IsClosed(); - _curve.length = curve.GetLength(curve.StartParameter, curve.EndParameter, tolerance); - _curve.domain = IntervalToSpeckle(curve.GetInterval()); - _curve.bbox = BoxToSpeckle(curve.OrthoBoundBlock); - _curve.units = ModelUnits; - - return _curve; - } - // TODO: need to handle curves generated from polycurves with spline segments (this probably has to do with control points with varying # of knots associated with it) - public NurbCurve3d NurbcurveToNative(Curve curve) - { - // process control points - // NOTE: for **closed periodic** curves that have "n" control pts, curves sent from rhino will have n+degree points. Remove extra pts for autocad. - var _points = curve.GetPoints().Select(o => PointToNative(o)).ToList(); - if (curve.closed && curve.periodic) - _points = _points.GetRange(0, _points.Count - curve.degree); - var points = new Point3dCollection(_points.ToArray()); - - // process knots - // NOTE: Autocad defines spline knots as a vector of size # control points + degree + 1. (# at start and end should match degree) - // Conversions for autocad need to make sure this is satisfied, otherwise will cause protected mem crash. - // NOTE: for **closed periodic** curves that have "n" control pts, # of knots should be n + 1. Remove degree = 3 knots from start and end. - var _knots = curve.knots; - if (curve.knots.Count == _points.Count + curve.degree - 1) // handles rhino format curves - { - _knots.Insert(0, _knots[0]); - _knots.Insert(_knots.Count - 1, _knots[_knots.Count - 1]); - } - if (curve.closed && curve.periodic) // handles closed periodic curves - _knots = _knots.GetRange(curve.degree, _knots.Count - curve.degree * 2); - var knots = new KnotCollection(); - foreach (var _knot in _knots) - knots.Add(_knot); - // process weights - // NOTE: if all weights are the same, autocad convention is to pass an empty list (this will assign them a value of -1) - var _weights = curve.weights; - if (curve.closed && curve.periodic) // handles closed periodic curves - _weights = curve.weights.GetRange(0, _points.Count); - DoubleCollection weights; - weights = (_weights.Distinct().Count() == 1) ? new DoubleCollection() : new DoubleCollection(_weights.ToArray()); + // process weights + // NOTE: if all weights are the same, autocad convention is to pass an empty list (this will assign them a value of -1) + var _weights = curve.weights; + if (curve.closed && curve.periodic) // handles closed periodic curves + { + _weights = curve.weights.GetRange(0, _points.Count); + } - NurbCurve3d _curve = new NurbCurve3d(curve.degree, knots, points, weights, curve.periodic); - if (curve.closed) - _curve.MakeClosed(); - _curve.SetInterval(IntervalToNative(curve.domain)); + DoubleCollection weights; + weights = (_weights.Distinct().Count() == 1) ? new DoubleCollection() : new DoubleCollection(_weights.ToArray()); - return _curve; - } - public ICurve CurveToSpeckle(AcadDB.Curve curve, string units = null) + NurbCurve3d _curve = new(curve.degree, knots, points, weights, curve.periodic); + if (curve.closed) { - var u = units ?? ModelUnits; + _curve.MakeClosed(); + } - switch (curve) - { - case AcadDB.Line line: - return LineToSpeckle(line, u); + _curve.SetInterval(IntervalToNative(curve.domain)); - case AcadDB.Polyline polyline: - if (polyline.IsOnlyLines) - return PolylineToSpeckle(polyline); - else - return PolycurveToSpeckle(polyline); + return _curve; + } + + public ICurve CurveToSpeckle(AcadDB.Curve curve, string units = null) + { + var u = units ?? ModelUnits; + + switch (curve) + { + case AcadDB.Line line: + return LineToSpeckle(line, u); + + case AcadDB.Polyline polyline: + if (polyline.IsOnlyLines) + { + return PolylineToSpeckle(polyline); + } + else + { + return PolycurveToSpeckle(polyline); + } - case AcadDB.Polyline2d polyline2d: - return PolycurveToSpeckle(polyline2d); + case AcadDB.Polyline2d polyline2d: + return PolycurveToSpeckle(polyline2d); - case AcadDB.Polyline3d polyline3d: - return PolylineToSpeckle(polyline3d); + case AcadDB.Polyline3d polyline3d: + return PolylineToSpeckle(polyline3d); - case AcadDB.Arc arc: - return ArcToSpeckle(arc); + case AcadDB.Arc arc: + return ArcToSpeckle(arc); - case AcadDB.Circle circle: - return CircleToSpeckle(circle); + case AcadDB.Circle circle: + return CircleToSpeckle(circle); - case AcadDB.Ellipse ellipse: - return EllipseToSpeckle(ellipse); + case AcadDB.Ellipse ellipse: + return EllipseToSpeckle(ellipse); - case AcadDB.Spline spline: - return SplineToSpeckle(spline); + case AcadDB.Spline spline: + return SplineToSpeckle(spline); - default: - return null; - } + default: + return null; } - public AcadDB.Curve NurbsToNativeDB(Curve curve) - { - var _curve = AcadDB.Curve.CreateFromGeCurve(NurbcurveToNative(curve)); - return _curve; + } + + public AcadDB.Curve NurbsToNativeDB(Curve curve) + { + var _curve = AcadDB.Curve.CreateFromGeCurve(NurbcurveToNative(curve)); + return _curve; + } + + public List CurveToNativeDB(ICurve icurve) + { + var convertedList = new List(); + AcadDB.Curve converted = null; + switch (icurve) + { + case Line line: + converted = LineToNativeDB(line); + break; + case Polyline polyline: + converted = PolylineToNativeDB(polyline); + break; + case Arc arc: + converted = ArcToNativeDB(arc); + break; + case Circle circle: + converted = CircleToNativeDB(circle); + break; + case Ellipse ellipse: + converted = EllipseToNativeDB(ellipse); + break; + case Polycurve polycurve: + if (polycurve.segments.Where(o => o is Curve).Count() > 0) + { + var convertedPolycurve = PolycurveSplineToNativeDB(polycurve); + convertedList = convertedPolycurve.Converted.Cast().ToList(); + } + else + { + converted = PolycurveToNativeDB(polycurve); + } + break; + case Curve curve: + converted = NurbsToNativeDB(curve); + break; + default: + break; } - public List CurveToNativeDB(ICurve icurve) + if (converted != null) { - var convertedList = new List(); - AcadDB.Curve converted = null; - switch (icurve) - { - case Line line: - converted = LineToNativeDB(line); - break; - case Polyline polyline: - converted = PolylineToNativeDB(polyline); - break; - case Arc arc: - converted = ArcToNativeDB(arc); - break; - case Circle circle: - converted = CircleToNativeDB(circle); - break; - case Ellipse ellipse: - converted = EllipseToNativeDB(ellipse); - break; - case Polycurve polycurve: - if (polycurve.segments.Where(o => o is Curve).Count() > 0) - { - var convertedPolycurve = PolycurveSplineToNativeDB(polycurve); - convertedList = convertedPolycurve.Converted.Cast().ToList(); - } - else - { - converted = PolycurveToNativeDB(polycurve); - } - break; - case Curve curve: - converted = NurbsToNativeDB(curve); - break; - default: - break; - } - if (converted != null) - convertedList.Add(converted); - return convertedList; + convertedList.Add(converted); } - // Surface - public Mesh SurfaceToSpeckle(AcadDB.Surface surface, out List notes, string units = null) - { - var u = units ?? ModelUnits; + return convertedList; + } - switch (surface) - { - case AcadDB.PlaneSurface _: - case AcadDB.NurbSurface _: - default: // return mesh for now - var displayMesh = GetMeshFromSolidOrSurface(out notes, surface: surface); - return displayMesh; - } - } + // Surface + public Mesh SurfaceToSpeckle(AcadDB.Surface surface, out List notes, string units = null) + { + var u = units ?? ModelUnits; - // Region - public Mesh RegionToSpeckle(Region region, out List notes, string units = null) + switch (surface) { - return GetMeshFromSolidOrSurface(out notes, region: region); + case AcadDB.PlaneSurface _: + case AcadDB.NurbSurface _: + default: // return mesh for now + var displayMesh = GetMeshFromSolidOrSurface(out notes, surface: surface); + return displayMesh; } + } + + // Region + public Mesh RegionToSpeckle(Region region, out List notes, string units = null) + { + return GetMeshFromSolidOrSurface(out notes, region: region); + } + + // Box + public Box BoxToSpeckle(BoundBlock2d bound) + { + // convert min and max pts to speckle first + var min = PointToSpeckle(bound.GetMinimumPoint()); + var max = PointToSpeckle(bound.GetMaximumPoint()); + + // get dimension intervals + var xSize = new Interval(min.x, max.x); + var ySize = new Interval(min.y, max.y); + var zSize = new Interval(min.z, max.z); + + // get the base plane of the bounding box from extents and current UCS + var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; + var plane = new AcadGeo.Plane( + new Point3d(bound.GetMinimumPoint().X, bound.GetMinimumPoint().Y, 0), + ucs.Xaxis, + ucs.Yaxis + ); + + var box = new Box() + { + xSize = xSize, + ySize = ySize, + zSize = zSize, + basePlane = PlaneToSpeckle(plane), + volume = xSize.Length * ySize.Length * zSize.Length, + units = ModelUnits + }; + + return box; + } - // Box - public Box BoxToSpeckle(BoundBlock2d bound) + public Box BoxToSpeckle(BoundBlock3d bound) + { + try { // convert min and max pts to speckle first var min = PointToSpeckle(bound.GetMinimumPoint()); @@ -1070,7 +1346,7 @@ public Box BoxToSpeckle(BoundBlock2d bound) // get the base plane of the bounding box from extents and current UCS var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - var plane = new AcadGeo.Plane(new Point3d(bound.GetMinimumPoint().X, bound.GetMinimumPoint().Y, 0), ucs.Xaxis, ucs.Yaxis); + var plane = new AcadGeo.Plane(bound.GetMinimumPoint(), ucs.Xaxis, ucs.Yaxis); var box = new Box() { @@ -1084,350 +1360,366 @@ public Box BoxToSpeckle(BoundBlock2d bound) return box; } - public Box BoxToSpeckle(BoundBlock3d bound) + catch { - try - { - // convert min and max pts to speckle first - var min = PointToSpeckle(bound.GetMinimumPoint()); - var max = PointToSpeckle(bound.GetMaximumPoint()); - - // get dimension intervals - var xSize = new Interval(min.x, max.x); - var ySize = new Interval(min.y, max.y); - var zSize = new Interval(min.z, max.z); - - // get the base plane of the bounding box from extents and current UCS - var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - var plane = new AcadGeo.Plane(bound.GetMinimumPoint(), ucs.Xaxis, ucs.Yaxis); - - var box = new Box() - { - xSize = xSize, - ySize = ySize, - zSize = zSize, - basePlane = PlaneToSpeckle(plane), - volume = xSize.Length * ySize.Length * zSize.Length, - units = ModelUnits - }; - - return box; - } - catch - { - return null; - } + return null; } - public Box BoxToSpeckle(Extents3d extents) + } + + public Box BoxToSpeckle(Extents3d extents) + { + try { - try - { - // convert min and max pts to speckle first - var min = PointToSpeckle(extents.MinPoint); - var max = PointToSpeckle(extents.MaxPoint); + // convert min and max pts to speckle first + var min = PointToSpeckle(extents.MinPoint); + var max = PointToSpeckle(extents.MaxPoint); - // get dimension intervals - var xSize = new Interval(min.x, max.x); - var ySize = new Interval(min.y, max.y); - var zSize = new Interval(min.z, max.z); + // get dimension intervals + var xSize = new Interval(min.x, max.x); + var ySize = new Interval(min.y, max.y); + var zSize = new Interval(min.z, max.z); - // get the base plane of the bounding box from extents and current UCS - var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; - var plane = new AcadGeo.Plane(extents.MinPoint, ucs.Xaxis, ucs.Yaxis); + // get the base plane of the bounding box from extents and current UCS + var ucs = Doc.Editor.CurrentUserCoordinateSystem.CoordinateSystem3d; + var plane = new AcadGeo.Plane(extents.MinPoint, ucs.Xaxis, ucs.Yaxis); - var box = new Box() - { - xSize = xSize, - ySize = ySize, - zSize = zSize, - basePlane = PlaneToSpeckle(plane), - volume = xSize.Length * ySize.Length * zSize.Length, - units = ModelUnits - }; - - return box; - } - catch + var box = new Box() { - return null; - } - } + xSize = xSize, + ySize = ySize, + zSize = zSize, + basePlane = PlaneToSpeckle(plane), + volume = xSize.Length * ySize.Length * zSize.Length, + units = ModelUnits + }; - // Brep - public Mesh SolidToSpeckle(Solid3d solid, out List notes, string units = null) + return box; + } + catch { - return GetMeshFromSolidOrSurface(out notes, solid: solid); + return null; } + } + + // Brep + public Mesh SolidToSpeckle(Solid3d solid, out List notes, string units = null) + { + return GetMeshFromSolidOrSurface(out notes, solid: solid); + } - // Mesh - /* need edge & face info on polygon meshes - public Mesh MeshToSpeckle(AcadDB.PolygonMesh mesh) + // Mesh + /* need edge & face info on polygon meshes + public Mesh MeshToSpeckle(AcadDB.PolygonMesh mesh) + { + var _vertices = new List(); + var colors = new List(); + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - var _vertices = new List(); - var colors = new List(); - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + foreach (ObjectId id in mesh) { - foreach (ObjectId id in mesh) - { - var vertex = (PolygonMeshVertex)tr.GetObject(id, OpenMode.ForRead); - _vertices.Add(vertex.Position); - colors.Add(vertex.Color.ColorValue.ToArgb()); - } - tr.Commit(); + var vertex = (PolygonMeshVertex)tr.GetObject(id, OpenMode.ForRead); + _vertices.Add(vertex.Position); + colors.Add(vertex.Color.ColorValue.ToArgb()); } - var vertices = PointsToFlatArray(_vertices); + tr.Commit(); + } + var vertices = PointsToFlatArray(_vertices); - var speckleMesh = new Mesh(vertices, faces, colors.ToArray(), null, ModelUnits); - speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents, true); + var speckleMesh = new Mesh(vertices, faces, colors.ToArray(), null, ModelUnits); + speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents, true); - return speckleMesh; - } - */ - // Polyface mesh vertex indexing starts at 1. Subtract 1 from face vertex index when sending to Speckle - public Mesh MeshToSpeckle(PolyFaceMesh mesh, string units = null) - { - var u = units ?? ModelUnits; + return speckleMesh; + } + */ + // Polyface mesh vertex indexing starts at 1. Subtract 1 from face vertex index when sending to Speckle + public Mesh MeshToSpeckle(PolyFaceMesh mesh, string units = null) + { + var u = units ?? ModelUnits; - var _vertices = new List(); - var faces = new List(); - var colors = new List(); - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + var _vertices = new List(); + var faces = new List(); + var colors = new List(); + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + foreach (ObjectId id in mesh) { - foreach (ObjectId id in mesh) + DBObject obj = tr.GetObject(id, OpenMode.ForRead); + switch (obj) { - DBObject obj = tr.GetObject(id, OpenMode.ForRead); - switch (obj) - { - case PolyFaceMeshVertex o: - _vertices.Add(o.Position); - colors.Add(o.Color.ColorValue.ToArgb()); - break; - case FaceRecord o: - var indices = new List(); - for (short i = 0; i < 4; i++) + case PolyFaceMeshVertex o: + _vertices.Add(o.Position); + colors.Add(o.Color.ColorValue.ToArgb()); + break; + case FaceRecord o: + var indices = new List(); + for (short i = 0; i < 4; i++) + { + short index = o.GetVertexAt(i); + if (index == 0) { - short index = o.GetVertexAt(i); - if (index == 0) continue; - var adjustedIndex = index > 0 ? index - 1 : Math.Abs(index) - 1; // vertices are 1 indexed, and can be negative (hidden) - indices.Add(adjustedIndex); + continue; } - if (indices.Count == 4) - faces.AddRange(new List { 4, indices[0], indices[1], indices[2], indices[3] }); - else - faces.AddRange(new List { 3, indices[0], indices[1], indices[2] }); - break; - } + var adjustedIndex = index > 0 ? index - 1 : Math.Abs(index) - 1; // vertices are 1 indexed, and can be negative (hidden) + indices.Add(adjustedIndex); + } + + if (indices.Count == 4) + { + faces.AddRange(new List { 4, indices[0], indices[1], indices[2], indices[3] }); + } + else + { + faces.AddRange(new List { 3, indices[0], indices[1], indices[2] }); + } + + break; } - tr.Commit(); } + tr.Commit(); + } + + var vertices = new List(_vertices.Count * 3); + foreach (Point3d vert in _vertices) + { + vertices.AddRange(PointToSpeckle(vert).ToList()); + } - var vertices = new List(_vertices.Count * 3); - foreach (Point3d vert in _vertices) - vertices.AddRange(PointToSpeckle(vert).ToList()); + var speckleMesh = new Mesh(vertices, faces, colors, null, u); + speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents); - var speckleMesh = new Mesh(vertices, faces, colors, null, u); - speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents); + return speckleMesh; + } - return speckleMesh; + public Mesh MeshToSpeckle(SubDMesh mesh) + { + //vertices + var vertices = new List(mesh.Vertices.Count * 3); + foreach (Point3d vert in mesh.Vertices) + { + vertices.AddRange(PointToSpeckle(vert).ToList()); } - public Mesh MeshToSpeckle(SubDMesh mesh) + + // faces + var faces = new List(); + int[] faceArr = mesh.FaceArray.ToArray(); // contains vertex indices + int edgeCount = 0; + for (int i = 0; i < faceArr.Length; i = i + edgeCount + 1) { - //vertices - var vertices = new List(mesh.Vertices.Count * 3); - foreach (Point3d vert in mesh.Vertices) - vertices.AddRange(PointToSpeckle(vert).ToList()); + List faceVertices = new(); + edgeCount = faceArr[i]; + for (int j = i + 1; j <= i + edgeCount; j++) + { + faceVertices.Add(faceArr[j]); + } - // faces - var faces = new List(); - int[] faceArr = mesh.FaceArray.ToArray(); // contains vertex indices - int edgeCount = 0; - for (int i = 0; i < faceArr.Length; i = i + edgeCount + 1) + if (edgeCount == 4) // quad face { - List faceVertices = new List(); - edgeCount = faceArr[i]; - for (int j = i + 1; j <= i + edgeCount; j++) - faceVertices.Add(faceArr[j]); - if (edgeCount == 4) // quad face - faces.AddRange(new List { 4, faceVertices[0], faceVertices[1], faceVertices[2], faceVertices[3] }); - else // triangle face - faces.AddRange(new List { 3, faceVertices[0], faceVertices[1], faceVertices[2] }); + faces.AddRange(new List { 4, faceVertices[0], faceVertices[1], faceVertices[2], faceVertices[3] }); } + else // triangle face + { + faces.AddRange(new List { 3, faceVertices[0], faceVertices[1], faceVertices[2] }); + } + } - // colors - var colors = mesh.VertexColorArray.Select(o => Color.FromArgb(Convert.ToInt32(o.Red), Convert.ToInt32(o.Green), Convert.ToInt32(o.Blue)).ToArgb()).ToList(); + // colors + var colors = mesh.VertexColorArray + .Select(o => Color.FromArgb(Convert.ToInt32(o.Red), Convert.ToInt32(o.Green), Convert.ToInt32(o.Blue)).ToArgb()) + .ToList(); - var speckleMesh = new Mesh(vertices, faces, colors, null, ModelUnits); - speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents); + var speckleMesh = new Mesh(vertices, faces, colors, null, ModelUnits); + speckleMesh.bbox = BoxToSpeckle(mesh.GeometricExtents); - return speckleMesh; - } - // Polyface mesh vertex indexing starts at 1. Add 1 to face vertex index when converting to native - public PolyFaceMesh MeshToNativeDB(Mesh mesh) - { - mesh.TriangulateMesh(true); + return speckleMesh; + } + + // Polyface mesh vertex indexing starts at 1. Add 1 to face vertex index when converting to native + public PolyFaceMesh MeshToNativeDB(Mesh mesh) + { + mesh.TriangulateMesh(true); - // get vertex points - var vertices = new Point3dCollection(); - var points = mesh.GetPoints().Select(o => PointToNative(o)).ToList(); - foreach (var point in points) - vertices.Add(point); + // get vertex points + var vertices = new Point3dCollection(); + var points = mesh.GetPoints().Select(o => PointToNative(o)).ToList(); + foreach (var point in points) + { + vertices.Add(point); + } - PolyFaceMesh _mesh = null; + PolyFaceMesh _mesh = null; - using (Transaction tr = Doc.TransactionManager.StartTransaction()) - { - _mesh = new PolyFaceMesh(); - _mesh.SetDatabaseDefaults(); + using (Transaction tr = Doc.TransactionManager.StartTransaction()) + { + _mesh = new PolyFaceMesh(); + _mesh.SetDatabaseDefaults(); - // append mesh to blocktable record - necessary before adding vertices and faces - BlockTableRecord btr = (BlockTableRecord)tr.GetObject(Doc.Database.CurrentSpaceId, OpenMode.ForWrite); - btr.AppendEntity(_mesh); - tr.AddNewlyCreatedDBObject(_mesh, true); + // append mesh to blocktable record - necessary before adding vertices and faces + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(Doc.Database.CurrentSpaceId, OpenMode.ForWrite); + btr.AppendEntity(_mesh); + tr.AddNewlyCreatedDBObject(_mesh, true); - // add polyfacemesh vertices - for (int i = 0; i < vertices.Count; i++) + // add polyfacemesh vertices + for (int i = 0; i < vertices.Count; i++) + { + var vertex = new PolyFaceMeshVertex(points[i]); + if (mesh.colors.Count > 0) { - var vertex = new PolyFaceMeshVertex(points[i]); - if (mesh.colors.Count > 0) - { - try - { - Color color = Color.FromArgb(mesh.colors[i]); - vertex.Color = Autodesk.AutoCAD.Colors.Color.FromRgb(color.R, color.G, color.B); - } - catch { } - } - if (vertex.IsNewObject) + try { - _mesh.AppendVertex(vertex); - tr.AddNewlyCreatedDBObject(vertex, true); + Color color = Color.FromArgb(mesh.colors[i]); + vertex.Color = Autodesk.AutoCAD.Colors.Color.FromRgb(color.R, color.G, color.B); } + catch { } } - - // add polyfacemesh faces. vertex index starts at 1 sigh - int j = 0; - while (j < mesh.faces.Count) + if (vertex.IsNewObject) { - FaceRecord face; - if (mesh.faces[j] == 3) // triangle - { - face = new FaceRecord((short)(mesh.faces[j + 1] + 1), (short)(mesh.faces[j + 2] + 1), (short)(mesh.faces[j + 3] + 1), 0); - j += 4; - } - else // quad - { - face = new FaceRecord((short)(mesh.faces[j + 1] + 1), (short)(mesh.faces[j + 2] + 1), (short)(mesh.faces[j + 3] + 1), (short)(mesh.faces[j + 4] + 1)); - j += 5; - } + _mesh.AppendVertex(vertex); + tr.AddNewlyCreatedDBObject(vertex, true); + } + } - if (face.IsNewObject) - { - _mesh.AppendFaceRecord(face); - tr.AddNewlyCreatedDBObject(face, true); - } + // add polyfacemesh faces. vertex index starts at 1 sigh + int j = 0; + while (j < mesh.faces.Count) + { + FaceRecord face; + if (mesh.faces[j] == 3) // triangle + { + face = new FaceRecord( + (short)(mesh.faces[j + 1] + 1), + (short)(mesh.faces[j + 2] + 1), + (short)(mesh.faces[j + 3] + 1), + 0 + ); + j += 4; + } + else // quad + { + face = new FaceRecord( + (short)(mesh.faces[j + 1] + 1), + (short)(mesh.faces[j + 2] + 1), + (short)(mesh.faces[j + 3] + 1), + (short)(mesh.faces[j + 4] + 1) + ); + j += 5; } - tr.Commit(); + if (face.IsNewObject) + { + _mesh.AppendFaceRecord(face); + tr.AddNewlyCreatedDBObject(face, true); + } } - return _mesh; + tr.Commit(); } - // Based on Kean Walmsley's blog post on mesh conversion using Brep API - private Mesh GetMeshFromSolidOrSurface(out List notes, Solid3d solid = null, AcadDB.Surface surface = null, Region region = null) - { - Mesh mesh = null; - double volume = 0; - double area = 0; - notes = new List(); + return _mesh; + } - AcadBRep.Brep brep = null; - Box bbox = null; - if (solid != null) - { - brep = new AcadBRep.Brep(solid); - try - { - area = solid.Area; - volume = solid.MassProperties.Volume; - } - catch (Exception e) - { }; + // Based on Kean Walmsley's blog post on mesh conversion using Brep API + private Mesh GetMeshFromSolidOrSurface( + out List notes, + Solid3d solid = null, + AcadDB.Surface surface = null, + Region region = null + ) + { + Mesh mesh = null; + double volume = 0; + double area = 0; + notes = new List(); - bbox = BoxToSpeckle(solid.GeometricExtents); - } - else if (surface != null) - { - brep = new AcadBRep.Brep(surface); - area = surface.GetArea(); - bbox = BoxToSpeckle(surface.GeometricExtents); - } - else if (region != null) + AcadBRep.Brep brep = null; + Box bbox = null; + if (solid != null) + { + brep = new AcadBRep.Brep(solid); + try { - brep = new AcadBRep.Brep(region); - area = region.Area; - bbox = BoxToSpeckle(region.GeometricExtents); + area = solid.Area; + volume = solid.MassProperties.Volume; } + catch (Exception e) { } + ; + + bbox = BoxToSpeckle(solid.GeometricExtents); + } + else if (surface != null) + { + brep = new AcadBRep.Brep(surface); + area = surface.GetArea(); + bbox = BoxToSpeckle(surface.GeometricExtents); + } + else if (region != null) + { + brep = new AcadBRep.Brep(region); + area = region.Area; + bbox = BoxToSpeckle(region.GeometricExtents); + } - if (brep != null) + if (brep != null) + { + try { - try + using (var control = new AcadBRep.Mesh2dControl()) { - using (var control = new AcadBRep.Mesh2dControl()) - { - // These settings may need adjusting - control.MaxSubdivisions = 10000; + // These settings may need adjusting + control.MaxSubdivisions = 10000; - // output mesh vars - var _vertices = new List(); - var faces = new List(); + // output mesh vars + var _vertices = new List(); + var faces = new List(); - // create mesh filters - using (var filter = new AcadBRep.Mesh2dFilter()) + // create mesh filters + using (var filter = new AcadBRep.Mesh2dFilter()) + { + filter.Insert(brep, control); + using (var m = new AcadBRep.Mesh2d(filter)) { - filter.Insert(brep, control); - using (var m = new AcadBRep.Mesh2d(filter)) + foreach (var e in m.Element2ds) { - foreach (var e in m.Element2ds) + // get vertices + var faceIndices = new List(); + foreach (var n in e.Nodes) + { + faceIndices.Add(_vertices.Count); + _vertices.Add(n.Point); + n.Dispose(); + } + + // get faces + if (e.Nodes.Count() == 3) { - // get vertices - var faceIndices = new List(); - foreach (var n in e.Nodes) - { - faceIndices.Add(_vertices.Count); - _vertices.Add(n.Point); - n.Dispose(); - } - - // get faces - if (e.Nodes.Count() == 3) - faces.AddRange(new List { 3, faceIndices[0], faceIndices[1], faceIndices[2] }); - else if (e.Nodes.Count() == 4) - faces.AddRange(new List { 4, faceIndices[0], faceIndices[1], faceIndices[2], faceIndices[3] }); - e.Dispose(); + faces.AddRange(new List { 3, faceIndices[0], faceIndices[1], faceIndices[2] }); } + else if (e.Nodes.Count() == 4) + { + faces.AddRange(new List { 4, faceIndices[0], faceIndices[1], faceIndices[2], faceIndices[3] }); + } + + e.Dispose(); } } - brep.Dispose(); - - // create speckle mesh - var vertices = _vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); - mesh = new Mesh(vertices, faces); - mesh.units = ModelUnits; - mesh.bbox = bbox; - mesh.area = area; - mesh.volume = volume; } - } - catch (Exception e) - { - notes.Add(e.Message); + brep.Dispose(); + + // create speckle mesh + var vertices = _vertices.SelectMany(o => PointToSpeckle(o).ToList()).ToList(); + mesh = new Mesh(vertices, faces); + mesh.units = ModelUnits; + mesh.bbox = bbox; + mesh.area = area; + mesh.volume = volume; } } - - return mesh; + catch (Exception e) + { + notes.Add(e.Message); + } } + return mesh; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Other.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Other.cs index f63c6fffee..93969b9720 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Other.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Other.cs @@ -28,1441 +28,1557 @@ using Text = Objects.Other.Text; using Objects.BuiltElements.Revit; -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil { - public partial class ConverterAutocadCivil + // Layers + public Collection LayerToSpeckle(LayerTableRecord layer) { - // Layers - public Collection LayerToSpeckle(LayerTableRecord layer) - { - var collection = new Collection(layer.Name, "layer") { applicationId = layer.Id.ToString() }; - - // add dynamic autocad props - var style = new DisplayStyle() { units = Units.Millimeters }; - style.color = layer.Color.ColorValue.ToArgb(); - var linetype = (LinetypeTableRecord)Trans.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); - style.linetype = linetype.Name; - var lineWeight = - (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) - ? (int)LineWeight.LineWeight025 - : (int)layer.LineWeight; - style.lineweight = lineWeight / 100; // convert to mm - collection["displayStyle"] = style; - - collection["visible"] = !layer.IsHidden; + var collection = new Collection(layer.Name, "layer") { applicationId = layer.Id.ToString() }; + + // add dynamic autocad props + var style = new DisplayStyle() { units = Units.Millimeters }; + style.color = layer.Color.ColorValue.ToArgb(); + var linetype = (LinetypeTableRecord)Trans.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); + style.linetype = linetype.Name; + var lineWeight = + (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) + ? (int)LineWeight.LineWeight025 + : (int)layer.LineWeight; + style.lineweight = lineWeight / 100; // convert to mm + collection["displayStyle"] = style; + + collection["visible"] = !layer.IsHidden; + + return collection; + } - return collection; - } + public ApplicationObject CollectionToNative(Collection collection) + { + // get layer table + var layerTable = (LayerTable)Trans.GetObject(Doc.Database.LayerTableId, OpenMode.ForWrite); - public ApplicationObject CollectionToNative(Collection collection) + #region local functions + LayerTableRecord GetLayer(string path) { - // get layer table - var layerTable = (LayerTable)Trans.GetObject(Doc.Database.LayerTableId, OpenMode.ForWrite); - - #region local functions - LayerTableRecord GetLayer(string path) + if (layerTable.Has(path)) { - if (layerTable.Has(path)) - return (LayerTableRecord)Trans.GetObject(layerTable[path], OpenMode.ForWrite); - return null; - } - LayerTableRecord MakeLayer(string name) - { - try - { - var _layer = new LayerTableRecord(); - - // Assign the layer properties - _layer.Name = name; - - // Append the new layer to the layer table and the transaction - layerTable.Add(_layer); - Trans.AddNewlyCreatedDBObject(_layer, true); - - return _layer; - } - catch (Exception e) - { - return null; - } + return (LayerTableRecord)Trans.GetObject(layerTable[path], OpenMode.ForWrite); } - #endregion - var appObj = new ApplicationObject(collection.id, collection.speckle_type) + return null; + } + LayerTableRecord MakeLayer(string name) + { + try { - applicationId = collection.applicationId - }; - LayerTableRecord layer = null; - var status = ApplicationObject.State.Unknown; + var _layer = new LayerTableRecord(); - // see if this layer already exists in the doc - var layerPath = collection["path"] as string; - LayerTableRecord existingLayer = GetLayer(layerPath); + // Assign the layer properties + _layer.Name = name; - // update this layer if it exists & receive mode is on update - if (existingLayer != null && ReceiveMode == ReceiveMode.Update) - { - layer = existingLayer; - status = ApplicationObject.State.Updated; + // Append the new layer to the layer table and the transaction + layerTable.Add(_layer); + Trans.AddNewlyCreatedDBObject(_layer, true); + + return _layer; } - else // create this layer + catch (Exception e) { - layer = MakeLayer(layerPath); - status = ApplicationObject.State.Created; + return null; } + } + #endregion - if (layer == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create layer"); - return appObj; - } + var appObj = new ApplicationObject(collection.id, collection.speckle_type) + { + applicationId = collection.applicationId + }; + LayerTableRecord layer = null; + var status = ApplicationObject.State.Unknown; - // get attributes - var displayStyle = collection["displayStyle"] as DisplayStyle; - var renderMaterial = collection["renderMaterial"] as RenderMaterial; - Base styleBase = displayStyle != null ? displayStyle : renderMaterial; - DisplayStyleToNative( - styleBase, - out Color color, - out Transparency transparency, - out LineWeight lineWeight, - out ObjectId lineType - ); - layer.Color = color; - layer.Transparency = transparency; - layer.LineWeight = lineWeight; - layer.LinetypeObjectId = lineType; - - appObj.Update(status: status, convertedItem: layer, createdId: layer.Id.ToString()); - return appObj; + // see if this layer already exists in the doc + var layerPath = collection["path"] as string; + LayerTableRecord existingLayer = GetLayer(layerPath); + + // update this layer if it exists & receive mode is on update + if (existingLayer != null && ReceiveMode == ReceiveMode.Update) + { + layer = existingLayer; + status = ApplicationObject.State.Updated; + } + else // create this layer + { + layer = MakeLayer(layerPath); + status = ApplicationObject.State.Created; } - // Display Style - private static LineWeight GetLineWeight(double weight) + if (layer == null) { - double hundredthMM = weight * 100; - var weights = Enum.GetValues(typeof(LineWeight)).Cast().ToList(); - int closest = weights.Aggregate((x, y) => Math.Abs(x - hundredthMM) < Math.Abs(y - hundredthMM) ? x : y); - return (LineWeight)closest; + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create layer"); + return appObj; } - public void DisplayStyleToNative( - Base styleBase, + // get attributes + var displayStyle = collection["displayStyle"] as DisplayStyle; + var renderMaterial = collection["renderMaterial"] as RenderMaterial; + Base styleBase = displayStyle != null ? displayStyle : renderMaterial; + DisplayStyleToNative( + styleBase, out Color color, out Transparency transparency, out LineWeight lineWeight, out ObjectId lineType - ) + ); + layer.Color = color; + layer.Transparency = transparency; + layer.LineWeight = lineWeight; + layer.LinetypeObjectId = lineType; + + appObj.Update(status: status, convertedItem: layer, createdId: layer.Id.ToString()); + return appObj; + } + + // Display Style + private static LineWeight GetLineWeight(double weight) + { + double hundredthMM = weight * 100; + var weights = Enum.GetValues(typeof(LineWeight)).Cast().ToList(); + int closest = weights.Aggregate((x, y) => Math.Abs(x - hundredthMM) < Math.Abs(y - hundredthMM) ? x : y); + return (LineWeight)closest; + } + + public void DisplayStyleToNative( + Base styleBase, + out Color color, + out Transparency transparency, + out LineWeight lineWeight, + out ObjectId lineType + ) + { + var systemColor = new System.Drawing.Color(); + byte alpha = 255; + lineWeight = LineWeight.ByLineWeightDefault; + lineType = LineTypeDictionary.First().Value; + if (styleBase is DisplayStyle style) { - var systemColor = new System.Drawing.Color(); - byte alpha = 255; - lineWeight = LineWeight.ByLineWeightDefault; - lineType = LineTypeDictionary.First().Value; - if (styleBase is DisplayStyle style) - { - systemColor = System.Drawing.Color.FromArgb(style.color); - alpha = systemColor.A; + systemColor = System.Drawing.Color.FromArgb(style.color); + alpha = systemColor.A; - double conversionFactor = - (style.units != null) - ? Units.GetConversionFactor(Units.GetUnitsFromString(style.units), Units.Millimeters) - : 1; - lineWeight = GetLineWeight(style.lineweight * conversionFactor); + double conversionFactor = + (style.units != null) ? Units.GetConversionFactor(Units.GetUnitsFromString(style.units), Units.Millimeters) : 1; + lineWeight = GetLineWeight(style.lineweight * conversionFactor); - if (LineTypeDictionary.ContainsKey(style.linetype)) - lineType = LineTypeDictionary[style.linetype]; - } - else if (styleBase is RenderMaterial material) // this is the fallback value if a rendermaterial is passed instead + if (LineTypeDictionary.ContainsKey(style.linetype)) { - systemColor = System.Drawing.Color.FromArgb(material.diffuse); - alpha = (byte)(material.opacity * 255d); + lineType = LineTypeDictionary[style.linetype]; } - color = Color.FromRgb(systemColor.R, systemColor.G, systemColor.B); - transparency = new Transparency(alpha); } - - public DisplayStyle DisplayStyleToSpeckle(Entity entity) + else if (styleBase is RenderMaterial material) // this is the fallback value if a rendermaterial is passed instead { - if (entity is null) - return null; + systemColor = System.Drawing.Color.FromArgb(material.diffuse); + alpha = (byte)(material.opacity * 255d); + } + color = Color.FromRgb(systemColor.R, systemColor.G, systemColor.B); + transparency = new Transparency(alpha); + } - var style = new DisplayStyle(); + public DisplayStyle DisplayStyleToSpeckle(Entity entity) + { + if (entity is null) + { + return null; + } - // get color - int color = System.Drawing.Color.Black.ToArgb(); - switch (entity.Color.ColorMethod) - { - case ColorMethod.ByLayer: - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - { - if (entity.LayerId.IsValid) - { - var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - color = layer.Color.ColorValue.ToArgb(); - } - tr.Commit(); - } - break; - case ColorMethod.ByBlock: - case ColorMethod.ByAci: - case ColorMethod.ByColor: - color = entity.Color.ColorValue.ToArgb(); - break; - } - style.color = color; + var style = new DisplayStyle(); - // get linetype - style.linetype = entity.Linetype; - if (entity.Linetype.ToUpper() == "BYLAYER") - { + // get color + int color = System.Drawing.Color.Black.ToArgb(); + switch (entity.Color.ColorMethod) + { + case ColorMethod.ByLayer: using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { if (entity.LayerId.IsValid) { var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - var linetype = (LinetypeTableRecord)tr.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); - style.linetype = linetype.Name; + color = layer.Color.ColorValue.ToArgb(); } tr.Commit(); } - } + break; + case ColorMethod.ByBlock: + case ColorMethod.ByAci: + case ColorMethod.ByColor: + color = entity.Color.ColorValue.ToArgb(); + break; + } + style.color = color; - // get lineweight - // system variable default is: LWDEFAULT - double lineWeight = 0.25; - switch (entity.LineWeight) + // get linetype + style.linetype = entity.Linetype; + if (entity.Linetype.ToUpper() == "BYLAYER") + { + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) { - case LineWeight.ByLayer: - using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + if (entity.LayerId.IsValid) + { + var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; + var linetype = (LinetypeTableRecord)tr.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); + style.linetype = linetype.Name; + } + tr.Commit(); + } + } + + // get lineweight + // system variable default is: LWDEFAULT + double lineWeight = 0.25; + switch (entity.LineWeight) + { + case LineWeight.ByLayer: + using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + { + if (entity.LayerId.IsValid) { - if (entity.LayerId.IsValid) + var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; + if (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) + { + lineWeight = (int)LineWeight.LineWeight025; + } + else { - var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - if (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) - lineWeight = (int)LineWeight.LineWeight025; - else - lineWeight = (int)layer.LineWeight; + lineWeight = (int)layer.LineWeight; } - tr.Commit(); } - break; - case LineWeight.ByBlock: - case LineWeight.ByLineWeightDefault: - case LineWeight.ByDIPs: - lineWeight = (int)LineWeight.LineWeight025; - break; - default: - lineWeight = (int)entity.LineWeight; - break; - } - style.lineweight = lineWeight / 100; // convert to mm + tr.Commit(); + } + break; + case LineWeight.ByBlock: + case LineWeight.ByLineWeightDefault: + case LineWeight.ByDIPs: + lineWeight = (int)LineWeight.LineWeight025; + break; + default: + lineWeight = (int)entity.LineWeight; + break; + } + style.lineweight = lineWeight / 100; // convert to mm - style.units = Units.Millimeters; + style.units = Units.Millimeters; + + return style; + } - return style; + // Hatches + private HatchLoopType HatchLoopTypeToSpeckle(HatchLoopTypes type) + { + if (type.HasFlag(HatchLoopTypes.Outermost) || type.HasFlag(HatchLoopTypes.External)) + { + return HatchLoopType.Outer; } - // Hatches - private HatchLoopType HatchLoopTypeToSpeckle(HatchLoopTypes type) + if (type.HasFlag(HatchLoopTypes.Default)) { - if (type.HasFlag(HatchLoopTypes.Outermost) || type.HasFlag(HatchLoopTypes.External)) - return HatchLoopType.Outer; - if (type.HasFlag(HatchLoopTypes.Default)) - return HatchLoopType.Unknown; return HatchLoopType.Unknown; } - private HatchLoopTypes HatchLoopTypeToNative(HatchLoopType type) + return HatchLoopType.Unknown; + } + + private HatchLoopTypes HatchLoopTypeToNative(HatchLoopType type) + { + switch (type) { - switch (type) - { - case HatchLoopType.Outer: - return HatchLoopTypes.External; - default: - return HatchLoopTypes.Default; - } + case HatchLoopType.Outer: + return HatchLoopTypes.External; + default: + return HatchLoopTypes.Default; } + } - public Hatch HatchToSpeckle(AcadDB.Hatch hatch) + public Hatch HatchToSpeckle(AcadDB.Hatch hatch) + { + var _hatch = new Hatch(); + _hatch.pattern = hatch.PatternName; + _hatch.scale = hatch.PatternScale; + _hatch.rotation = hatch.PatternAngle; + + // handle curves + var curves = new List(); + for (int i = 0; i < hatch.NumberOfLoops; i++) { - var _hatch = new Hatch(); - _hatch.pattern = hatch.PatternName; - _hatch.scale = hatch.PatternScale; - _hatch.rotation = hatch.PatternAngle; - - // handle curves - var curves = new List(); - for (int i = 0; i < hatch.NumberOfLoops; i++) + var loop = hatch.GetLoopAt(i); + if (loop.IsPolyline) + { + var poly = GetPolylineFromBulgeVertexCollection(loop.Polyline); + var convertedPoly = poly.IsOnlyLines ? PolylineToSpeckle(poly) : PolycurveToSpeckle(poly); + var speckleLoop = new HatchLoop(convertedPoly, HatchLoopTypeToSpeckle(loop.LoopType)); + curves.Add(speckleLoop); + } + else { - var loop = hatch.GetLoopAt(i); - if (loop.IsPolyline) + for (int j = 0; j < loop.Curves.Count; j++) { - var poly = GetPolylineFromBulgeVertexCollection(loop.Polyline); - var convertedPoly = poly.IsOnlyLines ? PolylineToSpeckle(poly) : PolycurveToSpeckle(poly); - var speckleLoop = new HatchLoop(convertedPoly, HatchLoopTypeToSpeckle(loop.LoopType)); + var convertedCurve = CurveToSpeckle(loop.Curves[j]); + var speckleLoop = new HatchLoop(convertedCurve, HatchLoopTypeToSpeckle(loop.LoopType)); curves.Add(speckleLoop); } - else - { - for (int j = 0; j < loop.Curves.Count; j++) - { - var convertedCurve = CurveToSpeckle(loop.Curves[j]); - var speckleLoop = new HatchLoop(convertedCurve, HatchLoopTypeToSpeckle(loop.LoopType)); - curves.Add(speckleLoop); - } - } } - _hatch.loops = curves; - _hatch["style"] = hatch.HatchStyle.ToString(); - - return _hatch; } + _hatch.loops = curves; + _hatch["style"] = hatch.HatchStyle.ToString(); - // TODO: this needs to be improved, hatch curves not being created with HatchLoopTypes.Polyline flag - public ApplicationObject HatchToNativeDB(Hatch hatch) - { - var appObj = new ApplicationObject(hatch.id, hatch.speckle_type) { applicationId = hatch.applicationId }; + return _hatch; + } + + // TODO: this needs to be improved, hatch curves not being created with HatchLoopTypes.Polyline flag + public ApplicationObject HatchToNativeDB(Hatch hatch) + { + var appObj = new ApplicationObject(hatch.id, hatch.speckle_type) { applicationId = hatch.applicationId }; - BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); + BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); - // convert curves - var loops = new Dictionary(); - if (hatch.loops != null) + // convert curves + var loops = new Dictionary(); + if (hatch.loops != null) + { + foreach (var loop in hatch.loops) { - foreach (var loop in hatch.loops) + var converted = CurveToNativeDB(loop.Curve); + if (converted == null || converted.Count == 0) + { + appObj.Log.Add($"Could not create {loop.Type} loop {loop.id}"); + continue; + } + foreach (var convertedItem in converted) { - var converted = CurveToNativeDB(loop.Curve); - if (converted == null || converted.Count == 0) + var curveId = modelSpaceRecord.Append(convertedItem); + if (curveId.IsValid) { - appObj.Log.Add($"Could not create {loop.Type} loop {loop.id}"); - continue; + HatchLoopTypes type = HatchLoopTypeToNative(loop.Type); + loops.Add(convertedItem, type); } - foreach (var convertedItem in converted) + else { - var curveId = modelSpaceRecord.Append(convertedItem); - if (curveId.IsValid) - { - HatchLoopTypes type = HatchLoopTypeToNative(loop.Type); - loops.Add(convertedItem, type); - } - else - { - appObj.Log.Add($"Could not add {loop.Type} loop {loop.id} to model space"); - } + appObj.Log.Add($"Could not add {loop.Type} loop {loop.id} to model space"); } } } - if (loops.Count == 0) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "No loops were successfully created"); - return appObj; - } + } + if (loops.Count == 0) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "No loops were successfully created"); + return appObj; + } - // add hatch to modelspace - var _hatch = new AcadDB.Hatch(); - modelSpaceRecord.Append(_hatch); + // add hatch to modelspace + var _hatch = new AcadDB.Hatch(); + modelSpaceRecord.Append(_hatch); - _hatch.SetDatabaseDefaults(); + _hatch.SetDatabaseDefaults(); - // try get hatch pattern - var patternCategory = HatchPatterns.ValidPatternName(hatch.pattern); - switch (patternCategory) - { - case PatPatternCategory.kCustomdef: - _hatch.SetHatchPattern(HatchPatternType.CustomDefined, hatch.pattern); - break; - case PatPatternCategory.kPredef: - case PatPatternCategory.kISOdef: - _hatch.SetHatchPattern(HatchPatternType.PreDefined, hatch.pattern); - break; - case PatPatternCategory.kUserdef: - _hatch.SetHatchPattern(HatchPatternType.UserDefined, hatch.pattern); - break; - default: - _hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID"); - break; - } - _hatch.PatternAngle = hatch.rotation; - _hatch.PatternScale = hatch.scale; + // try get hatch pattern + var patternCategory = HatchPatterns.ValidPatternName(hatch.pattern); + switch (patternCategory) + { + case PatPatternCategory.kCustomdef: + _hatch.SetHatchPattern(HatchPatternType.CustomDefined, hatch.pattern); + break; + case PatPatternCategory.kPredef: + case PatPatternCategory.kISOdef: + _hatch.SetHatchPattern(HatchPatternType.PreDefined, hatch.pattern); + break; + case PatPatternCategory.kUserdef: + _hatch.SetHatchPattern(HatchPatternType.UserDefined, hatch.pattern); + break; + default: + _hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID"); + break; + } + _hatch.PatternAngle = hatch.rotation; + _hatch.PatternScale = hatch.scale; - var style = hatch["style"] as string; - if (style != null) - _hatch.HatchStyle = Enum.TryParse(style, out HatchStyle hatchStyle) ? hatchStyle : HatchStyle.Normal; + var style = hatch["style"] as string; + if (style != null) + { + _hatch.HatchStyle = Enum.TryParse(style, out HatchStyle hatchStyle) ? hatchStyle : HatchStyle.Normal; + } - // create loops - foreach (var entry in loops) + // create loops + foreach (var entry in loops) + { + var loopHandle = entry.Key.Handle.ToString(); + try { - var loopHandle = entry.Key.Handle.ToString(); + _hatch.AppendLoop(entry.Value, new ObjectIdCollection() { entry.Key.ObjectId }); + _hatch.EvaluateHatch(true); try { - _hatch.AppendLoop(entry.Value, new ObjectIdCollection() { entry.Key.ObjectId }); - _hatch.EvaluateHatch(true); - try - { - entry.Key.Erase(); // delete created hatch loop curve - } - catch (Exception e) - { - appObj.Update( - createdId: loopHandle, - convertedItem: entry.Key, - logItem: $"Could not delete loop {loopHandle}: {e.Message}" - ); - } + entry.Key.Erase(); // delete created hatch loop curve } catch (Exception e) { appObj.Update( createdId: loopHandle, convertedItem: entry.Key, - logItem: $"Could not append loop {loopHandle}: {e.Message}" + logItem: $"Could not delete loop {loopHandle}: {e.Message}" ); } } + catch (Exception e) + { + appObj.Update( + createdId: loopHandle, + convertedItem: entry.Key, + logItem: $"Could not append loop {loopHandle}: {e.Message}" + ); + } + } - return appObj; + return appObj; + } + + private AcadDB.Polyline GetPolylineFromBulgeVertexCollection(BulgeVertexCollection bulges) + { + var polyline = new AcadDB.Polyline(bulges.Count); + double totalBulge = 0; + for (int i = 0; i < bulges.Count; i++) + { + BulgeVertex bulgeVertex = bulges[i]; + polyline.AddVertexAt(i, bulgeVertex.Vertex, bulgeVertex.Bulge, 1.0, 1.0); + totalBulge += bulgeVertex.Bulge; } + polyline.Closed = bulges[0].Vertex.IsEqualTo(bulges[bulges.Count - 1].Vertex) ? true : false; + return polyline; + } + + // Blocks + public BlockInstance BlockReferenceToSpeckle(BlockReference reference) + { + // get record + BlockDefinition definition = null; + var attributes = new Dictionary(); - private AcadDB.Polyline GetPolylineFromBulgeVertexCollection(BulgeVertexCollection bulges) + var btrObjId = reference.BlockTableRecord; + if (reference.IsDynamicBlock) { - var polyline = new AcadDB.Polyline(bulges.Count); - double totalBulge = 0; - for (int i = 0; i < bulges.Count; i++) - { - BulgeVertex bulgeVertex = bulges[i]; - polyline.AddVertexAt(i, bulgeVertex.Vertex, bulgeVertex.Bulge, 1.0, 1.0); - totalBulge += bulgeVertex.Bulge; - } - polyline.Closed = bulges[0].Vertex.IsEqualTo(bulges[bulges.Count - 1].Vertex) ? true : false; - return polyline; + btrObjId = + reference.AnonymousBlockTableRecord != ObjectId.Null + ? reference.AnonymousBlockTableRecord + : reference.DynamicBlockTableRecord; } - // Blocks - public BlockInstance BlockReferenceToSpeckle(BlockReference reference) + var btr = (BlockTableRecord)Trans.GetObject(btrObjId, OpenMode.ForRead); + definition = BlockRecordToSpeckle(btr); + foreach (ObjectId id in reference.AttributeCollection) { - // get record - BlockDefinition definition = null; - var attributes = new Dictionary(); + AttributeReference attRef = (AttributeReference)Trans.GetObject(id, OpenMode.ForRead); + attributes.Add(attRef.Tag, attRef.TextString); + } - var btrObjId = reference.BlockTableRecord; - if (reference.IsDynamicBlock) - btrObjId = - reference.AnonymousBlockTableRecord != ObjectId.Null - ? reference.AnonymousBlockTableRecord - : reference.DynamicBlockTableRecord; + if (definition == null) + { + return null; + } - var btr = (BlockTableRecord)Trans.GetObject(btrObjId, OpenMode.ForRead); - definition = BlockRecordToSpeckle(btr); - foreach (ObjectId id in reference.AttributeCollection) - { - AttributeReference attRef = (AttributeReference)Trans.GetObject(id, OpenMode.ForRead); - attributes.Add(attRef.Tag, attRef.TextString); - } + var instance = new BlockInstance() + { + transform = new Transform(reference.BlockTransform.ToArray(), ModelUnits), + typedDefinition = definition, + units = ModelUnits + }; - if (definition == null) - return null; + // add attributes + if (attributes.Any()) + { + instance["attributes"] = attributes; + } - var instance = new BlockInstance() - { - transform = new Transform(reference.BlockTransform.ToArray(), ModelUnits), - typedDefinition = definition, - units = ModelUnits - }; + return instance; + } - // add attributes - if (attributes.Any()) - instance["attributes"] = attributes; + public ApplicationObject InstanceToNativeDB(Instance instance, bool AppendToModelSpace = true) + { + var appObj = new ApplicationObject(instance.id, instance.speckle_type) { applicationId = instance.applicationId }; - return instance; + // get the definition + var definition = instance.definition ?? instance["@definition"] as Base ?? instance["@blockDefinition"] as Base; // some applications need to dynamically attach defs (eg sketchup) + if (definition == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "instance did not have a definition"); + return appObj; } - public ApplicationObject InstanceToNativeDB(Instance instance, bool AppendToModelSpace = true) + // delete existing objs if any and this is an update + if (ReceiveMode == ReceiveMode.Update) { - var appObj = new ApplicationObject(instance.id, instance.speckle_type) { applicationId = instance.applicationId }; - - // get the definition - var definition = instance.definition ?? instance["@definition"] as Base ?? instance["@blockDefinition"] as Base; // some applications need to dynamically attach defs (eg sketchup) - if (definition == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "instance did not have a definition"); - return appObj; - } - - // delete existing objs if any and this is an update - if (ReceiveMode == ReceiveMode.Update) + var existingObjs = GetExistingElementsByApplicationId(instance.applicationId); + try { - var existingObjs = GetExistingElementsByApplicationId(instance.applicationId); - try + foreach (var existingObjId in existingObjs) { - foreach (var existingObjId in existingObjs) - { - var existingObj = Trans.GetObject(existingObjId, OpenMode.ForWrite); - existingObj.Erase(); - } + var existingObj = Trans.GetObject(existingObjId, OpenMode.ForWrite); + existingObj.Erase(); } - catch (Exception e) + } + catch (Exception e) + { + if (!e.Message.Contains("eWasErased")) // this couldve been previously deleted & received? { - if (!e.Message.Contains("eWasErased")) // this couldve been previously deleted & received? - appObj.Update(logItem: $"Could not remove one or more existing instances on update: {e.Message}"); + appObj.Update(logItem: $"Could not remove one or more existing instances on update: {e.Message}"); } } + } - // convert the definition - ObjectId definitionId = DefinitionToNativeDB(definition, out List notes); - if (notes.Count > 0) - appObj.Update(log: notes); - if (definitionId == ObjectId.Null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create block definition"); - return appObj; - } + // convert the definition + ObjectId definitionId = DefinitionToNativeDB(definition, out List notes); + if (notes.Count > 0) + { + appObj.Update(log: notes); + } - // transform - Matrix3d convertedTransform = TransformToNativeMatrix(instance.transform); + if (definitionId == ObjectId.Null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create block definition"); + return appObj; + } - // add block reference - BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); - var insertionPoint = Point3d.Origin.TransformBy(convertedTransform); - BlockReference br = new BlockReference(insertionPoint, definitionId); - br.BlockTransform = convertedTransform; + // transform + Matrix3d convertedTransform = TransformToNativeMatrix(instance.transform); - // add attributes if there are any - var attributes = instance["attributes"] as Dictionary; - if (attributes != null) - { - // TODO: figure out how to add attributes - } - ObjectId id = ObjectId.Null; - if (AppendToModelSpace) - id = modelSpaceRecord.Append(br); + // add block reference + BlockTableRecord modelSpaceRecord = Doc.Database.GetModelSpace(); + var insertionPoint = Point3d.Origin.TransformBy(convertedTransform); + BlockReference br = new(insertionPoint, definitionId); + br.BlockTransform = convertedTransform; - if ((!id.IsValid || id.IsNull) && AppendToModelSpace) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Couldn't append instance to model space"); - return appObj; - } + // add attributes if there are any + var attributes = instance["attributes"] as Dictionary; + if (attributes != null) + { + // TODO: figure out how to add attributes + } + ObjectId id = ObjectId.Null; + if (AppendToModelSpace) + { + id = modelSpaceRecord.Append(br); + } - // update appobj - var status = - ReceiveMode == ReceiveMode.Update ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: status, convertedItem: br); - if (AppendToModelSpace) - appObj.CreatedIds.Add(id.Handle.ToString()); + if ((!id.IsValid || id.IsNull) && AppendToModelSpace) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Couldn't append instance to model space"); return appObj; } - public BlockDefinition BlockRecordToSpeckle(BlockTableRecord record) + // update appobj + var status = ReceiveMode == ReceiveMode.Update ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: status, convertedItem: br); + if (AppendToModelSpace) { - // get geometry - var geometry = new List(); - foreach (ObjectId id in record) - { - DBObject obj = Trans.GetObject(id, OpenMode.ForRead); - Entity objEntity = obj as Entity; - if (CanConvertToSpeckle(obj) && (objEntity != null && objEntity.Visible)) - { - Base converted = ConvertToSpeckle(obj); - if (converted != null) - { - converted["layer"] = objEntity.Layer; - geometry.Add(converted); - } - } - } + appObj.CreatedIds.Add(id.Handle.ToString()); + } - var definition = new BlockDefinition() - { - name = GetBlockDefName(record), - basePoint = PointToSpeckle(record.Origin), - geometry = geometry, - units = ModelUnits - }; - - return definition; - } - - public ObjectId DefinitionToNativeDB(Base definition, out List notes) - { - notes = new List(); - - // get the definition name - var commitInfo = RemoveInvalidAutocadChars(Doc.UserData["commit"] as string); - string definitionName = definition is BlockDefinition blockDef - ? RemoveInvalidAutocadChars(blockDef.name) - : definition is RevitSymbolElementType revitDef - ? RemoveInvalidAutocadChars($"{revitDef.family} - {revitDef.type} - {definition.id}") - : definition.id; - if (ReceiveMode == ReceiveMode.Create) - definitionName = $"{commitInfo} - " + definitionName; - BlockTable blckTbl = Trans.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; - if (blckTbl.Has(definitionName)) - return blckTbl[definitionName]; - - // get definition geometry to traverse and base point - Point3d basePoint = Point3d.Origin; - var toTraverse = new List(); - switch (definition) - { - case BlockDefinition o: - if (o.basePoint != null) - basePoint = PointToNative(o.basePoint); - toTraverse = o.geometry ?? (o["@geometry"] as List).Cast().ToList(); - break; - default: - toTraverse.Add(definition); - break; - } + return appObj; + } - // traverse definition geo to get convertible geo - var conversionDict = new Dictionary(); - foreach (var obj in toTraverse) + public BlockDefinition BlockRecordToSpeckle(BlockTableRecord record) + { + // get geometry + var geometry = new List(); + foreach (ObjectId id in record) + { + DBObject obj = Trans.GetObject(id, OpenMode.ForRead); + Entity objEntity = obj as Entity; + if (CanConvertToSpeckle(obj) && (objEntity != null && objEntity.Visible)) { - var convertible = FlattenDefinitionObject(obj); - foreach (var key in convertible.Keys) + Base converted = ConvertToSpeckle(obj); + if (converted != null) { - if (!conversionDict.ContainsKey(key)) - { - conversionDict.Add(key, convertible[key]); - } + converted["layer"] = objEntity.Layer; + geometry.Add(converted); } } + } - // convert definition geometry and attributes - var bakedGeometry = new ObjectIdCollection(); // this is to contain block def geometry that is already added to doc space during conversion + var definition = new BlockDefinition() + { + name = GetBlockDefName(record), + basePoint = PointToSpeckle(record.Origin), + geometry = geometry, + units = ModelUnits + }; - var converted = new List(); - foreach (var item in conversionDict) - { - var geo = item.Key; - var convertedGeo = new List(); - DisplayStyle style = geo["displayStyle"] as DisplayStyle; - RenderMaterial material = geo["renderMaterial"] as RenderMaterial; + return definition; + } - switch (geo) - { - case Instance o: - var instanceNotes = new List(); - var instanceAppObj = InstanceToNativeDB(o, false); - var instance = instanceAppObj.Converted.FirstOrDefault() as BlockReference; - if (instance != null) - { - convertedGeo.Add(instance); - } - else - { - notes.AddRange(instanceNotes); - notes.Add($"Could not create nested Instance of definition {definitionName}"); - } - break; - default: - ConvertWithDisplay(geo, style, material, ref convertedGeo); - break; - } - if (convertedGeo.Count == 0) - { - notes.Add($"Could not create definition geometry {geo.speckle_type} ({geo.id})"); - continue; - } + public ObjectId DefinitionToNativeDB(Base definition, out List notes) + { + notes = new List(); + + // get the definition name + var commitInfo = RemoveInvalidAutocadChars(Doc.UserData["commit"] as string); + string definitionName = definition is BlockDefinition blockDef + ? RemoveInvalidAutocadChars(blockDef.name) + : definition is RevitSymbolElementType revitDef + ? RemoveInvalidAutocadChars($"{revitDef.family} - {revitDef.type} - {definition.id}") + : definition.id; + if (ReceiveMode == ReceiveMode.Create) + { + definitionName = $"{commitInfo} - " + definitionName; + } + + BlockTable blckTbl = Trans.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead) as BlockTable; + if (blckTbl.Has(definitionName)) + { + return blckTbl[definitionName]; + } - foreach (var convertedItem in convertedGeo) + // get definition geometry to traverse and base point + Point3d basePoint = Point3d.Origin; + var toTraverse = new List(); + switch (definition) + { + case BlockDefinition o: + if (o.basePoint != null) { - if (!convertedItem.IsNewObject && !(convertedItem is BlockReference)) - bakedGeometry.Add(convertedItem.Id); - else - converted.Add(convertedItem); + basePoint = PointToNative(o.basePoint); } - } - if (converted.Count == 0 && bakedGeometry.Count == 0) - { - notes.Add("Could not convert any definition geometry"); - return ObjectId.Null; - } + toTraverse = o.geometry ?? (o["@geometry"] as List).Cast().ToList(); + break; + default: + toTraverse.Add(definition); + break; + } - // create btr - ObjectId blockId = ObjectId.Null; - using (BlockTableRecord btr = new BlockTableRecord()) + // traverse definition geo to get convertible geo + var conversionDict = new Dictionary(); + foreach (var obj in toTraverse) + { + var convertible = FlattenDefinitionObject(obj); + foreach (var key in convertible.Keys) { - btr.Name = definitionName; - btr.Origin = basePoint; - - // add geometry - blckTbl.UpgradeOpen(); - foreach (var convertedItem in converted) + if (!conversionDict.ContainsKey(key)) { - btr.AppendEntity(convertedItem); + conversionDict.Add(key, convertible[key]); } - blockId = blckTbl.Add(btr); - btr.AssumeOwnershipOf(bakedGeometry); // add in baked geo - Trans.AddNewlyCreatedDBObject(btr, true); - blckTbl.Dispose(); } - - return blockId; } - #region block def flattening - /// - /// Traverses the object graph, returning objects that can be converted. - /// - /// The root object to traverse - /// A flattened list of objects to be converted ToNative - private Dictionary FlattenDefinitionObject(Base obj) + // convert definition geometry and attributes + var bakedGeometry = new ObjectIdCollection(); // this is to contain block def geometry that is already added to doc space during conversion + + var converted = new List(); + foreach (var item in conversionDict) { - var StoredObjects = new Dictionary(); + var geo = item.Key; + var convertedGeo = new List(); + DisplayStyle style = geo["displayStyle"] as DisplayStyle; + RenderMaterial material = geo["renderMaterial"] as RenderMaterial; - void StoreObject(Base current, string containerId) + switch (geo) { - //Handle convertable objects - if (CanConvertToNative(current)) - { - StoredObjects.Add(current, containerId); - return; - } - - //Handle objects convertable using displayValues - var fallbackMember = current["displayValue"] ?? current["@displayValue"]; - if (fallbackMember != null) - { - GraphTraversal.TraverseMember(fallbackMember).ToList().ForEach(o => StoreObject(o, containerId)); - return; - } + case Instance o: + var instanceNotes = new List(); + var instanceAppObj = InstanceToNativeDB(o, false); + var instance = instanceAppObj.Converted.FirstOrDefault() as BlockReference; + if (instance != null) + { + convertedGeo.Add(instance); + } + else + { + notes.AddRange(instanceNotes); + notes.Add($"Could not create nested Instance of definition {definitionName}"); + } + break; + default: + ConvertWithDisplay(geo, style, material, ref convertedGeo); + break; } - - string LayerId(TraversalContext context) => LayerIdRecurse(context, new StringBuilder()).ToString(); - StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) + if (convertedGeo.Count == 0) { - if (context.propName == null) - return stringBuilder; - - // see if there's a layer property on this obj - var layer = context.current["layer"] as string ?? context.current["Layer"] as string; - if (!string.IsNullOrEmpty(layer)) - return new StringBuilder(layer); - - var objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; - - LayerIdRecurse(context.parent, stringBuilder); - stringBuilder.Append("$"); - stringBuilder.Append(objectLayerName); - - return stringBuilder; + notes.Add($"Could not create definition geometry {geo.speckle_type} ({geo.id})"); + continue; } - var traverseFunction = DefaultTraversal.CreateTraverseFunc(this); - - traverseFunction.Traverse(obj).ToList().ForEach(tc => StoreObject(tc.current, LayerId(tc))); + foreach (var convertedItem in convertedGeo) + { + if (!convertedItem.IsNewObject && !(convertedItem is BlockReference)) + { + bakedGeometry.Add(convertedItem.Id); + } + else + { + converted.Add(convertedItem); + } + } + } - return StoredObjects; + if (converted.Count == 0 && bakedGeometry.Count == 0) + { + notes.Add("Could not convert any definition geometry"); + return ObjectId.Null; } - #endregion - /// - /// Get the name of the block definition from BlockTableRecord. - /// If btr is a Dynamic Block, name is formatted as "DynamicBlockName"_"VisibilityName" - /// - /// BlockTableRecord object - /// block table record name - private string GetBlockDefName(BlockTableRecord btr) + // create btr + ObjectId blockId = ObjectId.Null; + using (BlockTableRecord btr = new()) { - var fullName = btr.Name; - var curVisibilityName = string.Empty; + btr.Name = definitionName; + btr.Origin = basePoint; - if (btr.IsAnonymous || btr.IsDynamicBlock) + // add geometry + blckTbl.UpgradeOpen(); + foreach (var convertedItem in converted) { - var referenceIds = btr.GetBlockReferenceIds(true, false); - ObjectId referenceId = referenceIds.Count > 0 ? referenceIds[0] : ObjectId.Null; - BlockReference reference = - referenceId != ObjectId.Null ? Trans.GetObject(referenceId, OpenMode.ForRead) as BlockReference : null; - if (reference == null) - return fullName; - - if (btr.IsAnonymous) - { - BlockTableRecord dynamicBlock = - reference.DynamicBlockTableRecord != ObjectId.Null - ? Trans.GetObject(reference.DynamicBlockTableRecord, OpenMode.ForRead) as BlockTableRecord - : null; - if (dynamicBlock != null) - fullName = dynamicBlock.Name; - } + btr.AppendEntity(convertedItem); + } + blockId = blckTbl.Add(btr); + btr.AssumeOwnershipOf(bakedGeometry); // add in baked geo + Trans.AddNewlyCreatedDBObject(btr, true); + blckTbl.Dispose(); + } - var descriptiveProps = new List(); - foreach (DynamicBlockReferenceProperty prop in reference.DynamicBlockReferencePropertyCollection) - if (prop.VisibleInCurrentVisibilityState && !prop.ReadOnly && IsSimpleType(prop.Value, out string value)) - descriptiveProps.Add(value); + return blockId; + } - if (descriptiveProps.Count > 0) - fullName = $"{fullName}_{String.Join("_", descriptiveProps.ToArray())}"; + #region block def flattening + /// + /// Traverses the object graph, returning objects that can be converted. + /// + /// The root object to traverse + /// A flattened list of objects to be converted ToNative + private Dictionary FlattenDefinitionObject(Base obj) + { + var StoredObjects = new Dictionary(); + + void StoreObject(Base current, string containerId) + { + //Handle convertable objects + if (CanConvertToNative(current)) + { + StoredObjects.Add(current, containerId); + return; } - return fullName; + //Handle objects convertable using displayValues + var fallbackMember = current["displayValue"] ?? current["@displayValue"]; + if (fallbackMember != null) + { + GraphTraversal.TraverseMember(fallbackMember).ToList().ForEach(o => StoreObject(o, containerId)); + return; + } } - private bool IsSimpleType(object value, out string stringValue) + string LayerId(TraversalContext context) => LayerIdRecurse(context, new StringBuilder()).ToString(); + StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) { - stringValue = String.Empty; - var type = value.GetType(); - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + if (context.propName == null) { - // nullable type, check if the nested type is simple. - return IsSimpleType(type.GetGenericArguments()[0], out stringValue); + return stringBuilder; } - if (type.IsPrimitive || type.IsEnum || type.Equals(typeof(string)) || type.Equals(typeof(decimal))) + + // see if there's a layer property on this obj + var layer = context.current["layer"] as string ?? context.current["Layer"] as string; + if (!string.IsNullOrEmpty(layer)) { - stringValue = value.ToString(); - return true; + return new StringBuilder(layer); } - return false; + + var objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; + + LayerIdRecurse(context.parent, stringBuilder); + stringBuilder.Append("$"); + stringBuilder.Append(objectLayerName); + + return stringBuilder; } - private void ConvertWithDisplay( - Base obj, - DisplayStyle style, - RenderMaterial material, - ref List converted, - bool TryUseObjDisplay = false - ) - { - if (TryUseObjDisplay && obj["displayStyle"] as DisplayStyle != null) - style = obj["displayStyle"] as DisplayStyle; - if (TryUseObjDisplay && obj["renderMaterial"] as RenderMaterial != null) - material = obj["renderMaterial"] as RenderMaterial; + var traverseFunction = DefaultTraversal.CreateTraverseFunc(this); - var convertedList = new List(); - var convertedGeo = ConvertToNative(obj); - if (convertedGeo == null) - return; + traverseFunction.Traverse(obj).ToList().ForEach(tc => StoreObject(tc.current, LayerId(tc))); - //Iteratively flatten any lists - void FlattenConvertedObject(object item) + return StoredObjects; + } + #endregion + + /// + /// Get the name of the block definition from BlockTableRecord. + /// If btr is a Dynamic Block, name is formatted as "DynamicBlockName"_"VisibilityName" + /// + /// BlockTableRecord object + /// block table record name + private string GetBlockDefName(BlockTableRecord btr) + { + var fullName = btr.Name; + var curVisibilityName = string.Empty; + + if (btr.IsAnonymous || btr.IsDynamicBlock) + { + var referenceIds = btr.GetBlockReferenceIds(true, false); + ObjectId referenceId = referenceIds.Count > 0 ? referenceIds[0] : ObjectId.Null; + BlockReference reference = + referenceId != ObjectId.Null ? Trans.GetObject(referenceId, OpenMode.ForRead) as BlockReference : null; + if (reference == null) { - if (item is System.Collections.IList list) - foreach (object child in list) - FlattenConvertedObject(child); - else - convertedList.Add(item); + return fullName; } - FlattenConvertedObject(convertedGeo); - foreach (Entity entity in convertedList) + if (btr.IsAnonymous) { - if (entity != null) + BlockTableRecord dynamicBlock = + reference.DynamicBlockTableRecord != ObjectId.Null + ? Trans.GetObject(reference.DynamicBlockTableRecord, OpenMode.ForRead) as BlockTableRecord + : null; + if (dynamicBlock != null) { - // get display attributes - Base styleBase = style != null ? style : material; - DisplayStyleToNative( - styleBase, - out Color color, - out Transparency transparency, - out LineWeight lineWeight, - out ObjectId lineType - ); - entity.Color = color; - entity.Transparency = transparency; - entity.LineWeight = lineWeight; - entity.LinetypeId = lineType; + fullName = dynamicBlock.Name; + } + } - converted.Add(entity); + var descriptiveProps = new List(); + foreach (DynamicBlockReferenceProperty prop in reference.DynamicBlockReferencePropertyCollection) + { + if (prop.VisibleInCurrentVisibilityState && !prop.ReadOnly && IsSimpleType(prop.Value, out string value)) + { + descriptiveProps.Add(value); } } + + if (descriptiveProps.Count > 0) + { + fullName = $"{fullName}_{String.Join("_", descriptiveProps.ToArray())}"; + } + } + + return fullName; + } + + private bool IsSimpleType(object value, out string stringValue) + { + stringValue = String.Empty; + var type = value.GetType(); + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // nullable type, check if the nested type is simple. + return IsSimpleType(type.GetGenericArguments()[0], out stringValue); + } + if (type.IsPrimitive || type.IsEnum || type.Equals(typeof(string)) || type.Equals(typeof(decimal))) + { + stringValue = value.ToString(); + return true; } + return false; + } - // Text - public Text TextToSpeckle(DBText text) + private void ConvertWithDisplay( + Base obj, + DisplayStyle style, + RenderMaterial material, + ref List converted, + bool TryUseObjDisplay = false + ) + { + if (TryUseObjDisplay && obj["displayStyle"] as DisplayStyle != null) { - var _text = new Text(); + style = obj["displayStyle"] as DisplayStyle; + } - // not realistically feasible to extract outline curves for displayvalue currently - _text.height = text.Height; - var center = GetTextCenter(text); - _text.plane = PlaneToSpeckle(new Plane(center, text.Normal)); - _text.rotation = text.Rotation; - _text.value = text.TextString; - _text.units = ModelUnits; + if (TryUseObjDisplay && obj["renderMaterial"] as RenderMaterial != null) + { + material = obj["renderMaterial"] as RenderMaterial; + } - // autocad props - var excludeProps = new List() { "Height", "Rotation", "TextString" }; - Base props = Utilities.GetApplicationProps(text, typeof(DBText), true, excludeProps); - props["TextPosition"] = PointToSpeckle(text.Position); - _text[AutocadPropName] = props; + var convertedList = new List(); + var convertedGeo = ConvertToNative(obj); + if (convertedGeo == null) + { + return; + } - return _text; + //Iteratively flatten any lists + void FlattenConvertedObject(object item) + { + if (item is System.Collections.IList list) + { + foreach (object child in list) + { + FlattenConvertedObject(child); + } + } + else + { + convertedList.Add(item); + } } + FlattenConvertedObject(convertedGeo); - public Text TextToSpeckle(MText text) + foreach (Entity entity in convertedList) { - var _text = new Text(); + if (entity != null) + { + // get display attributes + Base styleBase = style != null ? style : material; + DisplayStyleToNative( + styleBase, + out Color color, + out Transparency transparency, + out LineWeight lineWeight, + out ObjectId lineType + ); + entity.Color = color; + entity.Transparency = transparency; + entity.LineWeight = lineWeight; + entity.LinetypeId = lineType; + + converted.Add(entity); + } + } + } - // not realistically feasible to extract outline curves for displayvalue currently - _text.height = text.Height == 0 ? text.ActualHeight : text.Height; - var center = (text.Bounds != null) ? GetTextCenter(text.Bounds.Value) : text.Location; - _text.plane = PlaneToSpeckle(new Plane(center, text.Normal)); - _text.rotation = text.Rotation; - _text.value = text.Text; - _text.richText = text.ContentsRTF; - _text.units = ModelUnits; + // Text + public Text TextToSpeckle(DBText text) + { + var _text = new Text(); + + // not realistically feasible to extract outline curves for displayvalue currently + _text.height = text.Height; + var center = GetTextCenter(text); + _text.plane = PlaneToSpeckle(new Plane(center, text.Normal)); + _text.rotation = text.Rotation; + _text.value = text.TextString; + _text.units = ModelUnits; + + // autocad props + var excludeProps = new List() { "Height", "Rotation", "TextString" }; + Base props = Utilities.GetApplicationProps(text, typeof(DBText), true, excludeProps); + props["TextPosition"] = PointToSpeckle(text.Position); + _text[AutocadPropName] = props; + + return _text; + } - // autocad props - var excludeProps = new List() { "Height", "Rotation", "Contents", "ContentsRTF" }; - Base props = Utilities.GetApplicationProps(text, typeof(MText), true, excludeProps); - props["TextPosition"] = PointToSpeckle(text.Location); - _text[AutocadPropName] = props; + public Text TextToSpeckle(MText text) + { + var _text = new Text(); + + // not realistically feasible to extract outline curves for displayvalue currently + _text.height = text.Height == 0 ? text.ActualHeight : text.Height; + var center = (text.Bounds != null) ? GetTextCenter(text.Bounds.Value) : text.Location; + _text.plane = PlaneToSpeckle(new Plane(center, text.Normal)); + _text.rotation = text.Rotation; + _text.value = text.Text; + _text.richText = text.ContentsRTF; + _text.units = ModelUnits; + + // autocad props + var excludeProps = new List() { "Height", "Rotation", "Contents", "ContentsRTF" }; + Base props = Utilities.GetApplicationProps(text, typeof(MText), true, excludeProps); + props["TextPosition"] = PointToSpeckle(text.Location); + _text[AutocadPropName] = props; + + return _text; + } - return _text; + public Entity AcadTextToNative(Text text) + { + Entity _text = null; + Base sourceAppProps = text[AutocadPropName] as Base; + if (sourceAppProps == null) + { + return TextToNative(text); } - public Entity AcadTextToNative(Text text) + Point textPosition = + sourceAppProps["TextPosition"] != null ? sourceAppProps["TextPosition"] as Point : text.plane.origin; + ObjectId textStyle = + sourceAppProps["TextStyleName"] != null + ? GetTextStyle(sourceAppProps["TextStyleName"] as string) + : Doc.Database.Textstyle; + + string className = sourceAppProps["class"] as string; + switch (className) { - Entity _text = null; - Base sourceAppProps = text[AutocadPropName] as Base; - if (sourceAppProps == null) - return TextToNative(text); + case "MText": + MText mText = TextToNative(text); + mText.Location = PointToNative(textPosition); + mText.TextStyleId = textStyle; + Utilities.SetApplicationProps(mText, typeof(MText), sourceAppProps); + _text = mText; + break; + case "DBText": + var dbText = new DBText(); + dbText.TextString = text.value; + dbText.Height = ScaleToNative(text.height, text.units); + dbText.Position = PointToNative(textPosition); + dbText.Rotation = text.rotation; + dbText.Normal = VectorToNative(text.plane.normal); + dbText.TextStyleId = textStyle; + Utilities.SetApplicationProps(dbText, typeof(DBText), sourceAppProps); + _text = dbText; + break; + default: + _text = TextToNative(text); + break; + } + return _text; + } - Point textPosition = - sourceAppProps["TextPosition"] != null ? sourceAppProps["TextPosition"] as Point : text.plane.origin; - ObjectId textStyle = - sourceAppProps["TextStyleName"] != null - ? GetTextStyle(sourceAppProps["TextStyleName"] as string) - : Doc.Database.Textstyle; + public MText TextToNative(Text text) + { + var _text = new MText(); - string className = sourceAppProps["class"] as string; - switch (className) - { - case "MText": - MText mText = TextToNative(text); - mText.Location = PointToNative(textPosition); - mText.TextStyleId = textStyle; - Utilities.SetApplicationProps(mText, typeof(MText), sourceAppProps); - _text = mText; - break; - case "DBText": - var dbText = new DBText(); - dbText.TextString = text.value; - dbText.Height = ScaleToNative(text.height, text.units); - dbText.Position = PointToNative(textPosition); - dbText.Rotation = text.rotation; - dbText.Normal = VectorToNative(text.plane.normal); - dbText.TextStyleId = textStyle; - Utilities.SetApplicationProps(dbText, typeof(DBText), sourceAppProps); - _text = dbText; - break; - default: - _text = TextToNative(text); - break; - } - return _text; + if (string.IsNullOrEmpty(text.richText)) + { + _text.Contents = text.value; } - - public MText TextToNative(Text text) + else { - var _text = new MText(); + _text.ContentsRTF = text.richText; + } - if (string.IsNullOrEmpty(text.richText)) - _text.Contents = text.value; - else - _text.ContentsRTF = text.richText; - _text.TextHeight = ScaleToNative(text.height, text.units); - _text.Location = PointToNative(text.plane.origin); - _text.Rotation = text.rotation; - _text.Normal = VectorToNative(text.plane.normal); + _text.TextHeight = ScaleToNative(text.height, text.units); + _text.Location = PointToNative(text.plane.origin); + _text.Rotation = text.rotation; + _text.Normal = VectorToNative(text.plane.normal); - return _text; - } + return _text; + } - private ObjectId GetTextStyle(string styleName) + private ObjectId GetTextStyle(string styleName) + { + var textStyleTable = Trans.GetObject(Doc.Database.TextStyleTableId, OpenMode.ForRead) as DimStyleTable; + foreach (ObjectId id in textStyleTable) { - var textStyleTable = Trans.GetObject(Doc.Database.TextStyleTableId, OpenMode.ForRead) as DimStyleTable; - foreach (ObjectId id in textStyleTable) + var textStyle = Trans.GetObject(id, OpenMode.ForRead) as DimStyleTableRecord; + if (textStyle.Name == styleName) { - var textStyle = Trans.GetObject(id, OpenMode.ForRead) as DimStyleTableRecord; - if (textStyle.Name == styleName) - return id; + return id; } - return ObjectId.Null; } + return ObjectId.Null; + } + + private Point3d GetTextCenter(Extents3d extents) + { + var x = (extents.MaxPoint.X + extents.MinPoint.X) / 2.0; + var y = (extents.MaxPoint.Y + extents.MinPoint.Y) / 2.0; + var z = (extents.MaxPoint.Z + extents.MinPoint.Z) / 2.0; - private Point3d GetTextCenter(Extents3d extents) + return new Point3d(x, y, z); + } + + private Point3d GetTextCenter(DBText text) + { + var position = text.Position; + double x = position.X; + double y = position.Y; + double z = position.Z; + + if (text.Bounds != null) { - var x = (extents.MaxPoint.X + extents.MinPoint.X) / 2.0; - var y = (extents.MaxPoint.Y + extents.MinPoint.Y) / 2.0; - var z = (extents.MaxPoint.Z + extents.MinPoint.Z) / 2.0; + var extents = text.Bounds.Value; + x = (extents.MaxPoint.X + extents.MinPoint.X) / 2.0; + y = (extents.MaxPoint.Y + extents.MinPoint.Y) / 2.0; + z = (extents.MaxPoint.Z + extents.MinPoint.Z) / 2.0; return new Point3d(x, y, z); } - private Point3d GetTextCenter(DBText text) + var alignment = text.AlignmentPoint; + var height = text.Height; + switch (text.Justify) { - var position = text.Position; - double x = position.X; - double y = position.Y; - double z = position.Z; + case AttachmentPoint.BottomMid: + case AttachmentPoint.BottomCenter: + x = alignment.X; + y = alignment.Y + (height / 2); + break; + case AttachmentPoint.TopCenter: + case AttachmentPoint.TopMid: + x = alignment.X; + y = alignment.Y - (height / 2); + break; + case AttachmentPoint.MiddleRight: + x = alignment.X - ((alignment.X - position.X) / 2); + y = alignment.Y; + break; + case AttachmentPoint.BottomRight: + x = alignment.X - ((alignment.X - position.X) / 2); + y = alignment.Y + (height / 2); + break; + case AttachmentPoint.TopRight: + x = alignment.X - ((alignment.X - position.X) / 2); + y = alignment.Y - (height / 2); + break; + case AttachmentPoint.MiddleCenter: + case AttachmentPoint.MiddleMid: + x = alignment.X; + y = alignment.Y; + break; + default: + break; + } + return new Point3d(x, y, z); + } - if (text.Bounds != null) - { - var extents = text.Bounds.Value; - x = (extents.MaxPoint.X + extents.MinPoint.X) / 2.0; - y = (extents.MaxPoint.Y + extents.MinPoint.Y) / 2.0; - z = (extents.MaxPoint.Z + extents.MinPoint.Z) / 2.0; + // Dimension + public Dimension DimensionToSpeckle(AcadDB.Dimension dimension) + { + Dimension _dimension = null; + Base props = null; + var ignore = new List() { "DimensionText", "Measurement" }; - return new Point3d(x, y, z); - } + switch (dimension) + { + case AlignedDimension o: + var alignedDimension = new DistanceDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement, + isOrdinate = false + }; + var alignedNormal = new Vector3d( + o.XLine2Point.X - o.XLine1Point.X, + o.XLine2Point.Y - o.XLine1Point.Y, + o.XLine2Point.Z - o.XLine1Point.Z + ).GetPerpendicularVector(); + alignedDimension.direction = VectorToSpeckle(alignedNormal); + alignedDimension.position = PointToSpeckle(o.DimLinePoint); + alignedDimension.measured = new List() { PointToSpeckle(o.XLine1Point), PointToSpeckle(o.XLine2Point) }; + props = Utilities.GetApplicationProps(o, typeof(AlignedDimension), true, ignore); + _dimension = alignedDimension; + break; + case RotatedDimension o: + var rotatedDimension = new DistanceDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement, + isOrdinate = false + }; + var rotatedNormal = new Vector3d( + o.XLine2Point.X - o.XLine1Point.X, + o.XLine2Point.Y - o.XLine1Point.Y, + o.XLine2Point.Z - o.XLine1Point.Z + ).GetPerpendicularVector(); + rotatedDimension.direction = VectorToSpeckle(rotatedNormal.RotateBy(o.Rotation, Vector3d.ZAxis)); + rotatedDimension.position = PointToSpeckle(o.DimLinePoint); + rotatedDimension.measured = new List() { PointToSpeckle(o.XLine1Point), PointToSpeckle(o.XLine2Point) }; + props = Utilities.GetApplicationProps(o, typeof(RotatedDimension), true, ignore); + _dimension = rotatedDimension; + break; + case OrdinateDimension o: + var ordinateDimension = new DistanceDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement, + isOrdinate = true + }; + ordinateDimension.direction = o.UsingXAxis ? VectorToSpeckle(Vector3d.XAxis) : VectorToSpeckle(Vector3d.YAxis); + ordinateDimension.position = PointToSpeckle(o.LeaderEndPoint); + ordinateDimension.measured = new List() { PointToSpeckle(o.Origin), PointToSpeckle(o.DefiningPoint) }; + props = Utilities.GetApplicationProps(o, typeof(OrdinateDimension), true, ignore); + _dimension = ordinateDimension; + break; + case RadialDimension o: + var radialDimension = new LengthDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement + }; + radialDimension.measured = new Line(PointToSpeckle(o.Center), PointToSpeckle(o.ChordPoint), ModelUnits); + radialDimension.position = PointToSpeckle(o.ChordPoint); // TODO: the position could be improved by using the leader length x the direction of the dimension + props = Utilities.GetApplicationProps(o, typeof(RadialDimension), true, ignore); + _dimension = radialDimension; + break; + case DiametricDimension o: + var diametricDimension = new LengthDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement + }; + diametricDimension.measured = new Line( + PointToSpeckle(o.FarChordPoint), + PointToSpeckle(o.ChordPoint), + ModelUnits + ); + diametricDimension.position = PointToSpeckle(o.ChordPoint); // TODO: the position could be improved by using the leader length x the direction of the dimension + props = Utilities.GetApplicationProps(o, typeof(DiametricDimension), true, ignore); + _dimension = diametricDimension; + break; + case ArcDimension o: + var arcDimension = new LengthDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement + }; + arcDimension.measured = ArcToSpeckle(new CircularArc3d(o.XLine1Point, o.ArcPoint, o.XLine2Point)); + arcDimension.position = PointToSpeckle(o.ArcPoint); + props = Utilities.GetApplicationProps(o, typeof(ArcDimension), true, ignore); + _dimension = arcDimension; + break; + case LineAngularDimension2 o: + var lineAngularDimension = new AngleDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement + }; + var line1 = new Line(PointToSpeckle(o.XLine1Start), PointToSpeckle(o.XLine1End), ModelUnits); + var line2 = new Line(PointToSpeckle(o.XLine2Start), PointToSpeckle(o.XLine2End), ModelUnits); + lineAngularDimension.measured = new List() { line1, line2 }; + lineAngularDimension.position = PointToSpeckle(o.ArcPoint); + props = Utilities.GetApplicationProps(o, typeof(LineAngularDimension2), true, ignore); + _dimension = lineAngularDimension; + break; + case Point3AngularDimension o: + var pointAngularDimension = new AngleDimension() + { + units = ModelUnits, + value = dimension.DimensionText, + measurement = dimension.Measurement + }; + var point1 = new Line(PointToSpeckle(o.ArcPoint), PointToSpeckle(o.XLine1Point), ModelUnits); + var point2 = new Line(PointToSpeckle(o.ArcPoint), PointToSpeckle(o.XLine2Point), ModelUnits); + pointAngularDimension.measured = new List() { point1, point2 }; + pointAngularDimension.position = PointToSpeckle(o.ArcPoint); + props = Utilities.GetApplicationProps(o, typeof(Point3AngularDimension), true, ignore); + _dimension = pointAngularDimension; + break; + } + if (_dimension != null && props != null) + { + _dimension.textPosition = PointToSpeckle(dimension.TextPosition); + _dimension[AutocadPropName] = props; + } + return _dimension; + } - var alignment = text.AlignmentPoint; - var height = text.Height; - switch (text.Justify) - { - case AttachmentPoint.BottomMid: - case AttachmentPoint.BottomCenter: - x = alignment.X; - y = alignment.Y + (height / 2); - break; - case AttachmentPoint.TopCenter: - case AttachmentPoint.TopMid: - x = alignment.X; - y = alignment.Y - (height / 2); - break; - case AttachmentPoint.MiddleRight: - x = alignment.X - ((alignment.X - position.X) / 2); - y = alignment.Y; - break; - case AttachmentPoint.BottomRight: - x = alignment.X - ((alignment.X - position.X) / 2); - y = alignment.Y + (height / 2); - break; - case AttachmentPoint.TopRight: - x = alignment.X - ((alignment.X - position.X) / 2); - y = alignment.Y - (height / 2); - break; - case AttachmentPoint.MiddleCenter: - case AttachmentPoint.MiddleMid: - x = alignment.X; - y = alignment.Y; - break; - default: - break; - } - return new Point3d(x, y, z); + public AcadDB.Dimension AcadDimensionToNative(Dimension dimension) + { + AcadDB.Dimension _dimension = null; + Base sourceAppProps = dimension[AutocadPropName] as Base; + if (sourceAppProps == null) + { + return DimensionToNative(dimension); } - // Dimension - public Dimension DimensionToSpeckle(AcadDB.Dimension dimension) + ObjectId dimensionStyle = + sourceAppProps["DimensionStyleName"] != null + ? GetDimensionStyle(sourceAppProps["DimensionStyleName"] as string) + : Doc.Database.Dimstyle; + if (dimensionStyle == ObjectId.Null) { - Dimension _dimension = null; - Base props = null; - var ignore = new List() { "DimensionText", "Measurement" }; + dimensionStyle = Doc.Database.Dimstyle; + } - switch (dimension) - { - case AlignedDimension o: - var alignedDimension = new DistanceDimension() - { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement, - isOrdinate = false - }; - var alignedNormal = new Vector3d( - o.XLine2Point.X - o.XLine1Point.X, - o.XLine2Point.Y - o.XLine1Point.Y, - o.XLine2Point.Z - o.XLine1Point.Z - ).GetPerpendicularVector(); - alignedDimension.direction = VectorToSpeckle(alignedNormal); - alignedDimension.position = PointToSpeckle(o.DimLinePoint); - alignedDimension.measured = new List() - { - PointToSpeckle(o.XLine1Point), - PointToSpeckle(o.XLine2Point) - }; - props = Utilities.GetApplicationProps(o, typeof(AlignedDimension), true, ignore); + Point3d position = PointToNative(dimension.position); + string className = sourceAppProps["class"] as string; + switch (className) + { + case "AlignedDimension": + var alignedSpeckle = dimension as DistanceDimension; + if (alignedSpeckle == null || alignedSpeckle.measured.Count < 2) + { + return null; + } + + try + { + var alignedStart = PointToNative(alignedSpeckle.measured[0]); + var alignedEnd = PointToNative(alignedSpeckle.measured[1]); + var alignedDimension = new AlignedDimension( + alignedStart, + alignedEnd, + position, + dimension.value, + dimensionStyle + ); + Utilities.SetApplicationProps(alignedDimension, typeof(AlignedDimension), sourceAppProps); _dimension = alignedDimension; - break; - case RotatedDimension o: - var rotatedDimension = new DistanceDimension() - { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement, - isOrdinate = false - }; - var rotatedNormal = new Vector3d( - o.XLine2Point.X - o.XLine1Point.X, - o.XLine2Point.Y - o.XLine1Point.Y, - o.XLine2Point.Z - o.XLine1Point.Z - ).GetPerpendicularVector(); - rotatedDimension.direction = VectorToSpeckle(rotatedNormal.RotateBy(o.Rotation, Vector3d.ZAxis)); - rotatedDimension.position = PointToSpeckle(o.DimLinePoint); - rotatedDimension.measured = new List() - { - PointToSpeckle(o.XLine1Point), - PointToSpeckle(o.XLine2Point) - }; - props = Utilities.GetApplicationProps(o, typeof(RotatedDimension), true, ignore); + } + catch { } + ; + break; + case "RotatedDimension": + var rotatedSpeckle = dimension as DistanceDimension; + if (rotatedSpeckle == null || rotatedSpeckle.measured.Count < 2) + { + return null; + } + + double rotation = sourceAppProps["Rotation"] as double? ?? 0; + try + { + var rotatedStart = PointToNative(rotatedSpeckle.measured[0]); + var rotatedEnd = PointToNative(rotatedSpeckle.measured[1]); + var rotatedDimension = new RotatedDimension( + rotation, + rotatedStart, + rotatedEnd, + position, + dimension.value, + dimensionStyle + ); + Utilities.SetApplicationProps(rotatedDimension, typeof(RotatedDimension), sourceAppProps); _dimension = rotatedDimension; - break; - case OrdinateDimension o: - var ordinateDimension = new DistanceDimension() + } + catch { } + break; + case "OrdinateDimension": + try + { + var ordinateDimension = DimensionToNative(dimension) as OrdinateDimension; + if (ordinateDimension != null) { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement, - isOrdinate = true - }; - ordinateDimension.direction = o.UsingXAxis - ? VectorToSpeckle(Vector3d.XAxis) - : VectorToSpeckle(Vector3d.YAxis); - ordinateDimension.position = PointToSpeckle(o.LeaderEndPoint); - ordinateDimension.measured = new List() { PointToSpeckle(o.Origin), PointToSpeckle(o.DefiningPoint) }; - props = Utilities.GetApplicationProps(o, typeof(OrdinateDimension), true, ignore); + Utilities.SetApplicationProps(ordinateDimension, typeof(OrdinateDimension), sourceAppProps); + } + _dimension = ordinateDimension; - break; - case RadialDimension o: - var radialDimension = new LengthDimension() + } + catch { } + break; + case "RadialDimension": + try + { + var radialDimension = DimensionToNative(dimension) as RadialDimension; + if (radialDimension != null) { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement - }; - radialDimension.measured = new Line(PointToSpeckle(o.Center), PointToSpeckle(o.ChordPoint), ModelUnits); - radialDimension.position = PointToSpeckle(o.ChordPoint); // TODO: the position could be improved by using the leader length x the direction of the dimension - props = Utilities.GetApplicationProps(o, typeof(RadialDimension), true, ignore); + Utilities.SetApplicationProps(radialDimension, typeof(RadialDimension), sourceAppProps); + } + _dimension = radialDimension; - break; - case DiametricDimension o: - var diametricDimension = new LengthDimension() - { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement - }; - diametricDimension.measured = new Line( - PointToSpeckle(o.FarChordPoint), - PointToSpeckle(o.ChordPoint), - ModelUnits - ); - diametricDimension.position = PointToSpeckle(o.ChordPoint); // TODO: the position could be improved by using the leader length x the direction of the dimension - props = Utilities.GetApplicationProps(o, typeof(DiametricDimension), true, ignore); + } + catch { } + break; + case "DiametricDimension": + var diametricSpeckle = dimension as LengthDimension; + if (diametricSpeckle == null || diametricSpeckle.measured as Line == null) + { + return null; + } + + try + { + var line = diametricSpeckle.measured as Line; + var start = PointToNative(line.start); + var end = PointToNative(line.end); + double leaderLength = ScaleToNative(sourceAppProps["LeaderLength"] as double? ?? 0, ModelUnits); + var diametricDimension = new DiametricDimension(end, start, leaderLength, dimension.value, dimensionStyle); + sourceAppProps["LeaderLength"] = leaderLength; + Utilities.SetApplicationProps(diametricDimension, typeof(DiametricDimension), sourceAppProps); _dimension = diametricDimension; - break; - case ArcDimension o: - var arcDimension = new LengthDimension() - { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement - }; - arcDimension.measured = ArcToSpeckle(new CircularArc3d(o.XLine1Point, o.ArcPoint, o.XLine2Point)); - arcDimension.position = PointToSpeckle(o.ArcPoint); - props = Utilities.GetApplicationProps(o, typeof(ArcDimension), true, ignore); + } + catch { } + break; + case "ArcDimension": + var arcSpeckle = dimension as LengthDimension; + if (arcSpeckle == null || arcSpeckle.measured as Arc == null) + { + return null; + } + + try + { + var arc = ArcToNative(arcSpeckle.measured as Arc); + var arcDimension = new ArcDimension( + arc.Center, + arc.StartPoint, + arc.EndPoint, + position, + dimension.value, + dimensionStyle + ); + Utilities.SetApplicationProps(arcDimension, typeof(ArcDimension), sourceAppProps); _dimension = arcDimension; - break; - case LineAngularDimension2 o: - var lineAngularDimension = new AngleDimension() + } + catch { } + break; + case "LineAngularDimension2": + try + { + var lineAngularDimension = DimensionToNative(dimension) as LineAngularDimension2; + if (lineAngularDimension != null) { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement - }; - var line1 = new Line(PointToSpeckle(o.XLine1Start), PointToSpeckle(o.XLine1End), ModelUnits); - var line2 = new Line(PointToSpeckle(o.XLine2Start), PointToSpeckle(o.XLine2End), ModelUnits); - lineAngularDimension.measured = new List() { line1, line2 }; - lineAngularDimension.position = PointToSpeckle(o.ArcPoint); - props = Utilities.GetApplicationProps(o, typeof(LineAngularDimension2), true, ignore); + Utilities.SetApplicationProps(lineAngularDimension, typeof(LineAngularDimension2), sourceAppProps); + } + _dimension = lineAngularDimension; - break; - case Point3AngularDimension o: - var pointAngularDimension = new AngleDimension() + } + catch { } + break; + case "Point3AngularDimension": + try + { + var pointAngularDimension = DimensionToNative(dimension) as Point3AngularDimension; + if (pointAngularDimension != null) { - units = ModelUnits, - value = dimension.DimensionText, - measurement = dimension.Measurement - }; - var point1 = new Line(PointToSpeckle(o.ArcPoint), PointToSpeckle(o.XLine1Point), ModelUnits); - var point2 = new Line(PointToSpeckle(o.ArcPoint), PointToSpeckle(o.XLine2Point), ModelUnits); - pointAngularDimension.measured = new List() { point1, point2 }; - pointAngularDimension.position = PointToSpeckle(o.ArcPoint); - props = Utilities.GetApplicationProps(o, typeof(Point3AngularDimension), true, ignore); + Utilities.SetApplicationProps(pointAngularDimension, typeof(Point3AngularDimension), sourceAppProps); + } + _dimension = pointAngularDimension; - break; - } - if (_dimension != null && props != null) - { - _dimension.textPosition = PointToSpeckle(dimension.TextPosition); - _dimension[AutocadPropName] = props; - } - return _dimension; + } + catch { } + break; + default: + _dimension = DimensionToNative(dimension); + break; } - - public AcadDB.Dimension AcadDimensionToNative(Dimension dimension) + if (_dimension != null) { - AcadDB.Dimension _dimension = null; - Base sourceAppProps = dimension[AutocadPropName] as Base; - if (sourceAppProps == null) - return DimensionToNative(dimension); + _dimension.TextPosition = PointToNative(dimension.textPosition); + _dimension.DimensionStyle = dimensionStyle; + } + return _dimension; + } - ObjectId dimensionStyle = - sourceAppProps["DimensionStyleName"] != null - ? GetDimensionStyle(sourceAppProps["DimensionStyleName"] as string) - : Doc.Database.Dimstyle; - if (dimensionStyle == ObjectId.Null) - dimensionStyle = Doc.Database.Dimstyle; - Point3d position = PointToNative(dimension.position); - string className = sourceAppProps["class"] as string; - switch (className) - { - case "AlignedDimension": - var alignedSpeckle = dimension as DistanceDimension; - if (alignedSpeckle == null || alignedSpeckle.measured.Count < 2) - return null; - try - { - var alignedStart = PointToNative(alignedSpeckle.measured[0]); - var alignedEnd = PointToNative(alignedSpeckle.measured[1]); - var alignedDimension = new AlignedDimension( - alignedStart, - alignedEnd, - position, - dimension.value, - dimensionStyle - ); - Utilities.SetApplicationProps(alignedDimension, typeof(AlignedDimension), sourceAppProps); - _dimension = alignedDimension; - } - catch { } - ; - break; - case "RotatedDimension": - var rotatedSpeckle = dimension as DistanceDimension; - if (rotatedSpeckle == null || rotatedSpeckle.measured.Count < 2) - return null; - double rotation = sourceAppProps["Rotation"] as double? ?? 0; - try - { - var rotatedStart = PointToNative(rotatedSpeckle.measured[0]); - var rotatedEnd = PointToNative(rotatedSpeckle.measured[1]); - var rotatedDimension = new RotatedDimension( - rotation, - rotatedStart, - rotatedEnd, - position, - dimension.value, - dimensionStyle - ); - Utilities.SetApplicationProps(rotatedDimension, typeof(RotatedDimension), sourceAppProps); - _dimension = rotatedDimension; - } - catch { } - break; - case "OrdinateDimension": - try - { - var ordinateDimension = DimensionToNative(dimension) as OrdinateDimension; - if (ordinateDimension != null) - Utilities.SetApplicationProps(ordinateDimension, typeof(OrdinateDimension), sourceAppProps); - _dimension = ordinateDimension; - } - catch { } - break; - case "RadialDimension": - try + public AcadDB.Dimension DimensionToNative(Dimension dimension) + { + AcadDB.Dimension _dimension = null; + var style = Doc.Database.Dimstyle; + var position = PointToNative(dimension.position); + switch (dimension) + { + case LengthDimension o: + switch (o.measured) + { + case Arc a: + var arcCenter = PointToNative(a.plane.origin); + var arcStart = PointToNative(a.startPoint); + var arcEnd = PointToNative(a.endPoint); + try + { + var arcDimension = new ArcDimension(arcCenter, arcStart, arcEnd, position, dimension.value, style); + _dimension = arcDimension; + } + catch { } + break; + case Line l: + var radialStart = PointToNative(l.start); + var radialEnd = PointToNative(l.end); + double leaderLength = radialEnd.DistanceTo(position); + try + { + var radialDimension = new RadialDimension(radialStart, radialEnd, leaderLength, dimension.value, style); + _dimension = radialDimension; + } + catch { } + break; + } + break; + case AngleDimension o: + try + { + if (o.measured.Count < 2) { - var radialDimension = DimensionToNative(dimension) as RadialDimension; - if (radialDimension != null) - Utilities.SetApplicationProps(radialDimension, typeof(RadialDimension), sourceAppProps); - _dimension = radialDimension; + break; } - catch { } - break; - case "DiametricDimension": - var diametricSpeckle = dimension as LengthDimension; - if (diametricSpeckle == null || diametricSpeckle.measured as Line == null) - return null; - try + + var line1Start = PointToNative(o.measured[0].start); + var line1End = PointToNative(o.measured[0].end); + var line2Start = PointToNative(o.measured[1].start); + var line2End = PointToNative(o.measured[1].end); + if (Math.Round(line1Start.DistanceTo(line2Start), 3) == 0) { - var line = diametricSpeckle.measured as Line; - var start = PointToNative(line.start); - var end = PointToNative(line.end); - double leaderLength = ScaleToNative(sourceAppProps["LeaderLength"] as double? ?? 0, ModelUnits); - var diametricDimension = new DiametricDimension(end, start, leaderLength, dimension.value, dimensionStyle); - sourceAppProps["LeaderLength"] = leaderLength; - Utilities.SetApplicationProps(diametricDimension, typeof(DiametricDimension), sourceAppProps); - _dimension = diametricDimension; + _dimension = new Point3AngularDimension(line1Start, line1End, line2End, position, dimension.value, style); } - catch { } - break; - case "ArcDimension": - var arcSpeckle = dimension as LengthDimension; - if (arcSpeckle == null || arcSpeckle.measured as Arc == null) - return null; - try + else { - var arc = ArcToNative(arcSpeckle.measured as Arc); - var arcDimension = new ArcDimension( - arc.Center, - arc.StartPoint, - arc.EndPoint, + _dimension = new LineAngularDimension2( + line1Start, + line1End, + line2Start, + line2End, position, dimension.value, - dimensionStyle + style ); - Utilities.SetApplicationProps(arcDimension, typeof(ArcDimension), sourceAppProps); - _dimension = arcDimension; } - catch { } - break; - case "LineAngularDimension2": - try - { - var lineAngularDimension = DimensionToNative(dimension) as LineAngularDimension2; - if (lineAngularDimension != null) - Utilities.SetApplicationProps(lineAngularDimension, typeof(LineAngularDimension2), sourceAppProps); - _dimension = lineAngularDimension; - } - catch { } - break; - case "Point3AngularDimension": - try - { - var pointAngularDimension = DimensionToNative(dimension) as Point3AngularDimension; - if (pointAngularDimension != null) - Utilities.SetApplicationProps(pointAngularDimension, typeof(Point3AngularDimension), sourceAppProps); - _dimension = pointAngularDimension; - } - catch { } - break; - default: - _dimension = DimensionToNative(dimension); + } + catch { } + break; + case DistanceDimension o: + if (o.measured.Count < 2) + { break; - } - if (_dimension != null) - { - _dimension.TextPosition = PointToNative(dimension.textPosition); - _dimension.DimensionStyle = dimensionStyle; - } - return _dimension; - } + } - public AcadDB.Dimension DimensionToNative(Dimension dimension) - { - AcadDB.Dimension _dimension = null; - var style = Doc.Database.Dimstyle; - var position = PointToNative(dimension.position); - switch (dimension) - { - case LengthDimension o: - switch (o.measured) - { - case Arc a: - var arcCenter = PointToNative(a.plane.origin); - var arcStart = PointToNative(a.startPoint); - var arcEnd = PointToNative(a.endPoint); - try - { - var arcDimension = new ArcDimension(arcCenter, arcStart, arcEnd, position, dimension.value, style); - _dimension = arcDimension; - } - catch { } - break; - case Line l: - var radialStart = PointToNative(l.start); - var radialEnd = PointToNative(l.end); - double leaderLength = radialEnd.DistanceTo(position); - try - { - var radialDimension = new RadialDimension(radialStart, radialEnd, leaderLength, dimension.value, style); - _dimension = radialDimension; - } - catch { } - break; - } - break; - case AngleDimension o: - try + try + { + var start = PointToNative(o.measured[0]); + var end = PointToNative(o.measured[1]); + var normal = VectorToNative(o.direction); + + if (o.isOrdinate) { - if (o.measured.Count < 2) - break; - var line1Start = PointToNative(o.measured[0].start); - var line1End = PointToNative(o.measured[0].end); - var line2Start = PointToNative(o.measured[1].start); - var line2End = PointToNative(o.measured[1].end); - if (Math.Round(line1Start.DistanceTo(line2Start), 3) == 0) - _dimension = new Point3AngularDimension(line1Start, line1End, line2End, position, dimension.value, style); - else - _dimension = new LineAngularDimension2( - line1Start, - line1End, - line2Start, - line2End, - position, - dimension.value, - style - ); + bool useXAxis = normal.IsParallelTo(Vector3d.XAxis) ? true : false; + var ordinateDimension = new OrdinateDimension(useXAxis, end, position, dimension.value, style); + ordinateDimension.Origin = start; + _dimension = ordinateDimension; } - catch { } - break; - case DistanceDimension o: - if (o.measured.Count < 2) - break; - try + else { - var start = PointToNative(o.measured[0]); - var end = PointToNative(o.measured[1]); - var normal = VectorToNative(o.direction); - - if (o.isOrdinate) + var dir = new Vector3d(end.X - start.X, end.Y - start.Y, end.Z - start.Z); // dimension direction + var angleBetween = Math.Round(dir.GetAngleTo(normal), 3); + if (dir.IsParallelTo(normal, Tolerance.Global)) { - bool useXAxis = normal.IsParallelTo(Vector3d.XAxis) ? true : false; - var ordinateDimension = new OrdinateDimension(useXAxis, end, position, dimension.value, style); - ordinateDimension.Origin = start; - _dimension = ordinateDimension; + _dimension = new AlignedDimension(start, end, position, dimension.value, style); } else { - var dir = new Vector3d(end.X - start.X, end.Y - start.Y, end.Z - start.Z); // dimension direction - var angleBetween = Math.Round(dir.GetAngleTo(normal), 3); - if (dir.IsParallelTo(normal, Tolerance.Global)) - _dimension = new AlignedDimension(start, end, position, dimension.value, style); - else - _dimension = new RotatedDimension(angleBetween, start, end, position, dimension.value, style); + _dimension = new RotatedDimension(angleBetween, start, end, position, dimension.value, style); } } - catch { } - break; - default: - break; - } - //if (_dimension != null) - // _dimension.TextPosition = PointToNative(dimension.textPosition); - return _dimension; + } + catch { } + break; + default: + break; } + //if (_dimension != null) + // _dimension.TextPosition = PointToNative(dimension.textPosition); + return _dimension; + } - private ObjectId GetDimensionStyle(string styleName) + private ObjectId GetDimensionStyle(string styleName) + { + var dimStyleTable = Trans.GetObject(Doc.Database.DimStyleTableId, OpenMode.ForRead) as DimStyleTable; + foreach (ObjectId id in dimStyleTable) { - var dimStyleTable = Trans.GetObject(Doc.Database.DimStyleTableId, OpenMode.ForRead) as DimStyleTable; - foreach (ObjectId id in dimStyleTable) + var dimStyle = Trans.GetObject(id, OpenMode.ForRead) as DimStyleTableRecord; + if (dimStyle.Name == styleName) { - var dimStyle = Trans.GetObject(id, OpenMode.ForRead) as DimStyleTableRecord; - if (dimStyle.Name == styleName) - return id; + return id; } - return ObjectId.Null; } + return ObjectId.Null; + } - // Proxy Entity - public Base ProxyEntityToSpeckle(ProxyEntity proxy) + // Proxy Entity + public Base ProxyEntityToSpeckle(ProxyEntity proxy) + { + // Currently not possible to retrieve geometry of proxy entities, so sending props as a base instead + var _proxy = new Base(); + _proxy["bbox"] = BoxToSpeckle(proxy.GeometricExtents); + var props = Utilities.GetApplicationProps(proxy, typeof(ProxyEntity), false); + props["ApplicationDescription"] = proxy.ApplicationDescription; + props["OriginalClassName"] = proxy.OriginalClassName; + props["OriginalDxfName"] = proxy.OriginalDxfName; + props["ProxyFlags"] = proxy.ProxyFlags; + if (props != null) { - // Currently not possible to retrieve geometry of proxy entities, so sending props as a base instead - var _proxy = new Base(); - _proxy["bbox"] = BoxToSpeckle(proxy.GeometricExtents); - var props = Utilities.GetApplicationProps(proxy, typeof(ProxyEntity), false); - props["ApplicationDescription"] = proxy.ApplicationDescription; - props["OriginalClassName"] = proxy.OriginalClassName; - props["OriginalDxfName"] = proxy.OriginalDxfName; - props["ProxyFlags"] = proxy.ProxyFlags; - if (props != null) - _proxy[AutocadPropName] = props; - - return _proxy; + _proxy[AutocadPropName] = props; } + + return _proxy; } } diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs index df6f5c5f21..525f114df4 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs @@ -32,524 +32,547 @@ using CivilDB = Autodesk.Civil.DatabaseServices; #endif -namespace Objects.Converter.AutocadCivil +namespace Objects.Converter.AutocadCivil; + +public partial class ConverterAutocadCivil : ISpeckleConverter { - public partial class ConverterAutocadCivil : ISpeckleConverter - { #if AUTOCAD2021 - public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2021); + public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2021); #elif AUTOCAD2022 - public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2022); + public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2022); #elif AUTOCAD2023 - public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2023); + public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2023); #elif AUTOCAD2024 - public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2024); + public static string AutocadAppName = HostApplications.AutoCAD.GetVersion(HostAppVersion.v2024); #elif CIVIL2021 - public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2021); + public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2021); #elif CIVIL2022 - public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2022); + public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2022); #elif CIVIL2023 - public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2023); + public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2023); #elif CIVIL2024 - public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2024); + public static string AutocadAppName = HostApplications.Civil.GetVersion(HostAppVersion.v2024); #elif ADVANCESTEEL2023 - public static string AutocadAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2023); + public static string AutocadAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2023); #elif ADVANCESTEEL2024 - public static string AutocadAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2024); + public static string AutocadAppName = HostApplications.AdvanceSteel.GetVersion(HostAppVersion.v2024); #endif - public ConverterAutocadCivil() - { - var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterAutocadCivil)).GetName().Version; - } - - #region ISpeckleConverter props - public string Description => "Default Speckle Kit for AutoCAD"; - public string Name => nameof(ConverterAutocadCivil); - public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; - public ProgressReport Report { get; private set; } = new ProgressReport(); - - public IEnumerable GetServicedApplications() => new string[] { AutocadAppName }; - - public Document Doc { get; private set; } - public Transaction Trans { get; private set; } // TODO: evaluate if this should be here - public Dictionary Settings { get; private set; } = new Dictionary(); - #endregion ISpeckleConverter props + public ConverterAutocadCivil() + { + var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterAutocadCivil)).GetName().Version; + } - public ReceiveMode ReceiveMode { get; set; } + #region ISpeckleConverter props + public string Description => "Default Speckle Kit for AutoCAD"; + public string Name => nameof(ConverterAutocadCivil); + public string Author => "Speckle"; + public string WebsiteOrEmail => "https://speckle.systems"; + public ProgressReport Report { get; private set; } = new ProgressReport(); - public List ContextObjects { get; set; } = new List(); + public IEnumerable GetServicedApplications() => new string[] { AutocadAppName }; - public void SetContextObjects(List objects) => ContextObjects = objects; + public Document Doc { get; private set; } + public Transaction Trans { get; private set; } // TODO: evaluate if this should be here + public Dictionary Settings { get; private set; } = new Dictionary(); + #endregion ISpeckleConverter props - public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); + public ReceiveMode ReceiveMode { get; set; } - public void SetConverterSettings(object settings) - { - Settings = settings as Dictionary; - } + public List ContextObjects { get; set; } = new List(); - public void SetContextDocument(object doc) - { - Doc = (Document)doc; - Trans = Doc.TransactionManager.TopTransaction; // set the stream transaction here! make sure it is the top level transaction - } + public void SetContextObjects(List objects) => ContextObjects = objects; - private string ApplicationIdKey = "applicationId"; + public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); - public Base ConvertToSpeckle(object @object) - { - Base @base = null; - ApplicationObject reportObj = null; - DisplayStyle style = null; - Base extensionDictionary = null; - List notes = new List(); + public void SetConverterSettings(object settings) + { + Settings = settings as Dictionary; + } - switch (@object) - { - case DBObject obj: + public void SetContextDocument(object doc) + { + Doc = (Document)doc; + Trans = Doc.TransactionManager.TopTransaction; // set the stream transaction here! make sure it is the top level transaction + } - var appId = obj.ObjectId.ToString(); // TODO: UPDATE THIS WITH STORED APP ID IF IT EXISTS + private string ApplicationIdKey = "applicationId"; - //Use the Handle object to update progressReport object. - //In an AutoCAD session, you can get the Handle of a DBObject from its ObjectId using the ObjectId.Handle or Handle property. - reportObj = new ApplicationObject(obj.Handle.ToString(), obj.GetType().Name) { applicationId = appId }; - style = DisplayStyleToSpeckle(obj as Entity); // note layer display styles are converted in the layer method - extensionDictionary = obj.GetObjectExtensionDictionaryAsBase(); + public Base ConvertToSpeckle(object @object) + { + Base @base = null; + ApplicationObject reportObj = null; + DisplayStyle style = null; + Base extensionDictionary = null; + List notes = new(); - switch (obj) - { - case DBPoint o: - @base = PointToSpeckle(o); - break; - case AcadDB.Line o: - @base = LineToSpeckle(o); - break; - case AcadDB.Arc o: - @base = ArcToSpeckle(o); - break; - case AcadDB.Circle o: - @base = CircleToSpeckle(o); - break; - case AcadDB.Ellipse o: - @base = EllipseToSpeckle(o); - break; - case AcadDB.Hatch o: - @base = HatchToSpeckle(o); - break; - case AcadDB.Spline o: - @base = SplineToSpeckle(o); - break; - case AcadDB.Polyline o: - if (o.IsOnlyLines) // db polylines can have arc segments, decide between polycurve or polyline conversion - @base = PolylineToSpeckle(o); - else - @base = PolycurveToSpeckle(o); - break; - case AcadDB.Polyline3d o: + switch (@object) + { + case DBObject obj: + + var appId = obj.ObjectId.ToString(); // TODO: UPDATE THIS WITH STORED APP ID IF IT EXISTS + + //Use the Handle object to update progressReport object. + //In an AutoCAD session, you can get the Handle of a DBObject from its ObjectId using the ObjectId.Handle or Handle property. + reportObj = new ApplicationObject(obj.Handle.ToString(), obj.GetType().Name) { applicationId = appId }; + style = DisplayStyleToSpeckle(obj as Entity); // note layer display styles are converted in the layer method + extensionDictionary = obj.GetObjectExtensionDictionaryAsBase(); + + switch (obj) + { + case DBPoint o: + @base = PointToSpeckle(o); + break; + case AcadDB.Line o: + @base = LineToSpeckle(o); + break; + case AcadDB.Arc o: + @base = ArcToSpeckle(o); + break; + case AcadDB.Circle o: + @base = CircleToSpeckle(o); + break; + case AcadDB.Ellipse o: + @base = EllipseToSpeckle(o); + break; + case AcadDB.Hatch o: + @base = HatchToSpeckle(o); + break; + case AcadDB.Spline o: + @base = SplineToSpeckle(o); + break; + case AcadDB.Polyline o: + if (o.IsOnlyLines) // db polylines can have arc segments, decide between polycurve or polyline conversion + { @base = PolylineToSpeckle(o); - break; - case Polyline2d o: + } + else + { @base = PolycurveToSpeckle(o); - break; - case Region o: - @base = RegionToSpeckle(o, out notes); - break; - case AcadDB.Surface o: - @base = SurfaceToSpeckle(o, out notes); - break; - case PolyFaceMesh o: - @base = MeshToSpeckle(o); - break; - case ProxyEntity o: - @base = ProxyEntityToSpeckle(o); - break; - case SubDMesh o: - @base = MeshToSpeckle(o); - break; - case Solid3d o: - if (o.IsNull) - notes.Add($"Solid was null"); - else - @base = SolidToSpeckle(o, out notes); - break; - case AcadDB.Dimension o: - @base = DimensionToSpeckle(o); - break; - case BlockReference o: - @base = BlockReferenceToSpeckle(o); - break; - case BlockTableRecord o: - @base = BlockRecordToSpeckle(o); - break; - case DBText o: - @base = TextToSpeckle(o); - break; - case MText o: - @base = TextToSpeckle(o); - break; - case LayerTableRecord o: - @base = LayerToSpeckle(o); - break; + } + + break; + case AcadDB.Polyline3d o: + @base = PolylineToSpeckle(o); + break; + case Polyline2d o: + @base = PolycurveToSpeckle(o); + break; + case Region o: + @base = RegionToSpeckle(o, out notes); + break; + case AcadDB.Surface o: + @base = SurfaceToSpeckle(o, out notes); + break; + case PolyFaceMesh o: + @base = MeshToSpeckle(o); + break; + case ProxyEntity o: + @base = ProxyEntityToSpeckle(o); + break; + case SubDMesh o: + @base = MeshToSpeckle(o); + break; + case Solid3d o: + if (o.IsNull) + { + notes.Add($"Solid was null"); + } + else + { + @base = SolidToSpeckle(o, out notes); + } + + break; + case AcadDB.Dimension o: + @base = DimensionToSpeckle(o); + break; + case BlockReference o: + @base = BlockReferenceToSpeckle(o); + break; + case BlockTableRecord o: + @base = BlockRecordToSpeckle(o); + break; + case DBText o: + @base = TextToSpeckle(o); + break; + case MText o: + @base = TextToSpeckle(o); + break; + case LayerTableRecord o: + @base = LayerToSpeckle(o); + break; #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - case CivilDB.Alignment o: - @base = AlignmentToSpeckle(o); - break; - case CivilDB.Corridor o: - @base = CorridorToSpeckle(o); - break; - case CivilDB.FeatureLine o: - @base = FeatureLineToSpeckle(o); - break; - case CivilDB.Structure o: - @base = StructureToSpeckle(o); - break; - case CivilDB.Pipe o: - @base = PipeToSpeckle(o); - break; - case CivilDB.PressurePipe o: - @base = PipeToSpeckle(o); - break; - case CivilDB.Profile o: - @base = ProfileToSpeckle(o); - break; - case CivilDB.TinSurface o: - @base = SurfaceToSpeckle(o); - break; + case CivilDB.Alignment o: + @base = AlignmentToSpeckle(o); + break; + case CivilDB.Corridor o: + @base = CorridorToSpeckle(o); + break; + case CivilDB.FeatureLine o: + @base = FeatureLineToSpeckle(o); + break; + case CivilDB.Structure o: + @base = StructureToSpeckle(o); + break; + case CivilDB.Pipe o: + @base = PipeToSpeckle(o); + break; + case CivilDB.PressurePipe o: + @base = PipeToSpeckle(o); + break; + case CivilDB.Profile o: + @base = ProfileToSpeckle(o); + break; + case CivilDB.TinSurface o: + @base = SurfaceToSpeckle(o); + break; #elif ADVANCESTEEL - default: - try - { - @base = ConvertASToSpeckle(obj, reportObj, notes); - } - catch (Exception ex) - { - //Update report because AS object type - Report.UpdateReportObject(reportObj); - throw; - } - - break; -#endif - } - break; - case Acad.Geometry.Point3d o: - @base = PointToSpeckle(o); - break; - case Acad.Geometry.Vector3d o: - @base = VectorToSpeckle(o); - break; - case Acad.Geometry.Line3d o: - @base = LineToSpeckle(o); - break; - case Acad.Geometry.LineSegment3d o: - @base = LineToSpeckle(o); - break; - case Acad.Geometry.CircularArc3d o: - @base = ArcToSpeckle(o); - break; - case Acad.Geometry.Plane o: - @base = PlaneToSpeckle(o); - break; - case Acad.Geometry.Curve3d o: - @base = CurveToSpeckle(o) as Base; - break; - default: - if (reportObj != null) - { - reportObj.Update( - status: ApplicationObject.State.Skipped, - logItem: $"{@object.GetType()} type not supported" - ); - Report.UpdateReportObject(reportObj); - } - return @base; - } + default: + try + { + @base = ConvertASToSpeckle(obj, reportObj, notes); + } + catch (Exception ex) + { + //Update report because AS object type + Report.UpdateReportObject(reportObj); + throw; + } - if (@base is null) + break; +#endif + } + break; + case Acad.Geometry.Point3d o: + @base = PointToSpeckle(o); + break; + case Acad.Geometry.Vector3d o: + @base = VectorToSpeckle(o); + break; + case Acad.Geometry.Line3d o: + @base = LineToSpeckle(o); + break; + case Acad.Geometry.LineSegment3d o: + @base = LineToSpeckle(o); + break; + case Acad.Geometry.CircularArc3d o: + @base = ArcToSpeckle(o); + break; + case Acad.Geometry.Plane o: + @base = PlaneToSpeckle(o); + break; + case Acad.Geometry.Curve3d o: + @base = CurveToSpeckle(o) as Base; + break; + default: + if (reportObj != null) + { + reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"{@object.GetType()} type not supported"); + Report.UpdateReportObject(reportObj); + } return @base; + } - if (style != null) - @base["displayStyle"] = style; - - if (extensionDictionary != null) - @base["extensionDictionary"] = extensionDictionary; - - if (reportObj != null) - { - reportObj.Update(log: notes); - Report.UpdateReportObject(reportObj); - } + if (@base is null) + { return @base; } - private Base ObjectToSpeckleBuiltElement(DBObject o) + if (style != null) + { + @base["displayStyle"] = style; + } + + if (extensionDictionary != null) { - throw new NotImplementedException(); + @base["extensionDictionary"] = extensionDictionary; } - public List ConvertToSpeckle(List objects) + if (reportObj != null) { - return objects.Select(x => ConvertToSpeckle(x)).ToList(); + reportObj.Update(log: notes); + Report.UpdateReportObject(reportObj); } + return @base; + } + + private Base ObjectToSpeckleBuiltElement(DBObject o) + { + throw new NotImplementedException(); + } - public object ConvertToNative(Base @object) + public List ConvertToSpeckle(List objects) + { + return objects.Select(x => ConvertToSpeckle(x)).ToList(); + } + + public object ConvertToNative(Base @object) + { + // determine if this object has autocad props + bool isFromAutoCAD = @object[AutocadPropName] != null ? true : false; + bool isFromCivil = @object[CivilPropName] != null ? true : false; + object acadObj = null; + var reportObj = Report.ReportObjects.ContainsKey(@object.id) + ? new ApplicationObject(@object.id, @object.speckle_type) + : null; + List notes = new(); + switch (@object) { - // determine if this object has autocad props - bool isFromAutoCAD = @object[AutocadPropName] != null ? true : false; - bool isFromCivil = @object[CivilPropName] != null ? true : false; - object acadObj = null; - var reportObj = Report.ReportObjects.ContainsKey(@object.id) - ? new ApplicationObject(@object.id, @object.speckle_type) - : null; - List notes = new List(); - switch (@object) - { - case Point o: - acadObj = PointToNativeDB(o); - break; - - case Line o: - acadObj = LineToNativeDB(o); - break; - - case Arc o: - acadObj = ArcToNativeDB(o); - break; - - case Circle o: - acadObj = CircleToNativeDB(o); - break; - - case Ellipse o: - acadObj = EllipseToNativeDB(o); - break; - - case Spiral o: - acadObj = PolylineToNativeDB(o.displayValue); - break; - - case Hatch o: - acadObj = HatchToNativeDB(o); - break; - - case Polyline o: - acadObj = PolylineToNativeDB(o); - break; - - case Polycurve o: - bool convertAsSpline = (o.segments.Where(s => !(s is Line) && !(s is Arc)).Count() > 0) ? true : false; - if (convertAsSpline || !IsPolycurvePlanar(o)) - acadObj = PolycurveSplineToNativeDB(o); - else - acadObj = PolycurveToNativeDB(o); - break; - - case Curve o: - acadObj = CurveToNativeDB(o); - break; - - /* - case Surface o: - return SurfaceToNative(o); - - */ - - case Mesh o: + case Point o: + acadObj = PointToNativeDB(o); + break; + + case Line o: + acadObj = LineToNativeDB(o); + break; + + case Arc o: + acadObj = ArcToNativeDB(o); + break; + + case Circle o: + acadObj = CircleToNativeDB(o); + break; + + case Ellipse o: + acadObj = EllipseToNativeDB(o); + break; + + case Spiral o: + acadObj = PolylineToNativeDB(o.displayValue); + break; + + case Hatch o: + acadObj = HatchToNativeDB(o); + break; + + case Polyline o: + acadObj = PolylineToNativeDB(o); + break; + + case Polycurve o: + bool convertAsSpline = (o.segments.Where(s => !(s is Line) && !(s is Arc)).Count() > 0) ? true : false; + if (convertAsSpline || !IsPolycurvePlanar(o)) + { + acadObj = PolycurveSplineToNativeDB(o); + } + else + { + acadObj = PolycurveToNativeDB(o); + } + + break; + + case Curve o: + acadObj = CurveToNativeDB(o); + break; + + /* + case Surface o: + return SurfaceToNative(o); + + */ + + case Mesh o: #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - acadObj = isFromCivil ? CivilSurfaceToNative(o) : MeshToNativeDB(o); + acadObj = isFromCivil ? CivilSurfaceToNative(o) : MeshToNativeDB(o); #else - acadObj = MeshToNativeDB(o); + acadObj = MeshToNativeDB(o); #endif - break; + break; - case Dimension o: - acadObj = isFromAutoCAD ? AcadDimensionToNative(o) : DimensionToNative(o); - break; + case Dimension o: + acadObj = isFromAutoCAD ? AcadDimensionToNative(o) : DimensionToNative(o); + break; - case Instance o: - acadObj = InstanceToNativeDB(o); - break; + case Instance o: + acadObj = InstanceToNativeDB(o); + break; - case BlockDefinition o: - acadObj = DefinitionToNativeDB(o, out notes); - break; + case BlockDefinition o: + acadObj = DefinitionToNativeDB(o, out notes); + break; - case Text o: - acadObj = isFromAutoCAD ? AcadTextToNative(o) : TextToNative(o); - break; + case Text o: + acadObj = isFromAutoCAD ? AcadTextToNative(o) : TextToNative(o); + break; - case Collection o: - acadObj = CollectionToNative(o); - break; + case Collection o: + acadObj = CollectionToNative(o); + break; #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - case Alignment o: - acadObj = AlignmentToNative(o); - break; + case Alignment o: + acadObj = AlignmentToNative(o); + break; #endif - case ModelCurve o: - acadObj = CurveToNativeDB(o.baseCurve); - break; - - case GridLine o: - acadObj = CurveToNativeDB(o.baseLine); - break; - - default: - if (reportObj != null) - { - reportObj.Update( - status: ApplicationObject.State.Skipped, - logItem: $"{@object.GetType()} type not supported" - ); - Report.UpdateReportObject(reportObj); - } - throw new NotSupportedException(); - } - - switch (acadObj) - { - case ApplicationObject o: // some to native methods return an application object (if object is baked to doc during conv) - acadObj = o.Converted.Any() ? o.Converted : null; - if (reportObj != null) - reportObj.Update( - status: o.Status, - createdIds: o.CreatedIds, - converted: o.Converted, - container: o.Container, - log: o.Log - ); - break; - default: - if (reportObj != null) - reportObj.Update(log: notes); - break; - } - if (reportObj != null) - Report.UpdateReportObject(reportObj); - return acadObj; + case ModelCurve o: + acadObj = CurveToNativeDB(o.baseCurve); + break; + + case GridLine o: + acadObj = CurveToNativeDB(o.baseLine); + break; + + default: + if (reportObj != null) + { + reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"{@object.GetType()} type not supported"); + Report.UpdateReportObject(reportObj); + } + throw new NotSupportedException(); } - public object ConvertToNativeDisplayable(Base @object) + switch (acadObj) { - throw new NotImplementedException(); + case ApplicationObject o: // some to native methods return an application object (if object is baked to doc during conv) + acadObj = o.Converted.Any() ? o.Converted : null; + if (reportObj != null) + { + reportObj.Update( + status: o.Status, + createdIds: o.CreatedIds, + converted: o.Converted, + container: o.Container, + log: o.Log + ); + } + + break; + default: + if (reportObj != null) + { + reportObj.Update(log: notes); + } + + break; } - - public List ConvertToNative(List objects) + if (reportObj != null) { - return objects.Select(x => ConvertToNative(x)).ToList(); + Report.UpdateReportObject(reportObj); } - public bool CanConvertToSpeckle(object @object) + return acadObj; + } + + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } + + public List ConvertToNative(List objects) + { + return objects.Select(x => ConvertToNative(x)).ToList(); + } + + public bool CanConvertToSpeckle(object @object) + { + switch (@object) { - switch (@object) - { - case DBObject o: - switch (o) - { - case DBPoint _: - case AcadDB.Line _: - case AcadDB.Arc _: - case AcadDB.Circle _: - case AcadDB.Dimension _: - case AcadDB.Ellipse _: - case AcadDB.Hatch _: - case AcadDB.Spline _: - case AcadDB.Polyline _: - case AcadDB.Polyline2d _: - case AcadDB.Polyline3d _: - case AcadDB.Surface _: - case AcadDB.PolyFaceMesh _: - case AcadDB.ProxyEntity _: - case AcadDB.Region _: - case SubDMesh _: - case Solid3d _: - return true; - - case BlockReference _: - case BlockTableRecord _: - case AcadDB.DBText _: - case AcadDB.MText _: - case LayerTableRecord _: - return true; + case DBObject o: + switch (o) + { + case DBPoint _: + case AcadDB.Line _: + case AcadDB.Arc _: + case AcadDB.Circle _: + case AcadDB.Dimension _: + case AcadDB.Ellipse _: + case AcadDB.Hatch _: + case AcadDB.Spline _: + case AcadDB.Polyline _: + case AcadDB.Polyline2d _: + case AcadDB.Polyline3d _: + case AcadDB.Surface _: + case AcadDB.PolyFaceMesh _: + case AcadDB.ProxyEntity _: + case AcadDB.Region _: + case SubDMesh _: + case Solid3d _: + return true; + + case BlockReference _: + case BlockTableRecord _: + case AcadDB.DBText _: + case AcadDB.MText _: + case LayerTableRecord _: + return true; #if CIVIL2021 || CIVIL2022 || CIVIL2023 || CIVIL2024 - // NOTE: C3D pressure pipes and pressure fittings API under development - case CivilDB.FeatureLine _: - case CivilDB.Corridor _: - case CivilDB.Structure _: - case CivilDB.Alignment _: - case CivilDB.Pipe _: - case CivilDB.PressurePipe _: - case CivilDB.Profile _: - case CivilDB.TinSurface _: - return true; + // NOTE: C3D pressure pipes and pressure fittings API under development + case CivilDB.FeatureLine _: + case CivilDB.Corridor _: + case CivilDB.Structure _: + case CivilDB.Alignment _: + case CivilDB.Pipe _: + case CivilDB.PressurePipe _: + case CivilDB.Profile _: + case CivilDB.TinSurface _: + return true; #endif - default: - { + default: + { #if ADVANCESTEEL - return CanConvertASToSpeckle(o); + return CanConvertASToSpeckle(o); #else - return false; + return false; #endif - } } - - case Acad.Geometry.Point3d _: - case Acad.Geometry.Vector3d _: - case Acad.Geometry.Plane _: - case Acad.Geometry.Line3d _: - case Acad.Geometry.LineSegment3d _: - case Acad.Geometry.CircularArc3d _: - case Acad.Geometry.Curve3d _: - return true; - - default: - return false; - } + } + + case Acad.Geometry.Point3d _: + case Acad.Geometry.Vector3d _: + case Acad.Geometry.Plane _: + case Acad.Geometry.Line3d _: + case Acad.Geometry.LineSegment3d _: + case Acad.Geometry.CircularArc3d _: + case Acad.Geometry.Curve3d _: + return true; + + default: + return false; } + } - public bool CanConvertToNative(Base @object) + public bool CanConvertToNative(Base @object) + { + switch (@object) { - switch (@object) - { - case Point _: - case Line _: - case Arc _: - case Circle _: - case Ellipse _: - case Spiral _: - case Hatch _: - case Polyline _: - case Polycurve _: - case Curve _: - case Mesh _: - - case Dimension _: - case BlockDefinition _: - case Instance _: - case Text _: - case Collection _: - - case Alignment _: - case ModelCurve _: - case GridLine _: - return true; - - default: - return false; - } + case Point _: + case Line _: + case Arc _: + case Circle _: + case Ellipse _: + case Spiral _: + case Hatch _: + case Polyline _: + case Polycurve _: + case Curve _: + case Mesh _: + + case Dimension _: + case BlockDefinition _: + case Instance _: + case Text _: + case Collection _: + + case Alignment _: + case ModelCurve _: + case GridLine _: + return true; + + default: + return false; } + } - public bool CanConvertToNativeDisplayable(Base @object) - { - return false; - } + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; } } diff --git a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Civil.cs b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Civil.cs index 4aaae4a8bb..ec10ccaf18 100644 --- a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Civil.cs +++ b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Civil.cs @@ -1,4 +1,4 @@ -#if (OPENROADS || OPENRAIL) +#if (OPENROADS || OPENRAIL) using Objects.Geometry; using Objects.Primitive; using Objects.Other; @@ -23,235 +23,246 @@ using Bentley.CifNET.LinearGeometry; using Bentley.CifNET.Formatting; -namespace Objects.Converter.Bentley +namespace Objects.Converter.Bentley; + +public partial class ConverterBentley { - public partial class ConverterBentley + // stations + public Station StationToSpeckle(CifGM.StationEquation station) { - // stations - public Station StationToSpeckle(CifGM.StationEquation station) - { - return null; - } + return null; + } - public Base FeatureLineToSpeckle(CifGM.FeaturizedModelEntity entity) + public Base FeatureLineToSpeckle(CifGM.FeaturizedModelEntity entity) + { + return null; + } + + // alignments + public Alignment AlignmentToSpeckle(CifGM.Alignment alignment) + { + if(alignment.FeatureDefinition is null) { - return null; + // An alignment without a feature definition is likely a partial peice of geometry being picked up erroneously upstream. + // + // This is an assumption and hasn't been tested with larger OpenRoads models so may need to be revisted. + // + throw new Exception("Skipped undefined alignment"); } - // alignments - public Alignment AlignmentToSpeckle(CifGM.Alignment alignment) - { - if(alignment.FeatureDefinition is null) - { - // An alignment without a feature definition is likely a partial peice of geometry being picked up erroneously upstream. - // - // This is an assumption and hasn't been tested with larger OpenRoads models so may need to be revisted. - // - throw new Exception("Skipped undefined alignment"); - } + var _alignment = new Alignment(); - var _alignment = new Alignment(); + CifGM.StationFormatSettings settings = CifGM.StationFormatSettings.GetStationFormatSettingsForModel(Model); + var stationFormatter = new CifGM.StationingFormatter(alignment); - CifGM.StationFormatSettings settings = CifGM.StationFormatSettings.GetStationFormatSettingsForModel(Model); - var stationFormatter = new CifGM.StationingFormatter(alignment); + _alignment.curves = TryCurveToSpeckleCurveList(alignment.Element as DisplayableElement, ModelUnits); - _alignment.curves = TryCurveToSpeckleCurveList(alignment.Element as DisplayableElement, ModelUnits); + _alignment.profiles = new List { }; - _alignment.profiles = new List { }; + // To match LandXML export behaviour we only export the Active profile + // As I understand it other profiles are likely reference and work in progress and are generally not shared + // If designer wants to share multiple profiles they can swap active profile and export to a different branch + // This behaviour would be best exposed in the editor rather than in the converter. + // + // This also avoids another issue where other profiles are likely to be a partial piece of the active profile anyway. + // Haven't tracked down how to differentiate between partial and complete profiles + // + if (alignment.ActiveProfile is CifGM.Profile p) + { + var activeProfile = ProfileToSpeckle(p, ModelUnits) as BuiltElements.Profile; + _alignment.profiles.Add(activeProfile); + } - // To match LandXML export behaviour we only export the Active profile - // As I understand it other profiles are likely reference and work in progress and are generally not shared - // If designer wants to share multiple profiles they can swap active profile and export to a different branch - // This behaviour would be best exposed in the editor rather than in the converter. - // - // This also avoids another issue where other profiles are likely to be a partial piece of the active profile anyway. - // Haven't tracked down how to differentiate between partial and complete profiles - // - if (alignment.ActiveProfile is CifGM.Profile p) - { - var activeProfile = ProfileToSpeckle(p, ModelUnits) as BuiltElements.Profile; - _alignment.profiles.Add(activeProfile); - } + if (alignment.Name != null) + { + _alignment.name = alignment.Name; + } + + if (alignment.FeatureName is string featureName) + { + _alignment[nameof(featureName)] = alignment.FeatureName; + } - if (alignment.Name != null) - _alignment.name = alignment.Name; + if (alignment.FeatureDefinition?.Name is string featureDefinitionName) + { + _alignment[nameof(featureDefinitionName)] = featureDefinitionName; + } - if (alignment.FeatureName is string featureName) - _alignment[nameof(featureName)] = alignment.FeatureName; + var stationing = alignment.Stationing; + if (stationing != null) + { + _alignment.startStation = stationing.StartStation; + _alignment.endStation = alignment.LinearGeometry.Length + stationing.StartStation; // swap for end station - if (alignment.FeatureDefinition?.Name is string featureDefinitionName) - _alignment[nameof(featureDefinitionName)] = featureDefinitionName; + var region = stationing.GetStationRegionFromDistanceAlong(stationing.StartStation); - var stationing = alignment.Stationing; - if (stationing != null) + // handle station equations + var equations = new List(); + var formattedStationEquations = new List(); + //var directions = new List(); + foreach (var stationEquation in stationing.StationEquations) { - _alignment.startStation = stationing.StartStation; - _alignment.endStation = alignment.LinearGeometry.Length + stationing.StartStation; // swap for end station + var stnVal = ""; + stationFormatter.FormatStation(ref stnVal, stationEquation.DistanceAlong, settings); + formattedStationEquations.Add(stnVal); - var region = stationing.GetStationRegionFromDistanceAlong(stationing.StartStation); + // DistanceAlong represents Back Station/BackLocation, EquivalentStation represents Ahead Station + equations.AddRange(new List { stationEquation.DistanceAlong, stationEquation.DistanceAlong, stationEquation.EquivalentStation }); - // handle station equations - var equations = new List(); - var formattedStationEquations = new List(); - //var directions = new List(); - foreach (var stationEquation in stationing.StationEquations) - { - var stnVal = ""; - stationFormatter.FormatStation(ref stnVal, stationEquation.DistanceAlong, settings); - formattedStationEquations.Add(stnVal); + } + _alignment.stationEquations = equations; + _alignment[nameof(formattedStationEquations)] = formattedStationEquations; + //_alignment.stationEquationDirections = directions; + } + else + { + _alignment.startStation = 0; + } - // DistanceAlong represents Back Station/BackLocation, EquivalentStation represents Ahead Station - equations.AddRange(new List { stationEquation.DistanceAlong, stationEquation.DistanceAlong, stationEquation.EquivalentStation }); + _alignment.units = ModelUnits; - } - _alignment.stationEquations = equations; - _alignment[nameof(formattedStationEquations)] = formattedStationEquations; - //_alignment.stationEquationDirections = directions; - } - else - { - _alignment.startStation = 0; - } + return _alignment; + } - _alignment.units = ModelUnits; + public CifGM.Alignment AlignmentToNative(Alignment alignment) + { + ICurve singleBaseCurve; - return _alignment; + if (alignment.baseCurve is ICurve basecurve) + { + singleBaseCurve = basecurve; } - - public CifGM.Alignment AlignmentToNative(Alignment alignment) + else if (alignment?.curves?.Any() is null) { - ICurve singleBaseCurve; - - if (alignment.baseCurve is ICurve basecurve) - { - singleBaseCurve = basecurve; - } - else if (alignment?.curves?.Any() is null) - { - return null; - } - else if (alignment.curves?.Count == 1) - { - singleBaseCurve = alignment.curves.Single(); - } - else + return null; + } + else if (alignment.curves?.Count == 1) + { + singleBaseCurve = alignment.curves.Single(); + } + else + { + //Not 100% clear on how best to handle the conversion between multiple curves and single element + singleBaseCurve = new Polycurve() { - //Not 100% clear on how best to handle the conversion between multiple curves and single element - singleBaseCurve = new Polycurve() - { - segments = alignment.curves - }; - } + segments = alignment.curves + }; + } - var nativeCurve = CurveToNative(singleBaseCurve); + var nativeCurve = CurveToNative(singleBaseCurve); - ConsensusConnectionEdit con = ConsensusConnectionEdit.GetActive(); - con.StartTransientMode(); - AlignmentEdit alignmentEdit = (CifGM.Alignment.CreateFromElement(con, nativeCurve)) as AlignmentEdit; - if (alignmentEdit.DomainObject == null) - return null; + ConsensusConnectionEdit con = ConsensusConnectionEdit.GetActive(); + con.StartTransientMode(); + AlignmentEdit alignmentEdit = (CifGM.Alignment.CreateFromElement(con, nativeCurve)) as AlignmentEdit; + if (alignmentEdit.DomainObject == null) + { + return null; + } - alignmentEdit.AddStationing(0, alignment.startStation, true); + alignmentEdit.AddStationing(0, alignment.startStation, true); - if (alignment.stationEquations != null) + if (alignment.stationEquations != null) + { + var formatted = (List)alignment["formattedStationEquations"]; + for (int i = 0; i < formatted.Count(); i++) { - var formatted = (List)alignment["formattedStationEquations"]; - for (int i = 0; i < formatted.Count(); i++) - { - var locationAlong = alignment.stationEquations[(i * 3) + 1]; - var ahead = formatted[i]; - alignmentEdit.AddStationEquation(ahead, locationAlong); - } + var locationAlong = alignment.stationEquations[(i * 3) + 1]; + var ahead = formatted[i]; + alignmentEdit.AddStationEquation(ahead, locationAlong); } - - con.PersistTransients(); - - return null; } - // profiles - public Base ProfileToSpeckle(CifGM.Profile profile, string modelUnits = "m") - { - var curves = new List(); + con.PersistTransients(); + return null; + } + // profiles + public Base ProfileToSpeckle(CifGM.Profile profile, string modelUnits = "m") + { + var curves = new List(); - switch (profile.ProfileGeometry) - { - case ProfileParabola profileParabola: - - /// This has thrown exceptions in the past, but should be resolved now that only - /// the active profile is being exported, as it was throwing on isolated curve - /// elements with no assigned feature properties. - /// - /// Pulled out as its own case so it's a bit clearer why the failure is happening - /// if it reoccurs. - - try - { - curves.AddRange(TryCurveToSpeckleCurveList(profile.Element as DisplayableElement, modelUnits)); - break; - } - catch (Exception ex) - { - throw new Exception("Failed to import isolated profile Parabola", ex); - } - - default: - curves.AddRange(TryCurveToSpeckleCurveList(profile.Element as DisplayableElement, modelUnits)); - break; - } - var outProfile = new BuiltElements.Profile - { - curves = curves, - name = profile.Name, - startStation = profile.ProfileGeometry.StartPoint.Coordinates.X, - endStation = profile.ProfileGeometry.EndPoint.Coordinates.X, - }; - if (profile.FeatureName is string featureName) - outProfile[nameof(featureName)] = featureName; + switch (profile.ProfileGeometry) + { + case ProfileParabola profileParabola: + + /// This has thrown exceptions in the past, but should be resolved now that only + /// the active profile is being exported, as it was throwing on isolated curve + /// elements with no assigned feature properties. + /// + /// Pulled out as its own case so it's a bit clearer why the failure is happening + /// if it reoccurs. - if (profile.FeatureDefinition?.Name is string featureDefinitionName) - outProfile[nameof(featureDefinitionName)] = featureDefinitionName; + try + { + curves.AddRange(TryCurveToSpeckleCurveList(profile.Element as DisplayableElement, modelUnits)); + break; + } + catch (Exception ex) + { + throw new Exception("Failed to import isolated profile Parabola", ex); + } - return outProfile; + default: + curves.AddRange(TryCurveToSpeckleCurveList(profile.Element as DisplayableElement, modelUnits)); + break; } - // corridors - public Base CorridorToSpeckle(CifGM.Corridor corridor) + var outProfile = new BuiltElements.Profile { - var element = corridor.Element; - var _corridor = ConvertToSpeckle(element) as Base; + curves = curves, + name = profile.Name, + startStation = profile.ProfileGeometry.StartPoint.Coordinates.X, + endStation = profile.ProfileGeometry.EndPoint.Coordinates.X, + }; - var alignment = corridor.CorridorAlignment; - if (alignment != null) - { - var convertedAlignment = AlignmentToSpeckle(alignment); - _corridor["alignment"] = convertedAlignment; - } + if (profile.FeatureName is string featureName) + { + outProfile[nameof(featureName)] = featureName; + } - var stations = corridor.KeyStations; - var profile = corridor.CorridorProfile; - var surfaces = corridor.CorridorSurfaces; + if (profile.FeatureDefinition?.Name is string featureDefinitionName) + { + outProfile[nameof(featureDefinitionName)] = featureDefinitionName; + } - if (corridor.Name != null) - _corridor["name"] = corridor.Name; + return outProfile; + } - _corridor["units"] = ModelUnits; + // corridors + public Base CorridorToSpeckle(CifGM.Corridor corridor) + { + var element = corridor.Element; + var _corridor = ConvertToSpeckle(element) as Base; - return _corridor; + var alignment = corridor.CorridorAlignment; + if (alignment != null) + { + var convertedAlignment = AlignmentToSpeckle(alignment); + _corridor["alignment"] = convertedAlignment; } - public Point LinearPointToSpeckle(LinearPoint pt, string units = null) + var stations = corridor.KeyStations; + var profile = corridor.CorridorProfile; + var surfaces = corridor.CorridorSurfaces; + + if (corridor.Name != null) { - var u = units ?? ModelUnits; - return new Point(ScaleToSpeckle(pt.DistanceAlong, UoR), ScaleToSpeckle(pt.Offset, UoR), 0, u); + _corridor["name"] = corridor.Name; } - } + _corridor["units"] = ModelUnits; + + return _corridor; + } + public Point LinearPointToSpeckle(LinearPoint pt, string units = null) + { + var u = units ?? ModelUnits; + return new Point(ScaleToSpeckle(pt.DistanceAlong, UoR), ScaleToSpeckle(pt.Offset, UoR), 0, u); + } } #endif diff --git a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Geometry.cs b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Geometry.cs index 6342fbdd0c..6670027748 100644 --- a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Geometry.cs +++ b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Geometry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -26,1758 +26,1865 @@ using Surface = Objects.Geometry.Surface; using Vector = Objects.Geometry.Vector; -namespace Objects.Converter.Bentley -{ - public partial class ConverterBentley - { - public double tolerance = 0.000; // tolerance for geometry - - public double[] PointToArray(DPoint2d pt) - { - return new double[] { pt.X, pt.Y, 0 }; - } - public double[] PointToArray(DPoint3d pt) - { - return new double[] { ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR) }; - } +namespace Objects.Converter.Bentley; - public DPoint3d[] PointListToNative(IEnumerable arr, string units) - { - var enumerable = arr.ToList(); - if (enumerable.Count % 3 != 0) throw new Speckle.Core.Logging.SpeckleException("Array malformed: length%3 != 0."); - - DPoint3d[] points = new DPoint3d[enumerable.Count / 3]; - var asArray = enumerable.ToArray(); - for (int i = 2, k = 0; i < enumerable.Count; i += 3) - points[k++] = new DPoint3d( - ScaleToNative(asArray[i - 2], units, UoR), - ScaleToNative(asArray[i - 1], units, UoR), - ScaleToNative(asArray[i], units, UoR)); - - return points; - } +public partial class ConverterBentley +{ + public double tolerance = 0.000; // tolerance for geometry - public List PointsToFlatList(IEnumerable points) - { - return points.SelectMany(pt => PointToArray(pt)).ToList(); - } + public double[] PointToArray(DPoint2d pt) + { + return new double[] { pt.X, pt.Y, 0 }; + } - public List PointsToFlatList(IEnumerable points) - { - return points.SelectMany(pt => PointToArray(pt)).ToList(); - } + public double[] PointToArray(DPoint3d pt) + { + return new double[] { ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR) }; + } - // Point (2d and 3d) - public Point Point2dToSpeckle(DPoint2d pt, string units = null) + public DPoint3d[] PointListToNative(IEnumerable arr, string units) + { + var enumerable = arr.ToList(); + if (enumerable.Count % 3 != 0) { - var u = units ?? ModelUnits; - return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), 0, u); + throw new Speckle.Core.Logging.SpeckleException("Array malformed: length%3 != 0."); } - public Point Point2dToSpeckle(Point2d pt, string units = null) + DPoint3d[] points = new DPoint3d[enumerable.Count / 3]; + var asArray = enumerable.ToArray(); + for (int i = 2, k = 0; i < enumerable.Count; i += 3) { - var u = units ?? ModelUnits; - return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), 0, u); + points[k++] = new DPoint3d( + ScaleToNative(asArray[i - 2], units, UoR), + ScaleToNative(asArray[i - 1], units, UoR), + ScaleToNative(asArray[i], units, UoR) + ); } - public DPoint2d Point2dToNative(Point pt) - { - var myPoint = new DPoint2d( - ScaleToNative(pt.x, pt.units, UoR), - ScaleToNative(pt.y, pt.units, UoR)); - - return myPoint; - } + return points; + } - public Point Point3dToSpeckle(DPoint3d pt, string units = null) - { - var u = units ?? ModelUnits; - return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR), u); - } + public List PointsToFlatList(IEnumerable points) + { + return points.SelectMany(pt => PointToArray(pt)).ToList(); + } - public Point Point3dToSpeckle(Point3d pt, string units = null) - { - var u = units ?? ModelUnits; - return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR), u); - } + public List PointsToFlatList(IEnumerable points) + { + return points.SelectMany(pt => PointToArray(pt)).ToList(); + } - public DPoint3d Point3dToNative(Point pt) - { - var myPoint = new DPoint3d( - ScaleToNative(pt.x, pt.units, UoR), - ScaleToNative(pt.y, pt.units, UoR), - ScaleToNative(pt.z, pt.units, UoR)); + // Point (2d and 3d) + public Point Point2dToSpeckle(DPoint2d pt, string units = null) + { + var u = units ?? ModelUnits; + return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), 0, u); + } - return myPoint; - } + public Point Point2dToSpeckle(Point2d pt, string units = null) + { + var u = units ?? ModelUnits; + return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), 0, u); + } - public LineElement PointToNative(Point pt) - { - DSegment3d dSegment = new DSegment3d(Point3dToNative(pt), Point3dToNative(pt)); - var _line = new LineElement(Model, null, dSegment); - return _line; - } + public DPoint2d Point2dToNative(Point pt) + { + var myPoint = new DPoint2d(ScaleToNative(pt.x, pt.units, UoR), ScaleToNative(pt.y, pt.units, UoR)); - // Vector (2d and 3d) - public Vector Vector2dToSpeckle(DVector2d pt, string units = null) - { - return new Vector(pt.X, pt.Y, units ?? ModelUnits); - } + return myPoint; + } - public DVector2d Vector2dToNative(Vector pt) - { - return new DVector2d( - ScaleToNative(pt.x, pt.units, UoR), - ScaleToNative(pt.y, pt.units, UoR)); - } + public Point Point3dToSpeckle(DPoint3d pt, string units = null) + { + var u = units ?? ModelUnits; + return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR), u); + } - public Vector Vector3dToSpeckle(DVector3d pt, string units = null) - { - return new Vector(pt.X, pt.Y, pt.Z, units ?? ModelUnits); - } + public Point Point3dToSpeckle(Point3d pt, string units = null) + { + var u = units ?? ModelUnits; + return new Point(ScaleToSpeckle(pt.X, UoR), ScaleToSpeckle(pt.Y, UoR), ScaleToSpeckle(pt.Z, UoR), u); + } - public DVector3d VectorToNative(Vector pt) - { - return new DVector3d( - ScaleToNative(pt.x, pt.units, UoR), - ScaleToNative(pt.y, pt.units, UoR), - ScaleToNative(pt.z, pt.units, UoR)); - } + public DPoint3d Point3dToNative(Point pt) + { + var myPoint = new DPoint3d( + ScaleToNative(pt.x, pt.units, UoR), + ScaleToNative(pt.y, pt.units, UoR), + ScaleToNative(pt.z, pt.units, UoR) + ); - // Interval - public Interval IntervalToSpeckle(DRange1d range) - { - return new Interval(ScaleToSpeckle(range.Low, UoR), ScaleToSpeckle(range.High, UoR)); - } + return myPoint; + } - public Interval IntervalToSpeckle(DSegment1d segment) - { - return new Interval(ScaleToSpeckle(segment.Start, UoR), ScaleToSpeckle(segment.End, UoR)); - } + public LineElement PointToNative(Point pt) + { + DSegment3d dSegment = new(Point3dToNative(pt), Point3dToNative(pt)); + var _line = new LineElement(Model, null, dSegment); + return _line; + } - public DRange1d IntervalToNative(Interval interval) - { - return DRange1d.From(ScaleToNative((double)interval.start, ModelUnits, UoR), ScaleToNative((double)interval.end, ModelUnits, UoR)); - } + // Vector (2d and 3d) + public Vector Vector2dToSpeckle(DVector2d pt, string units = null) + { + return new Vector(pt.X, pt.Y, units ?? ModelUnits); + } - public Interval2d Interval2dToSpeckle(DRange2d range) - { - var u = new Interval(range.Low.X, range.Low.Y); - var v = new Interval(range.High.X, range.High.Y); - return new Interval2d(u, v); - } + public DVector2d Vector2dToNative(Vector pt) + { + return new DVector2d(ScaleToNative(pt.x, pt.units, UoR), ScaleToNative(pt.y, pt.units, UoR)); + } - public DRange2d Interval2dToNative(Interval2d interval) - { - var u = new DPoint2d((double)interval.u.start, (double)interval.u.end); - var v = new DPoint2d((double)interval.v.start, (double)interval.v.end); ; - return DRange2d.FromPoints(u, v); - } + public Vector Vector3dToSpeckle(DVector3d pt, string units = null) + { + return new Vector(pt.X, pt.Y, pt.Z, units ?? ModelUnits); + } - // Plane - public Plane PlaneToSpeckle(DPlane3d plane, string units = null) - { - DPoint3d origin = plane.Origin; - DVector3d normal = plane.Normal; + public DVector3d VectorToNative(Vector pt) + { + return new DVector3d( + ScaleToNative(pt.x, pt.units, UoR), + ScaleToNative(pt.y, pt.units, UoR), + ScaleToNative(pt.z, pt.units, UoR) + ); + } - DVector3d xAxis = DVector3d.UnitY.CrossProduct(plane.Normal); - DVector3d yAxis = normal.CrossProduct(xAxis); + // Interval + public Interval IntervalToSpeckle(DRange1d range) + { + return new Interval(ScaleToSpeckle(range.Low, UoR), ScaleToSpeckle(range.High, UoR)); + } - var u = units ?? ModelUnits; - var _plane = new Plane(Point3dToSpeckle(origin), Vector3dToSpeckle(normal), Vector3dToSpeckle(xAxis), Vector3dToSpeckle(yAxis), u); - return _plane; - } + public Interval IntervalToSpeckle(DSegment1d segment) + { + return new Interval(ScaleToSpeckle(segment.Start, UoR), ScaleToSpeckle(segment.End, UoR)); + } - public Plane PlaneToSpeckle(DPoint3d pt1, DPoint3d pt2, DPoint3d pt3, string units = null) - { - DPoint3d origin = pt1; + public DRange1d IntervalToNative(Interval interval) + { + return DRange1d.From( + ScaleToNative((double)interval.start, ModelUnits, UoR), + ScaleToNative((double)interval.end, ModelUnits, UoR) + ); + } - var v1 = new DVector3d(pt2.X - pt1.X, pt2.Y - pt1.Y, pt2.Z - pt1.Z); - var v2 = new DVector3d(pt3.X - pt1.X, pt3.Y - pt1.Y, pt3.Z - pt1.Z); - var cross = v1.CrossProduct(v2); + public Interval2d Interval2dToSpeckle(DRange2d range) + { + var u = new Interval(range.Low.X, range.Low.Y); + var v = new Interval(range.High.X, range.High.Y); + return new Interval2d(u, v); + } - cross.TryNormalize(out DVector3d normal); + public DRange2d Interval2dToNative(Interval2d interval) + { + var u = new DPoint2d((double)interval.u.start, (double)interval.u.end); + var v = new DPoint2d((double)interval.v.start, (double)interval.v.end); + ; + return DRange2d.FromPoints(u, v); + } - DVector3d xAxis = DVector3d.UnitY.CrossProduct(normal); - DVector3d yAxis = normal.CrossProduct(xAxis); + // Plane + public Plane PlaneToSpeckle(DPlane3d plane, string units = null) + { + DPoint3d origin = plane.Origin; + DVector3d normal = plane.Normal; + + DVector3d xAxis = DVector3d.UnitY.CrossProduct(plane.Normal); + DVector3d yAxis = normal.CrossProduct(xAxis); + + var u = units ?? ModelUnits; + var _plane = new Plane( + Point3dToSpeckle(origin), + Vector3dToSpeckle(normal), + Vector3dToSpeckle(xAxis), + Vector3dToSpeckle(yAxis), + u + ); + return _plane; + } - var u = units ?? ModelUnits; - var _plane = new Plane(Point3dToSpeckle(origin), Vector3dToSpeckle(normal), Vector3dToSpeckle(xAxis), Vector3dToSpeckle(yAxis), u); - return _plane; - } + public Plane PlaneToSpeckle(DPoint3d pt1, DPoint3d pt2, DPoint3d pt3, string units = null) + { + DPoint3d origin = pt1; + + var v1 = new DVector3d(pt2.X - pt1.X, pt2.Y - pt1.Y, pt2.Z - pt1.Z); + var v2 = new DVector3d(pt3.X - pt1.X, pt3.Y - pt1.Y, pt3.Z - pt1.Z); + var cross = v1.CrossProduct(v2); + + cross.TryNormalize(out DVector3d normal); + + DVector3d xAxis = DVector3d.UnitY.CrossProduct(normal); + DVector3d yAxis = normal.CrossProduct(xAxis); + + var u = units ?? ModelUnits; + var _plane = new Plane( + Point3dToSpeckle(origin), + Vector3dToSpeckle(normal), + Vector3dToSpeckle(xAxis), + Vector3dToSpeckle(yAxis), + u + ); + return _plane; + } - public DPlane3d PlaneToNative(Plane plane) - { - return new DPlane3d(Point3dToNative(plane.origin), VectorToNative(plane.normal)); - } + public DPlane3d PlaneToNative(Plane plane) + { + return new DPlane3d(Point3dToNative(plane.origin), VectorToNative(plane.normal)); + } - // Line (when the start and end point are the same, return line as point) - public Base LineToSpeckle(LineElement line, string units = null) + // Line (when the start and end point are the same, return line as point) + public Base LineToSpeckle(LineElement line, string units = null) + { + CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(line); + if (q != null) { - CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(line); - if (q != null) + CurveVector vec = q.GetCurveVector(); + if (vec != null) { - CurveVector vec = q.GetCurveVector(); - if (vec != null) - { - vec.GetStartEnd(out DPoint3d startPoint, out DPoint3d endPoint); - if (startPoint == endPoint) - return Point3dToSpeckle(startPoint, units); + vec.GetStartEnd(out DPoint3d startPoint, out DPoint3d endPoint); + if (startPoint == endPoint) + { + return Point3dToSpeckle(startPoint, units); + } - double length = vec.SumOfLengths() / UoR; + double length = vec.SumOfLengths() / UoR; - var u = units ?? ModelUnits; - var _line = new Line(Point3dToSpeckle(startPoint), Point3dToSpeckle(endPoint), u); - _line.length = length; - _line.domain = new Interval(0, length); + var u = units ?? ModelUnits; + var _line = new Line(Point3dToSpeckle(startPoint), Point3dToSpeckle(endPoint), u); + _line.length = length; + _line.domain = new Interval(0, length); - vec.GetRange(out var range); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _line.bbox = BoxToSpeckle(range, worldXY); + vec.GetRange(out var range); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _line.bbox = BoxToSpeckle(range, worldXY); - return _line; - } + return _line; } - - return new Line(); } - public Line LineToSpeckle(DSegment3d line, string units = null) - { - var u = units ?? ModelUnits; - var _line = new Line(Point3dToSpeckle(line.StartPoint), Point3dToSpeckle(line.EndPoint), u); - _line.length = line.Length; - _line.domain = new Interval(0, line.Length); + return new Line(); + } - var range = DRange3d.FromPoints(line.StartPoint, line.EndPoint); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _line.bbox = BoxToSpeckle(range, worldXY); + public Line LineToSpeckle(DSegment3d line, string units = null) + { + var u = units ?? ModelUnits; + var _line = new Line(Point3dToSpeckle(line.StartPoint), Point3dToSpeckle(line.EndPoint), u); + _line.length = line.Length; + _line.domain = new Interval(0, line.Length); - return _line; - } + var range = DRange3d.FromPoints(line.StartPoint, line.EndPoint); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _line.bbox = BoxToSpeckle(range, worldXY); - public LineElement LineToNative(Line line) - { - DSegment3d dSegment = new DSegment3d(Point3dToNative(line.start), Point3dToNative(line.end)); - var _line = new LineElement(Model, null, dSegment); - return _line; - } + return _line; + } - // All arcs - public ICurve ArcToSpeckle(ArcElement arc, string units = null) - { - double axisRatio = GetElementProperty(arc, "AxisRatio").DoubleValue; + public LineElement LineToNative(Line line) + { + DSegment3d dSegment = new(Point3dToNative(line.start), Point3dToNative(line.end)); + var _line = new LineElement(Model, null, dSegment); + return _line; + } - CurveVector vec = arc.GetCurveVector(); - vec.GetStartEnd(out DPoint3d startPoint, out DPoint3d endPoint); + // All arcs + public ICurve ArcToSpeckle(ArcElement arc, string units = null) + { + double axisRatio = GetElementProperty(arc, "AxisRatio").DoubleValue; - if (axisRatio == 1) + CurveVector vec = arc.GetCurveVector(); + vec.GetStartEnd(out DPoint3d startPoint, out DPoint3d endPoint); + + if (axisRatio == 1) + { + if (startPoint == endPoint) { - if (startPoint == endPoint) - { - return CircleToSpeckle(arc, units); - } - else - { - return CircularArcToSpeckle(arc, units); // Axis 1 == Axis 2 - } + return CircleToSpeckle(arc, units); } else { - return EllipticArcToSpeckle(arc, units); // Axis 1 != Axis 2 (return Curve instead of Arc) + return CircularArcToSpeckle(arc, units); // Axis 1 == Axis 2 } } - - - public ICurve ArcToSpeckle(DEllipse3d ellipse, string units = null) + else { - ellipse.GetMajorMinorData(out DPoint3d center, out DMatrix3d matrix, out double majorAxis, out double minorAxis, out Angle startAngle, out Angle endAngle); - var startPoint = ellipse.PointAtAngle(startAngle); - var endPoint = ellipse.PointAtAngle(endAngle); - var axisRatio = majorAxis / minorAxis; + return EllipticArcToSpeckle(arc, units); // Axis 1 != Axis 2 (return Curve instead of Arc) + } + } - if (axisRatio == 1) + public ICurve ArcToSpeckle(DEllipse3d ellipse, string units = null) + { + ellipse.GetMajorMinorData( + out DPoint3d center, + out DMatrix3d matrix, + out double majorAxis, + out double minorAxis, + out Angle startAngle, + out Angle endAngle + ); + var startPoint = ellipse.PointAtAngle(startAngle); + var endPoint = ellipse.PointAtAngle(endAngle); + var axisRatio = majorAxis / minorAxis; + + if (axisRatio == 1) + { + if (startPoint == endPoint) { - if (startPoint == endPoint) - { - return CircleToSpeckle(ellipse, units); - } - else - { - return CircularArcToSpeckle(ellipse, units); // Axis 1 == Axis 2 - } + return CircleToSpeckle(ellipse, units); } else { - return EllipticArcToSpeckle(ellipse, units); // Axis 1 != Axis 2 (return Curve instead of Arc) + return CircularArcToSpeckle(ellipse, units); // Axis 1 == Axis 2 } } - - // Arc - public Arc CircularArcToSpeckle(ArcElement arc, string units = null) + else { - var u = units ?? ModelUnits; + return EllipticArcToSpeckle(ellipse, units); // Axis 1 != Axis 2 (return Curve instead of Arc) + } + } + + // Arc + public Arc CircularArcToSpeckle(ArcElement arc, string units = null) + { + var u = units ?? ModelUnits; - CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(arc); - if (q != null) + CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(arc); + if (q != null) + { + CurveVector vec = q.GetCurveVector(); + if (vec != null) { - CurveVector vec = q.GetCurveVector(); - if (vec != null) + vec.GetStartEnd( + out DPoint3d startPoint, + out DPoint3d endPoint, + out DVector3d startTangent, + out DVector3d endTangent + ); + + double length = vec.SumOfLengths(); + double radius = GetElementProperty(arc, "Radius").DoubleValue / UoR; + + // in MicroStation, positive angle is measured in CCW direction + double startAngle = GetElementProperty(arc, "StartAngle").DoubleValue; + double endAngle = GetElementProperty(arc, "EndAngle").DoubleValue; + double sweep = GetElementProperty(arc, "SweepAngle").DoubleValue; + DPoint3d center = (DPoint3d)GetElementProperty(arc, "Center").NativeValue; + DPoint3d normal = (DPoint3d)GetElementProperty(arc, "Normal").NativeValue; + DPlane3d plane = new(center, new DVector3d(normal)); + + // an additional arc rotation can be applied in MicroStation, need to rotate the start/end points to correspond to this rotation before conversion + double rotation = GetElementProperty(arc, "RotationAngle").DoubleValue; + startAngle = rotation + startAngle; + endAngle = rotation + endAngle; + + // arc rotation can also be specified about each axis + var rotationX = GetElementProperty(arc, "RotationX"); + var rotationY = GetElementProperty(arc, "RotationY"); + var rotationZ = GetElementProperty(arc, "RotationZ"); + + if (rotationX != null) { - vec.GetStartEnd(out DPoint3d startPoint, out DPoint3d endPoint, out DVector3d startTangent, out DVector3d endTangent); - - double length = vec.SumOfLengths(); - double radius = GetElementProperty(arc, "Radius").DoubleValue / UoR; - - // in MicroStation, positive angle is measured in CCW direction - double startAngle = GetElementProperty(arc, "StartAngle").DoubleValue; - double endAngle = GetElementProperty(arc, "EndAngle").DoubleValue; - double sweep = GetElementProperty(arc, "SweepAngle").DoubleValue; - DPoint3d center = (DPoint3d)GetElementProperty(arc, "Center").NativeValue; - DPoint3d normal = (DPoint3d)GetElementProperty(arc, "Normal").NativeValue; - DPlane3d plane = new DPlane3d(center, new DVector3d(normal)); - - // an additional arc rotation can be applied in MicroStation, need to rotate the start/end points to correspond to this rotation before conversion - double rotation = GetElementProperty(arc, "RotationAngle").DoubleValue; - startAngle = rotation + startAngle; - endAngle = rotation + endAngle; - - // arc rotation can also be specified about each axis - var rotationX = GetElementProperty(arc, "RotationX"); - var rotationY = GetElementProperty(arc, "RotationY"); - var rotationZ = GetElementProperty(arc, "RotationZ"); - - if (rotationX != null) - { - startAngle = rotationX.DoubleValue + startAngle; - endAngle = rotationX.DoubleValue + endAngle; - } - else if (rotationY != null) - { - startAngle = -rotationY.DoubleValue + startAngle; - endAngle = -rotationY.DoubleValue + endAngle; - } - else if (rotationZ != null) - { - startAngle = rotationZ.DoubleValue + startAngle; - endAngle = rotationZ.DoubleValue + endAngle; - } + startAngle = rotationX.DoubleValue + startAngle; + endAngle = rotationX.DoubleValue + endAngle; + } + else if (rotationY != null) + { + startAngle = -rotationY.DoubleValue + startAngle; + endAngle = -rotationY.DoubleValue + endAngle; + } + else if (rotationZ != null) + { + startAngle = rotationZ.DoubleValue + startAngle; + endAngle = rotationZ.DoubleValue + endAngle; + } - var _arc = new Arc(); + var _arc = new Arc(); - _arc.radius = radius; + _arc.radius = radius; - _arc.angleRadians = Math.Abs(sweep); - _arc.startPoint = Point3dToSpeckle(startPoint); - _arc.endPoint = Point3dToSpeckle(endPoint); - _arc.units = u; + _arc.angleRadians = Math.Abs(sweep); + _arc.startPoint = Point3dToSpeckle(startPoint); + _arc.endPoint = Point3dToSpeckle(endPoint); + _arc.units = u; - if (sweep < 0) - { - plane.NegateNormalInPlace(); - } + if (sweep < 0) + { + plane.NegateNormalInPlace(); + } - _arc.startAngle = startAngle; - _arc.endAngle = endAngle; - _arc.plane = PlaneToSpeckle(plane); + _arc.startAngle = startAngle; + _arc.endAngle = endAngle; + _arc.plane = PlaneToSpeckle(plane); - CurveLocationDetail curveLoc = vec.GetPrimitive(0).PointAtSignedDistanceFromFraction(0, length / 2, false); - var midPoint = curveLoc.Point; - _arc.midPoint = Point3dToSpeckle(midPoint); + CurveLocationDetail curveLoc = vec.GetPrimitive(0).PointAtSignedDistanceFromFraction(0, length / 2, false); + var midPoint = curveLoc.Point; + _arc.midPoint = Point3dToSpeckle(midPoint); - _arc.length = length / UoR; - _arc.domain = new Interval(0, length / UoR); + _arc.length = length / UoR; + _arc.domain = new Interval(0, length / UoR); - vec.GetRange(out var range); - bool worldXY = startPoint.Z == 0 && endPoint.Z == 0 ? true : false; - _arc.bbox = BoxToSpeckle(range, worldXY); + vec.GetRange(out var range); + bool worldXY = startPoint.Z == 0 && endPoint.Z == 0 ? true : false; + _arc.bbox = BoxToSpeckle(range, worldXY); - //if (sweep < 0) - //{ - // Point start = _arc.endPoint; - // _arc.endPoint = _arc.startPoint; - // _arc.startPoint = start; + //if (sweep < 0) + //{ + // Point start = _arc.endPoint; + // _arc.endPoint = _arc.startPoint; + // _arc.startPoint = start; - // _arc.startAngle = endAngle; - // _arc.endAngle = startAngle; - //} + // _arc.startAngle = endAngle; + // _arc.endAngle = startAngle; + //} - return _arc; - } + return _arc; } - - return new Arc(); } - public Arc CircularArcToSpeckle(DEllipse3d ellipse, string units = null) - { - ellipse.IsCircular(out double radius, out DVector3d normal); - - var sweep = ellipse.SweepAngle.Radians; - var startAngle = ellipse.StartAngle.Radians; - var endAngle = ellipse.EndAngle.Radians; - var center = ellipse.Center; - - var startPoint = ellipse.PointAtAngle(ellipse.StartAngle); - var endPoint = ellipse.PointAtAngle(ellipse.EndAngle); - var midPoint = ellipse.PointAtAngle(ellipse.StartAngle + Angle.Multiply(ellipse.SweepAngle, 0.5)); - - var length = ellipse.ArcLength(); - - var range = DRange3d.FromEllipse(ellipse); - DPlane3d plane = new DPlane3d(center, normal); + return new Arc(); + } - var _arc = new Arc(); - _arc.radius = radius / UoR; - _arc.angleRadians = Math.Abs(sweep); - _arc.startPoint = Point3dToSpeckle(startPoint); - _arc.endPoint = Point3dToSpeckle(endPoint); - _arc.midPoint = Point3dToSpeckle(midPoint); - _arc.units = units ?? ModelUnits; + public Arc CircularArcToSpeckle(DEllipse3d ellipse, string units = null) + { + ellipse.IsCircular(out double radius, out DVector3d normal); - if (sweep < 0) - { - plane.NegateNormalInPlace(); - } + var sweep = ellipse.SweepAngle.Radians; + var startAngle = ellipse.StartAngle.Radians; + var endAngle = ellipse.EndAngle.Radians; + var center = ellipse.Center; - _arc.startAngle = startAngle; - _arc.endAngle = endAngle; - _arc.plane = PlaneToSpeckle(plane); + var startPoint = ellipse.PointAtAngle(ellipse.StartAngle); + var endPoint = ellipse.PointAtAngle(ellipse.EndAngle); + var midPoint = ellipse.PointAtAngle(ellipse.StartAngle + Angle.Multiply(ellipse.SweepAngle, 0.5)); - _arc.length = length / UoR; - _arc.domain = new Interval(0, length / UoR); + var length = ellipse.ArcLength(); - bool worldXY = startPoint.Z == 0 && endPoint.Z == 0 ? true : false; - _arc.bbox = BoxToSpeckle(range, worldXY); + var range = DRange3d.FromEllipse(ellipse); + DPlane3d plane = new(center, normal); - return _arc; - } + var _arc = new Arc(); + _arc.radius = radius / UoR; + _arc.angleRadians = Math.Abs(sweep); + _arc.startPoint = Point3dToSpeckle(startPoint); + _arc.endPoint = Point3dToSpeckle(endPoint); + _arc.midPoint = Point3dToSpeckle(midPoint); + _arc.units = units ?? ModelUnits; - // Elliptic arc - public Curve EllipticArcToSpeckle(ArcElement arc, string units = null) + if (sweep < 0) { - var vec = arc.GetCurveVector(); - var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element + plane.NegateNormalInPlace(); + } - primitive.TryGetArc(out DEllipse3d curve); + _arc.startAngle = startAngle; + _arc.endAngle = endAngle; + _arc.plane = PlaneToSpeckle(plane); - var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref curve); - var _splineElement = new BSplineCurveElement(Model, null, _spline); + _arc.length = length / UoR; + _arc.domain = new Interval(0, length / UoR); - return BSplineCurveToSpeckle(_splineElement, units); - } + bool worldXY = startPoint.Z == 0 && endPoint.Z == 0 ? true : false; + _arc.bbox = BoxToSpeckle(range, worldXY); - public Curve EllipticArcToSpeckle(DEllipse3d ellipse, string units = null) - { - var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref ellipse); - var _splineElement = new BSplineCurveElement(Model, null, _spline); + return _arc; + } - return BSplineCurveToSpeckle(_splineElement, units); - } + // Elliptic arc + public Curve EllipticArcToSpeckle(ArcElement arc, string units = null) + { + var vec = arc.GetCurveVector(); + var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element - public ArcElement ArcToNative(Arc arc) - { - var radius = (double)arc.radius; - var startAngle = (double)arc.startAngle; - var endAngle = (double)arc.endAngle; - var center = Point3dToNative(arc.plane.origin); + primitive.TryGetArc(out DEllipse3d curve); - DEllipse3d.TryCircularArcFromStartMiddleEnd(Point3dToNative(arc.startPoint), Point3dToNative(arc.midPoint), Point3dToNative(arc.endPoint), out DEllipse3d ellipse); + var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref curve); + var _splineElement = new BSplineCurveElement(Model, null, _spline); - var _arc = new ArcElement(Model, null, ellipse); - return _arc; - } + return BSplineCurveToSpeckle(_splineElement, units); + } - // Ellipse - public Ellipse EllipseWithoutRotationToSpeckle(EllipseElement ellipse, string units = null) - { - double length = ellipse.GetCurveVector().SumOfLengths() / UoR; - double axis1 = GetElementProperty(ellipse, "PrimaryAxis").DoubleValue / UoR; - double axis2 = GetElementProperty(ellipse, "SecondaryAxis").DoubleValue / UoR; + public Curve EllipticArcToSpeckle(DEllipse3d ellipse, string units = null) + { + var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref ellipse); + var _splineElement = new BSplineCurveElement(Model, null, _spline); - var vec = ellipse.GetCurveVector(); - vec.GetRange(out DRange3d range); - vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); + return BSplineCurveToSpeckle(_splineElement, units); + } - DPlane3d plane = new DPlane3d(center, new DVector3d(normal)); + public ArcElement ArcToNative(Arc arc) + { + var radius = (double)arc.radius; + var startAngle = (double)arc.startAngle; + var endAngle = (double)arc.endAngle; + var center = Point3dToNative(arc.plane.origin); + + DEllipse3d.TryCircularArcFromStartMiddleEnd( + Point3dToNative(arc.startPoint), + Point3dToNative(arc.midPoint), + Point3dToNative(arc.endPoint), + out DEllipse3d ellipse + ); + + var _arc = new ArcElement(Model, null, ellipse); + return _arc; + } - var u = units ?? ModelUnits; - var _ellipse = new Ellipse(PlaneToSpeckle(plane), axis1, axis2, u); - _ellipse.domain = new Interval(0, length); - _ellipse.length = length; + // Ellipse + public Ellipse EllipseWithoutRotationToSpeckle(EllipseElement ellipse, string units = null) + { + double length = ellipse.GetCurveVector().SumOfLengths() / UoR; + double axis1 = GetElementProperty(ellipse, "PrimaryAxis").DoubleValue / UoR; + double axis2 = GetElementProperty(ellipse, "SecondaryAxis").DoubleValue / UoR; - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _ellipse.bbox = BoxToSpeckle(range, worldXY); + var vec = ellipse.GetCurveVector(); + vec.GetRange(out DRange3d range); + vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); - _ellipse.area = area / Math.Pow(UoR, 2); + DPlane3d plane = new(center, new DVector3d(normal)); - return _ellipse; - } + var u = units ?? ModelUnits; + var _ellipse = new Ellipse(PlaneToSpeckle(plane), axis1, axis2, u); + _ellipse.domain = new Interval(0, length); + _ellipse.length = length; - public EllipseElement EllipseToNative(Ellipse ellipse) - { - var plane = PlaneToNative(ellipse.plane); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _ellipse.bbox = BoxToSpeckle(range, worldXY); - DPlacementZX placement = new DPlacementZX(plane.Origin); - var e = new DEllipse3d(placement, (double)ellipse.firstRadius, (double)ellipse.secondRadius, Angle.Zero, Angle.TWOPI); - var _ellipse = new EllipseElement(Model, null, e); + _ellipse.area = area / Math.Pow(UoR, 2); - return _ellipse; - } + return _ellipse; + } - // Ellipse element with rotation (converted to curve) - public Curve EllipseWithRotationToSpeckle(EllipseElement ellipse, string units = null) - { - var vec = ellipse.GetCurveVector(); - var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element + public EllipseElement EllipseToNative(Ellipse ellipse) + { + var plane = PlaneToNative(ellipse.plane); + + DPlacementZX placement = new(plane.Origin); + var e = new DEllipse3d( + placement, + (double)ellipse.firstRadius, + (double)ellipse.secondRadius, + Angle.Zero, + Angle.TWOPI + ); + var _ellipse = new EllipseElement(Model, null, e); + + return _ellipse; + } - primitive.TryGetArc(out DEllipse3d curve); + // Ellipse element with rotation (converted to curve) + public Curve EllipseWithRotationToSpeckle(EllipseElement ellipse, string units = null) + { + var vec = ellipse.GetCurveVector(); + var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element - var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref curve); - var _splineElement = new BSplineCurveElement(Model, null, _spline); + primitive.TryGetArc(out DEllipse3d curve); - return BSplineCurveToSpeckle(_splineElement, units); - } + var _spline = MSBsplineCurve.CreateFromDEllipse3d(ref curve); + var _splineElement = new BSplineCurveElement(Model, null, _spline); - // Circle - public Circle CircleToSpeckle(EllipseElement ellipse, string units = null) - { - double radius = GetElementProperty(ellipse, "Radius").DoubleValue / UoR; + return BSplineCurveToSpeckle(_splineElement, units); + } - var vec = ellipse.GetCurveVector(); - vec.GetRange(out DRange3d range); - vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); + // Circle + public Circle CircleToSpeckle(EllipseElement ellipse, string units = null) + { + double radius = GetElementProperty(ellipse, "Radius").DoubleValue / UoR; + var vec = ellipse.GetCurveVector(); + vec.GetRange(out DRange3d range); + vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); - DPlane3d plane = new DPlane3d(center, new DVector3d(normal)); - var specklePlane = PlaneToSpeckle(plane); + DPlane3d plane = new(center, new DVector3d(normal)); + var specklePlane = PlaneToSpeckle(plane); - var u = units ?? ModelUnits; - var _circle = new Circle(specklePlane, radius, u); - _circle.domain = new Interval(0, 1); - _circle.length = 2 * Math.PI * radius; - _circle.area = Math.PI * Math.Pow(radius, 2); + var u = units ?? ModelUnits; + var _circle = new Circle(specklePlane, radius, u); + _circle.domain = new Interval(0, 1); + _circle.length = 2 * Math.PI * radius; + _circle.area = Math.PI * Math.Pow(radius, 2); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _circle.bbox = BoxToSpeckle(range, worldXY); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _circle.bbox = BoxToSpeckle(range, worldXY); - return _circle; - } + return _circle; + } - public Circle CircleToSpeckle(ArcElement arc, string units = null) - { - double radius = GetElementProperty(arc, "Radius").DoubleValue / UoR; + public Circle CircleToSpeckle(ArcElement arc, string units = null) + { + double radius = GetElementProperty(arc, "Radius").DoubleValue / UoR; - CurveVector vec = arc.GetCurveVector(); - vec.GetRange(out DRange3d range); - vec.WireCentroid(out double length, out DPoint3d center); + CurveVector vec = arc.GetCurveVector(); + vec.GetRange(out DRange3d range); + vec.WireCentroid(out double length, out DPoint3d center); - CurvePrimitive primitive = vec.GetPrimitive(0); - primitive.FractionToPoint(0, out DPoint3d startPoint); - primitive.FractionToPoint(0.25, out DPoint3d quarterPoint); + CurvePrimitive primitive = vec.GetPrimitive(0); + primitive.FractionToPoint(0, out DPoint3d startPoint); + primitive.FractionToPoint(0.25, out DPoint3d quarterPoint); - Plane specklePlane = PlaneToSpeckle(center, quarterPoint, startPoint); + Plane specklePlane = PlaneToSpeckle(center, quarterPoint, startPoint); - var u = units ?? ModelUnits; - var _circle = new Circle(specklePlane, radius, u); - _circle.domain = new Interval(0, 1); - _circle.length = 2 * Math.PI * radius; - _circle.area = Math.PI * Math.Pow(radius, 2); + var u = units ?? ModelUnits; + var _circle = new Circle(specklePlane, radius, u); + _circle.domain = new Interval(0, 1); + _circle.length = 2 * Math.PI * radius; + _circle.area = Math.PI * Math.Pow(radius, 2); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _circle.bbox = BoxToSpeckle(range, worldXY); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _circle.bbox = BoxToSpeckle(range, worldXY); - return _circle; - } + return _circle; + } - public Circle CircleToSpeckle(DEllipse3d ellipse, string units = null) - { - ellipse.GetMajorMinorData(out DPoint3d center, out DMatrix3d matrix, out double majorAxis, out double minorAxis, out Angle startAngle, out Angle endAngle); - ellipse.IsCircular(out double radius, out DVector3d normal); - var range = DRange3d.FromEllipse(ellipse); + public Circle CircleToSpeckle(DEllipse3d ellipse, string units = null) + { + ellipse.GetMajorMinorData( + out DPoint3d center, + out DMatrix3d matrix, + out double majorAxis, + out double minorAxis, + out Angle startAngle, + out Angle endAngle + ); + ellipse.IsCircular(out double radius, out DVector3d normal); + var range = DRange3d.FromEllipse(ellipse); + + Plane specklePlane = PlaneToSpeckle(new DPlane3d(center, normal)); + + var u = units ?? ModelUnits; + var _circle = new Circle(specklePlane, radius, u); + _circle.domain = new Interval(0, 1); + _circle.length = 2 * Math.PI * radius; + _circle.area = Math.PI * Math.Pow(radius, 2); + + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _circle.bbox = BoxToSpeckle(range, worldXY); + + return _circle; + } - Plane specklePlane = PlaneToSpeckle(new DPlane3d(center, normal)); + public EllipseElement CircleToNative(Circle ellipse) + { + var radius = (double)ellipse.radius; + var plane = ellipse.plane; + var center = Point3dToNative(plane.origin); + var normal = VectorToNative(plane.normal); - var u = units ?? ModelUnits; - var _circle = new Circle(specklePlane, radius, u); - _circle.domain = new Interval(0, 1); - _circle.length = 2 * Math.PI * radius; - _circle.area = Math.PI * Math.Pow(radius, 2); + var e = DEllipse3d.FromCenterRadiusNormal(center, ScaleToNative(radius, ellipse.units, UoR), normal); + var _ellipse = new EllipseElement(Model, null, e); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _circle.bbox = BoxToSpeckle(range, worldXY); + return _ellipse; + } - return _circle; - } + // All ellipse cases (as a circle, as a curve - , as an ellipse) + public ICurve EllipseToSpeckle(EllipseElement ellipse, string units = null) + { + double axisRatio = GetElementProperty(ellipse, "AxisRatio").DoubleValue; + double rotation = GetElementProperty(ellipse, "RotationAngle").DoubleValue; - public EllipseElement CircleToNative(Circle ellipse) + if (axisRatio == 1) { - var radius = (double)ellipse.radius; - var plane = ellipse.plane; - var center = Point3dToNative(plane.origin); - var normal = VectorToNative(plane.normal); - - var e = DEllipse3d.FromCenterRadiusNormal(center, ScaleToNative(radius, ellipse.units, UoR), normal); - var _ellipse = new EllipseElement(Model, null, e); - - return _ellipse; + // primary axis = secondary axis, treat as circle + return CircleToSpeckle(ellipse, units); } - - // All ellipse cases (as a circle, as a curve - , as an ellipse) - public ICurve EllipseToSpeckle(EllipseElement ellipse, string units = null) + else { - double axisRatio = GetElementProperty(ellipse, "AxisRatio").DoubleValue; - double rotation = GetElementProperty(ellipse, "RotationAngle").DoubleValue; - - if (axisRatio == 1) + if (rotation != 0 && rotation % (Math.PI * 2) != 0) { - // primary axis = secondary axis, treat as circle - return CircleToSpeckle(ellipse, units); + return EllipseWithRotationToSpeckle(ellipse, units); } else { - if (rotation != 0 && rotation % (Math.PI * 2) != 0) - { - return EllipseWithRotationToSpeckle(ellipse, units); - } - else - { - return EllipseWithoutRotationToSpeckle(ellipse, units); - } + return EllipseWithoutRotationToSpeckle(ellipse, units); } } + } - // Line string element - public Polyline PolylineToSpeckle(LineStringElement lineString, string units = null) - { - List vertices = new List(); - double totalLength = 0; - DPoint3d firstPoint = new DPoint3d(); - DPoint3d lastPoint = new DPoint3d(); - bool closed = true; - - var segments = GetElementProperty(lineString, "Segments").ContainedValues; - for (int i = 0; i < segments.Count(); i++) - { - var segment = segments.ElementAt(i); - var segmentValues = segment.ContainedValues; - DPoint3d startPoint = (DPoint3d)segmentValues["Start"].NativeValue; - double length = segmentValues["Length"].DoubleValue; - - vertices.Add(startPoint); - totalLength += length; - - if (i == 0) - firstPoint = startPoint; - if (i == segments.Count() - 1) - { - DPoint3d endPoint = (DPoint3d)segmentValues["End"].NativeValue; - lastPoint = endPoint; - if (firstPoint != lastPoint) - { - closed = false; - vertices.Add(endPoint); - } - } - } - - var _polyline = new Polyline(PointsToFlatList(vertices)); - _polyline.closed = closed; - _polyline.length = totalLength / UoR; + // Line string element + public Polyline PolylineToSpeckle(LineStringElement lineString, string units = null) + { + List vertices = new(); + double totalLength = 0; + DPoint3d firstPoint = new(); + DPoint3d lastPoint = new(); + bool closed = true; - var curves = lineString.GetCurveVector(); - curves.GetRange(out var range); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _polyline.bbox = BoxToSpeckle(range, worldXY); - _polyline.units = units ?? ModelUnits; + var segments = GetElementProperty(lineString, "Segments").ContainedValues; + for (int i = 0; i < segments.Count(); i++) + { + var segment = segments.ElementAt(i); + var segmentValues = segment.ContainedValues; + DPoint3d startPoint = (DPoint3d)segmentValues["Start"].NativeValue; + double length = segmentValues["Length"].DoubleValue; - return _polyline; - } + vertices.Add(startPoint); + totalLength += length; - public Polyline PolylineToSpeckle(List pointList) - { - double length = 0; - var count = pointList.Count - 1; - for (int i = 0; i < count; i++) + if (i == 0) { - var dx = pointList[i + 1].X - pointList[i].X; - var dy = pointList[i + 1].Y - pointList[i].Y; - var dz = pointList[i + 1].Z - pointList[i].Z; - var d = Math.Sqrt(dx * dx + dy * dy + dz * dz); - length += d; + firstPoint = startPoint; } - var start = pointList[0]; - var end = pointList[count]; - var closed = start.Equals(end); - - var _polyline = new Polyline(PointsToFlatList(pointList), ModelUnits); - - _polyline.closed = closed; - _polyline.length = length / UoR; - - var range = DRange3d.FromArray(pointList); - - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _polyline.bbox = BoxToSpeckle(range, worldXY); - - return _polyline; - } - - public LineStringElement PolylineToNative(Polyline polyline) - { - var points = PointListToNative(polyline.value, polyline.units).ToList(); - if (polyline.closed) - points.Add(points[0]); - - LineStringElement _lineString = new LineStringElement(Model, null, points.ToArray()); - return _lineString; - } - - public Polycurve PolycurveToSpeckle(ComplexStringElement complexString, string units = null) - { - var segments = PolycurveToSpeckleList(complexString, units); - - DRange3d range = new DRange3d(); - double length = 0; - bool closed = false; - CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(complexString); - if (q != null) + if (i == segments.Count() - 1) { - CurveVector vec = q.GetCurveVector(); - if (vec != null) + DPoint3d endPoint = (DPoint3d)segmentValues["End"].NativeValue; + lastPoint = endPoint; + if (firstPoint != lastPoint) { - vec.GetRange(out range); - length = vec.SumOfLengths(); - closed = vec.IsClosedPath; + closed = false; + vertices.Add(endPoint); } } + } - var _polycurve = new Polycurve(); + var _polyline = new Polyline(PointsToFlatList(vertices)); + _polyline.closed = closed; + _polyline.length = totalLength / UoR; - _polycurve.units = units ?? ModelUnits; - _polycurve.closed = closed; - _polycurve.length = length; - _polycurve.segments = segments; + var curves = lineString.GetCurveVector(); + curves.GetRange(out var range); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _polyline.bbox = BoxToSpeckle(range, worldXY); + _polyline.units = units ?? ModelUnits; - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _polycurve.bbox = BoxToSpeckle(range, worldXY); + return _polyline; + } - return _polycurve; + public Polyline PolylineToSpeckle(List pointList) + { + double length = 0; + var count = pointList.Count - 1; + for (int i = 0; i < count; i++) + { + var dx = pointList[i + 1].X - pointList[i].X; + var dy = pointList[i + 1].Y - pointList[i].Y; + var dz = pointList[i + 1].Z - pointList[i].Z; + var d = Math.Sqrt(dx * dx + dy * dy + dz * dz); + length += d; } - // Complex string element (complex chain) - public List PolycurveToSpeckleList(ComplexStringElement complexString, string units = null) - { - var segments = new List(); + var start = pointList[0]; + var end = pointList[count]; + var closed = start.Equals(end); - Processor processor = new Processor(); - ElementGraphicsOutput.Process(complexString, processor); - var curves = processor.curveVectors; + var _polyline = new Polyline(PointsToFlatList(pointList), ModelUnits); - if (curves.Any()) - { - foreach (var curve in curves) - { + _polyline.closed = closed; + _polyline.length = length / UoR; - foreach (var primitive in curve) - { + var range = DRange3d.FromArray(pointList); - var curvePrimitiveType = primitive.GetCurvePrimitiveType(); - - switch (curvePrimitiveType) - { - case CurvePrimitive.CurvePrimitiveType.Line: - if(primitive.TryGetLine(out DSegment3d segment)) - { - segments.Add(LineToSpeckle(segment)); - } - break; - case CurvePrimitive.CurvePrimitiveType.Arc: - if (primitive.TryGetArc(out DEllipse3d arc)) - { - segments.Add(ArcToSpeckle(arc)); - } - break; - case CurvePrimitive.CurvePrimitiveType.LineString: - var pointList = new List(); - if (primitive.TryGetLineString(pointList)) - { - segments.Add(PolylineToSpeckle(pointList)); - } - break; - case CurvePrimitive.CurvePrimitiveType.BsplineCurve: - var spline = primitive.GetBsplineCurve(); - segments.Add(BSplineCurveToSpeckle(spline)); - break; - case CurvePrimitive.CurvePrimitiveType.Spiral: - var spiralSpline = primitive.GetProxyBsplineCurve(); - segments.Add(SpiralCurveElementToCurve(spiralSpline)); - break; - } - } - } - } + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _polyline.bbox = BoxToSpeckle(range, worldXY); + + return _polyline; + } - return segments; + public LineStringElement PolylineToNative(Polyline polyline) + { + var points = PointListToNative(polyline.value, polyline.units).ToList(); + if (polyline.closed) + { + points.Add(points[0]); } + LineStringElement _lineString = new(Model, null, points.ToArray()); + return _lineString; + } - //// Complex string element (complex chain) - public ComplexStringElement PolycurveToNative(Polycurve polycurve) - { - var _polycurve = new ComplexStringElement(Model, null); + public Polycurve PolycurveToSpeckle(ComplexStringElement complexString, string units = null) + { + var segments = PolycurveToSpeckleList(complexString, units); - for (int i = 0; i < polycurve.segments.Count; i++) + DRange3d range = new(); + double length = 0; + bool closed = false; + CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(complexString); + if (q != null) + { + CurveVector vec = q.GetCurveVector(); + if (vec != null) { - var segment = polycurve.segments[i]; - var _curve = CurveToNative(segment); - _polycurve.AddComponentElement(_curve); + vec.GetRange(out range); + length = vec.SumOfLengths(); + closed = vec.IsClosedPath; } - - return _polycurve; } - private List ProcessComplexElementSegments(BIM.Element[] subElements) - { - var segments = new List(); + var _polycurve = new Polycurve(); - for (int i = 0; i < subElements.Count(); i++) - { - var subElementId = subElements[i].ID; - var subElement = Model.FindElementById(new ElementId(ref subElementId)); - var subElementType = subElement.ElementType; + _polycurve.units = units ?? ModelUnits; + _polycurve.closed = closed; + _polycurve.length = length; + _polycurve.segments = segments; - switch (subElementType) - { - case MSElementType.Line: - var _line = (Line)LineToSpeckle(subElement as LineElement); - segments.Add(_line); - break; - case MSElementType.LineString: - var _lineString = PolylineToSpeckle(subElement as LineStringElement); - segments.Add(_lineString); - break; - case MSElementType.Arc: - var _arc = ArcToSpeckle(subElement as ArcElement); - segments.Add(_arc); - break; - case MSElementType.BsplineCurve: //lines, line strings, arcs, and curves, and open B-spline curves - var _spline = BSplineCurveToSpeckle(subElement as BSplineCurveElement); - segments.Add(_spline); - break; - } - } + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _polycurve.bbox = BoxToSpeckle(range, worldXY); - return segments; - } + return _polycurve; + } - // Splines - public Curve BSplineCurveToSpeckle(BSplineCurveElement curve, string units = null) - { - var vec = curve.GetCurveVector(); - vec.GetRange(out DRange3d range); + // Complex string element (complex chain) + public List PolycurveToSpeckleList(ComplexStringElement complexString, string units = null) + { + var segments = new List(); - var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element - var curveType = primitive.GetCurvePrimitiveType(); - var _curve = new Curve(); + Processor processor = new(); + ElementGraphicsOutput.Process(complexString, processor); + var curves = processor.curveVectors; - bool isSpiral = curveType == CurvePrimitive.CurvePrimitiveType.Spiral; - if (isSpiral) - { - _curve = SpiralCurveElementToCurve(primitive); - } - else + if (curves.Any()) + { + foreach (var curve in curves) { - MSBsplineCurve _spline = primitive.GetBsplineCurve(); - - if (_spline == null) + foreach (var primitive in curve) { - var _proxySpline = primitive.GetProxyBsplineCurve(); - if (_proxySpline != null) - { - _spline = _proxySpline; - } - else - { - return null; - } - } + var curvePrimitiveType = primitive.GetCurvePrimitiveType(); - var degree = _spline.Order - 1; - var closed = _spline.IsClosed; - var rational = _spline.IsRational; - var periodic = primitive.IsPeriodicFractionSpace(out double period); - var length = _spline.Length(); - var points = _spline.Poles; - if (closed) - points.Add(points[0]); - var knots = (List)_spline.Knots; - var weights = (List)_spline.Weights; - if (weights == null) - weights = Enumerable.Repeat((double)1, points.Count()).ToList(); - - var options = new FacetOptions(); - options.SetCurveDefaultsDefaults(); - options.SetDefaults(); - options.ChordTolerance = length / 1000 / UoR; - options.MaxEdgeLength = length / 1000 / UoR; - var stroked = vec.Stroke(options); - - var polyPoints = new List(); - foreach (var v in stroked) - v.TryGetLineString(polyPoints); - - var _points = new List(); - - // get control points - var controlPoints = GetElementProperty(curve, "ControlPointData.ControlPoints").ContainedValues; - - // get weights - var controlPointWeights = GetElementProperty(curve, "ControlPointData.ControlPointsWeights").ContainedValues; - - // get knots - var knotData = GetElementProperty(curve, "KnotData.Knots").ContainedValues; - - if (controlPoints.Count() > 0) - { - foreach (var controlPoint in controlPoints) - { - var point = (DPoint3d)controlPoint.NativeValue; - _points.Add(point); - } - } - else + switch (curvePrimitiveType) { - foreach (var controlPoint in controlPointWeights) - { - var point = (DPoint3d)controlPoint.ContainedValues["Point"].NativeValue; - _points.Add(point); - } + case CurvePrimitive.CurvePrimitiveType.Line: + if (primitive.TryGetLine(out DSegment3d segment)) + { + segments.Add(LineToSpeckle(segment)); + } + break; + case CurvePrimitive.CurvePrimitiveType.Arc: + if (primitive.TryGetArc(out DEllipse3d arc)) + { + segments.Add(ArcToSpeckle(arc)); + } + break; + case CurvePrimitive.CurvePrimitiveType.LineString: + var pointList = new List(); + if (primitive.TryGetLineString(pointList)) + { + segments.Add(PolylineToSpeckle(pointList)); + } + break; + case CurvePrimitive.CurvePrimitiveType.BsplineCurve: + var spline = primitive.GetBsplineCurve(); + segments.Add(BSplineCurveToSpeckle(spline)); + break; + case CurvePrimitive.CurvePrimitiveType.Spiral: + var spiralSpline = primitive.GetProxyBsplineCurve(); + segments.Add(SpiralCurveElementToCurve(spiralSpline)); + break; } - - - - // set nurbs curve info - _curve.points = PointsToFlatList(_points).ToList(); - _curve.knots = knots; - _curve.weights = weights; - _curve.degree = degree; - _curve.periodic = periodic; - _curve.rational = (bool)rational; - _curve.closed = (bool)closed; - _curve.length = length / UoR; - _curve.domain = new Interval(0, length / UoR); - _curve.units = units ?? ModelUnits; - - // handle the display polyline - try - { - var _polyPoints = new List(); - foreach (var pt in polyPoints) - _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); - - var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); - _curve.displayValue = poly; } - catch { } } - - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _curve.bbox = BoxToSpeckle(range, worldXY); - - return _curve; } - public Curve BSplineCurveToSpeckle(MSBsplineCurve curve, string units = null) - { - var degree = curve.Order - 1; - var closed = curve.IsClosed; - var rational = curve.IsRational; + return segments; + } - var range = curve.GetRange(); + //// Complex string element (complex chain) + public ComplexStringElement PolycurveToNative(Polycurve polycurve) + { + var _polycurve = new ComplexStringElement(Model, null); - //var periodic = primitive.IsPeriodicFractionSpace(out double period); - var length = curve.Length(); - var points = curve.Poles; - if (closed) - points.Add(points[0]); - var knots = (List)curve.Knots; - var weights = (List)curve.Weights; - if (weights == null) - weights = Enumerable.Repeat((double)1, points.Count()).ToList(); + for (int i = 0; i < polycurve.segments.Count; i++) + { + var segment = polycurve.segments[i]; + var _curve = CurveToNative(segment); + _polycurve.AddComponentElement(_curve); + } - var polyPoints = new List(); - for (int i = 0; i <= 100; i++) - { - curve.FractionToPoint(out DPoint3d point, (double)i / 100); - polyPoints.Add(point); - } + return _polycurve; + } - var _curve = new Curve(); + private List ProcessComplexElementSegments(BIM.Element[] subElements) + { + var segments = new List(); - // set nurbs curve info - _curve.points = PointsToFlatList(points).ToList(); - _curve.knots = knots; - _curve.weights = weights; - _curve.degree = degree; - //_curve.periodic = periodic; - _curve.rational = (bool)rational; - _curve.closed = (bool)closed; - _curve.length = length / UoR; - _curve.domain = new Interval(0, length / UoR); - _curve.units = units ?? ModelUnits; + for (int i = 0; i < subElements.Count(); i++) + { + var subElementId = subElements[i].ID; + var subElement = Model.FindElementById(new ElementId(ref subElementId)); + var subElementType = subElement.ElementType; - // handle the display polyline - try + switch (subElementType) { - var _polyPoints = new List(); - foreach (var pt in polyPoints) - _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); - - var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); - _curve.displayValue = poly; + case MSElementType.Line: + var _line = (Line)LineToSpeckle(subElement as LineElement); + segments.Add(_line); + break; + case MSElementType.LineString: + var _lineString = PolylineToSpeckle(subElement as LineStringElement); + segments.Add(_lineString); + break; + case MSElementType.Arc: + var _arc = ArcToSpeckle(subElement as ArcElement); + segments.Add(_arc); + break; + case MSElementType.BsplineCurve: //lines, line strings, arcs, and curves, and open B-spline curves + var _spline = BSplineCurveToSpeckle(subElement as BSplineCurveElement); + segments.Add(_spline); + break; } - catch { } - - return _curve; } - public Curve SpiralCurveElementToCurve(CurvePrimitive primitive) - { - var _spline = primitive.GetProxyBsplineCurve(); - - var degree = _spline.Order - 1; - var closed = _spline.IsClosed; - var rational = _spline.IsRational; - var periodic = primitive.IsPeriodicFractionSpace(out double period); - var length = _spline.Length(); - var points = _spline.Poles; - if (closed) - points.Add(points[0]); - var knots = (List)_spline.Knots; - var weights = (List)_spline.Weights; - if (weights == null) - weights = Enumerable.Repeat((double)1, points.Count()).ToList(); + return segments; + } - var polyPoints = new List(); - for (int i = 0; i <= 100; i++) - { - _spline.FractionToPoint(out DPoint3d point, i / 100); - polyPoints.Add(point); - } + // Splines + public Curve BSplineCurveToSpeckle(BSplineCurveElement curve, string units = null) + { + var vec = curve.GetCurveVector(); + vec.GetRange(out DRange3d range); - var _curve = new Curve(); + var primitive = vec.GetPrimitive(0); // assume one primitve in vector for single curve element + var curveType = primitive.GetCurvePrimitiveType(); + var _curve = new Curve(); - // set nurbs curve info - _curve.points = PointsToFlatList(points).ToList(); - _curve.knots = knots; - _curve.weights = weights; - _curve.degree = degree; - _curve.periodic = periodic; - _curve.rational = (bool)rational; - _curve.closed = (bool)closed; - _curve.length = length / UoR; - _curve.domain = new Interval(0, length / UoR); - _curve.units = ModelUnits; + bool isSpiral = curveType == CurvePrimitive.CurvePrimitiveType.Spiral; + if (isSpiral) + { + _curve = SpiralCurveElementToCurve(primitive); + } + else + { + MSBsplineCurve _spline = primitive.GetBsplineCurve(); - try + if (_spline == null) { - var _polyPoints = new List(); - foreach (var pt in polyPoints) - _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); - - var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); - _curve.displayValue = poly; + var _proxySpline = primitive.GetProxyBsplineCurve(); + if (_proxySpline != null) + { + _spline = _proxySpline; + } + else + { + return null; + } } - catch { } - return _curve; - } - - public Curve SpiralCurveElementToCurve(MSBsplineCurve _spline) - { var degree = _spline.Order - 1; var closed = _spline.IsClosed; var rational = _spline.IsRational; - //var periodic = primitive.IsPeriodicFractionSpace(out double period); + var periodic = primitive.IsPeriodicFractionSpace(out double period); var length = _spline.Length(); var points = _spline.Poles; if (closed) + { points.Add(points[0]); + } + var knots = (List)_spline.Knots; var weights = (List)_spline.Weights; if (weights == null) + { weights = Enumerable.Repeat((double)1, points.Count()).ToList(); + } + + var options = new FacetOptions(); + options.SetCurveDefaultsDefaults(); + options.SetDefaults(); + options.ChordTolerance = length / 1000 / UoR; + options.MaxEdgeLength = length / 1000 / UoR; + var stroked = vec.Stroke(options); var polyPoints = new List(); - for (int i = 0; i <= 100; i++) + foreach (var v in stroked) { - _spline.FractionToPoint(out DPoint3d point, i / 100); - polyPoints.Add(point); + v.TryGetLineString(polyPoints); } - var _curve = new Curve(); + var _points = new List(); + + // get control points + var controlPoints = GetElementProperty(curve, "ControlPointData.ControlPoints").ContainedValues; + + // get weights + var controlPointWeights = GetElementProperty(curve, "ControlPointData.ControlPointsWeights").ContainedValues; + + // get knots + var knotData = GetElementProperty(curve, "KnotData.Knots").ContainedValues; + + if (controlPoints.Count() > 0) + { + foreach (var controlPoint in controlPoints) + { + var point = (DPoint3d)controlPoint.NativeValue; + _points.Add(point); + } + } + else + { + foreach (var controlPoint in controlPointWeights) + { + var point = (DPoint3d)controlPoint.ContainedValues["Point"].NativeValue; + _points.Add(point); + } + } // set nurbs curve info - _curve.points = PointsToFlatList(points).ToList(); + _curve.points = PointsToFlatList(_points).ToList(); _curve.knots = knots; _curve.weights = weights; _curve.degree = degree; - //_curve.periodic = periodic; + _curve.periodic = periodic; _curve.rational = (bool)rational; _curve.closed = (bool)closed; _curve.length = length / UoR; _curve.domain = new Interval(0, length / UoR); - _curve.units = ModelUnits; + _curve.units = units ?? ModelUnits; + // handle the display polyline try { var _polyPoints = new List(); foreach (var pt in polyPoints) + { _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); + } var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); _curve.displayValue = poly; } catch { } + } + + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _curve.bbox = BoxToSpeckle(range, worldXY); + + return _curve; + } - return _curve; + public Curve BSplineCurveToSpeckle(MSBsplineCurve curve, string units = null) + { + var degree = curve.Order - 1; + var closed = curve.IsClosed; + var rational = curve.IsRational; + + var range = curve.GetRange(); + + //var periodic = primitive.IsPeriodicFractionSpace(out double period); + var length = curve.Length(); + var points = curve.Poles; + if (closed) + { + points.Add(points[0]); } - public BSplineCurveElement BSplineCurveToNative(Curve curve) + var knots = (List)curve.Knots; + var weights = (List)curve.Weights; + if (weights == null) { - var points = PointListToNative(curve.points, curve.units).ToArray(); - var weights = (curve.weights.Distinct().Count() == 1) ? null : curve.weights; - var knots = curve.knots; - var order = curve.degree + 1; - var closed = curve.closed; - - //var _points = PointListToNative(curve.points, curve.units).ToList(); - //if (curve.closed && curve.periodic) - // _points = _points.GetRange(0, _points.Count - curve.degree); - //List points1 = _points.ToList(); - - //var _knots = curve.knots; - //if (curve.knots.Count == points.Count() + curve.degree - 1) // handles rhino format curves - //{ - // _knots.Insert(0, _knots[0]); - // _knots.Insert(_knots.Count - 1, _knots[_knots.Count - 1]); - //} - //if (curve.closed && curve.periodic) // handles closed periodic curves - // _knots = _knots.GetRange(curve.degree, _knots.Count - curve.degree * 2); - //var knots1 = new List(); - //foreach (var _knot in _knots) - // knots1.Add(_knot); - - //var _weights = curve.weights; - //if (curve.closed && curve.periodic) // handles closed periodic curves - // _weights = curve.weights.GetRange(0, _points.Count); - - var _spline = MSBsplineCurve.CreateFromPoles(points, weights, knots, order, closed, false); - - if (curve.closed) - _spline.MakeClosed(); - - var _curve = new BSplineCurveElement(Model, null, _spline); - return _curve; + weights = Enumerable.Repeat((double)1, points.Count()).ToList(); } - // All curves - public DisplayableElement CurveToNative(ICurve curve) + var polyPoints = new List(); + for (int i = 0; i <= 100; i++) { - switch (curve) - { - case Circle circle: - return CircleToNative(circle); + curve.FractionToPoint(out DPoint3d point, (double)i / 100); + polyPoints.Add(point); + } - case Arc arc: - return ArcToNative(arc); + var _curve = new Curve(); - case Ellipse ellipse: - return EllipseToNative(ellipse); + // set nurbs curve info + _curve.points = PointsToFlatList(points).ToList(); + _curve.knots = knots; + _curve.weights = weights; + _curve.degree = degree; + //_curve.periodic = periodic; + _curve.rational = (bool)rational; + _curve.closed = (bool)closed; + _curve.length = length / UoR; + _curve.domain = new Interval(0, length / UoR); + _curve.units = units ?? ModelUnits; + + // handle the display polyline + try + { + var _polyPoints = new List(); + foreach (var pt in polyPoints) + { + _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); + } - case Curve crv: - return BSplineCurveToNative(crv); + var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); + _curve.displayValue = poly; + } + catch { } - case Polyline polyline: - return PolylineToNative(polyline); + return _curve; + } - case Line line: - return LineToNative(line); + public Curve SpiralCurveElementToCurve(CurvePrimitive primitive) + { + var _spline = primitive.GetProxyBsplineCurve(); - case Polycurve polycurve: - return PolycurveToNative(polycurve); + var degree = _spline.Order - 1; + var closed = _spline.IsClosed; + var rational = _spline.IsRational; + var periodic = primitive.IsPeriodicFractionSpace(out double period); + var length = _spline.Length(); + var points = _spline.Poles; + if (closed) + { + points.Add(points[0]); + } - default: - return null; - } + var knots = (List)_spline.Knots; + var weights = (List)_spline.Weights; + if (weights == null) + { + weights = Enumerable.Repeat((double)1, points.Count()).ToList(); } - public List TryCurveToSpeckleCurveList(DisplayableElement curve, string units = null) + var polyPoints = new List(); + for (int i = 0; i <= 100; i++) { - var outCurves = new List(); + _spline.FractionToPoint(out DPoint3d point, i / 100); + polyPoints.Add(point); + } + + var _curve = new Curve(); - switch (curve) + // set nurbs curve info + _curve.points = PointsToFlatList(points).ToList(); + _curve.knots = knots; + _curve.weights = weights; + _curve.degree = degree; + _curve.periodic = periodic; + _curve.rational = (bool)rational; + _curve.closed = (bool)closed; + _curve.length = length / UoR; + _curve.domain = new Interval(0, length / UoR); + _curve.units = ModelUnits; + + try + { + var _polyPoints = new List(); + foreach (var pt in polyPoints) { - case ComplexStringElement polyCurve: - outCurves.AddRange(PolycurveToSpeckleList(polyCurve, units)); break; + _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); + } + + var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); + _curve.displayValue = poly; + } + catch { } + + return _curve; + } - case ArcElement arc: - outCurves.Add(CircularArcToSpeckle(arc, units)); break; + public Curve SpiralCurveElementToCurve(MSBsplineCurve _spline) + { + var degree = _spline.Order - 1; + var closed = _spline.IsClosed; + var rational = _spline.IsRational; + //var periodic = primitive.IsPeriodicFractionSpace(out double period); + var length = _spline.Length(); + var points = _spline.Poles; + if (closed) + { + points.Add(points[0]); + } - case EllipseElement ellipse: - outCurves.Add(EllipseToSpeckle(ellipse, units)); break; + var knots = (List)_spline.Knots; + var weights = (List)_spline.Weights; + if (weights == null) + { + weights = Enumerable.Repeat((double)1, points.Count()).ToList(); + } - case BSplineCurveElement crv: - outCurves.Add(BSplineCurveToSpeckle(crv, units)); break; + var polyPoints = new List(); + for (int i = 0; i <= 100; i++) + { + _spline.FractionToPoint(out DPoint3d point, i / 100); + polyPoints.Add(point); + } - case LineElement line: - outCurves.Add((Line)LineToSpeckle(line, units)); break; + var _curve = new Curve(); - case LineStringElement polyLine: - outCurves.Add(PolylineToSpeckle(polyLine, units)); break; + // set nurbs curve info + _curve.points = PointsToFlatList(points).ToList(); + _curve.knots = knots; + _curve.weights = weights; + _curve.degree = degree; + //_curve.periodic = periodic; + _curve.rational = (bool)rational; + _curve.closed = (bool)closed; + _curve.length = length / UoR; + _curve.domain = new Interval(0, length / UoR); + _curve.units = ModelUnits; - default: break; + try + { + var _polyPoints = new List(); + foreach (var pt in polyPoints) + { + _polyPoints.Add(new DPoint3d(pt.X * UoR, pt.Y * UoR, pt.Z * UoR)); } - return outCurves; + var poly = new Polyline(PointsToFlatList(polyPoints), ModelUnits); + _curve.displayValue = poly; } + catch { } + return _curve; + } + + public BSplineCurveElement BSplineCurveToNative(Curve curve) + { + var points = PointListToNative(curve.points, curve.units).ToArray(); + var weights = (curve.weights.Distinct().Count() == 1) ? null : curve.weights; + var knots = curve.knots; + var order = curve.degree + 1; + var closed = curve.closed; + + //var _points = PointListToNative(curve.points, curve.units).ToList(); + //if (curve.closed && curve.periodic) + // _points = _points.GetRange(0, _points.Count - curve.degree); + //List points1 = _points.ToList(); + + //var _knots = curve.knots; + //if (curve.knots.Count == points.Count() + curve.degree - 1) // handles rhino format curves + //{ + // _knots.Insert(0, _knots[0]); + // _knots.Insert(_knots.Count - 1, _knots[_knots.Count - 1]); + //} + //if (curve.closed && curve.periodic) // handles closed periodic curves + // _knots = _knots.GetRange(curve.degree, _knots.Count - curve.degree * 2); + //var knots1 = new List(); + //foreach (var _knot in _knots) + // knots1.Add(_knot); + + //var _weights = curve.weights; + //if (curve.closed && curve.periodic) // handles closed periodic curves + // _weights = curve.weights.GetRange(0, _points.Count); + + var _spline = MSBsplineCurve.CreateFromPoles(points, weights, knots, order, closed, false); + + if (curve.closed) + { + _spline.MakeClosed(); + } + + var _curve = new BSplineCurveElement(Model, null, _spline); + return _curve; + } - // Box - public Box BoxToSpeckle(DRange3d range, bool OrientToWorldXY = false, string units = null) + // All curves + public DisplayableElement CurveToNative(ICurve curve) + { + switch (curve) { - try - { - Box box = null; + case Circle circle: + return CircleToNative(circle); - var min = range.Low; - var max = range.High; + case Arc arc: + return ArcToNative(arc); - // get dimension intervals - var xSize = new Interval(ScaleToSpeckle(min.X, UoR), ScaleToSpeckle(max.X, UoR)); - var ySize = new Interval(ScaleToSpeckle(min.Y, UoR), ScaleToSpeckle(max.Y, UoR)); - var zSize = new Interval(ScaleToSpeckle(min.Z, UoR), ScaleToSpeckle(max.Z, UoR)); + case Ellipse ellipse: + return EllipseToNative(ellipse); - // get box size info - double area = 2 * ((xSize.Length * ySize.Length) + (xSize.Length * zSize.Length) + (ySize.Length * zSize.Length)); - double volume = xSize.Length * ySize.Length * zSize.Length; + case Curve crv: + return BSplineCurveToNative(crv); - if (OrientToWorldXY) - { - var origin = new DPoint3d(0, 0, 0); - var normal = new DVector3d(0, 0, 1 * UoR); - var plane = PlaneToSpeckle(new DPlane3d(origin, normal)); - box = new Box(plane, xSize, ySize, zSize, ModelUnits) { area = area, volume = volume }; - } - else - { - // get base plane - var corner = new DPoint3d(max.X, max.Y, min.Z); - var origin = new DPoint3d((corner.X + min.X) / 2, (corner.Y + min.Y) / 2, (corner.Z + min.Z) / 2); + case Polyline polyline: + return PolylineToNative(polyline); - var v1 = new DVector3d(origin, corner); - var v2 = new DVector3d(origin, min); + case Line line: + return LineToNative(line); - var cross = v1.CrossProduct(v2); - var plane = PlaneToSpeckle(new DPlane3d(origin, cross)); - var u = units ?? ModelUnits; - box = new Box(plane, xSize, ySize, zSize, u) { area = area, volume = volume }; - } + case Polycurve polycurve: + return PolycurveToNative(polycurve); - return box; - } - catch - { + default: return null; - } } + } - public DRange3d BoxToNative(Box box) + public List TryCurveToSpeckleCurveList(DisplayableElement curve, string units = null) + { + var outCurves = new List(); + + switch (curve) { - var _startPoint = new Point((double)box.xSize.start, (double)box.ySize.start, (double)box.zSize.start); - var _endPoint = new Point((double)box.xSize.end, (double)box.ySize.end, (double)box.zSize.end); - var startPoint = Point3dToNative(_startPoint); - var endPoint = Point3dToNative(_endPoint); + case ComplexStringElement polyCurve: + outCurves.AddRange(PolycurveToSpeckleList(polyCurve, units)); + break; - var _range = DRange3d.FromPoints(startPoint, endPoint); - return _range; - } + case ArcElement arc: + outCurves.Add(CircularArcToSpeckle(arc, units)); + break; - // Shape - public Polyline ShapeToSpeckle(ShapeElement shape) - { - var vec = shape.GetCurveVector(); - vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); - vec.GetRange(out DRange3d range); - var length = vec.SumOfLengths(); - var vertices = new List(); - foreach (var p in vec) - { - var pPoints = new List(); - p.TryGetLineString(pPoints); - vertices.AddRange(pPoints.Distinct()); - } + case EllipseElement ellipse: + outCurves.Add(EllipseToSpeckle(ellipse, units)); + break; - var _polyline = new Polyline(PointsToFlatList(vertices), ModelUnits) { closed = true }; + case BSplineCurveElement crv: + outCurves.Add(BSplineCurveToSpeckle(crv, units)); + break; - _polyline.length = length / UoR; - _polyline.area = area / Math.Pow(UoR, 2); + case LineElement line: + outCurves.Add((Line)LineToSpeckle(line, units)); + break; - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _polyline.bbox = BoxToSpeckle(range, worldXY); + case LineStringElement polyLine: + outCurves.Add(PolylineToSpeckle(polyLine, units)); + break; - return _polyline; + default: + break; } - // should closed polylines be converted to shapes? - public ShapeElement ShapeToNative(Polyline shape) - { - var vertices = PointListToNative(shape.value, shape.units).ToArray(); - var _shape = new ShapeElement(Model, null, vertices); - return _shape; - } + return outCurves; + } - public Polycurve ComplexShapeToSpeckle(ComplexShapeElement shape, string units = null) + // Box + public Box BoxToSpeckle(DRange3d range, bool OrientToWorldXY = false, string units = null) + { + try { - //terrible, need to figure out how to avoid using COM interface!! - BIM.ComplexShapeElement complexShapeElement = BMIU.ComApp.ActiveModelReference.GetElementByID(shape.ElementId) as BIM.ComplexShapeElement; + Box box = null; - var closed = complexShapeElement.IsClosedElement(); - var length = complexShapeElement.Perimeter(); + var min = range.Low; + var max = range.High; - var subElements = complexShapeElement.GetSubElements().BuildArrayFromContents(); - var segments = ProcessComplexElementSegments(subElements); + // get dimension intervals + var xSize = new Interval(ScaleToSpeckle(min.X, UoR), ScaleToSpeckle(max.X, UoR)); + var ySize = new Interval(ScaleToSpeckle(min.Y, UoR), ScaleToSpeckle(max.Y, UoR)); + var zSize = new Interval(ScaleToSpeckle(min.Z, UoR), ScaleToSpeckle(max.Z, UoR)); - DRange3d range = new DRange3d(); - CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(shape); - if (q != null) + // get box size info + double area = 2 * ((xSize.Length * ySize.Length) + (xSize.Length * zSize.Length) + (ySize.Length * zSize.Length)); + double volume = xSize.Length * ySize.Length * zSize.Length; + + if (OrientToWorldXY) { - CurveVector vec = q.GetCurveVector(); - if (vec != null) - { - length = vec.SumOfLengths(); - vec.GetRange(out range); - } + var origin = new DPoint3d(0, 0, 0); + var normal = new DVector3d(0, 0, 1 * UoR); + var plane = PlaneToSpeckle(new DPlane3d(origin, normal)); + box = new Box(plane, xSize, ySize, zSize, ModelUnits) { area = area, volume = volume }; } + else + { + // get base plane + var corner = new DPoint3d(max.X, max.Y, min.Z); + var origin = new DPoint3d((corner.X + min.X) / 2, (corner.Y + min.Y) / 2, (corner.Z + min.Z) / 2); - var _polycurve = new Polycurve(); - _polycurve.units = units ?? ModelUnits; - _polycurve.closed = closed; - _polycurve.length = length; - _polycurve.segments = segments; + var v1 = new DVector3d(origin, corner); + var v2 = new DVector3d(origin, min); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _polycurve.bbox = BoxToSpeckle(range, worldXY); + var cross = v1.CrossProduct(v2); + var plane = PlaneToSpeckle(new DPlane3d(origin, cross)); + var u = units ?? ModelUnits; + box = new Box(plane, xSize, ySize, zSize, u) { area = area, volume = volume }; + } - return _polycurve; + return box; } - - // should closed polycurves be converted to complex shapes automatically? - public ComplexShapeElement ComplexShapeToNative(Polycurve shape) + catch { - var _shape = new ComplexShapeElement(Model, null); + return null; + } + } - for (int i = 0; i < shape.segments.Count; i++) - { - var segment = shape.segments[i]; - var _curve = CurveToNative(segment); - _shape.AddComponentElement(_curve); - } + public DRange3d BoxToNative(Box box) + { + var _startPoint = new Point((double)box.xSize.start, (double)box.ySize.start, (double)box.zSize.start); + var _endPoint = new Point((double)box.xSize.end, (double)box.ySize.end, (double)box.zSize.end); + var startPoint = Point3dToNative(_startPoint); + var endPoint = Point3dToNative(_endPoint); - return _shape; - } + var _range = DRange3d.FromPoints(startPoint, endPoint); + return _range; + } - public Mesh MeshToSpeckle(MeshHeaderElement mesh, string units = null) + // Shape + public Polyline ShapeToSpeckle(ShapeElement shape) + { + var vec = shape.GetCurveVector(); + vec.CentroidNormalArea(out DPoint3d center, out DVector3d normal, out double area); + vec.GetRange(out DRange3d range); + var length = vec.SumOfLengths(); + var vertices = new List(); + foreach (var p in vec) { - var u = units ?? ModelUnits; + var pPoints = new List(); + p.TryGetLineString(pPoints); + vertices.AddRange(pPoints.Distinct()); + } + + var _polyline = new Polyline(PointsToFlatList(vertices), ModelUnits) { closed = true }; + + _polyline.length = length / UoR; + _polyline.area = area / Math.Pow(UoR, 2); + + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _polyline.bbox = BoxToSpeckle(range, worldXY); + + return _polyline; + } + + // should closed polylines be converted to shapes? + public ShapeElement ShapeToNative(Polyline shape) + { + var vertices = PointListToNative(shape.value, shape.units).ToArray(); + var _shape = new ShapeElement(Model, null, vertices); + return _shape; + } + + public Polycurve ComplexShapeToSpeckle(ComplexShapeElement shape, string units = null) + { + //terrible, need to figure out how to avoid using COM interface!! + BIM.ComplexShapeElement complexShapeElement = + BMIU.ComApp.ActiveModelReference.GetElementByID(shape.ElementId) as BIM.ComplexShapeElement; - PolyfaceHeader meshData = mesh.GetMeshData(); + var closed = complexShapeElement.IsClosedElement(); + var length = complexShapeElement.Perimeter(); - // get vertices - var _vertices = meshData.Point.ToArray(); + var subElements = complexShapeElement.GetSubElements().BuildArrayFromContents(); + var segments = ProcessComplexElementSegments(subElements); - // get faces - var faces = new List(); - - var _pointIndex = meshData.PointIndex.ToList(); - var _faceIndices = new List(); - for (int i = 0; i < _pointIndex.Count(); i++) + DRange3d range = new(); + CurvePathQuery q = CurvePathQuery.GetAsCurvePathQuery(shape); + if (q != null) + { + CurveVector vec = q.GetCurveVector(); + if (vec != null) { - if (_pointIndex[i] != 0) // index of 0 is face loop pad/terminator - _faceIndices.Add(_pointIndex[i] - 1); - else - { - _faceIndices.Insert(0, _faceIndices.Count); - faces.AddRange(_faceIndices); - _faceIndices.Clear(); - } + length = vec.SumOfLengths(); + vec.GetRange(out range); } + } - // create speckle mesh - var vertices = PointsToFlatList(_vertices); + var _polycurve = new Polycurve(); + _polycurve.units = units ?? ModelUnits; + _polycurve.closed = closed; + _polycurve.length = length; + _polycurve.segments = segments; - /* - List _colorIndex = meshData.ColorIndex.ToList(); - var defaultColour = System.Drawing.Color.FromArgb(255, 100, 100, 100); - var colors = Enumerable.Repeat(defaultColour.ToArgb(), vertices.Count()).ToList(); - */ + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _polycurve.bbox = BoxToSpeckle(range, worldXY); - var _mesh = new Mesh(vertices, faces); - _mesh.units = u; + return _polycurve; + } - meshData.ComputePrincipalAreaMoments(out double area, out DPoint3d centoid, out DMatrix3d axes, out DVector3d moments); - _mesh.area = area / Math.Pow(UoR, 2); + // should closed polycurves be converted to complex shapes automatically? + public ComplexShapeElement ComplexShapeToNative(Polycurve shape) + { + var _shape = new ComplexShapeElement(Model, null); - var range = meshData.PointRange(); - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _mesh.bbox = BoxToSpeckle(range, worldXY); + for (int i = 0; i < shape.segments.Count; i++) + { + var segment = shape.segments[i]; + var _curve = CurveToNative(segment); + _shape.AddComponentElement(_curve); + } - meshData.Dispose(); + return _shape; + } - return _mesh; - } + public Mesh MeshToSpeckle(MeshHeaderElement mesh, string units = null) + { + var u = units ?? ModelUnits; - public MeshHeaderElement MeshToNative(Mesh mesh) - { - var vertices = PointListToNative(mesh.vertices, mesh.units).ToArray(); + PolyfaceHeader meshData = mesh.GetMeshData(); + + // get vertices + var _vertices = meshData.Point.ToArray(); - var meshData = new PolyfaceHeader(); + // get faces + var faces = new List(); - int j = 0; - while (j < mesh.faces.Count) + var _pointIndex = meshData.PointIndex.ToList(); + var _faceIndices = new List(); + for (int i = 0; i < _pointIndex.Count(); i++) + { + if (_pointIndex[i] != 0) // index of 0 is face loop pad/terminator + { + _faceIndices.Add(_pointIndex[i] - 1); + } + else { - int n = mesh.faces[j]; - if (n < 3) n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility + _faceIndices.Insert(0, _faceIndices.Count); + faces.AddRange(_faceIndices); + _faceIndices.Clear(); + } + } - List faceVertices = mesh.faces.GetRange(j + 1, n).Select(x => vertices[x]).ToList(); + // create speckle mesh + var vertices = PointsToFlatList(_vertices); - if (faceVertices.Count > 0) - meshData.AddPolygon(faceVertices, new List(), new List()); + /* + List _colorIndex = meshData.ColorIndex.ToList(); + var defaultColour = System.Drawing.Color.FromArgb(255, 100, 100, 100); + var colors = Enumerable.Repeat(defaultColour.ToArgb(), vertices.Count()).ToList(); + */ - j += n + 1; - } + var _mesh = new Mesh(vertices, faces); + _mesh.units = u; - var _mesh = new MeshHeaderElement(Model, null, meshData); + meshData.ComputePrincipalAreaMoments( + out double area, + out DPoint3d centoid, + out DMatrix3d axes, + out DVector3d moments + ); + _mesh.area = area / Math.Pow(UoR, 2); - meshData.Dispose(); + var range = meshData.PointRange(); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _mesh.bbox = BoxToSpeckle(range, worldXY); - return _mesh; - } + meshData.Dispose(); - // Nurbs surface - public Surface SurfaceToSpeckle(BSplineSurfaceElement surface, string units = null) - { - var u = units ?? ModelUnits; + return _mesh; + } - var nurbsSurface = surface.GetBsplineSurface(); + public MeshHeaderElement MeshToNative(Mesh mesh) + { + var vertices = PointListToNative(mesh.vertices, mesh.units).ToArray(); - var knotsU = new List(); - for (int i = 0; i < nurbsSurface.UKnotCount; i++) - { - knotsU.Add(nurbsSurface.get_UKnotAt(Convert.ToUInt32(i))); - } + var meshData = new PolyfaceHeader(); - var knotsV = new List(); - for (int i = 0; i < nurbsSurface.VKnotCount; i++) + int j = 0; + while (j < mesh.faces.Count) + { + int n = mesh.faces[j]; + if (n < 3) { - knotsV.Add(nurbsSurface.get_VKnotAt(Convert.ToUInt32(i))); + n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility } - var range = nurbsSurface.GetPoleRange(); - nurbsSurface.GetParameterRegion(out double uMin, out double uMax, out double vMin, out double vMax); + List faceVertices = mesh.faces.GetRange(j + 1, n).Select(x => vertices[x]).ToList(); - var _surface = new Surface() + if (faceVertices.Count > 0) { - degreeU = nurbsSurface.UOrder - 1, - degreeV = nurbsSurface.VOrder - 1, - rational = nurbsSurface.IsRational, - closedU = nurbsSurface.IsUClosed, - closedV = nurbsSurface.IsVClosed, - knotsU = knotsU, - knotsV = knotsV, - countU = nurbsSurface.UKnotCount, - countV = nurbsSurface.VKnotCount, - domainU = new Interval(uMin, uMax), - domainV = new Interval(vMin, vMax) - }; - - _surface.units = u; - - double area = GetElementProperty(surface, "SurfaceArea").DoubleValue; - _surface.area = area / Math.Pow(UoR, 2); - - //var _points = new List(); - //for (int i = 0; i < nurbsSurface.PoleCount; i++) - //{ - // _points.Add(nurbsSurface.get_PoleAt(Convert.ToUInt32(i))); - //} - - //var controlPoints = GetElementProperty(surface, "UVData.ControlPointData.ControlPoints").ContainedValues; - //var controlPointWeights = GetElementProperty(surface, "UVData.ControlPointData.ControlPointsWeights").ContainedValues; - //var controlPointRows = GetElementProperty(surface, "UVData.ControlPointData.ControlPointRows").ContainedValues; - - //var points = new List>(); - - //foreach (var _row in controlPointRows) - //{ - // var _pts = _row.ContainedValues["ControlPoints"].ContainedValues.ToList(); - // var _weight = _row.ContainedValues["ControlPointsWeights"].ContainedValues.ToList(); - - // var weight = new List(); - // if (!_weight.Any()) - // weight = Enumerable.Repeat((double)1, _pts.Count()).ToList(); - // else - // weight = _weight.Select(x => x.DoubleValue).ToList(); - // for(int i = 0; i < _pts.Count(); i++) - // { - // var row = new List(); - // var point = (DPoint3d)_pts[i].NativeValue; - // row.Add(new ControlPoint(ScaleToSpeckle(point.X, UoR), ScaleToSpeckle(point.Y, UoR), ScaleToSpeckle(point.Z, UoR), weight[i], null)); - - // points.Add(row); - // } - //} - - var _points = ControlPointsToSpeckle(nurbsSurface); - _surface.SetControlPoints(_points); - - bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; - _surface.bbox = BoxToSpeckle(range, worldXY); - - return _surface; + meshData.AddPolygon(faceVertices, new List(), new List()); + } + + j += n + 1; } - public List> ControlPointsToSpeckle(MSBsplineSurface surface) - { - var points = new List>(); - for (var i = 0; i < surface.PoleCount; i++) - { - var row = new List(); + var _mesh = new MeshHeaderElement(Model, null, meshData); - var point = surface.get_PoleAt(Convert.ToUInt32(i)); - var weight = surface.get_WeightAt(Convert.ToUInt32(i)); - row.Add(new ControlPoint(ScaleToSpeckle(point.X, UoR), ScaleToSpeckle(point.Y, UoR), ScaleToSpeckle(point.Z, UoR), weight, ModelUnits)); + meshData.Dispose(); - points.Add(row); - } - return points; + return _mesh; + } + + // Nurbs surface + public Surface SurfaceToSpeckle(BSplineSurfaceElement surface, string units = null) + { + var u = units ?? ModelUnits; + + var nurbsSurface = surface.GetBsplineSurface(); + + var knotsU = new List(); + for (int i = 0; i < nurbsSurface.UKnotCount; i++) + { + knotsU.Add(nurbsSurface.get_UKnotAt(Convert.ToUInt32(i))); + } + + var knotsV = new List(); + for (int i = 0; i < nurbsSurface.VKnotCount; i++) + { + knotsV.Add(nurbsSurface.get_VKnotAt(Convert.ToUInt32(i))); } - public Base ExtendedElementToSpeckle(ExtendedElementElement extendedElement, string units = null) + var range = nurbsSurface.GetPoleRange(); + nurbsSurface.GetParameterRegion(out double uMin, out double uMax, out double vMin, out double vMax); + + var _surface = new Surface() { - var element = new Base(); + degreeU = nurbsSurface.UOrder - 1, + degreeV = nurbsSurface.VOrder - 1, + rational = nurbsSurface.IsRational, + closedU = nurbsSurface.IsUClosed, + closedV = nurbsSurface.IsVClosed, + knotsU = knotsU, + knotsV = knotsV, + countU = nurbsSurface.UKnotCount, + countV = nurbsSurface.VKnotCount, + domainU = new Interval(uMin, uMax), + domainV = new Interval(vMin, vMax) + }; + + _surface.units = u; + + double area = GetElementProperty(surface, "SurfaceArea").DoubleValue; + _surface.area = area / Math.Pow(UoR, 2); + + //var _points = new List(); + //for (int i = 0; i < nurbsSurface.PoleCount; i++) + //{ + // _points.Add(nurbsSurface.get_PoleAt(Convert.ToUInt32(i))); + //} + + //var controlPoints = GetElementProperty(surface, "UVData.ControlPointData.ControlPoints").ContainedValues; + //var controlPointWeights = GetElementProperty(surface, "UVData.ControlPointData.ControlPointsWeights").ContainedValues; + //var controlPointRows = GetElementProperty(surface, "UVData.ControlPointData.ControlPointRows").ContainedValues; + + //var points = new List>(); + + //foreach (var _row in controlPointRows) + //{ + // var _pts = _row.ContainedValues["ControlPoints"].ContainedValues.ToList(); + // var _weight = _row.ContainedValues["ControlPointsWeights"].ContainedValues.ToList(); + + // var weight = new List(); + // if (!_weight.Any()) + // weight = Enumerable.Repeat((double)1, _pts.Count()).ToList(); + // else + // weight = _weight.Select(x => x.DoubleValue).ToList(); + // for(int i = 0; i < _pts.Count(); i++) + // { + // var row = new List(); + // var point = (DPoint3d)_pts[i].NativeValue; + // row.Add(new ControlPoint(ScaleToSpeckle(point.X, UoR), ScaleToSpeckle(point.Y, UoR), ScaleToSpeckle(point.Z, UoR), weight[i], null)); + + // points.Add(row); + // } + //} + + var _points = ControlPointsToSpeckle(nurbsSurface); + _surface.SetControlPoints(_points); - var segments = new List(); + bool worldXY = range.Low.Z == 0 && range.High.Z == 0 ? true : false; + _surface.bbox = BoxToSpeckle(range, worldXY); - Processor processor = new Processor(); - ElementGraphicsOutput.Process(extendedElement, processor); - var curves = processor.curveVectors; + return _surface; + } + + public List> ControlPointsToSpeckle(MSBsplineSurface surface) + { + var points = new List>(); + for (var i = 0; i < surface.PoleCount; i++) + { + var row = new List(); + + var point = surface.get_PoleAt(Convert.ToUInt32(i)); + var weight = surface.get_WeightAt(Convert.ToUInt32(i)); + row.Add( + new ControlPoint( + ScaleToSpeckle(point.X, UoR), + ScaleToSpeckle(point.Y, UoR), + ScaleToSpeckle(point.Z, UoR), + weight, + ModelUnits + ) + ); + + points.Add(row); + } + return points; + } + + public Base ExtendedElementToSpeckle(ExtendedElementElement extendedElement, string units = null) + { + var element = new Base(); + + var segments = new List(); + + Processor processor = new(); + ElementGraphicsOutput.Process(extendedElement, processor); + var curves = processor.curveVectors; - if (curves.Any()) + if (curves.Any()) + { + foreach (var curve in curves) { - foreach (var curve in curves) + foreach (var primitive in curve) { - foreach (var primitive in curve) - { - var curvePrimitiveType = primitive.GetCurvePrimitiveType(); + var curvePrimitiveType = primitive.GetCurvePrimitiveType(); - switch (curvePrimitiveType) - { - case CurvePrimitive.CurvePrimitiveType.Line: - primitive.TryGetLine(out DSegment3d segment); - segments.Add(LineToSpeckle(segment)); - break; - case CurvePrimitive.CurvePrimitiveType.Arc: - primitive.TryGetArc(out DEllipse3d arc); - segments.Add(ArcToSpeckle(arc)); - break; - case CurvePrimitive.CurvePrimitiveType.LineString: - var pointList = new List(); - primitive.TryGetLineString(pointList); - segments.Add(PolylineToSpeckle(pointList)); - break; - case CurvePrimitive.CurvePrimitiveType.BsplineCurve: - var spline = primitive.GetBsplineCurve(); - segments.Add(BSplineCurveToSpeckle(spline)); - break; - case CurvePrimitive.CurvePrimitiveType.Spiral: - var spiralSpline = primitive.GetProxyBsplineCurve(); - segments.Add(SpiralCurveElementToCurve(spiralSpline)); - break; - } + switch (curvePrimitiveType) + { + case CurvePrimitive.CurvePrimitiveType.Line: + primitive.TryGetLine(out DSegment3d segment); + segments.Add(LineToSpeckle(segment)); + break; + case CurvePrimitive.CurvePrimitiveType.Arc: + primitive.TryGetArc(out DEllipse3d arc); + segments.Add(ArcToSpeckle(arc)); + break; + case CurvePrimitive.CurvePrimitiveType.LineString: + var pointList = new List(); + primitive.TryGetLineString(pointList); + segments.Add(PolylineToSpeckle(pointList)); + break; + case CurvePrimitive.CurvePrimitiveType.BsplineCurve: + var spline = primitive.GetBsplineCurve(); + segments.Add(BSplineCurveToSpeckle(spline)); + break; + case CurvePrimitive.CurvePrimitiveType.Spiral: + var spiralSpline = primitive.GetProxyBsplineCurve(); + segments.Add(SpiralCurveElementToCurve(spiralSpline)); + break; } } } - - element["segments"] = segments; - return element; } - public Base CellHeaderElementToSpeckle(CellHeaderElement cellHeader, string units = null) - { - var element = new Base(); + element["segments"] = segments; + return element; + } + public Base CellHeaderElementToSpeckle(CellHeaderElement cellHeader, string units = null) + { + var element = new Base(); - return element; - } + return element; + } - public CellHeaderElement CellHeaderElementToNative(Base cellHeader, string units = null) - { - var element = new CellHeaderElement(Model, null, new DPoint3d(), new DMatrix3d(), new List() { }); + public CellHeaderElement CellHeaderElementToNative(Base cellHeader, string units = null) + { + var element = new CellHeaderElement(Model, null, new DPoint3d(), new DMatrix3d(), new List() { }); + return element; + } - return element; - } + public Base Type2ElementToSpeckle(Type2Element cellHeader, string units = null) + { + var element = new Base(); + Processor processor = new(); + ElementGraphicsOutput.Process(cellHeader, processor); + var x = cellHeader.GetChildren(); + var segments = new List(); + var curves = processor.curveVectors; - public Base Type2ElementToSpeckle(Type2Element cellHeader, string units = null) + if (curves.Any()) { - var element = new Base(); - Processor processor = new Processor(); - ElementGraphicsOutput.Process(cellHeader, processor); - - var x = cellHeader.GetChildren(); - var segments = new List(); - var curves = processor.curveVectors; - - if (curves.Any()) + foreach (var curve in curves) { - foreach (var curve in curves) + foreach (var primitive in curve) { - foreach (var primitive in curve) - { - var curvePrimitiveType = primitive.GetCurvePrimitiveType(); + var curvePrimitiveType = primitive.GetCurvePrimitiveType(); - switch (curvePrimitiveType) - { - case CurvePrimitive.CurvePrimitiveType.Line: - primitive.TryGetLine(out DSegment3d segment); - segments.Add(LineToSpeckle(segment)); - break; - case CurvePrimitive.CurvePrimitiveType.Arc: - primitive.TryGetArc(out DEllipse3d arc); - segments.Add(ArcToSpeckle(arc)); - break; - case CurvePrimitive.CurvePrimitiveType.LineString: - var pointList = new List(); - primitive.TryGetLineString(pointList); - segments.Add(PolylineToSpeckle(pointList)); - break; - case CurvePrimitive.CurvePrimitiveType.BsplineCurve: - var spline = primitive.GetBsplineCurve(); - segments.Add(BSplineCurveToSpeckle(spline)); - break; - case CurvePrimitive.CurvePrimitiveType.Spiral: - var spiralSpline = primitive.GetProxyBsplineCurve(); - segments.Add(SpiralCurveElementToCurve(spiralSpline)); - break; - } + switch (curvePrimitiveType) + { + case CurvePrimitive.CurvePrimitiveType.Line: + primitive.TryGetLine(out DSegment3d segment); + segments.Add(LineToSpeckle(segment)); + break; + case CurvePrimitive.CurvePrimitiveType.Arc: + primitive.TryGetArc(out DEllipse3d arc); + segments.Add(ArcToSpeckle(arc)); + break; + case CurvePrimitive.CurvePrimitiveType.LineString: + var pointList = new List(); + primitive.TryGetLineString(pointList); + segments.Add(PolylineToSpeckle(pointList)); + break; + case CurvePrimitive.CurvePrimitiveType.BsplineCurve: + var spline = primitive.GetBsplineCurve(); + segments.Add(BSplineCurveToSpeckle(spline)); + break; + case CurvePrimitive.CurvePrimitiveType.Spiral: + var spiralSpline = primitive.GetProxyBsplineCurve(); + segments.Add(SpiralCurveElementToCurve(spiralSpline)); + break; } } } - - element["segments"] = segments; - - return element; } + element["segments"] = segments; + return element; + } - internal class Processor : ElementGraphicsProcessor - { - private DTransform3d _transform; + internal class Processor : ElementGraphicsProcessor + { + private DTransform3d _transform; - public List curveVectors = new List(); - public List curvePrimitives = new List(); - public List elements = new List(); + public List curveVectors = new(); + public List curvePrimitives = new(); + public List elements = new(); - public override void AnnounceElementDisplayParameters(ElementDisplayParameters displayParams) - { - var asdfsaf = displayParams.ElementClass; - } + public override void AnnounceElementDisplayParameters(ElementDisplayParameters displayParams) + { + var asdfsaf = displayParams.ElementClass; + } - public override void AnnounceElementMatSymbology(ElementMatSymbology matSymb) - { - } + public override void AnnounceElementMatSymbology(ElementMatSymbology matSymb) { } - public override void AnnounceIdentityTransform() - { - } + public override void AnnounceIdentityTransform() { } - public override void AnnounceTransform(DTransform3d trans) - { - _transform = trans; - } + public override void AnnounceTransform(DTransform3d trans) + { + _transform = trans; + } - public override bool ProcessAsBody(bool isCurved) + public override bool ProcessAsBody(bool isCurved) + { + if (isCurved) { - if (isCurved) - return true; - else - return false; + return true; } - - public override bool ProcessAsFacets(bool isPolyface) + else { - if (isPolyface) - return true; - else - return false; + return false; } + } - public override BentleyStatus ProcessSurface(MSBsplineSurface surface) + public override bool ProcessAsFacets(bool isPolyface) + { + if (isPolyface) { - return BentleyStatus.Error; + return true; } - - public override BentleyStatus ProcessFacets(PolyfaceHeader meshData, bool filled) + else { - return BentleyStatus.Error; + return false; } + } - public override BentleyStatus ProcessCurveVector(CurveVector vector, bool isFilled) - { - vector.GetRange(out DRange3d range); - curveVectors.Add(vector.Clone()); - - return BentleyStatus.Success; - } + public override BentleyStatus ProcessSurface(MSBsplineSurface surface) + { + return BentleyStatus.Error; + } - public override BentleyStatus ProcessCurvePrimitive(CurvePrimitive curvePrimitive, bool isClosed, bool isFilled) - { - curvePrimitives.Add(curvePrimitive); - var curvePrimitiveType = curvePrimitive.GetCurvePrimitiveType(); + public override BentleyStatus ProcessFacets(PolyfaceHeader meshData, bool filled) + { + return BentleyStatus.Error; + } - Base geometry = null; - switch (curvePrimitiveType) - { - case CurvePrimitive.CurvePrimitiveType.LineString: - var pointList = new List(); - curvePrimitive.TryGetLineString(pointList); - //PolylineToSpeckle(pointList); - - break; - case CurvePrimitive.CurvePrimitiveType.Arc: - curvePrimitive.TryGetArc(out DEllipse3d arc); - break; - case CurvePrimitive.CurvePrimitiveType.Line: - curvePrimitive.TryGetLine(out DSegment3d segment); - break; - case CurvePrimitive.CurvePrimitiveType.BsplineCurve: - var curve = curvePrimitive.GetBsplineCurve(); - break; + public override BentleyStatus ProcessCurveVector(CurveVector vector, bool isFilled) + { + vector.GetRange(out DRange3d range); + curveVectors.Add(vector.Clone()); - } + return BentleyStatus.Success; + } - return BentleyStatus.Success; - } + public override BentleyStatus ProcessCurvePrimitive(CurvePrimitive curvePrimitive, bool isClosed, bool isFilled) + { + curvePrimitives.Add(curvePrimitive); + var curvePrimitiveType = curvePrimitive.GetCurvePrimitiveType(); - public override bool WantClipping() + Base geometry = null; + switch (curvePrimitiveType) { - return false; + case CurvePrimitive.CurvePrimitiveType.LineString: + var pointList = new List(); + curvePrimitive.TryGetLineString(pointList); + //PolylineToSpeckle(pointList); + + break; + case CurvePrimitive.CurvePrimitiveType.Arc: + curvePrimitive.TryGetArc(out DEllipse3d arc); + break; + case CurvePrimitive.CurvePrimitiveType.Line: + curvePrimitive.TryGetLine(out DSegment3d segment); + break; + case CurvePrimitive.CurvePrimitiveType.BsplineCurve: + var curve = curvePrimitive.GetBsplineCurve(); + break; } + + return BentleyStatus.Success; + } + + public override bool WantClipping() + { + return false; } } } diff --git a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.GridSystems.cs b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.GridSystems.cs index 5d80860f24..1da28f88e7 100644 --- a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.GridSystems.cs +++ b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.GridSystems.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; @@ -13,297 +13,334 @@ using Bentley.Building.Api; #endif -namespace Objects.Converter.Bentley +namespace Objects.Converter.Bentley; + +public partial class ConverterBentley { - public partial class ConverterBentley - { #if (OPENBUILDINGS) - private static GridLine CreateGridLine(ICurve baseLine, string label, string units) + private static GridLine CreateGridLine(ICurve baseLine, string label, string units) + { + GridLine gridLine = new(); + gridLine.baseLine = baseLine; + gridLine.label = label; + gridLine.units = units; + return gridLine; + } + + public static ITFLoadableProject GetCurrentProject() + { + ITFApplication appInst = new TFApplicationList(); + + if (0 == appInst.GetProject(0, out ITFLoadableProjectList projList) && projList != null) { - GridLine gridLine = new GridLine(); - gridLine.baseLine = baseLine; - gridLine.label = label; - gridLine.units = units; - return gridLine; + ITFLoadableProject proj = projList.AsTFLoadableProject; + return proj; } + return null; + } - public static ITFLoadableProject GetCurrentProject() - { - ITFApplication appInst = new TFApplicationList(); + private static Point Rotate(Point point, double angle) + { + double sin = Math.Sin(angle); + double cos = Math.Cos(angle); + Point p = new(cos * point.x - sin * point.y, sin * point.x + cos * point.y); + p.units = point.units; + return p; + } - if (0 == appInst.GetProject(0, out ITFLoadableProjectList projList) && projList != null) - { - ITFLoadableProject proj = projList.AsTFLoadableProject; - return proj; - } - return null; - } + private static Vector Rotate(Vector vector, double angle) + { + double sin = Math.Sin(angle); + double cos = Math.Cos(angle); + Vector v = new(cos * vector.x - sin * vector.y, sin * vector.x + cos * vector.y, vector.units); + return v; + } - private static Point Rotate(Point point, double angle) - { - double sin = Math.Sin(angle); - double cos = Math.Cos(angle); - Point p = new Point(cos * point.x - sin * point.y, sin * point.x + cos * point.y); - p.units = point.units; - return p; - } + private static Point Translate(Point point, double deltaX, double deltaY) + { + Point p = new(point.x + deltaX, point.y + deltaY); + p.units = point.units; + return p; + } - private static Vector Rotate(Vector vector, double angle) - { - double sin = Math.Sin(angle); - double cos = Math.Cos(angle); - Vector v = new Vector(cos * vector.x - sin * vector.y, sin * vector.x + cos * vector.y, vector.units); - return v; - } + private static Vector Translate(Vector vector, double deltaX, double deltaY) + { + Vector v = new(vector.x + deltaX, vector.y + deltaY, vector.units); + return v; + } - private static Point Translate(Point point, double deltaX, double deltaY) - { - Point p = new Point(point.x + deltaX, point.y + deltaY); - p.units = point.units; - return p; - } + public Base GridSystemsToSpeckle(ITFDrawingGrid drawingGrid, string units = null) + { + Base container = new(); + List gridLines = new(); + container["Grid Lines"] = gridLines; - private static Vector Translate(Vector vector, double deltaX, double deltaY) + drawingGrid.GetGridSystems(0, out ITFGridSystemList gridSystems); + if (gridSystems == null) { - Vector v = new Vector(vector.x + deltaX, vector.y + deltaY, vector.units); - return v; + return null; } - public Base GridSystemsToSpeckle(ITFDrawingGrid drawingGrid, string units = null) + for (ITFGridSystem gridSystem = gridSystems.AsTFGridSystem; + gridSystem != null; + gridSystems.GetNext("", out gridSystems), gridSystem = (gridSystems != null) ? gridSystems.AsTFGridSystem : null) { - Base container = new Base(); - List gridLines = new List(); - container["Grid Lines"] = gridLines; - - drawingGrid.GetGridSystems(0, out ITFGridSystemList gridSystems); - if (gridSystems == null) - return null; + gridSystem.GetGridCurves(0, out ITFGridCurveList curves); - for (ITFGridSystem gridSystem = gridSystems.AsTFGridSystem; - gridSystem != null; - gridSystems.GetNext("", out gridSystems), gridSystem = (gridSystems != null) ? gridSystems.AsTFGridSystem : null) + if (curves == null) { - gridSystem.GetGridCurves(0, out ITFGridCurveList curves); + continue; + } - if (curves == null) - continue; + gridSystem.GetLCS(out DPoint3d origin, 0, out double angle); - gridSystem.GetLCS(out DPoint3d origin, 0, out double angle); + gridSystem.GetMinGridLineExtension(0, out double mindGridLineExtendsion); - gridSystem.GetMinGridLineExtension(0, out double mindGridLineExtendsion); + // find overall minimum/maximum extends of grid lines + double minimumValueX = 0; + double minimumValueY = 0; + double maximumValueX = 0; + double maximumValueY = 0; + double maximumRadius = 0; + double maximumCircularAngle = 0; - // find overall minimum/maximum extends of grid lines - double minimumValueX = 0; - double minimumValueY = 0; - double maximumValueX = 0; - double maximumValueY = 0; - double maximumRadius = 0; - double maximumCircularAngle = 0; + List gridCurveList = new(); + for (ITFGridCurve gridCurve = curves.AsTFGridCurve; gridCurve != null; curves.GetNext("", out curves), gridCurve = curves != null ? curves.AsTFGridCurve : null) + { + gridCurveList.Add(gridCurve); + gridCurve.GetType(0, out TFdGridCurveType curveType); + gridCurve.GetValue(0, out double gridValue); + gridCurve.GetMinimumValue(0, out double minimumValue); - List gridCurveList = new List(); - for (ITFGridCurve gridCurve = curves.AsTFGridCurve; gridCurve != null; curves.GetNext("", out curves), gridCurve = curves != null ? curves.AsTFGridCurve : null) + switch (curveType) { - gridCurveList.Add(gridCurve); - gridCurve.GetType(0, out TFdGridCurveType curveType); - gridCurve.GetValue(0, out double gridValue); - gridCurve.GetMinimumValue(0, out double minimumValue); - - switch (curveType) - { - case (TFdGridCurveType.TFdGridCurveType_OrthogonalX): - if (gridValue < minimumValueX) - minimumValueX = gridValue; - // grid lines pick up the minimum value of their neighbors - if (minimumValue < minimumValueY) - minimumValueY = minimumValue; - if (gridValue > maximumValueX) - maximumValueX = gridValue; - break; - - case (TFdGridCurveType.TFdGridCurveType_OrthogonalY): - if (gridValue < minimumValueY) - minimumValueY = gridValue; - // grid lines pick up the minimum value of their neighbors - if (minimumValue < minimumValueX) - minimumValueX = minimumValue; - if (gridValue > maximumValueY) - maximumValueY = gridValue; - break; - - case (TFdGridCurveType.TFdGridCurveType_Circular): - if (gridValue > maximumRadius) - maximumRadius = gridValue; - break; - - case (TFdGridCurveType.TFdGridCurveType_Radial): - if (gridValue > maximumCircularAngle) - maximumCircularAngle = gridValue; - break; - - default: - break; - } + case (TFdGridCurveType.TFdGridCurveType_OrthogonalX): + if (gridValue < minimumValueX) + { + minimumValueX = gridValue; + } + + // grid lines pick up the minimum value of their neighbors + if (minimumValue < minimumValueY) + { + minimumValueY = minimumValue; + } + + if (gridValue > maximumValueX) + { + maximumValueX = gridValue; + } + + break; + + case (TFdGridCurveType.TFdGridCurveType_OrthogonalY): + if (gridValue < minimumValueY) + { + minimumValueY = gridValue; + } + + // grid lines pick up the minimum value of their neighbors + if (minimumValue < minimumValueX) + { + minimumValueX = minimumValue; + } + + if (gridValue > maximumValueY) + { + maximumValueY = gridValue; + } + + break; + + case (TFdGridCurveType.TFdGridCurveType_Circular): + if (gridValue > maximumRadius) + { + maximumRadius = gridValue; + } + + break; + + case (TFdGridCurveType.TFdGridCurveType_Radial): + if (gridValue > maximumCircularAngle) + { + maximumCircularAngle = gridValue; + } + + break; + + default: + break; } + } - // for some reason only angles are scaled - maximumCircularAngle *= UoR; + // for some reason only angles are scaled + maximumCircularAngle *= UoR; - foreach (ITFGridCurve gridCurve in gridCurveList) + foreach (ITFGridCurve gridCurve in gridCurveList) + { + ICurve baseLine; + + gridCurve.GetLabel(0, out string label); + gridCurve.GetType(0, out TFdGridCurveType curveType); + gridCurve.GetValue(0, out double gridValue); + //gridCurve.GetMsElementDescrP(out Element obj, 0); + + var u = units ?? ModelUnits; + + //if (obj != null) + //{ + // // coordinate transformation + // //double axx = Math.Cos(angle); + // //double axy = -Math.Sin(angle); + // //double axz = 0; + // //double axw = origin.X; + // //double ayx = Math.Sin(angle); + // //double ayy = Math.Cos(angle); + // //double ayz = 0; + // //double ayw = origin.Y; + // //double azx = 0; + // //double azy = 0; + // //double azz = 1; + // //double azw = origin.Z; + // //DTransform3d transform = new DTransform3d(axx, axy, axz, axw, ayx, ayy, ayz, ayw, azx, azy, azz, azw); + // if (obj is LineElement) + // { + // Line line = LineToSpeckle((LineElement)obj, u); + // baseLine = TransformCurve(line, origin, angle); + // } + // else if (obj is ArcElement) + // { + // ICurve arc = ArcToSpeckle((ArcElement)obj, u); + // baseLine = arc; + // baseLine = TransformCurve(arc, origin, angle); + // } + // else + // { + // throw new NotSupportedException("GridCurveType " + curveType + " not supported!"); + // } + // gridLines.Add(CreateGridLine(baseLine, label, u)); + //} + switch (curveType) { - ICurve baseLine; - - gridCurve.GetLabel(0, out string label); - gridCurve.GetType(0, out TFdGridCurveType curveType); - gridCurve.GetValue(0, out double gridValue); - //gridCurve.GetMsElementDescrP(out Element obj, 0); - - var u = units ?? ModelUnits; - - //if (obj != null) - //{ - // // coordinate transformation - // //double axx = Math.Cos(angle); - // //double axy = -Math.Sin(angle); - // //double axz = 0; - // //double axw = origin.X; - // //double ayx = Math.Sin(angle); - // //double ayy = Math.Cos(angle); - // //double ayz = 0; - // //double ayw = origin.Y; - // //double azx = 0; - // //double azy = 0; - // //double azz = 1; - // //double azw = origin.Z; - // //DTransform3d transform = new DTransform3d(axx, axy, axz, axw, ayx, ayy, ayz, ayw, azx, azy, azz, azw); - // if (obj is LineElement) - // { - // Line line = LineToSpeckle((LineElement)obj, u); - // baseLine = TransformCurve(line, origin, angle); - // } - // else if (obj is ArcElement) - // { - // ICurve arc = ArcToSpeckle((ArcElement)obj, u); - // baseLine = arc; - // baseLine = TransformCurve(arc, origin, angle); - // } - // else - // { - // throw new NotSupportedException("GridCurveType " + curveType + " not supported!"); - // } - // gridLines.Add(CreateGridLine(baseLine, label, u)); - //} - switch (curveType) - { - case TFdGridCurveType.TFdGridCurveType_OrthogonalX: - case TFdGridCurveType.TFdGridCurveType_OrthogonalY: - baseLine = GridCurveToSpeckle(gridCurve, origin, angle, minimumValueX, minimumValueY, maximumValueX, maximumValueY, u); - break; - - case TFdGridCurveType.TFdGridCurveType_Circular: - Plane xy = new Plane(new Point(origin.X, origin.Y, 0, u), new Vector(0, 0, 1, u), new Vector(1, 0, 0, u), new Vector(0, 1, 0, u), u); - baseLine = new Arc(xy, gridValue, angle, maximumCircularAngle + angle, maximumCircularAngle, u); - break; - - case TFdGridCurveType.TFdGridCurveType_Radial: - Point startPoint = Translate(Rotate(new Point(0, 0, 0, u), angle), origin.X, origin.Y); - Point endPoint = Translate(Rotate(Rotate(new Point(maximumRadius, 0, 0, u), gridValue * UoR), angle), origin.X, origin.Y); - baseLine = new Line(startPoint, endPoint, u); - break; - - default: - continue; - - } - gridLines.Add(CreateGridLine(baseLine, label, u)); + case TFdGridCurveType.TFdGridCurveType_OrthogonalX: + case TFdGridCurveType.TFdGridCurveType_OrthogonalY: + baseLine = GridCurveToSpeckle(gridCurve, origin, angle, minimumValueX, minimumValueY, maximumValueX, maximumValueY, u); + break; + + case TFdGridCurveType.TFdGridCurveType_Circular: + Plane xy = new(new Point(origin.X, origin.Y, 0, u), new Vector(0, 0, 1, u), new Vector(1, 0, 0, u), new Vector(0, 1, 0, u), u); + baseLine = new Arc(xy, gridValue, angle, maximumCircularAngle + angle, maximumCircularAngle, u); + break; + + case TFdGridCurveType.TFdGridCurveType_Radial: + Point startPoint = Translate(Rotate(new Point(0, 0, 0, u), angle), origin.X, origin.Y); + Point endPoint = Translate(Rotate(Rotate(new Point(maximumRadius, 0, 0, u), gridValue * UoR), angle), origin.X, origin.Y); + baseLine = new Line(startPoint, endPoint, u); + break; + + default: + continue; + } + gridLines.Add(CreateGridLine(baseLine, label, u)); } - return container; } + return container; + } - private ICurve TransformCurve(ICurve c, DPoint3d origin, double angle) + private ICurve TransformCurve(ICurve c, DPoint3d origin, double angle) + { + if (c is Line) { - if (c is Line) - { - Line line = (Line)c; - Point start = Translate(Rotate(line.start, angle), origin.X, origin.Y); - Point end = Translate(Rotate(line.end, angle), origin.X, origin.Y); - return new Line(start, end, line.units); - } - else if (c is Arc) - { - Arc arc = (Arc)c; - Point startPoint = Translate(Rotate(arc.startPoint, angle), origin.X, origin.Y); - Point midPoint = Translate(Rotate(arc.midPoint, angle), origin.X, origin.Y); - Point endPoint = Translate(Rotate(arc.endPoint, angle), origin.X, origin.Y); - Plane plane = TransformPlane(arc.plane, origin, angle); - Arc transformed = new Arc(plane, (double)arc.radius, (double)arc.startAngle + angle + Math.PI * 2, (double)arc.endAngle + angle + Math.PI * 2, (double)arc.angleRadians, arc.units); - transformed.startPoint = startPoint; - transformed.midPoint = midPoint; - transformed.endPoint = endPoint; - return transformed; - } - else if (c is Circle) - { - Circle circle = (Circle)c; - Plane plane = TransformPlane(circle.plane, origin, angle); - return new Circle(plane, (double)circle.radius, circle.units); - } - else - { - throw new NotSupportedException("ICurve " + c.GetType() + " not supported!"); - } - return null; + Line line = (Line)c; + Point start = Translate(Rotate(line.start, angle), origin.X, origin.Y); + Point end = Translate(Rotate(line.end, angle), origin.X, origin.Y); + return new Line(start, end, line.units); } - - private Plane TransformPlane(Plane plane, DPoint3d origin, double angle) + else if (c is Arc) + { + Arc arc = (Arc)c; + Point startPoint = Translate(Rotate(arc.startPoint, angle), origin.X, origin.Y); + Point midPoint = Translate(Rotate(arc.midPoint, angle), origin.X, origin.Y); + Point endPoint = Translate(Rotate(arc.endPoint, angle), origin.X, origin.Y); + Plane plane = TransformPlane(arc.plane, origin, angle); + Arc transformed = new(plane, (double)arc.radius, (double)arc.startAngle + angle + Math.PI * 2, (double)arc.endAngle + angle + Math.PI * 2, (double)arc.angleRadians, arc.units); + transformed.startPoint = startPoint; + transformed.midPoint = midPoint; + transformed.endPoint = endPoint; + return transformed; + } + else if (c is Circle) + { + Circle circle = (Circle)c; + Plane plane = TransformPlane(circle.plane, origin, angle); + return new Circle(plane, (double)circle.radius, circle.units); + } + else { - Point planeOrigin = Translate(plane.origin, origin.X, origin.Y); - Vector xdir = Translate(Rotate(plane.xdir, angle), origin.X, origin.Y); - Vector ydir = Translate(Rotate(plane.ydir, angle), origin.X, origin.Y); - return new Plane(planeOrigin, plane.normal, xdir, ydir, plane.units); + throw new NotSupportedException("ICurve " + c.GetType() + " not supported!"); } + return null; + } + + private Plane TransformPlane(Plane plane, DPoint3d origin, double angle) + { + Point planeOrigin = Translate(plane.origin, origin.X, origin.Y); + Vector xdir = Translate(Rotate(plane.xdir, angle), origin.X, origin.Y); + Vector ydir = Translate(Rotate(plane.ydir, angle), origin.X, origin.Y); + return new Plane(planeOrigin, plane.normal, xdir, ydir, plane.units); + } - public static ICurve GridCurveToSpeckle(ITFGridCurve gridCurve, DPoint3d origin, double angle, double minimumValueX = 0, double minimumValueY = 0, double maximumValueX = 0, double maximumValueY = 0, string units = null) + public static ICurve GridCurveToSpeckle(ITFGridCurve gridCurve, DPoint3d origin, double angle, double minimumValueX = 0, double minimumValueY = 0, double maximumValueX = 0, double maximumValueY = 0, string units = null) + { + ICurve baseLine; + + gridCurve.GetType(0, out TFdGridCurveType curveType); + gridCurve.GetMinimumValue(0, out double minimumValue); + gridCurve.GetMaximumValue(0, out double maximumValue); + gridCurve.GetValue(0, out double gridValue); + + Point startPoint, endPoint; + switch (curveType) { - ICurve baseLine; + case (TFdGridCurveType.TFdGridCurveType_OrthogonalX): + if (minimumValue == 0) + { + minimumValue = minimumValueY; + } - gridCurve.GetType(0, out TFdGridCurveType curveType); - gridCurve.GetMinimumValue(0, out double minimumValue); - gridCurve.GetMaximumValue(0, out double maximumValue); - gridCurve.GetValue(0, out double gridValue); + if (maximumValue == 0) + { + maximumValue = maximumValueY; + } - Point startPoint, endPoint; - switch (curveType) - { - case (TFdGridCurveType.TFdGridCurveType_OrthogonalX): - if (minimumValue == 0) - minimumValue = minimumValueY; - if (maximumValue == 0) - maximumValue = maximumValueY; - - startPoint = Translate(Rotate(new Point(gridValue, minimumValue, 0, units), angle), origin.X, origin.Y); - endPoint = Translate(Rotate(new Point(gridValue, maximumValue, 0, units), angle), origin.X, origin.Y); - baseLine = new Line(startPoint, endPoint, units); - break; - - case (TFdGridCurveType.TFdGridCurveType_OrthogonalY): - if (minimumValue == 0) - minimumValue = minimumValueX; - if (maximumValue == 0) - maximumValue = maximumValueX; - - startPoint = Translate(Rotate(new Point(minimumValue, gridValue, 0, units), angle), origin.X, origin.Y); - endPoint = Translate(Rotate(new Point(maximumValue, gridValue, 0, units), angle), origin.X, origin.Y); - baseLine = new Line(startPoint, endPoint, units); - break; - - default: - throw new NotSupportedException("GridCurveType " + curveType + " not supported!"); + startPoint = Translate(Rotate(new Point(gridValue, minimumValue, 0, units), angle), origin.X, origin.Y); + endPoint = Translate(Rotate(new Point(gridValue, maximumValue, 0, units), angle), origin.X, origin.Y); + baseLine = new Line(startPoint, endPoint, units); + break; + + case (TFdGridCurveType.TFdGridCurveType_OrthogonalY): + if (minimumValue == 0) + { + minimumValue = minimumValueX; + } + + if (maximumValue == 0) + { + maximumValue = maximumValueX; + } + + startPoint = Translate(Rotate(new Point(minimumValue, gridValue, 0, units), angle), origin.X, origin.Y); + endPoint = Translate(Rotate(new Point(maximumValue, gridValue, 0, units), angle), origin.X, origin.Y); + baseLine = new Line(startPoint, endPoint, units); + break; + + default: + throw new NotSupportedException("GridCurveType " + curveType + " not supported!"); - } - return baseLine; } -#endif + return baseLine; } -} \ No newline at end of file +#endif +} diff --git a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Utils.cs b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Utils.cs index 030dd9e65c..f8d2271a75 100644 --- a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Utils.cs +++ b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.Utils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using System.Linq; @@ -19,195 +19,195 @@ using System.Diagnostics; -namespace Objects.Converter.Bentley +namespace Objects.Converter.Bentley; + +public partial class ConverterBentley { - public partial class ConverterBentley + /// + /// Computes the Speckle Units of the current model. The active MicroStation model is passed as a reference, so it will always be up to date. + /// + private string _modelUnits; + public string ModelUnits { - /// - /// Computes the Speckle Units of the current model. The active MicroStation model is passed as a reference, so it will always be up to date. - /// - private string _modelUnits; - public string ModelUnits + get { - get + if (string.IsNullOrEmpty(_modelUnits)) { - if (string.IsNullOrEmpty(_modelUnits)) - { - DgnModel Model = Session.Instance.GetActiveDgnModel(); - var us = Model.GetModelInfo().GetMasterUnit().GetName(true, true); - _modelUnits = UnitToSpeckle(us); - } - return _modelUnits; + DgnModel Model = Session.Instance.GetActiveDgnModel(); + var us = Model.GetModelInfo().GetMasterUnit().GetName(true, true); + _modelUnits = UnitToSpeckle(us); } + return _modelUnits; } + } - private void SetUnits(Base geom) - { - geom["units"] = ModelUnits; - } + private void SetUnits(Base geom) + { + geom["units"] = ModelUnits; + } - private double ScaleToNative(double value, string units) - { - var f = Units.GetConversionFactor(units, ModelUnits); - return value * f; - } + private double ScaleToNative(double value, string units) + { + var f = Units.GetConversionFactor(units, ModelUnits); + return value * f; + } - private double ScaleToNative(double value, string units, double uor) - { - var f = Units.GetConversionFactor(units, ModelUnits); - return value * f * uor; - } + private double ScaleToNative(double value, string units, double uor) + { + var f = Units.GetConversionFactor(units, ModelUnits); + return value * f * uor; + } - private double ScaleToSpeckle(double value, double uor) - { - return value / uor; - } + private double ScaleToSpeckle(double value, double uor) + { + return value / uor; + } - private string UnitToSpeckle(string us) + private string UnitToSpeckle(string us) + { + switch (us) { - switch (us) - { - //case "Micrometers": - // break; - case "Millimeter": - return Units.Millimeters; - case "Centimeter": - return Units.Centimeters; - case "Meter": - return Units.Meters; - case "Kilometer": - return Units.Kilometers; - //case "Microinches": - // break; - //case "Mils": - //break; - case "Inches": - return Units.Inches; - case "Feet": - case "Foot": - return Units.Feet; - case "Yards": - return Units.Yards; - case "Miles": - return Units.Miles; - //case "Nautical Miles": - // break; - default: - throw new System.Exception("The current Unit System is unsupported."); - } + //case "Micrometers": + // break; + case "Millimeter": + return Units.Millimeters; + case "Centimeter": + return Units.Centimeters; + case "Meter": + return Units.Meters; + case "Kilometer": + return Units.Kilometers; + //case "Microinches": + // break; + //case "Mils": + //break; + case "Inches": + return Units.Inches; + case "Feet": + case "Foot": + return Units.Feet; + case "Yards": + return Units.Yards; + case "Miles": + return Units.Miles; + //case "Nautical Miles": + // break; + default: + throw new System.Exception("The current Unit System is unsupported."); } + } - public Objects.Other.DisplayStyle GetStyle(Element obj) - { - var style = new Objects.Other.DisplayStyle(); - Element entity = obj as Element; - - throw new NotImplementedException(); - - //try - //{ - // // get color - // int color = System.Drawing.Color.Black.ToArgb(); - // switch (entity.Color.ColorMethod) - // { - // case ColorMethod.ByLayer: - // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - // { - // if (entity.LayerId.IsValid) - // { - // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - // color = layer.Color.ColorValue.ToArgb(); - // } - // tr.Commit(); - // } - // break; - // case ColorMethod.ByBlock: - // case ColorMethod.ByAci: - // case ColorMethod.ByColor: - // color = entity.Color.ColorValue.ToArgb(); - // break; - // } - // style.color = color; - - // // get linetype - // style.linetype = entity.Linetype; - // if (entity.Linetype == "BYLAYER") - // { - // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - // { - // if (entity.LayerId.IsValid) - // { - // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - // var linetype = (LinetypeTableRecord)tr.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); - // style.linetype = linetype.Name; - // } - // tr.Commit(); - // } - // } - - // // get lineweight - // try - // { - // double lineWeight = 0.25; - // switch (entity.LineWeight) - // { - // case LineWeight.ByLayer: - // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) - // { - // if (entity.LayerId.IsValid) - // { - // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; - // if (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) - // lineWeight = (int)LineWeight.LineWeight025; - // else - // lineWeight = (int)layer.LineWeight; - // } - // tr.Commit(); - // } - // break; - // case LineWeight.ByBlock: - // case LineWeight.ByLineWeightDefault: - // case LineWeight.ByDIPs: - // lineWeight = (int)LineWeight.LineWeight025; - // break; - // default: - // lineWeight = (int)entity.LineWeight; - // break; - // } - // style.lineweight = lineWeight / 100; // convert to mm - // } - // catch { } - - // return style; - //} - //catch - //{ - // return null; - //} - } + public Objects.Other.DisplayStyle GetStyle(Element obj) + { + var style = new Objects.Other.DisplayStyle(); + Element entity = obj as Element; + + throw new NotImplementedException(); + + //try + //{ + // // get color + // int color = System.Drawing.Color.Black.ToArgb(); + // switch (entity.Color.ColorMethod) + // { + // case ColorMethod.ByLayer: + // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // { + // if (entity.LayerId.IsValid) + // { + // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; + // color = layer.Color.ColorValue.ToArgb(); + // } + // tr.Commit(); + // } + // break; + // case ColorMethod.ByBlock: + // case ColorMethod.ByAci: + // case ColorMethod.ByColor: + // color = entity.Color.ColorValue.ToArgb(); + // break; + // } + // style.color = color; + + // // get linetype + // style.linetype = entity.Linetype; + // if (entity.Linetype == "BYLAYER") + // { + // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // { + // if (entity.LayerId.IsValid) + // { + // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; + // var linetype = (LinetypeTableRecord)tr.GetObject(layer.LinetypeObjectId, OpenMode.ForRead); + // style.linetype = linetype.Name; + // } + // tr.Commit(); + // } + // } + + // // get lineweight + // try + // { + // double lineWeight = 0.25; + // switch (entity.LineWeight) + // { + // case LineWeight.ByLayer: + // using (Transaction tr = Doc.Database.TransactionManager.StartTransaction()) + // { + // if (entity.LayerId.IsValid) + // { + // var layer = tr.GetObject(entity.LayerId, OpenMode.ForRead) as LayerTableRecord; + // if (layer.LineWeight == LineWeight.ByLineWeightDefault || layer.LineWeight == LineWeight.ByBlock) + // lineWeight = (int)LineWeight.LineWeight025; + // else + // lineWeight = (int)layer.LineWeight; + // } + // tr.Commit(); + // } + // break; + // case LineWeight.ByBlock: + // case LineWeight.ByLineWeightDefault: + // case LineWeight.ByDIPs: + // lineWeight = (int)LineWeight.LineWeight025; + // break; + // default: + // lineWeight = (int)entity.LineWeight; + // break; + // } + // style.lineweight = lineWeight / 100; // convert to mm + // } + // catch { } + + // return style; + //} + //catch + //{ + // return null; + //} + } - public static DgnECInstanceCollection GetElementProperties(Element element) - { - DgnECManager manager = DgnECManager.Manager; - var properties = manager.GetElementProperties(element, ECQueryProcessFlags.SearchAllClasses); - return properties; - } + public static DgnECInstanceCollection GetElementProperties(Element element) + { + DgnECManager manager = DgnECManager.Manager; + var properties = manager.GetElementProperties(element, ECQueryProcessFlags.SearchAllClasses); + return properties; + } - public IECPropertyValue GetElementProperty(Element element, string propName) + public IECPropertyValue GetElementProperty(Element element, string propName) + { + using (var properties = GetElementProperties(element)) { - using (var properties = GetElementProperties(element)) + foreach (var prop in properties) { - foreach (var prop in properties) + var value = prop.GetPropertyValue(propName); + if (value != null) { - var value = prop.GetPropertyValue(propName); - if (value != null) - { - return value; - } + return value; } - }; - - return null; + } } + ; + + return null; } } diff --git a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.cs b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.cs index 2142e01b61..ecdc6c45f7 100644 --- a/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.cs +++ b/Objects/Converters/ConverterBentley/ConverterBentleyShared/ConverterBentley.cs @@ -45,366 +45,365 @@ using Bentley.CifNET.SDK; #endif -namespace Objects.Converter.Bentley +namespace Objects.Converter.Bentley; + +public partial class ConverterBentley : ISpeckleConverter { - public partial class ConverterBentley : ISpeckleConverter - { #if MICROSTATION - public static string BentleyAppName = HostApplications.MicroStation.Name; + public static string BentleyAppName = HostApplications.MicroStation.Name; #elif OPENROADS - public static string BentleyAppName = HostApplications.OpenRoads.Name; + public static string BentleyAppName = HostApplications.OpenRoads.Name; #elif OPENRAIL - public static string BentleyAppName = HostApplications.OpenRail.Name; + public static string BentleyAppName = HostApplications.OpenRail.Name; #elif OPENBUILDINGS - public static string BentleyAppName = HostApplications.OpenBuildings.Name; + public static string BentleyAppName = HostApplications.OpenBuildings.Name; #endif - public string Description => "Default Speckle Kit for MicroStation, OpenRoads, OpenRail and OpenBuildings"; - public string Name => nameof(ConverterBentley); - public string Author => "Arup"; - public string WebsiteOrEmail => "https://www.arup.com"; + public string Description => "Default Speckle Kit for MicroStation, OpenRoads, OpenRail and OpenBuildings"; + public string Name => nameof(ConverterBentley); + public string Author => "Arup"; + public string WebsiteOrEmail => "https://www.arup.com"; - public IEnumerable GetServicedApplications() => new string[] { BentleyAppName }; + public IEnumerable GetServicedApplications() => new string[] { BentleyAppName }; - public ProgressReport Report { get; private set; } = new ProgressReport(); - public HashSet ConversionErrors { get; private set; } = new HashSet(); - public Session Session { get; private set; } - public DgnFile Doc { get; private set; } - public DgnModel Model { get; private set; } + public ProgressReport Report { get; private set; } = new ProgressReport(); + public HashSet ConversionErrors { get; private set; } = new HashSet(); + public Session Session { get; private set; } + public DgnFile Doc { get; private set; } + public DgnModel Model { get; private set; } #if (OPENROADS || OPENRAIL) - public GeometricModel GeomModel { get; private set; } + public GeometricModel GeomModel { get; private set; } #endif - public double UoR { get; private set; } - public List ContextObjects { get; set; } = new List(); + public double UoR { get; private set; } + public List ContextObjects { get; set; } = new List(); - public void SetContextObjects(List objects) => ContextObjects = objects; + public void SetContextObjects(List objects) => ContextObjects = objects; - public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); + public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); - public void SetConverterSettings(object settings) - { - throw new NotImplementedException("This converter does not have any settings."); - } + public void SetConverterSettings(object settings) + { + throw new NotImplementedException("This converter does not have any settings."); + } - public ReceiveMode ReceiveMode { get; set; } + public ReceiveMode ReceiveMode { get; set; } - public void SetContextDocument(object session) - { - Session = (Session)session; - Doc = (DgnFile)Session.GetActiveDgnFile(); - Model = (DgnModel)Session.GetActiveDgnModel(); - UoR = Model.GetModelInfo().UorPerMaster; + public void SetContextDocument(object session) + { + Session = (Session)session; + Doc = (DgnFile)Session.GetActiveDgnFile(); + Model = (DgnModel)Session.GetActiveDgnModel(); + UoR = Model.GetModelInfo().UorPerMaster; #if (OPENROADS || OPENRAIL) - ConsensusConnection sdkCon = global::Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive(); - GeomModel = sdkCon.GetActiveGeometricModel(); + ConsensusConnection sdkCon = global::Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive(); + GeomModel = sdkCon.GetActiveGeometricModel(); #endif - Report.Log($"Using document: {Doc.GetFileName()}"); - Report.Log($"Using units: {ModelUnits}"); - } + Report.Log($"Using document: {Doc.GetFileName()}"); + Report.Log($"Using units: {ModelUnits}"); + } + + public Base ConvertToSpeckle(object @object) + { + Base @base = null; - public Base ConvertToSpeckle(object @object) + switch (@object) { - Base @base = null; - - switch (@object) - { - case DPoint2d o: - @base = Point2dToSpeckle(o); - Report.Log($"Converted DPoint2d {o}"); - break; - case Point2d o: - @base = Point2dToSpeckle(o); - Report.Log($"Converted Point2d {o}"); - break; - case DPoint3d o: - @base = Point3dToSpeckle(o); - Report.Log($"Converted DPoint3d {o}"); - break; - case Point3d o: - @base = Point3dToSpeckle(o); - Report.Log($"Converted Point3d {o}"); - break; - case DVector2d o: - @base = Vector2dToSpeckle(o); - Report.Log($"Converted DVector2d {o}"); - break; - case DVector3d o: - @base = Vector3dToSpeckle(o); - Report.Log($"Converted DVector3d {o}"); - break; - case DRange1d o: - @base = IntervalToSpeckle(o); - Report.Log($"Converted DRange1d {o} as Interval"); - break; - case DSegment1d o: - @base = IntervalToSpeckle(o); - Report.Log($"Converted DSegment1d {o} as Interval"); - break; - case DRange2d o: - @base = Interval2dToSpeckle(o); - Report.Log($"Converted DRange2d {o} as Interval"); - break; - case DRange3d o: - @base = BoxToSpeckle(o); - Report.Log($"Converted DRange3d {o} as Box"); - break; - case LineElement o: - @base = LineToSpeckle(o); - Report.Log($"Converted Line"); - break; - case DSegment3d o: - @base = LineToSpeckle(o); - Report.Log($"Converted DSegment3d as Line"); - break; - case DPlane3d o: - @base = PlaneToSpeckle(o); - Report.Log($"Converted Plane"); - break; - case ShapeElement o: - @base = ShapeToSpeckle(o); - Report.Log($"Converted Shape as Polyline"); - break; - case ArcElement o: - @base = ArcToSpeckle(o) as Base; //Arc, curve or circle - Report.Log($"Converted Arc as ICurve"); - break; - case EllipseElement o: - @base = EllipseToSpeckle(o) as Base; //Ellipse (with or without rotation) or circle - Report.Log($"Converted Ellipse as ICurve"); - break; - case LineStringElement o: - @base = PolylineToSpeckle(o); //Polyline - Report.Log($"Converted LineString as Polyline"); - break; - case ComplexStringElement o: - @base = PolycurveToSpeckle(o); //Polycurve - Report.Log($"Converted ComplexString as Polycurve"); - break; - case BSplineCurveElement o: - @base = BSplineCurveToSpeckle(o); //Nurbs curve - Report.Log($"Converted BSpline as Curve"); - break; - case ComplexShapeElement o: - @base = ComplexShapeToSpeckle(o); - Report.Log($"Converted ComplexShape as Polycurve"); - break; - case MeshHeaderElement o: - @base = MeshToSpeckle(o); - Report.Log($"Converted Mesh"); - break; - case BSplineSurfaceElement o: - @base = SurfaceToSpeckle(o); - Report.Log($"Converted Surface"); - break; - case ExtendedElementElement o: - @base = ExtendedElementToSpeckle(o); - Report.Log($"Converted ExtendedElement as Base"); - break; - case CellHeaderElement o: - @base = CellHeaderElementToSpeckle(o); - Report.Log($"Converted CellHeader as Base"); - break; - case Type2Element o: - @base = Type2ElementToSpeckle(o); - Report.Log($"Converted Type2 as Base"); - break; + case DPoint2d o: + @base = Point2dToSpeckle(o); + Report.Log($"Converted DPoint2d {o}"); + break; + case Point2d o: + @base = Point2dToSpeckle(o); + Report.Log($"Converted Point2d {o}"); + break; + case DPoint3d o: + @base = Point3dToSpeckle(o); + Report.Log($"Converted DPoint3d {o}"); + break; + case Point3d o: + @base = Point3dToSpeckle(o); + Report.Log($"Converted Point3d {o}"); + break; + case DVector2d o: + @base = Vector2dToSpeckle(o); + Report.Log($"Converted DVector2d {o}"); + break; + case DVector3d o: + @base = Vector3dToSpeckle(o); + Report.Log($"Converted DVector3d {o}"); + break; + case DRange1d o: + @base = IntervalToSpeckle(o); + Report.Log($"Converted DRange1d {o} as Interval"); + break; + case DSegment1d o: + @base = IntervalToSpeckle(o); + Report.Log($"Converted DSegment1d {o} as Interval"); + break; + case DRange2d o: + @base = Interval2dToSpeckle(o); + Report.Log($"Converted DRange2d {o} as Interval"); + break; + case DRange3d o: + @base = BoxToSpeckle(o); + Report.Log($"Converted DRange3d {o} as Box"); + break; + case LineElement o: + @base = LineToSpeckle(o); + Report.Log($"Converted Line"); + break; + case DSegment3d o: + @base = LineToSpeckle(o); + Report.Log($"Converted DSegment3d as Line"); + break; + case DPlane3d o: + @base = PlaneToSpeckle(o); + Report.Log($"Converted Plane"); + break; + case ShapeElement o: + @base = ShapeToSpeckle(o); + Report.Log($"Converted Shape as Polyline"); + break; + case ArcElement o: + @base = ArcToSpeckle(o) as Base; //Arc, curve or circle + Report.Log($"Converted Arc as ICurve"); + break; + case EllipseElement o: + @base = EllipseToSpeckle(o) as Base; //Ellipse (with or without rotation) or circle + Report.Log($"Converted Ellipse as ICurve"); + break; + case LineStringElement o: + @base = PolylineToSpeckle(o); //Polyline + Report.Log($"Converted LineString as Polyline"); + break; + case ComplexStringElement o: + @base = PolycurveToSpeckle(o); //Polycurve + Report.Log($"Converted ComplexString as Polycurve"); + break; + case BSplineCurveElement o: + @base = BSplineCurveToSpeckle(o); //Nurbs curve + Report.Log($"Converted BSpline as Curve"); + break; + case ComplexShapeElement o: + @base = ComplexShapeToSpeckle(o); + Report.Log($"Converted ComplexShape as Polycurve"); + break; + case MeshHeaderElement o: + @base = MeshToSpeckle(o); + Report.Log($"Converted Mesh"); + break; + case BSplineSurfaceElement o: + @base = SurfaceToSpeckle(o); + Report.Log($"Converted Surface"); + break; + case ExtendedElementElement o: + @base = ExtendedElementToSpeckle(o); + Report.Log($"Converted ExtendedElement as Base"); + break; + case CellHeaderElement o: + @base = CellHeaderElementToSpeckle(o); + Report.Log($"Converted CellHeader as Base"); + break; + case Type2Element o: + @base = Type2ElementToSpeckle(o); + Report.Log($"Converted Type2 as Base"); + break; #if (OPENBUILDINGS) - case ITFDrawingGrid o: - @base = GridSystemsToSpeckle(o); - Report.Log($"Converted GridSystems as Base"); - break; + case ITFDrawingGrid o: + @base = GridSystemsToSpeckle(o); + Report.Log($"Converted GridSystems as Base"); + break; #endif #if (OPENROADS || OPENRAIL) - case global::Bentley.CifNET.GeometryModel.SDK.Alignment o: - @base = AlignmentToSpeckle(o); - Report.Log($"Converted Alignment"); - break; - case Corridor o: - @base = CorridorToSpeckle(o); - Report.Log($"Converted Corridor as Base"); - break; - case Profile o: - @base = ProfileToSpeckle(o); - Report.Log($"Converted Profile as Base"); - break; - case FeaturizedModelEntity o: - @base = FeatureLineToSpeckle(o); - Report.Log($"Converted FeaturizedModel as Base"); - break; + case global::Bentley.CifNET.GeometryModel.SDK.Alignment o: + @base = AlignmentToSpeckle(o); + Report.Log($"Converted Alignment"); + break; + case Corridor o: + @base = CorridorToSpeckle(o); + Report.Log($"Converted Corridor as Base"); + break; + case Profile o: + @base = ProfileToSpeckle(o); + Report.Log($"Converted Profile as Base"); + break; + case FeaturizedModelEntity o: + @base = FeatureLineToSpeckle(o); + Report.Log($"Converted FeaturizedModel as Base"); + break; #endif - default: - Report.Log($"Skipped not supported type: {@object.GetType()}"); - throw new NotSupportedException(); - } - - return @base; + default: + Report.Log($"Skipped not supported type: {@object.GetType()}"); + throw new NotSupportedException(); } - public List ConvertToSpeckle(List objects) - { - return objects.Select(x => ConvertToSpeckle(x)).ToList(); - } + return @base; + } - public Base ConvertToSpeckleBE(object @object) - { - throw new NotImplementedException(); - } + public List ConvertToSpeckle(List objects) + { + return objects.Select(x => ConvertToSpeckle(x)).ToList(); + } - public List ConvertToSpeckleBE(List objects) - { - return objects.Select(x => ConvertToSpeckleBE(x)).ToList(); - } + public Base ConvertToSpeckleBE(object @object) + { + throw new NotImplementedException(); + } + + public List ConvertToSpeckleBE(List objects) + { + return objects.Select(x => ConvertToSpeckleBE(x)).ToList(); + } - public object ConvertToNative(Base @object) + public object ConvertToNative(Base @object) + { + switch (@object) { - switch (@object) - { - case Point o: - Report.Log($"Created Point {o.id}"); - return PointToNative(o); + case Point o: + Report.Log($"Created Point {o.id}"); + return PointToNative(o); - case Vector o: - Report.Log($"Created Vector {o.id}"); - return VectorToNative(o); + case Vector o: + Report.Log($"Created Vector {o.id}"); + return VectorToNative(o); - case Interval o: - Report.Log($"Created Interval {o.id}"); - return IntervalToNative(o); + case Interval o: + Report.Log($"Created Interval {o.id}"); + return IntervalToNative(o); - case Interval2d o: - Report.Log($"Created Interval2d {o.id}"); - return Interval2dToNative(o); + case Interval2d o: + Report.Log($"Created Interval2d {o.id}"); + return Interval2dToNative(o); - case Line o: - Report.Log($"Created Line {o.id}"); - return LineToNative(o); + case Line o: + Report.Log($"Created Line {o.id}"); + return LineToNative(o); - case Plane o: - Report.Log($"Created Plane {o.id}"); - return PlaneToNative(o); + case Plane o: + Report.Log($"Created Plane {o.id}"); + return PlaneToNative(o); - case Circle o: - Report.Log($"Created Circle {o.id}"); - return CircleToNative(o); + case Circle o: + Report.Log($"Created Circle {o.id}"); + return CircleToNative(o); - case Arc o: - Report.Log($"Created Arc {o.id}"); - return ArcToNative(o); + case Arc o: + Report.Log($"Created Arc {o.id}"); + return ArcToNative(o); - case Ellipse o: - Report.Log($"Created Ellipse {o.id}"); - return EllipseToNative(o); + case Ellipse o: + Report.Log($"Created Ellipse {o.id}"); + return EllipseToNative(o); - case Polyline o: - Report.Log($"Created Polyline {o.id}"); - return PolylineToNative(o); + case Polyline o: + Report.Log($"Created Polyline {o.id}"); + return PolylineToNative(o); - case Polycurve o: - Report.Log($"Created Polycurve {o.id} asn ComplexString"); - return PolycurveToNative(o); // polycurve converted to complex chain + case Polycurve o: + Report.Log($"Created Polycurve {o.id} asn ComplexString"); + return PolycurveToNative(o); // polycurve converted to complex chain - case Curve o: - Report.Log($"Created Curve {o.id} as DisplayableElement"); - return CurveToNative(o); + case Curve o: + Report.Log($"Created Curve {o.id} as DisplayableElement"); + return CurveToNative(o); - case Box o: - Report.Log($"Created Box {o.id} as DRange3d"); - return BoxToNative(o); + case Box o: + Report.Log($"Created Box {o.id} as DRange3d"); + return BoxToNative(o); - case Mesh o: - Report.Log($"Created Mesh {o.id}"); - return MeshToNative(o); + case Mesh o: + Report.Log($"Created Mesh {o.id}"); + return MeshToNative(o); #if (OPENROADS || OPENRAIL) - case Alignment o: - Report.Log($"Created Alignment {o.id}"); - return AlignmentToNative(o); + case Alignment o: + Report.Log($"Created Alignment {o.id}"); + return AlignmentToNative(o); #endif - default: - Report.Log($"Skipped not supported type: {@object.GetType()} {@object.id}"); - throw new NotSupportedException(); - } + default: + Report.Log($"Skipped not supported type: {@object.GetType()} {@object.id}"); + throw new NotSupportedException(); } + } - public object ConvertToNativeDisplayable(Base @object) - { - throw new NotImplementedException(); - } + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } - public List ConvertToNative(List objects) - { - return objects.Select(x => ConvertToNative(x)).ToList(); - } + public List ConvertToNative(List objects) + { + return objects.Select(x => ConvertToNative(x)).ToList(); + } - public bool CanConvertToSpeckle(object @object) + public bool CanConvertToSpeckle(object @object) + { + switch (@object) { - switch (@object) - { - case DPoint2d _: - case Point2d _: - case DPoint3d _: - case Point3d _: - case DVector2d _: - case DVector3d _: - case LineElement _: - case global::Bentley.GeometryNET.LineString _: - case LineStringElement _: - case ArcElement _: - case ComplexStringElement _: - case EllipseElement _: - case BSplineCurveElement _: - case ShapeElement _: - case ComplexShapeElement _: - case MeshHeaderElement _: - //case BSplineSurfaceElement _: - case ExtendedElementElement _: - case CellHeaderElement _: - case Type2Element _: //Complex header element - return true; + case DPoint2d _: + case Point2d _: + case DPoint3d _: + case Point3d _: + case DVector2d _: + case DVector3d _: + case LineElement _: + case global::Bentley.GeometryNET.LineString _: + case LineStringElement _: + case ArcElement _: + case ComplexStringElement _: + case EllipseElement _: + case BSplineCurveElement _: + case ShapeElement _: + case ComplexShapeElement _: + case MeshHeaderElement _: + //case BSplineSurfaceElement _: + case ExtendedElementElement _: + case CellHeaderElement _: + case Type2Element _: //Complex header element + return true; #if (OPENROADS || OPENRAIL) - case global::Bentley.CifNET.GeometryModel.SDK.Alignment _: - //case Corridor _: - //case Profile _: - //case FeaturizedModelEntity _: - return true; + case global::Bentley.CifNET.GeometryModel.SDK.Alignment _: + //case Corridor _: + //case Profile _: + //case FeaturizedModelEntity _: + return true; #endif - default: - return false; - } + default: + return false; } + } - public bool CanConvertToNative(Base @object) + public bool CanConvertToNative(Base @object) + { + switch (@object) { - switch (@object) - { - case Point _: - case Vector _: - case Interval _: - case Interval2d _: - case Line _: - case Plane _: - case Circle _: - case Arc _: - case Ellipse _: - case Polyline _: - case Polycurve _: - case Curve _: - case Box _: - case Mesh _: - //case Surface _: - //case Alignment _: ; - return true; - - default: - return false; - } + case Point _: + case Vector _: + case Interval _: + case Interval2d _: + case Line _: + case Plane _: + case Circle _: + case Arc _: + case Ellipse _: + case Polyline _: + case Polycurve _: + case Curve _: + case Box _: + case Mesh _: + //case Surface _: + //case Alignment _: ; + return true; + + default: + return false; } + } - public bool CanConvertToNativeDisplayable(Base @object) - { - return false; - } + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; } } diff --git a/Objects/Converters/ConverterBentley/ConverterMicroStation/ConverterMicroStation.csproj b/Objects/Converters/ConverterBentley/ConverterMicroStation/ConverterMicroStation.csproj index 02689c1d16..233f4eacf8 100644 --- a/Objects/Converters/ConverterBentley/ConverterMicroStation/ConverterMicroStation.csproj +++ b/Objects/Converters/ConverterBentley/ConverterMicroStation/ConverterMicroStation.csproj @@ -13,6 +13,12 @@ true + + 0 + false + false + + TRACE;MICROSTATION @@ -32,4 +38,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterBentley/ConverterOpenBuildings/ConverterOpenBuildings.csproj b/Objects/Converters/ConverterBentley/ConverterOpenBuildings/ConverterOpenBuildings.csproj index 2a6ed2dc1a..42d4549081 100644 --- a/Objects/Converters/ConverterBentley/ConverterOpenBuildings/ConverterOpenBuildings.csproj +++ b/Objects/Converters/ConverterBentley/ConverterOpenBuildings/ConverterOpenBuildings.csproj @@ -11,6 +11,12 @@ true + + 0 + false + false + + TRACE;OPENBUILDINGS @@ -30,4 +36,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterBentley/ConverterOpenRail/ConverterOpenRail.csproj b/Objects/Converters/ConverterBentley/ConverterOpenRail/ConverterOpenRail.csproj index 8fe9e5c115..47c2a15541 100644 --- a/Objects/Converters/ConverterBentley/ConverterOpenRail/ConverterOpenRail.csproj +++ b/Objects/Converters/ConverterBentley/ConverterOpenRail/ConverterOpenRail.csproj @@ -11,6 +11,12 @@ true + + 0 + false + false + + TRACE;OPENRAIL @@ -30,4 +36,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterBentley/ConverterOpenRoads/ConverterOpenRoads.csproj b/Objects/Converters/ConverterBentley/ConverterOpenRoads/ConverterOpenRoads.csproj index 7107650672..c5ca38f4fd 100644 --- a/Objects/Converters/ConverterBentley/ConverterOpenRoads/ConverterOpenRoads.csproj +++ b/Objects/Converters/ConverterBentley/ConverterOpenRoads/ConverterOpenRoads.csproj @@ -9,9 +9,14 @@ Arup Converter for OpenRoads Designer Connect true - + + 0 + false + false + + TRACE;OPENROADS @@ -31,4 +36,4 @@ - \ No newline at end of file + diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/AnalysisResultUtils.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/AnalysisResultUtils.cs index 7f72a69b73..56ee1d39f4 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/AnalysisResultUtils.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/AnalysisResultUtils.cs @@ -2,77 +2,79 @@ using ConverterCSIShared.Models; using CSiAPIv1; -namespace ConverterCSIShared +namespace ConverterCSIShared; + +internal static class AnalysisResultUtils { - internal static class AnalysisResultUtils + public delegate int ApiResultMethod( + string name, + eItemTypeElm eItemType, + ref int numItems, + ref string[] objs, + ref string[] elms, + ref string[] loadCombos, + ref string[] stepTypes, + ref double[] stepNum, + ref double[] x, + ref double[] y, + ref double[] z, + ref double[] xx, + ref double[] yy, + ref double[] zz + ); + + public static bool TryGetAPIResult( + ApiResultMethod apiResultMethod, + string nodeName, + out int numberResults, + out string[] obj, + out string[] elm, + out string[] loadCases, + out string[] stepType, + out double[] stepNum, + out double[] F1, + out double[] F2, + out double[] F3, + out double[] M1, + out double[] M2, + out double[] M3, + bool shouldGetResults = true + ) { - public delegate int ApiResultMethod( - string name, - eItemTypeElm eItemType, - ref int numItems, - ref string[] objs, - ref string[] elms, - ref string[] loadCombos, - ref string[] stepTypes, - ref double[] stepNum, - ref double[] x, - ref double[] y, - ref double[] z, - ref double[] xx, - ref double[] yy, - ref double[] zz); + numberResults = 0; + obj = null; + elm = null; + loadCases = null; + stepType = null; + stepNum = null; + F1 = null; + F2 = null; + F3 = null; + M1 = null; + M2 = null; + M3 = null; - public static bool TryGetAPIResult( - ApiResultMethod apiResultMethod, - string nodeName, - out int numberResults, - out string[] obj, - out string[] elm, - out string[] loadCases, - out string[] stepType, - out double[] stepNum, - out double[] F1, - out double[] F2, - out double[] F3, - out double[] M1, - out double[] M2, - out double[] M3, - bool shouldGetResults = true) + if (!shouldGetResults) { - numberResults = 0; - obj = null; - elm = null; - loadCases = null; - stepType = null; - stepNum = null; - F1 = null; - F2 = null; - F3 = null; - M1 = null; - M2 = null; - M3 = null; - - if (!shouldGetResults) - { - return false; - } - - int success = apiResultMethod( - nodeName, - eItemTypeElm.Element, - ref numberResults, - ref obj, - ref elm, - ref loadCases, - ref stepType, - ref stepNum, - ref F1, - ref F2, - ref F3, - ref M1, - ref M2, - ref M3); - return ApiResultValidator.IsSuccessful(success); + return false; } + + int success = apiResultMethod( + nodeName, + eItemTypeElm.Element, + ref numberResults, + ref obj, + ref elm, + ref loadCases, + ref stepType, + ref stepNum, + ref F1, + ref F2, + ref F3, + ref M1, + ref M2, + ref M3 + ); + return ApiResultValidator.IsSuccessful(success); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Constants.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Constants.cs index cb4324b246..33a9c2aa1e 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Constants.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Constants.cs @@ -3,29 +3,28 @@ using System.Text; using Microsoft.AspNetCore.Http; -namespace ConverterCSIShared +namespace ConverterCSIShared; + +internal static class Constants { - internal static class Constants - { - // these three slugs were previously used by the connector and now only serve to maintain backwards - // compatibility with the slugs that may be saved to a user's existing stream card - public const string LEGACY_SEND_NODE_RESULTS = "sendNodeResults"; - public const string LEGACY_SEND_1D_RESULTS = "send1DResults"; - public const string LEGACY_SEND_2D_RESULTS = "send2DResults"; + // these three slugs were previously used by the connector and now only serve to maintain backwards + // compatibility with the slugs that may be saved to a user's existing stream card + public const string LEGACY_SEND_NODE_RESULTS = "sendNodeResults"; + public const string LEGACY_SEND_1D_RESULTS = "send1DResults"; + public const string LEGACY_SEND_2D_RESULTS = "send2DResults"; - public const string RESULTS_NODE_SLUG = "node-results"; - public const string RESULTS_1D_SLUG = "1d-results"; - public const string RESULTS_2D_SLUG = "2d-results"; - public const string RESULTS_LOAD_CASES_SLUG = "load-cases"; + public const string RESULTS_NODE_SLUG = "node-results"; + public const string RESULTS_1D_SLUG = "1d-results"; + public const string RESULTS_2D_SLUG = "2d-results"; + public const string RESULTS_LOAD_CASES_SLUG = "load-cases"; - public const string BEAM_FORCES = "Beam Forces"; - public const string BRACE_FORCES = "Brace Forces"; - public const string COLUMN_FORCES = "Column Forces"; - public const string OTHER_FORCES = "Other Forces"; - public const string FORCES = "Forces"; - public const string STRESSES = "Stresses"; - public const string DISPLACEMENTS = "Displacements"; - public const string VELOCITIES = "Velocities"; - public const string ACCELERATIONS = "Accelerations"; - } + public const string BEAM_FORCES = "Beam Forces"; + public const string BRACE_FORCES = "Brace Forces"; + public const string COLUMN_FORCES = "Column Forces"; + public const string OTHER_FORCES = "Other Forces"; + public const string FORCES = "Forces"; + public const string STRESSES = "Stresses"; + public const string DISPLACEMENTS = "Displacements"; + public const string VELOCITIES = "Velocities"; + public const string ACCELERATIONS = "Accelerations"; } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.DatabaseTableUtils.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.DatabaseTableUtils.cs index 13e12071b1..08ed08cb03 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.DatabaseTableUtils.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.DatabaseTableUtils.cs @@ -1,14 +1,14 @@ using ConverterCSIShared.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + private ETABSGridLineDefinitionTable gridLineDefinitionTable; + private ETABSGridLineDefinitionTable GridLineDefinitionTable => gridLineDefinitionTable ??= new(Model, new(Model)); + + public void CommitAllDatabaseTableChanges() { - private ETABSGridLineDefinitionTable gridLineDefinitionTable; - private ETABSGridLineDefinitionTable GridLineDefinitionTable => gridLineDefinitionTable ??= new(Model, new(Model)); - public void CommitAllDatabaseTableChanges() - { - GridLineDefinitionTable.CommitPendingChanges(); - } + GridLineDefinitionTable.CommitPendingChanges(); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.cs index 5e58d8126c..7ba85f50e6 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSI.cs @@ -18,428 +18,437 @@ using Speckle.Core.Kits.ConverterInterfaces; using ConverterCSIShared.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI : ISpeckleConverter, IFinalizable { - public partial class ConverterCSI : ISpeckleConverter, IFinalizable - { #if ETABS - public static string CSIAppName = HostApplications.ETABS.Name; - public static string CSISlug = HostApplications.ETABS.Slug; + public static string CSIAppName = HostApplications.ETABS.Name; + public static string CSISlug = HostApplications.ETABS.Slug; #elif SAP2000 - public static string CSIAppName = HostApplications.SAP2000.Name; - public static string CSISlug = HostApplications.SAP2000.Slug; + public static string CSIAppName = HostApplications.SAP2000.Name; + public static string CSISlug = HostApplications.SAP2000.Slug; #elif CSIBRIDGE - public static string CSIAppName = HostApplications.CSiBridge.Name; - public static string CSISlug = HostApplications.CSiBridge.Slug; + public static string CSIAppName = HostApplications.CSiBridge.Name; + public static string CSISlug = HostApplications.CSiBridge.Slug; #elif SAFE - public static string CSIAppName = HostApplications.SAFE.Name; - public static string CSISlug = HostApplications.SAFE.Slug; + public static string CSIAppName = HostApplications.SAFE.Name; + public static string CSISlug = HostApplications.SAFE.Slug; #endif - public string Description => "Default Speckle Kit for CSI"; + public string Description => "Default Speckle Kit for CSI"; - public string Name => nameof(ConverterCSI); + public string Name => nameof(ConverterCSI); - public string Author => "Speckle"; + public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; + public string WebsiteOrEmail => "https://speckle.systems"; - public cSapModel Model { get; private set; } - public string ProgramVersion { get; private set; } + public cSapModel Model { get; private set; } + public string ProgramVersion { get; private set; } - public Model SpeckleModel { get; set; } + public Model SpeckleModel { get; set; } - public ReceiveMode ReceiveMode { get; set; } + public ReceiveMode ReceiveMode { get; set; } - /// - /// To know which objects are already in the model. These are *mostly* elements that are in the model before the receive operation starts, but certain names will be added for objects that may be referenced by other elements such as load patterns and load cases. - /// The keys are typically GUIDS and the values are exclusively names. It is easier to retrieve names, and names are typically used by the api, however GUIDS are more stable and can't be changed in the user interface. Some items (again load patterns and load combinations) don't have GUIDs so those just store the name value twice. - /// - public Dictionary ExistingObjectGuids { get; set; } + /// + /// To know which objects are already in the model. These are *mostly* elements that are in the model before the receive operation starts, but certain names will be added for objects that may be referenced by other elements such as load patterns and load cases. + /// The keys are typically GUIDS and the values are exclusively names. It is easier to retrieve names, and names are typically used by the api, however GUIDS are more stable and can't be changed in the user interface. Some items (again load patterns and load combinations) don't have GUIDs so those just store the name value twice. + /// + public Dictionary ExistingObjectGuids { get; set; } - /// - /// To know which other objects are being converted, in order to sort relationships between them. - /// For example, elements that have children use this to determine whether they should send their children out or not. - /// - public List ContextObjects { get; set; } = new List(); + /// + /// To know which other objects are being converted, in order to sort relationships between them. + /// For example, elements that have children use this to determine whether they should send their children out or not. + /// + public List ContextObjects { get; set; } = new List(); - /// - /// To keep track of previously received objects from a given stream in here. If possible, conversions routines - /// will edit an existing object, otherwise they will delete the old one and create the new one. - /// - public List PreviousContextObjects { get; set; } = new List(); - public Dictionary Settings { get; private set; } = new Dictionary(); + /// + /// To keep track of previously received objects from a given stream in here. If possible, conversions routines + /// will edit an existing object, otherwise they will delete the old one and create the new one. + /// + public List PreviousContextObjects { get; set; } = new List(); + public Dictionary Settings { get; private set; } = new Dictionary(); - public void SetContextObjects(List objects) => ContextObjects = objects; + public void SetContextObjects(List objects) => ContextObjects = objects; - public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; + public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; - private ResultsConverter? resultsConverter; - public void SetContextDocument(object doc) - { - Model = (cSapModel)doc; - double version = 0; - string versionString = null; - Model.GetVersion(ref versionString, ref version); - ProgramVersion = versionString; + private ResultsConverter? resultsConverter; - if (!Settings.ContainsKey("operation")) - throw new Exception("operation setting was not set before calling converter.SetContextDocument"); + public void SetContextDocument(object doc) + { + Model = (cSapModel)doc; + double version = 0; + string versionString = null; + Model.GetVersion(ref versionString, ref version); + ProgramVersion = versionString; - if (Settings["operation"] == "receive") - { - ExistingObjectGuids = GetAllGuids(Model); - // TODO: make sure we are setting the load patterns before we import load combinations - } - else if (Settings["operation"] == "send") - { - SpeckleModel = ModelToSpeckle(); - resultsConverter = new ResultsConverter(Model, Settings, GetLoadCases(), GetLoadCombos()); - } - else - throw new Exception("operation setting was not set to \"send\" or \"receive\""); + if (!Settings.ContainsKey("operation")) + { + throw new Exception("operation setting was not set before calling converter.SetContextDocument"); } - public void SetConverterSettings(object settings) + if (Settings["operation"] == "receive") { - Settings = settings as Dictionary; + ExistingObjectGuids = GetAllGuids(Model); + // TODO: make sure we are setting the load patterns before we import load combinations } - - public HashSet ConversionErrors { get; private set; } = new HashSet(); - public ProgressReport Report { get; private set; } = new ProgressReport(); - - public bool CanConvertToNative(Base @object) + else if (Settings["operation"] == "send") { - switch (@object) - { - case CSIDiaphragm _: - case CSIStories _: - case Element1D _: - case Element2D _: - case Load _: - //case Geometry.Line line: - case Node _: - case GridLine _: - //case Model o: - //case Property property: - - // for the moment we need to have this in here so the flatten traversal skips over this object - // otherwise it would add result.element to the list twice and the stored objects dictionary would throw - case Result _: - case BuiltElements.Beam _: - case BuiltElements.Brace _: - case BuiltElements.Column _: - case StructuralMaterial _: - return true; - } - ; - return false; + SpeckleModel = ModelToSpeckle(); + resultsConverter = new ResultsConverter(Model, Settings, GetLoadCases(), GetLoadCombos()); + } + else + { + throw new Exception("operation setting was not set to \"send\" or \"receive\""); } + } + + public void SetConverterSettings(object settings) + { + Settings = settings as Dictionary; + } + + public HashSet ConversionErrors { get; private set; } = new HashSet(); + public ProgressReport Report { get; private set; } = new ProgressReport(); - public bool CanConvertToNativeDisplayable(Base @object) + public bool CanConvertToNative(Base @object) + { + switch (@object) { - return false; + case CSIDiaphragm _: + case CSIStories _: + case Element1D _: + case Element2D _: + case Load _: + //case Geometry.Line line: + case Node _: + case GridLine _: + //case Model o: + //case Property property: + + // for the moment we need to have this in here so the flatten traversal skips over this object + // otherwise it would add result.element to the list twice and the stored objects dictionary would throw + case Result _: + case BuiltElements.Beam _: + case BuiltElements.Brace _: + case BuiltElements.Column _: + case StructuralMaterial _: + return true; } + ; + return false; + } + + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; + } - public bool CanConvertToSpeckle(object @object) + public bool CanConvertToSpeckle(object @object) + { + if (@object == null) { - if (@object == null) - return false; - foreach (var type in Enum.GetNames(typeof(ConverterCSI.CSIAPIUsableTypes))) - { - if (type == @object.ToString()) - { - return true; - } - } return false; } - public object ConvertToNative(Base @object) + foreach (var type in Enum.GetNames(typeof(ConverterCSI.CSIAPIUsableTypes))) { - ApplicationObject appObj = new(@object.id, @object.speckle_type) { applicationId = @object.applicationId }; - - List convertedNames = new(); - string? convertedName = null; - - switch (@object) + if (type == @object.ToString()) { - case CSIAreaSpring o: - convertedName = AreaSpringPropertyToNative(o); - break; - case CSIDiaphragm o: - convertedName = DiaphragmToNative(o); - break; - case CSILinearSpring o: - convertedName = LinearSpringPropertyToNative(o); - break; - case CSILinkProperty o: - convertedName = LinkPropertyToNative(o); - break; - case CSIProperty2D o: - convertedName = Property2DToNative(o); - break; - case CSISpringProperty o: - convertedName = SpringPropertyToNative(o); - break; - case CSIStories o: - convertedNames = StoriesToNative(o); - break; - // case CSIWindLoadingFace o: - // convertedName = LoadFaceToNative(o, appObj.Log); - // break; - // case CSITendonProperty o: - case OSG.Element1D o: - FrameToNative(o, appObj); - break; - case OSG.Element2D o: - AreaToNative(o, appObj); - break; - case LoadBeam o: - convertedNames = LoadFrameToNative(o, appObj.Log); - break; - case LoadFace o: - convertedName = LoadFaceToNative(o, appObj.Log); - break; - case Geometry.Line o: - convertedName = LineToNative(o); // do we really want to assume any line is a frame object? - break; - case OSG.Node o: - convertedName = PointToNative(o, appObj.Log); - break; - case Property1D o: - convertedName = Property1DToNative(o); - break; - case StructuralMaterial o: - convertedName = MaterialToNative(o); - break; - case BuiltElements.Beam o: - CurveBasedElementToNative(o, o.baseLine, appObj); - break; - case BuiltElements.Brace o: - CurveBasedElementToNative(o, o.baseLine, appObj); - break; - case BuiltElements.Column o: - CurveBasedElementToNative(o, o.baseLine, appObj); - break; - case GridLine o: - GridLineToNative(o); - break; - default: - throw new ConversionNotSupportedException($"{@object.GetType()} is an unsupported type"); + return true; } + } + return false; + } - if (convertedName is not null) - { - convertedNames.Add(convertedName); - } + public object ConvertToNative(Base @object) + { + ApplicationObject appObj = new(@object.id, @object.speckle_type) { applicationId = @object.applicationId }; - appObj.Update(createdIds: convertedNames); + List convertedNames = new(); + string? convertedName = null; - return appObj; - } - - public object ConvertToNativeDisplayable(Base @object) + switch (@object) { - throw new NotImplementedException(); + case CSIAreaSpring o: + convertedName = AreaSpringPropertyToNative(o); + break; + case CSIDiaphragm o: + convertedName = DiaphragmToNative(o); + break; + case CSILinearSpring o: + convertedName = LinearSpringPropertyToNative(o); + break; + case CSILinkProperty o: + convertedName = LinkPropertyToNative(o); + break; + case CSIProperty2D o: + convertedName = Property2DToNative(o); + break; + case CSISpringProperty o: + convertedName = SpringPropertyToNative(o); + break; + case CSIStories o: + convertedNames = StoriesToNative(o); + break; + // case CSIWindLoadingFace o: + // convertedName = LoadFaceToNative(o, appObj.Log); + // break; + // case CSITendonProperty o: + case OSG.Element1D o: + FrameToNative(o, appObj); + break; + case OSG.Element2D o: + AreaToNative(o, appObj); + break; + case LoadBeam o: + convertedNames = LoadFrameToNative(o, appObj.Log); + break; + case LoadFace o: + convertedName = LoadFaceToNative(o, appObj.Log); + break; + case Geometry.Line o: + convertedName = LineToNative(o); // do we really want to assume any line is a frame object? + break; + case OSG.Node o: + convertedName = PointToNative(o, appObj.Log); + break; + case Property1D o: + convertedName = Property1DToNative(o); + break; + case StructuralMaterial o: + convertedName = MaterialToNative(o); + break; + case BuiltElements.Beam o: + CurveBasedElementToNative(o, o.baseLine, appObj); + break; + case BuiltElements.Brace o: + CurveBasedElementToNative(o, o.baseLine, appObj); + break; + case BuiltElements.Column o: + CurveBasedElementToNative(o, o.baseLine, appObj); + break; + case GridLine o: + GridLineToNative(o); + break; + default: + throw new ConversionNotSupportedException($"{@object.GetType()} is an unsupported type"); } - public List ConvertToNative(List objects) + if (convertedName is not null) { - return objects.Select(x => ConvertToNative(x)).ToList(); + convertedNames.Add(convertedName); } - public Base ConvertToSpeckle(object @object) - { - (string type, string name) = ((string, string))@object; - Base returnObject = null; - switch (type) - { - case "Point": - returnObject = PointToSpeckle(name); - Report.Log($"Created Node"); - break; - case "Frame": - returnObject = FrameToSpeckle(name); - Report.Log($"Created Frame"); - break; - case "Model": - returnObject = SpeckleModel; - break; - case "AnalysisResults": - returnObject = ResultsToSpeckle(); - break; - case "Stories": - returnObject = StoriesToSpeckle(); - break; - case "Area": - returnObject = AreaToSpeckle(name); - Report.Log($"Created Area"); - break; - case "Wall": - returnObject = WallToSpeckle(name); - Report.Log($"Created Wall"); - break; - case "Floor": - returnObject = FloorToSpeckle(name); - Report.Log($"Created Floor"); - break; - case "Column": - returnObject = ColumnToSpeckle(name); - Report.Log($"Created Column"); - break; - case "Beam": - returnObject = BeamToSpeckle(name); - Report.Log($"Created Beam"); - break; - case "Brace": - returnObject = BraceToSpeckle(name); - Report.Log($"Created Brace"); - break; - case "Link": - returnObject = LinkToSpeckle(name); - Report.Log($"Created Link"); - break; - case "ElementsCount": - returnObject = ModelElementsCountToSpeckle(); - break; - case "Spandrel": - returnObject = SpandrelToSpeckle(name); - Report.Log($"Created Spandrel"); - break; - case "Pier": - returnObject = PierToSpeckle(name); - Report.Log($"Created Pier"); - break; - case "Grids": - returnObject = gridLinesToSpeckle(name); - Report.Log($"Created Grids"); - break; - case "Tendon": - returnObject = CSITendonToSpeckle(name); - Report.Log($"Created Tendons"); - break; - //case "Diaphragm": - // returnObject = diaphragmToSpeckle(name); - // Report.Log($"Created Diaphragm"); - case "Links": - returnObject = LinkToSpeckle(name); - break; - //case "LoadCase": - // returnObject = LoadCaseToSpeckle(name); - // break; - case "BeamLoading": - returnObject = LoadFrameToSpeckle(name, GetBeamNames(Model).Count()); - Report.Log($"Created Loading Beam"); - break; - case "ColumnLoading": - returnObject = LoadFrameToSpeckle(name, GetColumnNames(Model).Count()); - Report.Log($"Created Loading Column"); - break; - case "BraceLoading": - returnObject = LoadFrameToSpeckle(name, GetBraceNames(Model).Count()); - Report.Log($"Created Loading Brace"); - break; - case "FrameLoading": - returnObject = LoadFrameToSpeckle(name, GetAllFrameNames(Model).Count()); - Report.Log($"Created Loading Frame"); - break; - case "FloorLoading": - returnObject = LoadFaceToSpeckle(name, GetAllFloorNames(Model).Count()); - Report.Log($"Created Loading Floor"); - break; - case "WallLoading": - returnObject = LoadFaceToSpeckle(name, GetAllWallNames(Model).Count()); - Report.Log($"Created Loading Wall"); - break; - case "AreaLoading": - returnObject = LoadFaceToSpeckle(name, GetAllAreaNames(Model).Count()); - Report.Log($"Created Loading Area"); - break; - case "NodeLoading": - returnObject = LoadNodeToSpeckle(name, GetAllPointNames(Model).Count()); - Report.Log($"Created Loading Node"); - break; - case "LoadPattern": - returnObject = LoadPatternToSpeckle(name); - Report.Log($"Created Loading Pattern"); - break; - //case "ColumnResults": - // returnObject = FrameResultSet1dToSpeckle(name); - // break; - //case "BeamResults": - // returnObject = FrameResultSet1dToSpeckle(name); - // break; - //case "BraceResults": - // returnObject = FrameResultSet1dToSpeckle(name); - // break; - //case "PierResults": - // returnObject = PierResultSet1dToSpeckle(name); - // break; - //case "SpandrelResults": - // returnObject = SpandrelResultSet1dToSpeckle(name); - // break; - //case "GridSys": - // returnObject = GridSysToSpeckle(name); - // break; - //case "Combo": - // returnObject = ComboToSpeckle(name); - // break; - //case "DesignSteel": - // returnObject = DesignSteelToSpeckle(name); - // break; - //case "DeisgnConcrete": - // returnObject = DesignConcreteToSpeckle(name); - // break; - //case "Story": - // returnObject = StoryToSpeckle(name); - // break; - //case "Diaphragm": - // returnObject = DiaphragmToSpeckle(name); - // break; - //case "PierLabel": - // returnObject = PierLabelToSpeckle(name); - // break; - //case "PropAreaSpring": - // returnObject = PropAreaSpringToSpeckle(name); - // break; - //case "PropLineSpring": - // returnObject = PropLineSpringToSpeckle(name); - // break; - //case "PropPointSpring": - // returnObject = PropPointSpringToSpeckle(name); - // break; - //case "SpandrelLabel": - // returnObject = SpandrelLabelToSpeckle(name); - // break; - //case "PropTendon": - // returnObject = PropTendonToSpeckle(name); - // break; - //case "PropLink": - // returnObject = PropLinkToSpeckle(name); - // break; - //default: - // ConversionErrors.Add(new SpeckleException($"Skipping not supported type: {type}")); - // returnObject = null; - // break; - } + appObj.Update(createdIds: convertedNames); - // send the object out with the same appId that it came in with for updating purposes - if (returnObject != null) - returnObject.applicationId = GetOriginalApplicationId(returnObject.applicationId); + return appObj; + } - return returnObject; - } + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } + + public List ConvertToNative(List objects) + { + return objects.Select(x => ConvertToNative(x)).ToList(); + } - public List ConvertToSpeckle(List objects) + public Base ConvertToSpeckle(object @object) + { + (string type, string name) = ((string, string))@object; + Base returnObject = null; + switch (type) { - return objects.Select(x => ConvertToSpeckle(x)).ToList(); + case "Point": + returnObject = PointToSpeckle(name); + Report.Log($"Created Node"); + break; + case "Frame": + returnObject = FrameToSpeckle(name); + Report.Log($"Created Frame"); + break; + case "Model": + returnObject = SpeckleModel; + break; + case "AnalysisResults": + returnObject = ResultsToSpeckle(); + break; + case "Stories": + returnObject = StoriesToSpeckle(); + break; + case "Area": + returnObject = AreaToSpeckle(name); + Report.Log($"Created Area"); + break; + case "Wall": + returnObject = WallToSpeckle(name); + Report.Log($"Created Wall"); + break; + case "Floor": + returnObject = FloorToSpeckle(name); + Report.Log($"Created Floor"); + break; + case "Column": + returnObject = ColumnToSpeckle(name); + Report.Log($"Created Column"); + break; + case "Beam": + returnObject = BeamToSpeckle(name); + Report.Log($"Created Beam"); + break; + case "Brace": + returnObject = BraceToSpeckle(name); + Report.Log($"Created Brace"); + break; + case "Link": + returnObject = LinkToSpeckle(name); + Report.Log($"Created Link"); + break; + case "ElementsCount": + returnObject = ModelElementsCountToSpeckle(); + break; + case "Spandrel": + returnObject = SpandrelToSpeckle(name); + Report.Log($"Created Spandrel"); + break; + case "Pier": + returnObject = PierToSpeckle(name); + Report.Log($"Created Pier"); + break; + case "Grids": + returnObject = gridLinesToSpeckle(name); + Report.Log($"Created Grids"); + break; + case "Tendon": + returnObject = CSITendonToSpeckle(name); + Report.Log($"Created Tendons"); + break; + //case "Diaphragm": + // returnObject = diaphragmToSpeckle(name); + // Report.Log($"Created Diaphragm"); + case "Links": + returnObject = LinkToSpeckle(name); + break; + //case "LoadCase": + // returnObject = LoadCaseToSpeckle(name); + // break; + case "BeamLoading": + returnObject = LoadFrameToSpeckle(name, GetBeamNames(Model).Count()); + Report.Log($"Created Loading Beam"); + break; + case "ColumnLoading": + returnObject = LoadFrameToSpeckle(name, GetColumnNames(Model).Count()); + Report.Log($"Created Loading Column"); + break; + case "BraceLoading": + returnObject = LoadFrameToSpeckle(name, GetBraceNames(Model).Count()); + Report.Log($"Created Loading Brace"); + break; + case "FrameLoading": + returnObject = LoadFrameToSpeckle(name, GetAllFrameNames(Model).Count()); + Report.Log($"Created Loading Frame"); + break; + case "FloorLoading": + returnObject = LoadFaceToSpeckle(name, GetAllFloorNames(Model).Count()); + Report.Log($"Created Loading Floor"); + break; + case "WallLoading": + returnObject = LoadFaceToSpeckle(name, GetAllWallNames(Model).Count()); + Report.Log($"Created Loading Wall"); + break; + case "AreaLoading": + returnObject = LoadFaceToSpeckle(name, GetAllAreaNames(Model).Count()); + Report.Log($"Created Loading Area"); + break; + case "NodeLoading": + returnObject = LoadNodeToSpeckle(name, GetAllPointNames(Model).Count()); + Report.Log($"Created Loading Node"); + break; + case "LoadPattern": + returnObject = LoadPatternToSpeckle(name); + Report.Log($"Created Loading Pattern"); + break; + //case "ColumnResults": + // returnObject = FrameResultSet1dToSpeckle(name); + // break; + //case "BeamResults": + // returnObject = FrameResultSet1dToSpeckle(name); + // break; + //case "BraceResults": + // returnObject = FrameResultSet1dToSpeckle(name); + // break; + //case "PierResults": + // returnObject = PierResultSet1dToSpeckle(name); + // break; + //case "SpandrelResults": + // returnObject = SpandrelResultSet1dToSpeckle(name); + // break; + //case "GridSys": + // returnObject = GridSysToSpeckle(name); + // break; + //case "Combo": + // returnObject = ComboToSpeckle(name); + // break; + //case "DesignSteel": + // returnObject = DesignSteelToSpeckle(name); + // break; + //case "DeisgnConcrete": + // returnObject = DesignConcreteToSpeckle(name); + // break; + //case "Story": + // returnObject = StoryToSpeckle(name); + // break; + //case "Diaphragm": + // returnObject = DiaphragmToSpeckle(name); + // break; + //case "PierLabel": + // returnObject = PierLabelToSpeckle(name); + // break; + //case "PropAreaSpring": + // returnObject = PropAreaSpringToSpeckle(name); + // break; + //case "PropLineSpring": + // returnObject = PropLineSpringToSpeckle(name); + // break; + //case "PropPointSpring": + // returnObject = PropPointSpringToSpeckle(name); + // break; + //case "SpandrelLabel": + // returnObject = SpandrelLabelToSpeckle(name); + // break; + //case "PropTendon": + // returnObject = PropTendonToSpeckle(name); + // break; + //case "PropLink": + // returnObject = PropLinkToSpeckle(name); + // break; + //default: + // ConversionErrors.Add(new SpeckleException($"Skipping not supported type: {type}")); + // returnObject = null; + // break; } - public IEnumerable GetServicedApplications() => new string[] { CSIAppName }; - - public void FinalizeConversion() + // send the object out with the same appId that it came in with for updating purposes + if (returnObject != null) { - CommitAllDatabaseTableChanges(); + returnObject.applicationId = GetOriginalApplicationId(returnObject.applicationId); } + + return returnObject; + } + + public List ConvertToSpeckle(List objects) + { + return objects.Select(x => ConvertToSpeckle(x)).ToList(); + } + + public IEnumerable GetServicedApplications() => new string[] { CSIAppName }; + + public void FinalizeConversion() + { + CommitAllDatabaseTableChanges(); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSIUtils.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSIUtils.cs index 8f60893e5a..6677f74f6e 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSIUtils.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/ConverterCSIUtils.cs @@ -1,387 +1,404 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Objects.Structural.Geometry; using CSiAPIv1; using Objects.Structural.CSI.Analysis; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI - { - // warning: this delimter string needs to be the same as the delimter string in "connectorCSIUtils" - public const string Delimiter = "::"; + // warning: this delimter string needs to be the same as the delimter string in "connectorCSIUtils" + public const string Delimiter = "::"; - // WARNING: These strings need to have the same value as the strings in ConnectorBindingsCSI.Settings - readonly string SendNodeResults = "sendNodeResults"; - readonly string Send1DResults = "send1DResults"; - readonly string Send2DResults = "send2DResults"; + // WARNING: These strings need to have the same value as the strings in ConnectorBindingsCSI.Settings + readonly string SendNodeResults = "sendNodeResults"; + readonly string Send1DResults = "send1DResults"; + readonly string Send2DResults = "send2DResults"; - private string _modelUnits; + private string _modelUnits; - public string ModelUnits() + public string ModelUnits() + { + if (_modelUnits != null) { - if (_modelUnits != null) - return _modelUnits; - - var units = Model.GetPresentUnits(); - if (units != 0) - { - string[] unitsCat = units.ToString().Split('_'); - _modelUnits = unitsCat[1]; - return _modelUnits; - } - return null; + return _modelUnits; } - public double ScaleToNative(double value, string units) + var units = Model.GetPresentUnits(); + if (units != 0) { - var f = Speckle.Core.Kits.Units.GetConversionFactor(units, ModelUnits()); - return value * f; + string[] unitsCat = units.ToString().Split('_'); + _modelUnits = unitsCat[1]; + return _modelUnits; } + return null; + } + + public double ScaleToNative(double value, string units) + { + var f = Speckle.Core.Kits.Units.GetConversionFactor(units, ModelUnits()); + return value * f; + } - public static List GetAllFrameNames(cSapModel model) + public static List GetAllFrameNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - int num = 0; - var names = new string[] { }; - try - { - model.FrameObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } + model.FrameObj.GetNameList(ref num, ref names); + return names.ToList(); } - - public static List GetColumnNames(cSapModel model) + catch { - var frameNames = GetAllFrameNames(model); + return null; + } + } - List columnNames = new List(); + public static List GetColumnNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List columnNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("c")) - { - columnNames.Add(frameName); - } - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); - return columnNames; + if (frameLabel.ToLower().StartsWith("c")) + { + columnNames.Add(frameName); + } } - public static List GetBeamNames(cSapModel model) - { - var frameNames = GetAllFrameNames(model); + return columnNames; + } - List beamNames = new List(); + public static List GetBeamNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List beamNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("b")) - { - beamNames.Add(frameName); - } - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); - return beamNames; + if (frameLabel.ToLower().StartsWith("b")) + { + beamNames.Add(frameName); + } } - public static List GetBraceNames(cSapModel model) - { - var frameNames = GetAllFrameNames(model); + return beamNames; + } - List braceNames = new List(); + public static List GetBraceNames(cSapModel model) + { + var frameNames = GetAllFrameNames(model); - string frameLabel = ""; - string frameStory = ""; + List braceNames = new(); - foreach (var frameName in frameNames) - { - model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + string frameLabel = ""; + string frameStory = ""; - if (frameLabel.ToLower().StartsWith("d")) - { - braceNames.Add(frameName); - } + foreach (var frameName in frameNames) + { + model.FrameObj.GetLabelFromName(frameName, ref frameLabel, ref frameStory); + + if (frameLabel.ToLower().StartsWith("d")) + { + braceNames.Add(frameName); } + } - return braceNames; + return braceNames; + } + + public static List GetAllAreaNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try + { + model.AreaObj.GetNameList(ref num, ref names); + return names.ToList(); } + catch + { + return null; + } + } - public static List GetAllAreaNames(cSapModel model) + public static List GetAllWallNames(cSapModel model) + { + var WallNames = GetAllAreaNames(model); + + List WallName = new(); + + string wallLabel = ""; + string wallStory = ""; + + foreach (var wallName in WallNames) { - int num = 0; - var names = new string[] { }; - try - { - model.AreaObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch + model.AreaObj.GetLabelFromName(wallName, ref wallLabel, ref wallStory); + + if (wallLabel.ToLower().StartsWith("w")) { - return null; + WallName.Add(wallName); } } - public static List GetAllWallNames(cSapModel model) - { - var WallNames = GetAllAreaNames(model); + return WallName; + } - List WallName = new List(); + public static List GetAllFloorNames(cSapModel model) + { + var FloorNames = GetAllAreaNames(model); - string wallLabel = ""; - string wallStory = ""; + List FloorName = new(); - foreach (var wallName in WallNames) - { - model.AreaObj.GetLabelFromName(wallName, ref wallLabel, ref wallStory); + string FloorLabel = ""; + string FloorStory = ""; - if (wallLabel.ToLower().StartsWith("w")) - { - WallName.Add(wallName); - } - } + foreach (var floorName in FloorNames) + { + model.AreaObj.GetLabelFromName(floorName, ref FloorLabel, ref FloorStory); - return WallName; + if (FloorLabel.ToLower().StartsWith("f")) + { + FloorName.Add(floorName); + } } - public static List GetAllFloorNames(cSapModel model) - { - var FloorNames = GetAllAreaNames(model); - - List FloorName = new List(); + return FloorName; + } - string FloorLabel = ""; - string FloorStory = ""; + public Dictionary GetAllGuids(cSapModel model) + { + var guids = new Dictionary(); - foreach (var floorName in FloorNames) + var names = GetAllFrameNames(model); + var guid = ""; + foreach (var name in names) + { + var success = Model.FrameObj.GetGUID(name, ref guid); + if (success != 0) { - model.AreaObj.GetLabelFromName(floorName, ref FloorLabel, ref FloorStory); - - if (FloorLabel.ToLower().StartsWith("f")) - { - FloorName.Add(floorName); - } + continue; } - return FloorName; + if (!guids.ContainsKey(guid)) + { + guids.Add(guid, name); + } } - public Dictionary GetAllGuids(cSapModel model) + names = GetAllAreaNames(model); + foreach (var name in names) { - var guids = new Dictionary(); - - var names = GetAllFrameNames(model); - var guid = ""; - foreach (var name in names) + var success = Model.AreaObj.GetGUID(name, ref guid); + if (success != 0) { - var success = Model.FrameObj.GetGUID(name, ref guid); - if (success != 0) - continue; - - if (!guids.ContainsKey(guid)) - guids.Add(guid, name); + continue; } - names = GetAllAreaNames(model); - foreach (var name in names) + if (!guids.ContainsKey(guid)) { - var success = Model.AreaObj.GetGUID(name, ref guid); - if (success != 0) - continue; - - if (!guids.ContainsKey(guid)) - guids.Add(guid, name); + guids.Add(guid, name); } - - //names = GetAllPointNames(model); - //foreach (var name in names) - //{ - // var guid = ""; - // var success = Model.PointObj.GetGUID(name, ref guid); - // if (success != 0) - // continue; - - // if (!guids.ContainsKey(guid)) - // guids.Add(guid, name); - //} - - return guids; } - public bool ElementExistsWithApplicationId(string applicationId, out string name) - { - name = ""; - if (string.IsNullOrEmpty(applicationId) || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) - return false; + //names = GetAllPointNames(model); + //foreach (var name in names) + //{ + // var guid = ""; + // var success = Model.PointObj.GetGUID(name, ref guid); + // if (success != 0) + // continue; - var projectIds = PreviousContextObjects.Where(o => o.applicationId == applicationId).FirstOrDefault()?.CreatedIds; - projectIds = projectIds ?? new List { applicationId }; + // if (!guids.ContainsKey(guid)) + // guids.Add(guid, name); + //} - foreach (var guid in projectIds) - if (ExistingObjectGuids.Keys.Contains(guid)) - { - name = ExistingObjectGuids[guid]; - return true; - } + return guids; + } + public bool ElementExistsWithApplicationId(string applicationId, out string name) + { + name = ""; + if (string.IsNullOrEmpty(applicationId) || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) + { return false; } - public string GetOriginalApplicationId(string csiAppId) + var projectIds = PreviousContextObjects.Where(o => o.applicationId == applicationId).FirstOrDefault()?.CreatedIds; + projectIds = projectIds ?? new List { applicationId }; + + foreach (var guid in projectIds) { - if (string.IsNullOrEmpty(csiAppId)) - return csiAppId; + if (ExistingObjectGuids.Keys.Contains(guid)) + { + name = ExistingObjectGuids[guid]; + return true; + } + } - var originalAppId = PreviousContextObjects - .Where(o => o.CreatedIds.Contains(csiAppId)) - .FirstOrDefault() - ?.applicationId; + return false; + } - return originalAppId ?? csiAppId; + public string GetOriginalApplicationId(string csiAppId) + { + if (string.IsNullOrEmpty(csiAppId)) + { + return csiAppId; } - public ShellType ConvertShellType(eShellType eShellType) - { - ShellType shellType = new ShellType(); + var originalAppId = PreviousContextObjects + .Where(o => o.CreatedIds.Contains(csiAppId)) + .FirstOrDefault() + ?.applicationId; - switch (eShellType) - { - case eShellType.Membrane: - shellType = ShellType.Membrane; - break; - case eShellType.ShellThick: - shellType = ShellType.ShellThick; - break; - case eShellType.ShellThin: - shellType = ShellType.ShellThin; - break; - case eShellType.Layered: - shellType = ShellType.Layered; - break; - default: - shellType = ShellType.Null; - break; - } + return originalAppId ?? csiAppId; + } - return shellType; - } + public ShellType ConvertShellType(eShellType eShellType) + { + ShellType shellType = new(); - public bool[] RestraintToNative(Restraint restraint) + switch (eShellType) { - bool[] restraints = new bool[6]; + case eShellType.Membrane: + shellType = ShellType.Membrane; + break; + case eShellType.ShellThick: + shellType = ShellType.ShellThick; + break; + case eShellType.ShellThin: + shellType = ShellType.ShellThin; + break; + case eShellType.Layered: + shellType = ShellType.Layered; + break; + default: + shellType = ShellType.Null; + break; + } - var code = restraint.code; + return shellType; + } - int i = 0; - foreach (char c in code) - { - restraints[i] = c.Equals('F') ? true : false; // other assume default of released - i++; - } + public bool[] RestraintToNative(Restraint restraint) + { + bool[] restraints = new bool[6]; - return restraints; - } + var code = restraint.code; - public double[] PartialRestraintToNative(Restraint restraint) + int i = 0; + foreach (char c in code) { - double[] partialFix = new double[6]; - partialFix[0] = restraint.stiffnessX; - partialFix[1] = restraint.stiffnessY; - partialFix[2] = restraint.stiffnessZ; - partialFix[3] = restraint.stiffnessXX; - partialFix[4] = restraint.stiffnessYY; - partialFix[5] = restraint.stiffnessZZ; - return partialFix; + restraints[i] = c.Equals('F') ? true : false; // other assume default of released + i++; } - public Restraint RestraintToSpeckle(bool[] releases) + return restraints; + } + + public double[] PartialRestraintToNative(Restraint restraint) + { + double[] partialFix = new double[6]; + partialFix[0] = restraint.stiffnessX; + partialFix[1] = restraint.stiffnessY; + partialFix[2] = restraint.stiffnessZ; + partialFix[3] = restraint.stiffnessXX; + partialFix[4] = restraint.stiffnessYY; + partialFix[5] = restraint.stiffnessZZ; + return partialFix; + } + + public Restraint RestraintToSpeckle(bool[] releases) + { + var code = new List() { "R", "R", "R", "R", "R", "R" }; // default to free + if (releases != null) { - var code = new List() { "R", "R", "R", "R", "R", "R" }; // default to free - if (releases != null) + for (int i = 0; i < releases.Length; i++) { - for (int i = 0; i < releases.Length; i++) + if (releases[i]) { - if (releases[i]) - code[i] = "F"; + code[i] = "F"; } } - - var restraint = new Restraint(string.Join("", code)); - return restraint; } - public static List GetAllPointNames(cSapModel model) - { - int num = 0; - var names = new string[] { }; - try - { - model.PointObj.GetNameList(ref num, ref names); - return names.ToList(); - } - catch - { - return null; - } - } + var restraint = new Restraint(string.Join("", code)); + return restraint; + } - public enum CSIConverterSupported + public static List GetAllPointNames(cSapModel model) + { + int num = 0; + var names = new string[] { }; + try { - //CSINode, - Node, - Line, - Element1D, - Element2D, - //Model, + model.PointObj.GetNameList(ref num, ref names); + return names.ToList(); } - - public enum CSIAPIUsableTypes + catch { - Point, - Frame, - Area, // cAreaObj - LoadPattern, - Model, - Column, - Brace, - Beam, - Floor, - Wall, - Tendon, - Links, - Spandrel, - Pier, - Grids, - - //Diaphragm, - BeamLoading, - ColumnLoading, - BraceLoading, - FrameLoading, - FloorLoading, - AreaLoading, - WallLoading, - NodeLoading, - - //ColumnResults, - //BeamResults, - //BraceResults, - //PierResults, - //SpandrelResults - AnalysisResults + return null; } } + + public enum CSIConverterSupported + { + //CSINode, + Node, + Line, + Element1D, + Element2D, + //Model, + } + + public enum CSIAPIUsableTypes + { + Point, + Frame, + Area, // cAreaObj + LoadPattern, + Model, + Column, + Brace, + Beam, + Floor, + Wall, + Tendon, + Links, + Spandrel, + Pier, + Grids, + + //Diaphragm, + BeamLoading, + ColumnLoading, + BraceLoading, + FrameLoading, + FloorLoading, + AreaLoading, + WallLoading, + NodeLoading, + + //ColumnResults, + //BeamResults, + //BraceResults, + //PierResults, + //SpandrelResults + AnalysisResults + } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ArcExtensions.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ArcExtensions.cs index cd48c92568..76a89b6b10 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ArcExtensions.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ArcExtensions.cs @@ -5,73 +5,72 @@ using System.Text; using Objects.Geometry; -namespace ConverterCSIShared.Extensions +namespace ConverterCSIShared.Extensions; + +internal static class ArcExtensions { - internal static class ArcExtensions + public static IEnumerable ToPoints(this Arc arc) { - public static IEnumerable ToPoints(this Arc arc) - { - var startPoint = new Vector3((float)arc.startPoint.x, (float)arc.startPoint.y, (float)arc.startPoint.z); - var endPoint = new Vector3((float)arc.endPoint.x, (float)arc.endPoint.y, (float)arc.endPoint.z); - var midPoint = new Vector3((float)arc.midPoint.x, (float)arc.midPoint.y, (float)arc.midPoint.z); + var startPoint = new Vector3((float)arc.startPoint.x, (float)arc.startPoint.y, (float)arc.startPoint.z); + var endPoint = new Vector3((float)arc.endPoint.x, (float)arc.endPoint.y, (float)arc.endPoint.z); + var midPoint = new Vector3((float)arc.midPoint.x, (float)arc.midPoint.y, (float)arc.midPoint.z); - // Calculate the radius and center of the arc - Vector3 center = CalculateArcCenter(startPoint, midPoint, endPoint); - float radius = Vector3.Distance(startPoint, center); + // Calculate the radius and center of the arc + Vector3 center = CalculateArcCenter(startPoint, midPoint, endPoint); + float radius = Vector3.Distance(startPoint, center); - // Calculate the plane defined by the start, center, and end points - Vector3 normal = Vector3.Normalize(Vector3.Cross(startPoint - center, endPoint - center)); + // Calculate the plane defined by the start, center, and end points + Vector3 normal = Vector3.Normalize(Vector3.Cross(startPoint - center, endPoint - center)); - // Calculate the angles between the start, center, and end points - float startAngle = CalculateAngle(center, startPoint, normal); - float endAngle = CalculateAngle(center, endPoint, normal); - float angleRange = endAngle - startAngle; + // Calculate the angles between the start, center, and end points + float startAngle = CalculateAngle(center, startPoint, normal); + float endAngle = CalculateAngle(center, endPoint, normal); + float angleRange = endAngle - startAngle; - // Calculate the angular increment for each point - float angularIncrement = angleRange / 9; // 10 points including start and end points + // Calculate the angular increment for each point + float angularIncrement = angleRange / 9; // 10 points including start and end points - // Generate the arc points - for (int i = 0; i <= 10; i++) - { - float currentAngle = startAngle + (i * angularIncrement); - Vector3 point = RotatePoint(startPoint, center, normal, currentAngle); - yield return new Point(point.X, point.Y, point.Z); - } + // Generate the arc points + for (int i = 0; i <= 10; i++) + { + float currentAngle = startAngle + (i * angularIncrement); + Vector3 point = RotatePoint(startPoint, center, normal, currentAngle); + yield return new Point(point.X, point.Y, point.Z); } + } - private static Vector3 CalculateArcCenter(Vector3 startPoint, Vector3 midPoint, Vector3 endPoint) - { - // Calculate the perpendicular bisectors of the line segments between start-mid and mid-end - Vector3 startMidMidpoint = (startPoint + midPoint) / 2; - Vector3 midEndMidpoint = (midPoint + endPoint) / 2; - Vector3 startMidDirection = Vector3.Normalize(midPoint - startPoint); - Vector3 midEndDirection = Vector3.Normalize(endPoint - midPoint); + private static Vector3 CalculateArcCenter(Vector3 startPoint, Vector3 midPoint, Vector3 endPoint) + { + // Calculate the perpendicular bisectors of the line segments between start-mid and mid-end + Vector3 startMidMidpoint = (startPoint + midPoint) / 2; + Vector3 midEndMidpoint = (midPoint + endPoint) / 2; + Vector3 startMidDirection = Vector3.Normalize(midPoint - startPoint); + Vector3 midEndDirection = Vector3.Normalize(endPoint - midPoint); - // Calculate the normal to the plane containing the bisectors - Vector3 normal = Vector3.Normalize(Vector3.Cross(startMidDirection, midEndDirection)); + // Calculate the normal to the plane containing the bisectors + Vector3 normal = Vector3.Normalize(Vector3.Cross(startMidDirection, midEndDirection)); - // Calculate the intersection point of the plane and the perpendicular bisectors (arc center) - float startMidDot = Vector3.Dot(startMidMidpoint, normal); - float midEndDot = Vector3.Dot(midEndMidpoint, normal); - float normalDot = Vector3.Dot(normal, normal); - float t = (startMidDot - midEndDot) / normalDot; - Vector3 center = startMidMidpoint - t * normal; + // Calculate the intersection point of the plane and the perpendicular bisectors (arc center) + float startMidDot = Vector3.Dot(startMidMidpoint, normal); + float midEndDot = Vector3.Dot(midEndMidpoint, normal); + float normalDot = Vector3.Dot(normal, normal); + float t = (startMidDot - midEndDot) / normalDot; + Vector3 center = startMidMidpoint - t * normal; - return center; - } + return center; + } - private static float CalculateAngle(Vector3 center, Vector3 point, Vector3 normal) - { - Vector3 direction = point - center; - float angle = (float)Math.Atan2(Vector3.Dot(normal, Vector3.Cross(center, point)), Vector3.Dot(center, point)); - return angle; - } + private static float CalculateAngle(Vector3 center, Vector3 point, Vector3 normal) + { + Vector3 direction = point - center; + float angle = (float)Math.Atan2(Vector3.Dot(normal, Vector3.Cross(center, point)), Vector3.Dot(center, point)); + return angle; + } - private static Vector3 RotatePoint(Vector3 point, Vector3 center, Vector3 axis, float angle) - { - Quaternion rotation = Quaternion.CreateFromAxisAngle(axis, angle); - Vector3 rotatedPoint = Vector3.Transform(point - center, rotation); - return rotatedPoint + center; - } + private static Vector3 RotatePoint(Vector3 point, Vector3 center, Vector3 axis, float angle) + { + Quaternion rotation = Quaternion.CreateFromAxisAngle(axis, angle); + Vector3 rotatedPoint = Vector3.Transform(point - center, rotation); + return rotatedPoint + center; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/CurveExtensions.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/CurveExtensions.cs index 8432c489d9..60d4d2db89 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/CurveExtensions.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/CurveExtensions.cs @@ -3,16 +3,15 @@ using System.Text; using Objects.Geometry; -namespace ConverterCSIShared.Extensions +namespace ConverterCSIShared.Extensions; + +internal static class CurveExtensions { - internal static class CurveExtensions + public static IEnumerable ToPoints(this Curve curve) { - public static IEnumerable ToPoints(this Curve curve) + for (int i = 0; i < curve.points.Count; i += 3) { - for (int i = 0; i < curve.points.Count; i += 3) - { - yield return new Point(curve.points[i], curve.points[i + 1], curve.points[i + 2], curve.units); - } + yield return new Point(curve.points[i], curve.points[i + 1], curve.points[i + 2], curve.units); } } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ICurveExtensions.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ICurveExtensions.cs index c2a674cfbf..f1e555b36a 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ICurveExtensions.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/ICurveExtensions.cs @@ -4,24 +4,23 @@ using Objects.Geometry; using Objects; -namespace ConverterCSIShared.Extensions +namespace ConverterCSIShared.Extensions; + +internal static class ICurveExtensions { - internal static class ICurveExtensions + public static IEnumerable ToPoints(this ICurve crv) { - public static IEnumerable ToPoints(this ICurve crv) + return crv switch { - return crv switch - { - Line line => line.ToPoints(), - Arc arc => arc.ToPoints(), - Circle circle => throw new NotImplementedException("Circular openings are not yet supported"), - Ellipse ellipse => throw new NotImplementedException("Ellipse openings are not yet supported"), - Spiral spiral => throw new NotImplementedException("Spiral openings are not yet supported"), - Curve curve => curve.ToPoints(), - Polyline poly => poly.GetPoints(), - Polycurve plc => plc.ToPoints(), - _ => throw new Speckle.Core.Logging.SpeckleException("The provided geometry is not a valid curve"), - }; - } + Line line => line.ToPoints(), + Arc arc => arc.ToPoints(), + Circle circle => throw new NotImplementedException("Circular openings are not yet supported"), + Ellipse ellipse => throw new NotImplementedException("Ellipse openings are not yet supported"), + Spiral spiral => throw new NotImplementedException("Spiral openings are not yet supported"), + Curve curve => curve.ToPoints(), + Polyline poly => poly.GetPoints(), + Polycurve plc => plc.ToPoints(), + _ => throw new Speckle.Core.Logging.SpeckleException("The provided geometry is not a valid curve"), + }; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/LineExtensions.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/LineExtensions.cs index a43105b036..eaf1e12591 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/LineExtensions.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/LineExtensions.cs @@ -3,14 +3,13 @@ using System.Text; using Objects.Geometry; -namespace ConverterCSIShared.Extensions +namespace ConverterCSIShared.Extensions; + +internal static class LineExtensions { - internal static class LineExtensions + public static IEnumerable ToPoints(this Line line) { - public static IEnumerable ToPoints(this Line line) - { - yield return line.start; - yield return line.end; - } + yield return line.start; + yield return line.end; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/PolycurveExtensions.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/PolycurveExtensions.cs index bfc72e9cbd..9c499c1dc8 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/PolycurveExtensions.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Extensions/PolycurveExtensions.cs @@ -2,28 +2,27 @@ using System.Collections.Generic; using Objects.Geometry; -namespace ConverterCSIShared.Extensions +namespace ConverterCSIShared.Extensions; + +internal static class PolycurveExtensions { - internal static class PolycurveExtensions + public static IEnumerable ToPoints(this Polycurve polycurve) { - public static IEnumerable ToPoints(this Polycurve polycurve) + var prevPoint = new Point(double.NaN, double.NaN, double.NaN); + foreach (var seg in polycurve.segments) { - var prevPoint = new Point(double.NaN, double.NaN, double.NaN); - foreach (var seg in polycurve.segments) + foreach (var point in seg.ToPoints()) { - foreach (var point in seg.ToPoints()) + if ( + Math.Abs(point.x - prevPoint.x) < .01 + && Math.Abs(point.y - prevPoint.y) < .01 + && Math.Abs(point.z - prevPoint.z) < .01 + ) { - if ( - Math.Abs(point.x - prevPoint.x) < .01 - && Math.Abs(point.y - prevPoint.y) < .01 - && Math.Abs(point.z - prevPoint.z) < .01 - ) - { - continue; - } - prevPoint = point; - yield return point; + continue; } + prevPoint = point; + yield return point; } } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ApiResultValidator.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ApiResultValidator.cs index e3dec10b8b..989d06c448 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ApiResultValidator.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ApiResultValidator.cs @@ -1,32 +1,33 @@ using System; using Speckle.Core.Kits; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +public static class ApiResultValidator { - public static class ApiResultValidator + public static bool IsSuccessful(int success) + { + return success == 0; + } + + public static void ThrowIfUnsuccessful(int success, string message) { - public static bool IsSuccessful(int success) + if (IsSuccessful(success)) { - return success == 0; + return; } - public static void ThrowIfUnsuccessful(int success, string message) - { - if (IsSuccessful(success)) - { - return; - } - throw new ConversionException(message); - } - public static void ThrowIfUnsuccessful(int success, string message) - where T : Exception - { - if (IsSuccessful(success)) - { - return; - } + throw new ConversionException(message); + } - throw (T)Activator.CreateInstance(typeof(T), message); + public static void ThrowIfUnsuccessful(int success, string message) + where T : Exception + { + if (IsSuccessful(success)) + { + return; } + + throw (T)Activator.CreateInstance(typeof(T), message); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/DatabaseTableWrapper.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/DatabaseTableWrapper.cs index ed9ffce2d6..7859c46db5 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/DatabaseTableWrapper.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/DatabaseTableWrapper.cs @@ -4,83 +4,99 @@ using CSiAPIv1; using Speckle.Core.Logging; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +internal abstract class DatabaseTableWrapper { - internal abstract class DatabaseTableWrapper + public abstract string TableKey { get; } + + protected readonly cSapModel cSapModel; + protected readonly ToNativeScalingService toNativeScalingService; + + private int tableVersion; + protected string[] fieldKeysIncluded; + private int numRecords; + private List tableData; + + private readonly List rowsToAdd = new(); + + protected DatabaseTableWrapper(cSapModel cSapModel, ToNativeScalingService toNativeScalingService) { - public abstract string TableKey { get; } - - protected readonly cSapModel cSapModel; - protected readonly ToNativeScalingService toNativeScalingService; - - private int tableVersion; - protected string[] fieldKeysIncluded; - private int numRecords; - private List tableData; + this.cSapModel = cSapModel; + this.toNativeScalingService = toNativeScalingService; + RefreshTableData(); + } - private readonly List rowsToAdd = new(); - protected DatabaseTableWrapper(cSapModel cSapModel, ToNativeScalingService toNativeScalingService) - { - this.cSapModel = cSapModel; - this.toNativeScalingService = toNativeScalingService; - RefreshTableData(); - } - private void RefreshTableData() + private void RefreshTableData() + { + var tableData = Array.Empty(); + cSapModel.DatabaseTables.GetTableForEditingArray( + TableKey, + "this param does nothing", + ref tableVersion, + ref fieldKeysIncluded, + ref numRecords, + ref tableData + ); + this.tableData = new List(tableData); + } + + protected void AddRowToBeCommitted(params string[] arguments) + { + if (arguments.Length != fieldKeysIncluded.Length) { - var tableData = Array.Empty(); - cSapModel.DatabaseTables.GetTableForEditingArray( - TableKey, - "this param does nothing", - ref tableVersion, - ref fieldKeysIncluded, - ref numRecords, - ref tableData + throw new ArgumentException( + $"Method {nameof(AddRowToBeCommitted)} was passed an array of length {arguments.Length}, but was expecting an array of length {fieldKeysIncluded.Length}" ); - this.tableData = new List(tableData); } + rowsToAdd.Add(arguments); + } - protected void AddRowToBeCommitted(params string[] arguments) + public void CommitPendingChanges() + { + foreach (string[] row in rowsToAdd) { - if (arguments.Length != fieldKeysIncluded.Length) - { - throw new ArgumentException($"Method {nameof(AddRowToBeCommitted)} was passed an array of length {arguments.Length}, but was expecting an array of length {fieldKeysIncluded.Length}"); - } - rowsToAdd.Add(arguments); + tableData.AddRange(row); + numRecords++; } + ApplyTablesEditedTables(); + } - public void CommitPendingChanges() - { - foreach (string[] row in rowsToAdd) - { - tableData.AddRange(row); - numRecords++; - } - ApplyTablesEditedTables(); - } + private void ApplyTablesEditedTables() + { + var tableDataArray = tableData.ToArray(); + cSapModel.DatabaseTables.SetTableForEditingArray( + TableKey, + ref tableVersion, + ref fieldKeysIncluded, + numRecords, + ref tableDataArray + ); + + int numFatalErrors = 0; + int numWarnMsgs = 0; + int numInfoMsgs = 0; + int numErrorMsgs = 0; + string importLog = ""; + cSapModel.DatabaseTables.ApplyEditedTables( + false, + ref numFatalErrors, + ref numErrorMsgs, + ref numWarnMsgs, + ref numInfoMsgs, + ref importLog + ); - private void ApplyTablesEditedTables() + if (numFatalErrors == 0 && numErrorMsgs == 0) { - var tableDataArray = tableData.ToArray(); - cSapModel.DatabaseTables.SetTableForEditingArray( - TableKey, - ref tableVersion, - ref fieldKeysIncluded, - numRecords, - ref tableDataArray + SpeckleLog.Logger.Error( + "{numErrors} errors and {numFatalErrors} fatal errors occurred when attempting to add {numRowsToAdd} rows to table with key, {tableKey}", + numErrorMsgs, + numFatalErrors, + rowsToAdd.Count, + TableKey ); - - int numFatalErrors = 0; - int numWarnMsgs = 0; - int numInfoMsgs = 0; - int numErrorMsgs = 0; - string importLog = ""; - cSapModel.DatabaseTables.ApplyEditedTables(false, ref numFatalErrors, ref numErrorMsgs, ref numWarnMsgs, ref numInfoMsgs, ref importLog); - - if (numFatalErrors == 0 && numErrorMsgs == 0) - { - SpeckleLog.Logger.Error("{numErrors} errors and {numFatalErrors} fatal errors occurred when attempting to add {numRowsToAdd} rows to table with key, {tableKey}", numErrorMsgs, numFatalErrors, rowsToAdd.Count, TableKey); - } - rowsToAdd.Clear(); } + rowsToAdd.Clear(); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ETABSGridLineDefinitionTable.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ETABSGridLineDefinitionTable.cs index 209ebdce1d..7b27782d21 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ETABSGridLineDefinitionTable.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ETABSGridLineDefinitionTable.cs @@ -7,265 +7,264 @@ using Objects.Other; using Speckle.Core.Logging; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +/// +/// Encapsulates the logic dealing with creating and manipulating gridlines via the interactive database in ETABS +/// +internal class ETABSGridLineDefinitionTable : DatabaseTableWrapper { + private const double gridTolerance = .001; // .05 degrees as radians + public override string TableKey => "Grid Definitions - Grid Lines"; + public static string?[] DefaultRow => + new string?[] + { + null, // Name : Grid System name + null, // LineType + null, // Id : Grid name + null, // Ordinate : Offset in the positive direction + null, // Angle : clockwise offset in degrees for polar (cylindrical) coordinates + null, // X1 + null, // Y1 + null, // X2 + null, // Y2 + "Start", // BubbleLoc + "Yes", // Visible + }; + + public ETABSGridLineDefinitionTable(cSapModel cSapModel, ToNativeScalingService toNativeScalingService) + : base(cSapModel, toNativeScalingService) { } + + public const string XGridLineType = "X (Cartesian)"; + public const string YGridLineType = "Y (Cartesian)"; + public const string RGridLineType = "R (Cylindrical)"; + public const string TGridLineType = "T (Cylindrical)"; + /// - /// Encapsulates the logic dealing with creating and manipulating gridlines via the interactive database in ETABS + /// Add a gridline that is represented by a straight line to the ETABS document /// - internal class ETABSGridLineDefinitionTable : DatabaseTableWrapper + /// + /// + /// + /// + /// + /// + public void AddCartesian( + string gridSystemName, + string gridLineType, + string gridName, + double location, + string visible = "Yes" + ) { - private const double gridTolerance = .001; // .05 degrees as radians - public override string TableKey => "Grid Definitions - Grid Lines"; - public static string?[] DefaultRow => - new string?[] - { - null, // Name : Grid System name - null, // LineType - null, // Id : Grid name - null, // Ordinate : Offset in the positive direction - null, // Angle : clockwise offset in degrees for polar (cylindrical) coordinates - null, // X1 - null, // Y1 - null, // X2 - null, // Y2 - "Start", // BubbleLoc - "Yes", // Visible - }; - - public ETABSGridLineDefinitionTable(cSapModel cSapModel, ToNativeScalingService toNativeScalingService) - : base(cSapModel, toNativeScalingService) { } - - public const string XGridLineType = "X (Cartesian)"; - public const string YGridLineType = "Y (Cartesian)"; - public const string RGridLineType = "R (Cylindrical)"; - public const string TGridLineType = "T (Cylindrical)"; + if (gridLineType != XGridLineType && gridLineType != YGridLineType) + { + throw new ArgumentException( + $"Argument gridLineType must be either {XGridLineType} or {YGridLineType}", + nameof(gridLineType) + ); + } - /// - /// Add a gridline that is represented by a straight line to the ETABS document - /// - /// - /// - /// - /// - /// - /// - public void AddCartesian( - string gridSystemName, - string gridLineType, - string gridName, - double location, - string visible = "Yes" - ) + var newRow = new string?[fieldKeysIncluded.Length]; + for (var index = 0; index < fieldKeysIncluded.Length; index++) { - if (gridLineType != XGridLineType && gridLineType != YGridLineType) + newRow[index] = fieldKeysIncluded[index] switch { - throw new ArgumentException( - $"Argument gridLineType must be either {XGridLineType} or {YGridLineType}", - nameof(gridLineType) - ); - } + "Name" => gridSystemName, + "LineType" => gridLineType, + "ID" => gridName, + "Ordinate" => location.ToString(), + "Visible" => visible, + _ => DefaultRow[index], + }; + } - var newRow = new string?[fieldKeysIncluded.Length]; - for (var index = 0; index < fieldKeysIncluded.Length; index++) - { - newRow[index] = fieldKeysIncluded[index] switch - { - "Name" => gridSystemName, - "LineType" => gridLineType, - "ID" => gridName, - "Ordinate" => location.ToString(), - "Visible" => visible, - _ => DefaultRow[index], - }; - } + AddRowToBeCommitted(newRow); + } - AddRowToBeCommitted(newRow); + /// + /// Add a gridline that is represented by a straight line to the ETABS document + /// + /// + /// + /// + public void AddCartesian(GridLine gridLine) + { + if (gridLine.baseLine is not Line line) + { + throw new ArgumentException("Non line based gridlines are not supported", nameof(gridLine)); } - /// - /// Add a gridline that is represented by a straight line to the ETABS document - /// - /// - /// - /// - public void AddCartesian(GridLine gridLine) - { - if (gridLine.baseLine is not Line line) - { - throw new ArgumentException("Non line based gridlines are not supported", nameof(gridLine)); - } + var gridRotation = GetAngleOffsetFromGlobalCoordinateSystem(line); - var gridRotation = GetAngleOffsetFromGlobalCoordinateSystem(line); + var gridSystem = GetExistingGridSystem(gridRotation) ?? CreateGridSystem(gridRotation); + var transform = GetTransformFromGridSystem(gridSystem); + _ = line.TransformTo(transform.Inverse(), out Line transformedLine); - var gridSystem = GetExistingGridSystem(gridRotation) ?? CreateGridSystem(gridRotation); - var transform = GetTransformFromGridSystem(gridSystem); - _ = line.TransformTo(transform.Inverse(), out Line transformedLine); + var newUx = Math.Abs(transformedLine.start.x - transformedLine.end.x); + var newUy = Math.Abs(transformedLine.start.y - transformedLine.end.y); - var newUx = Math.Abs(transformedLine.start.x - transformedLine.end.x); - var newUy = Math.Abs(transformedLine.start.y - transformedLine.end.y); + string lineType; + double gridLineOffset; + if (newUx < gridTolerance) + { + lineType = XGridLineType; + gridLineOffset = toNativeScalingService.ScaleLength( + transformedLine.start.x, + transformedLine.units ?? transformedLine.start.units + ); + } + else if (newUy < gridTolerance) + { + lineType = YGridLineType; + gridLineOffset = toNativeScalingService.ScaleLength( + transformedLine.start.y, + transformedLine.units ?? transformedLine.start.units + ); + } + else + { + throw new SpeckleException( + $"Error in transforming line from global coordinates to grid system with rotation {gridSystem.Rotation} and x,y offsets {gridSystem.XOrigin}, {gridSystem.YOrigin}" + ); + } - string lineType; - double gridLineOffset; - if (newUx < gridTolerance) - { - lineType = XGridLineType; - gridLineOffset = toNativeScalingService.ScaleLength( - transformedLine.start.x, - transformedLine.units ?? transformedLine.start.units - ); - } - else if (newUy < gridTolerance) - { - lineType = YGridLineType; - gridLineOffset = toNativeScalingService.ScaleLength( - transformedLine.start.y, - transformedLine.units ?? transformedLine.start.units - ); - } - else - { - throw new SpeckleException( - $"Error in transforming line from global coordinates to grid system with rotation {gridSystem.Rotation} and x,y offsets {gridSystem.XOrigin}, {gridSystem.YOrigin}" - ); - } + AddCartesian(gridSystem.Name, lineType, gridLine.label, gridLineOffset); + } - AddCartesian(gridSystem.Name, lineType, gridLine.label, gridLineOffset); - } + /// + /// Returns the rotation counter-clockwise from from the global x axis in radians + /// + /// + /// + private static double GetAngleOffsetFromGlobalCoordinateSystem(Line line) + { + var ux = line.start.x - line.end.x; + var uy = line.start.y - line.end.y; - /// - /// Returns the rotation counter-clockwise from from the global x axis in radians - /// - /// - /// - private static double GetAngleOffsetFromGlobalCoordinateSystem(Line line) + if (Math.Abs(ux) < gridTolerance) { - var ux = line.start.x - line.end.x; - var uy = line.start.y - line.end.y; - - if (Math.Abs(ux) < gridTolerance) - { - return Math.PI / 2; - } - return Math.Atan(uy / ux); + return Math.PI / 2; } + return Math.Atan(uy / ux); + } - /// - /// Find a GridSystem in the CSi model whose local x axis is either parallel or perpendicular to the provided - /// grid angle. - /// - /// Rotation counter-clockwise from the global x axis in radians - /// - private GridSystemRepresentation? GetExistingGridSystem(double gridRotation) - { - var numGridSys = 0; - var gridSysNames = Array.Empty(); - this.cSapModel.GridSys.GetNameList(ref numGridSys, ref gridSysNames); + /// + /// Find a GridSystem in the CSi model whose local x axis is either parallel or perpendicular to the provided + /// grid angle. + /// + /// Rotation counter-clockwise from the global x axis in radians + /// + private GridSystemRepresentation? GetExistingGridSystem(double gridRotation) + { + var numGridSys = 0; + var gridSysNames = Array.Empty(); + this.cSapModel.GridSys.GetNameList(ref numGridSys, ref gridSysNames); - var xOrigin = 0.0; - var yOrigin = 0.0; - var rotationDeg = 0.0; - foreach (var gridSysName in gridSysNames) + var xOrigin = 0.0; + var yOrigin = 0.0; + var rotationDeg = 0.0; + foreach (var gridSysName in gridSysNames) + { + var success = cSapModel.GridSys.GetGridSys(gridSysName, ref xOrigin, ref yOrigin, ref rotationDeg); + if (success != 0) { - var success = cSapModel.GridSys.GetGridSys(gridSysName, ref xOrigin, ref yOrigin, ref rotationDeg); - if (success != 0) - { - // something went wrong. This is not necessarily unexpected or bad - continue; - } + // something went wrong. This is not necessarily unexpected or bad + continue; + } - var rotationRad = rotationDeg * Math.PI / 180; - var combinedRotationsNormalized = Math.Abs((rotationRad - gridRotation) / (Math.PI / 2)); - var combinedRotationsRemainder = combinedRotationsNormalized - Math.Floor(combinedRotationsNormalized); + var rotationRad = rotationDeg * Math.PI / 180; + var combinedRotationsNormalized = Math.Abs((rotationRad - gridRotation) / (Math.PI / 2)); + var combinedRotationsRemainder = combinedRotationsNormalized - Math.Floor(combinedRotationsNormalized); - if (combinedRotationsRemainder < gridTolerance || combinedRotationsRemainder > 1 - gridTolerance) - { - return new GridSystemRepresentation(gridSysName, xOrigin, yOrigin, rotationRad); - } + if (combinedRotationsRemainder < gridTolerance || combinedRotationsRemainder > 1 - gridTolerance) + { + return new GridSystemRepresentation(gridSysName, xOrigin, yOrigin, rotationRad); } - // could not find compatible existing grid system - return null; } + // could not find compatible existing grid system + return null; + } - private GridSystemRepresentation CreateGridSystem(double gridRotation) - { - var systemName = GetUniqueGridSystemName(); - _ = cSapModel.GridSys.SetGridSys(systemName, 0, 0, gridRotation * 180 / Math.PI); + private GridSystemRepresentation CreateGridSystem(double gridRotation) + { + var systemName = GetUniqueGridSystemName(); + _ = cSapModel.GridSys.SetGridSys(systemName, 0, 0, gridRotation * 180 / Math.PI); - // when a grid system is created, it doesn't show up unless it has at least one grid in each direction - AddCartesian(systemName, XGridLineType, "Default0", 0, "No"); - AddCartesian(systemName, YGridLineType, "Default1", 0, "No"); - return new GridSystemRepresentation(systemName, 0, 0, gridRotation); - } + // when a grid system is created, it doesn't show up unless it has at least one grid in each direction + AddCartesian(systemName, XGridLineType, "Default0", 0, "No"); + AddCartesian(systemName, YGridLineType, "Default1", 0, "No"); + return new GridSystemRepresentation(systemName, 0, 0, gridRotation); + } - /// - /// Returns a unique name to be used for a new speckle-created grid system. - /// - /// - private string GetUniqueGridSystemName() - { - var numGridSys = 0; - var gridSysNames = Array.Empty(); - this.cSapModel.GridSys.GetNameList(ref numGridSys, ref gridSysNames); + /// + /// Returns a unique name to be used for a new speckle-created grid system. + /// + /// + private string GetUniqueGridSystemName() + { + var numGridSys = 0; + var gridSysNames = Array.Empty(); + this.cSapModel.GridSys.GetNameList(ref numGridSys, ref gridSysNames); - var numberOfGridSystems = 0; - var gridSystemNamePrefix = "SpeckleGridSystem"; - foreach (var gridSysName in gridSysNames) + var numberOfGridSystems = 0; + var gridSystemNamePrefix = "SpeckleGridSystem"; + foreach (var gridSysName in gridSysNames) + { + // test if this grid system is one that we already created. If it is, then we need to adjust our + // numberOfGridSystems so that if we do end up creating a new one, it doesn't override an existing one. + if (!gridSysName.StartsWith(gridSystemNamePrefix)) { - // test if this grid system is one that we already created. If it is, then we need to adjust our - // numberOfGridSystems so that if we do end up creating a new one, it doesn't override an existing one. - if (!gridSysName.StartsWith(gridSystemNamePrefix)) - { - continue; - } - - if (int.TryParse(gridSysName.Replace(gridSystemNamePrefix, ""), out int gridSysNum)) - { - numberOfGridSystems = Math.Max(numberOfGridSystems, gridSysNum + 1); - } + continue; } - return $"{gridSystemNamePrefix}{numberOfGridSystems}"; - ; - } - private static Transform GetTransformFromGridSystem(GridSystemRepresentation sys) - { - return new Transform( - new double[] - { - Math.Cos(sys.Rotation), - -Math.Sin(sys.Rotation), - 0, - sys.XOrigin, - Math.Sin(sys.Rotation), - Math.Cos(sys.Rotation), - 0, - sys.YOrigin, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1 - } - ); + if (int.TryParse(gridSysName.Replace(gridSystemNamePrefix, ""), out int gridSysNum)) + { + numberOfGridSystems = Math.Max(numberOfGridSystems, gridSysNum + 1); + } } + return $"{gridSystemNamePrefix}{numberOfGridSystems}"; + ; } - public class GridSystemRepresentation + private static Transform GetTransformFromGridSystem(GridSystemRepresentation sys) { - public GridSystemRepresentation(string name, double xOrigin, double yOrigin, double rotation) - { - Name = name; - XOrigin = xOrigin; - YOrigin = yOrigin; - Rotation = rotation; - } + return new Transform( + new double[] + { + Math.Cos(sys.Rotation), + -Math.Sin(sys.Rotation), + 0, + sys.XOrigin, + Math.Sin(sys.Rotation), + Math.Cos(sys.Rotation), + 0, + sys.YOrigin, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + } + ); + } +} - public string Name { get; } - public double XOrigin { get; set; } - public double YOrigin { get; set; } - public double Rotation { get; set; } +public class GridSystemRepresentation +{ + public GridSystemRepresentation(string name, double xOrigin, double yOrigin, double rotation) + { + Name = name; + XOrigin = xOrigin; + YOrigin = yOrigin; + Rotation = rotation; } + + public string Name { get; } + public double XOrigin { get; set; } + public double YOrigin { get; set; } + public double Rotation { get; set; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element1DAnalyticalResultConverter.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element1DAnalyticalResultConverter.cs index 73e71fba9a..d718aa6524 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element1DAnalyticalResultConverter.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element1DAnalyticalResultConverter.cs @@ -10,310 +10,309 @@ using Speckle.Core.Logging; using Speckle.Core.Models; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +internal class Element1DAnalyticalResultConverter { - internal class Element1DAnalyticalResultConverter + private readonly cSapModel sapModel; + private readonly HashSet frameNames; + private readonly HashSet pierNames; + private readonly HashSet spandrelNames; + private readonly Dictionary loadCombinationsAndCases; + private readonly bool sendBeamForces; + private readonly bool sendBraceForces; + private readonly bool sendColumnForces; + private readonly bool sendOtherForces; + + public Element1DAnalyticalResultConverter( + cSapModel sapModel, + HashSet frameNames, + HashSet pierNames, + HashSet spandrelNames, + IEnumerable loadCombinations, + IEnumerable loadCases, + bool sendBeamForces, + bool sendBraceForces, + bool sendColumnForces, + bool sendOtherForces + ) { - private readonly cSapModel sapModel; - private readonly HashSet frameNames; - private readonly HashSet pierNames; - private readonly HashSet spandrelNames; - private readonly Dictionary loadCombinationsAndCases; - private readonly bool sendBeamForces; - private readonly bool sendBraceForces; - private readonly bool sendColumnForces; - private readonly bool sendOtherForces; + this.sapModel = sapModel; + this.frameNames = frameNames; + this.pierNames = pierNames; + this.spandrelNames = spandrelNames; + this.sapModel = sapModel; - public Element1DAnalyticalResultConverter( - cSapModel sapModel, - HashSet frameNames, - HashSet pierNames, - HashSet spandrelNames, - IEnumerable loadCombinations, - IEnumerable loadCases, - bool sendBeamForces, - bool sendBraceForces, - bool sendColumnForces, - bool sendOtherForces) + this.loadCombinationsAndCases = new(); + foreach (var combo in loadCombinations) + { + this.loadCombinationsAndCases.Add(combo.name, combo); + } + foreach (var loadCase in loadCases) { - this.sapModel = sapModel; - this.frameNames = frameNames; - this.pierNames = pierNames; - this.spandrelNames = spandrelNames; - this.sapModel = sapModel; + this.loadCombinationsAndCases.Add(loadCase.name, loadCase); + } - this.loadCombinationsAndCases = new(); - foreach (var combo in loadCombinations) - { - this.loadCombinationsAndCases.Add(combo.name, combo); - } - foreach (var loadCase in loadCases) - { - this.loadCombinationsAndCases.Add(loadCase.name, loadCase); - } + this.sendBeamForces = sendBeamForces; + this.sendBraceForces = sendBraceForces; + this.sendColumnForces = sendColumnForces; + this.sendOtherForces = sendOtherForces; + } - this.sendBeamForces = sendBeamForces; - this.sendBraceForces = sendBraceForces; - this.sendColumnForces = sendColumnForces; - this.sendOtherForces = sendOtherForces; + public AnalyticalResults? AnalyticalResultsToSpeckle(string elementName, ElementType1D elementType) + { + if (SendForces(elementType)) + { + return new() { resultsByLoadCombination = GetAnalysisResultsForElement1D(elementName).Cast().ToList() }; } + return null; + } - public AnalyticalResults? AnalyticalResultsToSpeckle(string elementName, ElementType1D elementType) + private ICollection GetAnalysisResultsForElement1D(string elementName) + { + if (frameNames.Contains(elementName)) { - if (SendForces(elementType)) - { - return new() - { - resultsByLoadCombination = GetAnalysisResultsForElement1D(elementName).Cast().ToList() - }; - } - return null; + return GetAnalysisResultsForFrame(elementName); } - private ICollection GetAnalysisResultsForElement1D(string elementName) + if (pierNames.Contains(elementName)) { - if (frameNames.Contains(elementName)) - { - return GetAnalysisResultsForFrame(elementName); - } - - if (pierNames.Contains(elementName)) - { - return GetAnalysisResultsForPier(elementName); - } - - if (spandrelNames.Contains(elementName)) - { - return GetAnalysisResultsForSpandrel(elementName); - } - - throw new SpeckleException($"Unable to find category for Element1D with name {elementName}"); + return GetAnalysisResultsForPier(elementName); } - private ICollection GetAnalysisResultsForFrame(string elementName) + if (spandrelNames.Contains(elementName)) { - int forcesSuccess = -1; + return GetAnalysisResultsForSpandrel(elementName); + } - // Reference variables for CSI API - int numberOfResults = 0; - var obj = Array.Empty(); - var elm = Array.Empty(); - var loadCase = Array.Empty(); - var stepType = Array.Empty(); - var objSta = Array.Empty(); - var elmSta = Array.Empty(); - var stepNum = Array.Empty(); - var p = Array.Empty(); - var v2 = Array.Empty(); - var v3 = Array.Empty(); - var t = Array.Empty(); - var m2 = Array.Empty(); - var m3 = Array.Empty(); + throw new SpeckleException($"Unable to find category for Element1D with name {elementName}"); + } - forcesSuccess = sapModel.Results.FrameForce( - elementName, - eItemTypeElm.ObjectElm, - ref numberOfResults, - ref obj, - ref objSta, - ref elm, - ref elmSta, - ref loadCase, - ref stepType, - ref stepNum, - ref p, - ref v2, - ref v3, - ref t, - ref m2, - ref m3 - ); + private ICollection GetAnalysisResultsForFrame(string elementName) + { + int forcesSuccess = -1; - // Value used to normalized output station of forces between 0 and 1 - double lengthOf1dElement = objSta.Max(); + // Reference variables for CSI API + int numberOfResults = 0; + var obj = Array.Empty(); + var elm = Array.Empty(); + var loadCase = Array.Empty(); + var stepType = Array.Empty(); + var objSta = Array.Empty(); + var elmSta = Array.Empty(); + var stepNum = Array.Empty(); + var p = Array.Empty(); + var v2 = Array.Empty(); + var v3 = Array.Empty(); + var t = Array.Empty(); + var m2 = Array.Empty(); + var m3 = Array.Empty(); - return CreateLoadCombinationResults( - elementName, - forcesSuccess, - numberOfResults, - null, - loadCase, - (int i) => (float)(objSta[i] / lengthOf1dElement), - p, - v2, - v3, - t, - m2, - m3); - } + forcesSuccess = sapModel.Results.FrameForce( + elementName, + eItemTypeElm.ObjectElm, + ref numberOfResults, + ref obj, + ref objSta, + ref elm, + ref elmSta, + ref loadCase, + ref stepType, + ref stepNum, + ref p, + ref v2, + ref v3, + ref t, + ref m2, + ref m3 + ); - private ResultSet1D GetOrCreateResult(Dictionary dict, string loadCaseName) + // Value used to normalized output station of forces between 0 and 1 + double lengthOf1dElement = objSta.Max(); + + return CreateLoadCombinationResults( + elementName, + forcesSuccess, + numberOfResults, + null, + loadCase, + (int i) => (float)(objSta[i] / lengthOf1dElement), + p, + v2, + v3, + t, + m2, + m3 + ); + } + + private ResultSet1D GetOrCreateResult(Dictionary dict, string loadCaseName) + { + if (!dict.TryGetValue(loadCaseName, out ResultSet1D comboResults)) { - if (!dict.TryGetValue(loadCaseName, out ResultSet1D comboResults)) - { - Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; - comboResults = new ResultSet1D(new()) - { - resultCase = loadCaseOrCombination - }; - dict[loadCaseName] = comboResults; - } - return comboResults; + Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; + comboResults = new ResultSet1D(new()) { resultCase = loadCaseOrCombination }; + dict[loadCaseName] = comboResults; } + return comboResults; + } - private ICollection GetAnalysisResultsForPier(string elementName) - { - int forcesSuccess = -1; + private ICollection GetAnalysisResultsForPier(string elementName) + { + int forcesSuccess = -1; - // Reference variables for CSI API - int numberOfResults = 0; - var storyName = Array.Empty(); - var pierName = Array.Empty(); - var loadCase = Array.Empty(); - var location = Array.Empty(); - var p = Array.Empty(); - var v2 = Array.Empty(); - var v3 = Array.Empty(); - var t = Array.Empty(); - var m2 = Array.Empty(); - var m3 = Array.Empty(); + // Reference variables for CSI API + int numberOfResults = 0; + var storyName = Array.Empty(); + var pierName = Array.Empty(); + var loadCase = Array.Empty(); + var location = Array.Empty(); + var p = Array.Empty(); + var v2 = Array.Empty(); + var v3 = Array.Empty(); + var t = Array.Empty(); + var m2 = Array.Empty(); + var m3 = Array.Empty(); - forcesSuccess = sapModel.Results.PierForce( - ref numberOfResults, - ref storyName, - ref pierName, - ref loadCase, - ref location, - ref p, - ref v2, - ref v3, - ref t, - ref m2, - ref m3 - ); + forcesSuccess = sapModel.Results.PierForce( + ref numberOfResults, + ref storyName, + ref pierName, + ref loadCase, + ref location, + ref p, + ref v2, + ref v3, + ref t, + ref m2, + ref m3 + ); - return CreateLoadCombinationResults( - elementName, - forcesSuccess, - numberOfResults, - pierName, - loadCase, - Return0Position, - p, - v2, - v3, - t, - m2, - m3); + return CreateLoadCombinationResults( + elementName, + forcesSuccess, + numberOfResults, + pierName, + loadCase, + Return0Position, + p, + v2, + v3, + t, + m2, + m3 + ); - // local function that just returns 0 in order to avoid unnecessary heap allocations - // that would occur if we were using a lambda - static float Return0Position(int i) - { - return 0; - } + // local function that just returns 0 in order to avoid unnecessary heap allocations + // that would occur if we were using a lambda + static float Return0Position(int i) + { + return 0; } + } - private ICollection GetAnalysisResultsForSpandrel(string elementName) - { - int forcesSuccess = -1; + private ICollection GetAnalysisResultsForSpandrel(string elementName) + { + int forcesSuccess = -1; - // Reference variables for CSI API - int numberOfResults = 0; - var storyName = Array.Empty(); - var spandrelName = Array.Empty(); - var loadCase = Array.Empty(); - var location = Array.Empty(); - var p = Array.Empty(); - var v2 = Array.Empty(); - var v3 = Array.Empty(); - var t = Array.Empty(); - var m2 = Array.Empty(); - var m3 = Array.Empty(); + // Reference variables for CSI API + int numberOfResults = 0; + var storyName = Array.Empty(); + var spandrelName = Array.Empty(); + var loadCase = Array.Empty(); + var location = Array.Empty(); + var p = Array.Empty(); + var v2 = Array.Empty(); + var v3 = Array.Empty(); + var t = Array.Empty(); + var m2 = Array.Empty(); + var m3 = Array.Empty(); - forcesSuccess = sapModel.Results.SpandrelForce( - ref numberOfResults, - ref storyName, - ref spandrelName, - ref loadCase, - ref location, - ref p, - ref v2, - ref v3, - ref t, - ref m2, - ref m3 - ); + forcesSuccess = sapModel.Results.SpandrelForce( + ref numberOfResults, + ref storyName, + ref spandrelName, + ref loadCase, + ref location, + ref p, + ref v2, + ref v3, + ref t, + ref m2, + ref m3 + ); - return CreateLoadCombinationResults( - elementName, - forcesSuccess, - numberOfResults, - spandrelName, - loadCase, - Return0Position, - p, - v2, - v3, - t, - m2, - m3); + return CreateLoadCombinationResults( + elementName, + forcesSuccess, + numberOfResults, + spandrelName, + loadCase, + Return0Position, + p, + v2, + v3, + t, + m2, + m3 + ); - // local function that just returns 0 in order to avoid unnecessary heap allocations - // that would occur if we were using a lambda - static float Return0Position(int i) - { - return 0; - } + // local function that just returns 0 in order to avoid unnecessary heap allocations + // that would occur if we were using a lambda + static float Return0Position(int i) + { + return 0; } + } - private ICollection CreateLoadCombinationResults( - string elementName, - int forcesSuccess, - int numberOfResults, - string[]? names, - string[] loadCase, - Func positionCalculator, - double[] p, - double[] v2, - double[] v3, - double[] t, - double[] m2, - double[] m3) + private ICollection CreateLoadCombinationResults( + string elementName, + int forcesSuccess, + int numberOfResults, + string[]? names, + string[] loadCase, + Func positionCalculator, + double[] p, + double[] v2, + double[] v3, + double[] t, + double[] m2, + double[] m3 + ) + { + Dictionary loadCombinationResults = new(); + for (int i = 0; i < numberOfResults; i++) { - Dictionary loadCombinationResults = new(); - for (int i = 0; i < numberOfResults; i++) + if (names != null && names[i] != elementName) { - if (names != null && names[i] != elementName) - { - continue; - } - Result1D result = new(); + continue; + } + Result1D result = new(); - if (ApiResultValidator.IsSuccessful(forcesSuccess)) - { - result.position = positionCalculator(i); - result.forceX = (float)p[i]; - result.forceY = (float)v2[i]; - result.forceZ = (float)v3[i]; - result.momentXX = (float)t[i]; - result.momentYY = (float)m2[i]; - result.momentZZ = (float)m3[i]; - }; - GetOrCreateResult(loadCombinationResults, loadCase[i]).results1D.Add(result); + if (ApiResultValidator.IsSuccessful(forcesSuccess)) + { + result.position = positionCalculator(i); + result.forceX = (float)p[i]; + result.forceY = (float)v2[i]; + result.forceZ = (float)v3[i]; + result.momentXX = (float)t[i]; + result.momentYY = (float)m2[i]; + result.momentZZ = (float)m3[i]; } - return loadCombinationResults.Values; + ; + GetOrCreateResult(loadCombinationResults, loadCase[i]).results1D.Add(result); } + return loadCombinationResults.Values; + } - private bool SendForces(ElementType1D type) + private bool SendForces(ElementType1D type) + { + return type switch { - return type switch - { - ElementType1D.Beam => sendBeamForces, - ElementType1D.Brace => sendBraceForces, - ElementType1D.Column => sendColumnForces, - _ => sendOtherForces - }; - } + ElementType1D.Beam => sendBeamForces, + ElementType1D.Brace => sendBraceForces, + ElementType1D.Column => sendColumnForces, + _ => sendOtherForces + }; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element2DAnalyticalResultConverter.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element2DAnalyticalResultConverter.cs index 842bf0c145..d7865ab1d7 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element2DAnalyticalResultConverter.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/Element2DAnalyticalResultConverter.cs @@ -8,219 +8,213 @@ using Objects.Structural.Results; using Speckle.Core.Models; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +internal class Element2DAnalyticalResultConverter { - internal class Element2DAnalyticalResultConverter + private readonly cSapModel sapModel; + private readonly Dictionary loadCombinationsAndCases; + private readonly bool sendForces; + private readonly bool sendStresses; + + public Element2DAnalyticalResultConverter( + cSapModel sapModel, + IEnumerable loadCombinations, + IEnumerable loadCases, + bool sendForces, + bool sendStresses + ) { - private readonly cSapModel sapModel; - private readonly Dictionary loadCombinationsAndCases; - private readonly bool sendForces; - private readonly bool sendStresses; - - public Element2DAnalyticalResultConverter( - cSapModel sapModel, - IEnumerable loadCombinations, - IEnumerable loadCases, - bool sendForces, - bool sendStresses) + this.sapModel = sapModel; + this.sapModel = sapModel; + + this.loadCombinationsAndCases = new(); + foreach (var combo in loadCombinations) { - this.sapModel = sapModel; - this.sapModel = sapModel; + this.loadCombinationsAndCases.Add(combo.name, combo); + } - this.loadCombinationsAndCases = new(); - foreach (var combo in loadCombinations) - { - this.loadCombinationsAndCases.Add(combo.name, combo); - } + foreach (var loadCase in loadCases) + { + this.loadCombinationsAndCases.Add(loadCase.name, loadCase); + } - foreach (var loadCase in loadCases) - { - this.loadCombinationsAndCases.Add(loadCase.name, loadCase); - } + this.sendForces = sendForces; + this.sendStresses = sendStresses; + } + + public AnalyticalResults AnalyticalResultsToSpeckle(string areaName) + { + return new() { resultsByLoadCombination = GetAnalysisResultsForElement2D(areaName).Cast().ToList() }; + } - this.sendForces = sendForces; - this.sendStresses = sendStresses; + private ICollection GetAnalysisResultsForElement2D(string areaName) + { + int forceSuccess = -1; + int stressSuccess = -1; + + int numberOfForceResults = 0; + string[] obj = Array.Empty(); + string[] elm = Array.Empty(); + string[] pointElm = Array.Empty(); + string[] loadCase = Array.Empty(); + string[] stepType = Array.Empty(); + double[] stepNum = Array.Empty(); + double[] f11 = Array.Empty(); + double[] f22 = Array.Empty(); + double[] f12 = Array.Empty(); + double[] fMax = Array.Empty(); + double[] fMin = Array.Empty(); + double[] fAngle = Array.Empty(); + double[] fVonMises = Array.Empty(); + double[] m11 = Array.Empty(); + double[] m22 = Array.Empty(); + double[] m12 = Array.Empty(); + double[] mMax = Array.Empty(); + double[] mMin = Array.Empty(); + double[] mAngle = Array.Empty(); + double[] v13 = Array.Empty(); + double[] v23 = Array.Empty(); + double[] vMax = Array.Empty(); + double[] vAngle = Array.Empty(); + + if (sendForces) + { + forceSuccess = sapModel.Results.AreaForceShell( + areaName, + CSiAPIv1.eItemTypeElm.ObjectElm, + ref numberOfForceResults, + ref obj, + ref elm, + ref pointElm, + ref loadCase, + ref stepType, + ref stepNum, + ref f11, + ref f22, + ref f12, + ref fMax, + ref fMin, + ref fAngle, + ref fVonMises, + ref m11, + ref m22, + ref m12, + ref mMax, + ref mMin, + ref mAngle, + ref v13, + ref v23, + ref vMax, + ref vAngle + ); } - public AnalyticalResults AnalyticalResultsToSpeckle(string areaName) + int numberOfStressResults = 0; + string[] stressObj = Array.Empty(); + string[] stressElm = Array.Empty(); + string[] stressPointElm = Array.Empty(); + string[] stressLoadCase = Array.Empty(); + string[] stressStepType = Array.Empty(); + double[] stressStepNum = Array.Empty(); + double[] S11Top = Array.Empty(); + double[] S22Top = Array.Empty(); + double[] S12Top = Array.Empty(); + double[] SMaxTop = Array.Empty(); + double[] SMinTop = Array.Empty(); + double[] SAngleTop = Array.Empty(); + double[] sVonMisesTop = Array.Empty(); + double[] S11Bot = Array.Empty(); + double[] S22Bot = Array.Empty(); + double[] S12Bot = Array.Empty(); + double[] SMaxBot = Array.Empty(); + double[] SMinBot = Array.Empty(); + double[] SAngleBot = Array.Empty(); + double[] sVonMisesBot = Array.Empty(); + double[] S13Avg = Array.Empty(); + double[] S23Avg = Array.Empty(); + double[] SMaxAvg = Array.Empty(); + double[] SAngleAvg = Array.Empty(); + + if (sendStresses) { - return new() - { - resultsByLoadCombination = GetAnalysisResultsForElement2D(areaName).Cast().ToList() - }; + stressSuccess = sapModel.Results.AreaStressShell( + areaName, + CSiAPIv1.eItemTypeElm.ObjectElm, + ref numberOfStressResults, + ref stressObj, + ref stressElm, + ref stressPointElm, + ref stressLoadCase, + ref stressStepType, + ref stressStepNum, + ref S11Top, + ref S22Top, + ref S12Top, + ref SMaxTop, + ref SMinTop, + ref SAngleTop, + ref sVonMisesTop, + ref S11Bot, + ref S22Bot, + ref S12Bot, + ref SMaxBot, + ref SMinBot, + ref SAngleBot, + ref sVonMisesBot, + ref S13Avg, + ref S23Avg, + ref SMaxAvg, + ref SAngleAvg + ); } - private ICollection GetAnalysisResultsForElement2D(string areaName) + Dictionary resultSets = new(); + for (int i = 0; i < numberOfForceResults; i++) { - int forceSuccess = -1; - int stressSuccess = -1; - - int numberOfForceResults = 0; - string[] obj = Array.Empty(); - string[] elm = Array.Empty(); - string[] pointElm = Array.Empty(); - string[] loadCase = Array.Empty(); - string[] stepType = Array.Empty(); - double[] stepNum = Array.Empty(); - double[] f11 = Array.Empty(); - double[] f22 = Array.Empty(); - double[] f12 = Array.Empty(); - double[] fMax = Array.Empty(); - double[] fMin = Array.Empty(); - double[] fAngle = Array.Empty(); - double[] fVonMises = Array.Empty(); - double[] m11 = Array.Empty(); - double[] m22 = Array.Empty(); - double[] m12 = Array.Empty(); - double[] mMax = Array.Empty(); - double[] mMin = Array.Empty(); - double[] mAngle = Array.Empty(); - double[] v13 = Array.Empty(); - double[] v23 = Array.Empty(); - double[] vMax = Array.Empty(); - double[] vAngle = Array.Empty(); - - if (sendForces) - { - forceSuccess = sapModel.Results.AreaForceShell( - areaName, - CSiAPIv1.eItemTypeElm.ObjectElm, - ref numberOfForceResults, - ref obj, - ref elm, - ref pointElm, - ref loadCase, - ref stepType, - ref stepNum, - ref f11, - ref f22, - ref f12, - ref fMax, - ref fMin, - ref fAngle, - ref fVonMises, - ref m11, - ref m22, - ref m12, - ref mMax, - ref mMin, - ref mAngle, - ref v13, - ref v23, - ref vMax, - ref vAngle - ); - } + Result2D speckleResult2D = new(); - int numberOfStressResults = 0; - string[] stressObj = Array.Empty(); - string[] stressElm = Array.Empty(); - string[] stressPointElm = Array.Empty(); - string[] stressLoadCase = Array.Empty(); - string[] stressStepType = Array.Empty(); - double[] stressStepNum = Array.Empty(); - double[] S11Top = Array.Empty(); - double[] S22Top = Array.Empty(); - double[] S12Top = Array.Empty(); - double[] SMaxTop = Array.Empty(); - double[] SMinTop = Array.Empty(); - double[] SAngleTop = Array.Empty(); - double[] sVonMisesTop = Array.Empty(); - double[] S11Bot = Array.Empty(); - double[] S22Bot = Array.Empty(); - double[] S12Bot = Array.Empty(); - double[] SMaxBot = Array.Empty(); - double[] SMinBot = Array.Empty(); - double[] SAngleBot = Array.Empty(); - double[] sVonMisesBot = Array.Empty(); - double[] S13Avg = Array.Empty(); - double[] S23Avg = Array.Empty(); - double[] SMaxAvg = Array.Empty(); - double[] SAngleAvg = Array.Empty(); - - if (sendStresses) + if (ApiResultValidator.IsSuccessful(forceSuccess)) { - stressSuccess = sapModel.Results.AreaStressShell( - areaName, - CSiAPIv1.eItemTypeElm.ObjectElm, - ref numberOfStressResults, - ref stressObj, - ref stressElm, - ref stressPointElm, - ref stressLoadCase, - ref stressStepType, - ref stressStepNum, - ref S11Top, - ref S22Top, - ref S12Top, - ref SMaxTop, - ref SMinTop, - ref SAngleTop, - ref sVonMisesTop, - ref S11Bot, - ref S22Bot, - ref S12Bot, - ref SMaxBot, - ref SMinBot, - ref SAngleBot, - ref sVonMisesBot, - ref S13Avg, - ref S23Avg, - ref SMaxAvg, - ref SAngleAvg - ); + speckleResult2D.forceXX = (float)f11[i]; + speckleResult2D.forceYY = (float)f22[i]; + speckleResult2D.forceXY = (float)f12[i]; + speckleResult2D.momentXX = (float)m11[i]; + speckleResult2D.momentYY = (float)m22[i]; + speckleResult2D.momentXY = (float)m12[i]; + speckleResult2D.shearX = (float)v13[i]; + speckleResult2D.shearY = (float)v23[i]; } - Dictionary resultSets = new(); - for (int i = 0; i < numberOfForceResults; i++) + if (ApiResultValidator.IsSuccessful(stressSuccess)) { - Result2D speckleResult2D = new(); - - if (ApiResultValidator.IsSuccessful(forceSuccess)) - { - speckleResult2D.forceXX = (float)f11[i]; - speckleResult2D.forceYY = (float)f22[i]; - speckleResult2D.forceXY = (float)f12[i]; - speckleResult2D.momentXX = (float)m11[i]; - speckleResult2D.momentYY = (float)m22[i]; - speckleResult2D.momentXY = (float)m12[i]; - speckleResult2D.shearX = (float)v13[i]; - speckleResult2D.shearY = (float)v23[i]; - } - - if (ApiResultValidator.IsSuccessful(stressSuccess)) - { - speckleResult2D.stressTopXX = (float)S11Top[i]; - speckleResult2D.stressTopYY = (float)S22Top[i]; - speckleResult2D.stressTopZZ = 0; // shell elements are 2D elements - speckleResult2D.stressTopXY = (float)S12Top[i]; - speckleResult2D.stressTopYZ = (float)S23Avg[i]; // CSI reports avg out-of-plane shear - speckleResult2D.stressTopZX = (float)S12Top[i]; - speckleResult2D.stressBotXX = (float)S11Bot[i]; - speckleResult2D.stressBotYY = (float)S22Bot[i]; - speckleResult2D.stressBotZZ = 0; // shell elements are 2D elements - speckleResult2D.stressBotXY = (float)S12Bot[i]; - speckleResult2D.stressBotYZ = (float)S23Avg[i]; // CSI reports avg out-of-plane shear - speckleResult2D.stressBotZX = (float)S12Bot[i]; - } - GetOrCreateResult(resultSets, loadCase[i]).results2D.Add(speckleResult2D); + speckleResult2D.stressTopXX = (float)S11Top[i]; + speckleResult2D.stressTopYY = (float)S22Top[i]; + speckleResult2D.stressTopZZ = 0; // shell elements are 2D elements + speckleResult2D.stressTopXY = (float)S12Top[i]; + speckleResult2D.stressTopYZ = (float)S23Avg[i]; // CSI reports avg out-of-plane shear + speckleResult2D.stressTopZX = (float)S12Top[i]; + speckleResult2D.stressBotXX = (float)S11Bot[i]; + speckleResult2D.stressBotYY = (float)S22Bot[i]; + speckleResult2D.stressBotZZ = 0; // shell elements are 2D elements + speckleResult2D.stressBotXY = (float)S12Bot[i]; + speckleResult2D.stressBotYZ = (float)S23Avg[i]; // CSI reports avg out-of-plane shear + speckleResult2D.stressBotZX = (float)S12Bot[i]; } - - return resultSets.Values; + GetOrCreateResult(resultSets, loadCase[i]).results2D.Add(speckleResult2D); } - private ResultSet2D GetOrCreateResult(Dictionary dict, string loadCaseName) + return resultSets.Values; + } + + private ResultSet2D GetOrCreateResult(Dictionary dict, string loadCaseName) + { + if (!dict.TryGetValue(loadCaseName, out ResultSet2D comboResults)) { - if (!dict.TryGetValue(loadCaseName, out ResultSet2D comboResults)) - { - Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; - comboResults = new ResultSet2D(new()) - { - resultCase = loadCaseOrCombination - }; - dict[loadCaseName] = comboResults; - } - return comboResults; + Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; + comboResults = new ResultSet2D(new()) { resultCase = loadCaseOrCombination }; + dict[loadCaseName] = comboResults; } + return comboResults; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/NodeAnalyticalResultsConverter.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/NodeAnalyticalResultsConverter.cs index 1c2abbf348..88e5433d8d 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/NodeAnalyticalResultsConverter.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/NodeAnalyticalResultsConverter.cs @@ -6,213 +6,212 @@ using Objects.Structural.Results; using Speckle.Core.Models; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +internal class NodeAnalyticalResultsConverter { - internal class NodeAnalyticalResultsConverter + private readonly cSapModel sapModel; + private readonly Dictionary loadCombinationsAndCases; + private readonly bool sendDisplacements; + private readonly bool sendForces; + private readonly bool sendVelocity; + private readonly bool sendAcceleration; + + public NodeAnalyticalResultsConverter( + cSapModel sapModel, + IEnumerable loadCombinations, + IEnumerable loadCases, + bool sendDisplacements, + bool sendForces, + bool sendVelocity, + bool sendAcceleration + ) { - private readonly cSapModel sapModel; - private readonly Dictionary loadCombinationsAndCases; - private readonly bool sendDisplacements; - private readonly bool sendForces; - private readonly bool sendVelocity; - private readonly bool sendAcceleration; - public NodeAnalyticalResultsConverter( - cSapModel sapModel, - IEnumerable loadCombinations, - IEnumerable loadCases, - bool sendDisplacements, - bool sendForces, - bool sendVelocity, - bool sendAcceleration) + this.sapModel = sapModel; + this.sapModel = sapModel; + + this.loadCombinationsAndCases = new(); + foreach (var combo in loadCombinations) { - this.sapModel = sapModel; - this.sapModel = sapModel; + this.loadCombinationsAndCases.Add(combo.name, combo); + } - this.loadCombinationsAndCases = new(); - foreach (var combo in loadCombinations) - { - this.loadCombinationsAndCases.Add(combo.name, combo); - } + foreach (var loadCase in loadCases) + { + this.loadCombinationsAndCases.Add(loadCase.name, loadCase); + } - foreach (var loadCase in loadCases) - { - this.loadCombinationsAndCases.Add(loadCase.name, loadCase); - } + this.sendDisplacements = sendDisplacements; + this.sendForces = sendForces; + this.sendVelocity = sendVelocity; + this.sendAcceleration = sendAcceleration; + } - this.sendDisplacements = sendDisplacements; - this.sendForces = sendForces; - this.sendVelocity = sendVelocity; - this.sendAcceleration = sendAcceleration; + public AnalyticalResults AnalyticalResultsToSpeckle(string nodeName) + { + return new() { resultsByLoadCombination = GetAnalysisResultsForNode(nodeName).Cast().ToList() }; + } + + private IEnumerable GetAnalysisResultsForNode(string nodeName) + { + int numberResults = 0; + string[] loadCases = null; + + bool displacementSuccess = AnalysisResultUtils.TryGetAPIResult( + sapModel.Results.JointDispl, + nodeName, + out int numberNodeResults, + out _, + out _, + out string[] nodeLoadCases, + out _, + out _, + out double[] U1, + out double[] U2, + out double[] U3, + out double[] R1, + out double[] R2, + out double[] R3, + sendDisplacements + ); + + if (displacementSuccess) + { + numberResults = numberNodeResults; + loadCases = nodeLoadCases; } - public AnalyticalResults AnalyticalResultsToSpeckle(string nodeName) + bool forceSuccess = AnalysisResultUtils.TryGetAPIResult( + sapModel.Results.JointReact, + nodeName, + out int numberForceResults, + out _, + out _, + out string[] forceLoadCases, + out _, + out _, + out double[] F1, + out double[] F2, + out double[] F3, + out double[] M1, + out double[] M2, + out double[] M3, + sendForces + ); + + if (forceSuccess) { - return new() - { - resultsByLoadCombination = GetAnalysisResultsForNode(nodeName).Cast().ToList() - }; + numberResults = numberForceResults; + loadCases = forceLoadCases; } - private IEnumerable GetAnalysisResultsForNode(string nodeName) + bool velocitySuccess = AnalysisResultUtils.TryGetAPIResult( + sapModel.Results.JointVelAbs, + nodeName, + out int numberVelocityResults, + out _, + out _, + out string[] velocityLoadCases, + out _, + out _, + out double[] U1Vel, + out double[] U2Vel, + out double[] U3Vel, + out double[] R1Vel, + out double[] R2Vel, + out double[] R3Vel, + sendVelocity + ); + + if (velocitySuccess) { - int numberResults = 0; - string[] loadCases = null; - - bool displacementSuccess = AnalysisResultUtils.TryGetAPIResult( - sapModel.Results.JointDispl, - nodeName, - out int numberNodeResults, - out _, - out _, - out string[] nodeLoadCases, - out _, - out _, - out double[] U1, - out double[] U2, - out double[] U3, - out double[] R1, - out double[] R2, - out double[] R3, - sendDisplacements); + numberResults = numberVelocityResults; + loadCases = velocityLoadCases; + } - if (displacementSuccess) - { - numberResults = numberNodeResults; - loadCases = nodeLoadCases; - } + bool accelerationSuccess = AnalysisResultUtils.TryGetAPIResult( + sapModel.Results.JointAccAbs, + nodeName, + out int numberAccelerationResults, + out _, + out _, + out string[] accelerationLoadCases, + out _, + out _, + out double[] U1Acc, + out double[] U2Acc, + out double[] U3Acc, + out double[] R1Acc, + out double[] R2Acc, + out double[] R3Acc, + sendAcceleration + ); + + if (accelerationSuccess) + { + numberResults = numberAccelerationResults; + loadCases = accelerationLoadCases; + } - bool forceSuccess = AnalysisResultUtils.TryGetAPIResult( - sapModel.Results.JointReact, - nodeName, - out int numberForceResults, - out _, - out _, - out string[] forceLoadCases, - out _, - out _, - out double[] F1, - out double[] F2, - out double[] F3, - out double[] M1, - out double[] M2, - out double[] M3, - sendForces); + Dictionary resultSets = new(); + for (int index = 0; index < numberResults; index++) + { + ResultNode speckleResultNode = new(); if (forceSuccess) { - numberResults = numberForceResults; - loadCases = forceLoadCases; + speckleResultNode.reactionX = (float)F1[index]; + speckleResultNode.reactionY = (float)F2[index]; + speckleResultNode.reactionZ = (float)F3[index]; + speckleResultNode.reactionXX = (float)M1[index]; + speckleResultNode.reactionYY = (float)M2[index]; + speckleResultNode.reactionZZ = (float)M3[index]; } - bool velocitySuccess = AnalysisResultUtils.TryGetAPIResult( - sapModel.Results.JointVelAbs, - nodeName, - out int numberVelocityResults, - out _, - out _, - out string[] velocityLoadCases, - out _, - out _, - out double[] U1Vel, - out double[] U2Vel, - out double[] U3Vel, - out double[] R1Vel, - out double[] R2Vel, - out double[] R3Vel, - sendVelocity); - - if (velocitySuccess) + if (displacementSuccess) { - numberResults = numberVelocityResults; - loadCases = velocityLoadCases; + speckleResultNode.dispX = (float)U1[index]; + speckleResultNode.dispY = (float)U2[index]; + speckleResultNode.dispZ = (float)U3[index]; + speckleResultNode.rotXX = (float)R1[index]; + speckleResultNode.rotYY = (float)R2[index]; + speckleResultNode.rotZZ = (float)R3[index]; } - bool accelerationSuccess = AnalysisResultUtils.TryGetAPIResult( - sapModel.Results.JointAccAbs, - nodeName, - out int numberAccelerationResults, - out _, - out _, - out string[] accelerationLoadCases, - out _, - out _, - out double[] U1Acc, - out double[] U2Acc, - out double[] U3Acc, - out double[] R1Acc, - out double[] R2Acc, - out double[] R3Acc, - sendAcceleration); - - if (accelerationSuccess) + if (velocitySuccess) { - numberResults = numberAccelerationResults; - loadCases = accelerationLoadCases; + speckleResultNode.velX = (float)U1Vel[index]; + speckleResultNode.velY = (float)U2Vel[index]; + speckleResultNode.velZ = (float)U3Vel[index]; + speckleResultNode.velXX = (float)R1Vel[index]; + speckleResultNode.velYY = (float)R2Vel[index]; + speckleResultNode.velZZ = (float)R3Vel[index]; } - Dictionary resultSets = new(); - for (int index = 0; index < numberResults; index++) + if (accelerationSuccess) { - ResultNode speckleResultNode = new(); - - if (forceSuccess) - { - speckleResultNode.reactionX = (float)F1[index]; - speckleResultNode.reactionY = (float)F2[index]; - speckleResultNode.reactionZ = (float)F3[index]; - speckleResultNode.reactionXX = (float)M1[index]; - speckleResultNode.reactionYY = (float)M2[index]; - speckleResultNode.reactionZZ = (float)M3[index]; - } - - if (displacementSuccess) - { - speckleResultNode.dispX = (float)U1[index]; - speckleResultNode.dispY = (float)U2[index]; - speckleResultNode.dispZ = (float)U3[index]; - speckleResultNode.rotXX = (float)R1[index]; - speckleResultNode.rotYY = (float)R2[index]; - speckleResultNode.rotZZ = (float)R3[index]; - } - - if (velocitySuccess) - { - speckleResultNode.velX = (float)U1Vel[index]; - speckleResultNode.velY = (float)U2Vel[index]; - speckleResultNode.velZ = (float)U3Vel[index]; - speckleResultNode.velXX = (float)R1Vel[index]; - speckleResultNode.velYY = (float)R2Vel[index]; - speckleResultNode.velZZ = (float)R3Vel[index]; - } - - if (accelerationSuccess) - { - speckleResultNode.accX = (float)U1Acc[index]; - speckleResultNode.accY = (float)U2Acc[index]; - speckleResultNode.accZ = (float)U3Acc[index]; - speckleResultNode.accXX = (float)R1Acc[index]; - speckleResultNode.accYY = (float)R2Acc[index]; - speckleResultNode.accZZ = (float)R3Acc[index]; - } - - GetOrCreateResult(resultSets, loadCases[index]).resultsNode.Add(speckleResultNode); + speckleResultNode.accX = (float)U1Acc[index]; + speckleResultNode.accY = (float)U2Acc[index]; + speckleResultNode.accZ = (float)U3Acc[index]; + speckleResultNode.accXX = (float)R1Acc[index]; + speckleResultNode.accYY = (float)R2Acc[index]; + speckleResultNode.accZZ = (float)R3Acc[index]; } - return resultSets.Values; + GetOrCreateResult(resultSets, loadCases[index]).resultsNode.Add(speckleResultNode); } - private ResultSetNode GetOrCreateResult(Dictionary dict, string loadCaseName) + return resultSets.Values; + } + + private ResultSetNode GetOrCreateResult(Dictionary dict, string loadCaseName) + { + if (!dict.TryGetValue(loadCaseName, out ResultSetNode comboResults)) { - if (!dict.TryGetValue(loadCaseName, out ResultSetNode comboResults)) - { - Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; - comboResults = new ResultSetNode(new()) - { - resultCase = loadCaseOrCombination - }; - dict[loadCaseName] = comboResults; - } - return comboResults; + Base loadCaseOrCombination = loadCombinationsAndCases[loadCaseName]; + comboResults = new ResultSetNode(new()) { resultCase = loadCaseOrCombination }; + dict[loadCaseName] = comboResults; } + return comboResults; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ResultsConverter.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ResultsConverter.cs index fbe890de38..3f89d21323 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ResultsConverter.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Models/ResultsConverter.cs @@ -5,200 +5,211 @@ using CSiAPIv1; using Objects.Structural.Loading; -namespace ConverterCSIShared.Models +namespace ConverterCSIShared.Models; + +internal sealed class ResultsConverter { - internal sealed class ResultsConverter + public ResultsConverter( + cSapModel sapModel, + Dictionary settings, + IEnumerable loadCases, + IEnumerable loadCombinations + ) { - public ResultsConverter( - cSapModel sapModel, - Dictionary settings, - IEnumerable loadCases, - IEnumerable loadCombinations - ) - { - SetLoadCombinationsForResults(sapModel, settings); + SetLoadCombinationsForResults(sapModel, settings); - DefineNodeResultsConverter(sapModel, settings, loadCases, loadCombinations); - DefineElement1DResultsConverter(sapModel, settings, loadCases, loadCombinations); - DefineElement2DResultsConverter(sapModel, settings, loadCases, loadCombinations); - } + DefineNodeResultsConverter(sapModel, settings, loadCases, loadCombinations); + DefineElement1DResultsConverter(sapModel, settings, loadCases, loadCombinations); + DefineElement2DResultsConverter(sapModel, settings, loadCases, loadCombinations); + } - public NodeAnalyticalResultsConverter? NodeAnalyticalResultsConverter { get; private set; } - public Element1DAnalyticalResultConverter? Element1DAnalyticalResultConverter { get; private set; } - public Element2DAnalyticalResultConverter? Element2DAnalyticalResultConverter { get; private set; } + public NodeAnalyticalResultsConverter? NodeAnalyticalResultsConverter { get; private set; } + public Element1DAnalyticalResultConverter? Element1DAnalyticalResultConverter { get; private set; } + public Element2DAnalyticalResultConverter? Element2DAnalyticalResultConverter { get; private set; } - private void DefineElement2DResultsConverter(cSapModel sapModel, Dictionary settings, IEnumerable loadCases, IEnumerable loadCombinations) + private void DefineElement2DResultsConverter( + cSapModel sapModel, + Dictionary settings, + IEnumerable loadCases, + IEnumerable loadCombinations + ) + { + if ( + settings.TryGetValue(Constants.RESULTS_2D_SLUG, out var selection2D) + && !string.IsNullOrEmpty(selection2D) + && selection2D.Split(',') is string[] results2DToSend + ) { - if (settings.TryGetValue(Constants.RESULTS_2D_SLUG, out var selection2D) - && !string.IsNullOrEmpty(selection2D) - && selection2D.Split(',') is string[] results2DToSend) - { - Element2DAnalyticalResultConverter = new( - sapModel, - loadCombinations, - loadCases, - results2DToSend.Contains(Constants.FORCES), - results2DToSend.Contains(Constants.STRESSES)); - } - else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_2D_RESULTS)) - { - Element2DAnalyticalResultConverter = new( - sapModel, - loadCombinations, - loadCases, - true, - true); - } + Element2DAnalyticalResultConverter = new( + sapModel, + loadCombinations, + loadCases, + results2DToSend.Contains(Constants.FORCES), + results2DToSend.Contains(Constants.STRESSES) + ); + } + else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_2D_RESULTS)) + { + Element2DAnalyticalResultConverter = new(sapModel, loadCombinations, loadCases, true, true); } + } - private void DefineElement1DResultsConverter(cSapModel sapModel, Dictionary settings, IEnumerable loadCases, IEnumerable loadCombinations) + private void DefineElement1DResultsConverter( + cSapModel sapModel, + Dictionary settings, + IEnumerable loadCases, + IEnumerable loadCombinations + ) + { + if ( + settings.TryGetValue(Constants.RESULTS_1D_SLUG, out var selection1D) + && !string.IsNullOrEmpty(selection1D) + && selection1D.Split(new string[] { ", " }, StringSplitOptions.None) is string[] results1DToSend + ) { - if (settings.TryGetValue(Constants.RESULTS_1D_SLUG, out var selection1D) - && !string.IsNullOrEmpty(selection1D) - && selection1D.Split(new string[] { ", " }, StringSplitOptions.None) is string[] results1DToSend) - { - Element1DAnalyticalResultConverter = new( - sapModel, - new HashSet(GetFrameNames(sapModel)), - new HashSet(GetPierNames(sapModel)), - new HashSet(GetSpandrelNames(sapModel)), - loadCombinations, - loadCases, - results1DToSend.Contains(Constants.BEAM_FORCES), - results1DToSend.Contains(Constants.BRACE_FORCES), - results1DToSend.Contains(Constants.COLUMN_FORCES), - results1DToSend.Contains(Constants.OTHER_FORCES)); - } - else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_1D_RESULTS)) - { - Element1DAnalyticalResultConverter = new( - sapModel, - new HashSet(GetFrameNames(sapModel)), - new HashSet(GetPierNames(sapModel)), - new HashSet(GetSpandrelNames(sapModel)), - loadCombinations, - loadCases, - true, - true, - true, - true); - } + Element1DAnalyticalResultConverter = new( + sapModel, + new HashSet(GetFrameNames(sapModel)), + new HashSet(GetPierNames(sapModel)), + new HashSet(GetSpandrelNames(sapModel)), + loadCombinations, + loadCases, + results1DToSend.Contains(Constants.BEAM_FORCES), + results1DToSend.Contains(Constants.BRACE_FORCES), + results1DToSend.Contains(Constants.COLUMN_FORCES), + results1DToSend.Contains(Constants.OTHER_FORCES) + ); } + else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_1D_RESULTS)) + { + Element1DAnalyticalResultConverter = new( + sapModel, + new HashSet(GetFrameNames(sapModel)), + new HashSet(GetPierNames(sapModel)), + new HashSet(GetSpandrelNames(sapModel)), + loadCombinations, + loadCases, + true, + true, + true, + true + ); + } + } - private void DefineNodeResultsConverter(cSapModel sapModel, Dictionary settings, IEnumerable loadCases, IEnumerable loadCombinations) + private void DefineNodeResultsConverter( + cSapModel sapModel, + Dictionary settings, + IEnumerable loadCases, + IEnumerable loadCombinations + ) + { + if ( + settings.TryGetValue(Constants.RESULTS_NODE_SLUG, out var selection) + && !string.IsNullOrEmpty(selection) + && selection.Split(',') is string[] resultsToSend + ) { - if (settings.TryGetValue(Constants.RESULTS_NODE_SLUG, out var selection) - && !string.IsNullOrEmpty(selection) - && selection.Split(',') is string[] resultsToSend) - { - NodeAnalyticalResultsConverter = new( - sapModel, - loadCombinations, - loadCases, - resultsToSend.Contains(Constants.DISPLACEMENTS), - resultsToSend.Contains(Constants.FORCES), - resultsToSend.Contains(Constants.VELOCITIES), - resultsToSend.Contains(Constants.ACCELERATIONS)); - } - else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_NODE_RESULTS)) - { - NodeAnalyticalResultsConverter = new( - sapModel, - loadCombinations, - loadCases, - true, - true, - true, - true); - } + NodeAnalyticalResultsConverter = new( + sapModel, + loadCombinations, + loadCases, + resultsToSend.Contains(Constants.DISPLACEMENTS), + resultsToSend.Contains(Constants.FORCES), + resultsToSend.Contains(Constants.VELOCITIES), + resultsToSend.Contains(Constants.ACCELERATIONS) + ); } + else if (GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_NODE_RESULTS)) + { + NodeAnalyticalResultsConverter = new(sapModel, loadCombinations, loadCases, true, true, true, true); + } + } - public static void SetLoadCombinationsForResults(cSapModel sapModel, Dictionary settings) + public static void SetLoadCombinationsForResults(cSapModel sapModel, Dictionary settings) + { + // because we switched the settings for allowing users to send results, + // some users may still have stream cards with saved data from the old settings + bool shouldSendAllLoadCases = ShouldSendResultsBasedOnLegacySettings(settings); + + sapModel.Results.Setup.DeselectAllCasesAndCombosForOutput(); + if ( + !settings.TryGetValue(Constants.RESULTS_LOAD_CASES_SLUG, out string loadCasesCommaSeparated) + || string.IsNullOrEmpty(loadCasesCommaSeparated) + ) { - // because we switched the settings for allowing users to send results, - // some users may still have stream cards with saved data from the old settings - bool shouldSendAllLoadCases = ShouldSendResultsBasedOnLegacySettings(settings); - - sapModel.Results.Setup.DeselectAllCasesAndCombosForOutput(); - if (!settings.TryGetValue(Constants.RESULTS_LOAD_CASES_SLUG, out string loadCasesCommaSeparated) - || string.IsNullOrEmpty(loadCasesCommaSeparated)) - { - // if not checking for legacy settings then we could just exit here - // return - loadCasesCommaSeparated = string.Empty; - } + // if not checking for legacy settings then we could just exit here + // return + loadCasesCommaSeparated = string.Empty; + } - string[] loadCases = loadCasesCommaSeparated.Split(','); + string[] loadCases = loadCasesCommaSeparated.Split(','); - var numberOfLoadCombinations = 0; - var loadCombinationNames = Array.Empty(); + var numberOfLoadCombinations = 0; + var loadCombinationNames = Array.Empty(); - sapModel.RespCombo.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); - foreach (var loadCombination in loadCombinationNames) + sapModel.RespCombo.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); + foreach (var loadCombination in loadCombinationNames) + { + if (loadCases.Contains(loadCombination) || shouldSendAllLoadCases) { - if (loadCases.Contains(loadCombination) || shouldSendAllLoadCases) - { - sapModel.Results.Setup.SetComboSelectedForOutput(loadCombination); - } + sapModel.Results.Setup.SetComboSelectedForOutput(loadCombination); } + } - sapModel.LoadCases.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); - foreach (var loadCase in loadCombinationNames) + sapModel.LoadCases.GetNameList(ref numberOfLoadCombinations, ref loadCombinationNames); + foreach (var loadCase in loadCombinationNames) + { + if (loadCases.Contains(loadCase) || shouldSendAllLoadCases) { - if (loadCases.Contains(loadCase) || shouldSendAllLoadCases) - { - sapModel.Results.Setup.SetCaseSelectedForOutput(loadCase); - } + sapModel.Results.Setup.SetCaseSelectedForOutput(loadCase); } } + } - private static bool ShouldSendResultsBasedOnLegacySettings(Dictionary settings) - { - bool legacySendNodes = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_NODE_RESULTS); - bool legacySendElement1D = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_1D_RESULTS); - bool legacySendElement2D = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_2D_RESULTS); + private static bool ShouldSendResultsBasedOnLegacySettings(Dictionary settings) + { + bool legacySendNodes = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_NODE_RESULTS); + bool legacySendElement1D = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_1D_RESULTS); + bool legacySendElement2D = GetLegacyBoolSettingOrFalse(settings, Constants.LEGACY_SEND_2D_RESULTS); - return legacySendNodes || legacySendElement1D || legacySendElement2D; - } + return legacySendNodes || legacySendElement1D || legacySendElement2D; + } - private static bool GetLegacyBoolSettingOrFalse( - Dictionary settings, - string slug) + private static bool GetLegacyBoolSettingOrFalse(Dictionary settings, string slug) + { + if (settings.TryGetValue(slug, out string stringValue) && bool.TryParse(stringValue, out bool value)) { - if (settings.TryGetValue(slug, out string stringValue) - && bool.TryParse(stringValue, out bool value)) - { - return value; - } - return false; + return value; } + return false; + } - private static string[] GetFrameNames(cSapModel sapModel) - { - int numberOfFrameNames = 0; - var frameNames = Array.Empty(); + private static string[] GetFrameNames(cSapModel sapModel) + { + int numberOfFrameNames = 0; + var frameNames = Array.Empty(); - sapModel.FrameObj.GetNameList(ref numberOfFrameNames, ref frameNames); - return frameNames; - } + sapModel.FrameObj.GetNameList(ref numberOfFrameNames, ref frameNames); + return frameNames; + } - private static string[] GetPierNames(cSapModel sapModel) - { - int numberOfNames = 0; - var pierNames = Array.Empty(); + private static string[] GetPierNames(cSapModel sapModel) + { + int numberOfNames = 0; + var pierNames = Array.Empty(); - sapModel.PierLabel.GetNameList(ref numberOfNames, ref pierNames); - return pierNames; - } + sapModel.PierLabel.GetNameList(ref numberOfNames, ref pierNames); + return pierNames; + } - private static string[] GetSpandrelNames(cSapModel sapModel) - { - int numberOfSpandrelNames = 0; - var spandrelNames = Array.Empty(); - var isMultiStory = Array.Empty(); + private static string[] GetSpandrelNames(cSapModel sapModel) + { + int numberOfSpandrelNames = 0; + var spandrelNames = Array.Empty(); + var isMultiStory = Array.Empty(); - sapModel.SpandrelLabel.GetNameList(ref numberOfSpandrelNames, ref spandrelNames, ref isMultiStory); - return spandrelNames; - } + sapModel.SpandrelLabel.GetNameList(ref numberOfSpandrelNames, ref spandrelNames, ref isMultiStory); + return spandrelNames; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModel.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModel.cs index d6f9516da7..5179a1f7a6 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModel.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Objects.Structural.Analysis; using Objects.Geometry; @@ -16,129 +16,128 @@ using System.Linq; using CSiAPIv1; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public object ModelToNative(Model model, ref ApplicationObject appObj) { - public object ModelToNative(Model model, ref ApplicationObject appObj) - { - return null; - } + return null; + } - Base ModelElementsCountToSpeckle() - { - var ElementsCount = new Base(); - int count = SpeckleModel.elements.Count(); - count += SpeckleModel.nodes.Count(); - ElementsCount.applicationId = count.ToString(); - return ElementsCount; - } + Base ModelElementsCountToSpeckle() + { + var ElementsCount = new Base(); + int count = SpeckleModel.elements.Count(); + count += SpeckleModel.nodes.Count(); + ElementsCount.applicationId = count.ToString(); + return ElementsCount; + } - public Model ModelToSpeckle() - { - var model = new Model(); - model.specs = ModelInfoToSpeckle(); - model.nodes = new List { }; - model.materials = new List { }; - model.elements = new List { }; - model.properties = new List { }; - model.restraints = new List { }; - model.loads = new List { }; - int number = 0; - string[] properties1D = { }; + public Model ModelToSpeckle() + { + var model = new Model(); + model.specs = ModelInfoToSpeckle(); + model.nodes = new List { }; + model.materials = new List { }; + model.elements = new List { }; + model.properties = new List { }; + model.restraints = new List { }; + model.loads = new List { }; + int number = 0; + string[] properties1D = { }; - //var stories = StoriesToSpeckle(); - ////Should stories belong here ? not sure - //model.elements.Add(stories); + //var stories = StoriesToSpeckle(); + ////Should stories belong here ? not sure + //model.elements.Add(stories); - //Properties are sent by default whether you want them to be sent or not. Easier this way to manage information about the model - Model.PropFrame.GetNameList(ref number, ref properties1D); - properties1D.ToList(); - foreach (string property1D in properties1D) - { - var speckleProperty1D = Property1DToSpeckle(property1D); - model.properties.Add(speckleProperty1D); - } + //Properties are sent by default whether you want them to be sent or not. Easier this way to manage information about the model + Model.PropFrame.GetNameList(ref number, ref properties1D); + properties1D.ToList(); + foreach (string property1D in properties1D) + { + var speckleProperty1D = Property1DToSpeckle(property1D); + model.properties.Add(speckleProperty1D); + } - string[] springPointProperties = { }; - Model.PropPointSpring.GetNameList(ref number, ref springPointProperties); - springPointProperties.ToList(); - foreach (string propertySpring in springPointProperties) - { - var specklePropertyPointSpring = SpringPropertyToSpeckle(propertySpring); - model.properties.Add(specklePropertyPointSpring); - } + string[] springPointProperties = { }; + Model.PropPointSpring.GetNameList(ref number, ref springPointProperties); + springPointProperties.ToList(); + foreach (string propertySpring in springPointProperties) + { + var specklePropertyPointSpring = SpringPropertyToSpeckle(propertySpring); + model.properties.Add(specklePropertyPointSpring); + } - string[] springLineProperties = { }; - Model.PropLineSpring.GetNameList(ref number, ref springLineProperties); - springLineProperties.ToList(); - foreach (string propertyLine in springLineProperties) - { - var specklePropertyLineSpring = LinearSpringToSpeckle(propertyLine); - model.properties.Add(specklePropertyLineSpring); - } + string[] springLineProperties = { }; + Model.PropLineSpring.GetNameList(ref number, ref springLineProperties); + springLineProperties.ToList(); + foreach (string propertyLine in springLineProperties) + { + var specklePropertyLineSpring = LinearSpringToSpeckle(propertyLine); + model.properties.Add(specklePropertyLineSpring); + } - string[] springAreaProperties = { }; - Model.PropAreaSpring.GetNameList(ref number, ref springAreaProperties); - springAreaProperties.ToList(); - foreach (string propertyArea in springAreaProperties) - { - var specklePropertyAreaSpring = AreaSpringToSpeckle(propertyArea); - model.properties.Add(specklePropertyAreaSpring); - } - string[] LinkProperties = { }; - Model.PropLink.GetNameList(ref number, ref LinkProperties); - LinkProperties.ToList(); - foreach (string propertyLink in LinkProperties) - { - var specklePropertyLink = LinkPropertyToSpeckle(propertyLink); - model.properties.Add(specklePropertyLink); - } + string[] springAreaProperties = { }; + Model.PropAreaSpring.GetNameList(ref number, ref springAreaProperties); + springAreaProperties.ToList(); + foreach (string propertyArea in springAreaProperties) + { + var specklePropertyAreaSpring = AreaSpringToSpeckle(propertyArea); + model.properties.Add(specklePropertyAreaSpring); + } + string[] LinkProperties = { }; + Model.PropLink.GetNameList(ref number, ref LinkProperties); + LinkProperties.ToList(); + foreach (string propertyLink in LinkProperties) + { + var specklePropertyLink = LinkPropertyToSpeckle(propertyLink); + model.properties.Add(specklePropertyLink); + } - string[] TendonProperties = { }; - Model.PropTendon.GetNameList(ref number, ref TendonProperties); - TendonProperties.ToList(); - foreach (string propertyTendon in TendonProperties) - { - var specklePropertyTendon = TendonPropToSpeckle(propertyTendon); - model.properties.Add(specklePropertyTendon); - } + string[] TendonProperties = { }; + Model.PropTendon.GetNameList(ref number, ref TendonProperties); + TendonProperties.ToList(); + foreach (string propertyTendon in TendonProperties) + { + var specklePropertyTendon = TendonPropToSpeckle(propertyTendon); + model.properties.Add(specklePropertyTendon); + } - string[] DiaphragmProperties = { }; - Model.Diaphragm.GetNameList(ref number, ref DiaphragmProperties); - DiaphragmProperties.ToList(); - foreach (string propertyDiaphragm in DiaphragmProperties) - { - var specklePropertyDiaphragm = diaphragmToSpeckle(propertyDiaphragm); - model.properties.Add(specklePropertyDiaphragm); - } + string[] DiaphragmProperties = { }; + Model.Diaphragm.GetNameList(ref number, ref DiaphragmProperties); + DiaphragmProperties.ToList(); + foreach (string propertyDiaphragm in DiaphragmProperties) + { + var specklePropertyDiaphragm = diaphragmToSpeckle(propertyDiaphragm); + model.properties.Add(specklePropertyDiaphragm); + } - string[] properties2D = { }; - Model.PropArea.GetNameList(ref number, ref properties2D); - properties2D.ToList(); - foreach (string property in properties2D) + string[] properties2D = { }; + Model.PropArea.GetNameList(ref number, ref properties2D); + properties2D.ToList(); + foreach (string property in properties2D) + { + var speckleProperty2D = FloorPropertyToSpeckle(property); + if (speckleProperty2D != null) { - var speckleProperty2D = FloorPropertyToSpeckle(property); - if (speckleProperty2D != null) - { - model.properties.Add(speckleProperty2D); - } - else - { - model.properties.Add(WallPropertyToSpeckle(property)); - } + model.properties.Add(speckleProperty2D); } - - string[] materials = { }; - Model.PropMaterial.GetNameList(ref number, ref materials); - foreach (string material in materials) + else { - var speckleMaterial = MaterialToSpeckle(material); - model.materials.Add(speckleMaterial); + model.properties.Add(WallPropertyToSpeckle(property)); } + } - return model; + string[] materials = { }; + Model.PropMaterial.GetNameList(ref number, ref materials); + foreach (string material in materials) + { + var speckleMaterial = MaterialToSpeckle(material); + model.materials.Add(speckleMaterial); } + + return model; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelInfo.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelInfo.cs index 7a94c83b4a..1065edd2b9 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelInfo.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelInfo.cs @@ -1,68 +1,67 @@ -using System; +using System; using System.Collections.Generic; using Objects.Geometry; using Objects.Structural.Geometry; using Objects.Structural.Analysis; using CSiAPIv1; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void ModelInfoToNative(ModelInfo modelInfo) { - public void ModelInfoToNative(ModelInfo modelInfo) + Model.SetProjectInfo("Engineer", modelInfo.initials); + Model.SetProjectInfo("Model Description", modelInfo.description); + Model.SetProjectInfo("Project Number", modelInfo.projectNumber); + Model.SetProjectInfo("Project Name", modelInfo.projectName); + if (modelInfo.settings != null) { - Model.SetProjectInfo("Engineer", modelInfo.initials); - Model.SetProjectInfo("Model Description", modelInfo.description); - Model.SetProjectInfo("Project Number", modelInfo.projectNumber); - Model.SetProjectInfo("Project Name", modelInfo.projectName); - if (modelInfo.settings != null) - { - modelSettingsToNative(modelInfo.settings); - } - - return; + modelSettingsToNative(modelInfo.settings); } - public ModelInfo ModelInfoToSpeckle() + return; + } + + public ModelInfo ModelInfoToSpeckle() + { + var modelInfo = new ModelInfo(); + modelInfo.name = Model.GetModelFilename(false); + string programName, + programVersion, + programLevel; + programVersion = programName = programLevel = null; + Model.GetProgramInfo(ref programName, ref programVersion, ref programLevel); + modelInfo.application = programName; + modelInfo.settings = modelSettingsToSpeckle(); + int numberItems = 0; + string[] items, + data; + items = data = null; + Model.GetProjectInfo(ref numberItems, ref items, ref data); + if (numberItems != 0) { - var modelInfo = new ModelInfo(); - modelInfo.name = Model.GetModelFilename(false); - string programName, - programVersion, - programLevel; - programVersion = programName = programLevel = null; - Model.GetProgramInfo(ref programName, ref programVersion, ref programLevel); - modelInfo.application = programName; - modelInfo.settings = modelSettingsToSpeckle(); - int numberItems = 0; - string[] items, - data; - items = data = null; - Model.GetProjectInfo(ref numberItems, ref items, ref data); - if (numberItems != 0) + for (int index = 0; index < numberItems; index++) { - for (int index = 0; index < numberItems; index++) + switch (items[index]) { - switch (items[index]) - { - default: - break; - case "Engineer": - modelInfo.initials = data[index]; - break; - case "Model Description": - modelInfo.description = data[index]; - break; - case "Project Name": - modelInfo.projectName = data[index]; - break; - case "Project Number": - modelInfo.projectNumber = data[index]; - break; - } + default: + break; + case "Engineer": + modelInfo.initials = data[index]; + break; + case "Model Description": + modelInfo.description = data[index]; + break; + case "Project Name": + modelInfo.projectName = data[index]; + break; + case "Project Number": + modelInfo.projectNumber = data[index]; + break; } } - return modelInfo; } + return modelInfo; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelSettings.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelSettings.cs index 77295af625..1bbda6dd72 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelSettings.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelSettings.cs @@ -1,33 +1,32 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using Objects.Structural.Analysis; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void modelSettingsToNative(ModelSettings modelSettings) { - public void modelSettingsToNative(ModelSettings modelSettings) + Model.DesignConcrete.SetCode(modelSettings.concreteCode); + Model.DesignSteel.SetCode(modelSettings.steelCode); + if (modelSettings.modelUnits != null) { - Model.DesignConcrete.SetCode(modelSettings.concreteCode); - Model.DesignSteel.SetCode(modelSettings.steelCode); - if (modelSettings.modelUnits != null) - { - UnitsToNative(modelSettings.modelUnits); - } + UnitsToNative(modelSettings.modelUnits); } + } - public ModelSettings modelSettingsToSpeckle() - { - var speckleModelSettings = new ModelSettings(); - speckleModelSettings.modelUnits = UnitsToSpeckle(); - string concreteCode = ""; - Model.DesignConcrete.GetCode(ref concreteCode); - speckleModelSettings.concreteCode = concreteCode; - string steelCode = ""; - Model.DesignSteel.GetCode(ref steelCode); - speckleModelSettings.steelCode = steelCode; - return speckleModelSettings; - } + public ModelSettings modelSettingsToSpeckle() + { + var speckleModelSettings = new ModelSettings(); + speckleModelSettings.modelUnits = UnitsToSpeckle(); + string concreteCode = ""; + Model.DesignConcrete.GetCode(ref concreteCode); + speckleModelSettings.concreteCode = concreteCode; + string steelCode = ""; + Model.DesignSteel.GetCode(ref steelCode); + speckleModelSettings.steelCode = steelCode; + return speckleModelSettings; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelUnits.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelUnits.cs index a2698f8ee5..b1ef3da5c1 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelUnits.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Analysis/ConvertModelUnits.cs @@ -5,57 +5,56 @@ using Objects.Structural.Analysis; using CSiAPIv1; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void UnitsToNative(ModelUnits units) { - public void UnitsToNative(ModelUnits units) + eForce force = units.force switch { - eForce force = units.force switch - { - "N" => eForce.N, - "kip" => eForce.kip, - "kN" => eForce.kN, - "lb" => eForce.lb, - "tf" => eForce.tonf, - _ => eForce.NotApplicable - }; + "N" => eForce.N, + "kip" => eForce.kip, + "kN" => eForce.kN, + "lb" => eForce.lb, + "tf" => eForce.tonf, + _ => eForce.NotApplicable + }; - eLength length = units.length switch - { - "m" => eLength.m, - "in" => eLength.inch, - "cm" => eLength.cm, - "mm" => eLength.mm, - "ft" => eLength.ft, - _ => eLength.NotApplicable - }; + eLength length = units.length switch + { + "m" => eLength.m, + "in" => eLength.inch, + "cm" => eLength.cm, + "mm" => eLength.mm, + "ft" => eLength.ft, + _ => eLength.NotApplicable + }; - eTemperature temp = units.temperature switch - { - "C" => eTemperature.C, - "F" => eTemperature.F, - _ => eTemperature.NotApplicable - }; - Model.SetPresentUnits_2(force, length, temp); - } + eTemperature temp = units.temperature switch + { + "C" => eTemperature.C, + "F" => eTemperature.F, + _ => eTemperature.NotApplicable + }; + Model.SetPresentUnits_2(force, length, temp); + } - public ModelUnits UnitsToSpeckle() + public ModelUnits UnitsToSpeckle() + { + var modelUnits = new ModelUnits(); + var units = Model.GetDatabaseUnits(); + if (units != 0) + { + string[] unitsCat = units.ToString().Split('_'); + modelUnits.temperature = unitsCat[2]; + modelUnits.length = unitsCat[1]; + modelUnits.force = unitsCat[0]; + } + else { - var modelUnits = new ModelUnits(); - var units = Model.GetDatabaseUnits(); - if (units != 0) - { - string[] unitsCat = units.ToString().Split('_'); - modelUnits.temperature = unitsCat[2]; - modelUnits.length = unitsCat[1]; - modelUnits.force = unitsCat[0]; - } - else - { - //TO DO: custom units - } - return modelUnits; + //TO DO: custom units } + return modelUnits; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertArea.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertArea.cs index 245882395b..ffab03b0f5 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertArea.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertArea.cs @@ -12,452 +12,477 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public object updateExistingArea(Element2D area) { - public object updateExistingArea(Element2D area) + string GUID = ""; + Model.AreaObj.GetGUID(area.name, ref GUID); + if (area.applicationId == GUID) { - string GUID = ""; - Model.AreaObj.GetGUID(area.name, ref GUID); - if (area.applicationId == GUID) - { - SetAreaProperties(area.name, area); - } - return area.name; + SetAreaProperties(area.name, area); } + return area.name; + } - public void UpdateArea(Element2D area, string name, ApplicationObject appObj) + public void UpdateArea(Element2D area, string name, ApplicationObject appObj) + { + var numPoints = 0; + var points = Array.Empty(); + int success = Model.AreaObj.GetPoints(name, ref numPoints, ref points); + if (success != 0) { - var numPoints = 0; - var points = Array.Empty(); - int success = Model.AreaObj.GetPoints(name, ref numPoints, ref points); - if (success != 0) - throw new ConversionException($"Failed to retrieve the names of the point object that define area: {name}"); + throw new ConversionException($"Failed to retrieve the names of the point object that define area: {name}"); + } - bool connectivityChanged = points.Length != area.topology.Count; + bool connectivityChanged = points.Length != area.topology.Count; - var pointsUpdated = new List(); - for (int i = 0; i < area.topology.Count; i++) + var pointsUpdated = new List(); + for (int i = 0; i < area.topology.Count; i++) + { + if (i >= points.Length) { - if (i >= points.Length) - { - CreatePoint(area.topology[i].basePoint, out string pointName); - pointsUpdated.Add(pointName); - continue; - } - - pointsUpdated.Add(UpdatePoint(points[i], area.topology[i])); - if (!connectivityChanged && pointsUpdated[i] != points[i]) - connectivityChanged = true; + CreatePoint(area.topology[i].basePoint, out string pointName); + pointsUpdated.Add(pointName); + continue; } - int numErrorMsgs = 0; - string importLog = ""; - if (connectivityChanged) + pointsUpdated.Add(UpdatePoint(points[i], area.topology[i])); + if (!connectivityChanged && pointsUpdated[i] != points[i]) { + connectivityChanged = true; + } + } + + int numErrorMsgs = 0; + string importLog = ""; + if (connectivityChanged) + { #if SAP2000 - var refArray = pointsUpdated.ToArray(); - success = Model.EditArea.ChangeConnectivity(name, pointsUpdated.Count, ref refArray); - if (success != 0) - throw new ConversionException( - $"Failed to modify the connectivity of the area: {name}" - ); -#else - int tableVersion = 0; - int numberRecords = 0; - string[] fieldsKeysIncluded = null; - string[] tableData = null; - const string floorTableKey = "Floor Object Connectivity"; - success = Model.DatabaseTables.GetTableForEditingArray( - floorTableKey, - "ThisParamIsNotActiveYet", - ref tableVersion, - ref fieldsKeysIncluded, - ref numberRecords, - ref tableData + var refArray = pointsUpdated.ToArray(); + success = Model.EditArea.ChangeConnectivity(name, pointsUpdated.Count, ref refArray); + if (success != 0) + { + throw new ConversionException( + $"Failed to modify the connectivity of the area: {name}" ); + } +#else + int tableVersion = 0; + int numberRecords = 0; + string[] fieldsKeysIncluded = null; + string[] tableData = null; + const string floorTableKey = "Floor Object Connectivity"; + success = Model.DatabaseTables.GetTableForEditingArray( + floorTableKey, + "ThisParamIsNotActiveYet", + ref tableVersion, + ref fieldsKeysIncluded, + ref numberRecords, + ref tableData + ); + if (success != 0) + { + throw new ConversionException($"Failed to retrieve database table for editing table key: {floorTableKey}"); + } + + // if the floor object now has more points than it previously had + // and it has more points that any other floor object, then updating would involve adding a new column to this array + // for the moment, forget that, it feels a bit fragile. Just delete the current object and remake it with the same GUID + if (pointsUpdated.Count > points.Length && pointsUpdated.Count > fieldsKeysIncluded.Length - 2) + { + string GUID = ""; + success = Model.AreaObj.GetGUID(name, ref GUID); if (success != 0) - throw new ConversionException($"Failed to retrieve database table for editing table key: {floorTableKey}"); + { + throw new ConversionException($"Failed to retrieve the GUID for area: {name}"); + } - // if the floor object now has more points than it previously had - // and it has more points that any other floor object, then updating would involve adding a new column to this array - // for the moment, forget that, it feels a bit fragile. Just delete the current object and remake it with the same GUID - if (pointsUpdated.Count > points.Length && pointsUpdated.Count > fieldsKeysIncluded.Length - 2) + var updatedArea = AreaToSpeckle(name); + + updatedArea.applicationId = GUID; + updatedArea.topology = area.topology; + + Model.AreaObj.Delete(name); + ExistingObjectGuids.Remove(GUID); + var dummyAppObj = new ApplicationObject(null, null); + AreaToNative(updatedArea, dummyAppObj); + if (dummyAppObj.Status != ApplicationObject.State.Created) { - string GUID = ""; - success = Model.AreaObj.GetGUID(name, ref GUID); - if (success != 0) - throw new ConversionException($"Failed to retrieve the GUID for area: {name}"); - - var updatedArea = AreaToSpeckle(name); - - updatedArea.applicationId = GUID; - updatedArea.topology = area.topology; - - Model.AreaObj.Delete(name); - ExistingObjectGuids.Remove(GUID); - var dummyAppObj = new ApplicationObject(null, null); - AreaToNative(updatedArea, dummyAppObj); - if (dummyAppObj.Status != ApplicationObject.State.Created) - throw new SpeckleException("Area failed!"); //This should never happen, AreaToNative should throw + throw new SpeckleException("Area failed!"); //This should never happen, AreaToNative should throw } - else + } + else + { + for (int record = 0; record < numberRecords; record++) { - for (int record = 0; record < numberRecords; record++) + if (tableData[record * fieldsKeysIncluded.Length] != name) { - if (tableData[record * fieldsKeysIncluded.Length] != name) - continue; - - for (int i = 0; i < pointsUpdated.Count; i++) - tableData[record * fieldsKeysIncluded.Length + (i + 1)] = pointsUpdated[i]; - break; + continue; } - // this is a workaround for a CSI bug. The applyEditedTables is looking for "Unique Name", not "UniqueName" - // this bug is patched in version 20.0.0 - if (ProgramVersion.CompareTo("20.0.0") < 0 && fieldsKeysIncluded[0] == "UniqueName") - fieldsKeysIncluded[0] = "Unique Name"; - - Model.DatabaseTables.SetTableForEditingArray( - floorTableKey, - ref tableVersion, - ref fieldsKeysIncluded, - numberRecords, - ref tableData - ); - - int numFatalErrors = 0; - int numWarnMsgs = 0; - int numInfoMsgs = 0; - success = Model.DatabaseTables.ApplyEditedTables( - true, - ref numFatalErrors, - ref numErrorMsgs, - ref numWarnMsgs, - ref numInfoMsgs, - ref importLog - ); - - if (success != 0) + for (int i = 0; i < pointsUpdated.Count; i++) { - appObj.Log.Add(importLog); - throw new ConversionException("Failed to apply edited database tables"); + tableData[record * fieldsKeysIncluded.Length + (i + 1)] = pointsUpdated[i]; } - int numItems = 0; - int[] objTypes = null; - string[] objNames = null; - int[] pointNums = null; - foreach (var node in points) - { - Model.PointObj.GetConnectivity(node, ref numItems, ref objTypes, ref objNames, ref pointNums); - if (numItems == 0) - { - Model.PointObj.DeleteSpecialPoint(node); - } - } + break; } -#endif - } - - SetAreaProperties(name, area); - - string guid = null; - Model.AreaObj.GetGUID(name, ref guid); - appObj.Update(status: ApplicationObject.State.Updated, createdId: guid, convertedItem: $"Area{Delimiter}{name}"); + // this is a workaround for a CSI bug. The applyEditedTables is looking for "Unique Name", not "UniqueName" + // this bug is patched in version 20.0.0 + if (ProgramVersion.CompareTo("20.0.0") < 0 && fieldsKeysIncluded[0] == "UniqueName") + { + fieldsKeysIncluded[0] = "Unique Name"; + } - if (numErrorMsgs != 0) - appObj.Update( - log: new List() - { - $"Area may not have updated successfully. Number of error messages for operation is {numErrorMsgs}", - importLog - } + Model.DatabaseTables.SetTableForEditingArray( + floorTableKey, + ref tableVersion, + ref fieldsKeysIncluded, + numberRecords, + ref tableData ); - } - - public void AreaToNative(Element2D area, ApplicationObject appObj) - { - if (ElementExistsWithApplicationId(area.applicationId, out string areaName)) - { - UpdateArea(area, areaName, appObj); - return; - } - - if (GetAllAreaNames(Model).Contains(area.name)) - { - throw new ConversionException($"There is already a frame object named {area.name} in the model"); - } - var propName = CreateOrGetProp(area.property, out bool isExactMatch); - if (!isExactMatch) - { - appObj.Update( - logItem: $"Area section for object could not be created and was replaced with section named \"{propName}\"" + int numFatalErrors = 0; + int numWarnMsgs = 0; + int numInfoMsgs = 0; + success = Model.DatabaseTables.ApplyEditedTables( + true, + ref numFatalErrors, + ref numErrorMsgs, + ref numWarnMsgs, + ref numInfoMsgs, + ref importLog ); - } - - var name = CreateAreaFromPoints(area.topology.Select(t => t.basePoint), propName); - SetAreaProperties(name, area); - if (area.openings?.Count > 0) - { - foreach (var opening in area.openings) + if (success != 0) { - string openingName; - try - { - openingName = CreateAreaFromPoints(opening.ToPoints(), propName); - } - catch (Exception) - { - openingName = string.Empty; - } + appObj.Log.Add(importLog); + throw new ConversionException("Failed to apply edited database tables"); + } - var openingSuccess = Model.AreaObj.SetOpening(openingName, true); - if (openingSuccess != 0) + int numItems = 0; + int[] objTypes = null; + string[] objNames = null; + int[] pointNums = null; + foreach (var node in points) + { + Model.PointObj.GetConnectivity(node, ref numItems, ref objTypes, ref objNames, ref pointNums); + if (numItems == 0) { - appObj.Update(logItem: $"Unable to create opening with id {opening.id}"); + Model.PointObj.DeleteSpecialPoint(node); } } } - - if (!string.IsNullOrEmpty(area.applicationId)) - Model.AreaObj.SetGUID(name, area.applicationId); - - var guid = ""; - Model.AreaObj.GetGUID(name, ref guid); - - appObj.Update(status: ApplicationObject.State.Created, createdId: guid, convertedItem: $"Area{Delimiter}{name}"); +#endif } - private string CreateAreaFromPoints(IEnumerable points, string propName) - { - var name = ""; - int numPoints = 0; - List X = new(); - List Y = new(); - List Z = new(); - - foreach (var point in points) - { - X.Add(ScaleToNative(point.x, point.units)); - Y.Add(ScaleToNative(point.y, point.units)); - Z.Add(ScaleToNative(point.z, point.units)); - numPoints++; - } + SetAreaProperties(name, area); - if ( - Math.Abs(X.Last() - X.First()) < .01 - && Math.Abs(Y.Last() - Y.First()) < .01 - && Math.Abs(Z.Last() - Z.First()) < .01 - ) - { - X.RemoveAt(X.Count - 1); - Y.RemoveAt(Y.Count - 1); - Z.RemoveAt(Z.Count - 1); - numPoints--; - } - var x = X.ToArray(); - var y = Y.ToArray(); - var z = Z.ToArray(); + string guid = null; + Model.AreaObj.GetGUID(name, ref guid); - int success = Model.AreaObj.AddByCoord(numPoints, ref x, ref y, ref z, ref name, propName); + appObj.Update(status: ApplicationObject.State.Updated, createdId: guid, convertedItem: $"Area{Delimiter}{name}"); - if (success != 0) - throw new ConversionException($"Failed to add new area object for area {name} at coords {x} {y} {z}"); - - return name; + if (numErrorMsgs != 0) + { + appObj.Update( + log: new List() + { + $"Area may not have updated successfully. Number of error messages for operation is {numErrorMsgs}", + importLog + } + ); } + } - private string? CreateOrGetProp(Property2D property, out bool isExactMatch) + public void AreaToNative(Element2D area, ApplicationObject appObj) + { + if (ElementExistsWithApplicationId(area.applicationId, out string areaName)) { - int numberNames = 0; - string[] propNames = Array.Empty(); + UpdateArea(area, areaName, appObj); + return; + } - int success = Model.PropArea.GetNameList(ref numberNames, ref propNames); - if (success != 0) - throw new ConversionException("Failed to retrieve the names of all defined area properties"); + if (GetAllAreaNames(Model).Contains(area.name)) + { + throw new ConversionException($"There is already a frame object named {area.name} in the model"); + } - isExactMatch = true; + var propName = CreateOrGetProp(area.property, out bool isExactMatch); + if (!isExactMatch) + { + appObj.Update( + logItem: $"Area section for object could not be created and was replaced with section named \"{propName}\"" + ); + } - if (propNames.Contains(property?.name)) - { - return property.name; - } + var name = CreateAreaFromPoints(area.topology.Select(t => t.basePoint), propName); + SetAreaProperties(name, area); - if (property is CSIProperty2D prop2D) + if (area.openings?.Count > 0) + { + foreach (var opening in area.openings) { + string openingName; try { - return Property2DToNative(prop2D); + openingName = CreateAreaFromPoints(opening.ToPoints(), propName); } catch (Exception) { - // something failed... replace the type + openingName = string.Empty; } - } - isExactMatch = false; - if (propNames.Any()) - { - // TODO: support creating of Property2D - return propNames.First(); + var openingSuccess = Model.AreaObj.SetOpening(openingName, true); + if (openingSuccess != 0) + { + appObj.Update(logItem: $"Unable to create opening with id {opening.id}"); + } } + } - throw new ConversionException( - "Cannot create area because there aren't any area sections defined in the project file" - ); + if (!string.IsNullOrEmpty(area.applicationId)) + { + Model.AreaObj.SetGUID(name, area.applicationId); } - public void SetAreaProperties(string name, Element2D area) + var guid = ""; + Model.AreaObj.GetGUID(name, ref guid); + + appObj.Update(status: ApplicationObject.State.Created, createdId: guid, convertedItem: $"Area{Delimiter}{name}"); + } + + private string CreateAreaFromPoints(IEnumerable points, string propName) + { + var name = ""; + int numPoints = 0; + List X = new(); + List Y = new(); + List Z = new(); + + foreach (var point in points) { - if (!string.IsNullOrEmpty(area.name)) - { - if (GetAllAreaNames(Model).Contains(area.name)) - area.name = area.id; - Model.AreaObj.ChangeName(name, area.name); - name = area.name; - } + X.Add(ScaleToNative(point.x, point.units)); + Y.Add(ScaleToNative(point.y, point.units)); + Z.Add(ScaleToNative(point.z, point.units)); + numPoints++; + } - Model.AreaObj.SetProperty(name, area.property?.name); - if (area is CSIElement2D csiArea) - { - double[] values = null; - if (csiArea.modifiers != null) - { - values = csiArea.modifiers; - } + if ( + Math.Abs(X.Last() - X.First()) < .01 + && Math.Abs(Y.Last() - Y.First()) < .01 + && Math.Abs(Z.Last() - Z.First()) < .01 + ) + { + X.RemoveAt(X.Count - 1); + Y.RemoveAt(Y.Count - 1); + Z.RemoveAt(Z.Count - 1); + numPoints--; + } + var x = X.ToArray(); + var y = Y.ToArray(); + var z = Z.ToArray(); - Model.AreaObj.SetModifiers(csiArea.name, ref values); - Model.AreaObj.SetLocalAxes(csiArea.name, csiArea.orientationAngle); - Model.AreaObj.SetPier(csiArea.name, csiArea.PierAssignment); - Model.AreaObj.SetSpandrel(csiArea.name, csiArea.SpandrelAssignment); - if (csiArea.CSIAreaSpring != null) - { - Model.AreaObj.SetSpringAssignment(csiArea.name, csiArea.CSIAreaSpring.name); - } + int success = Model.AreaObj.AddByCoord(numPoints, ref x, ref y, ref z, ref name, propName); - if (csiArea.DiaphragmAssignment != null) - { - Model.AreaObj.SetDiaphragm(csiArea.name, csiArea.DiaphragmAssignment); - } - } + if (success != 0) + { + throw new ConversionException($"Failed to add new area object for area {name} at coords {x} {y} {z}"); } - public Element2D AreaToSpeckle(string name) + return name; + } + + private string? CreateOrGetProp(Property2D property, out bool isExactMatch) + { + int numberNames = 0; + string[] propNames = Array.Empty(); + + int success = Model.PropArea.GetNameList(ref numberNames, ref propNames); + if (success != 0) { - string units = ModelUnits(); - var speckleStructArea = new CSIElement2D(); - - speckleStructArea.name = name; - int numPoints = 0; - string[] points = null; - Model.AreaObj.GetPoints(name, ref numPoints, ref points); - List nodes = new List(); - foreach (string point in points) - { - Node node = PointToSpeckle(point); - nodes.Add(node); - } - speckleStructArea.topology = nodes; + throw new ConversionException("Failed to retrieve the names of all defined area properties"); + } - bool isOpening = false; - Model.AreaObj.GetOpening(name, ref isOpening); - if (isOpening == true) + isExactMatch = true; + + if (propNames.Contains(property?.name)) + { + return property.name; + } + + if (property is CSIProperty2D prop2D) + { + try { - speckleStructArea.property = new CSIOpening(true); + return Property2DToNative(prop2D); } - else + catch (Exception) { - string propName = ""; - Model.AreaObj.GetProperty(name, ref propName); - speckleStructArea.property = Property2DToSpeckle(name, propName); + // something failed... replace the type } + } - List coordinates = new List { }; - foreach (Node node in nodes) - { - coordinates.Add(node.basePoint.x); - coordinates.Add(node.basePoint.y); - coordinates.Add(node.basePoint.z); - } + isExactMatch = false; + if (propNames.Any()) + { + // TODO: support creating of Property2D + return propNames.First(); + } - //Get orientation angle - double angle = 0; - bool advanced = true; - Model.AreaObj.GetLocalAxes(name, ref angle, ref advanced); - speckleStructArea.orientationAngle = angle; - if (coordinates.Count != 0) + throw new ConversionException( + "Cannot create area because there aren't any area sections defined in the project file" + ); + } + + public void SetAreaProperties(string name, Element2D area) + { + if (!string.IsNullOrEmpty(area.name)) + { + if (GetAllAreaNames(Model).Contains(area.name)) { - PolygonMesher polygonMesher = new PolygonMesher(); - polygonMesher.Init(coordinates); - var faces = polygonMesher.Faces(); - var vertices = polygonMesher.Coordinates; - //speckleStructArea.displayMesh = new Geometry.Mesh(vertices, faces.ToArray(), null, null, ModelUnits(), null); - speckleStructArea.displayValue = new List - { - new Geometry.Mesh(vertices.ToList(), faces, units: ModelUnits()) - }; + area.name = area.id; } - //Model.AreaObj.GetModifiers(area, ref value); - //speckleProperty2D.modifierInPlane = value[2]; - //speckleProperty2D.modifierBending = value[5]; - //speckleProperty2D.modifierShear = value[6]; + Model.AreaObj.ChangeName(name, area.name); + name = area.name; + } + Model.AreaObj.SetProperty(name, area.property?.name); + if (area is CSIElement2D csiArea) + { double[] values = null; - Model.AreaObj.GetModifiers(name, ref values); - speckleStructArea.modifiers = values; - - string springArea = null; - Model.AreaObj.GetSpringAssignment(name, ref springArea); - if (springArea != null) + if (csiArea.modifiers != null) { - speckleStructArea.CSIAreaSpring = AreaSpringToSpeckle(springArea); + values = csiArea.modifiers; } - string pierAssignment = null; - Model.AreaObj.GetPier(name, ref pierAssignment); - if (pierAssignment != null) + Model.AreaObj.SetModifiers(csiArea.name, ref values); + Model.AreaObj.SetLocalAxes(csiArea.name, csiArea.orientationAngle); + Model.AreaObj.SetPier(csiArea.name, csiArea.PierAssignment); + Model.AreaObj.SetSpandrel(csiArea.name, csiArea.SpandrelAssignment); + if (csiArea.CSIAreaSpring != null) { - speckleStructArea.PierAssignment = pierAssignment; + Model.AreaObj.SetSpringAssignment(csiArea.name, csiArea.CSIAreaSpring.name); } - string spandrelAssignment = null; - Model.AreaObj.GetSpandrel(name, ref spandrelAssignment); - if (spandrelAssignment != null) + if (csiArea.DiaphragmAssignment != null) { - speckleStructArea.SpandrelAssignment = spandrelAssignment; + Model.AreaObj.SetDiaphragm(csiArea.name, csiArea.DiaphragmAssignment); } + } + } - string diaphragmAssignment = null; - Model.AreaObj.GetDiaphragm(name, ref diaphragmAssignment); - if (diaphragmAssignment != null) - { - speckleStructArea.DiaphragmAssignment = diaphragmAssignment; - } + public Element2D AreaToSpeckle(string name) + { + string units = ModelUnits(); + var speckleStructArea = new CSIElement2D(); + + speckleStructArea.name = name; + int numPoints = 0; + string[] points = null; + Model.AreaObj.GetPoints(name, ref numPoints, ref points); + List nodes = new(); + foreach (string point in points) + { + Node node = PointToSpeckle(point); + nodes.Add(node); + } + speckleStructArea.topology = nodes; - speckleStructArea.AnalysisResults = resultsConverter? - .Element2DAnalyticalResultConverter? - .AnalyticalResultsToSpeckle(speckleStructArea.name); + bool isOpening = false; + Model.AreaObj.GetOpening(name, ref isOpening); + if (isOpening == true) + { + speckleStructArea.property = new CSIOpening(true); + } + else + { + string propName = ""; + Model.AreaObj.GetProperty(name, ref propName); + speckleStructArea.property = Property2DToSpeckle(name, propName); + } - var GUID = ""; - Model.AreaObj.GetGUID(name, ref GUID); - speckleStructArea.applicationId = GUID; - IList elements = SpeckleModel == null ? Array.Empty() : SpeckleModel.elements; - var applicationId = elements.Select(o => o.applicationId); - if (!applicationId.Contains(speckleStructArea.applicationId)) - { - SpeckleModel?.elements.Add(speckleStructArea); - } + List coordinates = new() { }; + foreach (Node node in nodes) + { + coordinates.Add(node.basePoint.x); + coordinates.Add(node.basePoint.y); + coordinates.Add(node.basePoint.z); + } + + //Get orientation angle + double angle = 0; + bool advanced = true; + Model.AreaObj.GetLocalAxes(name, ref angle, ref advanced); + speckleStructArea.orientationAngle = angle; + if (coordinates.Count != 0) + { + PolygonMesher polygonMesher = new(); + polygonMesher.Init(coordinates); + var faces = polygonMesher.Faces(); + var vertices = polygonMesher.Coordinates; + //speckleStructArea.displayMesh = new Geometry.Mesh(vertices, faces.ToArray(), null, null, ModelUnits(), null); + speckleStructArea.displayValue = new List { new(vertices.ToList(), faces, units: ModelUnits()) }; + } - // Should discretize between wall and slab types - //speckleStructArea.memberType = MemberType.Generic2D; + //Model.AreaObj.GetModifiers(area, ref value); + //speckleProperty2D.modifierInPlane = value[2]; + //speckleProperty2D.modifierBending = value[5]; + //speckleProperty2D.modifierShear = value[6]; - return speckleStructArea; + double[] values = null; + Model.AreaObj.GetModifiers(name, ref values); + speckleStructArea.modifiers = values; + + string springArea = null; + Model.AreaObj.GetSpringAssignment(name, ref springArea); + if (springArea != null) + { + speckleStructArea.CSIAreaSpring = AreaSpringToSpeckle(springArea); + } + + string pierAssignment = null; + Model.AreaObj.GetPier(name, ref pierAssignment); + if (pierAssignment != null) + { + speckleStructArea.PierAssignment = pierAssignment; } + + string spandrelAssignment = null; + Model.AreaObj.GetSpandrel(name, ref spandrelAssignment); + if (spandrelAssignment != null) + { + speckleStructArea.SpandrelAssignment = spandrelAssignment; + } + + string diaphragmAssignment = null; + Model.AreaObj.GetDiaphragm(name, ref diaphragmAssignment); + if (diaphragmAssignment != null) + { + speckleStructArea.DiaphragmAssignment = diaphragmAssignment; + } + + speckleStructArea.AnalysisResults = + resultsConverter?.Element2DAnalyticalResultConverter?.AnalyticalResultsToSpeckle(speckleStructArea.name); + + var GUID = ""; + Model.AreaObj.GetGUID(name, ref GUID); + speckleStructArea.applicationId = GUID; + IList elements = SpeckleModel == null ? Array.Empty() : SpeckleModel.elements; + var applicationId = elements.Select(o => o.applicationId); + if (!applicationId.Contains(speckleStructArea.applicationId)) + { + SpeckleModel?.elements.Add(speckleStructArea); + } + + // Should discretize between wall and slab types + //speckleStructArea.memberType = MemberType.Generic2D; + + return speckleStructArea; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBeam.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBeam.cs index 9ca479135f..46575e55e8 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBeam.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBeam.cs @@ -1,12 +1,11 @@ -using Objects.Structural.Geometry; +using Objects.Structural.Geometry; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Element1D BeamToSpeckle(string name) { - public Element1D BeamToSpeckle(string name) - { - return FrameToSpeckle(name); - } + return FrameToSpeckle(name); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBraces.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBraces.cs index 297a20ad9a..9e51c24ff7 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBraces.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBraces.cs @@ -1,17 +1,16 @@ -using System; +using System; using System.Collections.Generic; using Objects.Geometry; using Objects.Structural.Geometry; using Objects.Structural.Analysis; using CSiAPIv1; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Element1D BraceToSpeckle(string name) { - public Element1D BraceToSpeckle(string name) - { - return FrameToSpeckle(name); - } + return FrameToSpeckle(name); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBuiltElement.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBuiltElement.cs index b2aa213f78..8d62025136 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBuiltElement.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertBuiltElement.cs @@ -1,52 +1,55 @@ -using System; +using System; using Objects.Geometry; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void CurveBasedElementToNative(Base @base, ICurve curve, ApplicationObject appObj) { - public void CurveBasedElementToNative(Base @base, ICurve curve, ApplicationObject appObj) + if (curve is not Line baseLine) { - if (curve is not Line baseLine) - { - throw new ArgumentException("Only line based frames are currently supported", nameof(curve)); - } + throw new ArgumentException("Only line based frames are currently supported", nameof(curve)); + } - if (ElementExistsWithApplicationId(@base.applicationId, out string name)) - { - UpdateFrameLocation(name, baseLine.start, baseLine.end, appObj); - SetProfileSection(name, @base, appObj, true); - } - else - { - CreateFrame(baseLine.start, baseLine.end, out var frameName, out _, appObj); - SetProfileSection(frameName, @base, appObj); - } + if (ElementExistsWithApplicationId(@base.applicationId, out string name)) + { + UpdateFrameLocation(name, baseLine.start, baseLine.end, appObj); + SetProfileSection(name, @base, appObj, true); + } + else + { + CreateFrame(baseLine.start, baseLine.end, out var frameName, out _, appObj); + SetProfileSection(frameName, @base, appObj); } + } - public void SetProfileSection(string frameName, Base @base, ApplicationObject appObj, bool isUpdate = false) + public void SetProfileSection(string frameName, Base @base, ApplicationObject appObj, bool isUpdate = false) + { + string endMessage; + if (isUpdate) { - string endMessage; - if (isUpdate) - endMessage = "Section was not updated."; - else - endMessage = "Default section was assigned."; + endMessage = "Section was not updated."; + } + else + { + endMessage = "Default section was assigned."; + } - var speckleObjectType = @base["type"] as string; + var speckleObjectType = @base["type"] as string; - if (string.IsNullOrWhiteSpace(speckleObjectType)) - { - appObj.Update(logItem: $"Object has no type property. {endMessage}"); - } - else if (!Property1DExists(speckleObjectType)) - { - appObj.Update(logItem: $"Element type, {speckleObjectType}, is not present in ETABS model. {endMessage}"); - } - else - { - Model.FrameObj.SetSection(frameName, speckleObjectType); - } + if (string.IsNullOrWhiteSpace(speckleObjectType)) + { + appObj.Update(logItem: $"Object has no type property. {endMessage}"); + } + else if (!Property1DExists(speckleObjectType)) + { + appObj.Update(logItem: $"Element type, {speckleObjectType}, is not present in ETABS model. {endMessage}"); + } + else + { + Model.FrameObj.SetSection(frameName, speckleObjectType); } } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertColumn.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertColumn.cs index 0207249692..effbb18fc7 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertColumn.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertColumn.cs @@ -1,17 +1,16 @@ -using System; +using System; using System.Collections.Generic; using Objects.Geometry; using Objects.Structural.Geometry; using Objects.Structural.Analysis; using CSiAPIv1; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Element1D ColumnToSpeckle(string name) { - public Element1D ColumnToSpeckle(string name) - { - return FrameToSpeckle(name); - } + return FrameToSpeckle(name); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFloor.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFloor.cs index a81e23aef4..6fae1c4947 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFloor.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFloor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using CSiAPIv1; @@ -7,13 +7,12 @@ using Objects.Structural.CSI.Properties; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Element2D FloorToSpeckle(string name) { - public Element2D FloorToSpeckle(string name) - { - return AreaToSpeckle(name); - } + return AreaToSpeckle(name); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFrame.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFrame.cs index a8b2d80925..8a423fe917 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFrame.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertFrame.cs @@ -9,394 +9,408 @@ using CSiAPIv1; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void UpdateFrame(Element1D element1D, string name, ApplicationObject appObj) { - public void UpdateFrame(Element1D element1D, string name, ApplicationObject appObj) + var end1node = element1D.end1Node?.basePoint ?? element1D.baseLine?.start; + var end2node = element1D.end2Node?.basePoint ?? element1D.baseLine?.end; + + if (end1node == null || end2node == null) { - var end1node = element1D.end1Node?.basePoint ?? element1D.baseLine?.start; - var end2node = element1D.end2Node?.basePoint ?? element1D.baseLine?.end; + throw new ArgumentException($"Frame {element1D.name} does not have valid endpoints {end1node},{end2node}"); + } + + UpdateFrameLocation(name, end1node, end2node, appObj); + SetFrameElementProperties(element1D, name, appObj.Log); + } - if (end1node == null || end2node == null) + public void UpdateFrameLocation(string name, Point p1, Point p2, ApplicationObject appObj) + { + string pt1 = ""; + string pt2 = ""; + Model.FrameObj.GetPoints(name, ref pt1, ref pt2); + + // unfortunately this isn't as easy as just changing the coords of the end points of the frame, + // as those points may be shared by other frames. Need to check if there are other frames using + // those points and then check the new location of the endpoints to see if there are existing points + // that could be used. + var pt1Updated = UpdatePoint(pt1, null, p1); + var pt2Updated = UpdatePoint(pt2, null, p2); + + int success = 0; + if (pt1Updated != pt1 || pt2Updated != pt2) + { + success = Model.EditFrame.ChangeConnectivity(name, pt1Updated, pt2Updated); + + int numItems = 0; + int[] objTypes = null; + string[] objNames = null; + int[] pointNums = null; + Model.PointObj.GetConnectivity(pt1, ref numItems, ref objTypes, ref objNames, ref pointNums); + if (numItems == 0) { - throw new ArgumentException($"Frame {element1D.name} does not have valid endpoints {end1node},{end2node}"); + Model.PointObj.DeleteSpecialPoint(pt1); } - UpdateFrameLocation(name, end1node, end2node, appObj); - SetFrameElementProperties(element1D, name, appObj.Log); + Model.PointObj.GetConnectivity(pt2, ref numItems, ref objTypes, ref objNames, ref pointNums); + if (numItems == 0) + { + Model.PointObj.DeleteSpecialPoint(pt2); + } } - public void UpdateFrameLocation(string name, Point p1, Point p2, ApplicationObject appObj) + if (success != 0) { - string pt1 = ""; - string pt2 = ""; - Model.FrameObj.GetPoints(name, ref pt1, ref pt2); - - // unfortunately this isn't as easy as just changing the coords of the end points of the frame, - // as those points may be shared by other frames. Need to check if there are other frames using - // those points and then check the new location of the endpoints to see if there are existing points - // that could be used. - var pt1Updated = UpdatePoint(pt1, null, p1); - var pt2Updated = UpdatePoint(pt2, null, p2); - - int success = 0; - if (pt1Updated != pt1 || pt2Updated != pt2) - { - success = Model.EditFrame.ChangeConnectivity(name, pt1Updated, pt2Updated); - - int numItems = 0; - int[] objTypes = null; - string[] objNames = null; - int[] pointNums = null; - Model.PointObj.GetConnectivity(pt1, ref numItems, ref objTypes, ref objNames, ref pointNums); - if (numItems == 0) - Model.PointObj.DeleteSpecialPoint(pt1); - Model.PointObj.GetConnectivity(pt2, ref numItems, ref objTypes, ref objNames, ref pointNums); - if (numItems == 0) - Model.PointObj.DeleteSpecialPoint(pt2); - } + throw new ConversionException("Failed to change frame connectivity"); + } + + string guid = null; + Model.FrameObj.GetGUID(name, ref guid); + appObj.Update(status: ApplicationObject.State.Updated, createdId: guid, convertedItem: $"Frame{Delimiter}{name}"); + } + + public void FrameToNative(Element1D element1D, ApplicationObject appObj) + { + if (element1D.type == ElementType1D.Link) + { + string createdName = LinkToNative((CSIElement1D)element1D, appObj.Log); + appObj.Update(status: ApplicationObject.State.Created, createdId: createdName); + return; + } - if (success != 0) - throw new ConversionException("Failed to change frame connectivity"); + if (ElementExistsWithApplicationId(element1D.applicationId, out string name)) + { + UpdateFrame(element1D, name, appObj); + return; + } - string guid = null; - Model.FrameObj.GetGUID(name, ref guid); - appObj.Update(status: ApplicationObject.State.Updated, createdId: guid, convertedItem: $"Frame{Delimiter}{name}"); + Line baseline = element1D.baseLine; + string[] properties = Array.Empty(); + int number = 0; + int success = Model.PropFrame.GetNameList(ref number, ref properties); + if (success != 0) + { + appObj.Update(logItem: "Failed to retrieve frame section properties"); } - public void FrameToNative(Element1D element1D, ApplicationObject appObj) + if (!properties.Contains(element1D.property.name)) + { + TryConvertProperty1DToNative(element1D.property, appObj.Log); + Model.PropFrame.GetNameList(ref number, ref properties); + } + + Point end1node; + Point end2node; + if (baseline != null) + { + end1node = baseline.start; + end2node = baseline.end; + } + else { - if (element1D.type == ElementType1D.Link) + end1node = element1D.end1Node.basePoint; + end2node = element1D.end2Node.basePoint; + } + + CreateFrame(end1node, end2node, out var newFrame, out _, appObj); + SetFrameElementProperties(element1D, newFrame, appObj.Log); + } + + public void CreateFrame( + Point p0, + Point p1, + out string newFrame, + out string guid, + ApplicationObject appObj, + string type = "Default", + string nameOverride = null + ) + { + newFrame = string.Empty; + guid = string.Empty; + + int success = Model.FrameObj.AddByCoord( + ScaleToNative(p0.x, p0.units), + ScaleToNative(p0.y, p0.units), + ScaleToNative(p0.z, p0.units), + ScaleToNative(p1.x, p1.units), + ScaleToNative(p1.y, p1.units), + ScaleToNative(p1.z, p1.units), + ref newFrame, + type + ); + + Model.FrameObj.GetGUID(newFrame, ref guid); + + if (!string.IsNullOrEmpty(nameOverride) && !GetAllFrameNames(Model).Contains(nameOverride)) + { + Model.FrameObj.ChangeName(newFrame, nameOverride); + newFrame = nameOverride; + } + + if (success != 0) + { + throw new ConversionException("Failed to add new frame object at the specified coordinates"); + } + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: guid, + convertedItem: $"Frame{Delimiter}{newFrame}" + ); + } + + public CSIElement1D FrameToSpeckle(string name) + { + string units = ModelUnits(); + + var speckleStructFrame = new CSIElement1D(); + + speckleStructFrame.name = name; + string pointI, + pointJ; + pointI = pointJ = null; + _ = Model.FrameObj.GetPoints(name, ref pointI, ref pointJ); + var pointINode = PointToSpeckle(pointI); + var pointJNode = PointToSpeckle(pointJ); + speckleStructFrame.end1Node = pointINode; + speckleStructFrame.end2Node = pointJNode; + var speckleLine = new Line(); + if (units != null) + { + speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint, units); + } + else + { + speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint); + } + speckleStructFrame.baseLine = speckleLine; + eFrameDesignOrientation frameDesignOrientation = eFrameDesignOrientation.Null; + Model.FrameObj.GetDesignOrientation(name, ref frameDesignOrientation); + switch (frameDesignOrientation) + { + case eFrameDesignOrientation.Column: { - string createdName = LinkToNative((CSIElement1D)element1D, appObj.Log); - appObj.Update(status: ApplicationObject.State.Created, createdId: createdName); - return; + speckleStructFrame.type = ElementType1D.Column; + break; } - - if (ElementExistsWithApplicationId(element1D.applicationId, out string name)) + case eFrameDesignOrientation.Beam: { - UpdateFrame(element1D, name, appObj); - return; + speckleStructFrame.type = ElementType1D.Beam; + break; } - - Line baseline = element1D.baseLine; - string[] properties = Array.Empty(); - int number = 0; - int success = Model.PropFrame.GetNameList(ref number, ref properties); - if (success != 0) - appObj.Update(logItem: "Failed to retrieve frame section properties"); - - if (!properties.Contains(element1D.property.name)) + case eFrameDesignOrientation.Brace: { - TryConvertProperty1DToNative(element1D.property, appObj.Log); - Model.PropFrame.GetNameList(ref number, ref properties); + speckleStructFrame.type = ElementType1D.Brace; + break; } - - Point end1node; - Point end2node; - if (baseline != null) + case eFrameDesignOrientation.Null: { - end1node = baseline.start; - end2node = baseline.end; + //speckleStructFrame.memberType = MemberType.Generic1D; + speckleStructFrame.type = ElementType1D.Null; + break; } - else + case eFrameDesignOrientation.Other: { - end1node = element1D.end1Node.basePoint; - end2node = element1D.end2Node.basePoint; + speckleStructFrame.type = ElementType1D.Other; + break; } - - CreateFrame(end1node, end2node, out var newFrame, out _, appObj); - SetFrameElementProperties(element1D, newFrame, appObj.Log); } - public void CreateFrame( - Point p0, - Point p1, - out string newFrame, - out string guid, - ApplicationObject appObj, - string type = "Default", - string nameOverride = null - ) + bool[] iRelease, + jRelease; + iRelease = jRelease = null; + double[] startV, + endV; + startV = endV = null; + Model.FrameObj.GetReleases(name, ref iRelease, ref jRelease, ref startV, ref endV); + + speckleStructFrame.end1Releases = RestraintToSpeckle(iRelease); + speckleStructFrame.end2Releases = RestraintToSpeckle(jRelease); + SpeckleModel.restraints.Add(speckleStructFrame.end1Releases); + SpeckleModel.restraints.Add(speckleStructFrame.end2Releases); + + double localAxis = 0; + bool advanced = false; + Model.FrameObj.GetLocalAxes(name, ref localAxis, ref advanced); + speckleStructFrame.orientationAngle = localAxis; + + string property, + SAuto; + property = SAuto = null; + Model.FrameObj.GetSection(name, ref property, ref SAuto); + speckleStructFrame.property = Property1DToSpeckle(property); + + double offSetEnd1 = 0; + double offSetEnd2 = 0; + double RZ = 0; + bool autoOffSet = true; + Model.FrameObj.GetEndLengthOffset(name, ref autoOffSet, ref offSetEnd1, ref offSetEnd2, ref RZ); + //Offset needs to be oriented wrt to 1-axis + Vector end1Offset = new(0, 0, offSetEnd1, ModelUnits()); + Vector end2Offset = new(0, 0, offSetEnd2, ModelUnits()); + speckleStructFrame.end1Offset = end1Offset; + speckleStructFrame.end2Offset = end2Offset; + + string springLineName = null; + Model.FrameObj.GetSpringAssignment(name, ref springLineName); + if (springLineName != null) { - newFrame = string.Empty; - guid = string.Empty; - - int success = Model.FrameObj.AddByCoord( - ScaleToNative(p0.x, p0.units), - ScaleToNative(p0.y, p0.units), - ScaleToNative(p0.z, p0.units), - ScaleToNative(p1.x, p1.units), - ScaleToNative(p1.y, p1.units), - ScaleToNative(p1.z, p1.units), - ref newFrame, - type - ); - - Model.FrameObj.GetGUID(newFrame, ref guid); - - if (!string.IsNullOrEmpty(nameOverride) && !GetAllFrameNames(Model).Contains(nameOverride)) - { - Model.FrameObj.ChangeName(newFrame, nameOverride); - newFrame = nameOverride; - } + speckleStructFrame.CSILinearSpring = LinearSpringToSpeckle(springLineName); + } - if (success != 0) - throw new ConversionException("Failed to add new frame object at the specified coordinates"); + string pierAssignment = null; + Model.FrameObj.GetPier(name, ref pierAssignment); + if (pierAssignment != null) + { + speckleStructFrame.PierAssignment = pierAssignment; + } - appObj.Update( - status: ApplicationObject.State.Created, - createdId: guid, - convertedItem: $"Frame{Delimiter}{newFrame}" - ); + string spandrelAssignment = null; + Model.FrameObj.GetSpandrel(name, ref spandrelAssignment); + if (spandrelAssignment != null) + { + speckleStructFrame.SpandrelAssignment = spandrelAssignment; } - public CSIElement1D FrameToSpeckle(string name) + int designProcedure = 9; + Model.FrameObj.GetDesignProcedure(name, ref designProcedure); + if (designProcedure != 9) { - string units = ModelUnits(); - - var speckleStructFrame = new CSIElement1D(); - - speckleStructFrame.name = name; - string pointI, - pointJ; - pointI = pointJ = null; - _ = Model.FrameObj.GetPoints(name, ref pointI, ref pointJ); - var pointINode = PointToSpeckle(pointI); - var pointJNode = PointToSpeckle(pointJ); - speckleStructFrame.end1Node = pointINode; - speckleStructFrame.end2Node = pointJNode; - var speckleLine = new Line(); - if (units != null) - { - speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint, units); - } - else - { - speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint); - } - speckleStructFrame.baseLine = speckleLine; - eFrameDesignOrientation frameDesignOrientation = eFrameDesignOrientation.Null; - Model.FrameObj.GetDesignOrientation(name, ref frameDesignOrientation); - switch (frameDesignOrientation) + switch (designProcedure) { - case eFrameDesignOrientation.Column: - { - speckleStructFrame.type = ElementType1D.Column; + case 0: + speckleStructFrame.DesignProcedure = DesignProcedure.ProgramDetermined; break; - } - case eFrameDesignOrientation.Beam: - { - speckleStructFrame.type = ElementType1D.Beam; + case 1: + speckleStructFrame.DesignProcedure = DesignProcedure.SteelFrameDesign; break; - } - case eFrameDesignOrientation.Brace: - { - speckleStructFrame.type = ElementType1D.Brace; + case 2: + speckleStructFrame.DesignProcedure = DesignProcedure.ConcreteFrameDesign; break; - } - case eFrameDesignOrientation.Null: - { - //speckleStructFrame.memberType = MemberType.Generic1D; - speckleStructFrame.type = ElementType1D.Null; + case 3: + speckleStructFrame.DesignProcedure = DesignProcedure.CompositeBeamDesign; break; - } - case eFrameDesignOrientation.Other: - { - speckleStructFrame.type = ElementType1D.Other; + case 4: + speckleStructFrame.DesignProcedure = DesignProcedure.SteelJoistDesign; + break; + case 7: + speckleStructFrame.DesignProcedure = DesignProcedure.NoDesign; + break; + case 13: + speckleStructFrame.DesignProcedure = DesignProcedure.CompositeColumnDesign; break; - } } + } + double[] modifiers = new double[] { }; + int s = Model.FrameObj.GetModifiers(name, ref modifiers); + if (s == 0) + { + speckleStructFrame.Modifiers = modifiers; + } + + speckleStructFrame.AnalysisResults = + resultsConverter?.Element1DAnalyticalResultConverter?.AnalyticalResultsToSpeckle( + speckleStructFrame.name, + speckleStructFrame.type + ); + + var GUID = ""; + Model.FrameObj.GetGUID(name, ref GUID); + speckleStructFrame.applicationId = GUID; + List elements = SpeckleModel.elements; + List application_Id = elements.Select(o => o.applicationId).ToList(); + if (!application_Id.Contains(speckleStructFrame.applicationId)) + { + SpeckleModel.elements.Add(speckleStructFrame); + } - bool[] iRelease, - jRelease; - iRelease = jRelease = null; - double[] startV, - endV; - startV = endV = null; - Model.FrameObj.GetReleases(name, ref iRelease, ref jRelease, ref startV, ref endV); - - speckleStructFrame.end1Releases = RestraintToSpeckle(iRelease); - speckleStructFrame.end2Releases = RestraintToSpeckle(jRelease); - SpeckleModel.restraints.Add(speckleStructFrame.end1Releases); - SpeckleModel.restraints.Add(speckleStructFrame.end2Releases); - - double localAxis = 0; - bool advanced = false; - Model.FrameObj.GetLocalAxes(name, ref localAxis, ref advanced); - speckleStructFrame.orientationAngle = localAxis; - - string property, - SAuto; - property = SAuto = null; - Model.FrameObj.GetSection(name, ref property, ref SAuto); - speckleStructFrame.property = Property1DToSpeckle(property); - - double offSetEnd1 = 0; - double offSetEnd2 = 0; - double RZ = 0; - bool autoOffSet = true; - Model.FrameObj.GetEndLengthOffset(name, ref autoOffSet, ref offSetEnd1, ref offSetEnd2, ref RZ); - //Offset needs to be oriented wrt to 1-axis - Vector end1Offset = new Vector(0, 0, offSetEnd1, ModelUnits()); - Vector end2Offset = new Vector(0, 0, offSetEnd2, ModelUnits()); - speckleStructFrame.end1Offset = end1Offset; - speckleStructFrame.end2Offset = end2Offset; - - string springLineName = null; - Model.FrameObj.GetSpringAssignment(name, ref springLineName); - if (springLineName != null) + return speckleStructFrame; + } + + public void SetFrameElementProperties(Element1D element1D, string newFrame, IList? log) + { + bool[] end1Release = null; + bool[] end2Release = null; + double[] startV, + endV; + startV = null; + endV = null; + if (element1D.end1Releases != null && element1D.end2Releases != null) + { + end1Release = RestraintToNative(element1D.end1Releases); + end2Release = RestraintToNative(element1D.end2Releases); + startV = PartialRestraintToNative(element1D.end1Releases); + endV = PartialRestraintToNative(element1D.end2Releases); + } + + var propertyName = TryConvertProperty1DToNative(element1D.property, log); + if (propertyName != null) + { + Model.FrameObj.SetSection(newFrame, propertyName); + } + + if (element1D.orientationAngle != null) + { + Model.FrameObj.SetLocalAxes(newFrame, element1D.orientationAngle); + } + end1Release = end1Release.Select(b => !b).ToArray(); + end2Release = end2Release.Select(b => !b).ToArray(); + + Model.FrameObj.SetReleases(newFrame, ref end1Release, ref end2Release, ref startV, ref endV); + if (element1D is CSIElement1D) + { + var CSIelement1D = (CSIElement1D)element1D; + if (CSIelement1D.SpandrelAssignment != null) { - speckleStructFrame.CSILinearSpring = LinearSpringToSpeckle(springLineName); + Model.FrameObj.SetSpandrel(CSIelement1D.name, CSIelement1D.SpandrelAssignment); } - - string pierAssignment = null; - Model.FrameObj.GetPier(name, ref pierAssignment); - if (pierAssignment != null) + if (CSIelement1D.PierAssignment != null) { - speckleStructFrame.PierAssignment = pierAssignment; + Model.FrameObj.SetPier(CSIelement1D.name, CSIelement1D.PierAssignment); } - - string spandrelAssignment = null; - Model.FrameObj.GetSpandrel(name, ref spandrelAssignment); - if (spandrelAssignment != null) + if (CSIelement1D.CSILinearSpring != null) { - speckleStructFrame.SpandrelAssignment = spandrelAssignment; + Model.FrameObj.SetSpringAssignment(CSIelement1D.name, CSIelement1D.CSILinearSpring.name); } - - int designProcedure = 9; - Model.FrameObj.GetDesignProcedure(name, ref designProcedure); - if (designProcedure != 9) + if (CSIelement1D.Modifiers != null) + { + var modifiers = CSIelement1D.Modifiers; + Model.FrameObj.SetModifiers(CSIelement1D.name, ref modifiers); + } + if (CSIelement1D.property.material.name != null) { - switch (designProcedure) + switch (CSIelement1D.DesignProcedure) { - case 0: - speckleStructFrame.DesignProcedure = DesignProcedure.ProgramDetermined; + case DesignProcedure.ProgramDetermined: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 0); break; - case 1: - speckleStructFrame.DesignProcedure = DesignProcedure.SteelFrameDesign; + case DesignProcedure.CompositeBeamDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 3); break; - case 2: - speckleStructFrame.DesignProcedure = DesignProcedure.ConcreteFrameDesign; + case DesignProcedure.CompositeColumnDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 13); break; - case 3: - speckleStructFrame.DesignProcedure = DesignProcedure.CompositeBeamDesign; + case DesignProcedure.SteelFrameDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 1); break; - case 4: - speckleStructFrame.DesignProcedure = DesignProcedure.SteelJoistDesign; + case DesignProcedure.ConcreteFrameDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 2); break; - case 7: - speckleStructFrame.DesignProcedure = DesignProcedure.NoDesign; + case DesignProcedure.SteelJoistDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 4); break; - case 13: - speckleStructFrame.DesignProcedure = DesignProcedure.CompositeColumnDesign; + case DesignProcedure.NoDesign: + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 7); break; } } - double[] modifiers = new double[] { }; - int s = Model.FrameObj.GetModifiers(name, ref modifiers); - if (s == 0) - { - speckleStructFrame.Modifiers = modifiers; - } - - speckleStructFrame.AnalysisResults = resultsConverter? - .Element1DAnalyticalResultConverter? - .AnalyticalResultsToSpeckle(speckleStructFrame.name, speckleStructFrame.type); - - var GUID = ""; - Model.FrameObj.GetGUID(name, ref GUID); - speckleStructFrame.applicationId = GUID; - List elements = SpeckleModel.elements; - List application_Id = elements.Select(o => o.applicationId).ToList(); - if (!application_Id.Contains(speckleStructFrame.applicationId)) - { - SpeckleModel.elements.Add(speckleStructFrame); - } - - return speckleStructFrame; - } - - public void SetFrameElementProperties(Element1D element1D, string newFrame, IList? log) - { - bool[] end1Release = null; - bool[] end2Release = null; - double[] startV, - endV; - startV = null; - endV = null; - if (element1D.end1Releases != null && element1D.end2Releases != null) - { - end1Release = RestraintToNative(element1D.end1Releases); - end2Release = RestraintToNative(element1D.end2Releases); - startV = PartialRestraintToNative(element1D.end1Releases); - endV = PartialRestraintToNative(element1D.end2Releases); - } - - var propertyName = TryConvertProperty1DToNative(element1D.property, log); - if (propertyName != null) - Model.FrameObj.SetSection(newFrame, propertyName); - - if (element1D.orientationAngle != null) - { - Model.FrameObj.SetLocalAxes(newFrame, element1D.orientationAngle); - } - end1Release = end1Release.Select(b => !b).ToArray(); - end2Release = end2Release.Select(b => !b).ToArray(); - - Model.FrameObj.SetReleases(newFrame, ref end1Release, ref end2Release, ref startV, ref endV); - if (element1D is CSIElement1D) + else { - var CSIelement1D = (CSIElement1D)element1D; - if (CSIelement1D.SpandrelAssignment != null) - { - Model.FrameObj.SetSpandrel(CSIelement1D.name, CSIelement1D.SpandrelAssignment); - } - if (CSIelement1D.PierAssignment != null) - { - Model.FrameObj.SetPier(CSIelement1D.name, CSIelement1D.PierAssignment); - } - if (CSIelement1D.CSILinearSpring != null) - { - Model.FrameObj.SetSpringAssignment(CSIelement1D.name, CSIelement1D.CSILinearSpring.name); - } - if (CSIelement1D.Modifiers != null) - { - var modifiers = CSIelement1D.Modifiers; - Model.FrameObj.SetModifiers(CSIelement1D.name, ref modifiers); - } - if (CSIelement1D.property.material.name != null) - { - switch (CSIelement1D.DesignProcedure) - { - case DesignProcedure.ProgramDetermined: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 0); - break; - case DesignProcedure.CompositeBeamDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 3); - break; - case DesignProcedure.CompositeColumnDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 13); - break; - case DesignProcedure.SteelFrameDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 1); - break; - case DesignProcedure.ConcreteFrameDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 2); - break; - case DesignProcedure.SteelJoistDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 4); - break; - case DesignProcedure.NoDesign: - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 7); - break; - } - } - else - { - Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 0); - } + Model.FrameObj.SetDesignProcedure(CSIelement1D.name, 0); } } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertGridLines.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertGridLines.cs index fa9c268cc2..42b35e50a4 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertGridLines.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertGridLines.cs @@ -3,80 +3,79 @@ using Objects.Structural.CSI.Geometry; using Objects.BuiltElements; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void GridLineToNative(GridLine gridline) { - public void GridLineToNative(GridLine gridline) - { - GridLineDefinitionTable.AddCartesian(gridline); - } + GridLineDefinitionTable.AddCartesian(gridline); + } - public CSIGridLines gridLinesToSpeckle(string name) - { - double Xo = 0; - double Yo = 0; - double RZ = 0; - string GridSysType = null; - int NumXLines = 0; - int NumYLines = 0; - string[] GridLineIDX = null; - string[] GridLineIDY = null; - double[] OrdinateX = null; - double[] OrdinateY = null; - bool[] VisibleX = null; - bool[] VisibleY = null; - string[] BubbleLocX = null; - string[] BubbleLocY = null; + public CSIGridLines gridLinesToSpeckle(string name) + { + double Xo = 0; + double Yo = 0; + double RZ = 0; + string GridSysType = null; + int NumXLines = 0; + int NumYLines = 0; + string[] GridLineIDX = null; + string[] GridLineIDY = null; + double[] OrdinateX = null; + double[] OrdinateY = null; + bool[] VisibleX = null; + bool[] VisibleY = null; + string[] BubbleLocX = null; + string[] BubbleLocY = null; - Model.GridSys.GetGridSys_2( - name, - ref Xo, - ref Yo, - ref RZ, - ref GridSysType, - ref NumXLines, - ref NumYLines, - ref GridLineIDX, - ref GridLineIDY, - ref OrdinateX, - ref OrdinateY, - ref VisibleX, - ref VisibleY, - ref BubbleLocX, - ref BubbleLocY - ); + Model.GridSys.GetGridSys_2( + name, + ref Xo, + ref Yo, + ref RZ, + ref GridSysType, + ref NumXLines, + ref NumYLines, + ref GridLineIDX, + ref GridLineIDY, + ref OrdinateX, + ref OrdinateY, + ref VisibleX, + ref VisibleY, + ref BubbleLocX, + ref BubbleLocY + ); - var gridlines = new List { }; - CSIGridLines speckleGridLines = new CSIGridLines(); - speckleGridLines.gridLines = gridlines; + var gridlines = new List { }; + CSIGridLines speckleGridLines = new(); + speckleGridLines.gridLines = gridlines; - if (GridSysType == "Cartesian") + if (GridSysType == "Cartesian") + { + for (int i = 0; i < NumXLines; i++) { - for (int i = 0; i < NumXLines; i++) - { - var pt1 = new Point(OrdinateX[i], OrdinateY[0], units: ModelUnits()); - var pt2 = new Point(OrdinateX[i], OrdinateY[NumYLines - 1], units: ModelUnits()); - var gridline = new GridLine(new Line(pt1, pt2, ModelUnits())); - gridline.label = GridLineIDX[i]; - speckleGridLines.gridLines.Add(gridline); - } - for (int j = 0; j < NumYLines; j++) - { - var pt1 = new Point(OrdinateX[0], OrdinateY[j], units: ModelUnits()); - var pt2 = new Point(OrdinateX[NumXLines - 1], OrdinateY[j], units: ModelUnits()); - var gridline = new GridLine(new Line(pt1, pt2, ModelUnits())); - gridline.label = GridLineIDY[j]; - speckleGridLines.gridLines.Add(gridline); - } - speckleGridLines.GridSystemType = GridSysType; - speckleGridLines.Xo = Xo; - speckleGridLines.Yo = Yo; - speckleGridLines.Rz = RZ; + var pt1 = new Point(OrdinateX[i], OrdinateY[0], units: ModelUnits()); + var pt2 = new Point(OrdinateX[i], OrdinateY[NumYLines - 1], units: ModelUnits()); + var gridline = new GridLine(new Line(pt1, pt2, ModelUnits())); + gridline.label = GridLineIDX[i]; + speckleGridLines.gridLines.Add(gridline); } - - SpeckleModel.elements.Add(speckleGridLines); - return speckleGridLines; + for (int j = 0; j < NumYLines; j++) + { + var pt1 = new Point(OrdinateX[0], OrdinateY[j], units: ModelUnits()); + var pt2 = new Point(OrdinateX[NumXLines - 1], OrdinateY[j], units: ModelUnits()); + var gridline = new GridLine(new Line(pt1, pt2, ModelUnits())); + gridline.label = GridLineIDY[j]; + speckleGridLines.gridLines.Add(gridline); + } + speckleGridLines.GridSystemType = GridSysType; + speckleGridLines.Xo = Xo; + speckleGridLines.Yo = Yo; + speckleGridLines.Rz = RZ; } + + SpeckleModel.elements.Add(speckleGridLines); + return speckleGridLines; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLine.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLine.cs index fdbe3efe42..90ff0d7b5d 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLine.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Objects.Geometry; using Speckle.Core.Kits; @@ -7,34 +7,35 @@ using CSiAPIv1; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string LineToNative(Line line) { - public string LineToNative(Line line) - { - string newFrame = ""; - Point lineStart = line.start; - Point end2Node = line.end; - - var modelUnits = ModelUnits(); - var end1NodeSf = Units.GetConversionFactor(lineStart.units, modelUnits); - var end2NodeSf = Units.GetConversionFactor(end2Node.units, modelUnits); + string newFrame = ""; + Point lineStart = line.start; + Point end2Node = line.end; - var success = Model.FrameObj.AddByCoord( - lineStart.x * end1NodeSf, - lineStart.y * end1NodeSf, - lineStart.z * end1NodeSf, - end2Node.x * end2NodeSf, - end2Node.y * end2NodeSf, - end2Node.z * end2NodeSf, - ref newFrame - ); + var modelUnits = ModelUnits(); + var end1NodeSf = Units.GetConversionFactor(lineStart.units, modelUnits); + var end2NodeSf = Units.GetConversionFactor(end2Node.units, modelUnits); - if (success != 0) - throw new ConversionException("Failed to add new frame"); + var success = Model.FrameObj.AddByCoord( + lineStart.x * end1NodeSf, + lineStart.y * end1NodeSf, + lineStart.z * end1NodeSf, + end2Node.x * end2NodeSf, + end2Node.y * end2NodeSf, + end2Node.z * end2NodeSf, + ref newFrame + ); - return newFrame; + if (success != 0) + { + throw new ConversionException("Failed to add new frame"); } + + return newFrame; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLinks.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLinks.cs index 35a69b732d..205111dfa6 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLinks.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertLinks.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Objects.Geometry; using Objects.Structural.Geometry; using Speckle.Core.Models; @@ -7,86 +7,88 @@ using System.Linq; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string LinkToNative(CSIElement1D link, IList? notes) { - public string LinkToNative(CSIElement1D link, IList? notes) + PointToNative((CSINode)link.end1Node, notes); + PointToNative((CSINode)link.end2Node, notes); + string linkName = null; + int numberProps = 0; + string[] listProp = null; + Model.PropLink.GetNameList(ref numberProps, ref listProp); + if (listProp.Contains(link.property.name)) { - PointToNative((CSINode)link.end1Node, notes); - PointToNative((CSINode)link.end2Node, notes); - string linkName = null; - int numberProps = 0; - string[] listProp = null; - Model.PropLink.GetNameList(ref numberProps, ref listProp); - if (listProp.Contains(link.property.name)) - { - var success = Model.LinkObj.AddByPoint( - link.end1Node.name, - link.end2Node.name, - ref linkName, - PropName: link.property.name - ); - if (success != 0) - throw new ConversionException("Failed to add new link by point"); - return linkName; - } - else + var success = Model.LinkObj.AddByPoint( + link.end1Node.name, + link.end2Node.name, + ref linkName, + PropName: link.property.name + ); + if (success != 0) { - string propertyName = LinkPropertyToNative((CSILinkProperty)link.property); - Model.LinkObj.AddByPoint(link.end1Node.name, link.end2Node.name, ref linkName, PropName: propertyName); - return propertyName; + throw new ConversionException("Failed to add new link by point"); } - } - public CSIElement1D LinkToSpeckle(string name) + return linkName; + } + else { - string units = ModelUnits(); + string propertyName = LinkPropertyToNative((CSILinkProperty)link.property); + Model.LinkObj.AddByPoint(link.end1Node.name, link.end2Node.name, ref linkName, PropName: propertyName); + return propertyName; + } + } - var speckleStructLink = new CSIElement1D(); + public CSIElement1D LinkToSpeckle(string name) + { + string units = ModelUnits(); - speckleStructLink.type = ElementType1D.Link; - speckleStructLink.name = name; - string pointI, - pointJ; - pointI = pointJ = null; - _ = Model.LinkObj.GetPoints(name, ref pointI, ref pointJ); - var pointINode = PointToSpeckle(pointI); - var pointJNode = PointToSpeckle(pointJ); - speckleStructLink.end1Node = pointINode; - speckleStructLink.end2Node = pointJNode; - var speckleLine = new Line(); - if (units != null) - { - speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint, units); - } - else - { - speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint); - } - speckleStructLink.baseLine = speckleLine; + var speckleStructLink = new CSIElement1D(); - double localAxis = 0; - bool advanced = false; - Model.LinkObj.GetLocalAxes(name, ref localAxis, ref advanced); - speckleStructLink.orientationAngle = localAxis; + speckleStructLink.type = ElementType1D.Link; + speckleStructLink.name = name; + string pointI, + pointJ; + pointI = pointJ = null; + _ = Model.LinkObj.GetPoints(name, ref pointI, ref pointJ); + var pointINode = PointToSpeckle(pointI); + var pointJNode = PointToSpeckle(pointJ); + speckleStructLink.end1Node = pointINode; + speckleStructLink.end2Node = pointJNode; + var speckleLine = new Line(); + if (units != null) + { + speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint, units); + } + else + { + speckleLine = new Line(pointINode.basePoint, pointJNode.basePoint); + } + speckleStructLink.baseLine = speckleLine; - speckleStructLink.type = ElementType1D.Link; - string linkProp = null; - Model.LinkObj.GetProperty(name, ref linkProp); - speckleStructLink.property = LinkPropertyToSpeckle(linkProp); + double localAxis = 0; + bool advanced = false; + Model.LinkObj.GetLocalAxes(name, ref localAxis, ref advanced); + speckleStructLink.orientationAngle = localAxis; - var GUID = ""; - Model.LinkObj.GetGUID(name, ref GUID); - speckleStructLink.applicationId = GUID; - List elements = SpeckleModel.elements; - List application_Id = elements.Select(o => o.applicationId).ToList(); - if (!application_Id.Contains(speckleStructLink.applicationId)) - { - SpeckleModel.elements.Add(speckleStructLink); - } + speckleStructLink.type = ElementType1D.Link; + string linkProp = null; + Model.LinkObj.GetProperty(name, ref linkProp); + speckleStructLink.property = LinkPropertyToSpeckle(linkProp); - return speckleStructLink; + var GUID = ""; + Model.LinkObj.GetGUID(name, ref GUID); + speckleStructLink.applicationId = GUID; + List elements = SpeckleModel.elements; + List application_Id = elements.Select(o => o.applicationId).ToList(); + if (!application_Id.Contains(speckleStructLink.applicationId)) + { + SpeckleModel.elements.Add(speckleStructLink); } + + return speckleStructLink; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPier.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPier.cs index d02b42a4f9..8210206720 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPier.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPier.cs @@ -1,4 +1,4 @@ -using System; +using System; using Objects.Structural.Geometry; using Objects.Geometry; using Objects.Structural.Analysis; @@ -10,43 +10,42 @@ using CSiAPIv1; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void PierToNative(CSIPier CSIPier) { - public void PierToNative(CSIPier CSIPier) - { - Model.PierLabel.SetPier(CSIPier.name); - } + Model.PierLabel.SetPier(CSIPier.name); + } - public CSIPier PierToSpeckle(string name) - { - int numberStories = 0; - string[] storyName = null; - int[] numAreaObjs = null; - int[] numLineObjs = null; - double[] axisAngle = null; - double[] widthBot = null; - double[] thicknessBot = null; - double[] widthTop = null; - double[] thicknessTop = null; - string[] matProp = null; - double[] centerofGravityBotX = null; - double[] centerofGravityBotY = null; - double[] centerofGravityBotZ = null; - double[] centerofGravityTopX = null; - double[] centerofGravityTopY = null; - double[] centerofGravityTopZ = null; + public CSIPier PierToSpeckle(string name) + { + int numberStories = 0; + string[] storyName = null; + int[] numAreaObjs = null; + int[] numLineObjs = null; + double[] axisAngle = null; + double[] widthBot = null; + double[] thicknessBot = null; + double[] widthTop = null; + double[] thicknessTop = null; + string[] matProp = null; + double[] centerofGravityBotX = null; + double[] centerofGravityBotY = null; + double[] centerofGravityBotZ = null; + double[] centerofGravityTopX = null; + double[] centerofGravityTopY = null; + double[] centerofGravityTopZ = null; - // **** ISSUE WITH THIS METHOD HANGING IF PIER LABEL NOT ASSIGNED IN MODEL **** // - //var s = Model.PierLabel.GetSectionProperties(name, ref numberStories, ref storyName, ref axisAngle, ref numAreaObjs, ref numLineObjs, ref widthBot, ref thicknessBot, ref widthTop, ref thicknessTop, ref matProp - //, ref centerofGravityBotX, ref centerofGravityBotY, ref centerofGravityBotZ, ref centerofGravityTopX, ref centerofGravityTopY, ref centerofGravityTopZ); + // **** ISSUE WITH THIS METHOD HANGING IF PIER LABEL NOT ASSIGNED IN MODEL **** // + //var s = Model.PierLabel.GetSectionProperties(name, ref numberStories, ref storyName, ref axisAngle, ref numAreaObjs, ref numLineObjs, ref widthBot, ref thicknessBot, ref widthTop, ref thicknessTop, ref matProp + //, ref centerofGravityBotX, ref centerofGravityBotY, ref centerofGravityBotZ, ref centerofGravityTopX, ref centerofGravityTopY, ref centerofGravityTopZ); - //var speckleCSIPier = new CSIPier(name, numberStories, storyName, axisAngle, numAreaObjs, numLineObjs, widthBot, thicknessBot, widthTop, thicknessTop, matProp, centerofGravityBotX, centerofGravityTopY, centerofGravityTopZ, centerofGravityTopX, centerofGravityBotY, centerofGravityBotZ); - var speckleCSIPier = new CSIPier(); - speckleCSIPier.name = name; - SpeckleModel.elements.Add(speckleCSIPier); - return speckleCSIPier; - } + //var speckleCSIPier = new CSIPier(name, numberStories, storyName, axisAngle, numAreaObjs, numLineObjs, widthBot, thicknessBot, widthTop, thicknessTop, matProp, centerofGravityBotX, centerofGravityTopY, centerofGravityTopZ, centerofGravityTopX, centerofGravityBotY, centerofGravityBotZ); + var speckleCSIPier = new CSIPier(); + speckleCSIPier.name = name; + SpeckleModel.elements.Add(speckleCSIPier); + return speckleCSIPier; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPoint.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPoint.cs index 2b36de7dc3..b51a63a240 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPoint.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertPoint.cs @@ -10,178 +10,187 @@ using System.Linq; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string UpdatePoint(string name, Node speckleNode, Point basePoint = null) { - public string UpdatePoint(string name, Node speckleNode, Point basePoint = null) + basePoint = basePoint ?? speckleNode.basePoint; + if (basePoint == null) { - basePoint = basePoint ?? speckleNode.basePoint; - if (basePoint == null) - return name; - - CreatePoint(basePoint, out string newName); - name = newName; - - UpdatePointProperties(speckleNode, ref name); return name; } - public void UpdatePointProperties(Node speckleStructNode, ref string name) - { - if (speckleStructNode == null) - return; + CreatePoint(basePoint, out string newName); + name = newName; - if (speckleStructNode.restraint != null) - { - var restraint = RestraintToNative(speckleStructNode.restraint); - Model.PointObj.SetRestraint(name, ref restraint); - } + UpdatePointProperties(speckleNode, ref name); + return name; + } - if (speckleStructNode.name != null) - { - Model.PointObj.ChangeName(name, speckleStructNode.name); - name = speckleStructNode.name; - } + public void UpdatePointProperties(Node speckleStructNode, ref string name) + { + if (speckleStructNode == null) + { + return; + } - if (!(speckleStructNode is CSINode csiNode)) - return; + if (speckleStructNode.restraint != null) + { + var restraint = RestraintToNative(speckleStructNode.restraint); + Model.PointObj.SetRestraint(name, ref restraint); + } - if (csiNode.CSISpringProperty != null) - Model.PointObj.SetSpringAssignment(csiNode.name, csiNode.CSISpringProperty.name); + if (speckleStructNode.name != null) + { + Model.PointObj.ChangeName(name, speckleStructNode.name); + name = speckleStructNode.name; + } - if (csiNode.DiaphragmAssignment != null) - { - switch (csiNode.DiaphragmOption) - { - case DiaphragmOption.Disconnect: - Model.PointObj.SetDiaphragm( - csiNode.name, - eDiaphragmOption.Disconnect, - DiaphragmName: csiNode.DiaphragmAssignment - ); - break; - case DiaphragmOption.DefinedDiaphragm: - Model.PointObj.SetDiaphragm( - csiNode.name, - eDiaphragmOption.DefinedDiaphragm, - DiaphragmName: csiNode.DiaphragmAssignment - ); - break; - case DiaphragmOption.FromShellObject: - Model.PointObj.SetDiaphragm( - csiNode.name, - eDiaphragmOption.FromShellObject, - DiaphragmName: csiNode.DiaphragmAssignment - ); - break; - } - } + if (!(speckleStructNode is CSINode csiNode)) + { + return; } - public string PointToNative(Node speckleStructNode, IList? notes) + if (csiNode.CSISpringProperty != null) { - if (GetAllPointNames(Model).Contains(speckleStructNode.name)) - { - notes?.Add($"node with name {speckleStructNode.name} already exists"); - return speckleStructNode.name; - } + Model.PointObj.SetSpringAssignment(csiNode.name, csiNode.CSISpringProperty.name); + } - var point = speckleStructNode.basePoint; - if (point == null) + if (csiNode.DiaphragmAssignment != null) + { + switch (csiNode.DiaphragmOption) { - throw new ArgumentException($"Node does not have a valid location, {nameof(Node.basePoint)} was null"); + case DiaphragmOption.Disconnect: + Model.PointObj.SetDiaphragm( + csiNode.name, + eDiaphragmOption.Disconnect, + DiaphragmName: csiNode.DiaphragmAssignment + ); + break; + case DiaphragmOption.DefinedDiaphragm: + Model.PointObj.SetDiaphragm( + csiNode.name, + eDiaphragmOption.DefinedDiaphragm, + DiaphragmName: csiNode.DiaphragmAssignment + ); + break; + case DiaphragmOption.FromShellObject: + Model.PointObj.SetDiaphragm( + csiNode.name, + eDiaphragmOption.FromShellObject, + DiaphragmName: csiNode.DiaphragmAssignment + ); + break; } + } + } - var success = CreatePoint(point, out string name); - UpdatePointProperties(speckleStructNode, ref name); - - if (success != 0) - throw new ConversionException("Failed create point"); - + public string PointToNative(Node speckleStructNode, IList? notes) + { + if (GetAllPointNames(Model).Contains(speckleStructNode.name)) + { + notes?.Add($"node with name {speckleStructNode.name} already exists"); return speckleStructNode.name; } - public int CreatePoint(Point point, out string name) + var point = speckleStructNode.basePoint; + if (point == null) { - var scaleFactor = Units.GetConversionFactor(point.units, ModelUnits()); - - name = null; - var success = Model.PointObj.AddCartesian( - point.x * scaleFactor, - point.y * scaleFactor, - point.z * scaleFactor, - ref name - ); - return success; + throw new ArgumentException($"Node does not have a valid location, {nameof(Node.basePoint)} was null"); } - public CSINode PointToSpeckle(string name) + var success = CreatePoint(point, out string name); + UpdatePointProperties(speckleStructNode, ref name); + + if (success != 0) { - var speckleStructNode = new CSINode(); - double x, - y, - z; - x = y = z = 0; - int v = Model.PointObj.GetCoordCartesian(name, ref x, ref y, ref z); - speckleStructNode.basePoint = new Point(); - speckleStructNode.basePoint.x = x; - speckleStructNode.basePoint.y = y; - speckleStructNode.basePoint.z = z; - speckleStructNode.name = name; - speckleStructNode.units = ModelUnits(); - speckleStructNode.basePoint.units = ModelUnits(); - - bool[] restraints = null; - v = Model.PointObj.GetRestraint(name, ref restraints); - - speckleStructNode.restraint = RestraintToSpeckle(restraints); - - SpeckleModel?.restraints.Add(speckleStructNode.restraint); - - string SpringProp = null; - Model.PointObj.GetSpringAssignment(name, ref SpringProp); - if (SpringProp != null) - { - speckleStructNode.CSISpringProperty = SpringPropertyToSpeckle(SpringProp); - } + throw new ConversionException("Failed create point"); + } - string diaphragmAssignment = null; - eDiaphragmOption eDiaphragmOption = eDiaphragmOption.Disconnect; - Model.PointObj.GetDiaphragm(name, ref eDiaphragmOption, ref diaphragmAssignment); - if (diaphragmAssignment != null) - { - speckleStructNode.DiaphragmAssignment = diaphragmAssignment; - switch (eDiaphragmOption) - { - case eDiaphragmOption.Disconnect: - speckleStructNode.DiaphragmOption = DiaphragmOption.Disconnect; - break; - case eDiaphragmOption.FromShellObject: - speckleStructNode.DiaphragmOption = DiaphragmOption.FromShellObject; - break; - case eDiaphragmOption.DefinedDiaphragm: - speckleStructNode.DiaphragmOption = DiaphragmOption.DefinedDiaphragm; - break; - } - } + return speckleStructNode.name; + } - speckleStructNode.AnalysisResults = resultsConverter? - .NodeAnalyticalResultsConverter? - .AnalyticalResultsToSpeckle(speckleStructNode.name); + public int CreatePoint(Point point, out string name) + { + var scaleFactor = Units.GetConversionFactor(point.units, ModelUnits()); + + name = null; + var success = Model.PointObj.AddCartesian( + point.x * scaleFactor, + point.y * scaleFactor, + point.z * scaleFactor, + ref name + ); + return success; + } + + public CSINode PointToSpeckle(string name) + { + var speckleStructNode = new CSINode(); + double x, + y, + z; + x = y = z = 0; + int v = Model.PointObj.GetCoordCartesian(name, ref x, ref y, ref z); + speckleStructNode.basePoint = new Point(); + speckleStructNode.basePoint.x = x; + speckleStructNode.basePoint.y = y; + speckleStructNode.basePoint.z = z; + speckleStructNode.name = name; + speckleStructNode.units = ModelUnits(); + speckleStructNode.basePoint.units = ModelUnits(); + + bool[] restraints = null; + v = Model.PointObj.GetRestraint(name, ref restraints); + + speckleStructNode.restraint = RestraintToSpeckle(restraints); + + SpeckleModel?.restraints.Add(speckleStructNode.restraint); + + string SpringProp = null; + Model.PointObj.GetSpringAssignment(name, ref SpringProp); + if (SpringProp != null) + { + speckleStructNode.CSISpringProperty = SpringPropertyToSpeckle(SpringProp); + } - var GUID = ""; - Model.PointObj.GetGUID(name, ref GUID); - speckleStructNode.applicationId = GUID; - List nodes = SpeckleModel == null ? new List() : SpeckleModel.nodes; - List application_Id = nodes.Select(o => o.applicationId).ToList(); - if (!application_Id.Contains(speckleStructNode.applicationId)) + string diaphragmAssignment = null; + eDiaphragmOption eDiaphragmOption = eDiaphragmOption.Disconnect; + Model.PointObj.GetDiaphragm(name, ref eDiaphragmOption, ref diaphragmAssignment); + if (diaphragmAssignment != null) + { + speckleStructNode.DiaphragmAssignment = diaphragmAssignment; + switch (eDiaphragmOption) { - SpeckleModel?.nodes.Add(speckleStructNode); + case eDiaphragmOption.Disconnect: + speckleStructNode.DiaphragmOption = DiaphragmOption.Disconnect; + break; + case eDiaphragmOption.FromShellObject: + speckleStructNode.DiaphragmOption = DiaphragmOption.FromShellObject; + break; + case eDiaphragmOption.DefinedDiaphragm: + speckleStructNode.DiaphragmOption = DiaphragmOption.DefinedDiaphragm; + break; } - //SpeckleModel.nodes.Add(speckleStructNode); + } + + speckleStructNode.AnalysisResults = resultsConverter?.NodeAnalyticalResultsConverter?.AnalyticalResultsToSpeckle( + speckleStructNode.name + ); - return speckleStructNode; + var GUID = ""; + Model.PointObj.GetGUID(name, ref GUID); + speckleStructNode.applicationId = GUID; + List nodes = SpeckleModel == null ? new List() : SpeckleModel.nodes; + List application_Id = nodes.Select(o => o.applicationId).ToList(); + if (!application_Id.Contains(speckleStructNode.applicationId)) + { + SpeckleModel?.nodes.Add(speckleStructNode); } + //SpeckleModel.nodes.Add(speckleStructNode); + + return speckleStructNode; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertSpandrel.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertSpandrel.cs index 7a3bb18e64..45bf5b8d20 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertSpandrel.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertSpandrel.cs @@ -1,4 +1,4 @@ -using System; +using System; using Objects.Structural.Geometry; using Objects.Geometry; using Objects.Structural.Analysis; @@ -10,78 +10,77 @@ using CSiAPIv1; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void SpandrelToNative(CSISpandrel spandrel) { - public void SpandrelToNative(CSISpandrel spandrel) - { - Model.SpandrelLabel.SetSpandrel(spandrel.name, spandrel.multistory); - } + Model.SpandrelLabel.SetSpandrel(spandrel.name, spandrel.multistory); + } - public CSISpandrel SpandrelToSpeckle(string name) - { - int numberStories = 0; - string[] storyName = null; - int[] numAreaObjs = null; - int[] numLineObjs = null; - double[] length = null; - double[] depthLeft = null; - double[] thickLeft = null; - double[] depthRight = null; - double[] thickRight = null; - string[] matProp = null; - double[] centerofGravityLeftX = null; - double[] centerofGravityLeftY = null; - double[] centerofGravityLeftZ = null; - double[] centerofGravityRightX = null; - double[] centerofGravityRightY = null; - double[] centerofGravityRightZ = null; + public CSISpandrel SpandrelToSpeckle(string name) + { + int numberStories = 0; + string[] storyName = null; + int[] numAreaObjs = null; + int[] numLineObjs = null; + double[] length = null; + double[] depthLeft = null; + double[] thickLeft = null; + double[] depthRight = null; + double[] thickRight = null; + string[] matProp = null; + double[] centerofGravityLeftX = null; + double[] centerofGravityLeftY = null; + double[] centerofGravityLeftZ = null; + double[] centerofGravityRightX = null; + double[] centerofGravityRightY = null; + double[] centerofGravityRightZ = null; - Model.SpandrelLabel.GetSectionProperties( - name, - ref numberStories, - ref storyName, - ref numAreaObjs, - ref numLineObjs, - ref length, - ref depthLeft, - ref thickLeft, - ref depthRight, - ref thickRight, - ref matProp, - ref centerofGravityLeftX, - ref centerofGravityLeftY, - ref centerofGravityLeftZ, - ref centerofGravityRightX, - ref centerofGravityRightY, - ref centerofGravityRightZ - ); - bool multistory = false; - Model.SpandrelLabel.GetSpandrel(name, ref multistory); + Model.SpandrelLabel.GetSectionProperties( + name, + ref numberStories, + ref storyName, + ref numAreaObjs, + ref numLineObjs, + ref length, + ref depthLeft, + ref thickLeft, + ref depthRight, + ref thickRight, + ref matProp, + ref centerofGravityLeftX, + ref centerofGravityLeftY, + ref centerofGravityLeftZ, + ref centerofGravityRightX, + ref centerofGravityRightY, + ref centerofGravityRightZ + ); + bool multistory = false; + Model.SpandrelLabel.GetSpandrel(name, ref multistory); - var speckleCSISpandrel = new CSISpandrel( - name, - multistory, - numberStories, - storyName, - numAreaObjs, - numLineObjs, - length, - depthLeft, - thickLeft, - depthRight, - thickRight, - matProp, - centerofGravityLeftX, - centerofGravityLeftY, - centerofGravityLeftZ, - centerofGravityRightX, - centerofGravityRightY, - centerofGravityRightZ - ); - SpeckleModel.elements.Add(speckleCSISpandrel); - return speckleCSISpandrel; - } + var speckleCSISpandrel = new CSISpandrel( + name, + multistory, + numberStories, + storyName, + numAreaObjs, + numLineObjs, + length, + depthLeft, + thickLeft, + depthRight, + thickRight, + matProp, + centerofGravityLeftX, + centerofGravityLeftY, + centerofGravityLeftZ, + centerofGravityRightX, + centerofGravityRightY, + centerofGravityRightZ + ); + SpeckleModel.elements.Add(speckleCSISpandrel); + return speckleCSISpandrel; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertStories.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertStories.cs index 9457a6dc7b..da3afb8a3f 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertStories.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertStories.cs @@ -1,99 +1,100 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Objects.Structural.CSI.Analysis; using System.Linq; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public List StoriesToNative(CSIStories stories) { - public List StoriesToNative(CSIStories stories) - { - string[] storyNames = new string[stories.NumberStories]; - double[] storyElevations = new double[stories.NumberStories]; - double[] storyHeights = new double[stories.NumberStories]; - bool[] isMasterStory = new bool[stories.NumberStories]; - string[] similarToStory = new string[stories.NumberStories]; - bool[] spliceAbove = new bool[stories.NumberStories]; - double[] spliceHeight = new double[stories.NumberStories]; - int[] colors = new int[stories.NumberStories]; - - for (int i = 0; i < stories.NumberStories; i++) - { - storyNames[i] = stories.CSIStory[i].name; - storyElevations[i] = stories.CSIStory[i].elevation; - storyHeights[i] = stories.CSIStory[i].storeyHeight; - isMasterStory[i] = stories.CSIStory[i].IsMasterStory; - similarToStory[i] = stories.CSIStory[i].SimilarToStory; - spliceAbove[i] = stories.CSIStory[i].SpliceAbove; - spliceHeight[i] = stories.CSIStory[i].SpliceHeight; - colors[i] = stories.CSIStory[i].Color; - } - var success = Model.Story.SetStories_2( - stories.BaseElevation, - stories.NumberStories, - ref storyNames, - ref storyHeights, - ref isMasterStory, - ref similarToStory, - ref spliceAbove, - ref spliceHeight, - ref colors - ); + string[] storyNames = new string[stories.NumberStories]; + double[] storyElevations = new double[stories.NumberStories]; + double[] storyHeights = new double[stories.NumberStories]; + bool[] isMasterStory = new bool[stories.NumberStories]; + string[] similarToStory = new string[stories.NumberStories]; + bool[] spliceAbove = new bool[stories.NumberStories]; + double[] spliceHeight = new double[stories.NumberStories]; + int[] colors = new int[stories.NumberStories]; - if (success != 0) - throw new ConversionException("Failed to set the stories"); - - return storyNames.ToList(); + for (int i = 0; i < stories.NumberStories; i++) + { + storyNames[i] = stories.CSIStory[i].name; + storyElevations[i] = stories.CSIStory[i].elevation; + storyHeights[i] = stories.CSIStory[i].storeyHeight; + isMasterStory[i] = stories.CSIStory[i].IsMasterStory; + similarToStory[i] = stories.CSIStory[i].SimilarToStory; + spliceAbove[i] = stories.CSIStory[i].SpliceAbove; + spliceHeight[i] = stories.CSIStory[i].SpliceHeight; + colors[i] = stories.CSIStory[i].Color; } + var success = Model.Story.SetStories_2( + stories.BaseElevation, + stories.NumberStories, + ref storyNames, + ref storyHeights, + ref isMasterStory, + ref similarToStory, + ref spliceAbove, + ref spliceHeight, + ref colors + ); - public CSIStories StoriesToSpeckle() + if (success != 0) { - double baseElevation = 0; - int[] colors = null; - string[] names = null; - double[] storyElevations = null; - double[] storyHeights = null; - bool[] isMasterStory = null; - string[] SimilarToStory = null; - bool[] spliceAbove = null; - double[] spliceHeight = null; - int numberOfStories = 0; + throw new ConversionException("Failed to set the stories"); + } - var s = Model.Story.GetStories_2( - ref baseElevation, - ref numberOfStories, - ref names, - ref storyElevations, - ref storyHeights, - ref isMasterStory, - ref SimilarToStory, - ref spliceAbove, - ref spliceHeight, - ref colors - ); + return storyNames.ToList(); + } - var speckleStories = new CSIStories(); - speckleStories.BaseElevation = baseElevation; - speckleStories.NumberStories = numberOfStories; - speckleStories.CSIStory = new List { }; - for (int index = 0; index < numberOfStories; index++) - { - var speckleStory = new CSIStorey( - names[index], - storyElevations[index], - storyHeights[index], - isMasterStory[index], - SimilarToStory[index], - spliceAbove[index], - spliceHeight[index] - ); - speckleStories.CSIStory.Add(speckleStory); - } + public CSIStories StoriesToSpeckle() + { + double baseElevation = 0; + int[] colors = null; + string[] names = null; + double[] storyElevations = null; + double[] storyHeights = null; + bool[] isMasterStory = null; + string[] SimilarToStory = null; + bool[] spliceAbove = null; + double[] spliceHeight = null; + int numberOfStories = 0; - //SpeckleModel.elements.Add(speckleStories); + var s = Model.Story.GetStories_2( + ref baseElevation, + ref numberOfStories, + ref names, + ref storyElevations, + ref storyHeights, + ref isMasterStory, + ref SimilarToStory, + ref spliceAbove, + ref spliceHeight, + ref colors + ); - return speckleStories; + var speckleStories = new CSIStories(); + speckleStories.BaseElevation = baseElevation; + speckleStories.NumberStories = numberOfStories; + speckleStories.CSIStory = new List { }; + for (int index = 0; index < numberOfStories; index++) + { + var speckleStory = new CSIStorey( + names[index], + storyElevations[index], + storyHeights[index], + isMasterStory[index], + SimilarToStory[index], + spliceAbove[index], + spliceHeight[index] + ); + speckleStories.CSIStory.Add(speckleStory); } + + //SpeckleModel.elements.Add(speckleStories); + + return speckleStories; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertTendon.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertTendon.cs index 4c9b2092d0..a9ef987736 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertTendon.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertTendon.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using CSiAPIv1; @@ -9,40 +9,39 @@ using Objects.Geometry; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void CSITendonToSpeckle(CSITendon tendon) { - public void CSITendonToSpeckle(CSITendon tendon) - { - throw new NotSupportedException(); - } + throw new NotSupportedException(); + } - public CSITendon CSITendonToSpeckle(string name) + public CSITendon CSITendonToSpeckle(string name) + { + var speckleCSITendon = new CSITendon(); + int numberPoints = 0; + double[] X = null; + double[] Y = null; + double[] Z = null; + Model.TendonObj.GetTendonGeometry(name, ref numberPoints, ref X, ref Y, ref Z); + if (numberPoints != 0) { - var speckleCSITendon = new CSITendon(); - int numberPoints = 0; - double[] X = null; - double[] Y = null; - double[] Z = null; - Model.TendonObj.GetTendonGeometry(name, ref numberPoints, ref X, ref Y, ref Z); - if (numberPoints != 0) + var polyLine = new Polycurve(); + for (int i = 0; i < numberPoints - 1; i++) { - var polyLine = new Polycurve(); - for (int i = 0; i < numberPoints - 1; i++) - { - var pt1 = new Point(X[i], Y[i], Z[i]); - var pt2 = new Point(X[i + 1], Y[i + 1], Z[i + 1]); - var line = new Line(pt1, pt2); - polyLine.segments.Add(line); - } - speckleCSITendon.polycurve = polyLine; + var pt1 = new Point(X[i], Y[i], Z[i]); + var pt2 = new Point(X[i + 1], Y[i + 1], Z[i + 1]); + var line = new Line(pt1, pt2); + polyLine.segments.Add(line); } - string tendonProp = null; - Model.TendonObj.GetProperty(name, ref tendonProp); - speckleCSITendon.CSITendonProperty = TendonPropToSpeckle(tendonProp); - SpeckleModel.elements.Add(speckleCSITendon); - return speckleCSITendon; + speckleCSITendon.polycurve = polyLine; } + string tendonProp = null; + Model.TendonObj.GetProperty(name, ref tendonProp); + speckleCSITendon.CSITendonProperty = TendonPropToSpeckle(tendonProp); + SpeckleModel.elements.Add(speckleCSITendon); + return speckleCSITendon; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertWall.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertWall.cs index 7c47491c31..7ba11eb2ac 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertWall.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Geometry/ConvertWall.cs @@ -1,12 +1,11 @@ -using Objects.Structural.Geometry; +using Objects.Structural.Geometry; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Element2D WallToSpeckle(string name) { - public Element2D WallToSpeckle(string name) - { - return AreaToSpeckle(name); - } + return AreaToSpeckle(name); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadCombination.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadCombination.cs index 623b528362..b48e659980 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadCombination.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadCombination.cs @@ -6,58 +6,61 @@ using Objects.Structural.Loading; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public LoadCombination LoadCombinationToSpeckle(string loadComboName) { - public LoadCombination LoadCombinationToSpeckle(string loadComboName) + int numItems = 0; + eCNameType[] cNameTypes = null; + string[] loadCaseNames = null; + double[] scaleFactors = null; + int success = Model.RespCombo.GetCaseList( + loadComboName, + ref numItems, + ref cNameTypes, + ref loadCaseNames, + ref scaleFactors + ); + ApiResultValidator.ThrowIfUnsuccessful( + success, + $"Unable to get load cases for load combination named {loadComboName}" + ); + + List factors = new(); + List loadCases = new(); + for (int i = 0; i < numItems; i++) { - int numItems = 0; - eCNameType[] cNameTypes = null; - string[] loadCaseNames = null; - double[] scaleFactors = null; - int success = Model.RespCombo.GetCaseList( - loadComboName, - ref numItems, - ref cNameTypes, - ref loadCaseNames, - ref scaleFactors); - ApiResultValidator.ThrowIfUnsuccessful(success, $"Unable to get load cases for load combination named {loadComboName}"); + string loadCaseName = loadCaseNames[i]; + LoadCase loadCase = LoadPatternToSpeckle(loadCaseName); - List factors = new(); - List loadCases = new(); - for (int i = 0; i < numItems; i++) - { - string loadCaseName = loadCaseNames[i]; - LoadCase loadCase = LoadPatternToSpeckle(loadCaseName); + factors.Add(scaleFactors[i]); + loadCases.Add(loadCase); + } + CombinationType type = GetCombinationType(loadComboName); - factors.Add(scaleFactors[i]); - loadCases.Add(loadCase); - } - CombinationType type = GetCombinationType(loadComboName); + return new LoadCombination(loadComboName, loadCases.Cast().ToList(), factors, type); + } - return new LoadCombination(loadComboName, loadCases.Cast().ToList(), factors, type); + private CombinationType GetCombinationType(string loadComboName) + { + int comboType = 0; + int success = Model.RespCombo.GetTypeCombo(loadComboName, ref comboType); + if (!ApiResultValidator.IsSuccessful(success)) + { + // todo : add default (unset) value for this enum? + return CombinationType.LinearAdd; } - private CombinationType GetCombinationType(string loadComboName) + return comboType switch { - int comboType = 0; - int success = Model.RespCombo.GetTypeCombo(loadComboName, ref comboType); - if (!ApiResultValidator.IsSuccessful(success)) - { - // todo : add default (unset) value for this enum? - return CombinationType.LinearAdd; - } - - return comboType switch - { - 0 => CombinationType.LinearAdd, - 1 => CombinationType.Envelope, - 2 => CombinationType.AbsoluteAdd, - 3 => CombinationType.SRSS, - 4 => CombinationType.RangeAdd, - _ => CombinationType.LinearAdd - }; - } + 0 => CombinationType.LinearAdd, + 1 => CombinationType.Envelope, + 2 => CombinationType.AbsoluteAdd, + 3 => CombinationType.SRSS, + 4 => CombinationType.RangeAdd, + _ => CombinationType.LinearAdd + }; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadPattern.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadPattern.cs index b6351a28ab..aa3e879195 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadPattern.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/ConvertLoadPattern.cs @@ -1,134 +1,133 @@ using CSiAPIv1; using Objects.Structural.Loading; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public void LoadPatternToNative(LoadGravity gravityLoad) { - public void LoadPatternToNative(LoadGravity gravityLoad) - { - var selfweight = -1 * gravityLoad.gravityFactors.z; - var loadType = GetAndConvertToCSIPatternType(gravityLoad.loadCase.loadType); - Model.LoadPatterns.Add(gravityLoad.name, loadType, selfweight); - } - - public LoadCase LoadPatternToSpeckle(string loadPatternName) - { - LoadCase speckleLoadCase = new(); - speckleLoadCase.loadType = GetAndConvertCSILoadType(loadPatternName); - speckleLoadCase.name = loadPatternName; + var selfweight = -1 * gravityLoad.gravityFactors.z; + var loadType = GetAndConvertToCSIPatternType(gravityLoad.loadCase.loadType); + Model.LoadPatterns.Add(gravityLoad.name, loadType, selfweight); + } - // load pattern name cannot be duplicated in etabs, so safe for applicationId use - speckleLoadCase.applicationId = loadPatternName; + public LoadCase LoadPatternToSpeckle(string loadPatternName) + { + LoadCase speckleLoadCase = new(); + speckleLoadCase.loadType = GetAndConvertCSILoadType(loadPatternName); + speckleLoadCase.name = loadPatternName; - var selfWeight = GetSelfWeightMultiplier(loadPatternName); + // load pattern name cannot be duplicated in etabs, so safe for applicationId use + speckleLoadCase.applicationId = loadPatternName; - //Encoding loadPatterns selfWeight multiplier within - if (selfWeight != 0) - { - var gravityVector = new Geometry.Vector(0, 0, -selfWeight); - var gravityLoad = new LoadGravity(speckleLoadCase, gravityVector); - gravityLoad.name = loadPatternName; + var selfWeight = GetSelfWeightMultiplier(loadPatternName); - gravityLoad.applicationId = $"{loadPatternName}:self-weight"; + //Encoding loadPatterns selfWeight multiplier within + if (selfWeight != 0) + { + var gravityVector = new Geometry.Vector(0, 0, -selfWeight); + var gravityLoad = new LoadGravity(speckleLoadCase, gravityVector); + gravityLoad.name = loadPatternName; - SpeckleModel.loads.Add(gravityLoad); - } - if (!SpeckleModel.loads.Contains(speckleLoadCase)) - { - SpeckleModel.loads.Add(speckleLoadCase); - } + gravityLoad.applicationId = $"{loadPatternName}:self-weight"; - return speckleLoadCase; + SpeckleModel.loads.Add(gravityLoad); } - - public LoadCase LoadPatternCaseToSpeckle(string loadPatternName) + if (!SpeckleModel.loads.Contains(speckleLoadCase)) { - //Converts just the load case name - var speckleLoadCase = new LoadCase(); - speckleLoadCase.loadType = GetAndConvertCSILoadType(loadPatternName); - speckleLoadCase.name = loadPatternName; - - // load pattern name cannot be duplicated in etabs, so safe for applicationId use - speckleLoadCase.applicationId = loadPatternName; - - if (!SpeckleModel.loads.Contains(speckleLoadCase)) { } - else - { - SpeckleModel.loads.Add(speckleLoadCase); - } - return speckleLoadCase; + SpeckleModel.loads.Add(speckleLoadCase); } - public eLoadPatternType GetAndConvertToCSIPatternType(LoadType loadType) + return speckleLoadCase; + } + + public LoadCase LoadPatternCaseToSpeckle(string loadPatternName) + { + //Converts just the load case name + var speckleLoadCase = new LoadCase(); + speckleLoadCase.loadType = GetAndConvertCSILoadType(loadPatternName); + speckleLoadCase.name = loadPatternName; + + // load pattern name cannot be duplicated in etabs, so safe for applicationId use + speckleLoadCase.applicationId = loadPatternName; + + if (!SpeckleModel.loads.Contains(speckleLoadCase)) { } + else { - switch (loadType) - { - case LoadType.Dead: - return eLoadPatternType.Dead; - case LoadType.SuperDead: - return eLoadPatternType.SuperDead; - case LoadType.Live: - return eLoadPatternType.Live; - case LoadType.ReducibleLive: - return eLoadPatternType.ReduceLive; - case LoadType.SeismicStatic: - return eLoadPatternType.Quake; - case LoadType.Snow: - return eLoadPatternType.Snow; - case LoadType.Wind: - return eLoadPatternType.Wind; - case LoadType.Other: - return eLoadPatternType.Other; - default: - return eLoadPatternType.Other; - } + SpeckleModel.loads.Add(speckleLoadCase); } + return speckleLoadCase; + } - public LoadType GetAndConvertCSILoadType(string name) + public eLoadPatternType GetAndConvertToCSIPatternType(LoadType loadType) + { + switch (loadType) { - eLoadPatternType patternType = new eLoadPatternType(); + case LoadType.Dead: + return eLoadPatternType.Dead; + case LoadType.SuperDead: + return eLoadPatternType.SuperDead; + case LoadType.Live: + return eLoadPatternType.Live; + case LoadType.ReducibleLive: + return eLoadPatternType.ReduceLive; + case LoadType.SeismicStatic: + return eLoadPatternType.Quake; + case LoadType.Snow: + return eLoadPatternType.Snow; + case LoadType.Wind: + return eLoadPatternType.Wind; + case LoadType.Other: + return eLoadPatternType.Other; + default: + return eLoadPatternType.Other; + } + } + + public LoadType GetAndConvertCSILoadType(string name) + { + eLoadPatternType patternType = new(); - Model.LoadPatterns.GetLoadType(name, ref patternType); + Model.LoadPatterns.GetLoadType(name, ref patternType); - switch (patternType) - { - case eLoadPatternType.Dead: - return LoadType.Dead; + switch (patternType) + { + case eLoadPatternType.Dead: + return LoadType.Dead; - case eLoadPatternType.SuperDead: - return LoadType.SuperDead; + case eLoadPatternType.SuperDead: + return LoadType.SuperDead; - case eLoadPatternType.Live: - return LoadType.Live; + case eLoadPatternType.Live: + return LoadType.Live; - case eLoadPatternType.ReduceLive: - return LoadType.ReducibleLive; + case eLoadPatternType.ReduceLive: + return LoadType.ReducibleLive; - case eLoadPatternType.Quake: - return LoadType.SeismicStatic; + case eLoadPatternType.Quake: + return LoadType.SeismicStatic; - case eLoadPatternType.Wind: - return LoadType.Wind; + case eLoadPatternType.Wind: + return LoadType.Wind; - case eLoadPatternType.Snow: - return LoadType.Snow; + case eLoadPatternType.Snow: + return LoadType.Snow; - case eLoadPatternType.Other: - return LoadType.Other; + case eLoadPatternType.Other: + return LoadType.Other; - default: - return LoadType.Other; // Other (less frequent) load types to be converted later. - } + default: + return LoadType.Other; // Other (less frequent) load types to be converted later. } + } - public double GetSelfWeightMultiplier(string name) - { - double selfWeightMultiplier = 0; + public double GetSelfWeightMultiplier(string name) + { + double selfWeightMultiplier = 0; - Model.LoadPatterns.GetSelfWTMultiplier(name, ref selfWeightMultiplier); + Model.LoadPatterns.GetSelfWTMultiplier(name, ref selfWeightMultiplier); - return selfWeightMultiplier; - } + return selfWeightMultiplier; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading1DElements.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading1DElements.cs index a5cffab8bd..08d8807006 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading1DElements.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading1DElements.cs @@ -1,4 +1,4 @@ -using Objects.Structural.Loading; +using Objects.Structural.Loading; using System; using System.Collections.Generic; using Objects.Structural.Geometry; @@ -6,418 +6,425 @@ using Speckle.Core.Kits; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + readonly Dictionary _loadStoringBeam = new(); + readonly Dictionary> _frameStoring = new(); + int _counterFrame; + + List LoadFrameToNative(LoadBeam loadBeam, IList? notes) { - readonly Dictionary _loadStoringBeam = new(); - readonly Dictionary> _frameStoring = new(); - int _counterFrame; + int direction = 11; + int myType = 1; - List LoadFrameToNative(LoadBeam loadBeam, IList? notes) + if (loadBeam.isProjected) + { + switch (loadBeam.direction) + { + case LoadDirection.X: + direction = 7; + myType = 1; + break; + case LoadDirection.Y: + direction = 8; + myType = 1; + break; + case LoadDirection.Z: + direction = 9; + myType = 1; + break; + case LoadDirection.XX: + direction = 7; + myType = 2; + break; + case LoadDirection.YY: + direction = 8; + myType = 2; + break; + case LoadDirection.ZZ: + direction = 9; + myType = 2; + break; + default: + throw new ArgumentOutOfRangeException($"Unrecognised load direction {loadBeam.direction}"); + } + } + else if (loadBeam.loadAxisType == Structural.LoadAxisType.Local) { - int direction = 11; - int myType = 1; + switch (loadBeam.direction) + { + case LoadDirection.X: + direction = 1; + myType = 1; + break; + case LoadDirection.Y: + direction = 2; + myType = 1; + break; + case LoadDirection.Z: + direction = 3; + myType = 1; + break; + case LoadDirection.XX: + direction = 1; + myType = 2; + break; + case LoadDirection.YY: + direction = 2; + myType = 2; + break; + case LoadDirection.ZZ: + direction = 3; + myType = 2; + break; + default: + throw new ArgumentOutOfRangeException(nameof(loadBeam), $"Unrecognised load direction {loadBeam.direction}"); + } + } + else + { + switch (loadBeam.direction) + { + case LoadDirection.X: + direction = 4; + myType = 1; + break; + case LoadDirection.Y: + direction = 5; + myType = 1; + break; + case LoadDirection.Z: + direction = 6; + myType = 1; + break; + case LoadDirection.XX: + direction = 4; + myType = 2; + break; + case LoadDirection.YY: + direction = 5; + myType = 2; + break; + case LoadDirection.ZZ: + direction = 6; + myType = 2; + break; + default: + throw new ArgumentOutOfRangeException(nameof(loadBeam), $"Unrecognised load direction {loadBeam.direction}"); + } + } + + List createdElements = new(loadBeam.elements.Count); - if (loadBeam.isProjected) + foreach (var el in loadBeam.elements) + { + if (el is not Element1D element) { - switch (loadBeam.direction) - { - case LoadDirection.X: - direction = 7; - myType = 1; - break; - case LoadDirection.Y: - direction = 8; - myType = 1; - break; - case LoadDirection.Z: - direction = 9; - myType = 1; - break; - case LoadDirection.XX: - direction = 7; - myType = 2; - break; - case LoadDirection.YY: - direction = 8; - myType = 2; - break; - case LoadDirection.ZZ: - direction = 9; - myType = 2; - break; - default: - throw new ArgumentOutOfRangeException($"Unrecognised load direction {loadBeam.direction}"); - } + notes?.Add($"Skipping converting sub-element {el} as is not an {nameof(Element1D)}"); //TODO: is the term "sub-element" correct here? or is there a better word to use? + continue; } - else if (loadBeam.loadAxisType == Structural.LoadAxisType.Local) + + int success; + string name = element.name ?? element.id; + + if (loadBeam.loadType == BeamLoadType.Point) + { + success = Model.FrameObj.SetLoadDistributed( + name, + loadBeam.loadCase.name, + myType, + direction, + loadBeam.positions[0], + loadBeam.positions[1], + loadBeam.values[0], + loadBeam.values[1] + ); + } + else + { + success = Model.FrameObj.SetLoadPoint( + name, + loadBeam.loadCase.name, + myType, + direction, + loadBeam.positions[0], + loadBeam.values[0] + ); + } + + if (success != 0) { - switch (loadBeam.direction) + notes?.Add($"Failed to convert sub-element {element.name}"); + } + } + + if (!createdElements.Any()) + { + throw new ConversionException($"Zero out of {loadBeam.elements.Count} elements converted successfully"); + } + + return createdElements; + } + + Base LoadFrameToSpeckle(string name, int frameNumber) + { + int numberItems = 0; + string[] frameName = null; + string[] loadPat = null; + int[] MyType = null; + string[] csys = null; + int[] dir = null; + double[] RD1 = null; + double[] RD2 = null; + double[] dist1 = null; + double[] dist2 = null; + double[] val1 = null; + double[] val2 = null; + + //var element1DList = new List(); + + int s = Model.FrameObj.GetLoadDistributed( + name, + ref numberItems, + ref frameName, + ref loadPat, + ref MyType, + ref csys, + ref dir, + ref RD1, + ref RD2, + ref dist1, + ref dist2, + ref val1, + ref val2 + ); + if (s == 0) + { + foreach (int index in Enumerable.Range(0, numberItems)) + { + var speckleLoadFrame = new LoadBeam(); + var element = FrameToSpeckle(frameName[index]); + var loadID = String.Concat( + loadPat[index], + val1[index], + val2[index], + dist1[index], + dist2[index], + dir[index], + MyType[index] + ); + speckleLoadFrame.applicationId = loadID; + _frameStoring.TryGetValue(loadID, out var element1DList); + if (element1DList == null) { - case LoadDirection.X: - direction = 1; - myType = 1; - break; - case LoadDirection.Y: - direction = 2; - myType = 1; + element1DList = new List { }; + } + if (!element1DList.Select(el => el.applicationId).Contains(element.applicationId)) + { + element1DList.Add(element); + } + + _frameStoring[loadID] = element1DList; + + switch (dir[index]) + { + case 1: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; break; - case LoadDirection.Z: - direction = 3; - myType = 1; + case 2: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; break; - case LoadDirection.XX: - direction = 1; - myType = 2; + case 3: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; break; - case LoadDirection.YY: - direction = 2; - myType = 2; + case 4: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.ZZ: - direction = 3; - myType = 2; + case 5: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - default: - throw new ArgumentOutOfRangeException( - nameof(loadBeam), - $"Unrecognised load direction {loadBeam.direction}" - ); - } - } - else - { - switch (loadBeam.direction) - { - case LoadDirection.X: - direction = 4; - myType = 1; + case 6: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.Y: - direction = 5; - myType = 1; + case 7: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.Z: - direction = 6; - myType = 1; + case 8: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.XX: - direction = 4; - myType = 2; + case 9: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.YY: - direction = 5; - myType = 2; + case 10: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - case LoadDirection.ZZ: - direction = 6; - myType = 2; + case 11: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; break; - default: - throw new ArgumentOutOfRangeException( - nameof(loadBeam), - $"Unrecognised load direction {loadBeam.direction}" - ); } + if (speckleLoadFrame.values == null) + { + speckleLoadFrame.values = new List { }; + } + speckleLoadFrame.values.Add(val1[index]); + speckleLoadFrame.values.Add(val2[index]); + if (speckleLoadFrame.positions == null) + { + speckleLoadFrame.positions = new List { }; + } + speckleLoadFrame.positions.Add(dist1[index]); + speckleLoadFrame.positions.Add(dist2[index]); + speckleLoadFrame.loadType = BeamLoadType.Uniform; + speckleLoadFrame.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); + _loadStoringBeam[loadID] = speckleLoadFrame; } + _counterFrame += 1; - List createdElements = new(loadBeam.elements.Count); - - foreach (var el in loadBeam.elements) + if (_counterFrame == frameNumber) { - if (el is not Element1D element) + foreach (var entry in _loadStoringBeam.Keys) { - notes?.Add($"Skipping converting sub-element {el} as is not an {nameof(Element1D)}"); //TODO: is the term "sub-element" correct here? or is there a better word to use? - continue; + _loadStoringBeam.TryGetValue(entry, out var loadBeam); + _frameStoring.TryGetValue(entry, out var elements); + loadBeam.elements = elements; + SpeckleModel.loads.Add(loadBeam); } - - int success; - string name = element.name ?? element.id; - - if (loadBeam.loadType == BeamLoadType.Point) - success = Model.FrameObj.SetLoadDistributed( - name, - loadBeam.loadCase.name, - myType, - direction, - loadBeam.positions[0], - loadBeam.positions[1], - loadBeam.values[0], - loadBeam.values[1] - ); - else - success = Model.FrameObj.SetLoadPoint( - name, - loadBeam.loadCase.name, - myType, - direction, - loadBeam.positions[0], - loadBeam.values[0] - ); - - if (success != 0) - notes?.Add($"Failed to convert sub-element {element.name}"); + _counterFrame = 0; } - - if (!createdElements.Any()) - throw new ConversionException($"Zero out of {loadBeam.elements.Count} elements converted successfully"); - - return createdElements; } - Base LoadFrameToSpeckle(string name, int frameNumber) + double[] dist = null; + double[] relDist = null; + double[] val = null; + s = Model.FrameObj.GetLoadPoint( + name, + ref numberItems, + ref frameName, + ref loadPat, + ref MyType, + ref csys, + ref dir, + ref relDist, + ref dist, + ref val + ); + if (s == 0) { - int numberItems = 0; - string[] frameName = null; - string[] loadPat = null; - int[] MyType = null; - string[] csys = null; - int[] dir = null; - double[] RD1 = null; - double[] RD2 = null; - double[] dist1 = null; - double[] dist2 = null; - double[] val1 = null; - double[] val2 = null; - - //var element1DList = new List(); - - int s = Model.FrameObj.GetLoadDistributed( - name, - ref numberItems, - ref frameName, - ref loadPat, - ref MyType, - ref csys, - ref dir, - ref RD1, - ref RD2, - ref dist1, - ref dist2, - ref val1, - ref val2 - ); - if (s == 0) + foreach (int index in Enumerable.Range(0, numberItems)) { - foreach (int index in Enumerable.Range(0, numberItems)) + var speckleLoadFrame = new LoadBeam(); + var element = FrameToSpeckle(frameName[index]); + var loadID = String.Concat(loadPat[index], val, dist[index], dir[index], MyType[index]); + speckleLoadFrame.applicationId = loadID; + _frameStoring.TryGetValue(loadID, out var element1DList); + if (element1DList == null) { - var speckleLoadFrame = new LoadBeam(); - var element = FrameToSpeckle(frameName[index]); - var loadID = String.Concat( - loadPat[index], - val1[index], - val2[index], - dist1[index], - dist2[index], - dir[index], - MyType[index] - ); - speckleLoadFrame.applicationId = loadID; - _frameStoring.TryGetValue(loadID, out var element1DList); - if (element1DList == null) - { - element1DList = new List { }; - } - if (!element1DList.Select(el => el.applicationId).Contains(element.applicationId)) - element1DList.Add(element); - _frameStoring[loadID] = element1DList; - - switch (dir[index]) - { - case 1: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 2: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 3: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 4: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 5: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 6: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 7: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 8: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 9: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 10: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 11: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - } - if (speckleLoadFrame.values == null) - { - speckleLoadFrame.values = new List { }; - } - speckleLoadFrame.values.Add(val1[index]); - speckleLoadFrame.values.Add(val2[index]); - if (speckleLoadFrame.positions == null) - { - speckleLoadFrame.positions = new List { }; - } - speckleLoadFrame.positions.Add(dist1[index]); - speckleLoadFrame.positions.Add(dist2[index]); - speckleLoadFrame.loadType = BeamLoadType.Uniform; - speckleLoadFrame.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); - _loadStoringBeam[loadID] = speckleLoadFrame; + element1DList = new List { }; } - _counterFrame += 1; - - if (_counterFrame == frameNumber) + if (!element1DList.Select(el => el.applicationId).Contains(element.applicationId)) { - foreach (var entry in _loadStoringBeam.Keys) - { - _loadStoringBeam.TryGetValue(entry, out var loadBeam); - _frameStoring.TryGetValue(entry, out var elements); - loadBeam.elements = elements; - SpeckleModel.loads.Add(loadBeam); - } - _counterFrame = 0; + element1DList.Add(element); } - } - double[] dist = null; - double[] relDist = null; - double[] val = null; - s = Model.FrameObj.GetLoadPoint( - name, - ref numberItems, - ref frameName, - ref loadPat, - ref MyType, - ref csys, - ref dir, - ref relDist, - ref dist, - ref val - ); - if (s == 0) - { - foreach (int index in Enumerable.Range(0, numberItems)) - { - var speckleLoadFrame = new LoadBeam(); - var element = FrameToSpeckle(frameName[index]); - var loadID = String.Concat(loadPat[index], val, dist[index], dir[index], MyType[index]); - speckleLoadFrame.applicationId = loadID; - _frameStoring.TryGetValue(loadID, out var element1DList); - if (element1DList == null) - { - element1DList = new List { }; - } - if (!element1DList.Select(el => el.applicationId).Contains(element.applicationId)) - element1DList.Add(element); - _frameStoring[loadID] = element1DList; + _frameStoring[loadID] = element1DList; - switch (dir[index]) - { - case 1: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 2: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 3: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; - break; - case 4: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 5: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 6: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 7: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 8: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 9: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.isProjected = true; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 10: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - case 11: - speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; - speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; - break; - } - if (speckleLoadFrame.values == null) - { - speckleLoadFrame.values = new List { }; - } - speckleLoadFrame.values.Add(val[index]); + switch (dir[index]) + { + case 1: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; + break; + case 2: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; + break; + case 3: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Local; + break; + case 4: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 5: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 6: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 7: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.X : LoadDirection.XX; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 8: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Y : LoadDirection.YY; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 9: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.isProjected = true; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 10: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + case 11: + speckleLoadFrame.direction = (MyType[index] == 1) ? LoadDirection.Z : LoadDirection.ZZ; + speckleLoadFrame.loadAxisType = Structural.LoadAxisType.Global; + break; + } + if (speckleLoadFrame.values == null) + { + speckleLoadFrame.values = new List { }; + } + speckleLoadFrame.values.Add(val[index]); - if (speckleLoadFrame.positions == null) - { - speckleLoadFrame.positions = new List { }; - } - speckleLoadFrame.positions.Add(dist[index]); - speckleLoadFrame.loadType = BeamLoadType.Point; - speckleLoadFrame.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); - _loadStoringBeam[loadID] = speckleLoadFrame; + if (speckleLoadFrame.positions == null) + { + speckleLoadFrame.positions = new List { }; } - _counterFrame += 1; + speckleLoadFrame.positions.Add(dist[index]); + speckleLoadFrame.loadType = BeamLoadType.Point; + speckleLoadFrame.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); + _loadStoringBeam[loadID] = speckleLoadFrame; + } + _counterFrame += 1; - if (_counterFrame == frameNumber) + if (_counterFrame == frameNumber) + { + foreach (var entry in _loadStoringBeam.Keys) { - foreach (var entry in _loadStoringBeam.Keys) - { - _loadStoringBeam.TryGetValue(entry, out var loadBeam); - _frameStoring.TryGetValue(entry, out var elements); - loadBeam.elements = elements; - SpeckleModel.loads.Add(loadBeam); - } - _counterFrame = 0; + _loadStoringBeam.TryGetValue(entry, out var loadBeam); + _frameStoring.TryGetValue(entry, out var elements); + loadBeam.elements = elements; + SpeckleModel.loads.Add(loadBeam); } + _counterFrame = 0; } - var speckleObject = new Base(); - return speckleObject; } + var speckleObject = new Base(); + return speckleObject; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading2DElements.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading2DElements.cs index ef8704c05c..a09ae0b88a 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading2DElements.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/Loading2DElements.cs @@ -1,4 +1,4 @@ -using Objects.Structural.Loading; +using Objects.Structural.Loading; using System; using System.Collections.Generic; using Objects.Structural.Geometry; @@ -7,231 +7,232 @@ using Objects.Structural.CSI.Loading; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI - { - readonly Dictionary _loadStoringArea = new(); - readonly Dictionary> _areaStoring = new(); - int _counterAreaLoadUniform; - int _counterAreaLoadWind; + readonly Dictionary _loadStoringArea = new(); + readonly Dictionary> _areaStoring = new(); + int _counterAreaLoadUniform; + int _counterAreaLoadWind; - string LoadFaceToNative(LoadFace loadFace, IList? notes) + string LoadFaceToNative(LoadFace loadFace, IList? notes) + { + List convertedNames = new(loadFace.elements.Count); + foreach (Base e in loadFace.elements) { - List convertedNames = new(loadFace.elements.Count); - foreach (Base e in loadFace.elements) + if (e is not Element2D element) { - if (e is not Element2D element) - { - notes?.Add($"Expected all elements to be of type {nameof(Element2D)}, other types ignored"); - continue; - } + notes?.Add($"Expected all elements to be of type {nameof(Element2D)}, other types ignored"); + continue; + } - if (loadFace.loadType != FaceLoadType.Constant) // TODO: support other load types - { - notes?.Add($"Only {nameof(FaceLoadType.Constant)} are supported, other types ignored"); - continue; - } + if (loadFace.loadType != FaceLoadType.Constant) // TODO: support other load types + { + notes?.Add($"Only {nameof(FaceLoadType.Constant)} are supported, other types ignored"); + continue; + } - string elementName = element.name ?? element.id; + string elementName = element.name ?? element.id; - int dir = loadFace.direction switch - { - LoadDirection2D.X => 4, - LoadDirection2D.Y => 5, - LoadDirection2D.Z => 6, - _ => throw new ArgumentOutOfRangeException($"Unrecognised {nameof(LoadDirection2D)} {loadFace.direction}") - }; + int dir = loadFace.direction switch + { + LoadDirection2D.X => 4, + LoadDirection2D.Y => 5, + LoadDirection2D.Z => 6, + _ => throw new ArgumentOutOfRangeException($"Unrecognised {nameof(LoadDirection2D)} {loadFace.direction}") + }; - int success = Model.AreaObj.SetLoadUniform(elementName, loadFace.loadCase.name, loadFace.values[0], dir); + int success = Model.AreaObj.SetLoadUniform(elementName, loadFace.loadCase.name, loadFace.values[0], dir); - //TODO: if one element fails, should all? - if (success != 0) - { - notes?.Add($"Failed to assign uniform load to sub-element {elementName}"); - continue; - } - convertedNames.Add(elementName); + //TODO: if one element fails, should all? + if (success != 0) + { + notes?.Add($"Failed to assign uniform load to sub-element {elementName}"); + continue; } + convertedNames.Add(elementName); + } - if (!convertedNames.Any()) - throw new ConversionException($"Zero out of {loadFace.elements.Count} sub-elements converted successfully"); + if (!convertedNames.Any()) + { + throw new ConversionException($"Zero out of {loadFace.elements.Count} sub-elements converted successfully"); + } + + return loadFace.name; //TODO: why return loadFace name here? is there an object with that name? + } - return loadFace.name; //TODO: why return loadFace name here? is there an object with that name? + void LoadWindToNative(CSIWindLoadingFace windLoadingFace) + { + foreach (Element2D element in windLoadingFace.elements) + { + switch (windLoadingFace.WindPressureType) + { + case Structural.CSI.Analysis.WindPressureType.Windward: + Model.AreaObj.SetLoadWindPressure(element.name, windLoadingFace.loadCase.name, 1, windLoadingFace.Cp); + break; + case Structural.CSI.Analysis.WindPressureType.other: + Model.AreaObj.SetLoadWindPressure(element.name, windLoadingFace.loadCase.name, 2, windLoadingFace.Cp); + break; + } } + } - void LoadWindToNative(CSIWindLoadingFace windLoadingFace) + Base LoadFaceToSpeckle(string name, int areaNumber) + { + int numberItems = 0; + string[] areaName = null; + string[] loadPat = null; + string[] csys = null; + int[] dir = null; + double[] value = null; + int s = Model.AreaObj.GetLoadUniform( + name, + ref numberItems, + ref areaName, + ref loadPat, + ref csys, + ref dir, + ref value + ); + if (s == 0) { - foreach (Element2D element in windLoadingFace.elements) + foreach (int index in Enumerable.Range(0, numberItems)) { - switch (windLoadingFace.WindPressureType) + var speckleLoadFace = new LoadFace(); + var element = AreaToSpeckle(areaName[index]); + var loadID = string.Concat(loadPat[index], csys[index], dir[index], value[index]); + speckleLoadFace.applicationId = loadID; + _areaStoring.TryGetValue(loadID, out var element2Dlist); + if (element2Dlist == null) { - case Structural.CSI.Analysis.WindPressureType.Windward: - Model.AreaObj.SetLoadWindPressure(element.name, windLoadingFace.loadCase.name, 1, windLoadingFace.Cp); + element2Dlist = new List { }; + } + element2Dlist.Add(element); + _areaStoring[loadID] = element2Dlist; + + switch (dir[index]) + { + case 1: + speckleLoadFace.direction = LoadDirection2D.X; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; + break; + case 2: + speckleLoadFace.direction = LoadDirection2D.Y; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; + break; + case 3: + speckleLoadFace.direction = LoadDirection2D.Z; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; + break; + case 4: + speckleLoadFace.direction = LoadDirection2D.X; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + case 5: + speckleLoadFace.direction = LoadDirection2D.Y; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; break; - case Structural.CSI.Analysis.WindPressureType.other: - Model.AreaObj.SetLoadWindPressure(element.name, windLoadingFace.loadCase.name, 2, windLoadingFace.Cp); + case 6: + speckleLoadFace.direction = LoadDirection2D.Z; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; break; + case 7: + speckleLoadFace.direction = LoadDirection2D.X; + speckleLoadFace.isProjected = true; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + case 8: + speckleLoadFace.direction = LoadDirection2D.Y; + speckleLoadFace.isProjected = true; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + case 9: + speckleLoadFace.direction = LoadDirection2D.Z; + speckleLoadFace.isProjected = true; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + case 10: + speckleLoadFace.direction = LoadDirection2D.Z; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + case 11: + speckleLoadFace.direction = LoadDirection2D.Z; + speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; + break; + } + if (speckleLoadFace.values == null) + { + speckleLoadFace.values = new List { }; } + speckleLoadFace.values.Add(value[index]); + speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); + _loadStoringArea[loadID] = speckleLoadFace; + speckleLoadFace.loadType = FaceLoadType.Constant; + } + _counterAreaLoadUniform += 1; + if (_counterAreaLoadUniform == areaNumber) + { + foreach (var entry in _loadStoringArea.Keys) + { + _loadStoringArea.TryGetValue(entry, out var loadFace); + _areaStoring.TryGetValue(entry, out var areas); + loadFace.elements = areas; + SpeckleModel.loads.Add(loadFace); + } + _counterAreaLoadUniform = 0; } } - Base LoadFaceToSpeckle(string name, int areaNumber) + int[] myType = null; + double[] cp = null; + s = Model.AreaObj.GetLoadWindPressure(name, ref numberItems, ref areaName, ref loadPat, ref myType, ref cp); + if (s == 0) { - int numberItems = 0; - string[] areaName = null; - string[] loadPat = null; - string[] csys = null; - int[] dir = null; - double[] value = null; - int s = Model.AreaObj.GetLoadUniform( - name, - ref numberItems, - ref areaName, - ref loadPat, - ref csys, - ref dir, - ref value - ); - if (s == 0) + foreach (int index in Enumerable.Range(0, numberItems)) { - foreach (int index in Enumerable.Range(0, numberItems)) + var speckleLoadFace = new CSIWindLoadingFace(); + var element = AreaToSpeckle(areaName[index]); + var loadID = string.Concat(loadPat[index], myType[index], cp[index]); + speckleLoadFace.applicationId = loadID; + _areaStoring.TryGetValue(loadID, out var element2Dlist); + if (element2Dlist == null) { - var speckleLoadFace = new LoadFace(); - var element = AreaToSpeckle(areaName[index]); - var loadID = string.Concat(loadPat[index], csys[index], dir[index], value[index]); - speckleLoadFace.applicationId = loadID; - _areaStoring.TryGetValue(loadID, out var element2Dlist); - if (element2Dlist == null) - { - element2Dlist = new List { }; - } - element2Dlist.Add(element); - _areaStoring[loadID] = element2Dlist; - - switch (dir[index]) - { - case 1: - speckleLoadFace.direction = LoadDirection2D.X; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; - break; - case 2: - speckleLoadFace.direction = LoadDirection2D.Y; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; - break; - case 3: - speckleLoadFace.direction = LoadDirection2D.Z; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Local; - break; - case 4: - speckleLoadFace.direction = LoadDirection2D.X; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 5: - speckleLoadFace.direction = LoadDirection2D.Y; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 6: - speckleLoadFace.direction = LoadDirection2D.Z; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 7: - speckleLoadFace.direction = LoadDirection2D.X; - speckleLoadFace.isProjected = true; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 8: - speckleLoadFace.direction = LoadDirection2D.Y; - speckleLoadFace.isProjected = true; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 9: - speckleLoadFace.direction = LoadDirection2D.Z; - speckleLoadFace.isProjected = true; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 10: - speckleLoadFace.direction = LoadDirection2D.Z; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - case 11: - speckleLoadFace.direction = LoadDirection2D.Z; - speckleLoadFace.loadAxisType = Structural.LoadAxisType.Global; - break; - } - if (speckleLoadFace.values == null) - { - speckleLoadFace.values = new List { }; - } - speckleLoadFace.values.Add(value[index]); - speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); - _loadStoringArea[loadID] = speckleLoadFace; - speckleLoadFace.loadType = FaceLoadType.Constant; + element2Dlist = new List { }; } - _counterAreaLoadUniform += 1; - if (_counterAreaLoadUniform == areaNumber) + element2Dlist.Add(element); + _areaStoring[loadID] = element2Dlist; + if (speckleLoadFace.values == null) { - foreach (var entry in _loadStoringArea.Keys) - { - _loadStoringArea.TryGetValue(entry, out var loadFace); - _areaStoring.TryGetValue(entry, out var areas); - loadFace.elements = areas; - SpeckleModel.loads.Add(loadFace); - } - _counterAreaLoadUniform = 0; + speckleLoadFace.values = new List { }; } - } - - int[] myType = null; - double[] cp = null; - s = Model.AreaObj.GetLoadWindPressure(name, ref numberItems, ref areaName, ref loadPat, ref myType, ref cp); - if (s == 0) - { - foreach (int index in Enumerable.Range(0, numberItems)) + speckleLoadFace.Cp = cp[index]; + switch (myType[index]) { - var speckleLoadFace = new CSIWindLoadingFace(); - var element = AreaToSpeckle(areaName[index]); - var loadID = string.Concat(loadPat[index], myType[index], cp[index]); - speckleLoadFace.applicationId = loadID; - _areaStoring.TryGetValue(loadID, out var element2Dlist); - if (element2Dlist == null) - { - element2Dlist = new List { }; - } - element2Dlist.Add(element); - _areaStoring[loadID] = element2Dlist; - if (speckleLoadFace.values == null) - { - speckleLoadFace.values = new List { }; - } - speckleLoadFace.Cp = cp[index]; - switch (myType[index]) - { - case 1: - speckleLoadFace.WindPressureType = Structural.CSI.Analysis.WindPressureType.Windward; - break; - case 2: - speckleLoadFace.WindPressureType = Structural.CSI.Analysis.WindPressureType.other; - break; - } - //speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); - _loadStoringArea[loadID] = speckleLoadFace; + case 1: + speckleLoadFace.WindPressureType = Structural.CSI.Analysis.WindPressureType.Windward; + break; + case 2: + speckleLoadFace.WindPressureType = Structural.CSI.Analysis.WindPressureType.other; + break; } - _counterAreaLoadWind += 1; - if (_counterAreaLoadWind == areaNumber) + //speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); + _loadStoringArea[loadID] = speckleLoadFace; + } + _counterAreaLoadWind += 1; + if (_counterAreaLoadWind == areaNumber) + { + foreach (var entry in _loadStoringArea.Keys) { - foreach (var entry in _loadStoringArea.Keys) - { - _loadStoringArea.TryGetValue(entry, out var loadFace); - _areaStoring.TryGetValue(entry, out var areas); - loadFace.elements = areas; - SpeckleModel.loads.Add(loadFace); - } - _counterAreaLoadWind = 0; + _loadStoringArea.TryGetValue(entry, out var loadFace); + _areaStoring.TryGetValue(entry, out var areas); + loadFace.elements = areas; + SpeckleModel.loads.Add(loadFace); } + _counterAreaLoadWind = 0; } - var speckleBase = new Base(); - return speckleBase; } + var speckleBase = new Base(); + return speckleBase; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/LoadingNode.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/LoadingNode.cs index 47b0b84c96..0dcdb6891d 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/LoadingNode.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Loading/LoadingNode.cs @@ -1,132 +1,131 @@ -using Objects.Structural.Loading; +using Objects.Structural.Loading; using System.Collections.Generic; using Objects.Structural.Geometry; using System.Linq; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + readonly Dictionary _loadStoringNode = new(); + readonly Dictionary> _nodeStoring = new(); + int counterPoint; + + //need to figure out how to recombine forces into val6 + //void LoadNodeToNative(LoadNode loadNode) + //{ + // foreach(var node in loadNode.nodes) + // { + // Model.PointObj.SetLoadForce(node.name,loadNode.loadCase,load) + // } + //} + Base LoadNodeToSpeckle(string name, int pointNumber) { - readonly Dictionary _loadStoringNode = new(); - readonly Dictionary> _nodeStoring = new(); - int counterPoint; + double[] F1 = null; + double[] F2 = null; + double[] F3 = null; + double[] M1 = null; + double[] M2 = null; + double[] M3 = null; + string[] csys = null; + int[] lcStep = null; + string[] pointName = null; + string[] loadPat = null; + int numberItems = 0; - //need to figure out how to recombine forces into val6 - //void LoadNodeToNative(LoadNode loadNode) - //{ - // foreach(var node in loadNode.nodes) - // { - // Model.PointObj.SetLoadForce(node.name,loadNode.loadCase,load) - // } - //} - Base LoadNodeToSpeckle(string name, int pointNumber) + int s = Model.PointObj.GetLoadForce( + name, + ref numberItems, + ref pointName, + ref loadPat, + ref lcStep, + ref csys, + ref F1, + ref F2, + ref F3, + ref M1, + ref M2, + ref M3 + ); + if (s == 0) { - double[] F1 = null; - double[] F2 = null; - double[] F3 = null; - double[] M1 = null; - double[] M2 = null; - double[] M3 = null; - string[] csys = null; - int[] lcStep = null; - string[] pointName = null; - string[] loadPat = null; - int numberItems = 0; - - int s = Model.PointObj.GetLoadForce( - name, - ref numberItems, - ref pointName, - ref loadPat, - ref lcStep, - ref csys, - ref F1, - ref F2, - ref F3, - ref M1, - ref M2, - ref M3 - ); - if (s == 0) + foreach (int index in Enumerable.Range(0, numberItems)) { - foreach (int index in Enumerable.Range(0, numberItems)) + if (F1[index] != 0) { - if (F1[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.X; - var loadID = string.Concat(loadPat[index], F1[index], "F1"); - generateIDAndElements(loadID, loadPat[index], pointName[index], F1[index], speckleLoadNode); - } - else if (F2[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.Y; - var loadID = string.Concat(loadPat[index], F2[index], "F2"); - generateIDAndElements(loadID, loadPat[index], pointName[index], F2[index], speckleLoadNode); - } - else if (F3[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.Z; - var loadID = string.Concat(loadPat[index], F3[index], "F3"); - generateIDAndElements(loadID, loadPat[index], pointName[index], F3[index], speckleLoadNode); - } - else if (M1[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.XX; - var loadID = string.Concat(loadPat[index], M1[index], "M1"); - generateIDAndElements(loadID, loadPat[index], pointName[index], M1[index], speckleLoadNode); - } - else if (M2[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.YY; - var loadID = string.Concat(loadPat[index], M2[index], "M2"); - generateIDAndElements(loadID, loadPat[index], pointName[index], M2[index], speckleLoadNode); - } - else if (M3[index] != 0) - { - var speckleLoadNode = new LoadNode(); - speckleLoadNode.direction = LoadDirection.ZZ; - var loadID = string.Concat(loadPat[index], M3[index], "M3"); - generateIDAndElements(loadID, loadPat[index], pointName[index], M3[index], speckleLoadNode); - } - //speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.X; + var loadID = string.Concat(loadPat[index], F1[index], "F1"); + generateIDAndElements(loadID, loadPat[index], pointName[index], F1[index], speckleLoadNode); } - counterPoint += 1; - - if (counterPoint == pointNumber) + else if (F2[index] != 0) + { + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.Y; + var loadID = string.Concat(loadPat[index], F2[index], "F2"); + generateIDAndElements(loadID, loadPat[index], pointName[index], F2[index], speckleLoadNode); + } + else if (F3[index] != 0) { - foreach (var entry in _nodeStoring.Keys) - { - _nodeStoring.TryGetValue(entry, out var listNode); - _loadStoringNode.TryGetValue(entry, out var loadStoringNode); - loadStoringNode.nodes = listNode; - SpeckleModel.loads.Add(loadStoringNode); - } + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.Z; + var loadID = string.Concat(loadPat[index], F3[index], "F3"); + generateIDAndElements(loadID, loadPat[index], pointName[index], F3[index], speckleLoadNode); } + else if (M1[index] != 0) + { + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.XX; + var loadID = string.Concat(loadPat[index], M1[index], "M1"); + generateIDAndElements(loadID, loadPat[index], pointName[index], M1[index], speckleLoadNode); + } + else if (M2[index] != 0) + { + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.YY; + var loadID = string.Concat(loadPat[index], M2[index], "M2"); + generateIDAndElements(loadID, loadPat[index], pointName[index], M2[index], speckleLoadNode); + } + else if (M3[index] != 0) + { + var speckleLoadNode = new LoadNode(); + speckleLoadNode.direction = LoadDirection.ZZ; + var loadID = string.Concat(loadPat[index], M3[index], "M3"); + generateIDAndElements(loadID, loadPat[index], pointName[index], M3[index], speckleLoadNode); + } + //speckleLoadFace.loadCase = LoadPatternCaseToSpeckle(loadPat[index]); } + counterPoint += 1; - var speckleBase = new Base(); - return speckleBase; + if (counterPoint == pointNumber) + { + foreach (var entry in _nodeStoring.Keys) + { + _nodeStoring.TryGetValue(entry, out var listNode); + _loadStoringNode.TryGetValue(entry, out var loadStoringNode); + loadStoringNode.nodes = listNode; + SpeckleModel.loads.Add(loadStoringNode); + } + } } - void generateIDAndElements(string loadID, string loadPat, string nodeName, double value, LoadNode speckleLoadNode) + var speckleBase = new Base(); + return speckleBase; + } + + void generateIDAndElements(string loadID, string loadPat, string nodeName, double value, LoadNode speckleLoadNode) + { + speckleLoadNode.value = value; + Node speckleNode = PointToSpeckle(nodeName); + speckleLoadNode.loadCase = LoadPatternCaseToSpeckle(loadPat); + _nodeStoring.TryGetValue(loadID, out var nodeList); + if (nodeList == null) { - speckleLoadNode.value = value; - Node speckleNode = PointToSpeckle(nodeName); - speckleLoadNode.loadCase = LoadPatternCaseToSpeckle(loadPat); - _nodeStoring.TryGetValue(loadID, out var nodeList); - if (nodeList == null) - { - nodeList = new List { }; - } - nodeList.Add(speckleNode); - _nodeStoring[loadID] = nodeList; - _loadStoringNode[loadID] = speckleLoadNode; + nodeList = new List { }; } + nodeList.Add(speckleNode); + _nodeStoring[loadID] = nodeList; + _loadStoringNode[loadID] = speckleLoadNode; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Materials/ConvertMaterials.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Materials/ConvertMaterials.cs index c7406bb5ed..bdf7a82ff4 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Materials/ConvertMaterials.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Materials/ConvertMaterials.cs @@ -1,342 +1,343 @@ -using Objects.Structural.Materials; +using Objects.Structural.Materials; using CSiAPIv1; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string MaterialToNative(StructuralMaterial? material) { - public string MaterialToNative(StructuralMaterial? material) - { - material = material ?? new StructuralMaterial("undefined", Structural.MaterialType.Other, null, null, null); - int numbMaterial = 0; - string[] materials = new string[] { }; - Model.PropMaterial.GetNameList(ref numbMaterial, ref materials); - - if (materials.Contains(material.name)) - return material.name; - - var matType = material.materialType; - var eMaterialType = eMatType.NoDesign; - switch (matType) - { - case Structural.MaterialType.Steel: - eMaterialType = eMatType.Steel; - break; - case Structural.MaterialType.Concrete: - eMaterialType = eMatType.Concrete; - break; - case Structural.MaterialType.Other: - eMaterialType = eMatType.NoDesign; - break; - case Structural.MaterialType.Aluminium: - eMaterialType = eMatType.Aluminum; - break; - case Structural.MaterialType.Rebar: - eMaterialType = eMatType.Rebar; - break; - case Structural.MaterialType.ColdFormed: - eMaterialType = eMatType.ColdFormed; - break; - case Structural.MaterialType.Tendon: - eMaterialType = eMatType.Tendon; - break; - case Structural.MaterialType.Masonry: - eMaterialType = eMatType.Masonry; - break; - } - string materialName = material.name; - - if (material.designCode != null) - { - Model.PropMaterial.AddMaterial( - ref materialName, - eMaterialType, - material.designCode, - material.codeYear, - material.grade - ); - Model.PropMaterial.ChangeName(materialName, material.name); - } - else - { - Model.PropMaterial.SetMaterial(material.name, eMaterialType); - if (material is Structural.CSI.Materials.CSIConcrete csiConcrete) - { - SetConcreteMaterial(csiConcrete, material.name); - } - else if (material is Structural.CSI.Materials.CSISteel csiSteel) - { - SetSteelMaterial(csiSteel, material.name); - } - } - return material.name; - } + material = material ?? new StructuralMaterial("undefined", Structural.MaterialType.Other, null, null, null); + int numbMaterial = 0; + string[] materials = new string[] { }; + Model.PropMaterial.GetNameList(ref numbMaterial, ref materials); - public Structural.Materials.StructuralMaterial MaterialToSpeckle(string name) + if (materials.Contains(material.name)) { - var speckleStructMaterial = new Structural.Materials.StructuralMaterial(); - speckleStructMaterial.name = name; - eMatType matType = new eMatType(); - int color = 0; - string notes, - GUID; - notes = GUID = null; - Model.PropMaterial.GetMaterial(name, ref matType, ref color, ref notes, ref GUID); - - speckleStructMaterial.applicationId = GUID; - - switch (matType) - { - case eMatType.Steel: - return GetSteelMaterial(name); - break; - case eMatType.Concrete: - speckleStructMaterial.materialType = Structural.MaterialType.Concrete; - return GetConcreteMaterial(name); - break; - case eMatType.NoDesign: - speckleStructMaterial.materialType = Structural.MaterialType.Other; - break; - case eMatType.Aluminum: - speckleStructMaterial.materialType = Structural.MaterialType.Aluminium; - break; - case eMatType.Rebar: - - return GetRebarMaterial(name); - break; - case eMatType.ColdFormed: - speckleStructMaterial.materialType = Structural.MaterialType.ColdFormed; - break; - case eMatType.Tendon: - speckleStructMaterial.materialType = Structural.MaterialType.Tendon; - break; - case eMatType.Masonry: - speckleStructMaterial.materialType = Structural.MaterialType.Masonry; - break; - } - - return speckleStructMaterial; + return material.name; } - #region Helper functions - public Structural.CSI.Materials.CSISteel GetSteelMaterial(string materialName) + var matType = material.materialType; + var eMaterialType = eMatType.NoDesign; + switch (matType) { - double fy, - fu, - eFy, - eFu, - strainAtHardening, - strainAtMaxStress, - strainAtRupture, - finalSlope; - fy = fu = eFy = eFu = strainAtHardening = strainAtMaxStress = strainAtRupture = finalSlope = 0; - int sStype, - sSHysType; - sStype = sSHysType = 0; - - var speckleMaterial = new Structural.CSI.Materials.CSISteel(); - - // Material is isotropic or elastic - No support for other types currently - if (sSHysType == 7 || sSHysType == 1) - { - speckleMaterial = (Structural.CSI.Materials.CSISteel)GetIsotropicMaterial(materialName); - } - - Model.PropMaterial.GetOSteel_1( - materialName, - ref fy, - ref fu, - ref eFy, - ref eFu, - ref sStype, - ref sSHysType, - ref strainAtHardening, - ref strainAtMaxStress, - ref strainAtRupture, - ref finalSlope - ); - - speckleMaterial.strength = fy; - speckleMaterial.ultimateStrength = fu; - speckleMaterial.maxStrain = strainAtRupture; - speckleMaterial.strainHardeningModulus = finalSlope; - speckleMaterial.strainAtHardening = strainAtHardening; - speckleMaterial.strainAtMaxStress = strainAtMaxStress; - speckleMaterial.SSHysType = sSHysType; - speckleMaterial.SSType = sStype; - speckleMaterial.EFu = eFu; - speckleMaterial.EFy = eFy; - speckleMaterial.materialType = Structural.MaterialType.Steel; - - return speckleMaterial; + case Structural.MaterialType.Steel: + eMaterialType = eMatType.Steel; + break; + case Structural.MaterialType.Concrete: + eMaterialType = eMatType.Concrete; + break; + case Structural.MaterialType.Other: + eMaterialType = eMatType.NoDesign; + break; + case Structural.MaterialType.Aluminium: + eMaterialType = eMatType.Aluminum; + break; + case Structural.MaterialType.Rebar: + eMaterialType = eMatType.Rebar; + break; + case Structural.MaterialType.ColdFormed: + eMaterialType = eMatType.ColdFormed; + break; + case Structural.MaterialType.Tendon: + eMaterialType = eMatType.Tendon; + break; + case Structural.MaterialType.Masonry: + eMaterialType = eMatType.Masonry; + break; } + string materialName = material.name; - public void SetSteelMaterial(Structural.CSI.Materials.CSISteel structuralMaterial, string etabsMaterialName) + if (material.designCode != null) { - //Support only isotropic Steel Material setting - //Lossy transformation since Speckle classes are missing material properties - Model.PropMaterial.SetOSteel_1( - etabsMaterialName, - structuralMaterial.strength, - structuralMaterial.yieldStrength, - structuralMaterial.EFy, - structuralMaterial.EFu, - structuralMaterial.SSType, - structuralMaterial.SSHysType, - structuralMaterial.strainAtHardening, - structuralMaterial.strainAtMaxStress, - structuralMaterial.maxStrain, - structuralMaterial.strainHardeningModulus - ); - - Model.PropMaterial.SetMPIsotropic( - etabsMaterialName, - structuralMaterial.elasticModulus, - structuralMaterial.poissonsRatio, - structuralMaterial.thermalExpansivity, - structuralMaterial.shearModulus + Model.PropMaterial.AddMaterial( + ref materialName, + eMaterialType, + material.designCode, + material.codeYear, + material.grade ); + Model.PropMaterial.ChangeName(materialName, material.name); } - - public Structural.CSI.Materials.CSIConcrete GetConcreteMaterial(string materialName) + else { - double fc, - fcsFactor, - strainAtFc, - strainUltimate, - finalSlope, - frictionAngle, - dilatationalAngle; - fc = fcsFactor = strainAtFc = strainUltimate = finalSlope = frictionAngle = dilatationalAngle = 0; - int sStype, - sSHysType; - sStype = sSHysType = 0; - bool isLightweight = false; - - var speckleMaterial = new Structural.CSI.Materials.CSIConcrete(); - // Material is isotropic - No support for other types currently - if (sSHysType == 7 || sSHysType == 1 || sSHysType == 4) + Model.PropMaterial.SetMaterial(material.name, eMaterialType); + if (material is Structural.CSI.Materials.CSIConcrete csiConcrete) { - speckleMaterial = (Structural.CSI.Materials.CSIConcrete)GetIsotropicMaterial(materialName); + SetConcreteMaterial(csiConcrete, material.name); + } + else if (material is Structural.CSI.Materials.CSISteel csiSteel) + { + SetSteelMaterial(csiSteel, material.name); } - - Model.PropMaterial.GetOConcrete_1( - materialName, - ref fc, - ref isLightweight, - ref fcsFactor, - ref sStype, - ref sSHysType, - ref strainAtFc, - ref strainUltimate, - ref finalSlope, - ref frictionAngle, - ref dilatationalAngle - ); - - speckleMaterial.strength = fc; - speckleMaterial.materialSafetyFactor = fcsFactor; - speckleMaterial.maxCompressiveStrain = strainUltimate; - speckleMaterial.maxTensileStrain = strainAtFc; - speckleMaterial.finalSlope = finalSlope; - speckleMaterial.lightweight = isLightweight; - speckleMaterial.SSHysType = sSHysType; - speckleMaterial.SSType = sStype; - speckleMaterial.frictionAngle = frictionAngle; - speckleMaterial.dialationalAngle = dilatationalAngle; - speckleMaterial.materialType = Structural.MaterialType.Concrete; - - return speckleMaterial; } + return material.name; + } - public void SetConcreteMaterial(Structural.CSI.Materials.CSIConcrete structuralMaterial, string etabsMaterialName) + public Structural.Materials.StructuralMaterial MaterialToSpeckle(string name) + { + var speckleStructMaterial = new Structural.Materials.StructuralMaterial(); + speckleStructMaterial.name = name; + eMatType matType = new(); + int color = 0; + string notes, + GUID; + notes = GUID = null; + Model.PropMaterial.GetMaterial(name, ref matType, ref color, ref notes, ref GUID); + + speckleStructMaterial.applicationId = GUID; + + switch (matType) { - Model.PropMaterial.SetOConcrete_1( - etabsMaterialName, - structuralMaterial.strength, - structuralMaterial.lightweight, - structuralMaterial.materialSafetyFactor, - structuralMaterial.SSType, - structuralMaterial.SSHysType, - structuralMaterial.maxTensileStrain, - structuralMaterial.maxCompressiveStrain, - structuralMaterial.finalSlope, - structuralMaterial.frictionAngle, - structuralMaterial.dialationalAngle - ); - - Model.PropMaterial.SetMPIsotropic( - etabsMaterialName, - structuralMaterial.elasticModulus, - structuralMaterial.poissonsRatio, - structuralMaterial.thermalExpansivity, - structuralMaterial.shearModulus - ); + case eMatType.Steel: + return GetSteelMaterial(name); + break; + case eMatType.Concrete: + speckleStructMaterial.materialType = Structural.MaterialType.Concrete; + return GetConcreteMaterial(name); + break; + case eMatType.NoDesign: + speckleStructMaterial.materialType = Structural.MaterialType.Other; + break; + case eMatType.Aluminum: + speckleStructMaterial.materialType = Structural.MaterialType.Aluminium; + break; + case eMatType.Rebar: + + return GetRebarMaterial(name); + break; + case eMatType.ColdFormed: + speckleStructMaterial.materialType = Structural.MaterialType.ColdFormed; + break; + case eMatType.Tendon: + speckleStructMaterial.materialType = Structural.MaterialType.Tendon; + break; + case eMatType.Masonry: + speckleStructMaterial.materialType = Structural.MaterialType.Masonry; + break; } - public Structural.CSI.Materials.CSIRebar GetRebarMaterial(string materialName) - { - double fy, - fu, - eFy, - eFu, - strainAtHardening, - strainUltimate, - finalSlope; - fy = fu = eFy = eFu = strainAtHardening = strainUltimate = finalSlope = 0; - int sStype, - sSHysType; - sStype = sSHysType = 0; - bool useCaltransSSDefaults = false; - - Structural.CSI.Materials.CSIRebar rebarMaterial = new Structural.CSI.Materials.CSIRebar(); - // Rebar can only be set to uniaxial - //GetUniaxialMaterial(materialName); - //speckleMaterial = (Structural.CSI.Materials.CSIRebar)speckleMaterial; - //Model.PropMaterial.GetORebar_1(materialName, ref fy, ref fu, ref eFy, ref eFu, ref sStype, ref sSHysType, ref strainAtHardening, ref strainUltimate, ref finalSlope, ref useCaltransSSDefaults); - - //speckleMaterial.strength = fy; - return rebarMaterial; - } + return speckleStructMaterial; + } - public void SetRebarMaterial(StructuralMaterial structuralMaterial, string etabsMaterialName) + #region Helper functions + public Structural.CSI.Materials.CSISteel GetSteelMaterial(string materialName) + { + double fy, + fu, + eFy, + eFu, + strainAtHardening, + strainAtMaxStress, + strainAtRupture, + finalSlope; + fy = fu = eFy = eFu = strainAtHardening = strainAtMaxStress = strainAtRupture = finalSlope = 0; + int sStype, + sSHysType; + sStype = sSHysType = 0; + + var speckleMaterial = new Structural.CSI.Materials.CSISteel(); + + // Material is isotropic or elastic - No support for other types currently + if (sSHysType == 7 || sSHysType == 1) { - Model.PropMaterial.SetORebar_1(etabsMaterialName, structuralMaterial.strength, 0, 0, 0, 0, 0, 0, 0, 0, false); - Model.PropMaterial.SetMPUniaxial( - etabsMaterialName, - structuralMaterial.elasticModulus, - structuralMaterial.thermalExpansivity - ); + speckleMaterial = (Structural.CSI.Materials.CSISteel)GetIsotropicMaterial(materialName); } - public object GetIsotropicMaterial(string materialName) + Model.PropMaterial.GetOSteel_1( + materialName, + ref fy, + ref fu, + ref eFy, + ref eFu, + ref sStype, + ref sSHysType, + ref strainAtHardening, + ref strainAtMaxStress, + ref strainAtRupture, + ref finalSlope + ); + + speckleMaterial.strength = fy; + speckleMaterial.ultimateStrength = fu; + speckleMaterial.maxStrain = strainAtRupture; + speckleMaterial.strainHardeningModulus = finalSlope; + speckleMaterial.strainAtHardening = strainAtHardening; + speckleMaterial.strainAtMaxStress = strainAtMaxStress; + speckleMaterial.SSHysType = sSHysType; + speckleMaterial.SSType = sStype; + speckleMaterial.EFu = eFu; + speckleMaterial.EFy = eFy; + speckleMaterial.materialType = Structural.MaterialType.Steel; + + return speckleMaterial; + } + + public void SetSteelMaterial(Structural.CSI.Materials.CSISteel structuralMaterial, string etabsMaterialName) + { + //Support only isotropic Steel Material setting + //Lossy transformation since Speckle classes are missing material properties + Model.PropMaterial.SetOSteel_1( + etabsMaterialName, + structuralMaterial.strength, + structuralMaterial.yieldStrength, + structuralMaterial.EFy, + structuralMaterial.EFu, + structuralMaterial.SSType, + structuralMaterial.SSHysType, + structuralMaterial.strainAtHardening, + structuralMaterial.strainAtMaxStress, + structuralMaterial.maxStrain, + structuralMaterial.strainHardeningModulus + ); + + Model.PropMaterial.SetMPIsotropic( + etabsMaterialName, + structuralMaterial.elasticModulus, + structuralMaterial.poissonsRatio, + structuralMaterial.thermalExpansivity, + structuralMaterial.shearModulus + ); + } + + public Structural.CSI.Materials.CSIConcrete GetConcreteMaterial(string materialName) + { + double fc, + fcsFactor, + strainAtFc, + strainUltimate, + finalSlope, + frictionAngle, + dilatationalAngle; + fc = fcsFactor = strainAtFc = strainUltimate = finalSlope = frictionAngle = dilatationalAngle = 0; + int sStype, + sSHysType; + sStype = sSHysType = 0; + bool isLightweight = false; + + var speckleMaterial = new Structural.CSI.Materials.CSIConcrete(); + // Material is isotropic - No support for other types currently + if (sSHysType == 7 || sSHysType == 1 || sSHysType == 4) { - double e, - u, - a, - g; - e = u = a = g = 0; - - Model.PropMaterial.GetMPIsotropic(materialName, ref e, ref u, ref a, ref g); - var speckleMaterial = new Structural.Materials.StructuralMaterial(); - speckleMaterial.elasticModulus = e; - speckleMaterial.poissonsRatio = u; - speckleMaterial.thermalExpansivity = a; - speckleMaterial.shearModulus = g; - return speckleMaterial; + speckleMaterial = (Structural.CSI.Materials.CSIConcrete)GetIsotropicMaterial(materialName); } - public void GetUniaxialMaterial(string materialName, ref Structural.Materials.StructuralMaterial speckleMaterial) - { - double e = 0; - double a = 0; + Model.PropMaterial.GetOConcrete_1( + materialName, + ref fc, + ref isLightweight, + ref fcsFactor, + ref sStype, + ref sSHysType, + ref strainAtFc, + ref strainUltimate, + ref finalSlope, + ref frictionAngle, + ref dilatationalAngle + ); + + speckleMaterial.strength = fc; + speckleMaterial.materialSafetyFactor = fcsFactor; + speckleMaterial.maxCompressiveStrain = strainUltimate; + speckleMaterial.maxTensileStrain = strainAtFc; + speckleMaterial.finalSlope = finalSlope; + speckleMaterial.lightweight = isLightweight; + speckleMaterial.SSHysType = sSHysType; + speckleMaterial.SSType = sStype; + speckleMaterial.frictionAngle = frictionAngle; + speckleMaterial.dialationalAngle = dilatationalAngle; + speckleMaterial.materialType = Structural.MaterialType.Concrete; + + return speckleMaterial; + } - Model.PropMaterial.GetMPUniaxial(materialName, ref e, ref a); + public void SetConcreteMaterial(Structural.CSI.Materials.CSIConcrete structuralMaterial, string etabsMaterialName) + { + Model.PropMaterial.SetOConcrete_1( + etabsMaterialName, + structuralMaterial.strength, + structuralMaterial.lightweight, + structuralMaterial.materialSafetyFactor, + structuralMaterial.SSType, + structuralMaterial.SSHysType, + structuralMaterial.maxTensileStrain, + structuralMaterial.maxCompressiveStrain, + structuralMaterial.finalSlope, + structuralMaterial.frictionAngle, + structuralMaterial.dialationalAngle + ); + + Model.PropMaterial.SetMPIsotropic( + etabsMaterialName, + structuralMaterial.elasticModulus, + structuralMaterial.poissonsRatio, + structuralMaterial.thermalExpansivity, + structuralMaterial.shearModulus + ); + } - speckleMaterial.elasticModulus = e; - speckleMaterial.thermalExpansivity = a; - } - #endregion + public Structural.CSI.Materials.CSIRebar GetRebarMaterial(string materialName) + { + double fy, + fu, + eFy, + eFu, + strainAtHardening, + strainUltimate, + finalSlope; + fy = fu = eFy = eFu = strainAtHardening = strainUltimate = finalSlope = 0; + int sStype, + sSHysType; + sStype = sSHysType = 0; + bool useCaltransSSDefaults = false; + + Structural.CSI.Materials.CSIRebar rebarMaterial = new(); + // Rebar can only be set to uniaxial + //GetUniaxialMaterial(materialName); + //speckleMaterial = (Structural.CSI.Materials.CSIRebar)speckleMaterial; + //Model.PropMaterial.GetORebar_1(materialName, ref fy, ref fu, ref eFy, ref eFu, ref sStype, ref sSHysType, ref strainAtHardening, ref strainUltimate, ref finalSlope, ref useCaltransSSDefaults); + + //speckleMaterial.strength = fy; + return rebarMaterial; + } + + public void SetRebarMaterial(StructuralMaterial structuralMaterial, string etabsMaterialName) + { + Model.PropMaterial.SetORebar_1(etabsMaterialName, structuralMaterial.strength, 0, 0, 0, 0, 0, 0, 0, 0, false); + Model.PropMaterial.SetMPUniaxial( + etabsMaterialName, + structuralMaterial.elasticModulus, + structuralMaterial.thermalExpansivity + ); + } + + public object GetIsotropicMaterial(string materialName) + { + double e, + u, + a, + g; + e = u = a = g = 0; + + Model.PropMaterial.GetMPIsotropic(materialName, ref e, ref u, ref a, ref g); + var speckleMaterial = new Structural.Materials.StructuralMaterial(); + speckleMaterial.elasticModulus = e; + speckleMaterial.poissonsRatio = u; + speckleMaterial.thermalExpansivity = a; + speckleMaterial.shearModulus = g; + return speckleMaterial; + } + + public void GetUniaxialMaterial(string materialName, ref Structural.Materials.StructuralMaterial speckleMaterial) + { + double e = 0; + double a = 0; + + Model.PropMaterial.GetMPUniaxial(materialName, ref e, ref a); + + speckleMaterial.elasticModulus = e; + speckleMaterial.thermalExpansivity = a; } + #endregion } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert1DProperty.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert1DProperty.cs index 01a4b71b33..9e9ebd1b1f 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert1DProperty.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert1DProperty.cs @@ -6,171 +6,180 @@ using System.Linq; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public bool Property1DExists(string? name) { - public bool Property1DExists(string? name) - { - string[] properties = Array.Empty(); - int number = 0; + string[] properties = Array.Empty(); + int number = 0; - // TODO: we don't need to call this every time... - Model.PropFrame.GetNameList(ref number, ref properties); - if (properties.Contains(name)) - { - return true; - } - return false; + // TODO: we don't need to call this every time... + Model.PropFrame.GetNameList(ref number, ref properties); + if (properties.Contains(name)) + { + return true; } + return false; + } - public string? TryConvertProperty1DToNative(Property1D? property1D, IList? parentLog) + public string? TryConvertProperty1DToNative(Property1D? property1D, IList? parentLog) + { + if (property1D is null) { - if (property1D is null) - return null; + return null; + } - try - { - return Property1DToNative(property1D); - } - catch (ConversionNotSupportedException ex) - { - parentLog?.Add(ex.Message); - return property1D.name; - } - catch (Exception ex) - { - parentLog?.Add($"Failed to convert property {property1D.name}: {ex.Message}"); - return null; - } + try + { + return Property1DToNative(property1D); } + catch (ConversionNotSupportedException ex) + { + parentLog?.Add(ex.Message); + return property1D.name; + } + catch (Exception ex) + { + parentLog?.Add($"Failed to convert property {property1D.name}: {ex.Message}"); + return null; + } + } - public string Property1DToNative(Property1D property1D) + public string Property1DToNative(Property1D property1D) + { + if (property1D is null) { - if (property1D is null) - throw new ArgumentNullException(nameof(property1D)); + throw new ArgumentNullException(nameof(property1D)); + } - if (Property1DExists(property1D.name)) - { - throw new ConversionNotSupportedException( - $"Property {property1D.name} was not updated because it already exists" - ); - } + if (Property1DExists(property1D.name)) + { + throw new ConversionNotSupportedException( + $"Property {property1D.name} was not updated because it already exists" + ); + } - var materialName = MaterialToNative(property1D.material); + var materialName = MaterialToNative(property1D.material); - int success; + int success; - if ( - property1D.profile is Catalogue sectionProfile - && !string.IsNullOrEmpty(sectionProfile.catalogueName) - && !string.IsNullOrEmpty(sectionProfile.sectionName) - ) + if ( + property1D.profile is Catalogue sectionProfile + && !string.IsNullOrEmpty(sectionProfile.catalogueName) + && !string.IsNullOrEmpty(sectionProfile.sectionName) + ) + { + if (sectionProfile.catalogueName == "CA") { - if (sectionProfile.catalogueName == "CA") - sectionProfile.catalogueName = "CISC10"; - - success = Model.PropFrame.ImportProp( - property1D.name, - materialName, - sectionProfile.catalogueName + ".xml", - sectionProfile.sectionName.ToUpper() - ); - - if (success != 0) - throw new ConversionException($"Failed to import a frame section property {property1D.name}"); - - return property1D.name; + sectionProfile.catalogueName = "CISC10"; } - success = property1D.profile switch - { - Angle o - => Model.PropFrame.SetAngle( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units), - ScaleToNative(o.webThickness, o.units) - ), - Channel o - => Model.PropFrame.SetChannel( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units), - ScaleToNative(o.webThickness, o.units) - ), - Circular { wallThickness: > 0 } o - => Model.PropFrame.SetPipe( - property1D.name, - materialName, - ScaleToNative(o.radius * 2, o.units), - ScaleToNative(o.wallThickness, o.units) - ), - Circular o => Model.PropFrame.SetCircle(property1D.name, materialName, ScaleToNative(o.radius * 2, o.units)), - ISection o - => Model.PropFrame.SetISection( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units), - ScaleToNative(o.webThickness, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units) - ), - Rectangular { flangeThickness: > 0, webThickness: > 0 } o - => Model.PropFrame.SetTube( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units), - ScaleToNative(o.webThickness, o.units) - ), - Rectangular o - => Model.PropFrame.SetRectangle( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units) - ), - Tee o - => Model.PropFrame.SetConcreteTee( - property1D.name, - materialName, - ScaleToNative(o.depth, o.units), - ScaleToNative(o.width, o.units), - ScaleToNative(o.flangeThickness, o.units), - ScaleToNative(o.webThickness, o.units), - ScaleToNative(o.webThickness, o.units), - false - ), - _ => throw new ConversionNotSupportedException($"Unsupported profile type {property1D.profile.GetType()}") - }; + success = Model.PropFrame.ImportProp( + property1D.name, + materialName, + sectionProfile.catalogueName + ".xml", + sectionProfile.sectionName.ToUpper() + ); if (success != 0) - throw new ConversionException($"Failed to create section with profile named {property1D.name}"); + { + throw new ConversionException($"Failed to import a frame section property {property1D.name}"); + } return property1D.name; } - public Property1D Property1DToSpeckle(string name) + success = property1D.profile switch + { + Angle o + => Model.PropFrame.SetAngle( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units), + ScaleToNative(o.webThickness, o.units) + ), + Channel o + => Model.PropFrame.SetChannel( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units), + ScaleToNative(o.webThickness, o.units) + ), + Circular { wallThickness: > 0 } o + => Model.PropFrame.SetPipe( + property1D.name, + materialName, + ScaleToNative(o.radius * 2, o.units), + ScaleToNative(o.wallThickness, o.units) + ), + Circular o => Model.PropFrame.SetCircle(property1D.name, materialName, ScaleToNative(o.radius * 2, o.units)), + ISection o + => Model.PropFrame.SetISection( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units), + ScaleToNative(o.webThickness, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units) + ), + Rectangular { flangeThickness: > 0, webThickness: > 0 } o + => Model.PropFrame.SetTube( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units), + ScaleToNative(o.webThickness, o.units) + ), + Rectangular o + => Model.PropFrame.SetRectangle( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units) + ), + Tee o + => Model.PropFrame.SetConcreteTee( + property1D.name, + materialName, + ScaleToNative(o.depth, o.units), + ScaleToNative(o.width, o.units), + ScaleToNative(o.flangeThickness, o.units), + ScaleToNative(o.webThickness, o.units), + ScaleToNative(o.webThickness, o.units), + false + ), + _ => throw new ConversionNotSupportedException($"Unsupported profile type {property1D.profile.GetType()}") + }; + + if (success != 0) { - var speckleStructProperty1D = new Property1D(); - speckleStructProperty1D.name = name; - string materialProp = null; - Model.PropFrame.GetMaterial(name, ref materialProp); - speckleStructProperty1D.material = MaterialToSpeckle(materialProp); - speckleStructProperty1D.profile = SectionToSpeckle(name); + throw new ConversionException($"Failed to create section with profile named {property1D.name}"); + } - speckleStructProperty1D.applicationId = - $"{speckleStructProperty1D.material.applicationId}:{speckleStructProperty1D.profile.applicationId}"; + return property1D.name; + } - return speckleStructProperty1D; - } + public Property1D Property1DToSpeckle(string name) + { + var speckleStructProperty1D = new Property1D(); + speckleStructProperty1D.name = name; + string materialProp = null; + Model.PropFrame.GetMaterial(name, ref materialProp); + speckleStructProperty1D.material = MaterialToSpeckle(materialProp); + speckleStructProperty1D.profile = SectionToSpeckle(name); + + speckleStructProperty1D.applicationId = + $"{speckleStructProperty1D.material.applicationId}:{speckleStructProperty1D.profile.applicationId}"; + + return speckleStructProperty1D; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DProperty.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DProperty.cs index becd3b37ad..b759b6419f 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DProperty.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DProperty.cs @@ -8,57 +8,56 @@ using Objects.Structural.CSI.Properties; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + void setProperties(CSIProperty2D property2D, string matProp, double thickeness, string name) + { + property2D.name = name; + property2D.thickness = thickeness; + property2D.material = MaterialToSpeckle(matProp); + return; + } + + private string Property2DToNative(CSIProperty2D property2D) { - void setProperties(CSIProperty2D property2D, string matProp, double thickeness, string name) + if (property2D.type2D == CSIPropertyType2D.Wall) { - property2D.name = name; - property2D.thickness = thickeness; - property2D.material = MaterialToSpeckle(matProp); - return; + return WallPropertyToNative(property2D); } - - private string Property2DToNative(CSIProperty2D property2D) + else { - if (property2D.type2D == CSIPropertyType2D.Wall) - { - return WallPropertyToNative(property2D); - } - else - { - return FloorPropertyToNative(property2D); - } + return FloorPropertyToNative(property2D); } + } - private CSIProperty2D Property2DToSpeckle(string area, string property) - { - eAreaDesignOrientation areaDesignOrientation = eAreaDesignOrientation.Null; - Model.AreaObj.GetDesignOrientation(area, ref areaDesignOrientation); - eDeckType deckType = eDeckType.Filled; - eSlabType slabType = eSlabType.Drop; - eWallPropType wallPropType = eWallPropType.Specified; - eShellType shellType = eShellType.Layered; - string matProp = ""; - double thickness = 0; - int color = 0; - string notes = ""; - string GUID = ""; + private CSIProperty2D Property2DToSpeckle(string area, string property) + { + eAreaDesignOrientation areaDesignOrientation = eAreaDesignOrientation.Null; + Model.AreaObj.GetDesignOrientation(area, ref areaDesignOrientation); + eDeckType deckType = eDeckType.Filled; + eSlabType slabType = eSlabType.Drop; + eWallPropType wallPropType = eWallPropType.Specified; + eShellType shellType = eShellType.Layered; + string matProp = ""; + double thickness = 0; + int color = 0; + string notes = ""; + string GUID = ""; - switch (areaDesignOrientation) - { - case eAreaDesignOrientation.Wall: - return WallPropertyToSpeckle(property); - break; - case eAreaDesignOrientation.Floor: - return FloorPropertyToSpeckle(property); - break; - } + switch (areaDesignOrientation) + { + case eAreaDesignOrientation.Wall: + return WallPropertyToSpeckle(property); + break; + case eAreaDesignOrientation.Floor: + return FloorPropertyToSpeckle(property); + break; + } - double[] value = null; + double[] value = null; - return null; - } + return null; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyFloor.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyFloor.cs index 1c31284ebb..65524ab3e2 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyFloor.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyFloor.cs @@ -3,369 +3,374 @@ using Objects.Structural.CSI.Properties; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + private string FloorDeckPropertyToNative(CSIProperty2D property2D) { - private string FloorDeckPropertyToNative(CSIProperty2D property2D) + var success = SetDeck(property2D); + if (success != 0) { - var success = SetDeck(property2D); - if (success != 0) - throw new ConversionException("Failed to initialize deck property"); + throw new ConversionException("Failed to initialize deck property"); + } - switch (property2D.deckType) - { - case Structural.CSI.Analysis.DeckType.Filled: - var deckFilled = (CSIProperty2D.DeckFilled)property2D; - success = Model.PropArea.SetDeckFilled( - deckFilled.name, - deckFilled.SlabDepth, - deckFilled.RibDepth, - deckFilled.RibWidthTop, - deckFilled.RibWidthBot, - deckFilled.RibSpacing, - deckFilled.ShearThickness, - deckFilled.UnitWeight, - deckFilled.ShearStudDia, - deckFilled.ShearStudHt, - deckFilled.ShearStudFu - ); - break; - case Structural.CSI.Analysis.DeckType.Unfilled: - var deckUnfilled = (CSIProperty2D.DeckUnFilled)property2D; - success = Model.PropArea.SetDeckUnfilled( - deckUnfilled.name, - deckUnfilled.RibDepth, - deckUnfilled.RibWidthTop, - deckUnfilled.RibWidthBot, - deckUnfilled.RibSpacing, - deckUnfilled.ShearThickness, - deckUnfilled.UnitWeight - ); - break; - case Structural.CSI.Analysis.DeckType.SolidSlab: - var deckSlab = (CSIProperty2D.DeckSlab)property2D; - success = Model.PropArea.SetDeckSolidSlab( - deckSlab.name, - deckSlab.SlabDepth, - deckSlab.ShearStudDia, - deckSlab.ShearStudHt, - deckSlab.ShearStudFu - ); - break; - default: - throw new ArgumentOutOfRangeException($"Unrecognised deck type {property2D.deckType}"); - } + switch (property2D.deckType) + { + case Structural.CSI.Analysis.DeckType.Filled: + var deckFilled = (CSIProperty2D.DeckFilled)property2D; + success = Model.PropArea.SetDeckFilled( + deckFilled.name, + deckFilled.SlabDepth, + deckFilled.RibDepth, + deckFilled.RibWidthTop, + deckFilled.RibWidthBot, + deckFilled.RibSpacing, + deckFilled.ShearThickness, + deckFilled.UnitWeight, + deckFilled.ShearStudDia, + deckFilled.ShearStudHt, + deckFilled.ShearStudFu + ); + break; + case Structural.CSI.Analysis.DeckType.Unfilled: + var deckUnfilled = (CSIProperty2D.DeckUnFilled)property2D; + success = Model.PropArea.SetDeckUnfilled( + deckUnfilled.name, + deckUnfilled.RibDepth, + deckUnfilled.RibWidthTop, + deckUnfilled.RibWidthBot, + deckUnfilled.RibSpacing, + deckUnfilled.ShearThickness, + deckUnfilled.UnitWeight + ); + break; + case Structural.CSI.Analysis.DeckType.SolidSlab: + var deckSlab = (CSIProperty2D.DeckSlab)property2D; + success = Model.PropArea.SetDeckSolidSlab( + deckSlab.name, + deckSlab.SlabDepth, + deckSlab.ShearStudDia, + deckSlab.ShearStudHt, + deckSlab.ShearStudFu + ); + break; + default: + throw new ArgumentOutOfRangeException($"Unrecognised deck type {property2D.deckType}"); + } + + if (success != 0) + { + throw new ConversionException("Failed to set deck property"); + } - if (success != 0) - throw new ConversionException("Failed to set deck property"); + return property2D.name; + } - return property2D.name; + private string FloorSlabPropertyToNative(CSIProperty2D property2D) + { + int success = -1; + var materialName = MaterialToNative(property2D.material); + switch (property2D.slabType) + { + case Structural.CSI.Analysis.SlabType.Slab: + var solidSlab = property2D; + var shell = shellType(solidSlab); + success = Model.PropArea.SetSlab(solidSlab.name, eSlabType.Slab, shell, materialName, solidSlab.thickness); + break; + case Structural.CSI.Analysis.SlabType.Ribbed: + var slabRibbed = (CSIProperty2D.RibbedSlab)property2D; + shell = shellType(slabRibbed); + Model.PropArea.SetSlab(slabRibbed.name, eSlabType.Ribbed, shell, materialName, slabRibbed.thickness); + success = Model.PropArea.SetSlabRibbed( + slabRibbed.name, + slabRibbed.OverAllDepth, + slabRibbed.thickness, + slabRibbed.StemWidthTop, + slabRibbed.StemWidthTop, + slabRibbed.RibSpacing, + slabRibbed.RibsParallelTo + ); + break; + case Structural.CSI.Analysis.SlabType.Waffle: + var slabWaffled = (CSIProperty2D.WaffleSlab)property2D; + shell = shellType(slabWaffled); + Model.PropArea.SetSlab(slabWaffled.name, eSlabType.Waffle, shell, materialName, slabWaffled.thickness); + success = Model.PropArea.SetSlabWaffle( + slabWaffled.name, + slabWaffled.OverAllDepth, + slabWaffled.thickness, + slabWaffled.StemWidthTop, + slabWaffled.StemWidthBot, + slabWaffled.RibSpacingDir1, + slabWaffled.RibSpacingDir2 + ); + break; + default: + throw new ArgumentOutOfRangeException($"Unrecognised slab type {property2D.slabType}"); } - private string FloorSlabPropertyToNative(CSIProperty2D property2D) + if (success != 0) { - int success = -1; - var materialName = MaterialToNative(property2D.material); - switch (property2D.slabType) - { - case Structural.CSI.Analysis.SlabType.Slab: - var solidSlab = property2D; - var shell = shellType(solidSlab); - success = Model.PropArea.SetSlab(solidSlab.name, eSlabType.Slab, shell, materialName, solidSlab.thickness); - break; - case Structural.CSI.Analysis.SlabType.Ribbed: - var slabRibbed = (CSIProperty2D.RibbedSlab)property2D; - shell = shellType(slabRibbed); - Model.PropArea.SetSlab(slabRibbed.name, eSlabType.Ribbed, shell, materialName, slabRibbed.thickness); - success = Model.PropArea.SetSlabRibbed( - slabRibbed.name, - slabRibbed.OverAllDepth, - slabRibbed.thickness, - slabRibbed.StemWidthTop, - slabRibbed.StemWidthTop, - slabRibbed.RibSpacing, - slabRibbed.RibsParallelTo - ); - break; - case Structural.CSI.Analysis.SlabType.Waffle: - var slabWaffled = (CSIProperty2D.WaffleSlab)property2D; - shell = shellType(slabWaffled); - Model.PropArea.SetSlab(slabWaffled.name, eSlabType.Waffle, shell, materialName, slabWaffled.thickness); - success = Model.PropArea.SetSlabWaffle( - slabWaffled.name, - slabWaffled.OverAllDepth, - slabWaffled.thickness, - slabWaffled.StemWidthTop, - slabWaffled.StemWidthBot, - slabWaffled.RibSpacingDir1, - slabWaffled.RibSpacingDir2 - ); - break; - default: - throw new ArgumentOutOfRangeException($"Unrecognised slab type {property2D.slabType}"); - } + throw new ConversionException("Failed to set slab property"); + } - if (success != 0) - throw new ConversionException("Failed to set slab property"); + return property2D.name; + } - return property2D.name; + public string FloorPropertyToNative(CSIProperty2D property2D) + { + if (property2D.deckType != Structural.CSI.Analysis.DeckType.Null) + { + return FloorDeckPropertyToNative(property2D); } + else + { + return FloorSlabPropertyToNative(property2D); + } + } - public string FloorPropertyToNative(CSIProperty2D property2D) + public eShellType shellType(CSIProperty2D property) + { + var shellType = eShellType.Layered; + switch (property.shellType) + { + case Structural.CSI.Analysis.ShellType.ShellThin: + shellType = eShellType.ShellThin; + break; + case Structural.CSI.Analysis.ShellType.Layered: + shellType = eShellType.Layered; + break; + case Structural.CSI.Analysis.ShellType.ShellThick: + shellType = eShellType.ShellThick; + break; + case Structural.CSI.Analysis.ShellType.Membrane: + shellType = eShellType.Membrane; + break; + } + return shellType; + } + + private int SetDeck(CSIProperty2D deck) + { + var deckType = deck.deckType switch { - if (property2D.deckType != Structural.CSI.Analysis.DeckType.Null) + Structural.CSI.Analysis.DeckType.Filled => eDeckType.Filled, + Structural.CSI.Analysis.DeckType.Unfilled => eDeckType.Unfilled, + Structural.CSI.Analysis.DeckType.SolidSlab => eDeckType.SolidSlab, + _ => eDeckType.Filled + }; + var shell = shellType(deck); + return Model.PropArea.SetDeck(deck.name, deckType, shell, deck.material.name, deck.thickness); + } + + public CSIProperty2D FloorPropertyToSpeckle(string property) + { + eDeckType deckType = eDeckType.Filled; + eSlabType slabType = eSlabType.Drop; + eShellType shellType = eShellType.Layered; + string matProp = ""; + double thickness = 0; + int color = 0; + string notes = ""; + string GUID = ""; + + int d = Model.PropArea.GetDeck( + property, + ref deckType, + ref shellType, + ref matProp, + ref thickness, + ref color, + ref notes, + ref GUID + ); + if (d == 0) + { + var speckleProperties2D = new CSIProperty2D(); + double slabDepth = 0; + double shearStudDia = 0; + double shearStudFu = 0; + double shearStudHt = 0; + double ribDepth = 0; + double ribWidthTop = 0; + double ribWidthBot = 0; + double ribSpacing = 0; + double shearThickness = 0; + double unitWeight = 0; + var speckleShellType = ConvertShellType(shellType); + if (deckType == eDeckType.Filled) { - return FloorDeckPropertyToNative(property2D); + var speckleProperty2D = new CSIProperty2D.DeckFilled(); + Model.PropArea.GetDeckFilled( + property, + ref slabDepth, + ref ribDepth, + ref ribWidthTop, + ref ribWidthBot, + ref ribSpacing, + ref shearThickness, + ref unitWeight, + ref shearStudDia, + ref shearStudHt, + ref shearStudFu + ); + speckleProperty2D.SlabDepth = slabDepth; + speckleProperty2D.ShearStudDia = shearStudDia; + speckleProperty2D.ShearStudFu = shearStudFu; + speckleProperty2D.RibDepth = ribDepth; + speckleProperty2D.RibWidthTop = ribWidthTop; + speckleProperty2D.RibWidthBot = ribWidthBot; + speckleProperty2D.RibSpacing = ribSpacing; + speckleProperty2D.ShearThickness = shearThickness; + speckleProperty2D.UnitWeight = unitWeight; + speckleProperty2D.ShearStudHt = shearStudHt; + speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Filled; + setProperties(speckleProperty2D, matProp, thickness, property); + speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; + speckleProperty2D.shellType = speckleShellType; + speckleProperty2D.applicationId = GUID; + return speckleProperty2D; } - else + else if (deckType == eDeckType.Unfilled) { - return FloorSlabPropertyToNative(property2D); + var speckleProperty2D = new CSIProperty2D.DeckUnFilled(); + Model.PropArea.GetDeckUnfilled( + property, + ref ribDepth, + ref ribWidthTop, + ref ribWidthBot, + ref ribSpacing, + ref shearThickness, + ref unitWeight + ); + speckleProperty2D.RibDepth = ribDepth; + speckleProperty2D.RibWidthTop = ribWidthTop; + speckleProperty2D.RibWidthBot = ribWidthBot; + speckleProperty2D.RibSpacing = ribSpacing; + speckleProperty2D.ShearThickness = shearThickness; + speckleProperty2D.UnitWeight = unitWeight; + speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Filled; + setProperties(speckleProperty2D, matProp, thickness, property); + speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; + speckleProperty2D.shellType = speckleShellType; + speckleProperty2D.applicationId = GUID; + return speckleProperty2D; } - } - - public eShellType shellType(CSIProperty2D property) - { - var shellType = eShellType.Layered; - switch (property.shellType) + else if (deckType == eDeckType.SolidSlab) { - case Structural.CSI.Analysis.ShellType.ShellThin: - shellType = eShellType.ShellThin; - break; - case Structural.CSI.Analysis.ShellType.Layered: - shellType = eShellType.Layered; - break; - case Structural.CSI.Analysis.ShellType.ShellThick: - shellType = eShellType.ShellThick; - break; - case Structural.CSI.Analysis.ShellType.Membrane: - shellType = eShellType.Membrane; - break; + var speckleProperty2D = new CSIProperty2D.DeckSlab(); + Model.PropArea.GetDeckSolidSlab(property, ref slabDepth, ref shearStudDia, ref shearStudDia, ref shearStudFu); + speckleProperty2D.SlabDepth = slabDepth; + speckleProperty2D.ShearStudDia = shearStudDia; + speckleProperty2D.ShearStudFu = shearStudFu; + speckleProperty2D.ShearStudHt = shearStudHt; + speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.SolidSlab; + setProperties(speckleProperty2D, matProp, thickness, property); + speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; + speckleProperty2D.shellType = speckleShellType; + speckleProperty2D.applicationId = GUID; + return speckleProperty2D; } - return shellType; } - - private int SetDeck(CSIProperty2D deck) + int s = Model.PropArea.GetSlab( + property, + ref slabType, + ref shellType, + ref matProp, + ref thickness, + ref color, + ref notes, + ref GUID + ); + if (s == 0) { - var deckType = deck.deckType switch + var specklePropery2DSlab = new CSIProperty2D(); + setProperties(specklePropery2DSlab, matProp, thickness, property); + specklePropery2DSlab.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Slab; + double overallDepth = 0; + double slabThickness = 0; + double stemWidthTop = 0; + double stemWidthBot = 0; + double ribSpacingDir1 = 0; + double ribSpacingDir2 = 0; + double ribSpacing = 0; + int ribParrallelTo = 0; + var speckleShellType = ConvertShellType(shellType); + if (slabType == eSlabType.Waffle) { - Structural.CSI.Analysis.DeckType.Filled => eDeckType.Filled, - Structural.CSI.Analysis.DeckType.Unfilled => eDeckType.Unfilled, - Structural.CSI.Analysis.DeckType.SolidSlab => eDeckType.SolidSlab, - _ => eDeckType.Filled - }; - var shell = shellType(deck); - return Model.PropArea.SetDeck(deck.name, deckType, shell, deck.material.name, deck.thickness); - } - - public CSIProperty2D FloorPropertyToSpeckle(string property) - { - eDeckType deckType = eDeckType.Filled; - eSlabType slabType = eSlabType.Drop; - eShellType shellType = eShellType.Layered; - string matProp = ""; - double thickness = 0; - int color = 0; - string notes = ""; - string GUID = ""; - - int d = Model.PropArea.GetDeck( - property, - ref deckType, - ref shellType, - ref matProp, - ref thickness, - ref color, - ref notes, - ref GUID - ); - if (d == 0) + var speckleProperty2D = new CSIProperty2D.WaffleSlab(); + Model.PropArea.GetSlabWaffle( + property, + ref overallDepth, + ref slabThickness, + ref stemWidthTop, + ref stemWidthBot, + ref ribSpacingDir1, + ref ribSpacingDir2 + ); + speckleProperty2D.OverAllDepth = overallDepth; + speckleProperty2D.StemWidthBot = stemWidthBot; + speckleProperty2D.StemWidthTop = stemWidthTop; + speckleProperty2D.RibSpacingDir1 = ribSpacingDir1; + speckleProperty2D.RibSpacingDir2 = ribSpacingDir2; + speckleProperty2D.slabType = Structural.CSI.Analysis.SlabType.Waffle; + speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Null; + setProperties(speckleProperty2D, matProp, thickness, property); + speckleProperty2D.shellType = speckleShellType; + speckleProperty2D.applicationId = GUID; + return speckleProperty2D; + } + else if (slabType == eSlabType.Ribbed) { - var speckleProperties2D = new CSIProperty2D(); - double slabDepth = 0; - double shearStudDia = 0; - double shearStudFu = 0; - double shearStudHt = 0; - double ribDepth = 0; - double ribWidthTop = 0; - double ribWidthBot = 0; - double ribSpacing = 0; - double shearThickness = 0; - double unitWeight = 0; - var speckleShellType = ConvertShellType(shellType); - if (deckType == eDeckType.Filled) - { - var speckleProperty2D = new CSIProperty2D.DeckFilled(); - Model.PropArea.GetDeckFilled( - property, - ref slabDepth, - ref ribDepth, - ref ribWidthTop, - ref ribWidthBot, - ref ribSpacing, - ref shearThickness, - ref unitWeight, - ref shearStudDia, - ref shearStudHt, - ref shearStudFu - ); - speckleProperty2D.SlabDepth = slabDepth; - speckleProperty2D.ShearStudDia = shearStudDia; - speckleProperty2D.ShearStudFu = shearStudFu; - speckleProperty2D.RibDepth = ribDepth; - speckleProperty2D.RibWidthTop = ribWidthTop; - speckleProperty2D.RibWidthBot = ribWidthBot; - speckleProperty2D.RibSpacing = ribSpacing; - speckleProperty2D.ShearThickness = shearThickness; - speckleProperty2D.UnitWeight = unitWeight; - speckleProperty2D.ShearStudHt = shearStudHt; - speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Filled; - setProperties(speckleProperty2D, matProp, thickness, property); - speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; - speckleProperty2D.shellType = speckleShellType; - speckleProperty2D.applicationId = GUID; - return speckleProperty2D; - } - else if (deckType == eDeckType.Unfilled) - { - var speckleProperty2D = new CSIProperty2D.DeckUnFilled(); - Model.PropArea.GetDeckUnfilled( - property, - ref ribDepth, - ref ribWidthTop, - ref ribWidthBot, - ref ribSpacing, - ref shearThickness, - ref unitWeight - ); - speckleProperty2D.RibDepth = ribDepth; - speckleProperty2D.RibWidthTop = ribWidthTop; - speckleProperty2D.RibWidthBot = ribWidthBot; - speckleProperty2D.RibSpacing = ribSpacing; - speckleProperty2D.ShearThickness = shearThickness; - speckleProperty2D.UnitWeight = unitWeight; - speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Filled; - setProperties(speckleProperty2D, matProp, thickness, property); - speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; - speckleProperty2D.shellType = speckleShellType; - speckleProperty2D.applicationId = GUID; - return speckleProperty2D; - } - else if (deckType == eDeckType.SolidSlab) - { - var speckleProperty2D = new CSIProperty2D.DeckSlab(); - Model.PropArea.GetDeckSolidSlab(property, ref slabDepth, ref shearStudDia, ref shearStudDia, ref shearStudFu); - speckleProperty2D.SlabDepth = slabDepth; - speckleProperty2D.ShearStudDia = shearStudDia; - speckleProperty2D.ShearStudFu = shearStudFu; - speckleProperty2D.ShearStudHt = shearStudHt; - speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.SolidSlab; - setProperties(speckleProperty2D, matProp, thickness, property); - speckleProperty2D.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Deck; - speckleProperty2D.shellType = speckleShellType; - speckleProperty2D.applicationId = GUID; - return speckleProperty2D; - } + var speckleProperty2D = new CSIProperty2D.RibbedSlab(); + Model.PropArea.GetSlabRibbed( + property, + ref overallDepth, + ref slabThickness, + ref stemWidthTop, + ref stemWidthBot, + ref ribSpacing, + ref ribParrallelTo + ); + speckleProperty2D.OverAllDepth = overallDepth; + speckleProperty2D.StemWidthBot = stemWidthBot; + speckleProperty2D.StemWidthTop = stemWidthTop; + speckleProperty2D.RibSpacing = ribSpacing; + speckleProperty2D.RibsParallelTo = ribParrallelTo; + speckleProperty2D.slabType = Structural.CSI.Analysis.SlabType.Ribbed; + speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Null; + setProperties(speckleProperty2D, matProp, thickness, property); + speckleProperty2D.shellType = speckleShellType; + speckleProperty2D.applicationId = GUID; + return speckleProperty2D; } - int s = Model.PropArea.GetSlab( - property, - ref slabType, - ref shellType, - ref matProp, - ref thickness, - ref color, - ref notes, - ref GUID - ); - if (s == 0) + else { - var specklePropery2DSlab = new CSIProperty2D(); - setProperties(specklePropery2DSlab, matProp, thickness, property); - specklePropery2DSlab.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Slab; - double overallDepth = 0; - double slabThickness = 0; - double stemWidthTop = 0; - double stemWidthBot = 0; - double ribSpacingDir1 = 0; - double ribSpacingDir2 = 0; - double ribSpacing = 0; - int ribParrallelTo = 0; - var speckleShellType = ConvertShellType(shellType); - if (slabType == eSlabType.Waffle) - { - var speckleProperty2D = new CSIProperty2D.WaffleSlab(); - Model.PropArea.GetSlabWaffle( - property, - ref overallDepth, - ref slabThickness, - ref stemWidthTop, - ref stemWidthBot, - ref ribSpacingDir1, - ref ribSpacingDir2 - ); - speckleProperty2D.OverAllDepth = overallDepth; - speckleProperty2D.StemWidthBot = stemWidthBot; - speckleProperty2D.StemWidthTop = stemWidthTop; - speckleProperty2D.RibSpacingDir1 = ribSpacingDir1; - speckleProperty2D.RibSpacingDir2 = ribSpacingDir2; - speckleProperty2D.slabType = Structural.CSI.Analysis.SlabType.Waffle; - speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Null; - setProperties(speckleProperty2D, matProp, thickness, property); - speckleProperty2D.shellType = speckleShellType; - speckleProperty2D.applicationId = GUID; - return speckleProperty2D; - } - else if (slabType == eSlabType.Ribbed) - { - var speckleProperty2D = new CSIProperty2D.RibbedSlab(); - Model.PropArea.GetSlabRibbed( - property, - ref overallDepth, - ref slabThickness, - ref stemWidthTop, - ref stemWidthBot, - ref ribSpacing, - ref ribParrallelTo - ); - speckleProperty2D.OverAllDepth = overallDepth; - speckleProperty2D.StemWidthBot = stemWidthBot; - speckleProperty2D.StemWidthTop = stemWidthTop; - speckleProperty2D.RibSpacing = ribSpacing; - speckleProperty2D.RibsParallelTo = ribParrallelTo; - speckleProperty2D.slabType = Structural.CSI.Analysis.SlabType.Ribbed; - speckleProperty2D.deckType = Structural.CSI.Analysis.DeckType.Null; - setProperties(speckleProperty2D, matProp, thickness, property); - speckleProperty2D.shellType = speckleShellType; - speckleProperty2D.applicationId = GUID; - return speckleProperty2D; - } - else + switch (slabType) { - switch (slabType) - { - case eSlabType.Slab: - specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Slab; - break; - case eSlabType.Drop: - specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Drop; - break; - case eSlabType.Mat: - specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Mat; - break; - case eSlabType.Footing: - specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Footing; - break; - default: - specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Null; - break; - } - specklePropery2DSlab.deckType = Structural.CSI.Analysis.DeckType.Null; - specklePropery2DSlab.shellType = speckleShellType; - specklePropery2DSlab.applicationId = GUID; - return specklePropery2DSlab; + case eSlabType.Slab: + specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Slab; + break; + case eSlabType.Drop: + specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Drop; + break; + case eSlabType.Mat: + specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Mat; + break; + case eSlabType.Footing: + specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Footing; + break; + default: + specklePropery2DSlab.slabType = Structural.CSI.Analysis.SlabType.Null; + break; } + specklePropery2DSlab.deckType = Structural.CSI.Analysis.DeckType.Null; + specklePropery2DSlab.shellType = speckleShellType; + specklePropery2DSlab.applicationId = GUID; + return specklePropery2DSlab; } - return null; } + return null; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyWall.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyWall.cs index fcf7ac550b..fee5a3ca12 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyWall.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/Convert2DPropertyWall.cs @@ -4,42 +4,41 @@ using Speckle.Core.Kits; using Speckle.Core.Models; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string WallPropertyToNative(CSIProperty2D Wall) { - public string WallPropertyToNative(CSIProperty2D Wall) - { - throw new ConversionNotSupportedException("Wall properties are not currently supported on receive"); - } + throw new ConversionNotSupportedException("Wall properties are not currently supported on receive"); + } - public CSIProperty2D WallPropertyToSpeckle(string property) - { - eWallPropType wallPropType = eWallPropType.Specified; - eShellType shellType = eShellType.Layered; - string matProp = ""; - double thickness = 0; - int color = 0; - string notes = ""; - string GUID = ""; - var specklePropery2DWall = new CSIProperty2D(); - specklePropery2DWall.type = Structural.PropertyType2D.Wall; - Model.PropArea.GetWall( - property, - ref wallPropType, - ref shellType, - ref matProp, - ref thickness, - ref color, - ref notes, - ref GUID - ); - var speckleShellType = ConvertShellType(shellType); - specklePropery2DWall.shellType = speckleShellType; - setProperties(specklePropery2DWall, matProp, thickness, property); - specklePropery2DWall.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Wall; - specklePropery2DWall.applicationId = GUID; - return specklePropery2DWall; - } + public CSIProperty2D WallPropertyToSpeckle(string property) + { + eWallPropType wallPropType = eWallPropType.Specified; + eShellType shellType = eShellType.Layered; + string matProp = ""; + double thickness = 0; + int color = 0; + string notes = ""; + string GUID = ""; + var specklePropery2DWall = new CSIProperty2D(); + specklePropery2DWall.type = Structural.PropertyType2D.Wall; + Model.PropArea.GetWall( + property, + ref wallPropType, + ref shellType, + ref matProp, + ref thickness, + ref color, + ref notes, + ref GUID + ); + var speckleShellType = ConvertShellType(shellType); + specklePropery2DWall.shellType = speckleShellType; + setProperties(specklePropery2DWall, matProp, thickness, property); + specklePropery2DWall.type2D = Structural.CSI.Analysis.CSIPropertyType2D.Wall; + specklePropery2DWall.applicationId = GUID; + return specklePropery2DWall; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertDiaphragm.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertDiaphragm.cs index 69fdf601d4..d918abbe9e 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertDiaphragm.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertDiaphragm.cs @@ -1,4 +1,4 @@ -using Objects.Structural.CSI.Properties; +using Objects.Structural.CSI.Properties; using Speckle.Core.Kits; using System; @@ -12,26 +12,27 @@ using Speckle.Core.Models; using Objects.Structural.Geometry; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + private string DiaphragmToNative(CSIDiaphragm csiDiaphragm) { - private string DiaphragmToNative(CSIDiaphragm csiDiaphragm) - { - //TODO: test this bad boy, I'm not sure how it would create anything meaningful with just a name and a bool - var success = Model.Diaphragm.SetDiaphragm(csiDiaphragm.name, csiDiaphragm.SemiRigid); - - if (success != 0) - throw new ConversionException($"Failed to create/modify diaphragm {csiDiaphragm.name}"); - - return csiDiaphragm.name; - } + //TODO: test this bad boy, I'm not sure how it would create anything meaningful with just a name and a bool + var success = Model.Diaphragm.SetDiaphragm(csiDiaphragm.name, csiDiaphragm.SemiRigid); - CSIDiaphragm diaphragmToSpeckle(string name) + if (success != 0) { - bool semiRigid = false; - Model.Diaphragm.GetDiaphragm(name, ref semiRigid); - return new CSIDiaphragm(name, semiRigid); + throw new ConversionException($"Failed to create/modify diaphragm {csiDiaphragm.name}"); } + + return csiDiaphragm.name; + } + + CSIDiaphragm diaphragmToSpeckle(string name) + { + bool semiRigid = false; + Model.Diaphragm.GetDiaphragm(name, ref semiRigid); + return new CSIDiaphragm(name, semiRigid); } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertLinkProperty.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertLinkProperty.cs index 57515297e8..3896ea6be5 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertLinkProperty.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertLinkProperty.cs @@ -1,49 +1,53 @@ -using Objects.Structural.CSI.Properties; +using Objects.Structural.CSI.Properties; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string LinkPropertyToNative(CSILinkProperty linkProperty) { - public string LinkPropertyToNative(CSILinkProperty linkProperty) - { - double[] value = new double[4]; - value[0] = linkProperty.M2PdeltaEnd1; - value[1] = linkProperty.MP2deltaEnd2; - value[2] = linkProperty.MP3deltaEnd1; - value[3] = linkProperty.MP3deltaEnd2; + double[] value = new double[4]; + value[0] = linkProperty.M2PdeltaEnd1; + value[1] = linkProperty.MP2deltaEnd2; + value[2] = linkProperty.MP3deltaEnd1; + value[3] = linkProperty.MP3deltaEnd2; - // TODO: test if this works, because I don't think it will... - var success1 = Model.PropLink.SetPDelta(linkProperty.name, ref value); - var success2 = Model.PropLink.SetWeightAndMass( - linkProperty.name, - linkProperty.weight, - linkProperty.mass, - linkProperty.rotationalInertia1, - linkProperty.rotationalInertia2, - linkProperty.rotationalInertia3 - ); + // TODO: test if this works, because I don't think it will... + var success1 = Model.PropLink.SetPDelta(linkProperty.name, ref value); + var success2 = Model.PropLink.SetWeightAndMass( + linkProperty.name, + linkProperty.weight, + linkProperty.mass, + linkProperty.rotationalInertia1, + linkProperty.rotationalInertia2, + linkProperty.rotationalInertia3 + ); - if (success1 != 0) - throw new ConversionException($"Failed to assign P-delta value to link property {linkProperty.name}"); - if (success2 != 0) - throw new ConversionException($"Failed to assign Weight and Mass value to link property {linkProperty.name}"); - - return linkProperty.name; + if (success1 != 0) + { + throw new ConversionException($"Failed to assign P-delta value to link property {linkProperty.name}"); } - public CSILinkProperty LinkPropertyToSpeckle(string name) + if (success2 != 0) { - double W = 0; - double M = 0; - double R1 = 0; - double R2 = 0; - double R3 = 0; - double[] Value = null; - Model.PropLink.GetWeightAndMass(name, ref W, ref M, ref R1, ref R2, ref R3); - Model.PropLink.GetPDelta(name, ref Value); - var speckleLinkProp = new CSILinkProperty(name, M, W, R1, R2, R3, Value[0], Value[1], Value[2], Value[3]); - return speckleLinkProp; + throw new ConversionException($"Failed to assign Weight and Mass value to link property {linkProperty.name}"); } + + return linkProperty.name; + } + + public CSILinkProperty LinkPropertyToSpeckle(string name) + { + double W = 0; + double M = 0; + double R1 = 0; + double R2 = 0; + double R3 = 0; + double[] Value = null; + Model.PropLink.GetWeightAndMass(name, ref W, ref M, ref R1, ref R2, ref R3); + Model.PropLink.GetPDelta(name, ref Value); + var speckleLinkProp = new CSILinkProperty(name, M, W, R1, R2, R3, Value[0], Value[1], Value[2], Value[3]); + return speckleLinkProp; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSectionProfile.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSectionProfile.cs index 15cef83339..08a9e0d591 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSectionProfile.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSectionProfile.cs @@ -1,306 +1,305 @@ -using System; +using System; using System.Collections.Generic; using Objects.Structural.Properties.Profiles; using CSiAPIv1; using System.Linq; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public SectionProfile SectionToSpeckle(string property) { - public SectionProfile SectionToSpeckle(string property) - { - var speckleSectionProfile = new SectionProfile(); - eFramePropType propType = eFramePropType.I; - string catalogue = ""; - string matProp = ""; - string sectionPropertyName = ""; + var speckleSectionProfile = new SectionProfile(); + eFramePropType propType = eFramePropType.I; + string catalogue = ""; + string matProp = ""; + string sectionPropertyName = ""; - int s = Model.PropFrame.GetNameInPropFile( - property, - ref sectionPropertyName, - ref catalogue, - ref matProp, - ref propType - ); + int s = Model.PropFrame.GetNameInPropFile( + property, + ref sectionPropertyName, + ref catalogue, + ref matProp, + ref propType + ); - GetSectionProfile(property, matProp, propType, ref speckleSectionProfile); + GetSectionProfile(property, matProp, propType, ref speckleSectionProfile); - if (!string.IsNullOrEmpty(catalogue)) - { - string[] arrayCatPath = catalogue.Split('\\'); - catalogue = arrayCatPath.Last(); - arrayCatPath = catalogue.Split('.'); - catalogue = arrayCatPath[0]; - - var catalogueSectionProfile = new Catalogue(property, catalogue, propType.ToString(), sectionPropertyName); + if (!string.IsNullOrEmpty(catalogue)) + { + string[] arrayCatPath = catalogue.Split('\\'); + catalogue = arrayCatPath.Last(); + arrayCatPath = catalogue.Split('.'); + catalogue = arrayCatPath[0]; - catalogueSectionProfile.applicationId = speckleSectionProfile.applicationId; + var catalogueSectionProfile = new Catalogue(property, catalogue, propType.ToString(), sectionPropertyName); - return catalogueSectionProfile; - } + catalogueSectionProfile.applicationId = speckleSectionProfile.applicationId; - return speckleSectionProfile; + return catalogueSectionProfile; + } - #region deprecated - //double T3 = 0; - //double T2 = 0; - //double Tf = 0; - //double TwF = 0; - //double Twt = 0; - //double Tw = 0; - //bool mirrorAbout3 = false; - //int color = 0; - //string notes = ""; - //string GUID = ""; - //string FileName = ""; + return speckleSectionProfile; - //s = Model.PropFrame.GetRectangle(property, ref FileName, ref matProp, ref T3, ref T2, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Rectangular(property, T3, T2); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + #region deprecated + //double T3 = 0; + //double T2 = 0; + //double Tf = 0; + //double TwF = 0; + //double Twt = 0; + //double Tw = 0; + //bool mirrorAbout3 = false; + //int color = 0; + //string notes = ""; + //string GUID = ""; + //string FileName = ""; - //s = Model.PropFrame.GetConcreteTee(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref TwF, ref Twt, ref mirrorAbout3, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Tee(property, T3, T2, TwF, Tf); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + //s = Model.PropFrame.GetRectangle(property, ref FileName, ref matProp, ref T3, ref T2, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Rectangular(property, T3, T2); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - //s = Model.PropFrame.GetCircle(property, ref FileName, ref matProp, ref T3, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Circular(property, T3 / 2); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + //s = Model.PropFrame.GetConcreteTee(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref TwF, ref Twt, ref mirrorAbout3, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Tee(property, T3, T2, TwF, Tf); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - //s = Model.PropFrame.GetAngle(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Angle(property, T3, T2, Tw, Tf); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + //s = Model.PropFrame.GetCircle(property, ref FileName, ref matProp, ref T3, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Circular(property, T3 / 2); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - //s = Model.PropFrame.GetChannel(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Channel(property, T3, T2, Tw, Tf); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + //s = Model.PropFrame.GetAngle(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Angle(property, T3, T2, Tw, Tf); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - //s = Model.PropFrame.GetTube(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Rectangular(property, T3, T2, Tw, Tf); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} + //s = Model.PropFrame.GetChannel(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Channel(property, T3, T2, Tw, Tf); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - //s = Model.PropFrame.GetPipe(property, ref FileName, ref matProp, ref T3, ref Tw, ref color, ref notes, ref GUID); - //if (s == 0) - //{ - // speckleSectionProfile = new Circular(property, T3, Tw); - // GetSectionProperties(property, speckleSectionProfile); - // return speckleSectionProfile; - //} - //return null; - #endregion - } + //s = Model.PropFrame.GetTube(property, ref FileName, ref matProp, ref T3, ref T2, ref Tf, ref Tw, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Rectangular(property, T3, T2, Tw, Tf); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} - public void GetSectionProfile( - string property, - string matProp, - eFramePropType propType, - ref SectionProfile speckleSectionProfile - ) - { - double T3 = 0; - double T2 = 0; - double Tf = 0; - double TwF = 0; - double Twt = 0; - double Tw = 0; - double T2b = 0; - double Tfb = 0; - bool mirrorAbout3 = false; - int color = 0; - string notes = ""; - string GUID = ""; - string FileName = ""; + //s = Model.PropFrame.GetPipe(property, ref FileName, ref matProp, ref T3, ref Tw, ref color, ref notes, ref GUID); + //if (s == 0) + //{ + // speckleSectionProfile = new Circular(property, T3, Tw); + // GetSectionProperties(property, speckleSectionProfile); + // return speckleSectionProfile; + //} + //return null; + #endregion + } - switch (propType) - { - case eFramePropType.I: - Model.PropFrame.GetISection( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref Tf, - ref Tw, - ref T2b, - ref Tfb, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new ISection(property, T3, T2, Tw, Tf); - break; - case eFramePropType.Rectangular: - Model.PropFrame.GetRectangle( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new Rectangular(property, T3, T2); - break; - case eFramePropType.ConcreteTee: - Model.PropFrame.GetConcreteTee( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref Tf, - ref TwF, - ref Twt, - ref mirrorAbout3, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new Tee(property, T3, T2, TwF, Tf); - break; - case eFramePropType.Circle: - Model.PropFrame.GetCircle(property, ref FileName, ref matProp, ref T3, ref color, ref notes, ref GUID); - speckleSectionProfile = new Circular(property, T3 / 2); - break; - case eFramePropType.Angle: - Model.PropFrame.GetAngle( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref Tf, - ref Tw, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new Angle(property, T3, T2, Tw, Tf); - break; - case eFramePropType.Channel: - Model.PropFrame.GetChannel( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref Tf, - ref Tw, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new Channel(property, T3, T2, Tw, Tf); - break; - case eFramePropType.Box: - Model.PropFrame.GetTube( - property, - ref FileName, - ref matProp, - ref T3, - ref T2, - ref Tf, - ref Tw, - ref color, - ref notes, - ref GUID - ); - speckleSectionProfile = new Rectangular(property, T3, T2, Tw, Tf); - break; - case eFramePropType.Pipe: - Model.PropFrame.GetPipe(property, ref FileName, ref matProp, ref T3, ref Tw, ref color, ref notes, ref GUID); - speckleSectionProfile = new Circular(property, T3, Tw); - break; - default: - break; - } + public void GetSectionProfile( + string property, + string matProp, + eFramePropType propType, + ref SectionProfile speckleSectionProfile + ) + { + double T3 = 0; + double T2 = 0; + double Tf = 0; + double TwF = 0; + double Twt = 0; + double Tw = 0; + double T2b = 0; + double Tfb = 0; + bool mirrorAbout3 = false; + int color = 0; + string notes = ""; + string GUID = ""; + string FileName = ""; - GetSectionProperties(property, ref speckleSectionProfile); - speckleSectionProfile.applicationId = GUID; + switch (propType) + { + case eFramePropType.I: + Model.PropFrame.GetISection( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref Tf, + ref Tw, + ref T2b, + ref Tfb, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new ISection(property, T3, T2, Tw, Tf); + break; + case eFramePropType.Rectangular: + Model.PropFrame.GetRectangle( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new Rectangular(property, T3, T2); + break; + case eFramePropType.ConcreteTee: + Model.PropFrame.GetConcreteTee( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref Tf, + ref TwF, + ref Twt, + ref mirrorAbout3, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new Tee(property, T3, T2, TwF, Tf); + break; + case eFramePropType.Circle: + Model.PropFrame.GetCircle(property, ref FileName, ref matProp, ref T3, ref color, ref notes, ref GUID); + speckleSectionProfile = new Circular(property, T3 / 2); + break; + case eFramePropType.Angle: + Model.PropFrame.GetAngle( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref Tf, + ref Tw, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new Angle(property, T3, T2, Tw, Tf); + break; + case eFramePropType.Channel: + Model.PropFrame.GetChannel( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref Tf, + ref Tw, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new Channel(property, T3, T2, Tw, Tf); + break; + case eFramePropType.Box: + Model.PropFrame.GetTube( + property, + ref FileName, + ref matProp, + ref T3, + ref T2, + ref Tf, + ref Tw, + ref color, + ref notes, + ref GUID + ); + speckleSectionProfile = new Rectangular(property, T3, T2, Tw, Tf); + break; + case eFramePropType.Pipe: + Model.PropFrame.GetPipe(property, ref FileName, ref matProp, ref T3, ref Tw, ref color, ref notes, ref GUID); + speckleSectionProfile = new Circular(property, T3, Tw); + break; + default: + break; } - public void GetSectionProperties(string property, ref SectionProfile sectionProfile) - { - double Area = 0; - double As2 = 0; - double As3 = 0; - double Torsion = 0; - double I22 = 0; - double I33 = 0; - double S22 = 0; - double S33 = 0; - double Z22 = 0; - double Z33 = 0; - double R22 = 0; - double R33 = 0; - int Color = 0; - string Notes = ""; - string GUID = ""; - // var s = Model.PropFrame.GetGeneral(property,ref FileName,ref MatProp,ref T3,ref T2,ref Area,ref As2,ref As3,ref Torsion,ref I22,ref I33,ref S22,ref S33,ref Z22,ref Z33,ref R22,ref R33,ref Color,ref Notes,ref GUID); - // if(s == 0){ - // sectionProfile.name = property; - // sectionProfile.area = Area; - // sectionProfile.Ky = As3 / Area; - // sectionProfile.Kz = As2 / Area; - // sectionProfile.Iyy = I33; - // sectionProfile.Izz = I22; - // sectionProfile.J = Torsion; - // sectionProfile.applicationId = GUID; - // } + GetSectionProperties(property, ref speckleSectionProfile); + speckleSectionProfile.applicationId = GUID; + } - var k = Model.PropFrame.GetSectProps( - property, - ref Area, - ref As2, - ref As3, - ref Torsion, - ref I22, - ref I33, - ref S22, - ref S33, - ref Z22, - ref Z33, - ref R22, - ref R33 - ); - if (k == 0) - { - sectionProfile.name = property; - sectionProfile.area = Area; - sectionProfile.Ky = (Area == 0 || As3 == 0) ? 0 : As3 / Area; - sectionProfile.Kz = (Area == 0 || As2 == 0) ? 0 : As2 / Area; - sectionProfile.Iyy = I33; - sectionProfile.Izz = I22; - sectionProfile.J = Torsion; - } + public void GetSectionProperties(string property, ref SectionProfile sectionProfile) + { + double Area = 0; + double As2 = 0; + double As3 = 0; + double Torsion = 0; + double I22 = 0; + double I33 = 0; + double S22 = 0; + double S33 = 0; + double Z22 = 0; + double Z33 = 0; + double R22 = 0; + double R33 = 0; + int Color = 0; + string Notes = ""; + string GUID = ""; + // var s = Model.PropFrame.GetGeneral(property,ref FileName,ref MatProp,ref T3,ref T2,ref Area,ref As2,ref As3,ref Torsion,ref I22,ref I33,ref S22,ref S33,ref Z22,ref Z33,ref R22,ref R33,ref Color,ref Notes,ref GUID); + // if(s == 0){ + // sectionProfile.name = property; + // sectionProfile.area = Area; + // sectionProfile.Ky = As3 / Area; + // sectionProfile.Kz = As2 / Area; + // sectionProfile.Iyy = I33; + // sectionProfile.Izz = I22; + // sectionProfile.J = Torsion; + // sectionProfile.applicationId = GUID; + // } - //to be discussed whether radius of gyration and section mod/plastic mod is needed ~ i personally think so + var k = Model.PropFrame.GetSectProps( + property, + ref Area, + ref As2, + ref As3, + ref Torsion, + ref I22, + ref I33, + ref S22, + ref S33, + ref Z22, + ref Z33, + ref R22, + ref R33 + ); + if (k == 0) + { + sectionProfile.name = property; + sectionProfile.area = Area; + sectionProfile.Ky = (Area == 0 || As3 == 0) ? 0 : As3 / Area; + sectionProfile.Kz = (Area == 0 || As2 == 0) ? 0 : As2 / Area; + sectionProfile.Iyy = I33; + sectionProfile.Izz = I22; + sectionProfile.J = Torsion; } + + //to be discussed whether radius of gyration and section mod/plastic mod is needed ~ i personally think so } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSpring.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSpring.cs index 653855c6cd..fa3dbdf4e7 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSpring.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertSpring.cs @@ -1,292 +1,273 @@ -using Objects.Structural.CSI.Properties; +using Objects.Structural.CSI.Properties; using Speckle.Core.Kits; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public string SpringPropertyToNative(CSISpringProperty springProperty) { - public string SpringPropertyToNative(CSISpringProperty springProperty) - { - double[] k = new double[6]; - k[0] = springProperty.stiffnessX; - k[1] = springProperty.stiffnessY; - k[2] = springProperty.stiffnessZ; - k[3] = springProperty.stiffnessXX; - k[4] = springProperty.stiffnessYY; - k[5] = springProperty.stiffnessZZ; + double[] k = new double[6]; + k[0] = springProperty.stiffnessX; + k[1] = springProperty.stiffnessY; + k[2] = springProperty.stiffnessZ; + k[3] = springProperty.stiffnessXX; + k[4] = springProperty.stiffnessYY; + k[5] = springProperty.stiffnessZZ; - switch (springProperty.springOption) - { - case SpringOption.Link: - const int springOption = 1; - int success = Model.PropPointSpring.SetPointSpringProp( - springProperty.name, - springOption, - ref k, - springProperty.CYs, - iGUID: springProperty.applicationId - ); - if (success != 0) - throw new ConversionException("Failed to create or modify named point spring property"); - return springProperty.name; - default: - //springOption = 2; - throw new ConversionNotSupportedException( - $"Converting {nameof(SpringOption)} {springProperty.springOption} to native is not currently supported " - ); - } - } - - public string LinearSpringPropertyToNative(CSILinearSpring linearSpringProperty) + switch (springProperty.springOption) { - var linearOption1 = 0; - var linearOption2 = 0; - switch (linearSpringProperty.LinearOption1) - { - case NonLinearOptions.CompressionOnly: - linearOption1 = 0; - break; - case NonLinearOptions.Linear: - linearOption1 = 1; - break; - case NonLinearOptions.TensionOnly: - linearOption1 = 2; - break; - } - switch (linearSpringProperty.LinearOption2) - { - case NonLinearOptions.CompressionOnly: - linearOption2 = 0; - break; - case NonLinearOptions.Linear: - linearOption2 = 1; - break; - case NonLinearOptions.TensionOnly: - linearOption2 = 2; - break; - } - var success = Model.PropLineSpring.SetLineSpringProp( - linearSpringProperty.name, - linearSpringProperty.stiffnessX, - linearSpringProperty.stiffnessY, - linearSpringProperty.stiffnessZ, - linearSpringProperty.stiffnessXX, - linearOption1, - linearOption2, - iGUID: linearSpringProperty.applicationId - ); + case SpringOption.Link: + const int springOption = 1; + int success = Model.PropPointSpring.SetPointSpringProp( + springProperty.name, + springOption, + ref k, + springProperty.CYs, + iGUID: springProperty.applicationId + ); + if (success != 0) + { + throw new ConversionException("Failed to create or modify named point spring property"); + } - if (success != 0) - throw new ConversionException( - $"Failed to create/modify named line spring property {linearSpringProperty.name}" + return springProperty.name; + default: + //springOption = 2; + throw new ConversionNotSupportedException( + $"Converting {nameof(SpringOption)} {springProperty.springOption} to native is not currently supported " ); + } + } - return linearSpringProperty.name; + public string LinearSpringPropertyToNative(CSILinearSpring linearSpringProperty) + { + var linearOption1 = 0; + var linearOption2 = 0; + switch (linearSpringProperty.LinearOption1) + { + case NonLinearOptions.CompressionOnly: + linearOption1 = 0; + break; + case NonLinearOptions.Linear: + linearOption1 = 1; + break; + case NonLinearOptions.TensionOnly: + linearOption1 = 2; + break; } + switch (linearSpringProperty.LinearOption2) + { + case NonLinearOptions.CompressionOnly: + linearOption2 = 0; + break; + case NonLinearOptions.Linear: + linearOption2 = 1; + break; + case NonLinearOptions.TensionOnly: + linearOption2 = 2; + break; + } + var success = Model.PropLineSpring.SetLineSpringProp( + linearSpringProperty.name, + linearSpringProperty.stiffnessX, + linearSpringProperty.stiffnessY, + linearSpringProperty.stiffnessZ, + linearSpringProperty.stiffnessXX, + linearOption1, + linearOption2, + iGUID: linearSpringProperty.applicationId + ); - public string AreaSpringPropertyToNative(CSIAreaSpring areaSpring) + if (success != 0) { - var linearOption1 = 0; - switch (areaSpring.LinearOption3) - { - case NonLinearOptions.CompressionOnly: - linearOption1 = 0; - break; - case NonLinearOptions.Linear: - linearOption1 = 1; - break; - case NonLinearOptions.TensionOnly: - linearOption1 = 2; - break; - } - var success = Model.PropAreaSpring.SetAreaSpringProp( - areaSpring.name, - areaSpring.stiffnessX, - areaSpring.stiffnessY, - areaSpring.stiffnessZ, - linearOption1, - iGUID: areaSpring.applicationId - ); + throw new ConversionException($"Failed to create/modify named line spring property {linearSpringProperty.name}"); + } - if (success != 0) - throw new ConversionException($"Failed to create/modify named area spring property {areaSpring.name}"); + return linearSpringProperty.name; + } - return areaSpring.name; + public string AreaSpringPropertyToNative(CSIAreaSpring areaSpring) + { + var linearOption1 = 0; + switch (areaSpring.LinearOption3) + { + case NonLinearOptions.CompressionOnly: + linearOption1 = 0; + break; + case NonLinearOptions.Linear: + linearOption1 = 1; + break; + case NonLinearOptions.TensionOnly: + linearOption1 = 2; + break; } + var success = Model.PropAreaSpring.SetAreaSpringProp( + areaSpring.name, + areaSpring.stiffnessX, + areaSpring.stiffnessY, + areaSpring.stiffnessZ, + linearOption1, + iGUID: areaSpring.applicationId + ); - public CSISpringProperty SpringPropertyToSpeckle(string name) + if (success != 0) { - double[] stiffness = null; - int springOption = 0; - string Cys = null; - string soilProfile = null; - string footing = null; - double period = 0; - int color = 0; - string notes = null; - string GUID = null; - Model.PropPointSpring.GetPointSpringProp( - name, - ref springOption, - ref stiffness, - ref Cys, - ref soilProfile, - ref footing, - ref period, - ref color, - ref notes, - ref GUID - ); - switch (springOption) - { - case 1: - CSISpringProperty speckleSpringProperty = new CSISpringProperty( - name, - Cys, - stiffness[0], - stiffness[1], - stiffness[2], - stiffness[3], - stiffness[4], - stiffness[5] - ); - speckleSpringProperty.applicationId = GUID; - return speckleSpringProperty; - case 2: - speckleSpringProperty = new CSISpringProperty(name, soilProfile, footing, period); - speckleSpringProperty.applicationId = GUID; - return speckleSpringProperty; - default: - speckleSpringProperty = new CSISpringProperty(); - return speckleSpringProperty; - } + throw new ConversionException($"Failed to create/modify named area spring property {areaSpring.name}"); } - public CSILinearSpring LinearSpringToSpeckle(string name) + return areaSpring.name; + } + + public CSISpringProperty SpringPropertyToSpeckle(string name) + { + double[] stiffness = null; + int springOption = 0; + string Cys = null; + string soilProfile = null; + string footing = null; + double period = 0; + int color = 0; + string notes = null; + string GUID = null; + Model.PropPointSpring.GetPointSpringProp( + name, + ref springOption, + ref stiffness, + ref Cys, + ref soilProfile, + ref footing, + ref period, + ref color, + ref notes, + ref GUID + ); + switch (springOption) { - double stiffnessX = 0; - double stiffnessY = 0; - double stiffnessZ = 0; - double stiffnessXX = 0; - int nonLinearOpt1 = 0; - int nonLinearOpt2 = 0; - int color = 0; - string notes = null; - string GUID = null; - NonLinearOptions nonLinearOptions1 = NonLinearOptions.Linear; - NonLinearOptions nonLinearOptions2 = NonLinearOptions.Linear; + case 1: + CSISpringProperty speckleSpringProperty = + new(name, Cys, stiffness[0], stiffness[1], stiffness[2], stiffness[3], stiffness[4], stiffness[5]); + speckleSpringProperty.applicationId = GUID; + return speckleSpringProperty; + case 2: + speckleSpringProperty = new CSISpringProperty(name, soilProfile, footing, period); + speckleSpringProperty.applicationId = GUID; + return speckleSpringProperty; + default: + speckleSpringProperty = new CSISpringProperty(); + return speckleSpringProperty; + } + } - var s = Model.PropLineSpring.GetLineSpringProp( - name, - ref stiffnessX, - ref stiffnessY, - ref stiffnessZ, - ref stiffnessXX, - ref nonLinearOpt1, - ref nonLinearOpt2, - ref color, - ref notes, - ref GUID - ); - switch (nonLinearOpt1) - { - case 0: - nonLinearOptions1 = NonLinearOptions.Linear; - break; - case 1: - nonLinearOptions1 = NonLinearOptions.CompressionOnly; - break; - case 2: - nonLinearOptions1 = NonLinearOptions.TensionOnly; - break; - } - switch (nonLinearOpt2) - { - case 0: - nonLinearOptions2 = NonLinearOptions.Linear; - break; - case 1: - nonLinearOptions2 = NonLinearOptions.CompressionOnly; - break; - case 2: - nonLinearOptions2 = NonLinearOptions.TensionOnly; - break; - } + public CSILinearSpring LinearSpringToSpeckle(string name) + { + double stiffnessX = 0; + double stiffnessY = 0; + double stiffnessZ = 0; + double stiffnessXX = 0; + int nonLinearOpt1 = 0; + int nonLinearOpt2 = 0; + int color = 0; + string notes = null; + string GUID = null; + NonLinearOptions nonLinearOptions1 = NonLinearOptions.Linear; + NonLinearOptions nonLinearOptions2 = NonLinearOptions.Linear; - if (s == 0) - { - CSILinearSpring speckleLinearSpring = new CSILinearSpring( - name, - stiffnessX, - stiffnessY, - stiffnessZ, - stiffnessXX, - nonLinearOptions1, - nonLinearOptions2, - GUID - ); - return speckleLinearSpring; - } - return null; + var s = Model.PropLineSpring.GetLineSpringProp( + name, + ref stiffnessX, + ref stiffnessY, + ref stiffnessZ, + ref stiffnessXX, + ref nonLinearOpt1, + ref nonLinearOpt2, + ref color, + ref notes, + ref GUID + ); + switch (nonLinearOpt1) + { + case 0: + nonLinearOptions1 = NonLinearOptions.Linear; + break; + case 1: + nonLinearOptions1 = NonLinearOptions.CompressionOnly; + break; + case 2: + nonLinearOptions1 = NonLinearOptions.TensionOnly; + break; + } + switch (nonLinearOpt2) + { + case 0: + nonLinearOptions2 = NonLinearOptions.Linear; + break; + case 1: + nonLinearOptions2 = NonLinearOptions.CompressionOnly; + break; + case 2: + nonLinearOptions2 = NonLinearOptions.TensionOnly; + break; } - public CSIAreaSpring AreaSpringToSpeckle(string name) + if (s == 0) { - double stiffnessX = 0; - double stiffnessY = 0; - double stiffnessZ = 0; + CSILinearSpring speckleLinearSpring = + new(name, stiffnessX, stiffnessY, stiffnessZ, stiffnessXX, nonLinearOptions1, nonLinearOptions2, GUID); + return speckleLinearSpring; + } + return null; + } - int nonLinearOpt1 = 0; - int springOption = 0; - string soilProfile = null; - double endLengthRatio = 0; - double period = 0; + public CSIAreaSpring AreaSpringToSpeckle(string name) + { + double stiffnessX = 0; + double stiffnessY = 0; + double stiffnessZ = 0; - int color = 0; - string notes = null; - string GUID = null; - NonLinearOptions nonLinearOptions1 = NonLinearOptions.Linear; + int nonLinearOpt1 = 0; + int springOption = 0; + string soilProfile = null; + double endLengthRatio = 0; + double period = 0; - var s = Model.PropAreaSpring.GetAreaSpringProp( - name, - ref stiffnessX, - ref stiffnessY, - ref stiffnessZ, - ref nonLinearOpt1, - ref springOption, - ref soilProfile, - ref endLengthRatio, - ref period, - ref color, - ref notes, - ref GUID - ); - switch (nonLinearOpt1) - { - case 0: - nonLinearOptions1 = NonLinearOptions.Linear; - break; - case 1: - nonLinearOptions1 = NonLinearOptions.CompressionOnly; - break; - case 2: - nonLinearOptions1 = NonLinearOptions.TensionOnly; - break; - } + int color = 0; + string notes = null; + string GUID = null; + NonLinearOptions nonLinearOptions1 = NonLinearOptions.Linear; - if (s == 0) - { - CSIAreaSpring speckleAreaSpring = new CSIAreaSpring( - name, - stiffnessX, - stiffnessY, - stiffnessZ, - nonLinearOptions1, - GUID - ); - return speckleAreaSpring; - } - return null; + var s = Model.PropAreaSpring.GetAreaSpringProp( + name, + ref stiffnessX, + ref stiffnessY, + ref stiffnessZ, + ref nonLinearOpt1, + ref springOption, + ref soilProfile, + ref endLengthRatio, + ref period, + ref color, + ref notes, + ref GUID + ); + switch (nonLinearOpt1) + { + case 0: + nonLinearOptions1 = NonLinearOptions.Linear; + break; + case 1: + nonLinearOptions1 = NonLinearOptions.CompressionOnly; + break; + case 2: + nonLinearOptions1 = NonLinearOptions.TensionOnly; + break; + } + + if (s == 0) + { + CSIAreaSpring speckleAreaSpring = new(name, stiffnessX, stiffnessY, stiffnessZ, nonLinearOptions1, GUID); + return speckleAreaSpring; } + return null; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertTendonProperty.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertTendonProperty.cs index 70fa93d6a2..e3d3b88c96 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertTendonProperty.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Properties/ConvertTendonProperty.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Objects.Structural.Properties.Profiles; using CSiAPIv1; @@ -6,32 +6,31 @@ using Objects.Structural.CSI.Properties; using Objects.Structural.Properties; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public CSITendonProperty TendonPropToSpeckle(string name) { - public CSITendonProperty TendonPropToSpeckle(string name) + var specklePropertyTendon = new CSITendonProperty(); + string matProp = null; + int modelingOption = 0; + double area = 0; + int color = 0; + string notes = null; + string GUID = null; + Model.PropTendon.GetProp(name, ref matProp, ref modelingOption, ref area, ref color, ref notes, ref GUID); + specklePropertyTendon.applicationId = GUID; + specklePropertyTendon.Area = area; + specklePropertyTendon.material = MaterialToSpeckle(matProp); + if (modelingOption == 1) + { + specklePropertyTendon.modelingOption = ModelingOption.Loads; + } + else { - var specklePropertyTendon = new CSITendonProperty(); - string matProp = null; - int modelingOption = 0; - double area = 0; - int color = 0; - string notes = null; - string GUID = null; - Model.PropTendon.GetProp(name, ref matProp, ref modelingOption, ref area, ref color, ref notes, ref GUID); - specklePropertyTendon.applicationId = GUID; - specklePropertyTendon.Area = area; - specklePropertyTendon.material = MaterialToSpeckle(matProp); - if (modelingOption == 1) - { - specklePropertyTendon.modelingOption = ModelingOption.Loads; - } - else - { - specklePropertyTendon.modelingOption = ModelingOption.Elements; - } - return specklePropertyTendon; + specklePropertyTendon.modelingOption = ModelingOption.Elements; } + return specklePropertyTendon; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResultGlobal.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResultGlobal.cs index f0d79f45b9..50daa557f4 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResultGlobal.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResultGlobal.cs @@ -1,79 +1,78 @@ using Objects.Structural.Results; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public ResultGlobal ResultGlobal() { - public ResultGlobal ResultGlobal() - { - var speckleResultGlobal = new ResultGlobal(); - - int numberResult = 0; - string[] loadcase = null; - string[] stepType = null; - double[] stepNum = null; - double[] period = null; - double[] frequency = null; - double[] circFreq = null; - double[] eigenValue = null; - var s = Model.Results.ModalPeriod( - ref numberResult, - ref loadcase, - ref stepType, - ref stepNum, - ref period, - ref frequency, - ref circFreq, - ref eigenValue - ); + var speckleResultGlobal = new ResultGlobal(); - double[] UX = null; - double[] UY = null; - double[] UZ = null; - double[] RX = null; - double[] RY = null; - double[] RZ = null; - double[] ModalMass = null; - double[] ModalStiff = null; + int numberResult = 0; + string[] loadcase = null; + string[] stepType = null; + double[] stepNum = null; + double[] period = null; + double[] frequency = null; + double[] circFreq = null; + double[] eigenValue = null; + var s = Model.Results.ModalPeriod( + ref numberResult, + ref loadcase, + ref stepType, + ref stepNum, + ref period, + ref frequency, + ref circFreq, + ref eigenValue + ); - var i = Model.Results.ModalParticipationFactors( - ref numberResult, - ref loadcase, - ref stepType, - ref stepNum, - ref period, - ref UX, - ref UY, - ref UZ, - ref RX, - ref RY, - ref RZ, - ref ModalMass, - ref ModalStiff - ); + double[] UX = null; + double[] UY = null; + double[] UZ = null; + double[] RX = null; + double[] RY = null; + double[] RZ = null; + double[] ModalMass = null; + double[] ModalStiff = null; - if (s == 0 && i == 0) - { - speckleResultGlobal.modalStiffness = (float)ModalStiff[0]; - speckleResultGlobal.reactionX = (float)UX[0]; - speckleResultGlobal.reactionY = (float)UY[0]; - speckleResultGlobal.reactionZ = (float)UZ[0]; - speckleResultGlobal.reactionXX = (float)RX[0]; - speckleResultGlobal.reactionYY = (float)RY[0]; - speckleResultGlobal.reactionZZ = (float)RZ[0]; - speckleResultGlobal.effMassX = - speckleResultGlobal.effMassXX = - speckleResultGlobal.effMassY = - speckleResultGlobal.effMassYY = - speckleResultGlobal.effMassZ = - speckleResultGlobal.effMassZZ = - (float)ModalMass[0]; + var i = Model.Results.ModalParticipationFactors( + ref numberResult, + ref loadcase, + ref stepType, + ref stepNum, + ref period, + ref UX, + ref UY, + ref UZ, + ref RX, + ref RY, + ref RZ, + ref ModalMass, + ref ModalStiff + ); - speckleResultGlobal.mode = (float)stepNum[0]; - speckleResultGlobal.frequency = (float)frequency[0]; - } + if (s == 0 && i == 0) + { + speckleResultGlobal.modalStiffness = (float)ModalStiff[0]; + speckleResultGlobal.reactionX = (float)UX[0]; + speckleResultGlobal.reactionY = (float)UY[0]; + speckleResultGlobal.reactionZ = (float)UZ[0]; + speckleResultGlobal.reactionXX = (float)RX[0]; + speckleResultGlobal.reactionYY = (float)RY[0]; + speckleResultGlobal.reactionZZ = (float)RZ[0]; + speckleResultGlobal.effMassX = + speckleResultGlobal.effMassXX = + speckleResultGlobal.effMassY = + speckleResultGlobal.effMassYY = + speckleResultGlobal.effMassZ = + speckleResultGlobal.effMassZZ = + (float)ModalMass[0]; - return speckleResultGlobal; + speckleResultGlobal.mode = (float)stepNum[0]; + speckleResultGlobal.frequency = (float)frequency[0]; } + + return speckleResultGlobal; } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResults.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResults.cs index 75015840ac..8c8cc43043 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResults.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/PartialClasses/Results/ConvertResults.cs @@ -3,36 +3,36 @@ using System; using System.Collections.Generic; -namespace Objects.Converter.CSI +namespace Objects.Converter.CSI; + +public partial class ConverterCSI { - public partial class ConverterCSI + public Base ResultsToSpeckle() { - public Base ResultsToSpeckle() + return ResultGlobal(); + } + + private IEnumerable GetLoadCases() + { + var numberOfLoadCases = 0; + var loadCaseNames = Array.Empty(); + + Model.LoadCases.GetNameList(ref numberOfLoadCases, ref loadCaseNames); + foreach (var loadCase in loadCaseNames) { - return ResultGlobal(); + yield return LoadPatternToSpeckle(loadCase); } + } - private IEnumerable GetLoadCases() - { - var numberOfLoadCases = 0; - var loadCaseNames = Array.Empty(); + private IEnumerable GetLoadCombos() + { + var numberOfLoadCombos = 0; + var loadComboNames = Array.Empty(); - Model.LoadCases.GetNameList(ref numberOfLoadCases, ref loadCaseNames); - foreach (var loadCase in loadCaseNames) - { - yield return LoadPatternToSpeckle(loadCase); - } - } - private IEnumerable GetLoadCombos() + Model.RespCombo.GetNameList(ref numberOfLoadCombos, ref loadComboNames); + foreach (string loadComboName in loadComboNames) { - var numberOfLoadCombos = 0; - var loadComboNames = Array.Empty(); - - Model.RespCombo.GetNameList(ref numberOfLoadCombos, ref loadComboNames); - foreach (string loadComboName in loadComboNames) - { - yield return LoadCombinationToSpeckle(loadComboName); - } + yield return LoadCombinationToSpeckle(loadComboName); } } } diff --git a/Objects/Converters/ConverterCSI/ConverterCSIShared/Services/ToNativeScalingService.cs b/Objects/Converters/ConverterCSI/ConverterCSIShared/Services/ToNativeScalingService.cs index 21951aeaa6..073976b67a 100644 --- a/Objects/Converters/ConverterCSI/ConverterCSIShared/Services/ToNativeScalingService.cs +++ b/Objects/Converters/ConverterCSI/ConverterCSIShared/Services/ToNativeScalingService.cs @@ -3,33 +3,32 @@ using CSiAPIv1; using Speckle.Core.Kits; -namespace ConverterCSIShared.Services +namespace ConverterCSIShared.Services; + +public class ToNativeScalingService { - public class ToNativeScalingService + public ToNativeScalingService(cSapModel cSapModel) { - public ToNativeScalingService(cSapModel cSapModel) - { - var unitsArray = cSapModel.GetPresentUnits().ToString().Split('_'); + var unitsArray = cSapModel.GetPresentUnits().ToString().Split('_'); - ForceUnits = unitsArray[0]; - LengthUnits = unitsArray[1]; - TempuratureUnits = unitsArray[2]; - } + ForceUnits = unitsArray[0]; + LengthUnits = unitsArray[1]; + TempuratureUnits = unitsArray[2]; + } - public string LengthUnits { get; private set; } - public string ForceUnits { get; private set; } - public string TempuratureUnits { get; private set; } + public string LengthUnits { get; private set; } + public string ForceUnits { get; private set; } + public string TempuratureUnits { get; private set; } - /// - /// Scales a value from a length unit of a specified power to the native length unit to the same power - /// - /// - /// - /// - /// - public double ScaleLength(double value, string speckleUnits, int power = 1) - { - return value * Math.Pow(Units.GetConversionFactor(speckleUnits, LengthUnits), power); - } + /// + /// Scales a value from a length unit of a specified power to the native length unit to the same power + /// + /// + /// + /// + /// + public double ScaleLength(double value, string speckleUnits, int power = 1) + { + return value * Math.Pow(Units.GetConversionFactor(speckleUnits, LengthUnits), power); } } diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterFixture.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterFixture.cs index 013b763040..e1d3b2ea18 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterFixture.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterFixture.cs @@ -8,31 +8,31 @@ namespace ConverterDxf.Tests { - public class ConverterFixture: IDisposable - { - public SpeckleDxfConverter Converter; - public readonly Dxf.DxfDocument Doc; + public class ConverterFixture : IDisposable + { + public SpeckleDxfConverter Converter; + public readonly Dxf.DxfDocument Doc; - public ConverterFixture() - { - Converter = new SpeckleDxfConverter(); - Doc = new Dxf.DxfDocument(); - Doc.DrawingVariables.InsUnits = DrawingUnits.Meters; - Converter.SetContextDocument(Doc); - } + public ConverterFixture() + { + Converter = new SpeckleDxfConverter(); + Doc = new Dxf.DxfDocument(); + Doc.DrawingVariables.InsUnits = DrawingUnits.Meters; + Converter.SetContextDocument(Doc); + } - public T AssertAndConvertToNative(Base @base) - { - Assert.True(Converter.CanConvertToNative(@base)); - var dxfObject = Converter.ConvertToNative(@base); - Assert.NotNull(dxfObject); - Assert.IsAssignableFrom(dxfObject); - return (T)dxfObject; - } + public T AssertAndConvertToNative(Base @base) + { + Assert.True(Converter.CanConvertToNative(@base)); + var dxfObject = Converter.ConvertToNative(@base); + Assert.NotNull(dxfObject); + Assert.IsAssignableFrom(dxfObject); + return (T)dxfObject; + } - public void Dispose() - { - Converter = null; - } + public void Dispose() + { + Converter = null; } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterSetup.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterSetup.cs index bf3a70f0d5..c11304cd8e 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterSetup.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/ConverterSetup.cs @@ -5,22 +5,19 @@ namespace ConverterDxf.Tests { - public static class ConverterSetup - { - public static string TestStream = "https://latest.speckle.dev/streams/24c3741255/branches/1%20standard/meters"; - - public static IEnumerable FetchAllObjectsOfType(string streamUrl) where T: Base - => Speckle.Core.Api.Helpers.Receive(streamUrl) - .Result - .Flatten(b => b is T) - .Where(b => b is T) - .Cast(); - - public static IEnumerable GetTestMemberData() where T: Base - { - var d =FetchAllObjectsOfType(TestStream).Select(v => new object[] { v }); - return d; - } + public static class ConverterSetup + { + public static string TestStream = "https://latest.speckle.dev/streams/24c3741255/branches/1%20standard/meters"; + + public static IEnumerable FetchAllObjectsOfType(string streamUrl) + where T : Base => + Speckle.Core.Api.Helpers.Receive(streamUrl).Result.Flatten(b => b is T).Where(b => b is T).Cast(); + public static IEnumerable GetTestMemberData() + where T : Base + { + var d = FetchAllObjectsOfType(TestStream).Select(v => new object[] { v }); + return d; } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/BrepTests.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/BrepTests.cs index 49109a96d4..afbe881da4 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/BrepTests.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/BrepTests.cs @@ -7,32 +7,31 @@ namespace ConverterDxf.Tests.Geometry { - public class BrepTests : IClassFixture - { - private readonly ConverterFixture fixture = new ConverterFixture(); + public class BrepTests : IClassFixture + { + private readonly ConverterFixture fixture = new ConverterFixture(); - public static IEnumerable BrepData => ConverterSetup.GetTestMemberData(); + public static IEnumerable BrepData => ConverterSetup.GetTestMemberData(); - [Theory] - [MemberData(nameof(BrepData))] - public void CanConvert_BrepToPrettyNative(Brep mesh) - { - fixture.Converter.Settings.PrettyMeshes = true; - var dxfMeshEntities = fixture.AssertAndConvertToNative>(mesh).ToList(); - Assert.NotEmpty(dxfMeshEntities); - Assert.All(dxfMeshEntities, o => Assert.True(o is Dxfe.Face3D || o is Dxfe.Line)); - // TODO: Add better tests for the BREP fallback to mesh - } - - [Theory] - [MemberData(nameof(BrepData))] - public void CanConvert_BrepToNative(Brep mesh) - { - fixture.Converter.Settings.PrettyMeshes = false; - var dxfMeshes = fixture.AssertAndConvertToNative>(mesh); - Assert.NotEmpty(dxfMeshes); - // TODO: Add better tests for the BREP fallback to mesh - } + [Theory] + [MemberData(nameof(BrepData))] + public void CanConvert_BrepToPrettyNative(Brep mesh) + { + fixture.Converter.Settings.PrettyMeshes = true; + var dxfMeshEntities = fixture.AssertAndConvertToNative>(mesh).ToList(); + Assert.NotEmpty(dxfMeshEntities); + Assert.All(dxfMeshEntities, o => Assert.True(o is Dxfe.Face3D || o is Dxfe.Line)); + // TODO: Add better tests for the BREP fallback to mesh + } + [Theory] + [MemberData(nameof(BrepData))] + public void CanConvert_BrepToNative(Brep mesh) + { + fixture.Converter.Settings.PrettyMeshes = false; + var dxfMeshes = fixture.AssertAndConvertToNative>(mesh); + Assert.NotEmpty(dxfMeshes); + // TODO: Add better tests for the BREP fallback to mesh } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/CurveTests.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/CurveTests.cs index f14782b56e..850eab6132 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/CurveTests.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/CurveTests.cs @@ -6,18 +6,18 @@ namespace ConverterDxf.Tests.Geometry { - public class CurveTests : IClassFixture - { - private readonly ConverterFixture fixture = new ConverterFixture(); - - public static IEnumerable LineData => ConverterSetup.GetTestMemberData(); + public class CurveTests : IClassFixture + { + private readonly ConverterFixture fixture = new ConverterFixture(); + + public static IEnumerable LineData => ConverterSetup.GetTestMemberData(); - [Theory] - [MemberData(nameof(LineData))] - public void CanConvert_LineToNative(Line line) - { - var dxfLine = fixture.AssertAndConvertToNative(line); - // TODO: Add line specific tests. - } + [Theory] + [MemberData(nameof(LineData))] + public void CanConvert_LineToNative(Line line) + { + var dxfLine = fixture.AssertAndConvertToNative(line); + // TODO: Add line specific tests. } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/MeshTests.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/MeshTests.cs index 1e2a5d3f9c..a60b2c4923 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/MeshTests.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/MeshTests.cs @@ -7,31 +7,30 @@ namespace ConverterDxf.Tests.Geometry { - public class MeshTests : IClassFixture - { - private readonly ConverterFixture fixture = new ConverterFixture(); + public class MeshTests : IClassFixture + { + private readonly ConverterFixture fixture = new ConverterFixture(); - public static IEnumerable MeshData => ConverterSetup.GetTestMemberData(); + public static IEnumerable MeshData => ConverterSetup.GetTestMemberData(); - [Theory] - [MemberData(nameof(MeshData))] - public void CanConvert_MeshToPrettyNative(Mesh mesh) - { - fixture.Converter.Settings.PrettyMeshes = true; - var dxfMeshEntities = fixture.AssertAndConvertToNative>(mesh).ToList(); - Assert.NotEmpty(dxfMeshEntities); - Assert.All(dxfMeshEntities, o => Assert.True(o is Dxfe.Face3D || o is Dxfe.Line)); - } - - [Theory] - [MemberData(nameof(MeshData))] - public void CanConvert_MeshToNative(Mesh mesh) - { - fixture.Converter.Settings.PrettyMeshes = false; - var dxfMesh = fixture.AssertAndConvertToNative(mesh); - //TODO: Add mesh specific tests - Assert.Equal(mesh.vertices.Count, dxfMesh.Vertexes.Count * 3); - } + [Theory] + [MemberData(nameof(MeshData))] + public void CanConvert_MeshToPrettyNative(Mesh mesh) + { + fixture.Converter.Settings.PrettyMeshes = true; + var dxfMeshEntities = fixture.AssertAndConvertToNative>(mesh).ToList(); + Assert.NotEmpty(dxfMeshEntities); + Assert.All(dxfMeshEntities, o => Assert.True(o is Dxfe.Face3D || o is Dxfe.Line)); + } + [Theory] + [MemberData(nameof(MeshData))] + public void CanConvert_MeshToNative(Mesh mesh) + { + fixture.Converter.Settings.PrettyMeshes = false; + var dxfMesh = fixture.AssertAndConvertToNative(mesh); + //TODO: Add mesh specific tests + Assert.Equal(mesh.vertices.Count, dxfMesh.Vertexes.Count * 3); } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/VectorTests.cs b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/VectorTests.cs index 4a2f174392..2e7e97b5e7 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/VectorTests.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf.Tests/Geometry/VectorTests.cs @@ -6,31 +6,31 @@ namespace ConverterDxf.Tests.Geometry { - public class VectorTests : IClassFixture - { - private readonly ConverterFixture fixture = new ConverterFixture(); + public class VectorTests : IClassFixture + { + private readonly ConverterFixture fixture = new ConverterFixture(); - public static IEnumerable PointData => ConverterSetup.GetTestMemberData(); - public static IEnumerable VectorData => ConverterSetup.GetTestMemberData(); + public static IEnumerable PointData => ConverterSetup.GetTestMemberData(); + public static IEnumerable VectorData => ConverterSetup.GetTestMemberData(); - [Theory] - [MemberData(nameof(PointData))] - public void CanConvert_PointToNative(Point pt) - { - var dxfPt = fixture.AssertAndConvertToNative(pt); - Assert.Equal(pt.x, dxfPt.Position.X); - Assert.Equal(pt.y, dxfPt.Position.Y); - Assert.Equal(pt.z, dxfPt.Position.Z); - } + [Theory] + [MemberData(nameof(PointData))] + public void CanConvert_PointToNative(Point pt) + { + var dxfPt = fixture.AssertAndConvertToNative(pt); + Assert.Equal(pt.x, dxfPt.Position.X); + Assert.Equal(pt.y, dxfPt.Position.Y); + Assert.Equal(pt.z, dxfPt.Position.Z); + } - [Theory] - [MemberData(nameof(VectorData))] - public void CanConvert_VectorToNative(Vector v) - { - var dxfVector = fixture.AssertAndConvertToNative(v); - Assert.Equal(v.x, dxfVector.X); - Assert.Equal(v.y, dxfVector.Y); - Assert.Equal(v.z, dxfVector.Z); - } + [Theory] + [MemberData(nameof(VectorData))] + public void CanConvert_VectorToNative(Vector v) + { + var dxfVector = fixture.AssertAndConvertToNative(v); + Assert.Equal(v.x, dxfVector.X); + Assert.Equal(v.y, dxfVector.Y); + Assert.Equal(v.z, dxfVector.Z); } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/ConverterDxfSettings.cs b/Objects/Converters/ConverterDxf/ConverterDxf/ConverterDxfSettings.cs index 69296acdaa..e7f0a787ec 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/ConverterDxfSettings.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/ConverterDxfSettings.cs @@ -1,10 +1,9 @@ using Speckle.Core.Kits; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public class ConverterDxfSettings { - public class ConverterDxfSettings - { - public bool PrettyMeshes = true; - public string DocUnits = Units.Meters; - } -} \ No newline at end of file + public bool PrettyMeshes = true; + public string DocUnits = Units.Meters; +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Document.cs b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Document.cs index 859393144f..5da9c29086 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Document.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Document.cs @@ -2,42 +2,42 @@ using System.Collections.Generic; using Speckle.Core.Models; using Speckle.netDxf; -namespace Objects.Converters.DxfConverter + +namespace Objects.Converters.DxfConverter; + +public partial class SpeckleDxfConverter { - public partial class SpeckleDxfConverter + public void SetContextDocument(object doc) + { + switch (doc) { - public void SetContextDocument(object doc) - { - switch (doc) - { - case null: // Create a new in-memory document - Doc = new DxfDocument(); - Doc.DrawingVariables.InsUnits = UnitsToDocUnits(Settings.DocUnits); - break; - case string str: // Load up an existing document - Doc = DxfDocument.Load(str); - break; - case DxfDocument d: - Doc = d; - break; - default: - throw new Exception("Provided doc is not a string or a DXF doc"); - } - } + case null: // Create a new in-memory document + Doc = new DxfDocument(); + Doc.DrawingVariables.InsUnits = UnitsToDocUnits(Settings.DocUnits); + break; + case string str: // Load up an existing document + Doc = DxfDocument.Load(str); + break; + case DxfDocument d: + Doc = d; + break; + default: + throw new Exception("Provided doc is not a string or a DXF doc"); + } + } - public void SaveContextDocument(string path) - { - Doc?.Save(path); - } + public void SaveContextDocument(string path) + { + Doc?.Save(path); + } - public void SetContextObjects(List objects) - { - // No context tracking - } + public void SetContextObjects(List objects) + { + // No context tracking + } - public void SetPreviousContextObjects(List objects) - { - // No context tracking - } - } -} \ No newline at end of file + public void SetPreviousContextObjects(List objects) + { + // No context tracking + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Geometry.cs b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Geometry.cs index 12a54cc982..a775e57727 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Geometry.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Geometry.cs @@ -12,87 +12,94 @@ using Mesh = Objects.Geometry.Mesh; using Point = Objects.Geometry.Point; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public partial class SpeckleDxfConverter { - public partial class SpeckleDxfConverter - { - public Dxf.Vector3 VectorToNative(Point pt) => VectorToNative(new Vector(pt) { units = pt.units }); - public Dxf.Vector3 VectorToNative(Vector pt) => new Dxf.Vector3(ScaleToNative(pt.x, pt.units), ScaleToNative(pt.y, pt.units), ScaleToNative(pt.z, pt.units)); - public Dxf.Entities.Point PointToNative(Point pt) => new Dxf.Entities.Point(VectorToNative(pt)); + public Dxf.Vector3 VectorToNative(Point pt) => VectorToNative(new Vector(pt) { units = pt.units }); - public Dxf.Entities.Line LineToNative(Line line) => - new Dxf.Entities.Line(VectorToNative(line.start), VectorToNative(line.end)); + public Dxf.Vector3 VectorToNative(Vector pt) => + new(ScaleToNative(pt.x, pt.units), ScaleToNative(pt.y, pt.units), ScaleToNative(pt.z, pt.units)); - public Dxfe.Mesh MeshToNative(Mesh mesh) => new Dxfe.Mesh( - mesh.GetPoints().Select(VectorToNative), - mesh.GetFaceIndices() - ) - { - Color = MaterialToNativeColor(mesh["renderMaterial"] as RenderMaterial) - }; + public Dxf.Entities.Point PointToNative(Point pt) => new(VectorToNative(pt)); - public IEnumerable MeshToNativePretty(Mesh mesh, RenderMaterial renderMaterial = null) - { - var topology = mesh.GetMeshEdgeFaces(); - return MeshFacesToNative( - topology, - renderMaterial: renderMaterial ?? mesh["renderMaterial"] as RenderMaterial - ).Concat(MeshEdgesToNative(topology)); - } + public Dxf.Entities.Line LineToNative(Line line) => new(VectorToNative(line.start), VectorToNative(line.end)); - private IEnumerable MeshEdgesToNative(MeshTopologyResult topology, - string edgeLayerName = "Mesh boundaries") => - topology.EdgeFaceConnection - .Where((kv) => kv.Value.Count == 1) - .Select(kv => - { - var (iA, iB) = kv.Key; - var line = new Dxfe.Line( - VectorToNative(topology.Vertices[iA]), - VectorToNative(topology.Vertices[iB])); - line.Layer = new Dxf.Tables.Layer(edgeLayerName); - return line; - }); + public Dxfe.Mesh MeshToNative(Mesh mesh) => + new(mesh.GetPoints().Select(VectorToNative), mesh.GetFaceIndices()) + { + Color = MaterialToNativeColor(mesh["renderMaterial"] as RenderMaterial) + }; - private IEnumerable MeshFacesToNative(MeshTopologyResult topology, string layerName = "Mesh Faces", RenderMaterial renderMaterial = null) - { - var vertices = topology.Vertices.Select(VectorToNative).ToList(); - return topology.Faces.Select(indices => - { - var points = indices.Select(i => vertices[i]).ToList(); - Dxfe.Face3D face; - switch (points.Count) - { - case 3: - face = new Dxfe.Face3D(points[0], points[1], points[2]); - break; - case 4: - face = new Dxfe.Face3D(points[0], points[1], points[2], points[3]); - break; - default: - Report.Log("Ignoring n-gon face, currently unsupported."); - return null; - } + public IEnumerable MeshToNativePretty(Mesh mesh, RenderMaterial renderMaterial = null) + { + var topology = mesh.GetMeshEdgeFaces(); + return MeshFacesToNative(topology, renderMaterial: renderMaterial ?? mesh["renderMaterial"] as RenderMaterial) + .Concat(MeshEdgesToNative(topology)); + } - face.EdgeFlags = (Dxfe.Face3DEdgeFlags)15; // All edges hidden! - face.Layer = new Dxf.Tables.Layer(layerName); - face.Color = MaterialToNativeColor(renderMaterial); - return face; - }).Where(f => f != null); - } + private IEnumerable MeshEdgesToNative( + MeshTopologyResult topology, + string edgeLayerName = "Mesh boundaries" + ) => + topology.EdgeFaceConnection + .Where((kv) => kv.Value.Count == 1) + .Select(kv => + { + var (iA, iB) = kv.Key; + var line = new Dxfe.Line(VectorToNative(topology.Vertices[iA]), VectorToNative(topology.Vertices[iB])); + line.Layer = new Dxf.Tables.Layer(edgeLayerName); + return line; + }); - public Dxf.AciColor MaterialToNativeColor(RenderMaterial renderMaterial) + private IEnumerable MeshFacesToNative( + MeshTopologyResult topology, + string layerName = "Mesh Faces", + RenderMaterial renderMaterial = null + ) + { + var vertices = topology.Vertices.Select(VectorToNative).ToList(); + return topology.Faces + .Select(indices => + { + var points = indices.Select(i => vertices[i]).ToList(); + Dxfe.Face3D face; + switch (points.Count) { - if(renderMaterial == null) return Dxf.AciColor.ByLayer; - var sysColor = System.Drawing.Color.FromArgb(renderMaterial.diffuse); - return new Dxf.AciColor(sysColor.R, sysColor.G, sysColor.B); + case 3: + face = new Dxfe.Face3D(points[0], points[1], points[2]); + break; + case 4: + face = new Dxfe.Face3D(points[0], points[1], points[2], points[3]); + break; + default: + Report.Log("Ignoring n-gon face, currently unsupported."); + return null; } - public IEnumerable BrepToNative(Brep brep) - { - return Settings.PrettyMeshes - ? brep.displayValue.SelectMany(m => MeshToNativePretty(m, brep["renderMaterial"] as RenderMaterial)) - : brep.displayValue.Select(MeshToNative); - } + face.EdgeFlags = (Dxfe.Face3DEdgeFlags)15; // All edges hidden! + face.Layer = new Dxf.Tables.Layer(layerName); + face.Color = MaterialToNativeColor(renderMaterial); + return face; + }) + .Where(f => f != null); + } + + public Dxf.AciColor MaterialToNativeColor(RenderMaterial renderMaterial) + { + if (renderMaterial == null) + { + return Dxf.AciColor.ByLayer; } -} \ No newline at end of file + + var sysColor = System.Drawing.Color.FromArgb(renderMaterial.diffuse); + return new Dxf.AciColor(sysColor.R, sysColor.G, sysColor.B); + } + + public IEnumerable BrepToNative(Brep brep) + { + return Settings.PrettyMeshes + ? brep.displayValue.SelectMany(m => MeshToNativePretty(m, brep["renderMaterial"] as RenderMaterial)) + : brep.displayValue.Select(MeshToNative); + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Settings.cs b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Settings.cs index 32220b4102..69ba9e0fb8 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Settings.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Settings.cs @@ -1,14 +1,13 @@ using System; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public partial class SpeckleDxfConverter { - public partial class SpeckleDxfConverter - { - public void SetConverterSettings(object settings) => SetConverterSettings((ConverterDxfSettings)settings); + public void SetConverterSettings(object settings) => SetConverterSettings((ConverterDxfSettings)settings); - private void SetConverterSettings(ConverterDxfSettings settings) - { - Settings = settings ?? throw new ArgumentNullException(nameof(settings)); - } - } -} \ No newline at end of file + private void SetConverterSettings(ConverterDxfSettings settings) + { + Settings = settings ?? throw new ArgumentNullException(nameof(settings)); + } +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Units.cs b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Units.cs index ccc61d623b..d00194a115 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Units.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.Units.cs @@ -1,73 +1,74 @@ -using System; +using System; using Speckle.Core.Kits; using Speckle.Core.Logging; using Speckle.netDxf.Units; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public partial class SpeckleDxfConverter { - public partial class SpeckleDxfConverter + public double ScaleToNative(double value, string units) { - public double ScaleToNative(double value, string units) + Console.WriteLine(Doc); + Console.WriteLine(units); + if (units == null) { - Console.WriteLine(Doc); - Console.WriteLine(units); - if (units == null) - { - throw new Exception("null units"); - } + throw new Exception("null units"); + } - if (Doc == null) - throw new Exception("null doc"); - - return value * Units.GetConversionFactor(units, DocUnitsToUnits(Doc.DrawingVariables.InsUnits)); + if (Doc == null) + { + throw new Exception("null doc"); } - public DrawingUnits UnitsToDocUnits(string units) + return value * Units.GetConversionFactor(units, DocUnitsToUnits(Doc.DrawingVariables.InsUnits)); + } + + public DrawingUnits UnitsToDocUnits(string units) + { + switch (units) { - switch (units) - { - case Units.Centimeters: - return DrawingUnits.Centimeters; - case Units.Meters: - return DrawingUnits.Meters; - case Units.Kilometers: - return DrawingUnits.Kilometers; - case Units.Inches: - return DrawingUnits.Inches; - case Units.Feet: - return DrawingUnits.Feet; - case Units.Yards: - return DrawingUnits.Yards; - case Units.Miles: - return DrawingUnits.Miles; - default: - return DrawingUnits.Meters; - } + case Units.Centimeters: + return DrawingUnits.Centimeters; + case Units.Meters: + return DrawingUnits.Meters; + case Units.Kilometers: + return DrawingUnits.Kilometers; + case Units.Inches: + return DrawingUnits.Inches; + case Units.Feet: + return DrawingUnits.Feet; + case Units.Yards: + return DrawingUnits.Yards; + case Units.Miles: + return DrawingUnits.Miles; + default: + return DrawingUnits.Meters; } + } - public string DocUnitsToUnits(DrawingUnits units) + public string DocUnitsToUnits(DrawingUnits units) + { + switch (units) { - switch (units) - { - case DrawingUnits.Centimeters: - return Units.Centimeters; - case DrawingUnits.Meters: - return Units.Meters; - case DrawingUnits.Kilometers: - return Units.Kilometers; - case DrawingUnits.Inches: - return Units.Inches; - case DrawingUnits.Feet: - return Units.Feet; - case DrawingUnits.Yards: - return Units.Yards; - case DrawingUnits.Miles: - return Units.Miles; - case DrawingUnits.Unitless: - return Units.None; - default: - throw new SpeckleException($"Unknown document units: {units}"); - } + case DrawingUnits.Centimeters: + return Units.Centimeters; + case DrawingUnits.Meters: + return Units.Meters; + case DrawingUnits.Kilometers: + return Units.Kilometers; + case DrawingUnits.Inches: + return Units.Inches; + case DrawingUnits.Feet: + return Units.Feet; + case DrawingUnits.Yards: + return Units.Yards; + case DrawingUnits.Miles: + return Units.Miles; + case DrawingUnits.Unitless: + return Units.None; + default: + throw new SpeckleException($"Unknown document units: {units}"); } } -} \ No newline at end of file +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.cs b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.cs index 3eabeff37f..0cbba085e3 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/SpeckleDxfConverter.cs @@ -1,4 +1,4 @@ -using Objects.Geometry; +using Objects.Geometry; using Speckle.Core.Kits; using Speckle.Core.Models; using System; @@ -9,63 +9,67 @@ using Mesh = Objects.Geometry.Mesh; using Point = Objects.Geometry.Point; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public partial class SpeckleDxfConverter { - public partial class SpeckleDxfConverter - { - public Dxf.DxfDocument Doc; - public string Description => "The Objects DXF Converter"; - public string Name => "Speckle DXF Converter"; - public string Author => "Speckle Systems"; - public string WebsiteOrEmail => "https://speckle.systems"; + public Dxf.DxfDocument Doc; + public string Description => "The Objects DXF Converter"; + public string Name => "Speckle DXF Converter"; + public string Author => "Speckle Systems"; + public string WebsiteOrEmail => "https://speckle.systems"; + + public ProgressReport Report { get; } = new ProgressReport(); + public ConverterDxfSettings Settings = new(); + public ReceiveMode ReceiveMode { get; set; } = ReceiveMode.Create; - public ProgressReport Report { get; } = new ProgressReport(); - public ConverterDxfSettings Settings = new ConverterDxfSettings(); - public ReceiveMode ReceiveMode { get; set; } = ReceiveMode.Create; + // TODO: Convert to Speckle is currently not supported. + public List ConvertToSpeckle(List objects) => throw new NotImplementedException(); - // TODO: Convert to Speckle is currently not supported. - public List ConvertToSpeckle(List objects) => throw new NotImplementedException(); - public bool CanConvertToSpeckle(object @object) => throw new NotImplementedException(); - public Base ConvertToSpeckle(object @object) => throw new NotImplementedException(); + public bool CanConvertToSpeckle(object @object) => throw new NotImplementedException(); + public Base ConvertToSpeckle(object @object) => throw new NotImplementedException(); - public bool CanConvertToNative(Base @base) + public bool CanConvertToNative(Base @base) + { + switch (@base) { - switch (@base) - { - case Vector _: - case Point _: - case Line _: - case Mesh _: - case Brep _: - return true; - default: - return false; - } + case Vector _: + case Point _: + case Line _: + case Mesh _: + case Brep _: + return true; + default: + return false; } - public object ConvertToNative(Base @base) + } + + public object ConvertToNative(Base @base) + { + switch (@base) { - switch (@base) - { - case Point pt: - return PointToNative(pt); - case Vector vector: - return VectorToNative(vector); - case Line line: - return LineToNative(line); - case Mesh mesh: - if (Settings.PrettyMeshes) - return MeshToNativePretty(mesh); - return MeshToNative(mesh); - case Brep brep: - return BrepToNative(brep); - default: - return null; - } + case Point pt: + return PointToNative(pt); + case Vector vector: + return VectorToNative(vector); + case Line line: + return LineToNative(line); + case Mesh mesh: + if (Settings.PrettyMeshes) + { + return MeshToNativePretty(mesh); + } + + return MeshToNative(mesh); + case Brep brep: + return BrepToNative(brep); + default: + return null; } + } - public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); + public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); - public IEnumerable GetServicedApplications() => new[] { HostApplications.Dxf.Slug }; - } -} \ No newline at end of file + public IEnumerable GetServicedApplications() => new[] { HostApplications.Dxf.Slug }; +} diff --git a/Objects/Converters/ConverterDxf/ConverterDxf/Utilities.cs b/Objects/Converters/ConverterDxf/ConverterDxf/Utilities.cs index 47882ef72b..a511b8f6dd 100644 --- a/Objects/Converters/ConverterDxf/ConverterDxf/Utilities.cs +++ b/Objects/Converters/ConverterDxf/ConverterDxf/Utilities.cs @@ -4,57 +4,60 @@ using System.Linq; using Objects.Geometry; -namespace Objects.Converters.DxfConverter +namespace Objects.Converters.DxfConverter; + +public struct MeshTopologyResult +{ + public List Vertices; + public List Faces; + public ConcurrentDictionary, ConcurrentBag> EdgeFaceConnection; +} + +public static class Utilities { - public struct MeshTopologyResult + public static MeshTopologyResult GetMeshEdgeFaces(this Mesh mesh) + { + var result = new ConcurrentDictionary, ConcurrentBag>(); + var faces = mesh.GetFaceIndices().ToList(); + var vertices = mesh.GetPoints(); + var faceIndex = 0; + foreach (var indices in faces) { - public List Vertices; - public List Faces; - public ConcurrentDictionary, ConcurrentBag> EdgeFaceConnection; + for (var j = 0; j < indices.Length; j++) + { + var iA = indices[j]; + var iB = indices[(j + 1) % indices.Length]; + var temp = iA; + iA = temp < iB ? iA : iB; + iB = temp < iB ? iB : temp; + var connectedFaces = result.GetOrAdd(new Tuple(iA, iB), new ConcurrentBag()); + connectedFaces.Add(faceIndex); + } + faceIndex++; } - - public static class Utilities + + return new MeshTopologyResult() + { + Vertices = vertices, + Faces = faces, + EdgeFaceConnection = result + }; + } + + public static IEnumerable GetFaceIndices(this Mesh mesh) + { + var i = 0; + while (i < mesh.faces.Count) { - public static MeshTopologyResult GetMeshEdgeFaces(this Mesh mesh) - { - var result = new ConcurrentDictionary, ConcurrentBag>(); - var faces = mesh.GetFaceIndices().ToList(); - var vertices = mesh.GetPoints(); - var faceIndex = 0; - foreach (var indices in faces) - { - for (var j = 0; j < indices.Length; j++) - { - var iA = indices[j]; - var iB = indices[(j + 1) % indices.Length]; - var temp = iA; - iA = temp < iB ? iA : iB; - iB = temp < iB ? iB : temp; - var connectedFaces = result.GetOrAdd(new Tuple(iA,iB), new ConcurrentBag()); - connectedFaces.Add(faceIndex); - } - faceIndex++; - } - - return new MeshTopologyResult() - { - Vertices = vertices, - Faces = faces, - EdgeFaceConnection = result - }; - } - public static IEnumerable GetFaceIndices(this Mesh mesh) - { - var i = 0; - while (i < mesh.faces.Count) - { - var n = mesh.faces[i]; - if (n < 3) n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility + var n = mesh.faces[i]; + if (n < 3) + { + n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility + } - var points = mesh.faces.GetRange(i + 1, n).ToArray(); - yield return points; - i += n + 1; - } - } + var points = mesh.faces.GetRange(i + 1, n).ToArray(); + yield return points; + i += n + 1; } -} \ No newline at end of file + } +} diff --git a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Geometry.cs b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Geometry.cs index d1b10134eb..e97c24482d 100644 --- a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Geometry.cs +++ b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Geometry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -24,894 +24,982 @@ using Speckle.Core.Kits; using Speckle.Core.Logging; -namespace Objects.Converter.Dynamo +namespace Objects.Converter.Dynamo; + +//Original author +// Name: Alvaro Ortega Pickmans +// Github: alvpickmans +//Code form: https://github.com/speckleworks/SpeckleCoreGeometry/blob/master/SpeckleCoreGeometryDynamo/Conversions.cs +public partial class ConverterDynamo { - //Original author - // Name: Alvaro Ortega Pickmans - // Github: alvpickmans - //Code form: https://github.com/speckleworks/SpeckleCoreGeometry/blob/master/SpeckleCoreGeometryDynamo/Conversions.cs - public partial class ConverterDynamo + #region Points + + /// + /// DS Point to SpecklePoint + /// + /// + /// + public Point PointToSpeckle(DS.Point pt, string units = null) { - #region Points + var point = new Point(pt.X, pt.Y, pt.Z, units ?? ModelUnits); + CopyProperties(point, pt); + return point; + } - /// - /// DS Point to SpecklePoint - /// - /// - /// - public Point PointToSpeckle(DS.Point pt, string units = null) - { + /// + /// Speckle Point to DS Point + /// + /// + /// + /// + public DS.Point PointToNative(Point pt) + { + var point = DS.Point.ByCoordinates( + ScaleToNative(pt.x, pt.units), + ScaleToNative(pt.y, pt.units), + ScaleToNative(pt.z, pt.units) + ); - var point = new Point(pt.X, pt.Y, pt.Z, units ?? ModelUnits); - CopyProperties(point, pt); - return point; - } + return point.SetDynamoProperties(GetDynamicMembersFromBase(pt)); + } - /// - /// Speckle Point to DS Point - /// - /// - /// - /// - public DS.Point PointToNative(Point pt) + /// + /// Array of point coordinates to array of DS Points + /// + /// + /// + public DS.Point[] ArrayToPointList(IEnumerable arr, string units = null) + { + if (arr.Count() % 3 != 0) { - var point = DS.Point.ByCoordinates( - ScaleToNative(pt.x, pt.units), ScaleToNative(pt.y, pt.units), ScaleToNative(pt.z, pt.units)); - - return point.SetDynamoProperties(GetDynamicMembersFromBase(pt)); + throw new SpeckleException("Array malformed: length%3 != 0."); } - /// - /// Array of point coordinates to array of DS Points - /// - /// - /// - public DS.Point[] ArrayToPointList(IEnumerable arr, string units = null) + DS.Point[] points = new DS.Point[arr.Count() / 3]; + var asArray = arr.ToArray(); + for (int i = 2, k = 0; i < arr.Count(); i += 3) { - if (arr.Count() % 3 != 0) throw new SpeckleException("Array malformed: length%3 != 0."); + points[k++] = DS.Point.ByCoordinates( + ScaleToNative(asArray[i - 2], units), + ScaleToNative(asArray[i - 1], units), + ScaleToNative(asArray[i], units) + ); + } - DS.Point[] points = new DS.Point[arr.Count() / 3]; - var asArray = arr.ToArray(); - for (int i = 2, k = 0; i < arr.Count(); i += 3) - points[k++] = DS.Point.ByCoordinates(ScaleToNative(asArray[i - 2], units), ScaleToNative(asArray[i - 1], units), ScaleToNative(asArray[i], units)); + return points; + } - return points; - } + /// + /// Array of DS Points to array of point coordinates + /// + /// + /// + public List PointListToFlatList(IEnumerable points) + { + return points.SelectMany(pt => PointToArray(pt)).ToList(); + } - /// - /// Array of DS Points to array of point coordinates - /// - /// - /// - public List PointListToFlatList(IEnumerable points) - { - return points.SelectMany(pt => PointToArray(pt)).ToList(); - } + public double[] PointToArray(DS.Point pt) + { + return new double[] { pt.X, pt.Y, pt.Z }; + } - public double[] PointToArray(DS.Point pt) - { - return new double[] { pt.X, pt.Y, pt.Z }; - } + #endregion - #endregion + #region Vectors - #region Vectors + /// + /// DS Vector to Vector + /// + /// + /// + public Vector VectorToSpeckle(DS.Vector vc, string units = null) + { + return new Vector(vc.X, vc.Y, vc.Z, units ?? ModelUnits); + } - /// - /// DS Vector to Vector - /// - /// - /// - public Vector VectorToSpeckle(DS.Vector vc, string units = null) - { - return new Vector(vc.X, vc.Y, vc.Z, units ?? ModelUnits); - } + /// + /// Vector to DS Vector + /// + /// + /// + public DS.Vector VectorToNative(Vector vc) + { + return DS.Vector.ByCoordinates( + ScaleToNative(vc.x, vc.units), + ScaleToNative(vc.y, vc.units), + ScaleToNative(vc.z, vc.units) + ); + } + + /// + /// DS Vector to array of coordinates + /// + /// + /// + //public double[] VectorToArray(DS.Vector vc) + //{ + // return new double[] { vc.X, vc.Y, vc.Z }; + //} + + /// + /// Array of coordinates to DS Vector + /// + /// + /// + //public DS.Vector VectorToVector(double[] arr) + //{ + // return DS.Vector.ByCoordinates(arr[0], arr[1], arr[2]); + //} + + #endregion + + #region Planes + + /// + /// DS Plane to Plane + /// + /// + /// + public Plane PlaneToSpeckle(DS.Plane plane, string units = null) + { + var u = units ?? ModelUnits; + var p = new Plane( + PointToSpeckle(plane.Origin, u), + VectorToSpeckle(plane.Normal, u), + VectorToSpeckle(plane.XAxis, u), + VectorToSpeckle(plane.YAxis, u), + ModelUnits + ); + CopyProperties(p, plane); + return p; + } + + /// + /// Plane to DS Plane + /// + /// + /// + public DS.Plane PlaneToNative(Plane plane) + { + var pln = DS.Plane.ByOriginXAxisYAxis( + PointToNative(plane.origin), + VectorToNative(plane.xdir), + VectorToNative(plane.ydir) + ); + return pln.SetDynamoProperties(GetDynamicMembersFromBase(plane)); + } + + public CoordinateSystem TransformToNative(Transform transform) + { + return CoordinateSystem.ByMatrix(transform.value).Scale(Units.GetConversionFactor(transform.units, ModelUnits)); + } + + #endregion + + #region Linear + + /// + /// DS Line to SpeckleLine + /// + /// + /// + public Line LineToSpeckle(DS.Line line, string units = null) + { + var u = units ?? ModelUnits; + var l = new Line(PointListToFlatList(new DS.Point[] { line.StartPoint, line.EndPoint }), u); - /// - /// Vector to DS Vector - /// - /// - /// - public DS.Vector VectorToNative(Vector vc) + CopyProperties(l, line); + l.length = line.Length; + try { - return DS.Vector.ByCoordinates( - ScaleToNative(vc.x, vc.units), - ScaleToNative(vc.y, vc.units), - ScaleToNative(vc.z, vc.units)); + l.bbox = BoxToSpeckle(line.BoundingBox, u); } + catch { } + return l; + } - /// - /// DS Vector to array of coordinates - /// - /// - /// - //public double[] VectorToArray(DS.Vector vc) - //{ - // return new double[] { vc.X, vc.Y, vc.Z }; - //} + /// + /// SpeckleLine to DS Line + /// + /// + /// + public DS.Line LineToNative(Line line) + { + var ptStart = PointToNative(line.start); + var ptEnd = PointToNative(line.end); - /// - /// Array of coordinates to DS Vector - /// - /// - /// - //public DS.Vector VectorToVector(double[] arr) - //{ - // return DS.Vector.ByCoordinates(arr[0], arr[1], arr[2]); - //} + var ln = DS.Line.ByStartPointEndPoint(ptStart, ptEnd); + + ptStart.Dispose(); + ptEnd.Dispose(); + + return ln.SetDynamoProperties(GetDynamicMembersFromBase(line)); + } + + /// + /// DS Polygon to closed SpecklePolyline + /// + /// + /// + public Polyline PolylineToSpeckle(DS.Polygon polygon, string units = null) + { + var u = units ?? ModelUnits; + var poly = new Polyline(PointListToFlatList(polygon.Points), u) { closed = true, }; + CopyProperties(poly, polygon); + poly.length = polygon.Length; + poly.bbox = BoxToSpeckle(polygon.BoundingBox, u); + return poly; + } - #endregion + /// + /// DS Rectangle to SpecklePolyline + /// + /// + /// + public Polyline PolylineToSpeckle(DS.Rectangle rectangle, string units = null) + { + var rect = PolylineToSpeckle(rectangle as DS.Polygon, units ?? ModelUnits); - #region Planes + CopyProperties(rect, rectangle); + return rect; + } - /// - /// DS Plane to Plane - /// - /// - /// - public Plane PlaneToSpeckle(DS.Plane plane, string units = null) + /// + /// SpecklePolyline to DS Rectangle if closed , four points and sides parallel; + /// DS Polygon if closed or DS Polycurve otherwise + /// + /// + /// + public DS.Curve PolylineToNative(Polyline polyline) + { + var points = ArrayToPointList(polyline.value, polyline.units); + if (polyline.closed) { - var u = units ?? ModelUnits; - var p = new Plane( - PointToSpeckle(plane.Origin, u), - VectorToSpeckle(plane.Normal, u), - VectorToSpeckle(plane.XAxis, u), - VectorToSpeckle(plane.YAxis, u), - ModelUnits); - CopyProperties(p, plane); - return p; + return DS.PolyCurve + .ByPoints(points) + .CloseWithLine() + .SetDynamoProperties(GetDynamicMembersFromBase(polyline)); } - /// - /// Plane to DS Plane - /// - /// - /// - public DS.Plane PlaneToNative(Plane plane) + return PolyCurve.ByPoints(points).SetDynamoProperties(GetDynamicMembersFromBase(polyline)); + } + + #endregion + + #region Curves + + /// + /// DS Circle to SpeckleCircle. + /// + /// + /// + public Circle CircleToSpeckle(DS.Circle circ, string units = null) + { + var u = units ?? ModelUnits; + using (DS.Vector xAxis = DS.Vector.ByTwoPoints(circ.CenterPoint, circ.StartPoint)) + using (DS.Plane plane = DS.Plane.ByOriginNormalXAxis(circ.CenterPoint, circ.Normal, xAxis)) { - var pln = DS.Plane.ByOriginXAxisYAxis( - PointToNative(plane.origin), - VectorToNative(plane.xdir), - VectorToNative(plane.ydir)); - return pln.SetDynamoProperties(GetDynamicMembersFromBase(plane)); + var myCircle = new Circle(PlaneToSpeckle(plane, u), circ.Radius, u); + CopyProperties(myCircle, circ); + myCircle.length = circ.Length; + myCircle.bbox = BoxToSpeckle(circ.BoundingBox, u); + return myCircle; } + } - public CoordinateSystem TransformToNative(Transform transform) + /// + /// SpeckleCircle to DS Circle. Rotating the circle is due to a bug in ProtoGeometry + /// that will be solved on Dynamo 2.1. + /// + /// + /// + public DS.Circle CircleToNative(Circle circ) + { + using (DS.Plane basePlane = PlaneToNative(circ.plane)) + using (DS.Circle preCircle = DS.Circle.ByPlaneRadius(basePlane, ScaleToNative(circ.radius.Value, circ.units))) + using (DS.Vector preXvector = DS.Vector.ByTwoPoints(preCircle.CenterPoint, preCircle.StartPoint)) { - return CoordinateSystem.ByMatrix(transform.value) - .Scale(Units.GetConversionFactor(transform.units, ModelUnits)); + double angle = preXvector.AngleAboutAxis(basePlane.XAxis, basePlane.Normal); + var circle = (DS.Circle)preCircle.Rotate(basePlane, angle); + + return circle.SetDynamoProperties(GetDynamicMembersFromBase(circ)); } - - #endregion + } - #region Linear + /// + /// DS Arc to SpeckleArc + /// + /// + /// + public Arc ArcToSpeckle(DS.Arc a, string units = null) + { + var u = units ?? ModelUnits; + using (DS.Vector xAxis = DS.Vector.ByTwoPoints(a.CenterPoint, a.StartPoint)) + using (DS.Plane basePlane = DS.Plane.ByOriginNormalXAxis(a.CenterPoint, a.Normal, xAxis)) + using (DS.Point midPoint = a.PointAtParameter(0.5)) + { + var arc = new Arc( + PlaneToSpeckle(basePlane, u), + a.Radius, + 0, // This becomes 0 as arcs are interpreted to start from the plane's X axis. + a.SweepAngle.ToRadians(), + a.SweepAngle.ToRadians(), + u + ); + arc.startPoint = PointToSpeckle(a.StartPoint); + arc.midPoint = PointToSpeckle(midPoint); + arc.endPoint = PointToSpeckle(a.EndPoint); - /// - /// DS Line to SpeckleLine - /// - /// - /// - public Line LineToSpeckle(DS.Line line, string units = null) - { - var u = units ?? ModelUnits; - var l = new Line( - PointListToFlatList(new DS.Point[] { line.StartPoint, line.EndPoint }), - u); + CopyProperties(arc, a); - CopyProperties(l, line); - l.length = line.Length; - try - { - l.bbox = BoxToSpeckle(line.BoundingBox, u); - } - catch { } - return l; + arc.length = a.Length; + arc.bbox = BoxToSpeckle(a.BoundingBox); + + return arc; } + } - /// - /// SpeckleLine to DS Line - /// - /// - /// - public DS.Line LineToNative(Line line) - { - var ptStart = PointToNative(line.start); - var ptEnd = PointToNative(line.end); + /// + /// SpeckleArc to DS Arc + /// + /// + /// + public DS.Arc ArcToNative(Arc a) + { + var arc = DS.Arc.ByThreePoints(PointToNative(a.startPoint), PointToNative(a.midPoint), PointToNative(a.endPoint)); + return arc.SetDynamoProperties(GetDynamicMembersFromBase(a)); + } - var ln = DS.Line.ByStartPointEndPoint(ptStart, ptEnd); + /// + /// DS Ellipse to SpeckleEllipse + /// + /// + /// + public Ellipse EllipseToSpeckle(DS.Ellipse e, string units = null) + { + var u = units ?? ModelUnits; + using (DS.Plane basePlane = DS.Plane.ByOriginNormalXAxis(e.CenterPoint, e.Normal, e.MajorAxis)) + { + var ellipse = new Ellipse( + PlaneToSpeckle(basePlane, u), + e.MajorAxis.Length, + e.MinorAxis.Length, + new Interval(e.StartParameter(), e.EndParameter()), + null, + u + ); - ptStart.Dispose(); - ptEnd.Dispose(); + CopyProperties(ellipse, e); - return ln.SetDynamoProperties(GetDynamicMembersFromBase(line)); + ellipse.length = e.Length; + ellipse.bbox = BoxToSpeckle(e.BoundingBox, u); + + return ellipse; } + } - /// - /// DS Polygon to closed SpecklePolyline - /// - /// - /// - public Polyline PolylineToSpeckle(DS.Polygon polygon, string units = null) + /// + /// SpeckleEllipse to DS Ellipse + /// + /// + /// + public DS.Curve EllipseToNative(Ellipse e) + { + if (e.trimDomain != null) + { + // Curve is an ellipse arc + var ellipseArc = DS.EllipseArc.ByPlaneRadiiAngles( + PlaneToNative(e.plane), + ScaleToNative(e.firstRadius.Value, e.units), + ScaleToNative(e.secondRadius.Value, e.units), + e.trimDomain.start.Value * 360 / (2 * Math.PI), + (double)(e.trimDomain.end - e.trimDomain.start) * 360 / (2 * Math.PI) + ); + return ellipseArc; + } + else { - var u = units ?? ModelUnits; - var poly = new Polyline(PointListToFlatList(polygon.Points), u) - { - closed = true, - }; - CopyProperties(poly, polygon); - poly.length = polygon.Length; - poly.bbox = BoxToSpeckle(polygon.BoundingBox, u); - return poly; + // Curve is an ellipse + var ellipse = DS.Ellipse.ByPlaneRadii( + PlaneToNative(e.plane), + ScaleToNative(e.firstRadius.Value, e.units), + ScaleToNative(e.secondRadius.Value, e.units) + ); + ellipse.SetDynamoProperties(GetDynamicMembersFromBase(e)); + return ellipse; } + } - /// - /// DS Rectangle to SpecklePolyline - /// - /// - /// - public Polyline PolylineToSpeckle(DS.Rectangle rectangle, string units = null) + /// + /// DS EllipseArc to Speckle Ellipse + /// + /// + /// + public Ellipse EllipseToSpeckle(EllipseArc arc, string units = null) + { + var u = units ?? ModelUnits; + var ellipArc = new Ellipse( + PlaneToSpeckle(arc.Plane, u), + arc.MajorAxis.Length, + arc.MinorAxis.Length, + new Interval(0, 2 * Math.PI), + new Interval(arc.StartAngle, arc.StartAngle + arc.SweepAngle), + u + ); + + CopyProperties(ellipArc, arc); + + ellipArc.length = arc.Length; + ellipArc.bbox = BoxToSpeckle(arc.BoundingBox, u); + + return ellipArc; + } + + /// + /// DS Polycurve to SpecklePolyline if all curves are linear + /// SpecklePolycurve otherwise + /// + /// + /// + public Base PolycurveToSpeckle(PolyCurve polycurve, string units = null) + { + var u = units ?? ModelUnits; + if (polycurve.IsPolyline()) { - var rect = PolylineToSpeckle(rectangle as DS.Polygon, units ?? ModelUnits); + var points = polycurve.Curves().SelectMany(c => PointToArray(c.StartPoint)).ToList(); + points.AddRange(PointToArray(polycurve.Curves().Last().EndPoint)); + var poly = new Polyline(points, u); - CopyProperties(rect, rectangle); - return rect; - } + CopyProperties(poly, polycurve); + poly.length = polycurve.Length; + poly.bbox = BoxToSpeckle(polycurve.BoundingBox, u); - /// - /// SpecklePolyline to DS Rectangle if closed , four points and sides parallel; - /// DS Polygon if closed or DS Polycurve otherwise - /// - /// - /// - public DS.Curve PolylineToNative(Polyline polyline) + return poly; + } + else { - var points = ArrayToPointList(polyline.value, polyline.units); - if (polyline.closed) - return DS.PolyCurve.ByPoints(points).CloseWithLine() - .SetDynamoProperties(GetDynamicMembersFromBase(polyline)); + Polycurve spkPolycurve = new(u); + CopyProperties(spkPolycurve, polycurve); - return PolyCurve.ByPoints(points).SetDynamoProperties(GetDynamicMembersFromBase(polyline)); - } + spkPolycurve.segments = polycurve.Curves().Select(c => (ICurve)CurveToSpeckle(c, u)).ToList(); - #endregion + spkPolycurve.length = polycurve.Length; + spkPolycurve.bbox = BoxToSpeckle(polycurve.BoundingBox, u); - #region Curves + return spkPolycurve; + } + } - /// - /// DS Circle to SpeckleCircle. - /// - /// - /// - public Circle CircleToSpeckle(DS.Circle circ, string units = null) + public PolyCurve PolycurveToNative(Polycurve polycurve) + { + DS.Curve[] curves = new DS.Curve[polycurve.segments.Count]; + for (var i = 0; i < polycurve.segments.Count; i++) { - var u = units ?? ModelUnits; - using (DS.Vector xAxis = DS.Vector.ByTwoPoints(circ.CenterPoint, circ.StartPoint)) - using (DS.Plane plane = DS.Plane.ByOriginNormalXAxis(circ.CenterPoint, circ.Normal, xAxis)) + switch (polycurve.segments[i]) { - var myCircle = new Circle(PlaneToSpeckle(plane, u), circ.Radius, u); - CopyProperties(myCircle, circ); - myCircle.length = circ.Length; - myCircle.bbox = BoxToSpeckle(circ.BoundingBox, u); - return myCircle; + case Line curve: + curves[i] = LineToNative(curve); + break; + case Arc curve: + curves[i] = ArcToNative(curve); + break; + case Circle curve: + curves[i] = CircleToNative(curve); + break; + case Ellipse curve: + curves[i] = EllipseToNative(curve); + break; + case Spiral curve: + curves[i] = PolylineToNative(curve.displayValue); + break; + case Polycurve curve: + curves[i] = PolycurveToNative(curve); + break; + case Polyline curve: + curves[i] = PolylineToNative(curve); + break; + case Curve curve: + curves[i] = CurveToNative(curve); + break; } } - /// - /// SpeckleCircle to DS Circle. Rotating the circle is due to a bug in ProtoGeometry - /// that will be solved on Dynamo 2.1. - /// - /// - /// - public DS.Circle CircleToNative(Circle circ) + PolyCurve polyCrv = null; + if (curves.Any()) { - using (DS.Plane basePlane = PlaneToNative(circ.plane)) - using (DS.Circle preCircle = DS.Circle.ByPlaneRadius(basePlane, ScaleToNative(circ.radius.Value, circ.units))) - using (DS.Vector preXvector = DS.Vector.ByTwoPoints(preCircle.CenterPoint, preCircle.StartPoint)) - { - double angle = preXvector.AngleAboutAxis(basePlane.XAxis, basePlane.Normal); - var circle = (DS.Circle)preCircle.Rotate(basePlane, angle); + polyCrv = PolyCurve.ByJoinedCurves(curves); + polyCrv = polyCrv.SetDynamoProperties(GetDynamicMembersFromBase(polycurve)); + } + + return polyCrv; + } - return circle.SetDynamoProperties(GetDynamicMembersFromBase(circ)); + public Base CurveToSpeckle(DS.Curve curve, string units = null) + { + var u = units ?? ModelUnits; + Base speckleCurve; + if (curve.IsLinear()) + { + using (DS.Line line = curve.GetAsLine()) + { + speckleCurve = LineToSpeckle(line, u); } } - - /// - /// DS Arc to SpeckleArc - /// - /// - /// - public Arc ArcToSpeckle(DS.Arc a, string units = null) + else if (curve.IsArc()) { - var u = units ?? ModelUnits; - using (DS.Vector xAxis = DS.Vector.ByTwoPoints(a.CenterPoint, a.StartPoint)) - using (DS.Plane basePlane = DS.Plane.ByOriginNormalXAxis(a.CenterPoint, a.Normal, xAxis)) - using (DS.Point midPoint = a.PointAtParameter(0.5)) + using (DS.Arc arc = curve.GetAsArc()) { - var arc = new Arc( - PlaneToSpeckle(basePlane, u), - a.Radius, - 0, // This becomes 0 as arcs are interpreted to start from the plane's X axis. - a.SweepAngle.ToRadians(), - a.SweepAngle.ToRadians(), - u - ); - arc.startPoint = PointToSpeckle(a.StartPoint); - arc.midPoint = PointToSpeckle(midPoint); - arc.endPoint = PointToSpeckle(a.EndPoint); - - CopyProperties(arc, a); - - arc.length = a.Length; - arc.bbox = BoxToSpeckle(a.BoundingBox); - - return arc; + speckleCurve = ArcToSpeckle(arc, u); } } - - /// - /// SpeckleArc to DS Arc - /// - /// - /// - public DS.Arc ArcToNative(Arc a) + else if (curve.IsCircle()) { - var arc = DS.Arc.ByThreePoints(PointToNative(a.startPoint), PointToNative(a.midPoint), PointToNative(a.endPoint)); - return arc.SetDynamoProperties(GetDynamicMembersFromBase(a)); + using (DS.Circle circle = curve.GetAsCircle()) + { + speckleCurve = CircleToSpeckle(circle, u); + } } - - /// - /// DS Ellipse to SpeckleEllipse - /// - /// - /// - public Ellipse EllipseToSpeckle(DS.Ellipse e, string units = null) + else if (curve.IsEllipse()) { - var u = units ?? ModelUnits; - using (DS.Plane basePlane = DS.Plane.ByOriginNormalXAxis(e.CenterPoint, e.Normal, e.MajorAxis)) + using (DS.Ellipse ellipse = curve.GetAsEllipse()) { - var ellipse = new Ellipse( - PlaneToSpeckle(basePlane, u), - e.MajorAxis.Length, - e.MinorAxis.Length, - new Interval(e.StartParameter(), e.EndParameter()), - null, - u); + speckleCurve = EllipseToSpeckle(ellipse, u); + } + } + else + { + speckleCurve = CurveToSpeckle(curve.ToNurbsCurve(), u); + } + + CopyProperties(speckleCurve, curve); + return speckleCurve; + } + + public NurbsCurve CurveToNative(Curve curve) + { + var points = ArrayToPointList(curve.points, curve.units); + var dsKnots = curve.knots; - CopyProperties(ellipse, e); + NurbsCurve nurbsCurve = NurbsCurve.ByControlPointsWeightsKnots( + points, + curve.weights.ToArray(), + dsKnots.ToArray(), + curve.degree + ); - ellipse.length = e.Length; - ellipse.bbox = BoxToSpeckle(e.BoundingBox, u); + return nurbsCurve.SetDynamoProperties(GetDynamicMembersFromBase(curve)); + } - return ellipse; + public Base CurveToSpeckle(NurbsCurve curve, string units = null) + { + var u = units ?? ModelUnits; + Base speckleCurve; + if (curve.IsLinear()) + { + using (DS.Line line = curve.GetAsLine()) + { + speckleCurve = LineToSpeckle(line, u); } } - - /// - /// SpeckleEllipse to DS Ellipse - /// - /// - /// - public DS.Curve EllipseToNative(Ellipse e) + else if (curve.IsArc()) { - if (e.trimDomain != null) + using (DS.Arc arc = curve.GetAsArc()) { - // Curve is an ellipse arc - var ellipseArc = DS.EllipseArc.ByPlaneRadiiAngles( - PlaneToNative(e.plane), - ScaleToNative(e.firstRadius.Value, e.units), - ScaleToNative(e.secondRadius.Value, e.units), - e.trimDomain.start.Value * 360 / (2 * Math.PI), - (double)(e.trimDomain.end - e.trimDomain.start) * 360 / (2 * Math.PI)); - return ellipseArc; + speckleCurve = ArcToSpeckle(arc, u); } - else + } + else if (curve.IsCircle()) + { + using (DS.Circle circle = curve.GetAsCircle()) { - // Curve is an ellipse - var ellipse = DS.Ellipse.ByPlaneRadii( - PlaneToNative(e.plane), - ScaleToNative(e.firstRadius.Value, e.units), - ScaleToNative(e.secondRadius.Value, e.units) - ); - ellipse.SetDynamoProperties(GetDynamicMembersFromBase(e)); - return ellipse; + speckleCurve = CircleToSpeckle(circle, u); } } - - /// - /// DS EllipseArc to Speckle Ellipse - /// - /// - /// - public Ellipse EllipseToSpeckle(EllipseArc arc, string units = null) + else if (curve.IsEllipse()) { - var u = units ?? ModelUnits; - var ellipArc = new Ellipse( - PlaneToSpeckle(arc.Plane, u), - arc.MajorAxis.Length, - arc.MinorAxis.Length, - new Interval(0, 2 * Math.PI), - new Interval(arc.StartAngle, arc.StartAngle + arc.SweepAngle), - u); + using (DS.Ellipse ellipse = curve.GetAsEllipse()) + { + speckleCurve = EllipseToSpeckle(ellipse, u); + } + } + else + { + // SpeckleCurve DisplayValue + DS.Curve[] curves = curve.ApproximateWithArcAndLineSegments(); + List polylineCoordinates = curves + .SelectMany(c => PointListToFlatList(new DS.Point[2] { c.StartPoint, c.EndPoint })) + .ToList(); + polylineCoordinates.AddRange(PointToArray(curves.Last().EndPoint)); + curves.ForEach(c => c.Dispose()); - CopyProperties(ellipArc, arc); + Polyline displayValue = new(polylineCoordinates, u); + List dsKnots = curve.Knots().ToList(); - ellipArc.length = arc.Length; - ellipArc.bbox = BoxToSpeckle(arc.BoundingBox, u); + Curve spkCurve = new(displayValue, u); + spkCurve.weights = curve.Weights().ToList(); + spkCurve.points = PointListToFlatList(curve.ControlPoints()); + spkCurve.knots = dsKnots; + spkCurve.degree = curve.Degree; + spkCurve.periodic = curve.IsPeriodic; + spkCurve.rational = curve.IsRational; + spkCurve.closed = curve.IsClosed; + spkCurve.domain = new Interval(curve.StartParameter(), curve.EndParameter()); + spkCurve.length = curve.Length; + spkCurve.bbox = BoxToSpeckle(curve.BoundingBox, u); - return ellipArc; + speckleCurve = spkCurve; } - /// - /// DS Polycurve to SpecklePolyline if all curves are linear - /// SpecklePolycurve otherwise - /// - /// - /// - public Base PolycurveToSpeckle(PolyCurve polycurve, string units = null) + CopyProperties(speckleCurve, curve); + return speckleCurve; + } + + // TODO: send this as a spiral class + public Base HelixToSpeckle(Helix helix, string units = null) + { + var u = units ?? ModelUnits; + + /* untested code to send as spiral + using (DS.Plane basePlane = DS.Plane.ByOriginNormal(helix.AxisPoint, helix.Normal)) { - var u = units ?? ModelUnits; - if (polycurve.IsPolyline()) - { - var points = polycurve.Curves().SelectMany(c => PointToArray(c.StartPoint)).ToList(); - points.AddRange(PointToArray(polycurve.Curves().Last().EndPoint)); - var poly = new Polyline(points, u); + var spiral = new Spiral(); - CopyProperties(poly, polycurve); - poly.length = polycurve.Length; - poly.bbox = BoxToSpeckle(polycurve.BoundingBox, u); + spiral.startPoint = PointToSpeckle(helix.StartPoint, u); + spiral.endPoint = PointToSpeckle(helix.EndPoint, u); + spiral.plane = PlaneToSpeckle(basePlane, u); + spiral.pitchAxis = VectorToSpeckle(helix.AxisDirection, u); + spiral.pitch = helix.Pitch; + spiral.turns = helix.Angle / (2 * Math.PI); - return poly; - } - else - { - Polycurve spkPolycurve = new Polycurve(u); - CopyProperties(spkPolycurve, polycurve); + // display value + DS.Curve[] curves = helix.ApproximateWithArcAndLineSegments(); + List polylineCoordinates = + curves.SelectMany(c => PointListToFlatList(new DS.Point[2] { c.StartPoint, c.EndPoint })).ToList(); + polylineCoordinates.AddRange(PointToArray(curves.Last().EndPoint)); + curves.ForEach(c => c.Dispose()); + Polyline displayValue = new Polyline(polylineCoordinates, u); + spiral.displayValue = displayValue; - spkPolycurve.segments = polycurve.Curves().Select(c => (ICurve)CurveToSpeckle(c, u)).ToList(); + CopyProperties(spiral, helix); - spkPolycurve.length = polycurve.Length; - spkPolycurve.bbox = BoxToSpeckle(polycurve.BoundingBox, u); + spiral.length = helix.Length; + spiral.bbox = BoxToSpeckle(helix.BoundingBox.ToCuboid(), u); - return spkPolycurve; - } + return spiral; } + */ - public PolyCurve PolycurveToNative(Polycurve polycurve) + using (NurbsCurve nurbsCurve = helix.ToNurbsCurve()) { - DS.Curve[] curves = new DS.Curve[polycurve.segments.Count]; - for (var i = 0; i < polycurve.segments.Count; i++) - { - switch (polycurve.segments[i]) - { - case Line curve: - curves[i] = LineToNative(curve); - break; - case Arc curve: - curves[i] = ArcToNative(curve); - break; - case Circle curve: - curves[i] = CircleToNative(curve); - break; - case Ellipse curve: - curves[i] = EllipseToNative(curve); - break; - case Spiral curve: - curves[i] = PolylineToNative(curve.displayValue); - break; - case Polycurve curve: - curves[i] = PolycurveToNative(curve); - break; - case Polyline curve: - curves[i] = PolylineToNative(curve); - break; - case Curve curve: - curves[i] = CurveToNative(curve); - break; - } - } + var curve = CurveToSpeckle(nurbsCurve, u); + CopyProperties(curve, helix); + return curve; + } + } - PolyCurve polyCrv = null; - if (curves.Any()) - { - polyCrv = PolyCurve.ByJoinedCurves(curves); - polyCrv = polyCrv.SetDynamoProperties(GetDynamicMembersFromBase(polycurve)); - } + #endregion - return polyCrv; - } + #region mesh - public Base CurveToSpeckle(DS.Curve curve, string units = null) + public DS.Mesh BrepToNative(Brep brep) + { + if (brep.displayValue != null) { - var u = units ?? ModelUnits; - Base speckleCurve; - if (curve.IsLinear()) - { - using (DS.Line line = curve.GetAsLine()) - { - speckleCurve = LineToSpeckle(line, u); - } - } - else if (curve.IsArc()) - { - using (DS.Arc arc = curve.GetAsArc()) - { - speckleCurve = ArcToSpeckle(arc, u); - } - } - else if (curve.IsCircle()) + var meshToNative = MeshToNative(brep.displayValue[0]); + return meshToNative; + } + + return null; + } + + // Meshes + public Mesh MeshToSpeckle(DS.Mesh mesh, string units = null) + { + var u = units ?? ModelUnits; + var vertices = PointListToFlatList(mesh.VertexPositions); + var defaultColour = System.Drawing.Color.FromArgb(255, 100, 100, 100); + + var faces = mesh.FaceIndices + .SelectMany(f => { - using (DS.Circle circle = curve.GetAsCircle()) + if (f.Count == 4) { - speckleCurve = CircleToSpeckle(circle, u); + return new int[] { 4, (int)f.A, (int)f.B, (int)f.C, (int)f.D }; } - } - else if (curve.IsEllipse()) - { - using (DS.Ellipse ellipse = curve.GetAsEllipse()) + else { - speckleCurve = EllipseToSpeckle(ellipse, u); + return new int[] { 3, (int)f.A, (int)f.B, (int)f.C }; } - } - else - { - speckleCurve = CurveToSpeckle(curve.ToNurbsCurve(), u); - } + }) + .ToList(); - CopyProperties(speckleCurve, curve); - return speckleCurve; - } + //var colors = Enumerable.Repeat(defaultColour.ToArgb(), mesh.VertexPositions.Length).ToList(); + //double[] textureCoords; - public NurbsCurve CurveToNative(Curve curve) - { - var points = ArrayToPointList(curve.points, curve.units); - var dsKnots = curve.knots; + //if (SpeckleRhinoConverter.AddMeshTextureCoordinates) + //{ + // textureCoords = mesh.TextureCoordinates.Select(pt => pt).ToFlatArray(); + // return new SpeckleMesh(vertices, faces, Colors, textureCoords, properties: mesh.UserDictionary.ToSpeckle()); + //} - NurbsCurve nurbsCurve = NurbsCurve.ByControlPointsWeightsKnots( - points, - curve.weights.ToArray(), - dsKnots.ToArray(), - curve.degree - ); + var speckleMesh = new Mesh(vertices, faces, units: u); - return nurbsCurve.SetDynamoProperties(GetDynamicMembersFromBase(curve)); - } + CopyProperties(speckleMesh, mesh); - public Base CurveToSpeckle(NurbsCurve curve, string units = null) + using (var box = ComputeMeshBoundingBox(mesh)) { - var u = units ?? ModelUnits; - Base speckleCurve; - if (curve.IsLinear()) - { - using (DS.Line line = curve.GetAsLine()) - { - speckleCurve = LineToSpeckle(line, u); - } - } - else if (curve.IsArc()) - { - using (DS.Arc arc = curve.GetAsArc()) - { - speckleCurve = ArcToSpeckle(arc, u); - } - } - else if (curve.IsCircle()) + speckleMesh.bbox = BoxToSpeckle(box, u); + } + + return speckleMesh; + } + + private DS.Cuboid ComputeMeshBoundingBox(DS.Mesh mesh) + { + double lowX = double.PositiveInfinity, + lowY = double.PositiveInfinity, + lowZ = double.PositiveInfinity; + double highX = double.NegativeInfinity, + highY = double.NegativeInfinity, + highZ = double.NegativeInfinity; + mesh.VertexPositions.ForEach(pos => + { + if (pos.X < lowX) { - using (DS.Circle circle = curve.GetAsCircle()) - { - speckleCurve = CircleToSpeckle(circle, u); - } + lowX = pos.X; } - else if (curve.IsEllipse()) + + if (pos.Y < lowY) { - using (DS.Ellipse ellipse = curve.GetAsEllipse()) - { - speckleCurve = EllipseToSpeckle(ellipse, u); - } + lowY = pos.Y; } - else + + if (pos.Z < lowZ) { - // SpeckleCurve DisplayValue - DS.Curve[] curves = curve.ApproximateWithArcAndLineSegments(); - List polylineCoordinates = - curves.SelectMany(c => PointListToFlatList(new DS.Point[2] { c.StartPoint, c.EndPoint })).ToList(); - polylineCoordinates.AddRange(PointToArray(curves.Last().EndPoint)); - curves.ForEach(c => c.Dispose()); - - Polyline displayValue = new Polyline(polylineCoordinates, u); - List dsKnots = curve.Knots().ToList(); - - Curve spkCurve = new Curve(displayValue, u); - spkCurve.weights = curve.Weights().ToList(); - spkCurve.points = PointListToFlatList(curve.ControlPoints()); - spkCurve.knots = dsKnots; - spkCurve.degree = curve.Degree; - spkCurve.periodic = curve.IsPeriodic; - spkCurve.rational = curve.IsRational; - spkCurve.closed = curve.IsClosed; - spkCurve.domain = new Interval(curve.StartParameter(), curve.EndParameter()); - spkCurve.length = curve.Length; - spkCurve.bbox = BoxToSpeckle(curve.BoundingBox, u); - - speckleCurve = spkCurve; + lowZ = pos.Z; } - CopyProperties(speckleCurve, curve); - return speckleCurve; - } - - // TODO: send this as a spiral class - public Base HelixToSpeckle(Helix helix, string units = null) - { - var u = units ?? ModelUnits; - - /* untested code to send as spiral - using (DS.Plane basePlane = DS.Plane.ByOriginNormal(helix.AxisPoint, helix.Normal)) + if (pos.X > highX) { - var spiral = new Spiral(); - - spiral.startPoint = PointToSpeckle(helix.StartPoint, u); - spiral.endPoint = PointToSpeckle(helix.EndPoint, u); - spiral.plane = PlaneToSpeckle(basePlane, u); - spiral.pitchAxis = VectorToSpeckle(helix.AxisDirection, u); - spiral.pitch = helix.Pitch; - spiral.turns = helix.Angle / (2 * Math.PI); - - // display value - DS.Curve[] curves = helix.ApproximateWithArcAndLineSegments(); - List polylineCoordinates = - curves.SelectMany(c => PointListToFlatList(new DS.Point[2] { c.StartPoint, c.EndPoint })).ToList(); - polylineCoordinates.AddRange(PointToArray(curves.Last().EndPoint)); - curves.ForEach(c => c.Dispose()); - Polyline displayValue = new Polyline(polylineCoordinates, u); - spiral.displayValue = displayValue; - - CopyProperties(spiral, helix); - - spiral.length = helix.Length; - spiral.bbox = BoxToSpeckle(helix.BoundingBox.ToCuboid(), u); - - return spiral; + highX = pos.X; } - */ - using (NurbsCurve nurbsCurve = helix.ToNurbsCurve()) + if (pos.Y > highY) { - var curve = CurveToSpeckle(nurbsCurve, u); - CopyProperties(curve, helix); - return curve; + highY = pos.Y; } - } - #endregion - - #region mesh - - public DS.Mesh BrepToNative(Brep brep) - { - if (brep.displayValue != null) + if (pos.Z > highZ) { - var meshToNative = MeshToNative(brep.displayValue[0]); - return meshToNative; + highZ = pos.Z; } + }); - return null; - } - - // Meshes - public Mesh MeshToSpeckle(DS.Mesh mesh, string units = null) + using (var low = DS.Point.ByCoordinates(lowX, lowY, lowZ)) + using (var high = DS.Point.ByCoordinates(highX, highY, highZ)) { - var u = units ?? ModelUnits; - var vertices = PointListToFlatList(mesh.VertexPositions); - var defaultColour = System.Drawing.Color.FromArgb(255, 100, 100, 100); - - var faces = mesh.FaceIndices.SelectMany(f => - { - if (f.Count == 4) - { - return new int[] { 4, (int)f.A, (int)f.B, (int)f.C, (int)f.D }; - } - else - { - return new int[] { 3, (int)f.A, (int)f.B, (int)f.C }; - } - }) - .ToList(); - - //var colors = Enumerable.Repeat(defaultColour.ToArgb(), mesh.VertexPositions.Length).ToList(); - //double[] textureCoords; - - //if (SpeckleRhinoConverter.AddMeshTextureCoordinates) - //{ - // textureCoords = mesh.TextureCoordinates.Select(pt => pt).ToFlatArray(); - // return new SpeckleMesh(vertices, faces, Colors, textureCoords, properties: mesh.UserDictionary.ToSpeckle()); - //} - - var speckleMesh = new Mesh(vertices, faces, units: u); - - CopyProperties(speckleMesh, mesh); - - using (var box = ComputeMeshBoundingBox(mesh)) - speckleMesh.bbox = BoxToSpeckle(box, u); - - return speckleMesh; + return DS.Cuboid.ByCorners(low, high); } + } + + public DS.Mesh MeshToNative(Mesh mesh) + { + // Triangulate the mesh's NGons, since they're not supported in Dynamo + mesh.TriangulateMesh(true); - private DS.Cuboid ComputeMeshBoundingBox(DS.Mesh mesh) + var points = ArrayToPointList(mesh.vertices, mesh.units); + var faces = new List(); + var i = 0; + var faceIndices = new List(mesh.faces); + while (i < faceIndices.Count) { - double lowX = double.PositiveInfinity, lowY = double.PositiveInfinity, lowZ = double.PositiveInfinity; - double highX = double.NegativeInfinity, highY = double.NegativeInfinity, highZ = double.NegativeInfinity; - mesh.VertexPositions.ForEach(pos => + if (faceIndices[i] == 0 || faceIndices[i] == 3) { - if (pos.X < lowX) lowX = pos.X; - if (pos.Y < lowY) lowY = pos.Y; - if (pos.Z < lowZ) lowZ = pos.Z; - if (pos.X > highX) highX = pos.X; - if (pos.Y > highY) highY = pos.Y; - if (pos.Z > highZ) highZ = pos.Z; - }); - - using (var low = DS.Point.ByCoordinates(lowX, lowY, lowZ)) - using (var high = DS.Point.ByCoordinates(highX, highY, highZ)) - return DS.Cuboid.ByCorners(low, high); - } - - public DS.Mesh MeshToNative(Mesh mesh) - { - // Triangulate the mesh's NGons, since they're not supported in Dynamo - mesh.TriangulateMesh(true); - - var points = ArrayToPointList(mesh.vertices, mesh.units); - var faces = new List(); - var i = 0; - var faceIndices = new List(mesh.faces); - while (i < faceIndices.Count) + // triangle + var ig = IndexGroup.ByIndices((uint)faceIndices[i + 1], (uint)faceIndices[i + 2], (uint)faceIndices[i + 3]); + faces.Add(ig); + i += 4; + } + else if (faceIndices[i] == 1 || faceIndices[i] == 4) { - if (faceIndices[i] == 0 || faceIndices[i] == 3) - { - // triangle - var ig = IndexGroup.ByIndices((uint)faceIndices[i + 1], (uint)faceIndices[i + 2], (uint)faceIndices[i + 3]); - faces.Add(ig); - i += 4; - } - else if (faceIndices[i] == 1 || faceIndices[i] == 4) - { - // quad - var ig = IndexGroup.ByIndices((uint)faceIndices[i + 1], (uint)faceIndices[i + 2], (uint)faceIndices[i + 3], - (uint)faceIndices[i + 4]); - faces.Add(ig); - i += 5; - } - else - { - var fcount = faceIndices[i]; - i += fcount + 1; - } + // quad + var ig = IndexGroup.ByIndices( + (uint)faceIndices[i + 1], + (uint)faceIndices[i + 2], + (uint)faceIndices[i + 3], + (uint)faceIndices[i + 4] + ); + faces.Add(ig); + i += 5; + } + else + { + var fcount = faceIndices[i]; + i += fcount + 1; } - - var dsMesh = DS.Mesh.ByPointsFaceIndices(points, faces); - - dsMesh.SetDynamoProperties(GetDynamicMembersFromBase(mesh)); - - return dsMesh; - } - - #endregion - - public Cuboid BoxToNative(Box box) - { - using (var coordinateSystem = PlaneToNative(box.basePlane).ToCoordinateSystem()) - using (var cLow = DS.Point.ByCartesianCoordinates(coordinateSystem, box.xSize.start ?? 0, box.ySize.start ?? 0, box.zSize.start ?? 0)) - using (var cHigh = DS.Point.ByCartesianCoordinates(coordinateSystem, box.xSize.end ?? 0, box.ySize.end ?? 0, box.zSize.end ?? 0)) - return Cuboid.ByCorners(cLow, cHigh); } - public Box BoxToSpeckle(BoundingBox box, string units = null) - { - var u = units ?? ModelUnits; - return new Box( - PlaneToSpeckle(box.ContextCoordinateSystem.XYPlane), - new Interval(box.MinPoint.X, box.MaxPoint.X), - new Interval(box.MinPoint.Y, box.MaxPoint.Y), - new Interval(box.MinPoint.Z, box.MaxPoint.Z), - u - ); - } - public Box BoxToSpeckle(Cuboid box, string units = null) - { - var u = units ?? ModelUnits; - var plane = PlaneToSpeckle(box.ContextCoordinateSystem.XYPlane, u); + var dsMesh = DS.Mesh.ByPointsFaceIndices(points, faces); - // Todo: Check for cubes that are offset from the plane origin to ensure correct positioning. - var boxToSpeckle = new Box(plane, new Interval(-box.Width / 2, box.Width / 2), new Interval(-box.Length / 2, box.Length / 2), new Interval(-box.Height / 2, box.Height / 2), u); - boxToSpeckle.volume = box.Volume; - boxToSpeckle.area = box.Area; - return boxToSpeckle; - } + dsMesh.SetDynamoProperties(GetDynamicMembersFromBase(mesh)); - public NurbsSurface SurfaceToNative(Surface surface) - { - var points = new DS.Point[][] { }; - var weights = new double[][] { }; + return dsMesh; + } - var controlPoints = surface.GetControlPoints(); + #endregion - points = controlPoints.Select(row => row.Select(p => DS.Point.ByCoordinates( - ScaleToNative(p.x, p.units), - ScaleToNative(p.y, p.units), - ScaleToNative(p.z, p.units))).ToArray()) - .ToArray(); + public Cuboid BoxToNative(Box box) + { + using (var coordinateSystem = PlaneToNative(box.basePlane).ToCoordinateSystem()) + using ( + var cLow = DS.Point.ByCartesianCoordinates( + coordinateSystem, + box.xSize.start ?? 0, + box.ySize.start ?? 0, + box.zSize.start ?? 0 + ) + ) + using ( + var cHigh = DS.Point.ByCartesianCoordinates( + coordinateSystem, + box.xSize.end ?? 0, + box.ySize.end ?? 0, + box.zSize.end ?? 0 + ) + ) + { + return Cuboid.ByCorners(cLow, cHigh); + } + } - weights = controlPoints.Select(row => row.Select(p => p.weight).ToArray()).ToArray(); + public Box BoxToSpeckle(BoundingBox box, string units = null) + { + var u = units ?? ModelUnits; + return new Box( + PlaneToSpeckle(box.ContextCoordinateSystem.XYPlane), + new Interval(box.MinPoint.X, box.MaxPoint.X), + new Interval(box.MinPoint.Y, box.MaxPoint.Y), + new Interval(box.MinPoint.Z, box.MaxPoint.Z), + u + ); + } - var knotsU = surface.knotsU; - var knotsV = surface.knotsV; + public Box BoxToSpeckle(Cuboid box, string units = null) + { + var u = units ?? ModelUnits; + var plane = PlaneToSpeckle(box.ContextCoordinateSystem.XYPlane, u); + + // Todo: Check for cubes that are offset from the plane origin to ensure correct positioning. + var boxToSpeckle = new Box( + plane, + new Interval(-box.Width / 2, box.Width / 2), + new Interval(-box.Length / 2, box.Length / 2), + new Interval(-box.Height / 2, box.Height / 2), + u + ); + boxToSpeckle.volume = box.Volume; + boxToSpeckle.area = box.Area; + return boxToSpeckle; + } - var result = DS.NurbsSurface.ByControlPointsWeightsKnots(points, weights, knotsU.ToArray(), surface.knotsV.ToArray(), - surface.degreeU, surface.degreeV); - return result; - } + public NurbsSurface SurfaceToNative(Surface surface) + { + var points = new DS.Point[][] { }; + var weights = new double[][] { }; + + var controlPoints = surface.GetControlPoints(); + + points = controlPoints + .Select( + row => + row.Select( + p => + DS.Point.ByCoordinates( + ScaleToNative(p.x, p.units), + ScaleToNative(p.y, p.units), + ScaleToNative(p.z, p.units) + ) + ) + .ToArray() + ) + .ToArray(); + + weights = controlPoints.Select(row => row.Select(p => p.weight).ToArray()).ToArray(); + + var knotsU = surface.knotsU; + var knotsV = surface.knotsV; + + var result = DS.NurbsSurface.ByControlPointsWeightsKnots( + points, + weights, + knotsU.ToArray(), + surface.knotsV.ToArray(), + surface.degreeU, + surface.degreeV + ); + return result; + } - public Surface SurfaceToSpeckle(NurbsSurface surface, string units = null) - { - var u = units ?? ModelUnits; - var result = new Surface(); - result.units = u; - // Set control points - var dsPoints = surface.ControlPoints(); - var dsWeights = surface.Weights(); - var points = new List>(); - for (var i = 0; i < dsPoints.Length; i++) + public Surface SurfaceToSpeckle(NurbsSurface surface, string units = null) + { + var u = units ?? ModelUnits; + var result = new Surface(); + result.units = u; + // Set control points + var dsPoints = surface.ControlPoints(); + var dsWeights = surface.Weights(); + var points = new List>(); + for (var i = 0; i < dsPoints.Length; i++) + { + var row = new List(); + for (var j = 0; j < dsPoints[i].Length; j++) { - var row = new List(); - for (var j = 0; j < dsPoints[i].Length; j++) - { - var dsPoint = dsPoints[i][j]; - var dsWeight = dsWeights[i][j]; - row.Add(new ControlPoint(dsPoint.X, dsPoint.Y, dsPoint.Z, dsWeight, null)); - } - - points.Add(row); + var dsPoint = dsPoints[i][j]; + var dsWeight = dsWeights[i][j]; + row.Add(new ControlPoint(dsPoint.X, dsPoint.Y, dsPoint.Z, dsWeight, null)); } - result.SetControlPoints(points); + points.Add(row); + } - // Set degree - result.degreeU = surface.DegreeU; - result.degreeV = surface.DegreeV; + result.SetControlPoints(points); - // Set knot vectors - result.knotsU = surface.UKnots().ToList(); - result.knotsV = surface.VKnots().ToList(); + // Set degree + result.degreeU = surface.DegreeU; + result.degreeV = surface.DegreeV; - // Set other - result.rational = surface.IsRational; - result.closedU = surface.ClosedInU; - result.closedV = surface.ClosedInV; + // Set knot vectors + result.knotsU = surface.UKnots().ToList(); + result.knotsV = surface.VKnots().ToList(); - result.area = surface.Area; - result.bbox = BoxToSpeckle(surface.BoundingBox, u); + // Set other + result.rational = surface.IsRational; + result.closedU = surface.ClosedInU; + result.closedV = surface.ClosedInV; - return result; - } + result.area = surface.Area; + result.bbox = BoxToSpeckle(surface.BoundingBox, u); - /// - /// Copies props from a design script entity to a speckle object. - /// - /// - /// - public void CopyProperties(Base to, DesignScriptEntity from) - { - var dict = from.GetSpeckleProperties(); - foreach (var kvp in dict) - { - to[kvp.Key] = kvp.Value; - } - } + return result; + } - public Dictionary GetDynamicMembersFromBase(Base obj) + /// + /// Copies props from a design script entity to a speckle object. + /// + /// + /// + public void CopyProperties(Base to, DesignScriptEntity from) + { + var dict = from.GetSpeckleProperties(); + foreach (var kvp in dict) { - return obj.GetMembers(DynamicBaseMemberType.Dynamic); + to[kvp.Key] = kvp.Value; } + } + public Dictionary GetDynamicMembersFromBase(Base obj) + { + return obj.GetMembers(DynamicBaseMemberType.Dynamic); } } diff --git a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Units.cs b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Units.cs index 04af1f2fc8..518e7c2b70 100644 --- a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Units.cs +++ b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.Units.cs @@ -3,127 +3,141 @@ using Objects.Converter.Revit; #endif -namespace Objects.Converter.Dynamo +namespace Objects.Converter.Dynamo; + +public partial class ConverterDynamo { - public partial class ConverterDynamo + private string _modelUnits; + public string ModelUnits { - private string _modelUnits; - public string ModelUnits + get { - get + if (string.IsNullOrEmpty(_modelUnits)) { - if (string.IsNullOrEmpty(_modelUnits)) - { #if REVIT - _modelUnits = GetRevitDocUnits(); + _modelUnits = GetRevitDocUnits(); #else - _modelUnits = Speckle.Core.Kits.Units.Meters; + _modelUnits = Speckle.Core.Kits.Units.Meters; #endif - } - return _modelUnits; } + return _modelUnits; } + } #if REVIT - public string GetRevitDocUnits() + public string GetRevitDocUnits() + { + if (Doc != null) { - if (Doc != null) - { - _modelUnits = UnitsToSpeckle(RevitLengthTypeId); - return _modelUnits; - } - return Speckle.Core.Kits.Units.Meters; + _modelUnits = UnitsToSpeckle(RevitLengthTypeId); + return _modelUnits; } + return Speckle.Core.Kits.Units.Meters; + } #if (REVIT2020 || REVIT2021 ) - private DisplayUnitType _revitUnitsTypeId = DisplayUnitType.DUT_UNDEFINED; - public DisplayUnitType RevitLengthTypeId - { - get - { - if (_revitUnitsTypeId == DisplayUnitType.DUT_UNDEFINED) - { - var fo = Doc.GetUnits().GetFormatOptions(UnitType.UT_Length); - _revitUnitsTypeId = fo.DisplayUnits; - } - return _revitUnitsTypeId; - } - } - - private string UnitsToSpeckle(DisplayUnitType type) - { - switch (type) - { - case DisplayUnitType.DUT_MILLIMETERS: - return Speckle.Core.Kits.Units.Millimeters; - case DisplayUnitType.DUT_CENTIMETERS: - return Speckle.Core.Kits.Units.Centimeters; - case DisplayUnitType.DUT_METERS: - return Speckle.Core.Kits.Units.Meters; - case DisplayUnitType.DUT_METERS_CENTIMETERS: - return Speckle.Core.Kits.Units.Meters; - case DisplayUnitType.DUT_DECIMAL_INCHES: - return Speckle.Core.Kits.Units.Inches; - case DisplayUnitType.DUT_DECIMAL_FEET: - return Speckle.Core.Kits.Units.Feet; - case DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES: - return Speckle.Core.Kits.Units.Feet; - case DisplayUnitType.DUT_FRACTIONAL_INCHES: - return Speckle.Core.Kits.Units.Inches; - default: - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{type}\" is unsupported."); - } - - } -#else - - private ForgeTypeId _revitUnitsTypeId; - private ForgeTypeId RevitLengthTypeId + private DisplayUnitType _revitUnitsTypeId = DisplayUnitType.DUT_UNDEFINED; + public DisplayUnitType RevitLengthTypeId + { + get { - get + if (_revitUnitsTypeId == DisplayUnitType.DUT_UNDEFINED) { - if (_revitUnitsTypeId == null) - { - var fo = Doc.GetUnits().GetFormatOptions(SpecTypeId.Length); - _revitUnitsTypeId = fo.GetUnitTypeId(); - } - return _revitUnitsTypeId; + var fo = Doc.GetUnits().GetFormatOptions(UnitType.UT_Length); + _revitUnitsTypeId = fo.DisplayUnits; } + return _revitUnitsTypeId; } + } - private string UnitsToSpeckle(ForgeTypeId typeId) + private string UnitsToSpeckle(DisplayUnitType type) + { + switch (type) { - if (typeId == UnitTypeId.Millimeters) + case DisplayUnitType.DUT_MILLIMETERS: return Speckle.Core.Kits.Units.Millimeters; - else if (typeId == UnitTypeId.Centimeters) + case DisplayUnitType.DUT_CENTIMETERS: return Speckle.Core.Kits.Units.Centimeters; - else if (typeId == UnitTypeId.Meters) + case DisplayUnitType.DUT_METERS: return Speckle.Core.Kits.Units.Meters; - else if (typeId == UnitTypeId.MetersCentimeters) + case DisplayUnitType.DUT_METERS_CENTIMETERS: return Speckle.Core.Kits.Units.Meters; - else if (typeId == UnitTypeId.Inches) + case DisplayUnitType.DUT_DECIMAL_INCHES: return Speckle.Core.Kits.Units.Inches; - else if (typeId == UnitTypeId.Feet) + case DisplayUnitType.DUT_DECIMAL_FEET: return Speckle.Core.Kits.Units.Feet; - else if (typeId == UnitTypeId.FeetFractionalInches) + case DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES: return Speckle.Core.Kits.Units.Feet; - else if (typeId == UnitTypeId.FractionalInches) + case DisplayUnitType.DUT_FRACTIONAL_INCHES: return Speckle.Core.Kits.Units.Inches; - - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{typeId}\" is unsupported."); + default: + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{type}\" is unsupported."); } -#endif + } +#else -#endif + private ForgeTypeId _revitUnitsTypeId; + private ForgeTypeId RevitLengthTypeId + { + get + { + if (_revitUnitsTypeId == null) + { + var fo = Doc.GetUnits().GetFormatOptions(SpecTypeId.Length); + _revitUnitsTypeId = fo.GetUnitTypeId(); + } + return _revitUnitsTypeId; + } + } - private double ScaleToNative(double value, string units) + private string UnitsToSpeckle(ForgeTypeId typeId) + { + if (typeId == UnitTypeId.Millimeters) + { + return Speckle.Core.Kits.Units.Millimeters; + } + else if (typeId == UnitTypeId.Centimeters) + { + return Speckle.Core.Kits.Units.Centimeters; + } + else if (typeId == UnitTypeId.Meters) + { + return Speckle.Core.Kits.Units.Meters; + } + else if (typeId == UnitTypeId.MetersCentimeters) + { + return Speckle.Core.Kits.Units.Meters; + } + else if (typeId == UnitTypeId.Inches) + { + return Speckle.Core.Kits.Units.Inches; + } + else if (typeId == UnitTypeId.Feet) + { + return Speckle.Core.Kits.Units.Feet; + } + else if (typeId == UnitTypeId.FeetFractionalInches) + { + return Speckle.Core.Kits.Units.Feet; + } + else if (typeId == UnitTypeId.FractionalInches) { - var f = Speckle.Core.Kits.Units.GetConversionFactor(units, ModelUnits); - return value * f; + return Speckle.Core.Kits.Units.Inches; } + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{typeId}\" is unsupported."); + } + +#endif + +#endif + + private double ScaleToNative(double value, string units) + { + var f = Speckle.Core.Kits.Units.GetConversionFactor(units, ModelUnits); + return value * f; } } diff --git a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.cs b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.cs index fbc1a7ecf0..85c312b79f 100644 --- a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.cs +++ b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/ConverterDynamo.cs @@ -23,257 +23,256 @@ using Transform = Objects.Other.Transform; using Vector = Objects.Geometry.Vector; -namespace Objects.Converter.Dynamo +namespace Objects.Converter.Dynamo; + +public partial class ConverterDynamo : ISpeckleConverter { - public partial class ConverterDynamo : ISpeckleConverter - { #if REVIT2024 - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2024); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2024); #elif REVIT2023 - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2023); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2023); #elif REVIT2022 - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2022); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2022); #elif REVIT2021 - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2021); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit2021); #elif REVIT - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vRevit); #else - public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox); + public static string AppName = HostApplications.Dynamo.GetVersion(HostAppVersion.vSandbox); #endif - public string Description => "Default Speckle Kit for Dynamo"; - public string Name => nameof(ConverterDynamo); - public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; + public string Description => "Default Speckle Kit for Dynamo"; + public string Name => nameof(ConverterDynamo); + public string Author => "Speckle"; + public string WebsiteOrEmail => "https://speckle.systems"; - public ReceiveMode ReceiveMode { get; set; } + public ReceiveMode ReceiveMode { get; set; } - public IEnumerable GetServicedApplications() => new string[] { AppName }; + public IEnumerable GetServicedApplications() => new string[] { AppName }; - public HashSet ConversionErrors { get; private set; } = new HashSet(); + public HashSet ConversionErrors { get; private set; } = new HashSet(); #if REVIT - public Document Doc { get; private set; } + public Document Doc { get; private set; } #endif - public List ContextObjects { get; set; } = new List(); + public List ContextObjects { get; set; } = new List(); - public ProgressReport Report => new ProgressReport(); + public ProgressReport Report => new(); - public void SetContextObjects(List objects) => ContextObjects = objects; + public void SetContextObjects(List objects) => ContextObjects = objects; - public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); + public void SetPreviousContextObjects(List objects) => throw new NotImplementedException(); - public void SetConverterSettings(object settings) - { - throw new NotImplementedException("This converter does not have any settings."); - } + public void SetConverterSettings(object settings) + { + throw new NotImplementedException("This converter does not have any settings."); + } - public Base ConvertToSpeckle(object @object) + public Base ConvertToSpeckle(object @object) + { + switch (@object) { - switch (@object) - { - case DS.Point o: - return PointToSpeckle(o); + case DS.Point o: + return PointToSpeckle(o); - case DS.Vector o: - return VectorToSpeckle(o); + case DS.Vector o: + return VectorToSpeckle(o); - case DS.Plane o: - return PlaneToSpeckle(o); + case DS.Plane o: + return PlaneToSpeckle(o); - case DS.Line o: - return LineToSpeckle(o); + case DS.Line o: + return LineToSpeckle(o); - case DS.Rectangle o: - return PolylineToSpeckle(o); + case DS.Rectangle o: + return PolylineToSpeckle(o); - case DS.Polygon o: - return PolylineToSpeckle(o); + case DS.Polygon o: + return PolylineToSpeckle(o); - case DS.Circle o: - return CircleToSpeckle(o); + case DS.Circle o: + return CircleToSpeckle(o); - case DS.Arc o: - return ArcToSpeckle(o); + case DS.Arc o: + return ArcToSpeckle(o); - case DS.Ellipse o: - return EllipseToSpeckle(o); + case DS.Ellipse o: + return EllipseToSpeckle(o); - case DS.EllipseArc o: - return EllipseToSpeckle(o); + case DS.EllipseArc o: + return EllipseToSpeckle(o); - case DS.PolyCurve o: - return PolycurveToSpeckle(o); + case DS.PolyCurve o: + return PolycurveToSpeckle(o); - case DS.NurbsCurve o: - return CurveToSpeckle(o); + case DS.NurbsCurve o: + return CurveToSpeckle(o); - case DS.Helix o: - return HelixToSpeckle(o); + case DS.Helix o: + return HelixToSpeckle(o); - case DS.Curve o: //last of the curves - return CurveToSpeckle(o); + case DS.Curve o: //last of the curves + return CurveToSpeckle(o); - case DS.Mesh o: - return MeshToSpeckle(o); + case DS.Mesh o: + return MeshToSpeckle(o); - case DS.Cuboid o: - return BoxToSpeckle(o); + case DS.Cuboid o: + return BoxToSpeckle(o); #if REVIT - //using the revit converter to handle Revit geometry - case RD.Element o: - var c = new ConverterRevit(); - c.SetContextDocument(Doc); - return c.ConvertToSpeckle(o.InternalElement); + //using the revit converter to handle Revit geometry + case RD.Element o: + var c = new ConverterRevit(); + c.SetContextDocument(Doc); + return c.ConvertToSpeckle(o.InternalElement); #endif - default: - throw new NotSupportedException(); - } + default: + throw new NotSupportedException(); } + } - public object ConvertToNative(Base @object) + public object ConvertToNative(Base @object) + { + switch (@object) { - switch (@object) - { - case Point o: - return PointToNative(o); + case Point o: + return PointToNative(o); - case Vector o: - return VectorToNative(o); + case Vector o: + return VectorToNative(o); - case Plane o: - return PlaneToNative(o); + case Plane o: + return PlaneToNative(o); - case Line o: - return LineToNative(o); + case Line o: + return LineToNative(o); - case Polyline o: - return PolylineToNative(o); + case Polyline o: + return PolylineToNative(o); - case Polycurve o: - return PolycurveToNative(o); + case Polycurve o: + return PolycurveToNative(o); - case Circle o: - return CircleToNative(o); + case Circle o: + return CircleToNative(o); - case Arc o: - return ArcToNative(o); + case Arc o: + return ArcToNative(o); - case Ellipse o: - return EllipseToNative(o); + case Ellipse o: + return EllipseToNative(o); - case Spiral o: - return PolylineToNative(o.displayValue); + case Spiral o: + return PolylineToNative(o.displayValue); - case Curve o: - return CurveToNative(o); + case Curve o: + return CurveToNative(o); - case Brep o: - return BrepToNative(o); + case Brep o: + return BrepToNative(o); - case Mesh o: - return MeshToNative(o); + case Mesh o: + return MeshToNative(o); - case Box o: - return BoxToNative(o); + case Box o: + return BoxToNative(o); - case Transform o: - return TransformToNative(o); - default: - throw new NotSupportedException(); - } + case Transform o: + return TransformToNative(o); + default: + throw new NotSupportedException(); } + } - public object ConvertToNativeDisplayable(Base @object) - { - throw new NotImplementedException(); - } + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } - public List ConvertToSpeckle(List objects) - { - return objects.Select(x => ConvertToSpeckle(x)).ToList(); - } + public List ConvertToSpeckle(List objects) + { + return objects.Select(x => ConvertToSpeckle(x)).ToList(); + } - public List ConvertToNative(List objects) - { - return objects.Select(x => ConvertToNative(x)).ToList(); - ; - } + public List ConvertToNative(List objects) + { + return objects.Select(x => ConvertToNative(x)).ToList(); + ; + } - public bool CanConvertToSpeckle(object @object) + public bool CanConvertToSpeckle(object @object) + { + switch (@object) { - switch (@object) - { - case DS.Point _: - case DS.Vector _: - case DS.Plane _: - case DS.Line _: - case DS.Rectangle _: - case DS.Polygon _: - case DS.Circle _: - case DS.Arc _: - case DS.Ellipse _: - case DS.EllipseArc _: - case DS.PolyCurve _: - case DS.NurbsCurve _: - case DS.Helix _: - case DS.Curve _: //last _f the curves - case DS.Mesh _: - case DS.Cuboid _: - return true; + case DS.Point _: + case DS.Vector _: + case DS.Plane _: + case DS.Line _: + case DS.Rectangle _: + case DS.Polygon _: + case DS.Circle _: + case DS.Arc _: + case DS.Ellipse _: + case DS.EllipseArc _: + case DS.PolyCurve _: + case DS.NurbsCurve _: + case DS.Helix _: + case DS.Curve _: //last _f the curves + case DS.Mesh _: + case DS.Cuboid _: + return true; #if REVIT - //using the revit converter to handle Revit geometry - case RD.Element o: - var c = new ConverterRevit(); - c.SetContextDocument(Doc); - return c.CanConvertToSpeckle(o.InternalElement); + //using the revit converter to handle Revit geometry + case RD.Element o: + var c = new ConverterRevit(); + c.SetContextDocument(Doc); + return c.CanConvertToSpeckle(o.InternalElement); #endif - default: - return false; - } + default: + return false; } + } - public bool CanConvertToNative(Base @object) + public bool CanConvertToNative(Base @object) + { + switch (@object) { - switch (@object) - { - case Point _: - case Vector _: - case Plane _: - case Line _: - case Polyline _: - case Polycurve _: - case Circle _: - case Arc _: - case Ellipse _: - case Spiral _: - case Curve _: - case Brep _: - case Mesh _: - case Box _: - case Transform _: - return true; - - default: - return false; - } + case Point _: + case Vector _: + case Plane _: + case Line _: + case Polyline _: + case Polycurve _: + case Circle _: + case Arc _: + case Ellipse _: + case Spiral _: + case Curve _: + case Brep _: + case Mesh _: + case Box _: + case Transform _: + return true; + + default: + return false; } + } - public bool CanConvertToNativeDisplayable(Base @object) - { - return false; - } + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; + } - public void SetContextDocument(object doc) - { + public void SetContextDocument(object doc) + { #if REVIT - Doc = (Document)doc; + Doc = (Document)doc; #endif - } } } diff --git a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/Utils.cs b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/Utils.cs index 23cd7c44ac..d256330c07 100644 --- a/Objects/Converters/ConverterDynamo/ConverterDynamoShared/Utils.cs +++ b/Objects/Converters/ConverterDynamo/ConverterDynamoShared/Utils.cs @@ -1,292 +1,297 @@ -using Autodesk.DesignScript.Geometry; +using Autodesk.DesignScript.Geometry; using System; using System.Collections.Generic; using System.Linq; using DS = Autodesk.DesignScript.Geometry; -namespace Objects.Converter.Dynamo +namespace Objects.Converter.Dynamo; + +public static class Utils { - public static class Utils - { - private const double EPS = 1e-6; - private const string speckleKey = "speckle"; + private const double EPS = 1e-6; + private const string speckleKey = "speckle"; - #region Helper Methods + #region Helper Methods - public static DS.Point ToPoint(this double[] arr) - { - return DS.Point.ByCoordinates(arr[0], arr[1], arr[2]); - } + public static DS.Point ToPoint(this double[] arr) + { + return DS.Point.ByCoordinates(arr[0], arr[1], arr[2]); + } - public static double ToDegrees(this double radians) - { - return radians * (180 / Math.PI); - } + public static double ToDegrees(this double radians) + { + return radians * (180 / Math.PI); + } - public static double ToRadians(this double degrees) - { - return degrees * (Math.PI / 180); - } + public static double ToRadians(this double degrees) + { + return degrees * (Math.PI / 180); + } - public static bool Threshold(double value1, double value2, double error = EPS) - { - return Math.Abs(value1 - value2) <= error; - } + public static bool Threshold(double value1, double value2, double error = EPS) + { + return Math.Abs(value1 - value2) <= error; + } - public static double Median(double min, double max) - { - return ((max - min) * 0.5) + min; - } + public static double Median(double min, double max) + { + return ((max - min) * 0.5) + min; + } - #endregion + #endregion - #region Curves Helper Methods + #region Curves Helper Methods - public static bool IsLinear(this DS.Curve curve) + public static bool IsLinear(this DS.Curve curve) + { + try { - try - { - if (curve.IsClosed) - { - return false; - } - - //Dynamo cannot be trusted when less than 1e-6 - var extremesDistance = curve.StartPoint.DistanceTo(curve.EndPoint); - return Threshold(curve.Length, extremesDistance); - } - catch (Exception e) + if (curve.IsClosed) { return false; } - } - public static DS.Line GetAsLine(this DS.Curve curve) + //Dynamo cannot be trusted when less than 1e-6 + var extremesDistance = curve.StartPoint.DistanceTo(curve.EndPoint); + return Threshold(curve.Length, extremesDistance); + } + catch (Exception e) { - if (curve.IsClosed) - { - throw new ArgumentException("Curve is closed, cannot be a Line"); - } - - return DS.Line.ByStartPointEndPoint(curve.StartPoint, curve.EndPoint); + return false; } + } + public static DS.Line GetAsLine(this DS.Curve curve) + { + if (curve.IsClosed) + { + throw new ArgumentException("Curve is closed, cannot be a Line"); + } + return DS.Line.ByStartPointEndPoint(curve.StartPoint, curve.EndPoint); + } - public static DS.Arc GetAsArc(this DS.Curve curve) + public static DS.Arc GetAsArc(this DS.Curve curve) + { + if (curve.IsClosed) { - if (curve.IsClosed) - { - throw new ArgumentException("Curve is closed, cannot be an Arc"); - } - - using (DS.Point midPoint = curve.PointAtParameter(0.5)) - { - return DS.Arc.ByThreePoints(curve.StartPoint, midPoint, curve.EndPoint); - } + throw new ArgumentException("Curve is closed, cannot be an Arc"); } - public static bool IsCircle(this DS.Curve curve) + using (DS.Point midPoint = curve.PointAtParameter(0.5)) { - try - { - if (!curve.IsClosed) - { - return false; - } - - using (DS.Point midPoint = curve.PointAtParameter(0.5)) - { - double radius = curve.StartPoint.DistanceTo(midPoint) * 0.5; - return Threshold(radius, (curve.Length) / (2 * Math.PI)); - } - } - catch (Exception e) - { - return false; - } + return DS.Arc.ByThreePoints(curve.StartPoint, midPoint, curve.EndPoint); } + } - public static DS.Circle GetAsCircle(this DS.Curve curve) + public static bool IsCircle(this DS.Curve curve) + { + try { if (!curve.IsClosed) { - throw new ArgumentException("Curve is not closed, cannot be a Circle"); + return false; } - DS.Point start = curve.StartPoint; using (DS.Point midPoint = curve.PointAtParameter(0.5)) - using (DS.Point centre = DS.Point.ByCoordinates(Median(start.X, midPoint.X), Median(start.Y, midPoint.Y), - Median(start.Z, midPoint.Z))) { - return DS.Circle.ByCenterPointRadiusNormal( - centre, - centre.DistanceTo(start), - curve.Normal - ); + double radius = curve.StartPoint.DistanceTo(midPoint) * 0.5; + return Threshold(radius, (curve.Length) / (2 * Math.PI)); } } + catch (Exception e) + { + return false; + } + } + + public static DS.Circle GetAsCircle(this DS.Curve curve) + { + if (!curve.IsClosed) + { + throw new ArgumentException("Curve is not closed, cannot be a Circle"); + } - public static bool IsEllipse(this DS.Curve curve) + DS.Point start = curve.StartPoint; + using (DS.Point midPoint = curve.PointAtParameter(0.5)) + using ( + DS.Point centre = DS.Point.ByCoordinates( + Median(start.X, midPoint.X), + Median(start.Y, midPoint.Y), + Median(start.Z, midPoint.Z) + ) + ) { - try - { - if (!curve.IsClosed) - { - return false; - } - - //http://www.numericana.com/answer/ellipse.htm - double[] parameters = new double[4] { 0, 0.25, 0.5, 0.75 }; - DS.Point[] points = parameters.Select(p => curve.PointAtParameter(p)).ToArray(); - double a = points[0].DistanceTo(points[2]) * 0.5; // Max Radius - double b = points[1].DistanceTo(points[3]) * 0.5; // Min Radius - points.ForEach(p => p.Dispose()); - - double h = Math.Pow(a - b, 2) / Math.Pow(a + b, 2); - double perimeter = Math.PI * (a + b) * (1 + (3 * h / (10 + Math.Sqrt(4 - 3 * h)))); - - return Threshold(curve.Length, perimeter, 1e-5); //Ellipse perimeter is an approximation - } - catch (Exception e) - { - return false; - } + return DS.Circle.ByCenterPointRadiusNormal(centre, centre.DistanceTo(start), curve.Normal); } + } - public static DS.Ellipse GetAsEllipse(this DS.Curve curve) + public static bool IsEllipse(this DS.Curve curve) + { + try { if (!curve.IsClosed) { - throw new ArgumentException("Curve is not closed, cannot be an Ellipse"); + return false; } + //http://www.numericana.com/answer/ellipse.htm double[] parameters = new double[4] { 0, 0.25, 0.5, 0.75 }; DS.Point[] points = parameters.Select(p => curve.PointAtParameter(p)).ToArray(); double a = points[0].DistanceTo(points[2]) * 0.5; // Max Radius double b = points[1].DistanceTo(points[3]) * 0.5; // Min Radius + points.ForEach(p => p.Dispose()); - using (DS.Point centre = DS.Point.ByCoordinates(Median(points[0].X, points[2].X), - Median(points[0].Y, points[2].Y), Median(points[0].Z, points[2].Z))) - { - points.ForEach(p => p.Dispose()); + double h = Math.Pow(a - b, 2) / Math.Pow(a + b, 2); + double perimeter = Math.PI * (a + b) * (1 + (3 * h / (10 + Math.Sqrt(4 - 3 * h)))); - return DS.Ellipse.ByPlaneRadii( - DS.Plane.ByOriginNormalXAxis(centre, curve.Normal, DS.Vector.ByTwoPoints(centre, curve.StartPoint)), - a, - b - ); - } + return Threshold(curve.Length, perimeter, 1e-5); //Ellipse perimeter is an approximation + } + catch (Exception e) + { + return false; + } + } + + public static DS.Ellipse GetAsEllipse(this DS.Curve curve) + { + if (!curve.IsClosed) + { + throw new ArgumentException("Curve is not closed, cannot be an Ellipse"); } - public static bool IsPolyline(this PolyCurve polycurve) + double[] parameters = new double[4] { 0, 0.25, 0.5, 0.75 }; + DS.Point[] points = parameters.Select(p => curve.PointAtParameter(p)).ToArray(); + double a = points[0].DistanceTo(points[2]) * 0.5; // Max Radius + double b = points[1].DistanceTo(points[3]) * 0.5; // Min Radius + + using ( + DS.Point centre = DS.Point.ByCoordinates( + Median(points[0].X, points[2].X), + Median(points[0].Y, points[2].Y), + Median(points[0].Z, points[2].Z) + ) + ) { - return polycurve.Curves().All(c => c.IsLinear()); + points.ForEach(p => p.Dispose()); + + return DS.Ellipse.ByPlaneRadii( + DS.Plane.ByOriginNormalXAxis(centre, curve.Normal, DS.Vector.ByTwoPoints(centre, curve.StartPoint)), + a, + b + ); } + } - public static bool IsArc(this DS.Curve curve) + public static bool IsPolyline(this PolyCurve polycurve) + { + return polycurve.Curves().All(c => c.IsLinear()); + } + + public static bool IsArc(this DS.Curve curve) + { + try { - try + if (curve.IsClosed) { - if (curve.IsClosed) - { - return false; - } - - using (DS.Point midPoint = curve.PointAtParameter(0.5)) - using (DS.Arc arc = DS.Arc.ByThreePoints(curve.StartPoint, midPoint, curve.EndPoint)) - { - return Threshold(arc.Length, curve.Length); - } + return false; } - catch (Exception e) + + using (DS.Point midPoint = curve.PointAtParameter(0.5)) + using (DS.Arc arc = DS.Arc.ByThreePoints(curve.StartPoint, midPoint, curve.EndPoint)) { - return false; + return Threshold(arc.Length, curve.Length); } } + catch (Exception e) + { + return false; + } + } - #endregion + #endregion - public static Dictionary GetSpeckleProperties(this DesignScriptEntity geometry) + public static Dictionary GetSpeckleProperties(this DesignScriptEntity geometry) + { + var userData = geometry.Tags.LookupTag(speckleKey) as DesignScript.Builtin.Dictionary; + if (userData == null) { - var userData = geometry.Tags.LookupTag(speckleKey) as DesignScript.Builtin.Dictionary; - if (userData == null) - return new Dictionary(); - return userData.ToSpeckleX(); - ; + return new Dictionary(); } + return userData.ToSpeckleX(); + ; + } - public static T SetDynamoProperties(this DesignScriptEntity geometry, Dictionary properties) + public static T SetDynamoProperties(this DesignScriptEntity geometry, Dictionary properties) + { + if (properties != null) { - if (properties != null) - { - geometry.Tags.AddTag(speckleKey, properties.ToNativeX()); - } - - return (T)Convert.ChangeType(geometry, typeof(T)); + geometry.Tags.AddTag(speckleKey, properties.ToNativeX()); } - /// SpeckleCore does not currently support dictionaries, therefore avoiding the canonical ToSpeckle - public static Dictionary ToSpeckleX(this DesignScript.Builtin.Dictionary dict) + return (T)Convert.ChangeType(geometry, typeof(T)); + } + + /// SpeckleCore does not currently support dictionaries, therefore avoiding the canonical ToSpeckle + public static Dictionary ToSpeckleX(this DesignScript.Builtin.Dictionary dict) + { + if (dict == null) { - if (dict == null) - { - return null; - } + return null; + } - var speckleDict = new Dictionary(); - foreach (var key in dict.Keys) + var speckleDict = new Dictionary(); + foreach (var key in dict.Keys) + { + object value = dict.ValueAtKey(key); + if (value is DesignScript.Builtin.Dictionary) { - object value = dict.ValueAtKey(key); - if (value is DesignScript.Builtin.Dictionary) - { - value = (value as DesignScript.Builtin.Dictionary).ToSpeckleX(); - } - - //TODO: - //else if (value is Geometry) - //{ - // value = Converter.Serialise(value); - //} - speckleDict.Add(key, value); + value = (value as DesignScript.Builtin.Dictionary).ToSpeckleX(); } - return speckleDict; + //TODO: + //else if (value is Geometry) + //{ + // value = Converter.Serialise(value); + //} + speckleDict.Add(key, value); } - /// SpeckleCore does not currently support dictionaries, therofere avoiding the canonical ToNative - public static DesignScript.Builtin.Dictionary ToNativeX(this Dictionary speckleDict) + return speckleDict; + } + + /// SpeckleCore does not currently support dictionaries, therofere avoiding the canonical ToNative + public static DesignScript.Builtin.Dictionary ToNativeX(this Dictionary speckleDict) + { + if (speckleDict == null) { - if (speckleDict == null) - { - return null; - } + return null; + } - var keys = new List(); - var values = new List(); - foreach (var pair in speckleDict) + var keys = new List(); + var values = new List(); + foreach (var pair in speckleDict) + { + object value = pair.Value; + if (value is Dictionary) { - object value = pair.Value; - if (value is Dictionary) - { - value = (value as Dictionary).ToNativeX(); - } - - //else if (value is Base) - //{ - // value = Converter.Deserialise(value as Base); - //} - keys.Add(pair.Key); - values.Add(value); + value = (value as Dictionary).ToNativeX(); } - return DesignScript.Builtin.Dictionary.ByKeysValues(keys, values); + //else if (value is Base) + //{ + // value = Converter.Deserialise(value as Base); + //} + keys.Add(pair.Key); + values.Add(value); } + + return DesignScript.Builtin.Dictionary.ByKeysValues(keys, values); } } diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Geometry.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Geometry.cs index 87680c0486..7b589c644f 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Geometry.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Geometry.cs @@ -43,32 +43,26 @@ private PrimitiveProcessor() SetPoints(new List()); } - public IReadOnlyList Coords => _coords.AsReadOnly(); - private IReadOnlyList Faces => _faces.AsReadOnly(); - public IReadOnlyList Triangles => _triangles.AsReadOnly(); - public IReadOnlyList Lines => _lines.AsReadOnly(); - public IReadOnlyList Points => _points.AsReadOnly(); - public IEnumerable LocalToWorldTransformation { get; set; } - private bool ElevationMode { get; set; } - public void Line(InwSimpleVertex v1, InwSimpleVertex v2) { if (v1 == null || v2 == null) + { return; + } #pragma warning disable CA2000 var vD1 = SetElevationModeVector( @@ -99,7 +93,10 @@ public void Line(InwSimpleVertex v1, InwSimpleVertex v2) public void Point(InwSimpleVertex v1) { if (v1 == null) + { return; + } + var vD1 = SetElevationModeVector( ApplyTransformation(VectorFromVertex(v1), LocalToWorldTransformation), ElevationMode @@ -116,7 +113,9 @@ public void SnapPoint(InwSimpleVertex v1) public void Triangle(InwSimpleVertex v1, InwSimpleVertex v2, InwSimpleVertex v3) { if (v1 == null || v2 == null || v3 == null) + { return; + } var vD1 = SetElevationModeVector( ApplyTransformation(VectorFromVertex(v1), LocalToWorldTransformation), @@ -213,7 +212,7 @@ private static Vector3D ApplyTransformation(Vector3 vector3, IEnumerable private static Vector3 VectorFromVertex(InwSimpleVertex v) { var arrayV = (Array)v.coord; - return new Vector3((float)arrayV.GetValue(1), (float)arrayV.GetValue(2), (float)arrayV.GetValue(3)); + return new Vector3((float)arrayV.GetValue(1), (float)arrayV.GetValue(2), (float)arrayV.GetValue(3)); } } @@ -231,19 +230,14 @@ public NavisworksGeometry(ModelItem modelItem) Selection = ComBridge.ToInwOpSelection(modelItemCollection); } - public InwOpSelection Selection { get; set; } - public ModelItem ModelItem { get; set; } - private IEnumerable ModelFragments => ModelFragmentStack; - public bool ElevationMode { get; set; } - public IEnumerable GetUniqueGeometryFragments() { var processors = new List(); @@ -257,7 +251,9 @@ public IEnumerable GetUniqueGeometryFragments() if ( !IsSameFragmentPath(((Array)fragment.path.ArrayData).ToArray(), ((Array)path.ArrayData).ToArray()) ) + { continue; + } var localToWorldTransform = (InwLTransform3f3)fragment.GetLocalToWorldMatrix(); @@ -280,11 +276,15 @@ private static bool IsSameFragmentPath(Array a1, Array a2) private static double[] ConvertArrayToDouble(Array arr) { if (arr.Rank != 1) + { throw new ArgumentException("The input array must have a rank of 1."); + } var doubleArray = new double[arr.GetLength(0)]; for (var ix = arr.GetLowerBound(0); ix <= arr.GetUpperBound(0); ++ix) + { doubleArray[ix - arr.GetLowerBound(0)] = (double)arr.GetValue(ix); + } return doubleArray; } @@ -302,13 +302,10 @@ public TriangleD(Vector3D v1, Vector3D v2, Vector3D v3) Vertex3 = v3; } - public Vector3D Vertex1 { get; set; } - public Vector3D Vertex2 { get; set; } - public Vector3D Vertex3 { get; set; } } @@ -329,10 +326,8 @@ public LineD(Vector3D v1, Vector3D v2) Vertex2 = v2; } - public Vector3D Vertex1 { get; set; } - public Vector3D Vertex2 { get; set; } } @@ -354,16 +349,12 @@ public partial class ConverterNavisworks { private static Vector3D TransformVector3D { get; set; } - public Vector SettingOutPoint { get; set; } - public Vector TransformVector { get; set; } - private BoundingBox3D ModelBoundingBox { get; set; } - /// /// ElevationMode is the indicator that the model is being handled as an XY ground plane /// with Z as elevation height. @@ -423,8 +414,8 @@ private static void SetModelOrientationMode() private static bool VectorMatch(Vector3D vectorA, Vector3D vectorB, double tolerance = 1e-9) { return Math.Abs(vectorA.X - vectorB.X) < tolerance - && Math.Abs(vectorA.Y - vectorB.Y) < tolerance - && Math.Abs(vectorA.Z - vectorB.Z) < tolerance; + && Math.Abs(vectorA.Y - vectorB.Y) < tolerance + && Math.Abs(vectorA.Z - vectorB.Z) < tolerance; } private static void PopulateModelFragments(NavisworksGeometry geometry) @@ -441,7 +432,9 @@ private static void PopulateModelFragments(NavisworksGeometry geometry) var isSame = !(a1.Length != a2.Length || !a1.SequenceEqual(a2)); if (isSame) + { geometry.ModelFragmentStack.Push(fragment); + } GC.KeepAlive(fragments); } @@ -497,11 +490,15 @@ private static IReadOnlyList TranslateFragmentGeometry(NavisworksGeometry } if (lines == null) + { continue; + } var lineCount = lines.Count; if (lineCount <= 0) + { continue; + } baseGeometries.AddRange( from lineD in lines diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Other.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Other.cs index ab9999b4f0..fc48bb7c69 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Other.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Other.cs @@ -1,4 +1,4 @@ -using System; +using System; using Autodesk.Navisworks.Api; using Objects.Other; using Color = System.Drawing.Color; @@ -50,7 +50,9 @@ private static RenderMaterial TranslateMaterial(ModelItem geom) var itemProperties = itemCategory.Properties; var itemMaterial = itemProperties.FindPropertyByDisplayName("Material"); if (itemMaterial != null && !string.IsNullOrEmpty(itemMaterial.DisplayName)) + { materialName = itemMaterial.Value.ToDisplayString(); + } } var materialPropertyCategory = geom.PropertyCategories.FindCategoryByDisplayName("Material"); @@ -59,7 +61,9 @@ private static RenderMaterial TranslateMaterial(ModelItem geom) var material = materialPropertyCategory.Properties; var name = material.FindPropertyByDisplayName("Name"); if (name != null && !string.IsNullOrEmpty(name.DisplayName)) + { materialName = name.Value.ToDisplayString(); + } } var r = new RenderMaterial(1 - geom.Geometry.OriginalTransparency, 0, 1, renderColor, black) diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Properties.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Properties.cs index ee70909804..955507572f 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Properties.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Properties.cs @@ -19,7 +19,9 @@ private static Base GetPropertiesBase(ModelItem element) PropertyCategoryCollection userVisiblePropertyCategories = element.GetUserFilteredPropertyCategories(); foreach (PropertyCategory propertyCategory in userVisiblePropertyCategories) + { ProcessPropertyCategory(propertiesBase, propertyCategory); + } return propertiesBase; } @@ -27,7 +29,9 @@ private static Base GetPropertiesBase(ModelItem element) private static void ProcessPropertyCategory(DynamicBase propertiesBase, PropertyCategory propertyCategory) { if (IsCategoryToBeSkipped(propertyCategory)) + { return; + } DataPropertyCollection properties = propertyCategory.Properties; Base propertyCategoryBase = new(); @@ -35,7 +39,9 @@ private static void ProcessPropertyCategory(DynamicBase propertiesBase, Property properties.ToList().ForEach(property => BuildPropertyCategory(propertyCategory, property, propertyCategoryBase)); if (!propertyCategoryBase.GetMembers().Any() || propertyCategory.DisplayName == null) + { return; + } string propertyCategoryDisplayName = SanitizePropertyName(propertyCategory.DisplayName); string internalName = GetSanitizedPropertyName(propertyCategory.CombinedName.ToString()).Replace("LcOa", ""); @@ -67,7 +73,9 @@ Base propertyCategoryBase string internalName = GetSanitizedPropertyName(property.CombinedName.BaseName).Replace("LcOa", ""); if (propertyName == null) + { return; + } dynamic propertyValue = ConvertPropertyValue(property.Value); @@ -152,7 +160,9 @@ private static dynamic ConvertPropertyValue(VariantData value) private static void UpdatePropertyCategoryBase(Base propertyCategoryBase, string propertyName, dynamic propertyValue) { if (propertyValue == null) + { return; + } object keyPropValue = propertyCategoryBase[propertyName]; @@ -166,7 +176,9 @@ private static void UpdatePropertyCategoryBase(Base propertyCategoryBase, string List arrayPropValue = list; if (!arrayPropValue.Contains(propertyValue)) + { arrayPropValue.Add(propertyValue); + } propertyCategoryBase[propertyName] = arrayPropValue; break; @@ -198,7 +210,9 @@ private static void AddItemProperties(ModelItem element, Base @base) // If the node is a Model if (element.HasModel) + { ((Base)@base["properties"])["Model"] = GetModelProperties(element.Model); + } // Internal Properties AddInternalProperties(element, (Base)@base["properties"]); @@ -247,13 +261,24 @@ private static Base GetModelProperties(Model elementModel) }; if (elementModel.HasFrontVector) + { model["Front Vector"] = elementModel.FrontVector.ToString(); + } + if (elementModel.HasNorthVector) + { model["North Vector"] = elementModel.NorthVector.ToString(); + } + if (elementModel.HasRightVector) + { model["Right Vector"] = elementModel.RightVector.ToString(); + } + if (elementModel.HasUpVector) + { model["Up Vector"] = elementModel.UpVector.ToString(); + } return model; } diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Settings.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Settings.cs index 92eed3a210..bfc711393d 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Settings.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Settings.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using Autodesk.Navisworks.Api; @@ -20,16 +20,16 @@ public enum Transforms private const string ProxyOrigin = "Project Base Origin"; private const string BBoxOrigin = "Boundingbox Origin"; - private static Dictionary Settings { get; } = new(); - private static Vector2D ProjectBasePoint { get { if (!Settings.ContainsKey("x-coordinate") || !Settings.ContainsKey("y-coordinate")) + { return new Vector2D(0, 0); + } var x = Settings["x-coordinate"]; var y = Settings["y-coordinate"]; @@ -46,7 +46,10 @@ private static Transforms ModelTransform get { if (!Settings.ContainsKey("reference-point")) + { return Transforms.Default; + } + var value = Settings["reference-point"]; return value switch @@ -64,7 +67,10 @@ private static Units CoordinateUnits get { if (!Settings.ContainsKey("units")) + { return Units.Meters; + } + var value = Settings["units"]; return (Units)Enum.Parse(typeof(Units), value, true); @@ -76,7 +82,9 @@ private static bool UseInternalPropertyNames get { if (!Settings.ContainsKey("internal-property-names")) + { return false; + } var value = Settings["internal-property-names"]; diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.ToSpeckle.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.ToSpeckle.cs index 558b9aefea..43fa3e2a1a 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.ToSpeckle.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.ToSpeckle.cs @@ -80,7 +80,9 @@ public List ConvertToSpeckle(List objects) public bool CanConvertToSpeckle(object @object) { if (@object is ModelItem modelItem) + { return CanConvertToSpeckle(modelItem); + } return false; } @@ -97,9 +99,7 @@ private static SavedViewpoint ReferenceOrGuidToSavedViewpoint(string referenceOr { var parts = referenceOrGuid.Split(':'); using var savedItemReference = new SavedItemReference(parts[0], parts[1]); - savedViewpoint = parts.Length != 2 - ? null - : (SavedViewpoint)Doc.ResolveReference(savedItemReference); + savedViewpoint = parts.Length != 2 ? null : (SavedViewpoint)Doc.ResolveReference(savedItemReference); } return savedViewpoint; @@ -235,7 +235,9 @@ private static Base ViewpointToBase(SavedViewpoint savedViewpoint) private static Base ModelItemToSpeckle(ModelItem element) { if (IsElementHidden(element)) + { return null; + } var @base = ConvertModelItemToSpeckle(element); @@ -265,17 +267,23 @@ private static Base ModelItemToSpeckle(ModelItem element) // This really shouldn't exist, but is included for the what if arising from arbitrary IFCs if (!element.Children.Any()) + { return null; + } // Lookup ahead of time for wasted effort, collection is // invalid if it has no children, or no children through hiding if (element.Descendants.All(x => x.IsHidden)) + { return null; + } // After the fact empty Collection post traversal is also invalid // Emptiness by virtue of failure to convert for whatever reason if (!element.Children.Any(CanConvertToSpeckle)) + { return null; + } // ((Collection)@base).elements = elements; @@ -331,9 +339,7 @@ private static string GetCategoryDisplayName(DataProperty categoryProperty) /// A Speckle object. private static Base CreateSpeckleObject(ModelItem element, string categoryType) { - return element.HasGeometry - ? new GeometryNode() - : new Collection { collectionType = categoryType }; + return element.HasGeometry ? new GeometryNode() : new Collection { collectionType = categoryType }; } private static void GeometryToSpeckle(ModelItem element, Base @base) @@ -344,14 +350,18 @@ private static void GeometryToSpeckle(ModelItem element, Base @base) var fragmentGeometry = TranslateFragmentGeometry(geometry); if (fragmentGeometry != null && fragmentGeometry.Any()) + { @base["@displayValue"] = fragmentGeometry; + } } private static bool CanConvertToSpeckle(ModelItem item) { // Only Geometry no children if (!item.HasGeometry || item.Children.Any()) + { return true; + } const PrimitiveTypes allowedTypes = PrimitiveTypes.Lines | PrimitiveTypes.Triangles | PrimitiveTypes.SnapPoints | PrimitiveTypes.Text; @@ -371,10 +381,7 @@ private static ModelItem PointerToModelItem(object @string) pathArray = @string .ToString() .Split('-') - .Select( - x => int.TryParse(x, out var value) - ? value - : throw new FormatException("malformed path pseudoId")) + .Select(x => int.TryParse(x, out var value) ? value : throw new FormatException("malformed path pseudoId")) .ToArray(); } catch (FormatException) diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Types.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Types.cs index 4edb61a28b..b1a984c5ab 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Types.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Types.cs @@ -1,5 +1,5 @@ -using Speckle.Core.Models; +using Speckle.Core.Models; namespace Objects.Core.Models; -internal sealed class GeometryNode : Base {} +internal sealed class GeometryNode : Base { } diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Utilities.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Utilities.cs index cf4f5bc5b7..d8e34133d9 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Utilities.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.Utilities.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Runtime.CompilerServices; using Autodesk.Navisworks.Api; diff --git a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.cs b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.cs index b05c44a267..cf90205a41 100644 --- a/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.cs +++ b/Objects/Converters/ConverterNavisworks/ConverterNavisworks/ConverterNavisworks.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Autodesk.Navisworks.Api; using Speckle.Core.Kits; @@ -47,13 +47,19 @@ public IEnumerable GetServicedApplications() public void SetContextDocument(object doc) { if (doc != null && doc is not Document) + { throw new ArgumentException("Only Navisworks Document types are supported."); + } if (Doc == null && doc != null) + { Doc = (Document)doc; + } if (Doc == null && doc == null) + { Doc = Application.ActiveDocument; + } // This sets or resets the correct ElevationMode flag for model orientation. // Needs to be called every time a Send is initiated to reflect the options @@ -82,12 +88,20 @@ public void SetPreviousContextObjects(List objects) public void SetConverterSettings(object settings) { if (settings is not Dictionary newSettings) + { return; + } foreach (var key in newSettings.Keys) + { if (Settings.TryGetValue(key, out string _)) + { Settings[key] = newSettings[key]; + } else + { Settings.Add(key, newSettings[key]); + } + } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs index 59e741854c..cb51ab0a0f 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs @@ -12,171 +12,194 @@ using OSG = Objects.Structural.Geometry; using SHC = RevitSharedResources.Helpers.Categories; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +/// +/// Container of all pre-defined categories in Revit that incoming Base objects can be grouped under +/// +public class AllRevitCategories : IAllRevitCategories { - /// - /// Container of all pre-defined categories in Revit that incoming Base objects can be grouped under - /// - public class AllRevitCategories : IAllRevitCategories + private IRevitDocumentAggregateCache revitDocumentAggregateCache; + + public AllRevitCategories(IRevitDocumentAggregateCache revitDocumentAggregateCache) { - private IRevitDocumentAggregateCache revitDocumentAggregateCache; + this.revitDocumentAggregateCache = revitDocumentAggregateCache; + } + + #region IAllRevitCategories - public AllRevitCategories(IRevitDocumentAggregateCache revitDocumentAggregateCache) + public IRevitCategoryInfo GetRevitCategoryInfo(Base @base) + { + var elementType = GetRevitCategoryInfo(@base); + if (elementType != SHC.Undefined) { - this.revitDocumentAggregateCache = revitDocumentAggregateCache; + return elementType; } - #region IAllRevitCategories + var matchingType = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetAllObjects() + .Where(catInfo => catInfo.ElementTypeType == typeof(T) && catInfo.BuiltInCategories.Count == 0) + .FirstOrDefault(); - public IRevitCategoryInfo GetRevitCategoryInfo(Base @base) + if (matchingType != null) { - var elementType = GetRevitCategoryInfo(@base); - if (elementType != SHC.Undefined) return elementType; - - var matchingType = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetAllObjects() - .Where(catInfo => catInfo.ElementTypeType == typeof(T) - && catInfo.BuiltInCategories.Count == 0) - .FirstOrDefault(); - - if (matchingType != null) - { - return matchingType; - } + return matchingType; + } - var categoryInfo = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetOrAdd(typeof(T).Name, () => + var categoryInfo = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetOrAdd( + typeof(T).Name, + () => { return new RevitCategoryInfo(typeof(T).Name, null, typeof(T), new List()); - }, out _); + }, + out _ + ); - return categoryInfo; - } + return categoryInfo; + } - public IRevitCategoryInfo GetRevitCategoryInfo(Base @base) + public IRevitCategoryInfo GetRevitCategoryInfo(Base @base) + { + var categoryInfo = @base switch { - var categoryInfo = @base switch - { - BER.AdaptiveComponent _ => SHC.FamilyInstance, - BE.Beam _ => SHC.StructuralFraming, - BE.Brace _ => SHC.StructuralFraming, - BE.Column _ => SHC.Column, + BER.AdaptiveComponent _ => SHC.FamilyInstance, + BE.Beam _ => SHC.StructuralFraming, + BE.Brace _ => SHC.StructuralFraming, + BE.Column _ => SHC.Column, #if !REVIT2020 && !REVIT2021 - BE.Ceiling _ => SHC.Ceiling, + BE.Ceiling _ => SHC.Ceiling, #endif - BER.FamilyInstance _ => SHC.FamilyInstance, - BE.Floor _ => SHC.Floor, - BE.Roof _ => SHC.Roof, - BE.Wall _ => SHC.Wall, - BE.Duct _ => SHC.Duct, - BE.Pipe _ => SHC.Pipe, - BE.Wire _ => SHC.Wire, - BE.CableTray _ => SHC.CableTray, - BE.Conduit _ => SHC.Conduit, - BE.Revit.RevitRailing _ => SHC.Railing, - Other.Revit.RevitInstance _ => SHC.FamilyInstance, - OSG.Element1D e when e.type == OSG.ElementType1D.Beam => SHC.StructuralFraming, - OSG.Element1D e when e.type == OSG.ElementType1D.Brace => SHC.StructuralFraming, - OSG.Element1D e when e.type == OSG.ElementType1D.Column => SHC.Column, - OSG.Element2D => SHC.Floor, - _ => SHC.Undefined, - }; - - // family instance and undefined categories are very broad, so we can try to narrow those down - if (categoryInfo != SHC.FamilyInstance && categoryInfo != SHC.Undefined) - { - return categoryInfo; - } - - //2.16 onwards we check for "builtInCategory" - var instanceCategory = @base["builtInCategory"] as string; - //pre 2.16 we used the inconsistent, display value "category" - if (string.IsNullOrEmpty(instanceCategory)) - instanceCategory = @base["category"] as string; - - if (string.IsNullOrEmpty(instanceCategory)) - return categoryInfo; + BER.FamilyInstance _ => SHC.FamilyInstance, + BE.Floor _ => SHC.Floor, + BE.Roof _ => SHC.Roof, + BE.Wall _ => SHC.Wall, + BE.Duct _ => SHC.Duct, + BE.Pipe _ => SHC.Pipe, + BE.Wire _ => SHC.Wire, + BE.CableTray _ => SHC.CableTray, + BE.Conduit _ => SHC.Conduit, + BE.Revit.RevitRailing _ => SHC.Railing, + Other.Revit.RevitInstance _ => SHC.FamilyInstance, + OSG.Element1D e when e.type == OSG.ElementType1D.Beam => SHC.StructuralFraming, + OSG.Element1D e when e.type == OSG.ElementType1D.Brace => SHC.StructuralFraming, + OSG.Element1D e when e.type == OSG.ElementType1D.Column => SHC.Column, + OSG.Element2D => SHC.Floor, + _ => SHC.Undefined, + }; + + // family instance and undefined categories are very broad, so we can try to narrow those down + if (categoryInfo != SHC.FamilyInstance && categoryInfo != SHC.Undefined) + { + return categoryInfo; + } - var newCategoryInfo = GetRevitCategoryInfo(instanceCategory); + //2.16 onwards we check for "builtInCategory" + var instanceCategory = @base["builtInCategory"] as string; + //pre 2.16 we used the inconsistent, display value "category" + if (string.IsNullOrEmpty(instanceCategory)) + { + instanceCategory = @base["category"] as string; + } - if (newCategoryInfo != SHC.Undefined) return newCategoryInfo; + if (string.IsNullOrEmpty(instanceCategory)) + { return categoryInfo; } - public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName) + + var newCategoryInfo = GetRevitCategoryInfo(instanceCategory); + + if (newCategoryInfo != SHC.Undefined) { - var categoryInfo = GetCategoryInfoForObjectWithExactName(categoryName); - if (categoryInfo != null) return categoryInfo; + return newCategoryInfo; + } + return categoryInfo; + } - categoryName = CategoryNameFormatted(categoryName); - var revitCategoryInfoCache = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory(); + public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName) + { + var categoryInfo = GetCategoryInfoForObjectWithExactName(categoryName); + if (categoryInfo != null) + { + return categoryInfo; + } - categoryInfo = revitCategoryInfoCache - .TryGet(categoryName); - if (categoryInfo != null) return categoryInfo; + categoryName = CategoryNameFormatted(categoryName); + var revitCategoryInfoCache = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory(); + categoryInfo = revitCategoryInfoCache.TryGet(categoryName); + if (categoryInfo != null) + { + return categoryInfo; + } - foreach (var info in revitCategoryInfoCache.GetAllObjects()) + foreach (var info in revitCategoryInfoCache.GetAllObjects()) + { + if (categoryName.IndexOf(info.CategoryName, StringComparison.OrdinalIgnoreCase) >= 0) { - if (categoryName.IndexOf(info.CategoryName, StringComparison.OrdinalIgnoreCase) >= 0) + return info; + } + foreach (var alias in info.CategoryAliases) + { + if (categoryName.IndexOf(alias, StringComparison.OrdinalIgnoreCase) >= 0) { return info; } - foreach (var alias in info.CategoryAliases) - { - if (categoryName.IndexOf(alias, StringComparison.OrdinalIgnoreCase) >= 0) - { - return info; - } - } } - - return SHC.Undefined; } - #endregion + + return SHC.Undefined; + } + #endregion - private IRevitCategoryInfo? GetCategoryInfoForObjectWithExactName(string unformattedCatName) + private IRevitCategoryInfo? GetCategoryInfoForObjectWithExactName(string unformattedCatName) + { + var bic = BuiltInCategory.INVALID; + string formattedName = ""; + // 2.16 onwards we're passing the "builtInCategory" string + if (unformattedCatName.StartsWith("OST")) { - var bic = BuiltInCategory.INVALID; - string formattedName = ""; - // 2.16 onwards we're passing the "builtInCategory" string - if (unformattedCatName.StartsWith("OST")) + if (!Enum.TryParse(unformattedCatName, out bic)) { - if (!Enum.TryParse(unformattedCatName, out bic)) - { - return null; - } - formattedName = unformattedCatName.Replace("OST_", ""); + return null; } - // pre 2.16 we're passing the "category" string - else - { - var revitCat = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .TryGet(unformattedCatName); - - if (revitCat == null) return null; + formattedName = unformattedCatName.Replace("OST_", ""); + } + // pre 2.16 we're passing the "category" string + else + { + var revitCat = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .TryGet(unformattedCatName); - bic = Categories.GetBuiltInCategory(revitCat); - formattedName = CategoryNameFormatted(unformattedCatName); + if (revitCat == null) + { + return null; } - return revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetOrAdd(formattedName, () => + bic = Categories.GetBuiltInCategory(revitCat); + formattedName = CategoryNameFormatted(unformattedCatName); + } + + return revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetOrAdd( + formattedName, + () => { return new RevitCategoryInfo(formattedName, null, null, new List { bic }); - }, out _); - } + }, + out _ + ); + } - private static string CategoryNameFormatted(string name) - { - return name.Replace(" ", ""); - } + private static string CategoryNameFormatted(string name) + { + return name.Replace(" ", ""); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Categories.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Categories.cs index a9024b294d..711dd27dc1 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Categories.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Categories.cs @@ -5,54 +5,56 @@ using Objects.BuiltElements.Revit; using SCH = RevitSharedResources.Helpers.Categories; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public static class Categories { - public static class Categories + /// + /// Returns the corresponding based on a given built-in category name + /// + /// The name of the built-in category + /// The RevitCategory enum value that corresponds to the given name + public static RevitCategory GetSchemaBuilderCategoryFromBuiltIn(string builtInCategory) { - /// - /// Returns the corresponding based on a given built-in category name - /// - /// The name of the built-in category - /// The RevitCategory enum value that corresponds to the given name - public static RevitCategory GetSchemaBuilderCategoryFromBuiltIn(string builtInCategory) - { - // Clean up built-in name "OST_Walls" to be just "WALLS" - var cleanName = builtInCategory - .Replace("OST_IOS", "") //for OST_IOSModelGroups - .Replace("OST_MEP", "") //for OST_MEPSpaces - .Replace("OST_", "") //for any other OST_blablabla - .Replace("_", " "); - - var res = Enum.TryParse(cleanName, out RevitCategory cat); - if (!res) - throw new NotSupportedException($"Built-in category {builtInCategory} is not supported."); - return cat; - } + // Clean up built-in name "OST_Walls" to be just "WALLS" + var cleanName = builtInCategory + .Replace("OST_IOS", "") //for OST_IOSModelGroups + .Replace("OST_MEP", "") //for OST_MEPSpaces + .Replace("OST_", "") //for any other OST_blablabla + .Replace("_", " "); - /// - /// Returns the corresponding built-in category name from a specific - /// - /// The RevitCategory to convert - /// The name of the built-in category that corresponds to the input RevitCategory - public static string GetBuiltInFromSchemaBuilderCategory(RevitCategory c) + var res = Enum.TryParse(cleanName, out RevitCategory cat); + if (!res) { - var name = Enum.GetName(typeof(RevitCategory), c); - return $"OST_{name}"; + throw new NotSupportedException($"Built-in category {builtInCategory} is not supported."); } - public static string GetBuiltInFromSchemaBuilderCategory(RevitFamilyCategory c) - { - var name = Enum.GetName(typeof(RevitFamilyCategory), c); - return $"OST_{name}"; - } + return cat; + } - public static BuiltInCategory GetBuiltInCategory(Category category) - { + /// + /// Returns the corresponding built-in category name from a specific + /// + /// The RevitCategory to convert + /// The name of the built-in category that corresponds to the input RevitCategory + public static string GetBuiltInFromSchemaBuilderCategory(RevitCategory c) + { + var name = Enum.GetName(typeof(RevitCategory), c); + return $"OST_{name}"; + } + + public static string GetBuiltInFromSchemaBuilderCategory(RevitFamilyCategory c) + { + var name = Enum.GetName(typeof(RevitFamilyCategory), c); + return $"OST_{name}"; + } + + public static BuiltInCategory GetBuiltInCategory(Category category) + { #if REVIT2020 || REVIT2021 || REVIT2022 - return (BuiltInCategory)category.Id.IntegerValue; + return (BuiltInCategory)category.Id.IntegerValue; #else - return category.BuiltInCategory; + return category.BuiltInCategory; #endif - } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs index 4b4dd2cbca..6249ae63a9 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs @@ -22,1013 +22,1090 @@ using Parameter = Objects.BuiltElements.Revit.Parameter; using Point = Objects.Geometry.Point; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit + #region hosted elements + + private bool ShouldConvertHostedElement(DB.Element element, DB.Element host) { - #region hosted elements + //doesn't have a host, go ahead and convert + if (host == null) + { + return true; + } - private bool ShouldConvertHostedElement(DB.Element element, DB.Element host) + // has been converted before (from a parent host), skip it + if (ConvertedObjects.Contains(element.UniqueId)) { - //doesn't have a host, go ahead and convert - if (host == null) - return true; + return false; + } - // has been converted before (from a parent host), skip it - if (ConvertedObjects.Contains(element.UniqueId)) - { - return false; - } + // the parent is in our selection list,skip it, as this element will be converted by the host element + if (ContextObjects.ContainsKey(host.UniqueId)) + { + return false; + } + return true; + } - // the parent is in our selection list,skip it, as this element will be converted by the host element - if (ContextObjects.ContainsKey(host.UniqueId)) - { - return false; - } + private bool ShouldConvertHostedElement(DB.Element element, DB.Element host, Base extraProps) + { + // doesn't have a host that will convert the element, go ahead and do it now + if (host == null || host is DB.Level) + { return true; } - private bool ShouldConvertHostedElement(DB.Element element, DB.Element host, Base extraProps) + // has been converted before (from a parent host), skip it + if (ConvertedObjects.Contains(element.UniqueId)) { - // doesn't have a host that will convert the element, go ahead and do it now - if (host == null || host is DB.Level) - return true; - - // has been converted before (from a parent host), skip it - if (ConvertedObjects.Contains(element.UniqueId)) - return false; + return false; + } - // the parent is in our selection list,skip it, as this element will be converted by the host element - if (ContextObjects.ContainsKey(host.UniqueId)) + // the parent is in our selection list,skip it, as this element will be converted by the host element + if (ContextObjects.ContainsKey(host.UniqueId)) + { + // there are certain elements in Revit that can be a host to another element + // yet not know it. + var hostedElementIds = GetHostedElementIds(host); + var elementId = element.Id; + if (!hostedElementIds.Contains(elementId)) { - // there are certain elements in Revit that can be a host to another element - // yet not know it. - var hostedElementIds = GetHostedElementIds(host); - var elementId = element.Id; - if (!hostedElementIds.Contains(elementId)) + extraProps["speckleHost"] = new Base() { - extraProps["speckleHost"] = new Base() - { - applicationId = host.UniqueId, - ["category"] = host.Category.Name, - ["builtInCategory"] = Categories.GetBuiltInCategory(host.Category) - }; - } - else - return false; + applicationId = host.UniqueId, + ["category"] = host.Category.Name, + ["builtInCategory"] = Categories.GetBuiltInCategory(host.Category) + }; + } + else + { + return false; } - return true; } + return true; + } - /// - /// Gets the hosted element of a host and adds the to a Base object - /// - /// - /// - public void GetHostedElements(Base @base, Element host, out List notes) - { - notes = new List(); - var hostedElementIds = GetHostedElementIds(host); - - if (!hostedElementIds.Any()) - return; + /// + /// Gets the hosted element of a host and adds the to a Base object + /// + /// + /// + public void GetHostedElements(Base @base, Element host, out List notes) + { + notes = new List(); + var hostedElementIds = GetHostedElementIds(host); - if (ContextObjects.ContainsKey(host.UniqueId)) - { - ContextObjects.Remove(host.UniqueId); - } - GetHostedElementsFromIds(@base, host, hostedElementIds, out notes); + if (!hostedElementIds.Any()) + { + return; } - public void GetHostedElementsFromIds( - Base @base, - Element host, - IList hostedElementIds, - out List notes - ) + if (ContextObjects.ContainsKey(host.UniqueId)) { - notes = new List(); - var convertedHostedElements = new List(); + ContextObjects.Remove(host.UniqueId); + } + GetHostedElementsFromIds(@base, host, hostedElementIds, out notes); + } + + public void GetHostedElementsFromIds( + Base @base, + Element host, + IList hostedElementIds, + out List notes + ) + { + notes = new List(); + var convertedHostedElements = new List(); - foreach (var elemId in hostedElementIds) + foreach (var elemId in hostedElementIds) + { + var element = host.Document.GetElement(elemId); + if (!ContextObjects.ContainsKey(element.UniqueId)) { - var element = host.Document.GetElement(elemId); - if (!ContextObjects.ContainsKey(element.UniqueId)) - { - continue; - } + continue; + } - var reportObj = Report.ReportObjects.TryGetValue(element.UniqueId, out ApplicationObject value) - ? value - : new ApplicationObject(element.UniqueId, element.GetType().ToString()); + var reportObj = Report.ReportObjects.TryGetValue(element.UniqueId, out ApplicationObject value) + ? value + : new ApplicationObject(element.UniqueId, element.GetType().ToString()); - if (CanConvertToSpeckle(element)) + if (CanConvertToSpeckle(element)) + { + try { - try + var obj = ConvertToSpeckle(element); + if (obj != null) { - var obj = ConvertToSpeckle(element); - if (obj != null) - { - ContextObjects.Remove(element.UniqueId); - reportObj.Update( - status: ApplicationObject.State.Created, - logItem: $"Attached as hosted element to {host.UniqueId}" - ); - convertedHostedElements.Add(obj); - ConvertedObjects.Add(obj.applicationId); - } - else - { - reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); - } + ContextObjects.Remove(element.UniqueId); + reportObj.Update( + status: ApplicationObject.State.Created, + logItem: $"Attached as hosted element to {host.UniqueId}" + ); + convertedHostedElements.Add(obj); + ConvertedObjects.Add(obj.applicationId); } - catch (Exception ex) + else { - SpeckleLog.Logger.Error(ex, ex.Message); - reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion threw exception: {ex}"); + reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); } } - else + catch (Exception ex) { - reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"Conversion not supported"); + SpeckleLog.Logger.Error(ex, ex.Message); + reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion threw exception: {ex}"); } - Report.Log(reportObj); } - - if (convertedHostedElements.Any()) + else { - notes.Add($"Converted and attached {convertedHostedElements.Count} hosted elements"); - - if (@base.GetDetachedProp("elements") is List elements) - { - elements.AddRange(convertedHostedElements); - } - else - { - @base.SetDetachedProp("elements", convertedHostedElements); - } + reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"Conversion not supported"); } + Report.Log(reportObj); } - public IList GetHostedElementIds(Element host) + if (convertedHostedElements.Any()) { - IList ids = null; - if (host is HostObject hostObject) + notes.Add($"Converted and attached {convertedHostedElements.Count} hosted elements"); + + if (@base.GetDetachedProp("elements") is List elements) { - ids = hostObject.FindInserts(true, false, false, false); + elements.AddRange(convertedHostedElements); } else { - var typeFilter = new ElementIsElementTypeFilter(true); - var categoryFilter = new ElementMulticategoryFilter( - new List() - { - BuiltInCategory.OST_CLines, - BuiltInCategory.OST_SketchLines, - BuiltInCategory.OST_WeakDims - }, - true - ); - ids = host.GetDependentElements(new LogicalAndFilter(typeFilter, categoryFilter)); + @base.SetDetachedProp("elements", convertedHostedElements); } - - // dont include host elementId - ids.Remove(host.Id); - - return ids; } + } - #endregion - - #region parameters - - #region ToSpeckle - /// - /// Adds Instance and Type parameters, ElementId, ApplicationInternalName and Units. - /// - /// - /// - /// List of BuiltInParameters or GUIDs used to indicate what parameters NOT to get, - /// we exclude all params already defined on the top level object to avoid duplication and - /// potential conflicts when setting them back on the element - public void GetAllRevitParamsAndIds(Base speckleElement, DB.Element revitElement, List exclusions = null) + public IList GetHostedElementIds(Element host) + { + IList ids = null; + if (host is HostObject hostObject) { - var allParams = new Dictionary(); - AddElementParamsToDict(revitElement, allParams, false, exclusions); - - var elementType = revitElement.Document.GetElement(revitElement.GetTypeId()); - AddElementParamsToDict( - speckleElement is Level ? null : elementType, //ignore type props of levels..! - allParams, - true, - exclusions + ids = hostObject.FindInserts(true, false, false, false); + } + else + { + var typeFilter = new ElementIsElementTypeFilter(true); + var categoryFilter = new ElementMulticategoryFilter( + new List() + { + BuiltInCategory.OST_CLines, + BuiltInCategory.OST_SketchLines, + BuiltInCategory.OST_WeakDims + }, + true ); + ids = host.GetDependentElements(new LogicalAndFilter(typeFilter, categoryFilter)); + } - Base paramBase = new(); - //sort by key - foreach (var kv in allParams.OrderBy(x => x.Key)) - { - try - { - paramBase[kv.Key] = kv.Value; - } - catch - { - //ignore - } - } + // dont include host elementId + ids.Remove(host.Id); - if (paramBase.GetDynamicMembers().Any()) - speckleElement["parameters"] = paramBase; - speckleElement["elementId"] = revitElement.Id.ToString(); - speckleElement.applicationId = revitElement.UniqueId; - speckleElement["units"] = ModelUnits; - speckleElement["isRevitLinkedModel"] = revitElement.Document.IsLinked; - speckleElement["revitLinkedModelPath"] = revitElement.Document.PathName; - - Phase phaseCreated = Doc.GetElement(revitElement.CreatedPhaseId) as Phase; - if (phaseCreated != null) - speckleElement["phaseCreated"] = phaseCreated.Name; - - Phase phaseDemolished = Doc.GetElement(revitElement.DemolishedPhaseId) as Phase; - if (phaseDemolished != null) - speckleElement["phaseDemolished"] = phaseDemolished.Name; - - speckleElement["worksetId"] = revitElement.WorksetId.ToString(); - - // assign the category if it is null - // WARN: DirectShapes have a `category` prop of type `RevitCategory` (enum), NOT `string`. This is the only exception as of 2.16. - // In all other cases this should be the display value string (localized name) of the catogory - // If the null check is removed, the DirectShape case needs to be handled. - var category = revitElement.Category; - if (speckleElement["category"] is null && category is not null) - { - speckleElement["category"] = category.Name; - } - // from 2.16 onward we're also passing the full BuiltInCategory for better handling on receive - //TODO: move this to a typed property, define full list of categories in Objects - BuiltInCategory builtInCategory = Categories.GetBuiltInCategory(category); - speckleElement["builtInCategory"] = builtInCategory.ToString(); + return ids; + } + + #endregion + + #region parameters - //NOTE: adds the quantities of all materials to an element + #region ToSpeckle + /// + /// Adds Instance and Type parameters, ElementId, ApplicationInternalName and Units. + /// + /// + /// + /// List of BuiltInParameters or GUIDs used to indicate what parameters NOT to get, + /// we exclude all params already defined on the top level object to avoid duplication and + /// potential conflicts when setting them back on the element + public void GetAllRevitParamsAndIds(Base speckleElement, DB.Element revitElement, List exclusions = null) + { + var allParams = new Dictionary(); + AddElementParamsToDict(revitElement, allParams, false, exclusions); + + var elementType = revitElement.Document.GetElement(revitElement.GetTypeId()); + AddElementParamsToDict( + speckleElement is Level ? null : elementType, //ignore type props of levels..! + allParams, + true, + exclusions + ); + + Base paramBase = new(); + //sort by key + foreach (var kv in allParams.OrderBy(x => x.Key)) + { try { - speckleElement["materialQuantities"] = MaterialQuantitiesToSpeckle( - revitElement, - speckleElement["units"] as string)? - .ToList(); + paramBase[kv.Key] = kv.Value; } - catch (Autodesk.Revit.Exceptions.ApplicationException ex) + catch { - SpeckleLog.Logger.Error(ex, "An exception occurred in the Revit API while retrieving material quantities from element of type {elementType} and category {elementCategory}", revitElement.GetType(), revitElement.Category); + //ignore } } - private void AddElementParamsToDict( - DB.Element element, - Dictionary paramDict, - bool isTypeParameter = false, - List exclusions = null - ) + if (paramBase.GetDynamicMembers().Any()) { - if (element == null) - return; + speckleElement["parameters"] = paramBase; + } - exclusions ??= new(); - using var parameters = element.Parameters; - foreach (DB.Parameter param in parameters) - { - var internalName = GetParamInternalName(param); - if (paramDict.ContainsKey(internalName) || exclusions.Contains(internalName)) - { - continue; - } + speckleElement["elementId"] = revitElement.Id.ToString(); + speckleElement.applicationId = revitElement.UniqueId; + speckleElement["units"] = ModelUnits; + speckleElement["isRevitLinkedModel"] = revitElement.Document.IsLinked; + speckleElement["revitLinkedModelPath"] = revitElement.Document.PathName; - var speckleParam = ParameterToSpeckle(param, internalName, isTypeParameter); - paramDict[internalName] = speckleParam; - } + Phase phaseCreated = Doc.GetElement(revitElement.CreatedPhaseId) as Phase; + if (phaseCreated != null) + { + speckleElement["phaseCreated"] = phaseCreated.Name; } - /// - /// Returns the value of a Revit Built-In given a target and - /// - /// The containing the Built-In - /// The enum name of the target parameter - /// The units in which to return the value in the case where you want to override the Built-In 's units - /// - /// - public static T GetParamValue(DB.Element elem, BuiltInParameter bip, string unitsOverride = null) + Phase phaseDemolished = Doc.GetElement(revitElement.DemolishedPhaseId) as Phase; + if (phaseDemolished != null) { - var rp = elem.get_Parameter(bip); + speckleElement["phaseDemolished"] = phaseDemolished.Name; + } - if (rp == null || !rp.HasValue) - return default; + speckleElement["worksetId"] = revitElement.WorksetId.ToString(); - var value = rp.GetValue(rp.Definition, unitsOverride); - if (typeof(T) == typeof(int) && value.GetType() == typeof(bool)) - return (T)Convert.ChangeType(value, typeof(int)); + // assign the category if it is null + // WARN: DirectShapes have a `category` prop of type `RevitCategory` (enum), NOT `string`. This is the only exception as of 2.16. + // In all other cases this should be the display value string (localized name) of the catogory + // If the null check is removed, the DirectShape case needs to be handled. + var category = revitElement.Category; + if (speckleElement["category"] is null && category is not null) + { + speckleElement["category"] = category.Name; + } + // from 2.16 onward we're also passing the full BuiltInCategory for better handling on receive + //TODO: move this to a typed property, define full list of categories in Objects + BuiltInCategory builtInCategory = Categories.GetBuiltInCategory(category); + speckleElement["builtInCategory"] = builtInCategory.ToString(); - return (T)value; + //NOTE: adds the quantities of all materials to an element + try + { + speckleElement["materialQuantities"] = MaterialQuantitiesToSpeckle( + revitElement, + speckleElement["units"] as string + ) + ?.ToList(); + } + catch (Autodesk.Revit.Exceptions.ApplicationException ex) + { + SpeckleLog.Logger.Error( + ex, + "An exception occurred in the Revit API while retrieving material quantities from element of type {elementType} and category {elementCategory}", + revitElement.GetType(), + revitElement.Category + ); + } + } + + private void AddElementParamsToDict( + DB.Element element, + Dictionary paramDict, + bool isTypeParameter = false, + List exclusions = null + ) + { + if (element == null) + { + return; + } + + exclusions ??= new(); + using var parameters = element.Parameters; + foreach (DB.Parameter param in parameters) + { + var internalName = GetParamInternalName(param); + if (paramDict.ContainsKey(internalName) || exclusions.Contains(internalName)) + { + continue; + } + + var speckleParam = ParameterToSpeckle(param, internalName, isTypeParameter); + paramDict[internalName] = speckleParam; + } + } + + /// + /// Returns the value of a Revit Built-In given a target and + /// + /// The containing the Built-In + /// The enum name of the target parameter + /// The units in which to return the value in the case where you want to override the Built-In 's units + /// + /// + public static T GetParamValue(DB.Element elem, BuiltInParameter bip, string unitsOverride = null) + { + var rp = elem.get_Parameter(bip); + + if (rp == null || !rp.HasValue) + { + return default; } - /// - /// Converts a Revit Built-In to a Speckle . - /// - /// The Revit Built-In to convert - /// Defaults to false. True if this is a type parameter - /// The units in which to return the value in the case where you want to override the Built-In 's units - /// - private Parameter ParameterToSpeckle( - DB.Parameter rp, - string paramInternalName, - bool isTypeParameter = false, - string unitsOverride = null - ) + var value = rp.GetValue(rp.Definition, unitsOverride); + if (typeof(T) == typeof(int) && value.GetType() == typeof(bool)) { + return (T)Convert.ChangeType(value, typeof(int)); + } + + return (T)value; + } + + /// + /// Converts a Revit Built-In to a Speckle . + /// + /// The Revit Built-In to convert + /// Defaults to false. True if this is a type parameter + /// The units in which to return the value in the case where you want to override the Built-In 's units + /// + private Parameter ParameterToSpeckle( + DB.Parameter rp, + string paramInternalName, + bool isTypeParameter = false, + string unitsOverride = null + ) + { #if REVIT2020 - DisplayUnitType unitTypeId = default; + DisplayUnitType unitTypeId = default; #else - ForgeTypeId unitTypeId = null; + ForgeTypeId unitTypeId = null; #endif - // The parameter definitions are cached using the ParameterToSpeckleData struct - // This is done because in the case of type and instance parameter there is lots of redundant data that needs to be extracted from the Revit DB - // Caching noticeably speeds up the send process - // TODO : could add some generic getOrAdd overloads to avoid creating closures - var paramData = revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType(out _) - .GetOrAdd( - paramInternalName, - () => + // The parameter definitions are cached using the ParameterToSpeckleData struct + // This is done because in the case of type and instance parameter there is lots of redundant data that needs to be extracted from the Revit DB + // Caching noticeably speeds up the send process + // TODO : could add some generic getOrAdd overloads to avoid creating closures + var paramData = revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType(out _) + .GetOrAdd( + paramInternalName, + () => + { + var definition = rp.Definition; + var newParamData = new ParameterToSpeckleData() { - var definition = rp.Definition; - var newParamData = new ParameterToSpeckleData() - { - Definition = definition, - InternalName = paramInternalName, - IsReadOnly = rp.IsReadOnly, - IsShared = rp.IsShared, - IsTypeParameter = isTypeParameter, - Name = definition.Name, - UnitType = definition.GetUnityTypeString(), - }; - if (rp.StorageType == StorageType.Double) - { - unitTypeId = rp.GetUnitTypeId(); - newParamData.UnitsSymbol = GetSymbolUnit(rp, definition, unitTypeId); - newParamData.ApplicationUnits = - unitsOverride != null ? UnitsToNative(unitsOverride).ToUniqueString() : unitTypeId.ToUniqueString(); - } - return newParamData; - }, - out _ - ); - - return paramData.GetParameterObjectWithValue(rp.GetValue(paramData.Definition, unitTypeId)); - } + Definition = definition, + InternalName = paramInternalName, + IsReadOnly = rp.IsReadOnly, + IsShared = rp.IsShared, + IsTypeParameter = isTypeParameter, + Name = definition.Name, + UnitType = definition.GetUnityTypeString(), + }; + if (rp.StorageType == StorageType.Double) + { + unitTypeId = rp.GetUnitTypeId(); + newParamData.UnitsSymbol = GetSymbolUnit(rp, definition, unitTypeId); + newParamData.ApplicationUnits = + unitsOverride != null ? UnitsToNative(unitsOverride).ToUniqueString() : unitTypeId.ToUniqueString(); + } + return newParamData; + }, + out _ + ); - #endregion + return paramData.GetParameterObjectWithValue(rp.GetValue(paramData.Definition, unitTypeId)); + } - /// - /// Method for getting symbol when parameter is NOT validated to be a double or int - /// - /// - /// - /// - /// - /// - public string GetSymbolUnit(DB.Parameter parameter, DB.Definition definition, + #endregion + + /// + /// Method for getting symbol when parameter is NOT validated to be a double or int + /// + /// + /// + /// + /// + /// + public string GetSymbolUnit(DB.Parameter parameter, DB.Definition definition, #if REVIT2020 - DisplayUnitType unitTypeId + DisplayUnitType unitTypeId #else - ForgeTypeId unitTypeId + ForgeTypeId unitTypeId #endif - ) + ) + { + if (parameter.StorageType != StorageType.Double) { - if (parameter.StorageType != StorageType.Double) - { - return null; - } + return null; + } - return revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType(out _) - .GetOrAdd(unitTypeId.ToUniqueString(), () => unitTypeId.GetSymbol(), out _); - } - - /// - /// - /// - /// - public void SetInstanceParameters(Element revitElement, Base speckleElement, List exclusions = null) - { - if (revitElement == null) - return; - - var speckleParameters = speckleElement["parameters"] as Base; - if (speckleParameters == null || speckleParameters.GetDynamicMemberNames().Count() == 0) - return; - - // Set the phaseCreated parameter - if (speckleElement["phaseCreated"] is string phaseCreated && !string.IsNullOrEmpty(phaseCreated)) - TrySetParam(revitElement, BuiltInParameter.PHASE_CREATED, GetRevitPhase(revitElement.Document, phaseCreated)); - //Set the phaseDemolished parameter - if (speckleElement["phaseDemolished"] is string phaseDemolished && !string.IsNullOrEmpty(phaseDemolished)) - TrySetParam( - revitElement, - BuiltInParameter.PHASE_DEMOLISHED, - GetRevitPhase(revitElement.Document, phaseDemolished) - ); + return revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType(out _) + .GetOrAdd(unitTypeId.ToUniqueString(), () => unitTypeId.GetSymbol(), out _); + } - // NOTE: we are using the ParametersMap here and not Parameters, as it's a much smaller list of stuff and - // Parameters most likely contains extra (garbage) stuff that we don't need to set anyways - // so it's a much faster conversion. If we find that's not the case, we might need to change it in the future - IEnumerable revitParameters = null; - if (exclusions == null) - revitParameters = revitElement.ParametersMap.Cast().Where(x => x != null && !x.IsReadOnly); - else - revitParameters = revitElement.ParametersMap - .Cast() - .Where(x => x != null && !x.IsReadOnly && !exclusions.Contains(GetParamInternalName(x))); - - // Here we are creating two dictionaries for faster lookup - // one uses the BuiltInName / GUID the other the name as Key - // we need both to support parameter set by Schema Builder, that might be generated with one or the other - // Also, custom parameters that are not Shared, will have an INVALID BuiltInParameter name and no GUID, then we need to use their name - var revitParameterById = revitParameters.ToDictionary(x => GetParamInternalName(x), x => x); - var revitParameterByName = revitParameters.ToDictionary(x => x.Definition.Name, x => x); - - // speckleParameters is a Base - // its member names will have for Key either a BuiltInName, GUID or Name of the parameter (depending onwhere it comes from) - // and as value the full Parameter object, that might come from Revit or SchemaBuilder - // We only loop params we can set and that actually exist on the revit element - var filteredSpeckleParameters = speckleParameters - .GetMembers() - .Where(x => revitParameterById.ContainsKey(x.Key) || revitParameterByName.ContainsKey(x.Key)); - - foreach (var spk in filteredSpeckleParameters) - { - if (!(spk.Value is Parameter sp) || sp.isReadOnly || sp.value == null) - continue; + /// + /// + /// + /// + public void SetInstanceParameters(Element revitElement, Base speckleElement, List exclusions = null) + { + if (revitElement == null) + { + return; + } - var rp = revitParameterById.ContainsKey(spk.Key) ? revitParameterById[spk.Key] : revitParameterByName[spk.Key]; + var speckleParameters = speckleElement["parameters"] as Base; + if (speckleParameters == null || speckleParameters.GetDynamicMemberNames().Count() == 0) + { + return; + } - TrySetParam(rp, sp.value, sp.units, sp.applicationUnit); - } + // Set the phaseCreated parameter + if (speckleElement["phaseCreated"] is string phaseCreated && !string.IsNullOrEmpty(phaseCreated)) + { + TrySetParam(revitElement, BuiltInParameter.PHASE_CREATED, GetRevitPhase(revitElement.Document, phaseCreated)); } - private void TrySetParam(DB.Parameter rp, object value, string units = "", string applicationUnit = "") + //Set the phaseDemolished parameter + if (speckleElement["phaseDemolished"] is string phaseDemolished && !string.IsNullOrEmpty(phaseDemolished)) { - try + TrySetParam( + revitElement, + BuiltInParameter.PHASE_DEMOLISHED, + GetRevitPhase(revitElement.Document, phaseDemolished) + ); + } + + // NOTE: we are using the ParametersMap here and not Parameters, as it's a much smaller list of stuff and + // Parameters most likely contains extra (garbage) stuff that we don't need to set anyways + // so it's a much faster conversion. If we find that's not the case, we might need to change it in the future + IEnumerable revitParameters = null; + if (exclusions == null) + { + revitParameters = revitElement.ParametersMap.Cast().Where(x => x != null && !x.IsReadOnly); + } + else + { + revitParameters = revitElement.ParametersMap + .Cast() + .Where(x => x != null && !x.IsReadOnly && !exclusions.Contains(GetParamInternalName(x))); + } + + // Here we are creating two dictionaries for faster lookup + // one uses the BuiltInName / GUID the other the name as Key + // we need both to support parameter set by Schema Builder, that might be generated with one or the other + // Also, custom parameters that are not Shared, will have an INVALID BuiltInParameter name and no GUID, then we need to use their name + var revitParameterById = revitParameters.ToDictionary(x => GetParamInternalName(x), x => x); + var revitParameterByName = revitParameters.ToDictionary(x => x.Definition.Name, x => x); + + // speckleParameters is a Base + // its member names will have for Key either a BuiltInName, GUID or Name of the parameter (depending onwhere it comes from) + // and as value the full Parameter object, that might come from Revit or SchemaBuilder + // We only loop params we can set and that actually exist on the revit element + var filteredSpeckleParameters = speckleParameters + .GetMembers() + .Where(x => revitParameterById.ContainsKey(x.Key) || revitParameterByName.ContainsKey(x.Key)); + + foreach (var spk in filteredSpeckleParameters) + { + if (!(spk.Value is Parameter sp) || sp.isReadOnly || sp.value == null) { - switch (rp.StorageType) - { - case StorageType.Double: - // This is meant for parameters that come from Revit - // as they might use a lot more unit types that Speckle doesn't currently support - if (!string.IsNullOrEmpty(applicationUnit)) - { - var val = RevitVersionHelper.ConvertToInternalUnits(value, applicationUnit); - rp.Set(val); - } - // the following two cases are for parameters comimg form schema builder - // they do not have applicationUnit but just units - // units are automatically set but the user can override them - // users might set them to "none" so that we convert them by using the Revit destination parameter display units - // this is needed to correctly receive non lenght based parameters (eg air flow) - else if (units == Speckle.Core.Kits.Units.None) - { - var val = RevitVersionHelper.ConvertToInternalUnits(Convert.ToDouble(value), rp); - rp.Set(val); - } - else if (TryGetUnitsFromString(units, out string formattedUnits)) - { - double val = ScaleToNative(Convert.ToDouble(value), formattedUnits); - rp.Set(val); - } - else - { - rp.Set(Convert.ToDouble(value)); - } - break; + continue; + } - case StorageType.Integer: - if (value is string s) - { - if (s.ToLower() == "no") - { - value = 0; - } - else if (s.ToLower() == "yes") - { - value = 1; - } - } - rp.Set(Convert.ToInt32(value)); - break; + var rp = revitParameterById.ContainsKey(spk.Key) ? revitParameterById[spk.Key] : revitParameterByName[spk.Key]; - case StorageType.String: - if (rp.Definition.Name.ToLower().Contains("name")) + TrySetParam(rp, sp.value, sp.units, sp.applicationUnit); + } + } + + private void TrySetParam(DB.Parameter rp, object value, string units = "", string applicationUnit = "") + { + try + { + switch (rp.StorageType) + { + case StorageType.Double: + // This is meant for parameters that come from Revit + // as they might use a lot more unit types that Speckle doesn't currently support + if (!string.IsNullOrEmpty(applicationUnit)) + { + var val = RevitVersionHelper.ConvertToInternalUnits(value, applicationUnit); + rp.Set(val); + } + // the following two cases are for parameters comimg form schema builder + // they do not have applicationUnit but just units + // units are automatically set but the user can override them + // users might set them to "none" so that we convert them by using the Revit destination parameter display units + // this is needed to correctly receive non lenght based parameters (eg air flow) + else if (units == Speckle.Core.Kits.Units.None) + { + var val = RevitVersionHelper.ConvertToInternalUnits(Convert.ToDouble(value), rp); + rp.Set(val); + } + else if (TryGetUnitsFromString(units, out string formattedUnits)) + { + double val = ScaleToNative(Convert.ToDouble(value), formattedUnits); + rp.Set(val); + } + else + { + rp.Set(Convert.ToDouble(value)); + } + break; + + case StorageType.Integer: + if (value is string s) + { + if (s.ToLower() == "no") { - var temp = Regex.Replace(Convert.ToString(value), "[^0-9a-zA-Z ]+", ""); - Report.Log($@"Invalid characters in param name '{rp.Definition.Name}': Renamed to '{temp}'"); - rp.Set(temp); + value = 0; } - else + else if (s.ToLower() == "yes") { - rp.Set(Convert.ToString(value)); + value = 1; } - break; - default: - break; - } - } - catch - { - // do nothing for now... + } + rp.Set(Convert.ToInt32(value)); + break; + + case StorageType.String: + if (rp.Definition.Name.ToLower().Contains("name")) + { + var temp = Regex.Replace(Convert.ToString(value), "[^0-9a-zA-Z ]+", ""); + Report.Log($@"Invalid characters in param name '{rp.Definition.Name}': Renamed to '{temp}'"); + rp.Set(temp); + } + else + { + rp.Set(Convert.ToString(value)); + } + break; + default: + break; } } - - //Shared parameters use a GUID to be uniquely identified - //Other parameters use a BuiltInParameter enum - private static string GetParamInternalName(DB.Parameter rp) + catch { - if (rp.IsShared) - return rp.GUID.ToString(); - else - { - var def = rp.Definition as InternalDefinition; - if (def.BuiltInParameter == BuiltInParameter.INVALID) - return def.Name; - return def.BuiltInParameter.ToString(); - } + // do nothing for now... } + } - private void TrySetParam(DB.Element elem, BuiltInParameter bip, DB.Element value) + //Shared parameters use a GUID to be uniquely identified + //Other parameters use a BuiltInParameter enum + private static string GetParamInternalName(DB.Parameter rp) + { + if (rp.IsShared) + { + return rp.GUID.ToString(); + } + else { - var param = elem.get_Parameter(bip); - if (param != null && value != null && !param.IsReadOnly) + var def = rp.Definition as InternalDefinition; + if (def.BuiltInParameter == BuiltInParameter.INVALID) { - param.Set(value.Id); + return def.Name; } + + return def.BuiltInParameter.ToString(); } + } - private void TrySetParam(DB.Element elem, BuiltInParameter bip, bool value) + private void TrySetParam(DB.Element elem, BuiltInParameter bip, DB.Element value) + { + var param = elem.get_Parameter(bip); + if (param != null && value != null && !param.IsReadOnly) { - var param = elem.get_Parameter(bip); - if (param != null && !param.IsReadOnly) - { - param.Set(value ? 1 : 0); - } + param.Set(value.Id); } + } - private void TrySetParam(DB.Element elem, BuiltInParameter bip, object value, string units = "") + private void TrySetParam(DB.Element elem, BuiltInParameter bip, bool value) + { + var param = elem.get_Parameter(bip); + if (param != null && !param.IsReadOnly) { - var param = elem.get_Parameter(bip); - if (param == null || param.IsReadOnly) - { - return; - } + param.Set(value ? 1 : 0); + } + } - TrySetParam(param, value, units); + private void TrySetParam(DB.Element elem, BuiltInParameter bip, object value, string units = "") + { + var param = elem.get_Parameter(bip); + if (param == null || param.IsReadOnly) + { + return; } - /// - /// Queries a Revit Document for phases by the given name. - /// - /// - /// The name of the Phase - /// the phase which has the same name. null if none or multiple phases were found. - private Phase GetRevitPhase(DB.Document document, string phaseName) + TrySetParam(param, value, units); + } + + /// + /// Queries a Revit Document for phases by the given name. + /// + /// + /// The name of the Phase + /// the phase which has the same name. null if none or multiple phases were found. + private Phase GetRevitPhase(DB.Document document, string phaseName) + { + // cache the phases if we haven't already done so + if (Phases.Count == 0) { - // cache the phases if we haven't already done so - if (Phases.Count == 0) + var phases = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_Phases).ToList(); + foreach (var phase in phases) { - var phases = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_Phases).ToList(); - foreach (var phase in phases) - { - Phases[phase.Name] = phase as Phase; - } + Phases[phase.Name] = phase as Phase; } - if (Phases.ContainsKey(phaseName)) - return Phases[phaseName]; - - return null; + } + if (Phases.ContainsKey(phaseName)) + { + return Phases[phaseName]; } -#endregion + return null; + } - #region conversion "edit existing if possible" utilities + #endregion - /// - /// Returns, if found, the corresponding doc element. - /// The doc object can be null if the user deleted it. - /// - /// Id of the application that originally created the element, in Revit it's the UniqueId - /// The element, if found, otherwise null - public DB.Element? GetExistingElementByApplicationId(string applicationId) + #region conversion "edit existing if possible" utilities + + /// + /// Returns, if found, the corresponding doc element. + /// The doc object can be null if the user deleted it. + /// + /// Id of the application that originally created the element, in Revit it's the UniqueId + /// The element, if found, otherwise null + public DB.Element? GetExistingElementByApplicationId(string applicationId) + { + if (applicationId == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) { - if (applicationId == null || ReceiveMode == Speckle.Core.Kits.ReceiveMode.Create) - return null; + return null; + } - var cachedIds = PreviouslyReceivedObjectIds?.GetCreatedIdsFromConvertedId(applicationId); - // TODO: we may not want just the first one - return cachedIds == null ? null : Doc.GetElement(cachedIds.First()); + var cachedIds = PreviouslyReceivedObjectIds?.GetCreatedIdsFromConvertedId(applicationId); + // TODO: we may not want just the first one + return cachedIds == null ? null : Doc.GetElement(cachedIds.First()); + } + + public IEnumerable GetExistingElementsByApplicationId(string applicationId) + { + if (applicationId == null || ReceiveMode == ReceiveMode.Create) + { + yield break; } - public IEnumerable GetExistingElementsByApplicationId(string applicationId) + var cachedIds = PreviouslyReceivedObjectIds?.GetCreatedIdsFromConvertedId(applicationId); + if (cachedIds == null) { - if (applicationId == null || ReceiveMode == ReceiveMode.Create) - yield break; + yield break; + } - var cachedIds = PreviouslyReceivedObjectIds?.GetCreatedIdsFromConvertedId(applicationId); - if (cachedIds == null) - yield break; - foreach (var id in cachedIds) - yield return Doc.GetElement(id); + foreach (var id in cachedIds) + { + yield return Doc.GetElement(id); } + } - /// - /// Returns true if element is not null and the user-selected receive mode is set to "ignore" - /// - /// Existing document element - /// - /// The updated appObj if method returns true, the original appObj if false - /// - public bool IsIgnore(Element docObj, ApplicationObject appObj) + /// + /// Returns true if element is not null and the user-selected receive mode is set to "ignore" + /// + /// Existing document element + /// + /// The updated appObj if method returns true, the original appObj if false + /// + public bool IsIgnore(Element docObj, ApplicationObject appObj) + { + if (docObj != null) { - if (docObj != null) + if (ReceiveMode == ReceiveMode.Ignore) { - if (ReceiveMode == ReceiveMode.Ignore) - { - appObj.Update( - status: ApplicationObject.State.Skipped, - createdId: docObj.UniqueId, - convertedItem: docObj, - logItem: $"ApplicationId already exists in document, new object ignored." - ); - return true; - } - else if (docObj.Pinned) - { - appObj.Update( - status: ApplicationObject.State.Skipped, - createdId: docObj.UniqueId, - convertedItem: docObj, - logItem: "Element is pinned and cannot be updated" - ); - return true; - } + appObj.Update( + status: ApplicationObject.State.Skipped, + createdId: docObj.UniqueId, + convertedItem: docObj, + logItem: $"ApplicationId already exists in document, new object ignored." + ); + return true; + } + else if (docObj.Pinned) + { + appObj.Update( + status: ApplicationObject.State.Skipped, + createdId: docObj.UniqueId, + convertedItem: docObj, + logItem: "Element is pinned and cannot be updated" + ); + return true; } - return false; } - #endregion + return false; + } + #endregion - #region Reference Point + #region Reference Point - // CAUTION: these strings need to have the same values as in the connector bindings - const string InternalOrigin = "Internal Origin (default)"; - const string ProjectBase = "Project Base"; - const string Survey = "Survey"; + // CAUTION: these strings need to have the same values as in the connector bindings + const string InternalOrigin = "Internal Origin (default)"; + const string ProjectBase = "Project Base"; + const string Survey = "Survey"; - //cached during conversion - private List _revitLinkInstances = null; - private List RevitLinkInstances + //cached during conversion + private List _revitLinkInstances = null; + private List RevitLinkInstances + { + get { - get + if (_revitLinkInstances == null) { - if (_revitLinkInstances == null) - _revitLinkInstances = new FilteredElementCollector(Doc) - .OfClass(typeof(RevitLinkInstance)) - .ToElements() - .Cast() - .ToList(); - - return _revitLinkInstances; + _revitLinkInstances = new FilteredElementCollector(Doc) + .OfClass(typeof(RevitLinkInstance)) + .ToElements() + .Cast() + .ToList(); } + + return _revitLinkInstances; } + } + + private Dictionary _docTransforms = new(); - private Dictionary _docTransforms = new Dictionary(); + private DB.Transform GetDocReferencePointTransform(Document doc) + { + //linked files are always saved to disc and will have a path name + //if the current doc is unsaved it will not, but then it'll be the only one :) + var id = doc.PathName; - private DB.Transform GetDocReferencePointTransform(Document doc) + if (!_docTransforms.ContainsKey(id)) { - //linked files are always saved to disc and will have a path name - //if the current doc is unsaved it will not, but then it'll be the only one :) - var id = doc.PathName; + // get from settings + var referencePointSetting = Settings.ContainsKey("reference-point") ? Settings["reference-point"] : string.Empty; + _docTransforms[id] = GetReferencePointTransform(referencePointSetting, doc); + } - if (!_docTransforms.ContainsKey(id)) - { - // get from settings - var referencePointSetting = Settings.ContainsKey("reference-point") - ? Settings["reference-point"] - : string.Empty; - _docTransforms[id] = GetReferencePointTransform(referencePointSetting, doc); - } + return _docTransforms[id]; + } - return _docTransforms[id]; + //////////////////////////////////////////////// + /// NOTE + //////////////////////////////////////////////// + /// The BasePoint shared properties in Revit are based off of the survey point. + /// The BasePoint non-shared properties are based off of the internal origin. + /// Also, survey point does NOT have an rotation parameter. + //////////////////////////////////////////////// + private DB.Transform GetReferencePointTransform(string type, Document doc) + { + // first get the main doc base points and reference setting transform + var referencePointTransform = DB.Transform.Identity; + var points = new FilteredElementCollector(Doc).OfClass(typeof(BasePoint)).Cast().ToList(); + var projectPoint = points.FirstOrDefault(o => o.IsShared == false); + var surveyPoint = points.FirstOrDefault(o => o.IsShared == true); + switch (type) + { + case ProjectBase: // note that the project base (ui) rotation is registered on the survey pt, not on the base point + referencePointTransform = DB.Transform.CreateTranslation(projectPoint.Position); + break; + case Survey: + // note that the project base (ui) rotation is registered on the survey pt, not on the base point + // retrieve the survey point rotation from the project point + var angle = projectPoint.get_Parameter(BuiltInParameter.BASEPOINT_ANGLETON_PARAM)?.AsDouble() ?? 0; + referencePointTransform = DB.Transform + .CreateTranslation(surveyPoint.Position) + .Multiply(DB.Transform.CreateRotation(XYZ.BasisZ, angle)); + break; + case InternalOrigin: + break; } - //////////////////////////////////////////////// - /// NOTE - //////////////////////////////////////////////// - /// The BasePoint shared properties in Revit are based off of the survey point. - /// The BasePoint non-shared properties are based off of the internal origin. - /// Also, survey point does NOT have an rotation parameter. - //////////////////////////////////////////////// - private DB.Transform GetReferencePointTransform(string type, Document doc) + // Second, if this is a linked doc get the transform and adjust + if (doc.IsLinked) { - // first get the main doc base points and reference setting transform - var referencePointTransform = DB.Transform.Identity; - var points = new FilteredElementCollector(Doc).OfClass(typeof(BasePoint)).Cast().ToList(); - var projectPoint = points.FirstOrDefault(o => o.IsShared == false); - var surveyPoint = points.FirstOrDefault(o => o.IsShared == true); - switch (type) + // get the linked doc instance transform + var instance = RevitLinkInstances.FirstOrDefault(x => x?.GetLinkDocument()?.PathName == doc.PathName); + if (instance != null) { - case ProjectBase: // note that the project base (ui) rotation is registered on the survey pt, not on the base point - referencePointTransform = DB.Transform.CreateTranslation(projectPoint.Position); - break; - case Survey: - // note that the project base (ui) rotation is registered on the survey pt, not on the base point - // retrieve the survey point rotation from the project point - var angle = projectPoint.get_Parameter(BuiltInParameter.BASEPOINT_ANGLETON_PARAM)?.AsDouble() ?? 0; - referencePointTransform = DB.Transform - .CreateTranslation(surveyPoint.Position) - .Multiply(DB.Transform.CreateRotation(XYZ.BasisZ, angle)); - break; - case InternalOrigin: - break; + var linkInstanceTransform = instance.GetTotalTransform(); + referencePointTransform = linkInstanceTransform.Inverse.Multiply(referencePointTransform); } + } - // Second, if this is a linked doc get the transform and adjust - if (doc.IsLinked) - { - // get the linked doc instance transform - var instance = RevitLinkInstances.FirstOrDefault(x => x?.GetLinkDocument()?.PathName == doc.PathName); - if (instance != null) - { - var linkInstanceTransform = instance.GetTotalTransform(); - referencePointTransform = linkInstanceTransform.Inverse.Multiply(referencePointTransform); - } - } + return referencePointTransform; + } - return referencePointTransform; - } + /// + /// For exporting out of Revit, moves and rotates a point according to this document BasePoint + /// + /// + /// + public XYZ ToExternalCoordinates(XYZ p, bool isPoint, Document doc) + { + var rpt = GetDocReferencePointTransform(doc); + return (isPoint) ? rpt.Inverse.OfPoint(p) : rpt.Inverse.OfVector(p); + } + + /// + /// For importing in Revit, moves and rotates a point according to this document BasePoint + /// + /// + /// + public XYZ ToInternalCoordinates(XYZ p, bool isPoint) + { + var rpt = GetDocReferencePointTransform(Doc); + return (isPoint) ? rpt.OfPoint(p) : rpt.OfVector(p); + } + #endregion - /// - /// For exporting out of Revit, moves and rotates a point according to this document BasePoint - /// - /// - /// - public XYZ ToExternalCoordinates(XYZ p, bool isPoint, Document doc) + #region Floor/ceiling/roof openings + + //a floor/roof/ceiling outline can have "voids/holes" for 3 reasons: + // - there is a shaft cutting through it > we don't need to create an opening (the shaft will be created on its own) + // - there is a vertical opening cutting through it > we don't need to create an opening (the opening will be created on its own) + // - the floor profile was modeled with holes > we need to create an openeing as the Revit API doesn't let us generate it with holes! + private void CreateVoids(DB.Element host, Base speckleElement) + { + if (speckleElement["voids"] == null || !(speckleElement["voids"] is List)) { - var rpt = GetDocReferencePointTransform(doc); - return (isPoint) ? rpt.Inverse.OfPoint(p) : rpt.Inverse.OfVector(p); + return; } - /// - /// For importing in Revit, moves and rotates a point according to this document BasePoint - /// - /// - /// - public XYZ ToInternalCoordinates(XYZ p, bool isPoint) + //list of openings hosted in this speckle element + var openings = new List(); + //we used to use "elements" but have now switched to "@elements" + //this extra check is for backwards compatibility + var nestedElements = @speckleElement["elements"] ?? @speckleElement["@elements"]; + if (nestedElements is List elements) { - var rpt = GetDocReferencePointTransform(Doc); - return (isPoint) ? rpt.OfPoint(p) : rpt.OfVector(p); + openings.AddRange(elements.Where(x => x is RevitVerticalOpening).Cast()); } - #endregion - #region Floor/ceiling/roof openings + //list of shafts part of this conversion set + var shafts = ContextObjects.Values + .SelectMany(x => x.Converted.Where(y => y is RevitShaft).Cast()) + .ToList(); - //a floor/roof/ceiling outline can have "voids/holes" for 3 reasons: - // - there is a shaft cutting through it > we don't need to create an opening (the shaft will be created on its own) - // - there is a vertical opening cutting through it > we don't need to create an opening (the opening will be created on its own) - // - the floor profile was modeled with holes > we need to create an openeing as the Revit API doesn't let us generate it with holes! - private void CreateVoids(DB.Element host, Base speckleElement) - { - if (speckleElement["voids"] == null || !(speckleElement["voids"] is List)) - return; - - //list of openings hosted in this speckle element - var openings = new List(); - //we used to use "elements" but have now switched to "@elements" - //this extra check is for backwards compatibility - var nestedElements = @speckleElement["elements"] ?? @speckleElement["@elements"]; - if (nestedElements is List elements) - openings.AddRange(elements.Where(x => x is RevitVerticalOpening).Cast()); + openings.AddRange(shafts); - //list of shafts part of this conversion set - var shafts = ContextObjects.Values - .SelectMany(x => x.Converted.Where(y => y is RevitShaft).Cast()) - .ToList(); + foreach (var @void in speckleElement["voids"] as List) + { + if (HasOverlappingOpening(@void, openings)) + { + continue; + } - openings.AddRange(shafts); + var curveArray = CurveToNative(@void, true); + UnboundCurveIfSingle(curveArray); + Doc.Create.NewOpening(host, curveArray, false); + } + } - foreach (var @void in speckleElement["voids"] as List) + private bool HasOverlappingOpening(ICurve @void, List openings) + { + foreach (RevitOpening opening in openings) + { + if (CurvesOverlap(@void, opening.outline)) { - if (HasOverlappingOpening(@void, openings)) - continue; - - var curveArray = CurveToNative(@void, true); - UnboundCurveIfSingle(curveArray); - Doc.Create.NewOpening(host, curveArray, false); + return true; } } - private bool HasOverlappingOpening(ICurve @void, List openings) - { - foreach (RevitOpening opening in openings) - if (CurvesOverlap(@void, opening.outline)) - return true; + return false; + } - return false; - } + private bool CurvesOverlap(ICurve icurveA, ICurve icurveB) + { + var curveArrayA = CurveToNative(icurveA).Cast().ToList(); + var curveArrayB = CurveToNative(icurveB).Cast().ToList(); - private bool CurvesOverlap(ICurve icurveA, ICurve icurveB) + //we need to account for various scenarios, eg a shaft might be made of multiple shapes + //while the resulting cut in the floor will only be made on a single shape, so we need to cross check them all + foreach (var curveA in curveArrayA) { - var curveArrayA = CurveToNative(icurveA).Cast().ToList(); - var curveArrayB = CurveToNative(icurveB).Cast().ToList(); + //move curves to Z = 0, needed for shafts! + curveA.MakeBound(0, 1); + var z = curveA.GetEndPoint(0).Z; + var cA = curveA.CreateTransformed(DB.Transform.CreateTranslation(new XYZ(0, 0, -z))); - //we need to account for various scenarios, eg a shaft might be made of multiple shapes - //while the resulting cut in the floor will only be made on a single shape, so we need to cross check them all - foreach (var curveA in curveArrayA) + foreach (var curveB in curveArrayB) { //move curves to Z = 0, needed for shafts! - curveA.MakeBound(0, 1); - var z = curveA.GetEndPoint(0).Z; - var cA = curveA.CreateTransformed(DB.Transform.CreateTranslation(new XYZ(0, 0, -z))); + curveB.MakeBound(0, 1); + z = curveB.GetEndPoint(0).Z; + var cB = curveB.CreateTransformed(DB.Transform.CreateTranslation(new XYZ(0, 0, -z))); - foreach (var curveB in curveArrayB) + var result = cA.Intersect(cB); + if (result != SetComparisonResult.BothEmpty && result != SetComparisonResult.Disjoint) { - //move curves to Z = 0, needed for shafts! - curveB.MakeBound(0, 1); - z = curveB.GetEndPoint(0).Z; - var cB = curveB.CreateTransformed(DB.Transform.CreateTranslation(new XYZ(0, 0, -z))); - - var result = cA.Intersect(cB); - if (result != SetComparisonResult.BothEmpty && result != SetComparisonResult.Disjoint) - return true; + return true; } } - - return false; } - #endregion - - #region misc + return false; + } - public string GetTemplatePath(string templateName) - { - var directoryPath = Path.Combine( - SpecklePathProvider.ObjectsFolderPath, - "Templates", - "Revit", - RevitVersionHelper.Version - ); - string templatePath = ""; - switch (Doc.DisplayUnitSystem) - { - case DisplayUnit.IMPERIAL: - templatePath = Path.Combine(directoryPath, $"{templateName} - Imperial.rft"); - break; - case DisplayUnit.METRIC: - templatePath = Path.Combine(directoryPath, $"{templateName} - Metric.rft"); - break; - } + #endregion - return templatePath; - } + #region misc - public IEnumerable<(string, Element, Connector)> GetRevitConnectorsThatConnectToSpeckleConnector( - RevitMEPConnector revitMEPConnector, - IConvertedObjectsCache receivedObjectsCache - ) + public string GetTemplatePath(string templateName) + { + var directoryPath = Path.Combine( + SpecklePathProvider.ObjectsFolderPath, + "Templates", + "Revit", + RevitVersionHelper.Version + ); + string templatePath = ""; + switch (Doc.DisplayUnitSystem) { - var origin = PointToNative(revitMEPConnector.origin); - - foreach (var connectedId in revitMEPConnector.connectedConnectorIds) - { - var connectorAppId = connectedId.Split('.').First(); - var convertedElement = receivedObjectsCache.GetCreatedObjectsFromConvertedId(connectorAppId).FirstOrDefault(); + case DisplayUnit.IMPERIAL: + templatePath = Path.Combine(directoryPath, $"{templateName} - Imperial.rft"); + break; + case DisplayUnit.METRIC: + templatePath = Path.Combine(directoryPath, $"{templateName} - Metric.rft"); + break; + } - var existingRevitConnector = convertedElement - ?.GetConnectorSet() - .Where(c => c.Origin.DistanceTo(origin) < .01) - .FirstOrDefault(); + return templatePath; + } - yield return (connectorAppId, convertedElement, existingRevitConnector); - } - } + public IEnumerable<(string, Element, Connector)> GetRevitConnectorsThatConnectToSpeckleConnector( + RevitMEPConnector revitMEPConnector, + IConvertedObjectsCache receivedObjectsCache + ) + { + var origin = PointToNative(revitMEPConnector.origin); - public void CreateSystemConnections( - IEnumerable revitMEPConnectors, - Element revitEl, - IConvertedObjectsCache receivedObjectsCache - ) + foreach (var connectedId in revitMEPConnector.connectedConnectorIds) { - foreach (var speckleConnector in revitMEPConnectors) - { - var origin = PointToNative(speckleConnector.origin); - var newRevitConnector = revitEl - .GetConnectorSet() - .Where(c => c.Origin.DistanceTo(origin) < .01) - .FirstOrDefault(); + var connectorAppId = connectedId.Split('.').First(); + var convertedElement = receivedObjectsCache.GetCreatedObjectsFromConvertedId(connectorAppId).FirstOrDefault(); - if (newRevitConnector == null) - continue; + var existingRevitConnector = convertedElement + ?.GetConnectorSet() + .Where(c => c.Origin.DistanceTo(origin) < .01) + .FirstOrDefault(); - foreach ( - var (elementAppId, element, existingConnector) in GetRevitConnectorsThatConnectToSpeckleConnector( - speckleConnector, - receivedObjectsCache - ) - ) - { - existingConnector?.ConnectTo(newRevitConnector); - } - } + yield return (connectorAppId, convertedElement, existingRevitConnector); } + } - public T TryInSubtransaction(Func func, Action catchFunc) + public void CreateSystemConnections( + IEnumerable revitMEPConnectors, + Element revitEl, + IConvertedObjectsCache receivedObjectsCache + ) + { + foreach (var speckleConnector in revitMEPConnectors) { - using var subtransaction = new SubTransaction(Doc); - subtransaction.Start(); + var origin = PointToNative(speckleConnector.origin); + var newRevitConnector = revitEl.GetConnectorSet().Where(c => c.Origin.DistanceTo(origin) < .01).FirstOrDefault(); - T returnValue = default; - try + if (newRevitConnector == null) { - returnValue = func(); - subtransaction.Commit(); + continue; } - catch (Exception ex) + + foreach ( + var (elementAppId, element, existingConnector) in GetRevitConnectorsThatConnectToSpeckleConnector( + speckleConnector, + receivedObjectsCache + ) + ) { - subtransaction.RollBack(); - Doc.Regenerate(); - catchFunc(ex); + existingConnector?.ConnectTo(newRevitConnector); } - return returnValue; } - #endregion + } + + public T TryInSubtransaction(Func func, Action catchFunc) + { + using var subtransaction = new SubTransaction(Doc); + subtransaction.Start(); + + T returnValue = default; + try + { + returnValue = func(); + subtransaction.Commit(); + } + catch (Exception ex) + { + subtransaction.RollBack(); + Doc.Regenerate(); + catchFunc(ex); + } + return returnValue; + } + #endregion - private List GetProfiles(DB.SpatialElement room) + private List GetProfiles(DB.SpatialElement room) + { + var profiles = new List(); + var boundaries = room.GetBoundarySegments(new SpatialElementBoundaryOptions()); + foreach (var loop in boundaries) { - var profiles = new List(); - var boundaries = room.GetBoundarySegments(new SpatialElementBoundaryOptions()); - foreach (var loop in boundaries) + var poly = new Polycurve(ModelUnits); + foreach (var segment in loop) { - var poly = new Polycurve(ModelUnits); - foreach (var segment in loop) - { - var c = segment.GetCurve(); + var c = segment.GetCurve(); - if (c == null) - continue; + if (c == null) + { + continue; + } - var curve = CurveToSpeckle(c, room.Document); + var curve = CurveToSpeckle(c, room.Document); - ((Base)curve)["elementId"] = segment.ElementId.ToString(); + ((Base)curve)["elementId"] = segment.ElementId.ToString(); - poly.segments.Add(curve); - } - profiles.Add(poly); + poly.segments.Add(curve); } - return profiles; + profiles.Add(poly); } + return profiles; + } - public WallLocationLine GetWallLocationLine(LocationLine location) + public WallLocationLine GetWallLocationLine(LocationLine location) + { + switch (location) { - switch (location) - { - case LocationLine.Centerline: - return WallLocationLine.WallCenterline; - case LocationLine.Exterior: - return WallLocationLine.FinishFaceExterior; - case LocationLine.Interior: - return WallLocationLine.FinishFaceInterior; - default: - return WallLocationLine.FinishFaceInterior; - } + case LocationLine.Centerline: + return WallLocationLine.WallCenterline; + case LocationLine.Exterior: + return WallLocationLine.FinishFaceExterior; + case LocationLine.Interior: + return WallLocationLine.FinishFaceInterior; + default: + return WallLocationLine.FinishFaceInterior; } + } - #region materials - public RenderMaterial GetElementRenderMaterial(DB.Element element) + #region materials + public RenderMaterial GetElementRenderMaterial(DB.Element element) + { + var matId = element?.GetMaterialIds(false)?.FirstOrDefault(); + + if (matId == null) { - var matId = element?.GetMaterialIds(false)?.FirstOrDefault(); + // TODO: Fallback to display color or something? + return null; + } - if (matId == null) - { - // TODO: Fallback to display color or something? - return null; - } + var revitMaterial = element.Document.GetElement(matId) as DB.Material; + return RenderMaterialToSpeckle(revitMaterial); + } - var revitMaterial = element.Document.GetElement(matId) as DB.Material; - return RenderMaterialToSpeckle(revitMaterial); + public static RenderMaterial RenderMaterialToSpeckle(DB.Material revitMaterial) + { + if (revitMaterial == null) + { + return null; } - public static RenderMaterial RenderMaterialToSpeckle(DB.Material revitMaterial) - { - if (revitMaterial == null) - return null; - RenderMaterial material = new RenderMaterial() + RenderMaterial material = + new() { name = revitMaterial.Name, opacity = 1 - (revitMaterial.Transparency / 100d), @@ -1039,280 +1116,299 @@ public static RenderMaterial RenderMaterialToSpeckle(DB.Material revitMaterial) .ToArgb() }; - return material; - } + return material; + } - public ElementId RenderMaterialToNative(RenderMaterial speckleMaterial) + public ElementId RenderMaterialToNative(RenderMaterial speckleMaterial) + { + if (speckleMaterial == null) { - if (speckleMaterial == null) - return ElementId.InvalidElementId; + return ElementId.InvalidElementId; + } - string matName = RemoveProhibitedCharacters(speckleMaterial.name); + string matName = RemoveProhibitedCharacters(speckleMaterial.name); - // Try and find an existing material - var existing = new FilteredElementCollector(Doc) - .OfClass(typeof(DB.Material)) - .Cast() - .FirstOrDefault(m => string.Equals(m.Name, matName, StringComparison.CurrentCultureIgnoreCase)); + // Try and find an existing material + var existing = new FilteredElementCollector(Doc) + .OfClass(typeof(DB.Material)) + .Cast() + .FirstOrDefault(m => string.Equals(m.Name, matName, StringComparison.CurrentCultureIgnoreCase)); - if (existing != null) - return existing.Id; + if (existing != null) + { + return existing.Id; + } - // Create new material - ElementId materialId = DB.Material.Create(Doc, matName ?? Guid.NewGuid().ToString()); - DB.Material mat = Doc.GetElement(materialId) as DB.Material; + // Create new material + ElementId materialId = DB.Material.Create(Doc, matName ?? Guid.NewGuid().ToString()); + DB.Material mat = Doc.GetElement(materialId) as DB.Material; - var sysColor = System.Drawing.Color.FromArgb(speckleMaterial.diffuse); - mat.Color = new DB.Color(sysColor.R, sysColor.G, sysColor.B); - mat.Transparency = (int)((1d - speckleMaterial.opacity) * 100d); + var sysColor = System.Drawing.Color.FromArgb(speckleMaterial.diffuse); + mat.Color = new DB.Color(sysColor.R, sysColor.G, sysColor.B); + mat.Transparency = (int)((1d - speckleMaterial.opacity) * 100d); - return materialId; - } + return materialId; + } + + /// + /// Retrieves the material from assigned system type for mep elements + /// + /// Revit element to parse + /// + public static RenderMaterial GetMEPSystemMaterial(Element e) + { + DB.Material material = GetMEPSystemRevitMaterial(e); + return material != null ? RenderMaterialToSpeckle(material) : null; + } + + /// + /// Retrieves the revit material from assigned system type for mep elements + /// + /// Revit element to parse + /// Revit material of the element, null if no material found + public static DB.Material? GetMEPSystemRevitMaterial(Element e) + { + ElementId idType = ElementId.InvalidElementId; - /// - /// Retrieves the material from assigned system type for mep elements - /// - /// Revit element to parse - /// - public static RenderMaterial GetMEPSystemMaterial(Element e) + if (e is DB.MEPCurve dt) { - DB.Material material = GetMEPSystemRevitMaterial(e); - return material != null ? RenderMaterialToSpeckle(material) : null; + var system = dt.MEPSystem; + if (system != null) + { + idType = system.GetTypeId(); + } } - - /// - /// Retrieves the revit material from assigned system type for mep elements - /// - /// Revit element to parse - /// Revit material of the element, null if no material found - public static DB.Material? GetMEPSystemRevitMaterial(Element e) + else if (e.GetConnectorManager() is ConnectorManager connectorManager) { - ElementId idType = ElementId.InvalidElementId; - - if (e is DB.MEPCurve dt) + //retrieve the first material from first connector. Could go wrong, but better than nothing ;-) + foreach (Connector item in connectorManager.Connectors) { - var system = dt.MEPSystem; + var system = item.MEPSystem; if (system != null) { idType = system.GetTypeId(); + break; } } - else if (e.GetConnectorManager() is ConnectorManager connectorManager) - { - //retrieve the first material from first connector. Could go wrong, but better than nothing ;-) - foreach (Connector item in connectorManager.Connectors) - { - var system = item.MEPSystem; - if (system != null) - { - idType = system.GetTypeId(); - break; - } - } - } - - if (idType == ElementId.InvalidElementId) - return null; - - if (e.Document.GetElement(idType) is MEPSystemType mechType) - { - return e.Document.GetElement(mechType.MaterialId) as DB.Material; - } + } + if (idType == ElementId.InvalidElementId) + { return null; } - #endregion - - - /// - /// Checks if a Speckle is too sort to be created in Revit. - /// - /// - /// The length of the line will be computed on the spot to ensure it is accurate. - /// - /// The to be tested. - /// true if the line is too short, false otherwise. - public bool IsLineTooShort(Line line) + if (e.Document.GetElement(idType) is MEPSystemType mechType) { - var scaleToNative = ScaleToNative(Point.Distance(line.start, line.end), line.units); - return scaleToNative < Doc.Application.ShortCurveTolerance; + return e.Document.GetElement(mechType.MaterialId) as DB.Material; } - /// - /// Attempts to append a Speckle onto a Revit . - /// This method ensures the line is long enough to be supported. - /// It will also convert the line to Revit before appending it to the . - /// - /// The revit to add the line to. - /// The to be added. - /// True if the line was added, false otherwise. - public bool TryAppendLineSafely(CurveArray curveArray, Line line, ApplicationObject appObj) + return null; + } + + #endregion + + + /// + /// Checks if a Speckle is too sort to be created in Revit. + /// + /// + /// The length of the line will be computed on the spot to ensure it is accurate. + /// + /// The to be tested. + /// true if the line is too short, false otherwise. + public bool IsLineTooShort(Line line) + { + var scaleToNative = ScaleToNative(Point.Distance(line.start, line.end), line.units); + return scaleToNative < Doc.Application.ShortCurveTolerance; + } + + /// + /// Attempts to append a Speckle onto a Revit . + /// This method ensures the line is long enough to be supported. + /// It will also convert the line to Revit before appending it to the . + /// + /// The revit to add the line to. + /// The to be added. + /// True if the line was added, false otherwise. + public bool TryAppendLineSafely(CurveArray curveArray, Line line, ApplicationObject appObj) + { + if (IsLineTooShort(line)) { - if (IsLineTooShort(line)) - { - appObj.Log.Add( - "Some lines in the CurveArray where ignored due to being smaller than the allowed curve length." - ); - return false; - } - try - { - curveArray.Append(LineToNative(line)); - return true; - } - catch (Exception e) - { - appObj.Log.Add(e.Message); - return false; - } + appObj.Log.Add("Some lines in the CurveArray where ignored due to being smaller than the allowed curve length."); + return false; } - - public bool UnboundCurveIfSingle(DB.CurveArray array) + try { - if (array.Size != 1) - return false; - var item = array.get_Item(0); - if (!item.IsBound) - return false; - item.MakeUnbound(); + curveArray.Append(LineToNative(line)); return true; } - - public bool IsCurveClosed(DB.Curve nativeCurve, double tol = 1E-6) + catch (Exception e) { - var endPoint = nativeCurve.GetEndPoint(0); - var source = nativeCurve.GetEndPoint(1); - var distanceTo = endPoint.DistanceTo(source); - return distanceTo < tol; + appObj.Log.Add(e.Message); + return false; } + } - public (DB.Curve, DB.Curve) SplitCurveInTwoHalves(DB.Curve nativeCurve) + public bool UnboundCurveIfSingle(DB.CurveArray array) + { + if (array.Size != 1) { - var curveArray = new CurveArray(); - // Revit does not like single curve loop edges, so we split them in two. - var start = nativeCurve.GetEndParameter(0); - var end = nativeCurve.GetEndParameter(1); - var mid = start + ((end - start) / 2); - - var a = nativeCurve.Clone(); - a.MakeBound(start, mid); - curveArray.Append(a); - var b = nativeCurve.Clone(); - b.MakeBound(mid, end); - curveArray.Append(b); - - return (a, b); + return false; } - public class FallbackToDxfException : Exception + var item = array.get_Item(0); + if (!item.IsBound) { - public FallbackToDxfException(string message) - : base(message) { } - - public FallbackToDxfException(string message, Exception innerException) - : base(message, innerException) { } + return false; } - public ApplicationObject CheckForExistingObject(Base @base) - { - @base.applicationId ??= @base.id; + item.MakeUnbound(); + return true; + } + + public bool IsCurveClosed(DB.Curve nativeCurve, double tol = 1E-6) + { + var endPoint = nativeCurve.GetEndPoint(0); + var source = nativeCurve.GetEndPoint(1); + var distanceTo = endPoint.DistanceTo(source); + return distanceTo < tol; + } - var docObj = GetExistingElementByApplicationId(@base.applicationId); - var appObj = new ApplicationObject(@base.id, @base.speckle_type) { applicationId = @base.applicationId }; + public (DB.Curve, DB.Curve) SplitCurveInTwoHalves(DB.Curve nativeCurve) + { + var curveArray = new CurveArray(); + // Revit does not like single curve loop edges, so we split them in two. + var start = nativeCurve.GetEndParameter(0); + var end = nativeCurve.GetEndParameter(1); + var mid = start + ((end - start) / 2); + + var a = nativeCurve.Clone(); + a.MakeBound(start, mid); + curveArray.Append(a); + var b = nativeCurve.Clone(); + b.MakeBound(mid, end); + curveArray.Append(b); + + return (a, b); + } - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; + public class FallbackToDxfException : Exception + { + public FallbackToDxfException(string message) + : base(message) { } - // otherwise just create new one - if (docObj != null) - Doc.Delete(docObj.Id); + public FallbackToDxfException(string message, Exception innerException) + : base(message, innerException) { } + } - return null; + public ApplicationObject CheckForExistingObject(Base @base) + { + @base.applicationId ??= @base.id; + + var docObj = GetExistingElementByApplicationId(@base.applicationId); + var appObj = new ApplicationObject(@base.id, @base.speckle_type) { applicationId = @base.applicationId }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; } - private string RemoveProhibitedCharacters(string s) + // otherwise just create new one + if (docObj != null) { - if (string.IsNullOrEmpty(s)) - return s; - return Regex.Replace(s, "[\\[\\]{}|;<>?`~]", ""); + Doc.Delete(docObj.Id); } - public static ModelLine GetSlopeArrow(Element element) + return null; + } + + private string RemoveProhibitedCharacters(string s) + { + if (string.IsNullOrEmpty(s)) { - IList elementIds = null; + return s; + } + + return Regex.Replace(s, "[\\[\\]{}|;<>?`~]", ""); + } + + public static ModelLine GetSlopeArrow(Element element) + { + IList elementIds = null; #if !REVIT2020 && !REVIT2021 - if (element is DB.Floor floor) - { - elementIds = ((Sketch)floor.Document.GetElement(floor.SketchId)).GetAllElements(); - } + if (element is DB.Floor floor) + { + elementIds = ((Sketch)floor.Document.GetElement(floor.SketchId)).GetAllElements(); + } #endif - if (elementIds == null) + if (elementIds == null) + { + using var modelLineFilter = new ElementCategoryFilter(BuiltInCategory.OST_SketchLines); + elementIds = element.GetDependentElements(modelLineFilter); + } + + foreach (var elementId in elementIds) + { + if (element.Document.GetElement(elementId) is not ModelLine line) { - using var modelLineFilter = new ElementCategoryFilter(BuiltInCategory.OST_SketchLines); - elementIds = element.GetDependentElements(modelLineFilter); + continue; } - foreach (var elementId in elementIds) + var offsetAtTailParameter = line.get_Parameter(BuiltInParameter.SLOPE_START_HEIGHT); + if (offsetAtTailParameter != null) { - if (element.Document.GetElement(elementId) is not ModelLine line) - continue; - - var offsetAtTailParameter = line.get_Parameter(BuiltInParameter.SLOPE_START_HEIGHT); - if (offsetAtTailParameter != null) - { - return line; - } + return line; } - return null; } + return null; + } - private Point GetSlopeArrowHead(ModelLine slopeArrow, Document doc) + private Point GetSlopeArrowHead(ModelLine slopeArrow, Document doc) + { + if (slopeArrow == null) { - if (slopeArrow == null) - return null; - return PointToSpeckle(((LocationCurve)slopeArrow.Location).Curve.GetEndPoint(1), doc); + return null; } - private Point GetSlopeArrowTail(ModelLine slopeArrow, Document doc) - { - if (slopeArrow == null) - return null; - return PointToSpeckle(((LocationCurve)slopeArrow.Location).Curve.GetEndPoint(0), doc); - } + return PointToSpeckle(((LocationCurve)slopeArrow.Location).Curve.GetEndPoint(1), doc); + } - public static double GetSlopeArrowTailOffset(ModelLine slopeArrow, Document doc) + private Point GetSlopeArrowTail(ModelLine slopeArrow, Document doc) + { + if (slopeArrow == null) { - return GetParamValue(slopeArrow, BuiltInParameter.SLOPE_START_HEIGHT); + return null; } - public static double GetSlopeArrowHeadOffset( - ModelLine slopeArrow, - Document doc, - double tailOffset, - out double slope - ) - { - var specifyOffset = GetParamValue(slopeArrow, BuiltInParameter.SPECIFY_SLOPE_OR_OFFSET); - var lineLength = GetParamValue(slopeArrow, BuiltInParameter.CURVE_ELEM_LENGTH); + return PointToSpeckle(((LocationCurve)slopeArrow.Location).Curve.GetEndPoint(0), doc); + } - slope = 0; - double headOffset = 0; - // 1 corrosponds to the "slope" option - if (specifyOffset == 1) - { - // in this scenario, slope is returned as a percentage. Divide by 100 to get the unitless form - slope = GetParamValue(slopeArrow, BuiltInParameter.ROOF_SLOPE) / 100; - headOffset = tailOffset + lineLength * Math.Sin(Math.Atan(slope)); - } - else if (specifyOffset == 0) // 0 corrospondes to the "height at tail" option - { - headOffset = GetParamValue(slopeArrow, BuiltInParameter.SLOPE_END_HEIGHT); - slope = (headOffset - tailOffset) / lineLength; - } + public static double GetSlopeArrowTailOffset(ModelLine slopeArrow, Document doc) + { + return GetParamValue(slopeArrow, BuiltInParameter.SLOPE_START_HEIGHT); + } + + public static double GetSlopeArrowHeadOffset(ModelLine slopeArrow, Document doc, double tailOffset, out double slope) + { + var specifyOffset = GetParamValue(slopeArrow, BuiltInParameter.SPECIFY_SLOPE_OR_OFFSET); + var lineLength = GetParamValue(slopeArrow, BuiltInParameter.CURVE_ELEM_LENGTH); - return headOffset; + slope = 0; + double headOffset = 0; + // 1 corrosponds to the "slope" option + if (specifyOffset == 1) + { + // in this scenario, slope is returned as a percentage. Divide by 100 to get the unitless form + slope = GetParamValue(slopeArrow, BuiltInParameter.ROOF_SLOPE) / 100; + headOffset = tailOffset + lineLength * Math.Sin(Math.Atan(slope)); } + else if (specifyOffset == 0) // 0 corrospondes to the "height at tail" option + { + headOffset = GetParamValue(slopeArrow, BuiltInParameter.SLOPE_END_HEIGHT); + slope = (headOffset - tailOffset) / lineLength; + } + + return headOffset; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.DxfImport.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.DxfImport.cs index f69e1c4cd4..6f87247752 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.DxfImport.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.DxfImport.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -16,225 +16,237 @@ using Mesh = Objects.Geometry.Mesh; using DirectShape = Objects.BuiltElements.Revit.DirectShape; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit + public ApplicationObject DirectShapeToDxfImport(DirectShape ds, DB.Document doc = null) { - public ApplicationObject DirectShapeToDxfImport(DirectShape ds, DB.Document doc = null) + var appObj = new ApplicationObject(ds.id, ds.speckle_type) { applicationId = ds.applicationId }; + var existing = CheckForExistingObject(ds); + if (existing != null) { - var appObj = new ApplicationObject(ds.id, ds.speckle_type) { applicationId = ds.applicationId }; - var existing = CheckForExistingObject(ds); - if (existing != null) - return existing; - - var el = CreateDxfImport( - new List(ds.baseGeometries), - $"Speckle-Mesh-{ds.id}-{ds.applicationId}.dxf", - 1, - doc - ); - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; + return existing; } - public ApplicationObject DirectShapeToDxfImportFamily(DirectShape ds, DB.Document doc = null) - { - var appObj = new ApplicationObject(ds.id, ds.speckle_type) { applicationId = ds.applicationId }; - var existing = CheckForExistingObject(ds); - if (existing != null) - return existing; - - var el = CreateDxfImportFamily( - new List(ds.baseGeometries), - $"Speckle-Mesh-{ds.id}-{ds.applicationId}.dxf", - 1, - doc - ); - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; - } + var el = CreateDxfImport(new List(ds.baseGeometries), $"Speckle-Mesh-{ds.id}-{ds.applicationId}.dxf", 1, doc); + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } - public ApplicationObject MeshToDxfImport(Mesh mesh, DB.Document doc = null) + public ApplicationObject DirectShapeToDxfImportFamily(DirectShape ds, DB.Document doc = null) + { + var appObj = new ApplicationObject(ds.id, ds.speckle_type) { applicationId = ds.applicationId }; + var existing = CheckForExistingObject(ds); + if (existing != null) { - var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; - var existing = CheckForExistingObject(mesh); - if (existing != null) - return existing; - - var el = CreateDxfImport(new List { mesh }, $"Speckle-Mesh-{mesh.id}-{mesh.applicationId}.dxf", 1, doc); - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; + return existing; } - public ApplicationObject MeshToDxfImportFamily(Mesh mesh, DB.Document doc = null) + var el = CreateDxfImportFamily( + new List(ds.baseGeometries), + $"Speckle-Mesh-{ds.id}-{ds.applicationId}.dxf", + 1, + doc + ); + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } + + public ApplicationObject MeshToDxfImport(Mesh mesh, DB.Document doc = null) + { + var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; + var existing = CheckForExistingObject(mesh); + if (existing != null) { - var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; - var existing = CheckForExistingObject(mesh); - if (existing != null) - return existing; - - var el = CreateDxfImportFamily(new List { mesh }, $"Speckle-Mesh-{mesh.id}-{mesh.applicationId}", 1, doc); - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; + return existing; } - public ApplicationObject BrepToDxfImport(Brep brep, DB.Document doc) + var el = CreateDxfImport(new List { mesh }, $"Speckle-Mesh-{mesh.id}-{mesh.applicationId}.dxf", 1, doc); + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } + + public ApplicationObject MeshToDxfImportFamily(Mesh mesh, DB.Document doc = null) + { + var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; + var existing = CheckForExistingObject(mesh); + if (existing != null) { - var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; - var existing = CheckForExistingObject(brep); - if (existing != null) - return existing; + return existing; + } - var el = CreateDxfImport(new List { brep }, $"Speckle-Brep-{brep.id}-{brep.applicationId}", 1, doc); + var el = CreateDxfImportFamily(new List { mesh }, $"Speckle-Mesh-{mesh.id}-{mesh.applicationId}", 1, doc); + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; + public ApplicationObject BrepToDxfImport(Brep brep, DB.Document doc) + { + var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; + var existing = CheckForExistingObject(brep); + if (existing != null) + { + return existing; } - public ApplicationObject BrepToDxfImportFamily(Brep brep, DB.Document doc = null) - { - var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; - var existing = CheckForExistingObject(brep); - if (existing != null) - return existing; + var el = CreateDxfImport(new List { brep }, $"Speckle-Brep-{brep.id}-{brep.applicationId}", 1, doc); - var el = CreateDxfImportFamily(new List { brep }, $"Speckle-Brep-{brep.id}-{brep.applicationId}", 1, doc); + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } - appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); - return appObj; + public ApplicationObject BrepToDxfImportFamily(Brep brep, DB.Document doc = null) + { + var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; + var existing = CheckForExistingObject(brep); + if (existing != null) + { + return existing; } - /// - /// Creates a new Revit Element from a list of Base objects by exporting them to DXF and importing that file back. - /// - /// The objects to be imported. - /// The filename for the temporary DXF file. - /// The scale factor for the DXF. - /// The document to import the DXF into. - /// The Element containing the imported DXF geometry. - /// Will throw an error if no objects where successfully converted. - public DB.Element CreateDxfImport( - List objects, - string fileName, - double scaleFactor = 1, - DB.Document doc = null - ) - { - doc ??= Doc; // Use the global doc if no doc is passed in. - var dxfConverter = new SpeckleDxfConverter { Settings = { PrettyMeshes = true, DocUnits = ModelUnits } }; + var el = CreateDxfImportFamily(new List { brep }, $"Speckle-Brep-{brep.id}-{brep.applicationId}", 1, doc); - dxfConverter.SetContextDocument(null); // Resets the internal Doc. + appObj.Update(status: ApplicationObject.State.Created, createdId: el.UniqueId, convertedItem: el); + return appObj; + } - var collection = dxfConverter - .ConvertToNative(objects) - .SelectMany(o => - { - if (o is IEnumerable e) - return e; - return new List { (EntityObject)o }; - }) - .Where(e => e != null) - .ToList(); + /// + /// Creates a new Revit Element from a list of Base objects by exporting them to DXF and importing that file back. + /// + /// The objects to be imported. + /// The filename for the temporary DXF file. + /// The scale factor for the DXF. + /// The document to import the DXF into. + /// The Element containing the imported DXF geometry. + /// Will throw an error if no objects where successfully converted. + public DB.Element CreateDxfImport(List objects, string fileName, double scaleFactor = 1, DB.Document doc = null) + { + doc ??= Doc; // Use the global doc if no doc is passed in. + var dxfConverter = new SpeckleDxfConverter { Settings = { PrettyMeshes = true, DocUnits = ModelUnits } }; - if (collection.Count == 0) - throw new SpeckleException("No objects could be converted to DXF."); + dxfConverter.SetContextDocument(null); // Resets the internal Doc. - dxfConverter.Doc.Entities.Add(collection.Where(x => x != null)); + var collection = dxfConverter + .ConvertToNative(objects) + .SelectMany(o => + { + if (o is IEnumerable e) + { + return e; + } - var folderPath = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "Temp", "Dxf"); + return new List { (EntityObject)o }; + }) + .Where(e => e != null) + .ToList(); - // Ensure directory exists - if (!Directory.Exists(folderPath)) - Directory.CreateDirectory(folderPath); + if (collection.Count == 0) + { + throw new SpeckleException("No objects could be converted to DXF."); + } - // Save the DXF file - var path = Path.Combine(folderPath, fileName + ".dxf"); - dxfConverter.Doc.Save(path); + dxfConverter.Doc.Entities.Add(collection.Where(x => x != null)); - // Create a 3D view to import the DXF file - var typeId = doc.GetDefaultElementTypeId(DB.ElementTypeGroup.ViewType3D); - var view = DB.View3D.CreatePerspective(doc, typeId); + var folderPath = Path.Combine(SpecklePathProvider.UserSpeckleFolderPath, "Temp", "Dxf"); - // Call Doc Import - var success = doc.Import( - path, - new DB.DWGImportOptions - { - Unit = DB.ImportUnit.Meter, - CustomScale = Units.GetConversionFactor("meter", ModelUnits) * scaleFactor - }, - view, - out var elementId - ); - - doc.Delete(view.Id); - File.Delete(path); - - if (!success) - throw new SpeckleException($"Failed to import DXF file: {path}"); - - var el = doc.GetElement(elementId); - el.Pinned = false; - return el; + // Ensure directory exists + if (!Directory.Exists(folderPath)) + { + Directory.CreateDirectory(folderPath); } - /// - /// Creates a new Revit Family from a list of Base objects by exporting them to DXF; importing that DXF into a new Generic Model family, and returning - /// - /// The objects to be imported. - /// The filename for the temporary DXF file. - /// The scale factor for the DXF. - /// The document to import the DXF into. - /// The Family instance containing the imported DXF geometry. - /// Will throw an error if no objects where successfully converted. - public DB.FamilyInstance CreateDxfImportFamily( - List objects, - string fileName, - double scaleFactor = 1, - DB.Document doc = null - ) - { - doc ??= Doc; // Use the global doc if no doc is passed in. - var templatePath = GetTemplatePath("Generic Model"); - if (!File.Exists(templatePath)) - throw new Exception($"Could not find Generic Model rft file - {templatePath}"); + // Save the DXF file + var path = Path.Combine(folderPath, fileName + ".dxf"); + dxfConverter.Doc.Save(path); - var famDoc = doc.Application.NewFamilyDocument(templatePath); - using (var t = new DB.Transaction(famDoc, "Import DXF elements")) + // Create a 3D view to import the DXF file + var typeId = doc.GetDefaultElementTypeId(DB.ElementTypeGroup.ViewType3D); + var view = DB.View3D.CreatePerspective(doc, typeId); + + // Call Doc Import + var success = doc.Import( + path, + new DB.DWGImportOptions { - t.Start(); - try - { - CreateDxfImport(objects, fileName, scaleFactor, famDoc); - } - catch (SpeckleException e) - { - t.RollBack(); - famDoc.Close(); - throw; - } - t.Commit(); - } + Unit = DB.ImportUnit.Meter, + CustomScale = Units.GetConversionFactor("meter", ModelUnits) * scaleFactor + }, + view, + out var elementId + ); - var tempFamilyPath = Path.Combine(Path.GetTempPath(), fileName + ".rfa"); - var so = new DB.SaveAsOptions { OverwriteExistingFile = true }; + doc.Delete(view.Id); + File.Delete(path); - famDoc.SaveAs(tempFamilyPath, so); - famDoc.Close(); + if (!success) + { + throw new SpeckleException($"Failed to import DXF file: {path}"); + } - Report.Log($"Created Dxf Import Family at: {tempFamilyPath}"); + var el = doc.GetElement(elementId); + el.Pinned = false; + return el; + } - Doc.LoadFamily(tempFamilyPath, new FamilyLoadOption(), out var fam); - var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; - symbol.Activate(); + /// + /// Creates a new Revit Family from a list of Base objects by exporting them to DXF; importing that DXF into a new Generic Model family, and returning + /// + /// The objects to be imported. + /// The filename for the temporary DXF file. + /// The scale factor for the DXF. + /// The document to import the DXF into. + /// The Family instance containing the imported DXF geometry. + /// Will throw an error if no objects where successfully converted. + public DB.FamilyInstance CreateDxfImportFamily( + List objects, + string fileName, + double scaleFactor = 1, + DB.Document doc = null + ) + { + doc ??= Doc; // Use the global doc if no doc is passed in. + var templatePath = GetTemplatePath("Generic Model"); + if (!File.Exists(templatePath)) + { + throw new Exception($"Could not find Generic Model rft file - {templatePath}"); + } + var famDoc = doc.Application.NewFamilyDocument(templatePath); + using (var t = new DB.Transaction(famDoc, "Import DXF elements")) + { + t.Start(); try { - File.Delete(tempFamilyPath); + CreateDxfImport(objects, fileName, scaleFactor, famDoc); } - catch { } + catch (SpeckleException e) + { + t.RollBack(); + famDoc.Close(); + throw; + } + t.Commit(); + } - return Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + var tempFamilyPath = Path.Combine(Path.GetTempPath(), fileName + ".rfa"); + var so = new DB.SaveAsOptions { OverwriteExistingFile = true }; + + famDoc.SaveAs(tempFamilyPath, so); + famDoc.Close(); + + Report.Log($"Created Dxf Import Family at: {tempFamilyPath}"); + + Doc.LoadFamily(tempFamilyPath, new FamilyLoadOption(), out var fam); + var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; + symbol.Activate(); + + try + { + File.Delete(tempFamilyPath); } + catch { } + + return Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.MeshBuildHelper.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.MeshBuildHelper.cs index 4ab83bc286..c4bcd96060 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.MeshBuildHelper.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.MeshBuildHelper.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Linq; @@ -7,65 +6,74 @@ using DB = Autodesk.Revit.DB; using Mesh = Objects.Geometry.Mesh; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit + /// + /// Helper class for a single object for each + /// + private class MeshBuildHelper { - /// - /// Helper class for a single object for each - /// - private class MeshBuildHelper - { - //Lazy initialised Dictionary of Revit material (hash) -> Speckle material - private readonly Dictionary materialMap = new Dictionary(); + //Lazy initialised Dictionary of Revit material (hash) -> Speckle material + private readonly Dictionary materialMap = new(); - public RenderMaterial GetOrCreateMaterial(DB.Material revitMaterial) + public RenderMaterial GetOrCreateMaterial(DB.Material revitMaterial) + { + if (revitMaterial == null) { - if (revitMaterial == null) return null; - - int - hash = Hash( - revitMaterial); //Key using the hash as we may be given several instances with identical material properties - if (materialMap.TryGetValue(hash, out RenderMaterial m)) - { - return m; - } - - var material = RenderMaterialToSpeckle(revitMaterial); - materialMap.Add(hash, material); - return material; + return null; } - private static int Hash(DB.Material mat) - => mat.Transparency ^ mat.Color.Red ^ mat.Color.Green ^ mat.Color.Blue ^ mat.Smoothness ^ mat.Shininess; + int hash = Hash(revitMaterial); //Key using the hash as we may be given several instances with identical material properties + if (materialMap.TryGetValue(hash, out RenderMaterial m)) + { + return m; + } - //Mesh to use for null materials (because dictionary keys can't be null) - private Mesh nullMesh; + var material = RenderMaterialToSpeckle(revitMaterial); + materialMap.Add(hash, material); + return material; + } - //Lazy initialised Dictionary of revit material (hash) -> Speckle Mesh - private readonly Dictionary meshMap = new Dictionary(); + private static int Hash(DB.Material mat) => + mat.Transparency ^ mat.Color.Red ^ mat.Color.Green ^ mat.Color.Blue ^ mat.Smoothness ^ mat.Shininess; - public Mesh GetOrCreateMesh(DB.Material mat, string units) - { - if (mat == null) return nullMesh ??= new Mesh { units = units }; + //Mesh to use for null materials (because dictionary keys can't be null) + private Mesh nullMesh; - int materialHash = Hash(mat); - if (meshMap.TryGetValue(materialHash, out Mesh m)) return m; + //Lazy initialised Dictionary of revit material (hash) -> Speckle Mesh + private readonly Dictionary meshMap = new(); - var mesh = new Mesh { ["renderMaterial"] = GetOrCreateMaterial(mat), units = units }; - meshMap.Add(materialHash, mesh); - return mesh; + public Mesh GetOrCreateMesh(DB.Material mat, string units) + { + if (mat == null) + { + return nullMesh ??= new Mesh { units = units }; } - public List GetAllMeshes() + int materialHash = Hash(mat); + if (meshMap.TryGetValue(materialHash, out Mesh m)) { - List meshes = meshMap.Values?.ToList() ?? new List(); - if (nullMesh != null) meshes.Add(nullMesh); - return meshes; + return m; } - public List GetAllValidMeshes() => GetAllMeshes().FindAll(m => m.vertices.Count > 0 && m.faces.Count > 0); + var mesh = new Mesh { ["renderMaterial"] = GetOrCreateMaterial(mat), units = units }; + meshMap.Add(materialHash, mesh); + return mesh; + } + + public List GetAllMeshes() + { + List meshes = meshMap.Values?.ToList() ?? new List(); + if (nullMesh != null) + { + meshes.Add(nullMesh); + } + return meshes; } + + public List GetAllValidMeshes() => GetAllMeshes().FindAll(m => m.vertices.Count > 0 && m.faces.Count > 0); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.Previews.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.Previews.cs index 6e35db1c8f..0c872c7d44 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.Previews.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.Previews.cs @@ -1,4 +1,4 @@ -using ConverterRevitShared; +using ConverterRevitShared; using Objects.Geometry; using Speckle.Core.Models; using Speckle.Core.Models.Extensions; @@ -9,34 +9,36 @@ using System.Text; using Mesh = Objects.Geometry.Mesh; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit + private ApplicationObject PreviewGeometry(Base @object) { - private ApplicationObject PreviewGeometry(Base @object) - { - var appObj = new ApplicationObject(@object.applicationId, @object.speckle_type); - DirectContext3DServer server = null; - - Instance = this; - var meshes = @object.Flatten().Where(b => b is Mesh).Cast(); - if (meshes == null || !meshes.Any()) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"No displayable meshes found for object of type {@object.speckle_type}"); - return appObj; - } - try - { - server = new DirectContext3DServer(meshes, Doc); - appObj.Update(status: ApplicationObject.State.Created); - } - catch (Exception ex) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); - } + var appObj = new ApplicationObject(@object.applicationId, @object.speckle_type); + DirectContext3DServer server = null; - appObj.Converted = new List { server }; + Instance = this; + var meshes = @object.Flatten().Where(b => b is Mesh).Cast(); + if (meshes == null || !meshes.Any()) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"No displayable meshes found for object of type {@object.speckle_type}" + ); return appObj; } + try + { + server = new DirectContext3DServer(meshes, Doc); + appObj.Update(status: ApplicationObject.State.Created); + } + catch (Exception ex) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: ex.Message); + } + + appObj.Converted = new List { server }; + return appObj; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.SettingsHelpers.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.SettingsHelpers.cs index d0b29407e4..fd36b4cb05 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.SettingsHelpers.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.SettingsHelpers.cs @@ -1,46 +1,49 @@ -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit - { - // CAUTION: these strings need to have the same values as in the connector - const string defaultValue = "Default"; - const string dxf = "DXF"; - const string familyDxf = "Family DXF"; + // CAUTION: these strings need to have the same values as in the connector + const string defaultValue = "Default"; + const string dxf = "DXF"; + const string familyDxf = "Family DXF"; - public enum ToNativeMeshSettingEnum - { - Default, - DxfImport, - DxfImportInFamily - } + public enum ToNativeMeshSettingEnum + { + Default, + DxfImport, + DxfImportInFamily + } - public ToNativeMeshSettingEnum ToNativeMeshSetting + public ToNativeMeshSettingEnum ToNativeMeshSetting + { + get { - get + if (!Settings.ContainsKey("pretty-mesh")) { - if (!Settings.ContainsKey("pretty-mesh")) return ToNativeMeshSettingEnum.Default; - var value = Settings["pretty-mesh"]; - switch (value) - { - case dxf: - return ToNativeMeshSettingEnum.DxfImport; - case familyDxf: - return ToNativeMeshSettingEnum.DxfImportInFamily; - case defaultValue: - default: - return ToNativeMeshSettingEnum.Default; - } + return ToNativeMeshSettingEnum.Default; } - set + + var value = Settings["pretty-mesh"]; + switch (value) { - Settings["pretty-mesh"] = value switch - { - ToNativeMeshSettingEnum.DxfImport => dxf, - ToNativeMeshSettingEnum.DxfImportInFamily => familyDxf, - ToNativeMeshSettingEnum.Default => defaultValue, - _ => Settings["pretty-mesh"] - }; + case dxf: + return ToNativeMeshSettingEnum.DxfImport; + case familyDxf: + return ToNativeMeshSettingEnum.DxfImportInFamily; + case defaultValue: + default: + return ToNativeMeshSettingEnum.Default; } } + set + { + Settings["pretty-mesh"] = value switch + { + ToNativeMeshSettingEnum.DxfImport => dxf, + ToNativeMeshSettingEnum.DxfImportInFamily => familyDxf, + ToNativeMeshSettingEnum.Default => defaultValue, + _ => Settings["pretty-mesh"] + }; + } } -} \ No newline at end of file +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs index 96ae9222fa..e53d7872b5 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs @@ -24,874 +24,913 @@ using GE = Objects.Geometry; using STR = Objects.Structural; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit : ISpeckleConverter { - public partial class ConverterRevit : ISpeckleConverter - { #if REVIT2024 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2024); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2024); #elif REVIT2023 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2023); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2023); #elif REVIT2022 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2022); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2022); #elif REVIT2021 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2021); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2021); #elif REVIT2020 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2020); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2020); #elif REVIT2019 - public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2019); + public static string RevitAppName = HostApplications.Revit.GetVersion(HostAppVersion.v2019); #endif - #region ISpeckleConverter props + #region ISpeckleConverter props - public string Description => "Default Speckle Kit for Revit"; - public string Name => nameof(ConverterRevit); - public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; + public string Description => "Default Speckle Kit for Revit"; + public string Name => nameof(ConverterRevit); + public string Author => "Speckle"; + public string WebsiteOrEmail => "https://speckle.systems"; - public IEnumerable GetServicedApplications() => new string[] { RevitAppName }; + public IEnumerable GetServicedApplications() => new string[] { RevitAppName }; - #endregion ISpeckleConverter props + #endregion ISpeckleConverter props - private const double TOLERANCE = 0.0164042; // 5mm in ft + private const double TOLERANCE = 0.0164042; // 5mm in ft - public Document Doc { get; private set; } + public Document Doc { get; private set; } - /// - /// To know which other objects are being converted, in order to sort relationships between them. - /// For example, elements that have children use this to determine whether they should send their children out or not. - /// - public Dictionary ContextObjects { get; set; } = - new Dictionary(); + /// + /// To know which other objects are being converted, in order to sort relationships between them. + /// For example, elements that have children use this to determine whether they should send their children out or not. + /// + public Dictionary ContextObjects { get; set; } = + new Dictionary(); - /// - /// To keep track of previously received objects from a given stream in here. If possible, conversions routines - /// will edit an existing object, otherwise they will delete the old one and create the new one. - /// - public IReceivedObjectIdMap PreviouslyReceivedObjectIds { get; set; } + /// + /// To keep track of previously received objects from a given stream in here. If possible, conversions routines + /// will edit an existing object, otherwise they will delete the old one and create the new one. + /// + public IReceivedObjectIdMap PreviouslyReceivedObjectIds { get; set; } - /// - /// Keeps track of the current host element that is creating any sub-objects it may have. - /// - public Element CurrentHostElement => RevitConverterState.Peek?.CurrentHostElement; + /// + /// Keeps track of the current host element that is creating any sub-objects it may have. + /// + public Element CurrentHostElement => RevitConverterState.Peek?.CurrentHostElement; - /// - /// Used when sending; keeps track of all the converted objects so far. Child elements first check in here if they should convert themselves again (they may have been converted as part of a parent's hosted elements). - /// - public ISet ConvertedObjects { get; private set; } = new HashSet(); + /// + /// Used when sending; keeps track of all the converted objects so far. Child elements first check in here if they should convert themselves again (they may have been converted as part of a parent's hosted elements). + /// + public ISet ConvertedObjects { get; private set; } = new HashSet(); - public ProgressReport Report { get; private set; } = new ProgressReport(); + public ProgressReport Report { get; private set; } = new ProgressReport(); - public Dictionary Settings { get; private set; } = new Dictionary(); + public Dictionary Settings { get; private set; } = new Dictionary(); - public Dictionary Levels { get; private set; } = new Dictionary(); + public Dictionary Levels { get; private set; } = new Dictionary(); - public Dictionary Phases { get; private set; } = new Dictionary(); + public Dictionary Phases { get; private set; } = new Dictionary(); - /// - /// Used to cache already converted family instance FamilyType deifnitions - /// - public Dictionary Symbols { get; private set; } = - new Dictionary(); + /// + /// Used to cache already converted family instance FamilyType deifnitions + /// + public Dictionary Symbols { get; private set; } = + new Dictionary(); - public Dictionary SectionProfiles { get; private set; } = - new Dictionary(); + public Dictionary SectionProfiles { get; private set; } = + new Dictionary(); - public ReceiveMode ReceiveMode { get; set; } + public ReceiveMode ReceiveMode { get; set; } - /// - /// Contains all materials in the model - /// - public Dictionary Materials { get; private set; } = - new Dictionary(); + /// + /// Contains all materials in the model + /// + public Dictionary Materials { get; private set; } = + new Dictionary(); - public ConverterRevit() - { - var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterRevit)).GetName().Version; - Report.Log($"Using converter: {Name} v{ver}"); - } + public ConverterRevit() + { + var ver = System.Reflection.Assembly.GetAssembly(typeof(ConverterRevit)).GetName().Version; + Report.Log($"Using converter: {Name} v{ver}"); + } - private IRevitDocumentAggregateCache revitDocumentAggregateCache; - private IConvertedObjectsCache receivedObjectsCache; - private TransactionManager transactionManager; + private IRevitDocumentAggregateCache revitDocumentAggregateCache; + private IConvertedObjectsCache receivedObjectsCache; + private TransactionManager transactionManager; - public void SetContextDocument(object doc) + public void SetContextDocument(object doc) + { + if (doc is TransactionManager transactionManager) { - if (doc is TransactionManager transactionManager) - { - this.transactionManager = transactionManager; - } - else if (doc is IRevitDocumentAggregateCache revitDocumentAggregateCache) - { - this.revitDocumentAggregateCache = revitDocumentAggregateCache; - } - else if (doc is IConvertedObjectsCache receivedObjectsCache) - { - this.receivedObjectsCache = receivedObjectsCache; - } - else if (doc is IReceivedObjectIdMap cache) - { - PreviouslyReceivedObjectIds = cache; - } - else if (doc is DB.View view) - { - // setting the view as a 2d view will result in no objects showing up, so only do it if it's a 3D view - if (view is View3D view3D) - { - ViewSpecificOptions = new Options() { View = view, ComputeReferences = true }; - } - } - else if (doc is Document document) - { - Doc = document; - Report.Log($"Using document: {Doc.PathName}"); - Report.Log($"Using units: {ModelUnits}"); - } - else + this.transactionManager = transactionManager; + } + else if (doc is IRevitDocumentAggregateCache revitDocumentAggregateCache) + { + this.revitDocumentAggregateCache = revitDocumentAggregateCache; + } + else if (doc is IConvertedObjectsCache receivedObjectsCache) + { + this.receivedObjectsCache = receivedObjectsCache; + } + else if (doc is IReceivedObjectIdMap cache) + { + PreviouslyReceivedObjectIds = cache; + } + else if (doc is DB.View view) + { + // setting the view as a 2d view will result in no objects showing up, so only do it if it's a 3D view + if (view is View3D view3D) { - throw new ArgumentException( - $"Converter.{nameof(SetContextDocument)}() was passed an object of unexpected type, {doc.GetType()}" - ); + ViewSpecificOptions = new Options() { View = view, ComputeReferences = true }; } } + else if (doc is Document document) + { + Doc = document; + Report.Log($"Using document: {Doc.PathName}"); + Report.Log($"Using units: {ModelUnits}"); + } + else + { + throw new ArgumentException( + $"Converter.{nameof(SetContextDocument)}() was passed an object of unexpected type, {doc.GetType()}" + ); + } + } - const string DetailLevelCoarse = "Coarse"; - const string DetailLevelMedium = "Medium"; - const string DetailLevelFine = "Fine"; - public ViewDetailLevel DetailLevelSetting => GetDetailLevelSetting() ?? ViewDetailLevel.Fine; + const string DetailLevelCoarse = "Coarse"; + const string DetailLevelMedium = "Medium"; + const string DetailLevelFine = "Fine"; + public ViewDetailLevel DetailLevelSetting => GetDetailLevelSetting() ?? ViewDetailLevel.Fine; - private ViewDetailLevel? GetDetailLevelSetting() + private ViewDetailLevel? GetDetailLevelSetting() + { + if (!Settings.TryGetValue("detail-level", out string detailLevel)) { - if (!Settings.TryGetValue("detail-level", out string detailLevel)) - { - return null; - } - return detailLevel switch - { - DetailLevelCoarse => ViewDetailLevel.Coarse, - DetailLevelMedium => ViewDetailLevel.Medium, - DetailLevelFine => ViewDetailLevel.Fine, - _ => null - }; + return null; } + return detailLevel switch + { + DetailLevelCoarse => ViewDetailLevel.Coarse, + DetailLevelMedium => ViewDetailLevel.Medium, + DetailLevelFine => ViewDetailLevel.Fine, + _ => null + }; + } - //NOTE: not all objects come from Revit, so their applicationId might be null, in this case we fall back on the Id - //this fallback is only needed for a couple of ToNative conversions such as Floor, Ceiling, and Roof - public void SetContextObjects(List objects) + //NOTE: not all objects come from Revit, so their applicationId might be null, in this case we fall back on the Id + //this fallback is only needed for a couple of ToNative conversions such as Floor, Ceiling, and Roof + public void SetContextObjects(List objects) + { + ContextObjects = new(objects.Count); + foreach (var ao in objects) { - ContextObjects = new(objects.Count); - foreach (var ao in objects) + var key = ao.applicationId ?? ao.OriginalId; + if (ContextObjects.ContainsKey(key)) { - var key = ao.applicationId ?? ao.OriginalId; - if (ContextObjects.ContainsKey(key)) - continue; - ContextObjects.Add(key, ao); + continue; } - } - public void SetPreviousContextObjects(List objects) - { - //PreviousContextObjects = new(objects.Count); - //foreach (var ao in objects) - //{ - // var key = ao.applicationId ?? ao.OriginalId; - // if (PreviousContextObjects.ContainsKey(key)) - // continue; - // PreviousContextObjects.Add(key, ao); - //} + ContextObjects.Add(key, ao); } + } - public void SetConverterSettings(object settings) - { - Settings = settings as Dictionary; - } + public void SetPreviousContextObjects(List objects) + { + //PreviousContextObjects = new(objects.Count); + //foreach (var ao in objects) + //{ + // var key = ao.applicationId ?? ao.OriginalId; + // if (PreviousContextObjects.ContainsKey(key)) + // continue; + // PreviousContextObjects.Add(key, ao); + //} + } + + public void SetConverterSettings(object settings) + { + Settings = settings as Dictionary; + } + + public Base ConvertToSpeckle(object @object) + { + Base returnObject = null; + List notes = new(); + string id = @object is Element element ? element.UniqueId : string.Empty; - public Base ConvertToSpeckle(object @object) + switch (@object) { - Base returnObject = null; - List notes = new List(); - string id = @object is Element element ? element.UniqueId : string.Empty; + case DB.Document o: + returnObject = ModelToSpeckle(o, !o.IsFamilyDocument); + break; + case DB.DetailCurve o: + returnObject = DetailCurveToSpeckle(o); + break; + case DB.DirectShape o: + returnObject = DirectShapeToSpeckle(o); + break; + case DB.FamilyInstance o: + returnObject = FamilyInstanceToSpeckle(o, out notes); + break; + case DB.Floor o: + returnObject = FloorToSpeckle(o, out notes); + break; + case DB.FabricationPart o: + returnObject = FabricationPartToSpeckle(o, out notes); + break; + case DB.Group o: + returnObject = GroupToSpeckle(o); + break; + case DB.Level o: + returnObject = LevelToSpeckle(o); + break; + case DB.View o: + returnObject = ViewToSpeckle(o); + break; + //NOTE: Converts all materials in the materials library + case DB.Material o: + returnObject = ConvertAndCacheMaterial(o.Id, o.Document); + break; + case DB.ModelCurve o: + if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_RoomSeparationLines) + { + returnObject = RoomBoundaryLineToSpeckle(o); + } + else if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_MEPSpaceSeparationLines) + { + returnObject = SpaceSeparationLineToSpeckle(o); + } + else + { + returnObject = ModelCurveToSpeckle(o); + } - switch (@object) - { - case DB.Document o: - returnObject = ModelToSpeckle(o, !o.IsFamilyDocument); - break; - case DB.DetailCurve o: - returnObject = DetailCurveToSpeckle(o); - break; - case DB.DirectShape o: - returnObject = DirectShapeToSpeckle(o); - break; - case DB.FamilyInstance o: - returnObject = FamilyInstanceToSpeckle(o, out notes); - break; - case DB.Floor o: - returnObject = FloorToSpeckle(o, out notes); - break; - case DB.FabricationPart o: - returnObject = FabricationPartToSpeckle(o, out notes); - break; - case DB.Group o: - returnObject = GroupToSpeckle(o); - break; - case DB.Level o: - returnObject = LevelToSpeckle(o); - break; - case DB.View o: - returnObject = ViewToSpeckle(o); - break; - //NOTE: Converts all materials in the materials library - case DB.Material o: - returnObject = ConvertAndCacheMaterial(o.Id, o.Document); - break; - case DB.ModelCurve o: - if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_RoomSeparationLines) - returnObject = RoomBoundaryLineToSpeckle(o); - else if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_MEPSpaceSeparationLines) - returnObject = SpaceSeparationLineToSpeckle(o); - else - returnObject = ModelCurveToSpeckle(o); - break; - case DB.Opening o: - returnObject = OpeningToSpeckle(o); - break; - case DB.RoofBase o: - returnObject = RoofToSpeckle(o, out notes); - break; - case DB.Area o: - returnObject = AreaToSpeckle(o); - break; - case DB.Architecture.Room o: - returnObject = RoomToSpeckle(o); - break; - case DB.Architecture.TopographySurface o: - returnObject = TopographyToSpeckle(o); - break; - case DB.Wall o: - returnObject = WallToSpeckle(o, out notes); - break; - case DB.Mechanical.Duct o: - returnObject = DuctToSpeckle(o, out notes); - break; - case DB.Mechanical.FlexDuct o: - returnObject = DuctToSpeckle(o); - break; - case DB.Mechanical.Space o: - returnObject = SpaceToSpeckle(o); - break; - case DB.Plumbing.Pipe o: - returnObject = PipeToSpeckle(o); - break; - case DB.Plumbing.FlexPipe o: - returnObject = PipeToSpeckle(o); - break; - case DB.Electrical.Wire o: - returnObject = WireToSpeckle(o); - break; - case DB.Electrical.CableTray o: - returnObject = CableTrayToSpeckle(o); - break; - case DB.Electrical.Conduit o: - returnObject = ConduitToSpeckle(o); - break; - //these should be handled by curtain walls - case DB.CurtainGridLine _: - throw new ConversionSkippedException( - "Curtain Grid Lines are handled as part of the parent CurtainWall conversion" - ); - case DB.Architecture.BuildingPad o: - returnObject = BuildingPadToSpeckle(o); - break; - case DB.Architecture.Stairs o: - returnObject = StairToSpeckle(o); - break; - //these are handled by Stairs - case DB.Architecture.StairsRun _: - throw new ConversionSkippedException($"{nameof(StairsRun)} are handled by the {nameof(Stairs)} conversion"); - case DB.Architecture.StairsLanding _: - throw new ConversionSkippedException( - $"{nameof(StairsLanding)} are handled by the {nameof(Stairs)} conversion" - ); - break; - case DB.Architecture.Railing o: - returnObject = RailingToSpeckle(o); - break; - case DB.Architecture.TopRail o: - returnObject = TopRailToSpeckle(o); - break; - case DB.Architecture.HandRail _: - throw new ConversionSkippedException($"{nameof(HandRail)} are handled by the {nameof(Railing)} conversion"); - case DB.Structure.Rebar o: - returnObject = RebarToSpeckle(o); - break; - case DB.Ceiling o: - returnObject = CeilingToSpeckle(o, out notes); - break; - case DB.PointCloudInstance o: - returnObject = PointcloudToSpeckle(o); - break; - case DB.ProjectInfo o: - returnObject = ProjectInfoToSpeckle(o); - break; - case DB.ElementType o: - returnObject = ElementTypeToSpeckle(o); - break; - case DB.Grid o: - returnObject = GridLineToSpeckle(o); - break; - case DB.ReferencePoint o: - if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_AnalyticalNodes) - returnObject = AnalyticalNodeToSpeckle(o); - break; - case DB.Structure.BoundaryConditions o: - returnObject = BoundaryConditionsToSpeckle(o); - break; - case DB.Structure.StructuralConnectionHandler o: - returnObject = StructuralConnectionHandlerToSpeckle(o); - break; - case DB.CombinableElement o: - returnObject = CombinableElementToSpeckle(o); - break; + break; + case DB.Opening o: + returnObject = OpeningToSpeckle(o); + break; + case DB.RoofBase o: + returnObject = RoofToSpeckle(o, out notes); + break; + case DB.Area o: + returnObject = AreaToSpeckle(o); + break; + case DB.Architecture.Room o: + returnObject = RoomToSpeckle(o); + break; + case DB.Architecture.TopographySurface o: + returnObject = TopographyToSpeckle(o); + break; + case DB.Wall o: + returnObject = WallToSpeckle(o, out notes); + break; + case DB.Mechanical.Duct o: + returnObject = DuctToSpeckle(o, out notes); + break; + case DB.Mechanical.FlexDuct o: + returnObject = DuctToSpeckle(o); + break; + case DB.Mechanical.Space o: + returnObject = SpaceToSpeckle(o); + break; + case DB.Plumbing.Pipe o: + returnObject = PipeToSpeckle(o); + break; + case DB.Plumbing.FlexPipe o: + returnObject = PipeToSpeckle(o); + break; + case DB.Electrical.Wire o: + returnObject = WireToSpeckle(o); + break; + case DB.Electrical.CableTray o: + returnObject = CableTrayToSpeckle(o); + break; + case DB.Electrical.Conduit o: + returnObject = ConduitToSpeckle(o); + break; + //these should be handled by curtain walls + case DB.CurtainGridLine _: + throw new ConversionSkippedException( + "Curtain Grid Lines are handled as part of the parent CurtainWall conversion" + ); + case DB.Architecture.BuildingPad o: + returnObject = BuildingPadToSpeckle(o); + break; + case DB.Architecture.Stairs o: + returnObject = StairToSpeckle(o); + break; + //these are handled by Stairs + case DB.Architecture.StairsRun _: + throw new ConversionSkippedException($"{nameof(StairsRun)} are handled by the {nameof(Stairs)} conversion"); + case DB.Architecture.StairsLanding _: + throw new ConversionSkippedException($"{nameof(StairsLanding)} are handled by the {nameof(Stairs)} conversion"); + break; + case DB.Architecture.Railing o: + returnObject = RailingToSpeckle(o); + break; + case DB.Architecture.TopRail o: + returnObject = TopRailToSpeckle(o); + break; + case DB.Architecture.HandRail _: + throw new ConversionSkippedException($"{nameof(HandRail)} are handled by the {nameof(Railing)} conversion"); + case DB.Structure.Rebar o: + returnObject = RebarToSpeckle(o); + break; + case DB.Ceiling o: + returnObject = CeilingToSpeckle(o, out notes); + break; + case DB.PointCloudInstance o: + returnObject = PointcloudToSpeckle(o); + break; + case DB.ProjectInfo o: + returnObject = ProjectInfoToSpeckle(o); + break; + case DB.ElementType o: + returnObject = ElementTypeToSpeckle(o); + break; + case DB.Grid o: + returnObject = GridLineToSpeckle(o); + break; + case DB.ReferencePoint o: + if ((BuiltInCategory)o.Category.Id.IntegerValue == BuiltInCategory.OST_AnalyticalNodes) + { + returnObject = AnalyticalNodeToSpeckle(o); + } - // toposolid from Revit 2024 + break; + case DB.Structure.BoundaryConditions o: + returnObject = BoundaryConditionsToSpeckle(o); + break; + case DB.Structure.StructuralConnectionHandler o: + returnObject = StructuralConnectionHandlerToSpeckle(o); + break; + case DB.CombinableElement o: + returnObject = CombinableElementToSpeckle(o); + break; + + // toposolid from Revit 2024 #if (REVIT2024) - case DB.Toposolid o: - returnObject = ToposolidToSpeckle(o, out notes); - break; + case DB.Toposolid o: + returnObject = ToposolidToSpeckle(o, out notes); + break; #endif #if REVIT2020 || REVIT2021 || REVIT2022 - case DB.Structure.AnalyticalModelStick o: - returnObject = AnalyticalStickToSpeckle(o); - break; - case DB.Structure.AnalyticalModelSurface o: - returnObject = AnalyticalSurfaceToSpeckle(o); - break; + case DB.Structure.AnalyticalModelStick o: + returnObject = AnalyticalStickToSpeckle(o); + break; + case DB.Structure.AnalyticalModelSurface o: + returnObject = AnalyticalSurfaceToSpeckle(o); + break; #else - case DB.Structure.AnalyticalMember o: - returnObject = AnalyticalStickToSpeckle(o); - break; - case DB.Structure.AnalyticalPanel o: - returnObject = AnalyticalSurfaceToSpeckle(o); - break; + case DB.Structure.AnalyticalMember o: + returnObject = AnalyticalStickToSpeckle(o); + break; + case DB.Structure.AnalyticalPanel o: + returnObject = AnalyticalSurfaceToSpeckle(o); + break; #endif - default: - // if we don't have a direct conversion, still try to send this element as a generic RevitElement - var el = @object as Element; - if (el.IsElementSupported()) - { - returnObject = RevitElementToSpeckle(el, out notes); - break; - } - throw new NotSupportedException($"Conversion of {@object.GetType().Name} is not supported."); - } - - // NOTE: Only try generic method assignment if there is no existing render material from conversions; - // we might want to try later on to capture it more intelligently from inside conversion routines. - if ( - returnObject != null - && returnObject["renderMaterial"] == null - && returnObject["displayValue"] == null - && !(returnObject is Collection) - ) - { - try + default: + // if we don't have a direct conversion, still try to send this element as a generic RevitElement + var el = @object as Element; + if (el.IsElementSupported()) { - var material = GetElementRenderMaterial(@object as DB.Element); - returnObject["renderMaterial"] = material; - } - catch (Exception e) - { - // passing for stuff without a material (eg converting the current document to get the `Model` and `Info` objects) + returnObject = RevitElementToSpeckle(el, out notes); + break; } - } + throw new NotSupportedException($"Conversion of {@object.GetType().Name} is not supported."); + } - // log - if (Report.ReportObjects.TryGetValue(id, out var reportObj) && notes.Count > 0) - reportObj.Update(log: notes); + // NOTE: Only try generic method assignment if there is no existing render material from conversions; + // we might want to try later on to capture it more intelligently from inside conversion routines. + if ( + returnObject != null + && returnObject["renderMaterial"] == null + && returnObject["displayValue"] == null + && !(returnObject is Collection) + ) + { + try + { + var material = GetElementRenderMaterial(@object as DB.Element); + returnObject["renderMaterial"] = material; + } + catch (Exception e) + { + // passing for stuff without a material (eg converting the current document to get the `Model` and `Info` objects) + } + } - return returnObject; + // log + if (Report.ReportObjects.TryGetValue(id, out var reportObj) && notes.Count > 0) + { + reportObj.Update(log: notes); } - private string GetElemInfo(object o) + return returnObject; + } + + private string GetElemInfo(object o) + { + if (o is Element e) { - if (o is Element e) - return $", name: {e.Name}, id: {e.UniqueId}"; + return $", name: {e.Name}, id: {e.UniqueId}"; + } - return ""; + return ""; + } + + private Base SwapGeometrySchemaObject(Base @object) + { + // schema check + var speckleSchema = @object["@SpeckleSchema"] as Base; + if (speckleSchema == null || !CanConvertToNative(speckleSchema)) + { + return @object; // Skip if no schema, or schema is non-convertible. } - private Base SwapGeometrySchemaObject(Base @object) + // Invert the "Geometry->SpeckleSchema" to be the logical "SpeckleSchema -> Geometry" order. + // This is caused by RhinoBIM, the MappingTool in rhino, and any Grasshopper Schema node with the option active. + if (speckleSchema is BER.DirectShape ds) { - // schema check - var speckleSchema = @object["@SpeckleSchema"] as Base; - if (speckleSchema == null || !CanConvertToNative(speckleSchema)) - return @object; // Skip if no schema, or schema is non-convertible. - - // Invert the "Geometry->SpeckleSchema" to be the logical "SpeckleSchema -> Geometry" order. - // This is caused by RhinoBIM, the MappingTool in rhino, and any Grasshopper Schema node with the option active. - if (speckleSchema is BER.DirectShape ds) + // HACK: This is an explicit exception for DirectShapes. This is the only object class that does not have a + // `SchemaMainParam`, which means the swap performed below would not work. + // In this case, we cast directly and "unwrap" the schema object manually, setting the Brep as the only + // item in the list. + ds.baseGeometries = new List { @object }; + } + else if (speckleSchema is MappedBlockWrapper mbw) + { + if (@object is not BlockInstance bi) { - // HACK: This is an explicit exception for DirectShapes. This is the only object class that does not have a - // `SchemaMainParam`, which means the swap performed below would not work. - // In this case, we cast directly and "unwrap" the schema object manually, setting the Brep as the only - // item in the list. - ds.baseGeometries = new List { @object }; + throw new Exception($"{nameof(MappedBlockWrapper)} can only be used with {nameof(BlockInstance)} objects."); } - else if (speckleSchema is MappedBlockWrapper mbw) - { - if (@object is not BlockInstance bi) - throw new Exception($"{nameof(MappedBlockWrapper)} can only be used with {nameof(BlockInstance)} objects."); - mbw.instance = bi; - } - else + mbw.instance = bi; + } + else + { + // find self referential prop and set value to @object if it is null (happens when sent from gh) + // if you can find a "MainParamProperty" get that + // HACK: The results of this can be inconsistent as we don't really know which is the `MainParamProperty`, that is info that is attached to the constructor input. Hence the hack above ☝🏼 + var prop = speckleSchema + .GetInstanceMembers() + .Where(o => speckleSchema[o.Name] == null) + .FirstOrDefault(o => o.PropertyType.IsInstanceOfType(@object)); + if (prop != null) { - // find self referential prop and set value to @object if it is null (happens when sent from gh) - // if you can find a "MainParamProperty" get that - // HACK: The results of this can be inconsistent as we don't really know which is the `MainParamProperty`, that is info that is attached to the constructor input. Hence the hack above ☝🏼 - var prop = speckleSchema - .GetInstanceMembers() - .Where(o => speckleSchema[o.Name] == null) - .FirstOrDefault(o => o.PropertyType.IsInstanceOfType(@object)); - if (prop != null) - speckleSchema[prop.Name] = @object; + speckleSchema[prop.Name] = @object; } - return speckleSchema; } + return speckleSchema; + } - public object ConvertToNative(Base @base) + public object ConvertToNative(Base @base) + { + var nativeObject = ConvertToNativeObject(@base); + + switch (nativeObject) { - var nativeObject = ConvertToNativeObject(@base); + case ApplicationObject appObject: + if (appObject.Converted.Cast().ToList() is List typedList && typedList.Count >= 1) + { + receivedObjectsCache?.AddConvertedObjects(@base, typedList); + } + break; + case Element element: + receivedObjectsCache?.AddConvertedObjects(@base, new List { element }); + break; + } - switch (nativeObject) - { - case ApplicationObject appObject: - if (appObject.Converted.Cast().ToList() is List typedList && typedList.Count >= 1) - { - receivedObjectsCache?.AddConvertedObjects(@base, typedList); - } - break; - case Element element: - receivedObjectsCache?.AddConvertedObjects(@base, new List { element }); - break; - } + return nativeObject; + } - return nativeObject; + public object ConvertToNativeObject(Base @object) + { + // Get setting for if the user is only trying to preview the geometry + Settings.TryGetValue("preview", out string isPreview); + if (bool.Parse(isPreview ?? "false") == true) + { + return PreviewGeometry(@object); } - public object ConvertToNativeObject(Base @object) + // Get settings for receive direct meshes , assumes objects aren't nested like in Tekla Structures + Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); + if (bool.Parse(recieveModelMesh ?? "false")) { - // Get setting for if the user is only trying to preview the geometry - Settings.TryGetValue("preview", out string isPreview); - if (bool.Parse(isPreview ?? "false") == true) - return PreviewGeometry(@object); - - // Get settings for receive direct meshes , assumes objects aren't nested like in Tekla Structures - Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); - if (bool.Parse(recieveModelMesh ?? "false")) - if ((@object is Other.Instance || @object.IsDisplayableObject()) && @object is not BE.Room) - return DisplayableObjectToNative(@object); - else - return null; - - //Family Document - if (Doc.IsFamilyDocument) + if ((@object is Other.Instance || @object.IsDisplayableObject()) && @object is not BE.Room) { - switch (@object) - { - case ICurve o: - return ModelCurveToNative(o); - case Geometry.Brep o: - return TryDirectShapeToNative(o, ToNativeMeshSettingEnum.Default); - case Geometry.Mesh o: - return TryDirectShapeToNative(o, ToNativeMeshSettingEnum.Default); - case BER.FreeformElement o: - return FreeformElementToNative(o); - default: - return null; - } + return DisplayableObjectToNative(@object); } + else + { + return null; + } + } - // Check if object has inner `SpeckleSchema` prop and swap if appropriate - @object = SwapGeometrySchemaObject(@object); - + //Family Document + if (Doc.IsFamilyDocument) + { switch (@object) { - //geometry case ICurve o: return ModelCurveToNative(o); case Geometry.Brep o: - return TryDirectShapeToNative(o, ToNativeMeshSetting); - case Geometry.Mesh mesh: - switch (ToNativeMeshSetting) - { - case ToNativeMeshSettingEnum.DxfImport: - return MeshToDxfImport(mesh, Doc); - case ToNativeMeshSettingEnum.DxfImportInFamily: - return MeshToDxfImportFamily(mesh, Doc); - case ToNativeMeshSettingEnum.Default: - default: - return TryDirectShapeToNative(mesh, ToNativeMeshSettingEnum.Default); - } - // non revit built elems - case BE.Alignment o: - if (o.curves is null) // TODO: remove after a few releases, this is for backwards compatibility - return ModelCurveToNative(o.baseCurve); + return TryDirectShapeToNative(o, ToNativeMeshSettingEnum.Default); + case Geometry.Mesh o: + return TryDirectShapeToNative(o, ToNativeMeshSettingEnum.Default); + case BER.FreeformElement o: + return FreeformElementToNative(o); + default: + return null; + } + } + + // Check if object has inner `SpeckleSchema` prop and swap if appropriate + @object = SwapGeometrySchemaObject(@object); + + switch (@object) + { + //geometry + case ICurve o: + return ModelCurveToNative(o); + case Geometry.Brep o: + return TryDirectShapeToNative(o, ToNativeMeshSetting); + case Geometry.Mesh mesh: + switch (ToNativeMeshSetting) + { + case ToNativeMeshSettingEnum.DxfImport: + return MeshToDxfImport(mesh, Doc); + case ToNativeMeshSettingEnum.DxfImportInFamily: + return MeshToDxfImportFamily(mesh, Doc); + case ToNativeMeshSettingEnum.Default: + default: + return TryDirectShapeToNative(mesh, ToNativeMeshSettingEnum.Default); + } + // non revit built elems + case BE.Alignment o: + if (o.curves is null) // TODO: remove after a few releases, this is for backwards compatibility + { + return ModelCurveToNative(o.baseCurve); + } - return AlignmentToNative(o); + return AlignmentToNative(o); - case BE.Structure o: - return TryDirectShapeToNative( - new ApplicationObject(o.id, o.speckle_type) { applicationId = o.applicationId }, - o.displayValue, - ToNativeMeshSetting - ); - //built elems - case BER.AdaptiveComponent o: - return AdaptiveComponentToNative(o); + case BE.Structure o: + return TryDirectShapeToNative( + new ApplicationObject(o.id, o.speckle_type) { applicationId = o.applicationId }, + o.displayValue, + ToNativeMeshSetting + ); + //built elems + case BER.AdaptiveComponent o: + return AdaptiveComponentToNative(o); - //case BE.TeklaStructures.TeklaBeam o: - // return TeklaBeamToNative(o); + //case BE.TeklaStructures.TeklaBeam o: + // return TeklaBeamToNative(o); - case BE.Beam o: - return BeamToNative(o); + case BE.Beam o: + return BeamToNative(o); - case BE.Brace o: - return BraceToNative(o); + case BE.Brace o: + return BraceToNative(o); - case BE.Column o: - return ColumnToNative(o); + case BE.Column o: + return ColumnToNative(o); #if REVIT2020 || REVIT2021 #else - case BE.Ceiling o: - return CeilingToNative(o); + case BE.Ceiling o: + return CeilingToNative(o); #endif - case BERC.DetailCurve o: - return DetailCurveToNative(o); + case BERC.DetailCurve o: + return DetailCurveToNative(o); - case BER.DirectShape o: - try - { - // Try to convert to direct shape, taking into account the current mesh settings - return DirectShapeToNative(o, ToNativeMeshSetting); - } - catch (FallbackToDxfException e) + case BER.DirectShape o: + try + { + // Try to convert to direct shape, taking into account the current mesh settings + return DirectShapeToNative(o, ToNativeMeshSetting); + } + catch (FallbackToDxfException e) + { + // FallbackToDxf exception means we should attempt a DXF import instead. + switch (ToNativeMeshSetting) { - // FallbackToDxf exception means we should attempt a DXF import instead. - switch (ToNativeMeshSetting) - { - case ToNativeMeshSettingEnum.DxfImport: - return DirectShapeToDxfImport(o); // DirectShape -> DXF - case ToNativeMeshSettingEnum.DxfImportInFamily: - return DirectShapeToDxfImportFamily(o); // DirectShape -> Family (DXF inside) - case ToNativeMeshSettingEnum.Default: - default: - // For anything else, try again with the default fallback (ugly meshes). - return DirectShapeToNative(o, ToNativeMeshSettingEnum.Default); - } + case ToNativeMeshSettingEnum.DxfImport: + return DirectShapeToDxfImport(o); // DirectShape -> DXF + case ToNativeMeshSettingEnum.DxfImportInFamily: + return DirectShapeToDxfImportFamily(o); // DirectShape -> Family (DXF inside) + case ToNativeMeshSettingEnum.Default: + default: + // For anything else, try again with the default fallback (ugly meshes). + return DirectShapeToNative(o, ToNativeMeshSettingEnum.Default); } + } - case BER.FreeformElement o: - return FreeformElementToNative(o); + case BER.FreeformElement o: + return FreeformElementToNative(o); - case BER.FamilyInstance o: - return FamilyInstanceToNative(o); + case BER.FamilyInstance o: + return FamilyInstanceToNative(o); - case BE.Network o: - return NetworkToNative(o); + case BE.Network o: + return NetworkToNative(o); - case BE.Floor o: - return FloorToNative(o); - case BE.Level o: - return LevelToNative(o); + case BE.Floor o: + return FloorToNative(o); + case BE.Level o: + return LevelToNative(o); - case BERC.ModelCurve o: - return ModelCurveToNative(o); + case BERC.ModelCurve o: + return ModelCurveToNative(o); - case BE.Opening o: - return OpeningToNative(o); + case BE.Opening o: + return OpeningToNative(o); - case BERC.RoomBoundaryLine o: - return RoomBoundaryLineToNative(o); + case BERC.RoomBoundaryLine o: + return RoomBoundaryLineToNative(o); - case BERC.SpaceSeparationLine o: - return SpaceSeparationLineToNative(o); + case BERC.SpaceSeparationLine o: + return SpaceSeparationLineToNative(o); - case BER.RevitRebarGroup o: - return RebarToNative(o); + case BER.RevitRebarGroup o: + return RebarToNative(o); - case BE.Roof o: - return RoofToNative(o); + case BE.Roof o: + return RoofToNative(o); - case BE.Topography o: - return TopographyToNative(o); + case BE.Topography o: + return TopographyToNative(o); - case BER.RevitCurtainWallPanel o: - return PanelToNative(o); + case BER.RevitCurtainWallPanel o: + return PanelToNative(o); - case BER.RevitProfileWall o: - return ProfileWallToNative(o); + case BER.RevitProfileWall o: + return ProfileWallToNative(o); - case BER.RevitFaceWall o: - return FaceWallToNativeV2(o); + case BER.RevitFaceWall o: + return FaceWallToNativeV2(o); - case BE.Wall o: - return WallToNative(o); + case BE.Wall o: + return WallToNative(o); - case BE.Duct o: - return DuctToNative(o); + case BE.Duct o: + return DuctToNative(o); - case BE.Pipe o: - return PipeToNative(o); + case BE.Pipe o: + return PipeToNative(o); - case BE.Wire o: - return WireToNative(o); + case BE.Wire o: + return WireToNative(o); - case BE.CableTray o: - return CableTrayToNative(o); + case BE.CableTray o: + return CableTrayToNative(o); - case BE.Conduit o: - return ConduitToNative(o); + case BE.Conduit o: + return ConduitToNative(o); - case BE.Revit.RevitRailing o: - return RailingToNative(o); + case BE.Revit.RevitRailing o: + return RailingToNative(o); - case BER.ParameterUpdater o: - return UpdateParameter(o); + case BER.ParameterUpdater o: + return UpdateParameter(o); - case BE.View3D o: - return ViewToNative(o); + case BE.View3D o: + return ViewToNative(o); - case RevitMEPFamilyInstance o: - return FittingOrMEPInstanceToNative(o); + case RevitMEPFamilyInstance o: + return FittingOrMEPInstanceToNative(o); - case Other.Revit.RevitInstance o: - return RevitInstanceToNative(o); + case Other.Revit.RevitInstance o: + return RevitInstanceToNative(o); - case BE.Room o: - return RoomToNative(o); + case BE.Room o: + return RoomToNative(o); - case BE.GridLine o: - return GridLineToNative(o); + case BE.GridLine o: + return GridLineToNative(o); - case DataTable o: - return DataTableToNative(o); + case DataTable o: + return DataTableToNative(o); - case BE.Space o: - return SpaceToNative(o); - //Structural - case STR.Geometry.Element1D o: - return AnalyticalStickToNative(o); + case BE.Space o: + return SpaceToNative(o); + //Structural + case STR.Geometry.Element1D o: + return AnalyticalStickToNative(o); - case STR.Geometry.Element2D o: - return AnalyticalSurfaceToNative(o); + case STR.Geometry.Element2D o: + return AnalyticalSurfaceToNative(o); - case STR.Geometry.Node o: - return AnalyticalNodeToNative(o); + case STR.Geometry.Node o: + return AnalyticalNodeToNative(o); - case STR.Analysis.Model o: - return StructuralModelToNative(o); + case STR.Analysis.Model o: + return StructuralModelToNative(o); - // other - case Other.BlockInstance o: - return BlockInstanceToNative(o); + // other + case Other.BlockInstance o: + return BlockInstanceToNative(o); - case Other.MappedBlockWrapper o: - return MappedBlockWrapperToNative(o); - // gis - case PolygonElement o: - return PolygonElementToNative(o); + case Other.MappedBlockWrapper o: + return MappedBlockWrapperToNative(o); + // gis + case PolygonElement o: + return PolygonElementToNative(o); #if (REVIT2024) - case RevitToposolid o: - return ToposolidToNative(o); + case RevitToposolid o: + return ToposolidToNative(o); #endif + //hacky but the current comments camera is not a Base object + //used only from DUI and not for normal geometry conversion + case Base b: //hacky but the current comments camera is not a Base object //used only from DUI and not for normal geometry conversion - case Base b: - //hacky but the current comments camera is not a Base object - //used only from DUI and not for normal geometry conversion - var boo = b["isHackySpeckleCamera"] as bool?; - if (boo == true) - return ViewOrientation3DToNative(b); - return null; + var boo = b["isHackySpeckleCamera"] as bool?; + if (boo == true) + { + return ViewOrientation3DToNative(b); + } - default: - return null; - } + return null; + + default: + return null; } + } - public object ConvertToNativeDisplayable(Base @base) + public object ConvertToNativeDisplayable(Base @base) + { + var nativeObject = DisplayableObjectToNative(@base); + if (nativeObject.Converted.Cast().ToList() is List typedList && typedList.Count >= 1) { - var nativeObject = DisplayableObjectToNative(@base); - if (nativeObject.Converted.Cast().ToList() is List typedList && typedList.Count >= 1) - { - receivedObjectsCache?.AddConvertedObjects(@base, typedList); - } - return nativeObject; + receivedObjectsCache?.AddConvertedObjects(@base, typedList); } + return nativeObject; + } - public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); + public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); - public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); + public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); - public bool CanConvertToSpeckle(object @object) + public bool CanConvertToSpeckle(object @object) + { + return @object switch { - return @object switch - { - DB.DetailCurve _ => true, - DB.Material _ => true, - DB.DirectShape _ => true, - DB.FamilyInstance _ => true, - DB.Floor _ => true, - DB.Level _ => true, - DB.View _ => true, - DB.ModelCurve _ => true, - DB.Opening _ => true, - DB.RoofBase _ => true, - DB.Area _ => true, - DB.Architecture.Room _ => true, - DB.Architecture.TopographySurface _ => true, - DB.Wall _ => true, - DB.Mechanical.Duct _ => true, - DB.Mechanical.FlexDuct _ => true, - DB.Mechanical.Space _ => true, - DB.Plumbing.Pipe _ => true, - DB.Plumbing.FlexPipe _ => true, - DB.Electrical.Wire _ => true, - DB.Electrical.CableTray _ => true, - DB.Electrical.Conduit _ => true, - DB.CurtainGridLine _ => true, //these should be handled by curtain walls - DB.Architecture.BuildingPad _ => true, - DB.Architecture.Stairs _ => true, - DB.Architecture.StairsRun _ => true, - DB.Architecture.StairsLanding _ => true, - DB.Architecture.Railing _ => true, - DB.Architecture.TopRail _ => true, - DB.Ceiling _ => true, - DB.PointCloudInstance _ => true, - DB.Group _ => true, - DB.ProjectInfo _ => true, - DB.ElementType _ => true, - DB.Grid _ => true, - DB.ReferencePoint _ => true, - DB.FabricationPart _ => true, - DB.CombinableElement _ => true, + DB.DetailCurve _ => true, + DB.Material _ => true, + DB.DirectShape _ => true, + DB.FamilyInstance _ => true, + DB.Floor _ => true, + DB.Level _ => true, + DB.View _ => true, + DB.ModelCurve _ => true, + DB.Opening _ => true, + DB.RoofBase _ => true, + DB.Area _ => true, + DB.Architecture.Room _ => true, + DB.Architecture.TopographySurface _ => true, + DB.Wall _ => true, + DB.Mechanical.Duct _ => true, + DB.Mechanical.FlexDuct _ => true, + DB.Mechanical.Space _ => true, + DB.Plumbing.Pipe _ => true, + DB.Plumbing.FlexPipe _ => true, + DB.Electrical.Wire _ => true, + DB.Electrical.CableTray _ => true, + DB.Electrical.Conduit _ => true, + DB.CurtainGridLine _ => true, //these should be handled by curtain walls + DB.Architecture.BuildingPad _ => true, + DB.Architecture.Stairs _ => true, + DB.Architecture.StairsRun _ => true, + DB.Architecture.StairsLanding _ => true, + DB.Architecture.Railing _ => true, + DB.Architecture.TopRail _ => true, + DB.Ceiling _ => true, + DB.PointCloudInstance _ => true, + DB.Group _ => true, + DB.ProjectInfo _ => true, + DB.ElementType _ => true, + DB.Grid _ => true, + DB.ReferencePoint _ => true, + DB.FabricationPart _ => true, + DB.CombinableElement _ => true, #if (REVIT2024) - DB.Toposolid _ => true, + DB.Toposolid _ => true, #endif #if REVIT2020 || REVIT2021 || REVIT2022 - DB.Structure.AnalyticalModelStick _ => true, - DB.Structure.AnalyticalModelSurface _ => true, + DB.Structure.AnalyticalModelStick _ => true, + DB.Structure.AnalyticalModelSurface _ => true, #else - DB.Structure.AnalyticalMember _ => true, - DB.Structure.AnalyticalPanel _ => true, + DB.Structure.AnalyticalMember _ => true, + DB.Structure.AnalyticalPanel _ => true, #endif - DB.Structure.BoundaryConditions _ => true, - _ => (@object as Element).IsElementSupported() - }; - } + DB.Structure.BoundaryConditions _ => true, + _ => (@object as Element).IsElementSupported() + }; + } - public bool CanConvertToNative(Base @object) + public bool CanConvertToNative(Base @object) + { + //Family Document + if (Doc.IsFamilyDocument) { - //Family Document - if (Doc.IsFamilyDocument) - { - return @object switch - { - ICurve _ => true, - Geometry.Brep _ => true, - Geometry.Mesh _ => true, - BER.FreeformElement _ => true, - _ => false - }; - } - - //Project Document - var schema = @object["@SpeckleSchema"] as Base; // check for contained schema - if (schema != null) - return CanConvertToNative(schema); - - var objRes = @object switch + return @object switch { - //geometry ICurve _ => true, Geometry.Brep _ => true, Geometry.Mesh _ => true, - // non revit built elems - BE.Structure _ => true, - BE.Alignment _ => true, - //built elems - BER.AdaptiveComponent _ => true, - BE.Beam _ => true, - BE.Brace _ => true, - BE.Column _ => true, + BER.FreeformElement _ => true, + _ => false + }; + } + + //Project Document + var schema = @object["@SpeckleSchema"] as Base; // check for contained schema + if (schema != null) + { + return CanConvertToNative(schema); + } + + var objRes = @object switch + { + //geometry + ICurve _ => true, + Geometry.Brep _ => true, + Geometry.Mesh _ => true, + // non revit built elems + BE.Structure _ => true, + BE.Alignment _ => true, + //built elems + BER.AdaptiveComponent _ => true, + BE.Beam _ => true, + BE.Brace _ => true, + BE.Column _ => true, #if !REVIT2020 && !REVIT2021 - BE.Ceiling _ => true, + BE.Ceiling _ => true, #endif - BERC.DetailCurve _ => true, - BER.DirectShape _ => true, - BER.FreeformElement _ => true, - BER.FamilyInstance _ => true, - BE.Floor _ => true, - BE.Level _ => true, - BERC.ModelCurve _ => true, - BE.Opening _ => true, - BERC.RoomBoundaryLine _ => true, - BERC.SpaceSeparationLine _ => true, - BE.Roof _ => true, + BERC.DetailCurve _ => true, + BER.DirectShape _ => true, + BER.FreeformElement _ => true, + BER.FamilyInstance _ => true, + BE.Floor _ => true, + BE.Level _ => true, + BERC.ModelCurve _ => true, + BE.Opening _ => true, + BERC.RoomBoundaryLine _ => true, + BERC.SpaceSeparationLine _ => true, + BE.Roof _ => true, #if (REVIT2024) - RevitToposolid _ => true, + RevitToposolid _ => true, #endif - BE.Topography _ => true, - BER.RevitCurtainWallPanel _ => true, - BER.RevitFaceWall _ => true, - BER.RevitProfileWall _ => true, - BE.Wall _ => true, - BE.Duct _ => true, - BE.Pipe _ => true, - BE.Wire _ => true, - BE.CableTray _ => true, - BE.Conduit _ => true, - BE.Revit.RevitRailing _ => true, - Other.Revit.RevitInstance _ => true, - BER.ParameterUpdater _ => true, - BE.View3D _ => true, - BE.Room _ => true, - BE.GridLine _ => true, - BE.Space _ => true, - BE.Network _ => true, - //Structural - STR.Geometry.Element1D _ => true, - STR.Geometry.Element2D _ => true, - Other.BlockInstance _ => true, - Other.MappedBlockWrapper => true, - Organization.DataTable _ => true, - // GIS - PolygonElement _ => true, - _ => false, - }; - if (objRes) - return true; - - return false; + BE.Topography _ => true, + BER.RevitCurtainWallPanel _ => true, + BER.RevitFaceWall _ => true, + BER.RevitProfileWall _ => true, + BE.Wall _ => true, + BE.Duct _ => true, + BE.Pipe _ => true, + BE.Wire _ => true, + BE.CableTray _ => true, + BE.Conduit _ => true, + BE.Revit.RevitRailing _ => true, + Other.Revit.RevitInstance _ => true, + BER.ParameterUpdater _ => true, + BE.View3D _ => true, + BE.Room _ => true, + BE.GridLine _ => true, + BE.Space _ => true, + BE.Network _ => true, + //Structural + STR.Geometry.Element1D _ => true, + STR.Geometry.Element2D _ => true, + Other.BlockInstance _ => true, + Other.MappedBlockWrapper => true, + Organization.DataTable _ => true, + // GIS + PolygonElement _ => true, + _ => false, + }; + if (objRes) + { + return true; } - public bool CanConvertToNativeDisplayable(Base @object) - { - // check for schema - var schema = @object["@SpeckleSchema"] as Base; // check for contained schema - if (schema != null) - return CanConvertToNativeDisplayable(schema); + return false; + } - return @object.IsDisplayableObject(); + public bool CanConvertToNativeDisplayable(Base @object) + { + // check for schema + var schema = @object["@SpeckleSchema"] as Base; // check for contained schema + if (schema != null) + { + return CanConvertToNativeDisplayable(schema); } + + return @object.IsDisplayableObject(); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevitShared.projitems b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevitShared.projitems index d9de737509..a42188f2c0 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevitShared.projitems +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevitShared.projitems @@ -28,69 +28,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/DirectContext3DServer.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/DirectContext3DServer.cs index a04425d06f..f488a548b6 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/DirectContext3DServer.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/DirectContext3DServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -11,449 +11,528 @@ using Speckle.Core.Models; using OG = Objects.Geometry; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public partial class ConverterRevit { - public partial class ConverterRevit + public static ConverterRevit Instance; + + public class DirectContext3DServer : IDirectContext3DServer { - public static ConverterRevit Instance; - public class DirectContext3DServer : IDirectContext3DServer + private Document document; + + private RenderingPassBufferStorage m_nonTransparentFaceBufferStorage; + private RenderingPassBufferStorage m_transparentFaceBufferStorage; + private RenderingPassBufferStorage m_edgeBufferStorage; + private Guid m_guid; + private IEnumerable speckleMeshes; + public OG.Point minValues = new(double.MaxValue, double.MaxValue, double.MaxValue); + public OG.Point maxValues = new(double.MinValue, double.MinValue, double.MinValue); + public bool allMeshesStored => + speckleMeshes.Count() + == m_nonTransparentFaceBufferStorage?.Meshes.Count + m_transparentFaceBufferStorage?.Meshes.Count; + + public DirectContext3DServer(IEnumerable meshes, Document doc) { - private Document document; - - private RenderingPassBufferStorage m_nonTransparentFaceBufferStorage; - private RenderingPassBufferStorage m_transparentFaceBufferStorage; - private RenderingPassBufferStorage m_edgeBufferStorage; - private Guid m_guid; - private IEnumerable speckleMeshes; - public OG.Point minValues = new OG.Point(double.MaxValue, double.MaxValue, double.MaxValue); - public OG.Point maxValues = new OG.Point(double.MinValue, double.MinValue, double.MinValue); - public bool allMeshesStored => speckleMeshes.Count() == m_nonTransparentFaceBufferStorage?.Meshes.Count + m_transparentFaceBufferStorage?.Meshes.Count; - public DirectContext3DServer(IEnumerable meshes, Document doc) - { - m_guid = Guid.NewGuid(); - speckleMeshes = meshes; - document = doc; - } - public bool CanExecute(View dBView) + m_guid = Guid.NewGuid(); + speckleMeshes = meshes; + document = doc; + } + + public bool CanExecute(View dBView) + { + //if (!m_element.IsValidObject) + // return false; + if (dBView.ViewType != ViewType.ThreeD) { - //if (!m_element.IsValidObject) - // return false; - if (dBView.ViewType != ViewType.ThreeD) - return false; - - Document doc = dBView.Document; - Document otherDoc = document; - return doc.Equals(otherDoc); + return false; } - public string GetApplicationId() => " "; - public Outline GetBoundingBox(View dBView) - { - //return new Outline(new XYZ(0, 0, 0), new XYZ(2, 2, 2)); - return new Outline - ( - new XYZ(minValues.x, minValues.y, minValues.z), - new XYZ(maxValues.x, maxValues.y, maxValues.z) - ); - } - public string GetDescription() => "Implements preview functionality for a Speckle Object"; - public string GetName() => "Speckle Object Drawing Server"; - public Guid GetServerId() => m_guid; - public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; - public string GetSourceId() => " "; - public string GetVendorId() => "Speckle"; - public void RenderScene(View dBView, DisplayStyle displayStyle) + Document doc = dBView.Document; + Document otherDoc = document; + return doc.Equals(otherDoc); + } + + public string GetApplicationId() => " "; + + public Outline GetBoundingBox(View dBView) + { + //return new Outline(new XYZ(0, 0, 0), new XYZ(2, 2, 2)); + + return new Outline( + new XYZ(minValues.x, minValues.y, minValues.z), + new XYZ(maxValues.x, maxValues.y, maxValues.z) + ); + } + + public string GetDescription() => "Implements preview functionality for a Speckle Object"; + + public string GetName() => "Speckle Object Drawing Server"; + + public Guid GetServerId() => m_guid; + + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + + public string GetSourceId() => " "; + + public string GetVendorId() => "Speckle"; + + public void RenderScene(View dBView, DisplayStyle displayStyle) + { + try { - try + // Populate geometry buffers if they are not initialized or need updating. + if ( + m_nonTransparentFaceBufferStorage == null + || m_nonTransparentFaceBufferStorage.NeedsUpdate(displayStyle) + || m_transparentFaceBufferStorage == null + || m_transparentFaceBufferStorage.NeedsUpdate(displayStyle) + || m_edgeBufferStorage == null + || m_edgeBufferStorage.NeedsUpdate(displayStyle) + ) { - // Populate geometry buffers if they are not initialized or need updating. - if (m_nonTransparentFaceBufferStorage == null || m_nonTransparentFaceBufferStorage.NeedsUpdate(displayStyle) || - m_transparentFaceBufferStorage == null || m_transparentFaceBufferStorage.NeedsUpdate(displayStyle) || - m_edgeBufferStorage == null || m_edgeBufferStorage.NeedsUpdate(displayStyle)) - { + CreateBufferStorageForMeshes(displayStyle); + } - CreateBufferStorageForMeshes(displayStyle); - } + // Submit a subset of the geometry for drawing. Determine what geometry should be submitted based on + // the type of the rendering pass (opaque or transparent) and DisplayStyle (wireframe or shaded). - // Submit a subset of the geometry for drawing. Determine what geometry should be submitted based on - // the type of the rendering pass (opaque or transparent) and DisplayStyle (wireframe or shaded). - - // If the server is requested to submit transparent geometry, DrawContext().IsTransparentPass() - // will indicate that the current rendering pass is for transparent objects. - RenderingPassBufferStorage faceBufferStorage = DrawContext.IsTransparentPass() ? m_transparentFaceBufferStorage : m_nonTransparentFaceBufferStorage; - - // Conditionally submit triangle primitives (for non-wireframe views). - if (displayStyle != DisplayStyle.Wireframe && - faceBufferStorage?.PrimitiveCount > 0) - DrawContext.FlushBuffer(faceBufferStorage.VertexBuffer, - faceBufferStorage.VertexBufferCount, - faceBufferStorage.IndexBuffer, - faceBufferStorage.IndexBufferCount, - faceBufferStorage.VertexFormat, - faceBufferStorage.EffectInstance, PrimitiveType.TriangleList, 0, - faceBufferStorage.PrimitiveCount); - - // Conditionally submit line segment primitives. - if (displayStyle == DisplayStyle.Wireframe && - displayStyle != DisplayStyle.Shading && - m_edgeBufferStorage?.PrimitiveCount > 0) - DrawContext.FlushBuffer(m_edgeBufferStorage.VertexBuffer, - m_edgeBufferStorage.VertexBufferCount, - m_edgeBufferStorage.IndexBuffer, - m_edgeBufferStorage.IndexBufferCount, - m_edgeBufferStorage.VertexFormat, - m_edgeBufferStorage.EffectInstance, PrimitiveType.LineList, 0, - m_edgeBufferStorage.PrimitiveCount); + // If the server is requested to submit transparent geometry, DrawContext().IsTransparentPass() + // will indicate that the current rendering pass is for transparent objects. + RenderingPassBufferStorage faceBufferStorage = DrawContext.IsTransparentPass() + ? m_transparentFaceBufferStorage + : m_nonTransparentFaceBufferStorage; + + // Conditionally submit triangle primitives (for non-wireframe views). + if (displayStyle != DisplayStyle.Wireframe && faceBufferStorage?.PrimitiveCount > 0) + { + DrawContext.FlushBuffer( + faceBufferStorage.VertexBuffer, + faceBufferStorage.VertexBufferCount, + faceBufferStorage.IndexBuffer, + faceBufferStorage.IndexBufferCount, + faceBufferStorage.VertexFormat, + faceBufferStorage.EffectInstance, + PrimitiveType.TriangleList, + 0, + faceBufferStorage.PrimitiveCount + ); } - catch (Exception e) + + // Conditionally submit line segment primitives. + if ( + displayStyle == DisplayStyle.Wireframe + && displayStyle != DisplayStyle.Shading + && m_edgeBufferStorage?.PrimitiveCount > 0 + ) { - System.Diagnostics.Debug.WriteLine(e.ToString()); + DrawContext.FlushBuffer( + m_edgeBufferStorage.VertexBuffer, + m_edgeBufferStorage.VertexBufferCount, + m_edgeBufferStorage.IndexBuffer, + m_edgeBufferStorage.IndexBufferCount, + m_edgeBufferStorage.VertexFormat, + m_edgeBufferStorage.EffectInstance, + PrimitiveType.LineList, + 0, + m_edgeBufferStorage.PrimitiveCount + ); } } - public bool UseInTransparentPass(View dBView) => true; - public bool UsesHandles() => false; - - private void CreateBufferStorageForMeshes(DisplayStyle displayStyle) + catch (Exception e) { - if (allMeshesStored) - RefreshBufferStorage(displayStyle); - else - foreach (var mesh in speckleMeshes) - CreateBufferStorageForMesh(mesh, displayStyle); + System.Diagnostics.Debug.WriteLine(e.ToString()); } + } + + public bool UseInTransparentPass(View dBView) => true; + + public bool UsesHandles() => false; - private void RefreshBufferStorage(DisplayStyle displayStyle) + private void CreateBufferStorageForMeshes(DisplayStyle displayStyle) + { + if (allMeshesStored) { - m_nonTransparentFaceBufferStorage.DisplayStyle = displayStyle; - m_transparentFaceBufferStorage.DisplayStyle = displayStyle; - m_edgeBufferStorage.DisplayStyle = displayStyle; - - // Fill out buffers with primitives based on the intermediate information about faces and edges. - ProcessFaces(m_nonTransparentFaceBufferStorage); - ProcessFaces(m_transparentFaceBufferStorage); - if (displayStyle == DisplayStyle.Wireframe) - ProcessEdges(m_edgeBufferStorage); + RefreshBufferStorage(displayStyle); } - - // Initialize and populate buffers that hold graphics primitives, set up related parameters that are needed for drawing. - private void CreateBufferStorageForMesh(OG.Mesh mesh, DisplayStyle displayStyle) + else { - ColorWithTransparency color = null; - if (mesh["renderMaterial"] is Objects.Other.RenderMaterial mat) + foreach (var mesh in speckleMeshes) { - // System.Drawing.Color treats the A value as opacity, with 255 being fully opaque. - // Revit interprets the A value as transparency, with 0 being fully opaque and 255 being fully transparent - // so we need to translate the A value as below - color = new ColorWithTransparency(mat.diffuseColor.R, mat.diffuseColor.G, mat.diffuseColor.B, Math.Max((uint)(255 - mat.diffuseColor.A * mat.opacity), 0)); + CreateBufferStorageForMesh(mesh, displayStyle); } + } + } - color ??= new ColorWithTransparency(255, 255, 255, 0); - var meshInfo = new SpeckleMeshInfo(mesh, color, ref minValues, ref maxValues); + private void RefreshBufferStorage(DisplayStyle displayStyle) + { + m_nonTransparentFaceBufferStorage.DisplayStyle = displayStyle; + m_transparentFaceBufferStorage.DisplayStyle = displayStyle; + m_edgeBufferStorage.DisplayStyle = displayStyle; + + // Fill out buffers with primitives based on the intermediate information about faces and edges. + ProcessFaces(m_nonTransparentFaceBufferStorage); + ProcessFaces(m_transparentFaceBufferStorage); + if (displayStyle == DisplayStyle.Wireframe) + { + ProcessEdges(m_edgeBufferStorage); + } + } - m_nonTransparentFaceBufferStorage ??= new RenderingPassBufferStorage(displayStyle); - m_transparentFaceBufferStorage ??= new RenderingPassBufferStorage(displayStyle); - m_edgeBufferStorage ??= new RenderingPassBufferStorage(displayStyle); + // Initialize and populate buffers that hold graphics primitives, set up related parameters that are needed for drawing. + private void CreateBufferStorageForMesh(OG.Mesh mesh, DisplayStyle displayStyle) + { + ColorWithTransparency color = null; + if (mesh["renderMaterial"] is Objects.Other.RenderMaterial mat) + { + // System.Drawing.Color treats the A value as opacity, with 255 being fully opaque. + // Revit interprets the A value as transparency, with 0 being fully opaque and 255 being fully transparent + // so we need to translate the A value as below + color = new ColorWithTransparency( + mat.diffuseColor.R, + mat.diffuseColor.G, + mat.diffuseColor.B, + Math.Max((uint)(255 - mat.diffuseColor.A * mat.opacity), 0) + ); + } - if (color.GetTransparency() != 0) - { - m_transparentFaceBufferStorage.Meshes.Add(meshInfo); - m_transparentFaceBufferStorage.VertexBufferCount += meshInfo.Mesh.VerticesCount; - m_transparentFaceBufferStorage.PrimitiveCount += meshInfo.Faces.Count; - } - else - { - m_nonTransparentFaceBufferStorage.Meshes.Add(meshInfo); - m_nonTransparentFaceBufferStorage.VertexBufferCount += meshInfo.Mesh.VerticesCount; - m_nonTransparentFaceBufferStorage.PrimitiveCount += meshInfo.Faces.Count; - } + color ??= new ColorWithTransparency(255, 255, 255, 0); + var meshInfo = new SpeckleMeshInfo(mesh, color, ref minValues, ref maxValues); - foreach (var xyzs in meshInfo.XYZs) - { - m_edgeBufferStorage.VertexBufferCount += xyzs.Count; - m_edgeBufferStorage.PrimitiveCount += xyzs.Count - 1; - m_edgeBufferStorage.EdgeXYZs.Add(xyzs); - } + m_nonTransparentFaceBufferStorage ??= new RenderingPassBufferStorage(displayStyle); + m_transparentFaceBufferStorage ??= new RenderingPassBufferStorage(displayStyle); + m_edgeBufferStorage ??= new RenderingPassBufferStorage(displayStyle); - RefreshBufferStorage(displayStyle); + if (color.GetTransparency() != 0) + { + m_transparentFaceBufferStorage.Meshes.Add(meshInfo); + m_transparentFaceBufferStorage.VertexBufferCount += meshInfo.Mesh.VerticesCount; + m_transparentFaceBufferStorage.PrimitiveCount += meshInfo.Faces.Count; + } + else + { + m_nonTransparentFaceBufferStorage.Meshes.Add(meshInfo); + m_nonTransparentFaceBufferStorage.VertexBufferCount += meshInfo.Mesh.VerticesCount; + m_nonTransparentFaceBufferStorage.PrimitiveCount += meshInfo.Faces.Count; } - private void ProcessFaces(RenderingPassBufferStorage bufferStorage) + foreach (var xyzs in meshInfo.XYZs) { - List meshes = bufferStorage.Meshes; - List numVerticesInMeshesBefore = new List(); - if (meshes.Count == 0) return; + m_edgeBufferStorage.VertexBufferCount += xyzs.Count; + m_edgeBufferStorage.PrimitiveCount += xyzs.Count - 1; + m_edgeBufferStorage.EdgeXYZs.Add(xyzs); + } + + RefreshBufferStorage(displayStyle); + } + + private void ProcessFaces(RenderingPassBufferStorage bufferStorage) + { + List meshes = bufferStorage.Meshes; + List numVerticesInMeshesBefore = new(); + if (meshes.Count == 0) + { + return; + } - bool useNormals = bufferStorage.DisplayStyle == DisplayStyle.Shading || - bufferStorage.DisplayStyle == DisplayStyle.ShadingWithEdges; + bool useNormals = + bufferStorage.DisplayStyle == DisplayStyle.Shading + || bufferStorage.DisplayStyle == DisplayStyle.ShadingWithEdges; - // Vertex attributes are stored sequentially in vertex buffers. The attributes can include position, normal vector, and color. - // All vertices within a vertex buffer must have the same format. Possible formats are enumerated by VertexFormatBits. - // Vertex format also determines the type of rendering effect that can be used with the vertex buffer. In this sample, - // the color is always encoded in the vertex attributes. + // Vertex attributes are stored sequentially in vertex buffers. The attributes can include position, normal vector, and color. + // All vertices within a vertex buffer must have the same format. Possible formats are enumerated by VertexFormatBits. + // Vertex format also determines the type of rendering effect that can be used with the vertex buffer. In this sample, + // the color is always encoded in the vertex attributes. - bufferStorage.FormatBits = useNormals ? VertexFormatBits.PositionNormalColored : VertexFormatBits.PositionColored; + bufferStorage.FormatBits = useNormals ? VertexFormatBits.PositionNormalColored : VertexFormatBits.PositionColored; - // The format of the vertices determines the size of the vertex buffer. - int vertexBufferSizeInFloats = (useNormals ? VertexPositionNormalColored.GetSizeInFloats() : VertexPositionColored.GetSizeInFloats()) * - bufferStorage.VertexBufferCount; - numVerticesInMeshesBefore.Add(0); + // The format of the vertices determines the size of the vertex buffer. + int vertexBufferSizeInFloats = + (useNormals ? VertexPositionNormalColored.GetSizeInFloats() : VertexPositionColored.GetSizeInFloats()) + * bufferStorage.VertexBufferCount; + numVerticesInMeshesBefore.Add(0); - bufferStorage.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); - bufferStorage.VertexBuffer.Map(vertexBufferSizeInFloats); + bufferStorage.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + bufferStorage.VertexBuffer.Map(vertexBufferSizeInFloats); - if (useNormals) //must use normals for shaded displayStyle + if (useNormals) //must use normals for shaded displayStyle + { + // A VertexStream is used to write data into a VertexBuffer. + VertexStreamPositionNormalColored vertexStream = + bufferStorage.VertexBuffer.GetVertexStreamPositionNormalColored(); + foreach (SpeckleMeshInfo meshInfo in meshes) { - // A VertexStream is used to write data into a VertexBuffer. - VertexStreamPositionNormalColored vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPositionNormalColored(); - foreach (SpeckleMeshInfo meshInfo in meshes) + OG.Mesh mesh = meshInfo.Mesh; + var addedVertexIndicies = new List(); + for (var i = 0; i < meshInfo.Faces.Count; i++) { - OG.Mesh mesh = meshInfo.Mesh; - var addedVertexIndicies = new List(); - for (var i = 0; i < meshInfo.Faces.Count; i++) + foreach (var index in meshInfo.Faces[i]) { - foreach (var index in meshInfo.Faces[i]) + if (addedVertexIndicies.Contains(index)) { - if (addedVertexIndicies.Contains(index)) - continue; - - var p1 = meshInfo.Vertices.ElementAt(index); - vertexStream.AddVertex(new VertexPositionNormalColored(p1, meshInfo.Normals.ElementAt(i), meshInfo.ColorWithTransparency)); - addedVertexIndicies.Add(index); + continue; } + + var p1 = meshInfo.Vertices.ElementAt(index); + vertexStream.AddVertex( + new VertexPositionNormalColored(p1, meshInfo.Normals.ElementAt(i), meshInfo.ColorWithTransparency) + ); + addedVertexIndicies.Add(index); } - numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.VerticesCount); } + numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.VerticesCount); } - else + } + else + { + // A VertexStream is used to write data into a VertexBuffer. + VertexStreamPositionColored vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPositionColored(); + foreach (SpeckleMeshInfo meshInfo in meshes) { - // A VertexStream is used to write data into a VertexBuffer. - VertexStreamPositionColored vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPositionColored(); - foreach (SpeckleMeshInfo meshInfo in meshes) - { - OG.Mesh mesh = meshInfo.Mesh; - - foreach (XYZ vertex in meshInfo.Vertices) - vertexStream.AddVertex(new VertexPositionColored(vertex, meshInfo.ColorWithTransparency)); + OG.Mesh mesh = meshInfo.Mesh; - numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.VerticesCount); + foreach (XYZ vertex in meshInfo.Vertices) + { + vertexStream.AddVertex(new VertexPositionColored(vertex, meshInfo.ColorWithTransparency)); } + + numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.VerticesCount); } + } - bufferStorage.VertexBuffer.Unmap(); + bufferStorage.VertexBuffer.Unmap(); - // Primitives are specified using a pair of vertex and index buffers. An index buffer contains a sequence of indices into - // the associated vertex buffer, each index referencing a particular vertex. + // Primitives are specified using a pair of vertex and index buffers. An index buffer contains a sequence of indices into + // the associated vertex buffer, each index referencing a particular vertex. - int meshNumber = 0; - bufferStorage.IndexBufferCount = bufferStorage.PrimitiveCount * IndexTriangle.GetSizeInShortInts(); - int indexBufferSizeInShortInts = 1 * bufferStorage.IndexBufferCount; - bufferStorage.IndexBuffer = new IndexBuffer(indexBufferSizeInShortInts); - bufferStorage.IndexBuffer.Map(indexBufferSizeInShortInts); + int meshNumber = 0; + bufferStorage.IndexBufferCount = bufferStorage.PrimitiveCount * IndexTriangle.GetSizeInShortInts(); + int indexBufferSizeInShortInts = 1 * bufferStorage.IndexBufferCount; + bufferStorage.IndexBuffer = new IndexBuffer(indexBufferSizeInShortInts); + bufferStorage.IndexBuffer.Map(indexBufferSizeInShortInts); + { + // An IndexStream is used to write data into an IndexBuffer. + IndexStreamTriangle indexStream = bufferStorage.IndexBuffer.GetIndexStreamTriangle(); + foreach (SpeckleMeshInfo meshInfo in meshes) { - // An IndexStream is used to write data into an IndexBuffer. - IndexStreamTriangle indexStream = bufferStorage.IndexBuffer.GetIndexStreamTriangle(); - foreach (SpeckleMeshInfo meshInfo in meshes) + var mesh = meshInfo.Mesh; + int startIndex = numVerticesInMeshesBefore[meshNumber]; + foreach (var face in meshInfo.Faces) { - var mesh = meshInfo.Mesh; - int startIndex = numVerticesInMeshesBefore[meshNumber]; - foreach (var face in meshInfo.Faces) - { - // Add three indices that define a triangle. - indexStream.AddTriangle(new IndexTriangle(startIndex + face[0], - startIndex + face[1], - startIndex + face[2])); - } - meshNumber++; + // Add three indices that define a triangle. + indexStream.AddTriangle( + new IndexTriangle(startIndex + face[0], startIndex + face[1], startIndex + face[2]) + ); } + meshNumber++; } - bufferStorage.IndexBuffer.Unmap(); - - - // VertexFormat is a specification of the data that is associated with a vertex (e.g., position). - bufferStorage.VertexFormat = new VertexFormat(bufferStorage.FormatBits); - // Effect instance is a specification of the appearance of geometry. For example, it may be used to specify color, if there is no color information provided with the vertices. - bufferStorage.EffectInstance = new EffectInstance(bufferStorage.FormatBits); } + bufferStorage.IndexBuffer.Unmap(); + + // VertexFormat is a specification of the data that is associated with a vertex (e.g., position). + bufferStorage.VertexFormat = new VertexFormat(bufferStorage.FormatBits); + // Effect instance is a specification of the appearance of geometry. For example, it may be used to specify color, if there is no color information provided with the vertices. + bufferStorage.EffectInstance = new EffectInstance(bufferStorage.FormatBits); + } - // A helper function, analogous to ProcessFaces. - private void ProcessEdges(RenderingPassBufferStorage bufferStorage) + // A helper function, analogous to ProcessFaces. + private void ProcessEdges(RenderingPassBufferStorage bufferStorage) + { + List> edges = bufferStorage.EdgeXYZs; + if (edges.Count == 0) { - List> edges = bufferStorage.EdgeXYZs; - if (edges.Count == 0) - return; + return; + } - // Edges are encoded as line segment primitives whose vertices contain only position information. - bufferStorage.FormatBits = VertexFormatBits.Position; + // Edges are encoded as line segment primitives whose vertices contain only position information. + bufferStorage.FormatBits = VertexFormatBits.Position; - int edgeVertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * bufferStorage.VertexBufferCount; - List numVerticesInEdgesBefore = new List(); - numVerticesInEdgesBefore.Add(0); + int edgeVertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * bufferStorage.VertexBufferCount; + List numVerticesInEdgesBefore = new(); + numVerticesInEdgesBefore.Add(0); - bufferStorage.VertexBuffer = new VertexBuffer(edgeVertexBufferSizeInFloats); - bufferStorage.VertexBuffer.Map(edgeVertexBufferSizeInFloats); + bufferStorage.VertexBuffer = new VertexBuffer(edgeVertexBufferSizeInFloats); + bufferStorage.VertexBuffer.Map(edgeVertexBufferSizeInFloats); + { + VertexStreamPosition vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPosition(); + foreach (IList xyzs in edges) { - VertexStreamPosition vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPosition(); - foreach (IList xyzs in edges) + foreach (XYZ vertex in xyzs) { - foreach (XYZ vertex in xyzs) - { - vertexStream.AddVertex(new VertexPosition(vertex)); - } - - numVerticesInEdgesBefore.Add(numVerticesInEdgesBefore.Last() + xyzs.Count); + vertexStream.AddVertex(new VertexPosition(vertex)); } + + numVerticesInEdgesBefore.Add(numVerticesInEdgesBefore.Last() + xyzs.Count); } - bufferStorage.VertexBuffer.Unmap(); + } + bufferStorage.VertexBuffer.Unmap(); - int edgeNumber = 0; - bufferStorage.IndexBufferCount = bufferStorage.PrimitiveCount * IndexLine.GetSizeInShortInts(); - int indexBufferSizeInShortInts = 1 * bufferStorage.IndexBufferCount; - bufferStorage.IndexBuffer = new IndexBuffer(indexBufferSizeInShortInts); - bufferStorage.IndexBuffer.Map(indexBufferSizeInShortInts); + int edgeNumber = 0; + bufferStorage.IndexBufferCount = bufferStorage.PrimitiveCount * IndexLine.GetSizeInShortInts(); + int indexBufferSizeInShortInts = 1 * bufferStorage.IndexBufferCount; + bufferStorage.IndexBuffer = new IndexBuffer(indexBufferSizeInShortInts); + bufferStorage.IndexBuffer.Map(indexBufferSizeInShortInts); + { + IndexStreamLine indexStream = bufferStorage.IndexBuffer.GetIndexStreamLine(); + foreach (IList xyzs in edges) { - IndexStreamLine indexStream = bufferStorage.IndexBuffer.GetIndexStreamLine(); - foreach (IList xyzs in edges) + int startIndex = numVerticesInEdgesBefore[edgeNumber]; + for (int i = 1; i < xyzs.Count; i++) { - int startIndex = numVerticesInEdgesBefore[edgeNumber]; - for (int i = 1; i < xyzs.Count; i++) - { - // Add two indices that define a line segment. - indexStream.AddLine(new IndexLine((int)(startIndex + i - 1), - (int)(startIndex + i))); - } - edgeNumber++; + // Add two indices that define a line segment. + indexStream.AddLine(new IndexLine((int)(startIndex + i - 1), (int)(startIndex + i))); } + edgeNumber++; } - bufferStorage.IndexBuffer.Unmap(); + } + bufferStorage.IndexBuffer.Unmap(); + bufferStorage.VertexFormat = new VertexFormat(bufferStorage.FormatBits); + bufferStorage.EffectInstance = new EffectInstance(bufferStorage.FormatBits); + } - bufferStorage.VertexFormat = new VertexFormat(bufferStorage.FormatBits); - bufferStorage.EffectInstance = new EffectInstance(bufferStorage.FormatBits); - } + #region Helper classes - #region Helper classes + // A class that brings together all the data and rendering parameters that are needed to draw one sequence of primitives (e.g., triangles) + // with the same format and appearance. + class RenderingPassBufferStorage + { + public RenderingPassBufferStorage(DisplayStyle displayStyle) + { + DisplayStyle = displayStyle; + Meshes = new List(); + EdgeXYZs = new List>(); + } - // A class that brings together all the data and rendering parameters that are needed to draw one sequence of primitives (e.g., triangles) - // with the same format and appearance. - class RenderingPassBufferStorage + public bool NeedsUpdate(DisplayStyle newDisplayStyle) { - public RenderingPassBufferStorage(DisplayStyle displayStyle) + if (newDisplayStyle != DisplayStyle) { - DisplayStyle = displayStyle; - Meshes = new List(); - EdgeXYZs = new List>(); + return true; } - public bool NeedsUpdate(DisplayStyle newDisplayStyle) + if (PrimitiveCount > 0) { - if (newDisplayStyle != DisplayStyle) + if ( + VertexBuffer == null + || !VertexBuffer.IsValid() + || IndexBuffer == null + || !IndexBuffer.IsValid() + || VertexFormat == null + || !VertexFormat.IsValid() + || EffectInstance == null + || !EffectInstance.IsValid() + ) + { return true; - - if (PrimitiveCount > 0) - if (VertexBuffer == null || !VertexBuffer.IsValid() || - IndexBuffer == null || !IndexBuffer.IsValid() || - VertexFormat == null || !VertexFormat.IsValid() || - EffectInstance == null || !EffectInstance.IsValid()) - return true; - - return false; + } } - public DisplayStyle DisplayStyle { get; set; } + return false; + } + + public DisplayStyle DisplayStyle { get; set; } - public VertexFormatBits FormatBits { get; set; } + public VertexFormatBits FormatBits { get; set; } - public List Meshes { get; set; } - public List> EdgeXYZs { get; set; } + public List Meshes { get; set; } + public List> EdgeXYZs { get; set; } - public int PrimitiveCount { get; set; } - public int VertexBufferCount { get; set; } - public int IndexBufferCount { get; set; } - public VertexBuffer VertexBuffer { get; set; } - public IndexBuffer IndexBuffer { get; set; } - public VertexFormat VertexFormat { get; set; } - public EffectInstance EffectInstance { get; set; } - } + public int PrimitiveCount { get; set; } + public int VertexBufferCount { get; set; } + public int IndexBufferCount { get; set; } + public VertexBuffer VertexBuffer { get; set; } + public IndexBuffer IndexBuffer { get; set; } + public VertexFormat VertexFormat { get; set; } + public EffectInstance EffectInstance { get; set; } + } - public class SpeckleMeshInfo + public class SpeckleMeshInfo + { + public OG.Mesh Mesh; + public List Vertices = new(); + public List Faces; + public List> XYZs = new(); + public List Normals = new(); + public ColorWithTransparency ColorWithTransparency; + + public SpeckleMeshInfo(OG.Mesh mesh, ColorWithTransparency color, ref OG.Point minValues, ref OG.Point maxValue) { - public OG.Mesh Mesh; - public List Vertices = new List(); - public List Faces; - public List> XYZs = new List>(); - public List Normals = new List(); - public ColorWithTransparency ColorWithTransparency; - - public SpeckleMeshInfo(OG.Mesh mesh, ColorWithTransparency color, ref OG.Point minValues, ref OG.Point maxValue) + Mesh = mesh; + ColorWithTransparency = color; + Faces = GetFaceIndices(mesh).ToList(); + + foreach (var vertex in mesh.GetPoints()) + { + Vertices.Add(Instance.PointToNative(vertex)); + } + + var edges = new List<(int, int)>(); + var faceIndex = 0; + foreach (var indices in Faces) { - Mesh = mesh; - ColorWithTransparency = color; - Faces = GetFaceIndices(mesh).ToList(); + var vectorA = Vertices.ElementAt(indices[0]); + var vectorB = Vertices.ElementAt(indices[1]); + var vectorC = Vertices.ElementAt(indices[2]); + var result = (vectorB - vectorA).CrossProduct(vectorC - vectorA).Normalize(); - foreach(var vertex in mesh.GetPoints()) - Vertices.Add(Instance.PointToNative(vertex)); + try + { + Normals.Add(result); + } + catch (Exception ex) + { + Normals.Add(new XYZ(0, 0, 1)); + } - var edges = new List<(int, int)>(); - var faceIndex = 0; - foreach (var indices in Faces) + for (var j = 0; j < indices.Length; j++) { - var vectorA = Vertices.ElementAt(indices[0]); - var vectorB = Vertices.ElementAt(indices[1]); - var vectorC = Vertices.ElementAt(indices[2]); - var result = (vectorB - vectorA).CrossProduct(vectorC - vectorA).Normalize(); + var iA = indices[j]; + var iB = indices[(j + 1) % indices.Length]; + var temp = iA; + iA = temp < iB ? iA : iB; + iB = temp < iB ? iB : temp; - try - { - Normals.Add(result); - } - catch (Exception ex) + if (edges.Contains((iA, iB))) { - Normals.Add(new XYZ(0, 0, 1)); + continue; } - for (var j = 0; j < indices.Length; j++) - { - var iA = indices[j]; - var iB = indices[(j + 1) % indices.Length]; - var temp = iA; - iA = temp < iB ? iA : iB; - iB = temp < iB ? iB : temp; - - if (edges.Contains((iA, iB))) - continue; - - edges.Add((iA, iB)); - var p1 = Vertices.ElementAt(iA); - var p2 = Vertices.ElementAt(iB); - XYZs.Add(new List { p1, p2 }); + edges.Add((iA, iB)); + var p1 = Vertices.ElementAt(iA); + var p2 = Vertices.ElementAt(iB); + XYZs.Add(new List { p1, p2 }); - minValues.x = Math.Min(minValues.x, Math.Min(p1.X, p2.X)); - minValues.y = Math.Min(minValues.y, Math.Min(p1.Y, p2.Y)); - minValues.z = Math.Min(minValues.z, Math.Min(p1.Z, p2.Z)); + minValues.x = Math.Min(minValues.x, Math.Min(p1.X, p2.X)); + minValues.y = Math.Min(minValues.y, Math.Min(p1.Y, p2.Y)); + minValues.z = Math.Min(minValues.z, Math.Min(p1.Z, p2.Z)); - maxValue.x = Math.Max(maxValue.x, Math.Max(p1.X, p2.X)); - maxValue.y = Math.Max(maxValue.y, Math.Max(p1.Y, p2.Y)); - maxValue.z = Math.Max(maxValue.z, Math.Max(p1.Z, p2.Z)); - } - faceIndex++; + maxValue.x = Math.Max(maxValue.x, Math.Max(p1.X, p2.X)); + maxValue.y = Math.Max(maxValue.y, Math.Max(p1.Y, p2.Y)); + maxValue.z = Math.Max(maxValue.z, Math.Max(p1.Z, p2.Z)); } + faceIndex++; } - public static IEnumerable GetFaceIndices(OG.Mesh mesh) + } + + public static IEnumerable GetFaceIndices(OG.Mesh mesh) + { + var i = 0; + while (i < mesh.faces.Count) { - var i = 0; - while (i < mesh.faces.Count) + var n = mesh.faces[i]; + if (n < 3) { - var n = mesh.faces[i]; - if (n < 3) n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility - - var points = mesh.faces.GetRange(i + 1, n).ToArray(); - yield return points; - i += n + 1; + n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility } + + var points = mesh.faces.GetRange(i + 1, n).ToArray(); + yield return points; + i += n + 1; } } - - #endregion } + + #endregion } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/CategoryExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/CategoryExtensions.cs index 30a8851be6..33bb170541 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/CategoryExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/CategoryExtensions.cs @@ -1,16 +1,15 @@ using Autodesk.Revit.DB; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +internal static class CategoryExtensions { - internal static class CategoryExtensions + public static bool EqualsBuiltInCategory(this Category category, BuiltInCategory builtInCategory) { - public static bool EqualsBuiltInCategory(this Category category, BuiltInCategory builtInCategory) - { # if REVIT2020 || REVIT2021 || REVIT2022 - return category.Id.IntegerValue == (int)builtInCategory; + return category.Id.IntegerValue == (int)builtInCategory; #else - return category.BuiltInCategory == builtInCategory; + return category.BuiltInCategory == builtInCategory; #endif - } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ConnectorExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ConnectorExtensions.cs index 845fd1c342..c94b559099 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ConnectorExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ConnectorExtensions.cs @@ -3,13 +3,12 @@ using System.Text; using Autodesk.Revit.DB; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +internal static class ConnectorExtensions { - internal static class ConnectorExtensions + public static string GetUniqueApplicationId(this Connector connector) { - public static string GetUniqueApplicationId(this Connector connector) - { - return $"{connector.Owner.UniqueId}.{connector.Id}"; - } + return $"{connector.Owner.UniqueId}.{connector.Id}"; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DefinitionExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DefinitionExtensions.cs index 15a701af42..c0f4794410 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DefinitionExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DefinitionExtensions.cs @@ -4,26 +4,29 @@ using Autodesk.Revit.DB; using Objects.Primitive; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +public static class DefinitionExtensions { - public static class DefinitionExtensions + public static bool IsBool(this Definition definition) { - public static bool IsBool(this Definition definition) - { #if REVIT2020 || REVIT2021 || REVIT2022 - switch (definition.ParameterType) - { - case ParameterType.YesNo: - return true; - default: - return false; - } -#else - if (definition.GetDataType() == SpecTypeId.Boolean.YesNo) + switch (definition.ParameterType) + { + case ParameterType.YesNo: return true; - else + default: return false; -#endif } +#else + if (definition.GetDataType() == SpecTypeId.Boolean.YesNo) + { + return true; + } + else + { + return false; + } +#endif } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DisplayUnitTypeExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DisplayUnitTypeExtensions.cs index 81fd7e3a04..08deefd559 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DisplayUnitTypeExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/DisplayUnitTypeExtensions.cs @@ -3,25 +3,24 @@ using System.Linq; using Autodesk.Revit.DB; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +internal static class DisplayUnitTypeExtensions { - internal static class DisplayUnitTypeExtensions + public static string? GetSymbol(this DisplayUnitType displayUnitType) { - public static string? GetSymbol(this DisplayUnitType displayUnitType) + var validSymbols = FormatOptions.GetValidUnitSymbols(displayUnitType); + var unitSymbolTypes = validSymbols.Where(x => x != UnitSymbolType.UST_NONE); + foreach (var symbolId in unitSymbolTypes) { - var validSymbols = FormatOptions.GetValidUnitSymbols(displayUnitType); - var unitSymbolTypes = validSymbols.Where(x => x != UnitSymbolType.UST_NONE); - foreach (var symbolId in unitSymbolTypes) - { - return LabelUtils.GetLabelFor(symbolId); - } - return null; + return LabelUtils.GetLabelFor(symbolId); } + return null; + } - public static string ToUniqueString(this DisplayUnitType displayUnitType) - { - return displayUnitType.ToString(); - } + public static string ToUniqueString(this DisplayUnitType displayUnitType) + { + return displayUnitType.ToString(); } } #endif diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ElementExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ElementExtensions.cs index a16fe4297b..3daa8a776d 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ElementExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ElementExtensions.cs @@ -3,29 +3,28 @@ using System.Linq; using Autodesk.Revit.DB; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +public static class ElementExtensions { - public static class ElementExtensions + public static IEnumerable GetConnectorSet(this Element element) { - public static IEnumerable GetConnectorSet(this Element element) - { - var empty = Enumerable.Empty(); - return element.GetConnectorManager()?.Connectors?.Cast() ?? empty; - } + var empty = Enumerable.Empty(); + return element.GetConnectorManager()?.Connectors?.Cast() ?? empty; + } - public static ConnectorManager? GetConnectorManager(this Element element) + public static ConnectorManager? GetConnectorManager(this Element element) + { + return element switch { - return element switch - { - MEPCurve o => o.ConnectorManager, - FamilyInstance o => o.MEPModel?.ConnectorManager, - _ => null, - }; - } + MEPCurve o => o.ConnectorManager, + FamilyInstance o => o.MEPModel?.ConnectorManager, + _ => null, + }; + } - public static bool IsMEPElement(this Element element) - { - return element.GetConnectorManager() != null; - } + public static bool IsMEPElement(this Element element) + { + return element.GetConnectorManager() != null; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ForgeTypeIdExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ForgeTypeIdExtensions.cs index 63947da575..2c3462dee1 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ForgeTypeIdExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ForgeTypeIdExtensions.cs @@ -4,28 +4,28 @@ using Autodesk.Revit.DB; using DB = Autodesk.Revit.DB; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +public static class ForgeTypeIdExtensions { - public static class ForgeTypeIdExtensions + public static string? GetSymbol(this ForgeTypeId forgeTypeId) { - public static string? GetSymbol(this ForgeTypeId forgeTypeId) + if (!FormatOptions.CanHaveSymbol(forgeTypeId)) { - if (!FormatOptions.CanHaveSymbol(forgeTypeId)) - { - return null; - } - var validSymbols = FormatOptions.GetValidSymbols(forgeTypeId); - var typeId = validSymbols?.Where(x => !x.Empty()); - foreach (DB.ForgeTypeId symbolId in typeId) - { - return LabelUtils.GetLabelForSymbol(symbolId); - } return null; } - public static string ToUniqueString(this ForgeTypeId forgeTypeId) + var validSymbols = FormatOptions.GetValidSymbols(forgeTypeId); + var typeId = validSymbols?.Where(x => !x.Empty()); + foreach (DB.ForgeTypeId symbolId in typeId) { - return forgeTypeId.TypeId; + return LabelUtils.GetLabelForSymbol(symbolId); } + return null; + } + + public static string ToUniqueString(this ForgeTypeId forgeTypeId) + { + return forgeTypeId.TypeId; } } #endif diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ParameterExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ParameterExtensions.cs index 43dce63f1b..0103f15db5 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ParameterExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/ParameterExtensions.cs @@ -3,63 +3,55 @@ using Autodesk.Revit.DB; using Objects.Converter.Revit; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +internal static class ParameterExtensions { - internal static class ParameterExtensions + public static object? GetValue(this Parameter parameter, Definition definition, string unitsOverride) { - public static object? GetValue( - this Parameter parameter, - Definition definition, - string unitsOverride - ) - { #if REVIT2020 - DisplayUnitType? unitTypeId = null; + DisplayUnitType? unitTypeId = null; #else - ForgeTypeId? unitTypeId = null; + ForgeTypeId? unitTypeId = null; #endif - if (parameter.StorageType == StorageType.Double) - { - unitTypeId = unitsOverride != null - ? ConverterRevit.UnitsToNative(unitsOverride) - : parameter.GetUnitTypeId(); - } - return GetValue(parameter, definition, unitTypeId); + if (parameter.StorageType == StorageType.Double) + { + unitTypeId = unitsOverride != null ? ConverterRevit.UnitsToNative(unitsOverride) : parameter.GetUnitTypeId(); } - public static object? GetValue( - this Parameter parameter, - Definition definition, + return GetValue(parameter, definition, unitTypeId); + } + + public static object? GetValue(this Parameter parameter, Definition definition, #if REVIT2020 - DisplayUnitType? unitTypeId = null + DisplayUnitType? unitTypeId = null #else - ForgeTypeId? unitTypeId = null + ForgeTypeId? unitTypeId = null #endif - ) + ) + { + switch (parameter.StorageType) { - switch (parameter.StorageType) - { - case StorageType.Double: - var val = parameter.AsDouble(); - if (val == default(double) && parameter.HasValue == false) - { - return null; - } - return ConverterRevit.ScaleToSpeckle(val, unitTypeId ?? parameter.GetUnitTypeId()); - case StorageType.Integer: - var intVal = parameter.AsInteger(); - if (intVal == default(int) && parameter.HasValue == false) - { - return null; - } - return definition.IsBool() ? Convert.ToBoolean(intVal) : intVal; - - case StorageType.String: - return parameter.AsString(); - case StorageType.ElementId: - return parameter.AsElementId().ToString(); - default: + case StorageType.Double: + var val = parameter.AsDouble(); + if (val == default(double) && parameter.HasValue == false) + { return null; - } + } + return ConverterRevit.ScaleToSpeckle(val, unitTypeId ?? parameter.GetUnitTypeId()); + case StorageType.Integer: + var intVal = parameter.AsInteger(); + if (intVal == default(int) && parameter.HasValue == false) + { + return null; + } + return definition.IsBool() ? Convert.ToBoolean(intVal) : intVal; + + case StorageType.String: + return parameter.AsString(); + case StorageType.ElementId: + return parameter.AsElementId().ToString(); + default: + return null; } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/PointExtensions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/PointExtensions.cs index f5f650afc6..ab5b47f896 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/PointExtensions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Extensions/PointExtensions.cs @@ -1,21 +1,20 @@ using System; using Objects.Geometry; -namespace ConverterRevitShared.Extensions +namespace ConverterRevitShared.Extensions; + +internal static class PointExtensions { - internal static class PointExtensions + public static bool IsOnLineBetweenPoints(this Point middle, Point p0, Point p1, double tolerance = .01) { - public static bool IsOnLineBetweenPoints(this Point middle, Point p0, Point p1, double tolerance = .01) - { - Vector outerPointsDirection = new(p1 - p0); - Vector middleToStartPointsDirection = new(middle - p0); + Vector outerPointsDirection = new(p1 - p0); + Vector middleToStartPointsDirection = new(middle - p0); - Vector crossProduct = Vector.CrossProduct(outerPointsDirection, middleToStartPointsDirection); + Vector crossProduct = Vector.CrossProduct(outerPointsDirection, middleToStartPointsDirection); - // Check if the cross product vector is within tolerance - return Math.Abs(crossProduct.x) < tolerance - && Math.Abs(crossProduct.y) < tolerance - && Math.Abs(crossProduct.z) < tolerance; - } + // Check if the cross product vector is within tolerance + return Math.Abs(crossProduct.x) < tolerance + && Math.Abs(crossProduct.y) < tolerance + && Math.Abs(crossProduct.z) < tolerance; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/Element2DOutlineBuilder.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/Element2DOutlineBuilder.cs index f1a4fe05f5..ee3e68ab91 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/Element2DOutlineBuilder.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/Element2DOutlineBuilder.cs @@ -4,235 +4,244 @@ using ConverterRevitShared.Extensions; using Objects.Geometry; -namespace ConverterRevitShared.Models +namespace ConverterRevitShared.Models; + +/// +/// Responsible for taking the outermost loop of an analytical 2D element (as a list of points) and +/// adding back the sections that have been removed due to openings being present. This way, instead of sending +/// a wall with a door as 8-sided n-gon, we'll send it as a rectangle with the polyline representing the door +/// opening in a separate property. The latter format is much easier for structural software to represent and +/// is a more clear representation of the design intent. +/// +internal class Element2DOutlineBuilder { - /// - /// Responsible for taking the outermost loop of an analytical 2D element (as a list of points) and - /// adding back the sections that have been removed due to openings being present. This way, instead of sending - /// a wall with a door as 8-sided n-gon, we'll send it as a rectangle with the polyline representing the door - /// opening in a separate property. The latter format is much easier for structural software to represent and - /// is a more clear representation of the design intent. - /// - internal class Element2DOutlineBuilder - { - private const double POINT_TOLERANCE = .1; + private const double POINT_TOLERANCE = .1; - private readonly List openingPolylines; - private readonly List outlinePoints; + private readonly List openingPolylines; + private readonly List outlinePoints; - public Element2DOutlineBuilder(List openingPolylines, List outlinePoints) - { - this.openingPolylines = openingPolylines; - this.outlinePoints = outlinePoints; - } + public Element2DOutlineBuilder(List openingPolylines, List outlinePoints) + { + this.openingPolylines = openingPolylines; + this.outlinePoints = outlinePoints; + } - private void AddPointsToOutline(List pointsToAdd, int indexToBeInserted) + private void AddPointsToOutline(List pointsToAdd, int indexToBeInserted) + { + if (outlinePoints.Count == 0) { - if (outlinePoints.Count == 0) - { - if (indexToBeInserted > 0) - { - throw new ArgumentException($"Outline currently has 0 points, cannot add point at index {indexToBeInserted}"); - } - outlinePoints.AddRange(pointsToAdd); - } - else + if (indexToBeInserted > 0) { - AddPointsToPopulatedOutline(pointsToAdd, indexToBeInserted); + throw new ArgumentException($"Outline currently has 0 points, cannot add point at index {indexToBeInserted}"); } + outlinePoints.AddRange(pointsToAdd); } - - private void AddPointsToPopulatedOutline(List pointsToAdd, int insertIndex) + else { - Point previousPoint = outlinePoints[insertIndex]; + AddPointsToPopulatedOutline(pointsToAdd, indexToBeInserted); + } + } - if (previousPoint.DistanceTo(pointsToAdd.First()) < POINT_TOLERANCE) - { - int prevNumOrLast = insertIndex == 0 ? outlinePoints.Count - 1 : insertIndex - 1; - RemoveLastPointToAddIfItAlreadyExists(pointsToAdd, prevNumOrLast); - outlinePoints.InsertRange(insertIndex, pointsToAdd.Skip(1)); - } - else if (previousPoint.DistanceTo(pointsToAdd.Last()) < POINT_TOLERANCE) - { - pointsToAdd.Reverse(); - int nextNumOrZero = insertIndex == outlinePoints.Count - 1 ? 0 : insertIndex + 1; - RemoveLastPointToAddIfItAlreadyExists(pointsToAdd, nextNumOrZero); - outlinePoints.InsertRange(insertIndex, pointsToAdd.Skip(1)); - } - else - { - throw new InvalidOperationException("The provided list of points that doesn't start at the beginning or end of the existing outline"); - } + private void AddPointsToPopulatedOutline(List pointsToAdd, int insertIndex) + { + Point previousPoint = outlinePoints[insertIndex]; + + if (previousPoint.DistanceTo(pointsToAdd.First()) < POINT_TOLERANCE) + { + int prevNumOrLast = insertIndex == 0 ? outlinePoints.Count - 1 : insertIndex - 1; + RemoveLastPointToAddIfItAlreadyExists(pointsToAdd, prevNumOrLast); + outlinePoints.InsertRange(insertIndex, pointsToAdd.Skip(1)); } + else if (previousPoint.DistanceTo(pointsToAdd.Last()) < POINT_TOLERANCE) + { + pointsToAdd.Reverse(); + int nextNumOrZero = insertIndex == outlinePoints.Count - 1 ? 0 : insertIndex + 1; + RemoveLastPointToAddIfItAlreadyExists(pointsToAdd, nextNumOrZero); + outlinePoints.InsertRange(insertIndex, pointsToAdd.Skip(1)); + } + else + { + throw new InvalidOperationException( + "The provided list of points that doesn't start at the beginning or end of the existing outline" + ); + } + } - private void RemoveLastPointToAddIfItAlreadyExists(List pointsToAdd, int nextPointIndex) + private void RemoveLastPointToAddIfItAlreadyExists(List pointsToAdd, int nextPointIndex) + { + Point nextPoint = outlinePoints[nextPointIndex]; + if (nextPoint.DistanceTo(pointsToAdd.Last()) < POINT_TOLERANCE) { - Point nextPoint = outlinePoints[nextPointIndex]; - if (nextPoint.DistanceTo(pointsToAdd.Last()) < POINT_TOLERANCE) - { - pointsToAdd.RemoveAt(pointsToAdd.Count - 1); - } + pointsToAdd.RemoveAt(pointsToAdd.Count - 1); } + } - /// - /// Will go through each opening and, if the opening is partially on the edge of an area topology, - /// then it will alter the topology such that the section of the opening that is part of the topology - /// is removed and the rest, the section of the opening that is not on the topology, will be added to it - /// - /// - public List GetOutline() + /// + /// Will go through each opening and, if the opening is partially on the edge of an area topology, + /// then it will alter the topology such that the section of the opening that is part of the topology + /// is removed and the rest, the section of the opening that is not on the topology, will be added to it + /// + /// + public List GetOutline() + { + foreach (Polyline polyline in openingPolylines) { - foreach (Polyline polyline in openingPolylines) + List lineOverlapData = polyline + .EnumerateAsLines() + .Select(GetLineOverlappingOutlineData) + .ToList(); + + if ( + !lineOverlapData.Any(data => data.OverlapsOutline) + || RemoveIndicesFromOutline(lineOverlapData) is not int indexToAddTo + ) { - List lineOverlapData = polyline - .EnumerateAsLines() - .Select(GetLineOverlappingOutlineData) - .ToList(); - - if (!lineOverlapData.Any(data => data.OverlapsOutline) - || RemoveIndicesFromOutline(lineOverlapData) is not int indexToAddTo) - { - continue; - } - - List linesToAddToOutline = lineOverlapData - .Where(data => !data.OverlapsOutline) - .Select(data => data.Line) - .ToList(); - - List pointsToAddToOutline = linesToAddToOutline - .Select(line => line.start) - .ToList(); - pointsToAddToOutline.Add(linesToAddToOutline.Last().end); - - AddPointsToOutline(pointsToAddToOutline, indexToAddTo); + continue; } - RemoveRedundantPointsFromOutline(); + List linesToAddToOutline = lineOverlapData + .Where(data => !data.OverlapsOutline) + .Select(data => data.Line) + .ToList(); - return outlinePoints; + List pointsToAddToOutline = linesToAddToOutline.Select(line => line.start).ToList(); + pointsToAddToOutline.Add(linesToAddToOutline.Last().end); + + AddPointsToOutline(pointsToAddToOutline, indexToAddTo); } - void RemoveRedundantPointsFromOutline() - { - Point previousPoint = outlinePoints[0]; - for (int i = outlinePoints.Count - 1; i >= 0; i--) - { - Point currentPoint = outlinePoints[i]; + RemoveRedundantPointsFromOutline(); - int nextPointIndex = i == 0 ? outlinePoints.Count - 1 : i - 1; - Point nextPoint = outlinePoints[nextPointIndex]; + return outlinePoints; + } - if (currentPoint.IsOnLineBetweenPoints(previousPoint, nextPoint)) - { - outlinePoints.RemoveAt(i); - } - previousPoint = currentPoint; - } - } - - int? RemoveIndicesFromOutline(List allLineOverlapData) + void RemoveRedundantPointsFromOutline() + { + Point previousPoint = outlinePoints[0]; + for (int i = outlinePoints.Count - 1; i >= 0; i--) { - SortedSet allIndicesInvolved = new(); - SortedSet indicesToRemove = new(); - foreach (LineOverlappingOutlineData data in allLineOverlapData) - { - if (data.OutlineIndexForStartPoint.HasValue) - { - SortIndicesIntoCorrectSet(data.OutlineIndexForStartPoint.Value, allIndicesInvolved, indicesToRemove); - SortIndicesIntoCorrectSet(data.OutlineIndexForEndPoint.Value, allIndicesInvolved, indicesToRemove); - } - } + Point currentPoint = outlinePoints[i]; - // This code handles an edge case where there is an opening near the top of a wall. - // the outline of the wall may dip down to include the opening, even if the opening doesn't actually reach - // the top of the wall. For example, if you have a duct that goes through the a wall near the top, it may - // not reach the top, but you still wouldn't need to close the wall over the top of the duct. - // ___ ___________________________ - // | | not opening | | - // | | but not wall | | - // | |_______________| wall | - // | | opening | | - // | |_______________| | - // | | - // | | - // |_______________________________________________| - // in the above scenario, only the bottom two indices of the opening will be included in the - // allIndicesInvolved set and none will be in the indicesToRemove set. What we need to do is remove - // the two points in the allIndicesInvolved from the outline and NOT add the missing ones like we will - // typically do - - if (allIndicesInvolved.Count == 2 && indicesToRemove.Count == 0) + int nextPointIndex = i == 0 ? outlinePoints.Count - 1 : i - 1; + Point nextPoint = outlinePoints[nextPointIndex]; + + if (currentPoint.IsOnLineBetweenPoints(previousPoint, nextPoint)) { - outlinePoints.RemoveAt(allIndicesInvolved.ElementAt(1)); - outlinePoints.RemoveAt(allIndicesInvolved.ElementAt(0)); - return null; + outlinePoints.RemoveAt(i); } + previousPoint = currentPoint; + } + } - // loop backward to remove items from the list at certain indices without shifting the rest of the indices - foreach (int indexToRemove in indicesToRemove.Reverse()) + int? RemoveIndicesFromOutline(List allLineOverlapData) + { + SortedSet allIndicesInvolved = new(); + SortedSet indicesToRemove = new(); + foreach (LineOverlappingOutlineData data in allLineOverlapData) + { + if (data.OutlineIndexForStartPoint.HasValue) { - outlinePoints.RemoveAt(indexToRemove); + SortIndicesIntoCorrectSet(data.OutlineIndexForStartPoint.Value, allIndicesInvolved, indicesToRemove); + SortIndicesIntoCorrectSet(data.OutlineIndexForEndPoint.Value, allIndicesInvolved, indicesToRemove); } + } - return indicesToRemove.Min(); + // This code handles an edge case where there is an opening near the top of a wall. + // the outline of the wall may dip down to include the opening, even if the opening doesn't actually reach + // the top of the wall. For example, if you have a duct that goes through the a wall near the top, it may + // not reach the top, but you still wouldn't need to close the wall over the top of the duct. + // ___ ___________________________ + // | | not opening | | + // | | but not wall | | + // | |_______________| wall | + // | | opening | | + // | |_______________| | + // | | + // | | + // |_______________________________________________| + // in the above scenario, only the bottom two indices of the opening will be included in the + // allIndicesInvolved set and none will be in the indicesToRemove set. What we need to do is remove + // the two points in the allIndicesInvolved from the outline and NOT add the missing ones like we will + // typically do + + if (allIndicesInvolved.Count == 2 && indicesToRemove.Count == 0) + { + outlinePoints.RemoveAt(allIndicesInvolved.ElementAt(1)); + outlinePoints.RemoveAt(allIndicesInvolved.ElementAt(0)); + return null; } - static void SortIndicesIntoCorrectSet(int currentIndex, SortedSet allIndicesInvolved, SortedSet indicesToRemove) + // loop backward to remove items from the list at certain indices without shifting the rest of the indices + foreach (int indexToRemove in indicesToRemove.Reverse()) { - if (allIndicesInvolved.Contains(currentIndex)) - { - if (!indicesToRemove.Contains(currentIndex)) - { - indicesToRemove.Add(currentIndex); - } - } - else - { - allIndicesInvolved.Add(currentIndex); - } + outlinePoints.RemoveAt(indexToRemove); } - LineOverlappingOutlineData GetLineOverlappingOutlineData(Line openingLine) + return indicesToRemove.Min(); + } + + static void SortIndicesIntoCorrectSet( + int currentIndex, + SortedSet allIndicesInvolved, + SortedSet indicesToRemove + ) + { + if (allIndicesInvolved.Contains(currentIndex)) { - Point previousPoint = outlinePoints[0]; - for (int i = 1; i < outlinePoints.Count; i++) + if (!indicesToRemove.Contains(currentIndex)) { - Point currentPoint = outlinePoints[i]; - if (openingLine.start.DistanceTo(currentPoint) < POINT_TOLERANCE - && openingLine.end.DistanceTo(previousPoint) < POINT_TOLERANCE) - { - return new(openingLine, true, i, i - 1); - } - else if (openingLine.end.DistanceTo(currentPoint) < POINT_TOLERANCE - && openingLine.start.DistanceTo(previousPoint) < POINT_TOLERANCE) - { - return new(openingLine, true, i - 1, i); - } - previousPoint = currentPoint; + indicesToRemove.Add(currentIndex); } - return new LineOverlappingOutlineData(openingLine, false); + } + else + { + allIndicesInvolved.Add(currentIndex); } } - public readonly struct LineOverlappingOutlineData + LineOverlappingOutlineData GetLineOverlappingOutlineData(Line openingLine) { - public LineOverlappingOutlineData( - Line line, - bool overlapsOutline, - int? outlineIndexForStartPoint = null, - int? outlineIndexForEndPoint = null - ) + Point previousPoint = outlinePoints[0]; + for (int i = 1; i < outlinePoints.Count; i++) { - OverlapsOutline = overlapsOutline; - this.OutlineIndexForStartPoint = outlineIndexForStartPoint; - this.OutlineIndexForEndPoint = outlineIndexForEndPoint; - Line = line; + Point currentPoint = outlinePoints[i]; + if ( + openingLine.start.DistanceTo(currentPoint) < POINT_TOLERANCE + && openingLine.end.DistanceTo(previousPoint) < POINT_TOLERANCE + ) + { + return new(openingLine, true, i, i - 1); + } + else if ( + openingLine.end.DistanceTo(currentPoint) < POINT_TOLERANCE + && openingLine.start.DistanceTo(previousPoint) < POINT_TOLERANCE + ) + { + return new(openingLine, true, i - 1, i); + } + previousPoint = currentPoint; } + return new LineOverlappingOutlineData(openingLine, false); + } +} - public Line Line { get; } - public bool OverlapsOutline { get; } - public int? OutlineIndexForStartPoint { get; } - public int? OutlineIndexForEndPoint { get; } +public readonly struct LineOverlappingOutlineData +{ + public LineOverlappingOutlineData( + Line line, + bool overlapsOutline, + int? outlineIndexForStartPoint = null, + int? outlineIndexForEndPoint = null + ) + { + OverlapsOutline = overlapsOutline; + this.OutlineIndexForStartPoint = outlineIndexForStartPoint; + this.OutlineIndexForEndPoint = outlineIndexForEndPoint; + Line = line; } + + public Line Line { get; } + public bool OverlapsOutline { get; } + public int? OutlineIndexForStartPoint { get; } + public int? OutlineIndexForEndPoint { get; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/ParameterToSpeckleData.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/ParameterToSpeckleData.cs index 48fd206935..1421cf2d66 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/ParameterToSpeckleData.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Models/ParameterToSpeckleData.cs @@ -2,37 +2,36 @@ using Objects.BuiltElements.Revit; using DB = Autodesk.Revit.DB; -namespace Objects.Converter.Revit.Models +namespace Objects.Converter.Revit.Models; + +/// +/// This struct is used when caching parameter definitions upon sending to avoid having to deep clone the parameter object +/// This is done because all the fields except the parameter value will change +/// +internal struct ParameterToSpeckleData { - /// - /// This struct is used when caching parameter definitions upon sending to avoid having to deep clone the parameter object - /// This is done because all the fields except the parameter value will change - /// - internal struct ParameterToSpeckleData - { - public string ApplicationUnits; - public DB.Definition Definition; - public string InternalName; - public bool IsReadOnly; - public bool IsShared; - public bool IsTypeParameter; - public string Name; - public string UnitsSymbol; - public string UnitType; + public string ApplicationUnits; + public DB.Definition Definition; + public string InternalName; + public bool IsReadOnly; + public bool IsShared; + public bool IsTypeParameter; + public string Name; + public string UnitsSymbol; + public string UnitType; - public Parameter GetParameterObjectWithValue(object? value) + public Parameter GetParameterObjectWithValue(object? value) + { + return new Parameter() { - return new Parameter() - { - applicationInternalName = InternalName, - applicationUnit = ApplicationUnits, - isShared = IsShared, - isReadOnly = IsReadOnly, - isTypeParameter = IsTypeParameter, - name = Name, - units = UnitsSymbol, - value = value - }; - } + applicationInternalName = InternalName, + applicationUnit = ApplicationUnits, + isShared = IsShared, + isReadOnly = IsReadOnly, + isTypeParameter = IsTypeParameter, + name = Name, + units = UnitsSymbol, + value = value + }; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAdaptiveComponent.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAdaptiveComponent.cs deleted file mode 100644 index 9637644464..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAdaptiveComponent.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject AdaptiveComponentToNative(AdaptiveComponent speckleAc) - { - var docObj = GetExistingElementByApplicationId(speckleAc.applicationId); - var appObj = new ApplicationObject(speckleAc.id, speckleAc.speckle_type) { applicationId = speckleAc.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - string familyName = speckleAc["family"] as string != null ? speckleAc["family"] as string : ""; - - var familySymbol = GetElementType(speckleAc, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (!isExactMatch) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not find adaptive component {familyName}"); - return appObj; - } - - DB.FamilyInstance revitAc = null; - var isUpdate = false; - //try update existing - if (docObj != null) - { - try - { - var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; - - // if family changed, tough luck. delete and let us create a new one. - if (familyName != revitType.FamilyName) - Doc.Delete(docObj.Id); - - else - { - revitAc = (DB.FamilyInstance)docObj; - - // check for a type change - if (speckleAc.type != null && speckleAc.type != revitType.Name) - revitAc.ChangeTypeId(familySymbol.Id); - } - - isUpdate = true; - } - catch - { - //something went wrong, re-create it - } - } - - //create family instance - if (revitAc == null) - revitAc = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(Doc, familySymbol); - - SetAdaptivePoints(revitAc, speckleAc.basePoints, out List notes); - AdaptiveComponentInstanceUtils.SetInstanceFlipped(revitAc, speckleAc.flipped); - - SetInstanceParameters(revitAc, speckleAc); - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitAc.UniqueId, convertedItem: revitAc, log: notes); - return appObj; - } - - private AdaptiveComponent AdaptiveComponentToSpeckle(DB.FamilyInstance revitAc) - { - var speckleAc = new AdaptiveComponent(); - - var symbol = revitAc.Document.GetElement(revitAc.GetTypeId()) as FamilySymbol; - - speckleAc.family = symbol.FamilyName; - speckleAc.type = revitAc.Document.GetElement(revitAc.GetTypeId()).Name; - - speckleAc.basePoints = GetAdaptivePoints(revitAc); - speckleAc.flipped = AdaptiveComponentInstanceUtils.IsInstanceFlipped(revitAc); - speckleAc.displayValue = GetElementDisplayValue(revitAc); - - GetAllRevitParamsAndIds(speckleAc, revitAc); - Report.Log($"Converted AdaptiveComponent {revitAc.Id}"); - return speckleAc; - } - - private void SetAdaptivePoints(DB.FamilyInstance revitAc, List points, out List notes) - { - notes = new List(); - var pointIds = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(revitAc).ToList(); - - if (pointIds.Count != points.Count) - { - notes.Add("Adaptive family error: wrong number of points supplied"); - return; - } - - //set adaptive points - for (int i = 0; i < pointIds.Count; i++) - { - var point = Doc.GetElement(pointIds[i]) as ReferencePoint; - point.Position = PointToNative(points[i]); - } - } - - private List GetAdaptivePoints(DB.FamilyInstance revitAc) - { - var pointIds = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(revitAc).ToList(); - var points = new List(); - for (int i = 0; i < pointIds.Count; i++) - { - var point = revitAc.Document.GetElement(pointIds[i]) as ReferencePoint; - points.Add(PointToSpeckle(point.Position, revitAc.Document)); - } - return points; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalNode.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalNode.cs deleted file mode 100644 index f2e5daf555..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalNode.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Objects.Structural.Geometry; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Plane = Objects.Geometry.Plane; -using Vector = Objects.Geometry.Vector; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject AnalyticalNodeToNative(Node speckleNode) - { - return new ApplicationObject(speckleNode.id, speckleNode.speckle_type) { applicationId = speckleNode.applicationId }; - } - - private Node AnalyticalNodeToSpeckle(ReferencePoint revitNode) - { - var cs = revitNode.GetCoordinateSystem(); - var localAxis = new Plane(PointToSpeckle(cs.Origin, revitNode.Document), VectorToSpeckle(cs.BasisZ, revitNode.Document), VectorToSpeckle(cs.BasisX, revitNode.Document), VectorToSpeckle(cs.BasisY, revitNode.Document)); - var basePoint = PointToSpeckle(cs.Origin, revitNode.Document); // alternative to revitNode.Position - //var speckleNode = new Node(basePoint, revitNode.Name, null, localAxis); - var speckleNode = new Node(); - - GetAllRevitParamsAndIds(speckleNode, revitNode); - - return speckleNode; - } - - private Base BoundaryConditionsToSpeckle(BoundaryConditions revitBoundary) - { - var points = new List { }; - var nodes = new List { }; - - var cs = revitBoundary.GetDegreesOfFreedomCoordinateSystem(); - var localAxis = new Plane(PointToSpeckle(cs.Origin, revitBoundary.Document), VectorToSpeckle(cs.BasisZ, revitBoundary.Document), VectorToSpeckle(cs.BasisX, revitBoundary.Document), VectorToSpeckle(cs.BasisY, revitBoundary.Document)); - - var restraintType = revitBoundary.GetBoundaryConditionsType(); - var state = 0; - switch (restraintType) - { - case BoundaryConditionsType.Point: - var point = revitBoundary.Point; - points.Add(point); - state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET); // 1 fixed, 2 pinned, 3 roller, 4 user/variable - break; - case BoundaryConditionsType.Line: - var curve = revitBoundary.GetCurve(); - points.Add(curve.GetEndPoint(0)); - points.Add(curve.GetEndPoint(1)); - state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET_LINEAR); - break; - case BoundaryConditionsType.Area: - var loops = revitBoundary.GetLoops(); - foreach (var loop in loops) - foreach (var areaCurve in loop) - points.Add(areaCurve.GetEndPoint(1)); - - points = points.Distinct().ToList(); - state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET_AREA); - break; - default: - break; - } - - var restraint = GetRestraintCode(revitBoundary, restraintType, state); - - foreach (var point in points) - { - var speckleNode = new Node(); - //var speckleNode = new Node(PointToSpeckle(point), null, restraint, localAxis); - - GetAllRevitParamsAndIds(speckleNode, revitBoundary); - - nodes.Add(speckleNode); - } - - var speckleBoundaryCondition = new Base(); - if (nodes.Count > 1) - speckleBoundaryCondition["nodes"] = nodes; - else - speckleBoundaryCondition = nodes[0]; - - return speckleBoundaryCondition; - } - - private Restraint GetRestraintCode(DB.Element elem, BoundaryConditionsType type, int presetState) - { - if (presetState == 0) - return new Restraint(RestraintType.Fixed); - else if (presetState == 1) - return new Restraint(RestraintType.Pinned); - else if (presetState == 2) - return new Restraint(RestraintType.Roller); - - var boundaryParams = new BuiltInParameter[] { - BuiltInParameter.BOUNDARY_DIRECTION_X, - BuiltInParameter.BOUNDARY_DIRECTION_Y, - BuiltInParameter.BOUNDARY_DIRECTION_Z, - BuiltInParameter.BOUNDARY_DIRECTION_ROT_X, - BuiltInParameter.BOUNDARY_DIRECTION_ROT_Y, - BuiltInParameter.BOUNDARY_DIRECTION_ROT_Z - }; - - var springValueParams = new BuiltInParameter[] { - BuiltInParameter.BOUNDARY_RESTRAINT_X, - BuiltInParameter.BOUNDARY_RESTRAINT_Y, - BuiltInParameter.BOUNDARY_RESTRAINT_Z, - BuiltInParameter.BOUNDARY_RESTRAINT_ROT_X, - BuiltInParameter.BOUNDARY_RESTRAINT_ROT_Y, - BuiltInParameter.BOUNDARY_RESTRAINT_ROT_Z, - }; - - var linSpringValueParams = new BuiltInParameter[] { - BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_X, - BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_Y, - BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_Z, - BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_ROT_X, - }; - - var areaSpingValueParams = new BuiltInParameter[] { - BuiltInParameter.BOUNDARY_AREA_RESTRAINT_X, - BuiltInParameter.BOUNDARY_AREA_RESTRAINT_Y, - BuiltInParameter.BOUNDARY_AREA_RESTRAINT_Z, - BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_ROT_X, - }; - - string code = ""; - var springStiffness = new double[6]; - for (int i = 0; i < boundaryParams.Length; i++) - { - var value = GetParamValue(elem, boundaryParams[i]); - switch (value) - { - case 0: - code = code + "F"; //fixed - break; - case 1: - code = code + "R"; //released - break; - case 2: - code = code + "K"; //spring - if (type == BoundaryConditionsType.Line) - { - switch (boundaryParams[i]) - { - case BuiltInParameter.BOUNDARY_DIRECTION_X: - springStiffness[i] = GetParamValue(elem, linSpringValueParams[0]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_Y: - springStiffness[i] = GetParamValue(elem, linSpringValueParams[1]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_Z: - springStiffness[i] = GetParamValue(elem, linSpringValueParams[2]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_ROT_X: - springStiffness[i] = GetParamValue(elem, linSpringValueParams[3]); // kN-m/°/m - break; - default: - springStiffness[i] = 0; - break; - } - } - else if (type == BoundaryConditionsType.Area) - { - switch (boundaryParams[i]) - { - case BuiltInParameter.BOUNDARY_DIRECTION_X: - springStiffness[i] = GetParamValue(elem, areaSpingValueParams[0]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_Y: - springStiffness[i] = GetParamValue(elem, areaSpingValueParams[1]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_Z: - springStiffness[i] = GetParamValue(elem, areaSpingValueParams[2]); // kN/m² - break; - case BuiltInParameter.BOUNDARY_DIRECTION_ROT_X: - springStiffness[i] = GetParamValue(elem, areaSpingValueParams[3]); // kN-m/°/m - break; - default: - springStiffness[i] = 0; - break; - } - } - else - springStiffness[i] = GetParamValue(elem, springValueParams[i]); - break; - default: - return null; - } - } - - var restraint = new Restraint(code, springStiffness[0], springStiffness[1], springStiffness[2], springStiffness[3], springStiffness[4], springStiffness[5]); - - return restraint; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalStick.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalStick.cs deleted file mode 100644 index cdf9aa6b63..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalStick.cs +++ /dev/null @@ -1,713 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Autodesk.Revit.DB.Structure.StructuralSections; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Objects.Structural.Geometry; -using Objects.Structural.Materials; -using Objects.Structural.Properties; -using Objects.Structural.Properties.Profiles; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject AnalyticalStickToNative(Element1D speckleStick) - { - ApplicationObject appObj = null; - XYZ offset1 = VectorToNative(speckleStick.end1Offset ?? new Geometry.Vector(0, 0, 0)); - XYZ offset2 = VectorToNative(speckleStick.end2Offset ?? new Geometry.Vector(0, 0, 0)); - -#if REVIT2020 || REVIT2021 || REVIT2022 - appObj = CreatePhysicalMember(speckleStick); - DB.FamilyInstance physicalMember = (DB.FamilyInstance)appObj.Converted.FirstOrDefault(); - SetAnalyticalProps(physicalMember, speckleStick, offset1, offset2); -#else - var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(Doc); - - // check for existing member - var docObj = GetExistingElementByApplicationId(speckleStick.applicationId); - appObj = new ApplicationObject(speckleStick.id, speckleStick.speckle_type) { applicationId = speckleStick.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (speckleStick.baseLine == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Only line based Analytical Members are currently supported."); - return appObj; - } - - var baseLine = CurveToNative(speckleStick.baseLine).get_Item(0); - DB.Level level = null; - - level ??= ConvertLevelToRevit(LevelFromCurve(baseLine), out ApplicationObject.State levelState); - var isUpdate = false; - - var familySymbol = GetElementType(speckleStick, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - AnalyticalMember revitMember = null; - DB.FamilyInstance physicalMember = null; - - if (docObj != null && docObj is AnalyticalMember analyticalMember) - { - // update location - var currentCurve = analyticalMember.GetCurve(); - var p0 = currentCurve.GetEndPoint(0); - - if (p0.DistanceTo(baseLine.GetEndPoint(0)) > p0.DistanceTo(baseLine.GetEndPoint(1))) - analyticalMember.SetCurve(baseLine.CreateReversed()); - else - analyticalMember.SetCurve(baseLine); - - if (isExactMatch) - { - //update type - if (familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralColumns) - || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralFraming)) - { - analyticalMember.SectionTypeId = familySymbol.Id; - } - isUpdate = true; - revitMember = analyticalMember; - - if (analyticalToPhysicalManager.HasAssociation(revitMember.Id)) - { - var physicalMemberId = analyticalToPhysicalManager.GetAssociatedElementId(revitMember.Id); - physicalMember = (DB.FamilyInstance)Doc.GetElement(physicalMemberId); - if (physicalMember.Symbol != familySymbol) - physicalMember.Symbol = familySymbol; - } - } - } - - //create family instance - if (revitMember == null) - { - revitMember = AnalyticalMember.Create(Doc, baseLine); - //set type - if (familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralColumns) - || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralFraming)) - { - revitMember.SectionTypeId = familySymbol.Id; - } - } - - // set or update analytical properties - SetAnalyticalProps(revitMember, speckleStick, offset1, offset2); - - // if there isn't an associated physical element to the analytical element, create it - if (!analyticalToPhysicalManager.HasAssociation(revitMember.Id)) - { - var physicalMemberAppObj = CreatePhysicalMember(speckleStick); - physicalMember = (DB.FamilyInstance)physicalMemberAppObj.Converted.FirstOrDefault(); - analyticalToPhysicalManager.AddAssociation(revitMember.Id, physicalMember.Id); - - appObj.Update(createdId: physicalMember.UniqueId, convertedItem: physicalMember); - } - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitMember.UniqueId, convertedItem: revitMember); -#endif - return appObj; - } - - private ApplicationObject CreatePhysicalMember(Element1D speckleStick) - { - ApplicationObject appObj = null; - XYZ offset1 = VectorToNative(speckleStick.end1Offset ?? new Geometry.Vector(0, 0, 0)); - XYZ offset2 = VectorToNative(speckleStick.end2Offset ?? new Geometry.Vector(0, 0, 0)); - - var propertyName = speckleStick.property?.name; - - //This only works for CSIC sections now for sure. Need to test on other sections - if (!string.IsNullOrEmpty(propertyName)) - propertyName = propertyName.Replace('X', 'x'); - - switch (speckleStick.type) - { - case ElementType1D.Beam: - RevitBeam revitBeam = new RevitBeam(); - revitBeam.type = propertyName; - revitBeam.baseLine = speckleStick.baseLine; -#if REVIT2020 || REVIT2021 || REVIT2022 - revitBeam.applicationId = speckleStick.applicationId; -#endif - appObj = BeamToNative(revitBeam); - - return appObj; - - case ElementType1D.Brace: - Brace speckleBrace = new(); - SetElementType(speckleBrace, propertyName); - speckleBrace.baseLine = speckleStick.baseLine; - speckleBrace.units = speckleStick.units; -#if REVIT2020 || REVIT2021 || REVIT2022 - speckleBrace.applicationId = speckleStick.applicationId; -#endif - appObj = BraceToNative(speckleBrace); - - return appObj; - - case ElementType1D.Column: - Column speckleColumn = new(); - SetElementType(speckleColumn, propertyName); - speckleColumn.baseLine = speckleStick.baseLine; - speckleColumn.units = speckleStick.units; -#if REVIT2020 || REVIT2021 || REVIT2022 - speckleColumn.applicationId = speckleStick.applicationId; -#endif - appObj = ColumnToNative(speckleColumn); - - return appObj; - } - return appObj; - } - - private void SetAnalyticalProps(Element element, Element1D element1d, XYZ offset1, XYZ offset2) - { - Func releaseConvert = rel => rel == 'R'; - -#if REVIT2020 || REVIT2021 || REVIT2022 - var analyticalModel = (AnalyticalModelStick)element.GetAnalyticalModel(); - analyticalModel.SetReleases(true, releaseConvert(element1d.end1Releases.code[0]), releaseConvert(element1d.end1Releases.code[1]), releaseConvert(element1d.end1Releases.code[2]), releaseConvert(element1d.end1Releases.code[3]), releaseConvert(element1d.end1Releases.code[4]), releaseConvert(element1d.end1Releases.code[5])); - analyticalModel.SetReleases(false, releaseConvert(element1d.end2Releases.code[0]), releaseConvert(element1d.end2Releases.code[1]), releaseConvert(element1d.end2Releases.code[2]), releaseConvert(element1d.end2Releases.code[3]), releaseConvert(element1d.end2Releases.code[4]), releaseConvert(element1d.end2Releases.code[5])); - analyticalModel.SetOffset(AnalyticalElementSelector.StartOrBase, offset1); - analyticalModel.SetOffset(AnalyticalElementSelector.EndOrTop, offset2); -#else - if (element is AnalyticalMember analyticalMember) - { - analyticalMember.SetReleaseConditions(new ReleaseConditions(true, releaseConvert(element1d.end1Releases.code[0]), releaseConvert(element1d.end1Releases.code[1]), releaseConvert(element1d.end1Releases.code[2]), releaseConvert(element1d.end1Releases.code[3]), releaseConvert(element1d.end1Releases.code[4]), releaseConvert(element1d.end1Releases.code[5]))); - analyticalMember.SetReleaseConditions(new ReleaseConditions(false, releaseConvert(element1d.end2Releases.code[0]), releaseConvert(element1d.end2Releases.code[1]), releaseConvert(element1d.end2Releases.code[2]), releaseConvert(element1d.end2Releases.code[3]), releaseConvert(element1d.end2Releases.code[4]), releaseConvert(element1d.end2Releases.code[5]))); - } - //TODO Set offsets -#endif - } -#if REVIT2020 || REVIT2021 || REVIT2022 - private Element1D AnalyticalStickToSpeckle(AnalyticalModelStick revitStick) - { - if (!revitStick.IsEnabled()) - return new Element1D(); - - var speckleElement1D = new Element1D(); - switch (revitStick.Category.Name) - { - case "Analytical Columns": - speckleElement1D.type = ElementType1D.Column; - break; - case "Analytical Beams": - speckleElement1D.type = ElementType1D.Beam; - break; - case "Analytical Braces": - speckleElement1D.type = ElementType1D.Brace; - break; - default: - speckleElement1D.type = ElementType1D.Other; - break; - } - - var curves = revitStick.GetCurves(AnalyticalCurveType.RigidLinkHead).ToList(); - curves.AddRange(revitStick.GetCurves(AnalyticalCurveType.ActiveCurves)); - curves.AddRange(revitStick.GetCurves(AnalyticalCurveType.RigidLinkTail)); - - if (curves.Count > 1) - speckleElement1D.baseLine = null; - else - speckleElement1D.baseLine = CurveToSpeckle(curves[0], revitStick.Document) as Objects.Geometry.Line; - - - var coordinateSystem = revitStick.GetLocalCoordinateSystem(); - if (coordinateSystem != null) - speckleElement1D.localAxis = new Geometry.Plane(PointToSpeckle(coordinateSystem.Origin, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisZ, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisX, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisY, revitStick.Document)); - - var startOffset = revitStick.GetOffset(AnalyticalElementSelector.StartOrBase); - var endOffset = revitStick.GetOffset(AnalyticalElementSelector.EndOrTop); - speckleElement1D.end1Offset = VectorToSpeckle(startOffset, revitStick.Document); - speckleElement1D.end2Offset = VectorToSpeckle(endOffset, revitStick.Document); - - SetEndReleases(revitStick, ref speckleElement1D); - - var prop = new Property1D(); - - var stickFamily = (Autodesk.Revit.DB.FamilyInstance)revitStick.Document.GetElement(revitStick.GetElementId()); - - var speckleSection = GetSectionProfile(stickFamily.Symbol); - - var structMat = (DB.Material)stickFamily.Document.GetElement(stickFamily.StructuralMaterialId); - if (structMat == null) - structMat = (DB.Material)stickFamily.Document.GetElement(stickFamily.Symbol.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId()); - - - prop.profile = speckleSection; - prop.material = GetStructuralMaterial(structMat); - prop.name = revitStick.Document.GetElement(revitStick.GetElementId()).Name; - prop.applicationId = stickFamily.Symbol.UniqueId; - - var structuralElement = revitStick.Document.GetElement(revitStick.GetElementId()); - var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); - - if (revitStick is AnalyticalModelColumn) - { - speckleElement1D.type = ElementType1D.Column; - //prop.memberType = MemberType.Column; - var locationMark = GetParamValue(structuralElement, BuiltInParameter.COLUMN_LOCATION_MARK); - if (locationMark == null) - speckleElement1D.name = mark; - else - speckleElement1D.name = locationMark; - } - else - { - prop.memberType = MemberType.Beam; - speckleElement1D.name = mark; - } - - speckleElement1D.property = prop; - - GetAllRevitParamsAndIds(speckleElement1D, revitStick); - speckleElement1D.displayValue = GetElementDisplayValue(revitStick.Document.GetElement(revitStick.GetElementId())); - return speckleElement1D; - } - -#else - private Element1D AnalyticalStickToSpeckle(AnalyticalMember revitStick) - { - var speckleElement1D = new Element1D(); - switch (revitStick.StructuralRole) - { - case AnalyticalStructuralRole.StructuralRoleColumn: - speckleElement1D.type = ElementType1D.Column; - break; - case AnalyticalStructuralRole.StructuralRoleBeam: - speckleElement1D.type = ElementType1D.Beam; - break; - case AnalyticalStructuralRole.StructuralRoleMember: - speckleElement1D.type = ElementType1D.Brace; - break; - default: - speckleElement1D.type = ElementType1D.Other; - break; - } - - speckleElement1D.baseLine = CurveToSpeckle(revitStick.GetCurve(), revitStick.Document) as Objects.Geometry.Line; - - SetEndReleases(revitStick, ref speckleElement1D); - - var prop = new Property1D(); - - var stickFamily = (Autodesk.Revit.DB.FamilySymbol)revitStick.Document.GetElement(revitStick.SectionTypeId); - - var speckleSection = GetSectionProfile(stickFamily); - - var structMat = (DB.Material)stickFamily.Document.GetElement(revitStick.MaterialId); - if (structMat == null) - structMat = (DB.Material)stickFamily.Document.GetElement(stickFamily.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId()); - - prop.profile = speckleSection; - prop.material = GetStructuralMaterial(structMat); - prop.name = stickFamily.Name; - - var mark = GetParamValue(stickFamily, BuiltInParameter.ALL_MODEL_MARK); - - //TODO: how to differenciate between column and beam? - - //if (revitStick is AnalyticalModelColumn) - //{ - // speckleElement1D.type = ElementType1D.Column; - // //prop.memberType = MemberType.Column; - // var locationMark = GetParamValue(stickFamily, BuiltInParameter.COLUMN_LOCATION_MARK); - // if (locationMark == null) - // speckleElement1D.name = mark; - // else - // speckleElement1D.name = locationMark; - //} - //else - //{ - prop.memberType = MemberType.Beam; - speckleElement1D.name = mark; - //} - - speckleElement1D.property = prop; - - GetAllRevitParamsAndIds(speckleElement1D, revitStick); - - var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(Doc); - if (analyticalToPhysicalManager.HasAssociation(revitStick.Id)) - { - var physicalElementId = analyticalToPhysicalManager.GetAssociatedElementId(revitStick.Id); - var physicalElement = Doc.GetElement(physicalElementId); - speckleElement1D.displayValue = GetElementDisplayValue(physicalElement); - } - - return speckleElement1D; - } -#endif - - private void SetEndReleases(Element revitStick, ref Element1D speckleElement1D) - { - var startRelease = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_START_RELEASE_TYPE); - var endRelease = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_END_RELEASE_TYPE); - if (startRelease == 0) - speckleElement1D.end1Releases = new Restraint(RestraintType.Fixed); - else - { - var botReleaseX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FX) == 1 ? "R" : "F"; - var botReleaseY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FY) == 1 ? "R" : "F"; - var botReleaseZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FZ) == 1 ? "R" : "F"; - var botReleaseXX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MX) == 1 ? "R" : "F"; - var botReleaseYY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MY) == 1 ? "R" : "F"; - var botReleaseZZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MZ) == 1 ? "R" : "F"; - - string botReleaseCode = botReleaseX + botReleaseY + botReleaseZ + botReleaseXX + botReleaseYY + botReleaseZZ; - speckleElement1D.end1Releases = new Restraint(botReleaseCode); - } - - if (endRelease == 0) - speckleElement1D.end2Releases = new Restraint(RestraintType.Fixed); - else - { - var topReleaseX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FX) == 1 ? "R" : "F"; - var topReleaseY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FY) == 1 ? "R" : "F"; - var topReleaseZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FZ) == 1 ? "R" : "F"; - var topReleaseXX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MX) == 1 ? "R" : "F"; - var topReleaseYY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MY) == 1 ? "R" : "F"; - var topReleaseZZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MZ) == 1 ? "R" : "F"; - - string topReleaseCode = topReleaseX + topReleaseY + topReleaseZ + topReleaseXX + topReleaseYY + topReleaseZZ; - speckleElement1D.end2Releases = new Restraint(topReleaseCode); - } - } - - private SectionProfile GetSectionProfile(FamilySymbol familySymbol) - { - var revitSection = familySymbol.GetStructuralSection(); - if (revitSection == null) - return null; - - // check section profile cache - if (SectionProfiles.Keys.Contains(familySymbol.Name)) - return SectionProfiles[familySymbol.Name]; - - var speckleSection = new SectionProfile(); - - // note to future self, the StructuralSectionGeneralShape prop is sometimes null so it isn't reliable to use - // therefore switch on the object itself instead - switch (revitSection) - { - - case StructuralSectionIWelded _: // Built up wide flange - case StructuralSectionIWideFlange _: // I shaped wide flange - case StructuralSectionGeneralI _: // General Double T shape - speckleSection = new ISection(); - break; - case StructuralSectionGeneralT _: // General Tee shape - speckleSection = new Tee(); - break; - case StructuralSectionGeneralH _: // Rectangular Pipe structural sections - case StructuralSectionGeneralF _: // Flat Bar structural sections - speckleSection = new Rectangular(); - break; - case StructuralSectionGeneralR _: // Pipe structural sections - case StructuralSectionGeneralS _: // Round Bar structural sections - speckleSection = new Circular(); - break; - case StructuralSectionGeneralW _: // Angle structural sections - speckleSection = new Angle(); - break; - case StructuralSectionGeneralU _: // Channel structural sections - speckleSection = new Channel(); - break; - - //case StructuralSectionGeneralLA o: - //case StructuralSectionColdFormed o: - //case StructuralSectionUserDefined o: - //case StructuralSectionGeneralLZ o: - - // keep these two last. They are last resorts - case StructuralSectionRectangular _: - speckleSection = new Rectangular(); - break; - case StructuralSectionRound _: - speckleSection = new Circular(); - break; - } - - SetStructuralSectionProps(revitSection, speckleSection); - - speckleSection.units = ModelUnits; - speckleSection.name = familySymbol.Name; - - SectionProfiles.Add(familySymbol.Name, speckleSection); - - return speckleSection; - } - - private void SetStructuralSectionProps(StructuralSection revitSection, SectionProfile speckleSection) - { - var scaleFactor = ScaleToSpeckle(1); - var scaleFactor2 = scaleFactor * scaleFactor; - - //TODO we need to support setting other units than just length - if (revitSection is StructuralSection _) - { - // static props - //TODO change this prop, Iyy can mean different things - speckleSection.Iyy = revitSection.MomentOfInertiaStrongAxis * scaleFactor2; - speckleSection.Izz = revitSection.MomentOfInertiaWeakAxis * scaleFactor2; - speckleSection.weight = revitSection.NominalWeight / scaleFactor; - speckleSection.area = revitSection.SectionArea * scaleFactor2; - speckleSection.J = revitSection.TorsionalMomentOfInertia * scaleFactor2 * scaleFactor2; - } - if (revitSection is StructuralSectionRectangular rect) - { - // these should be a static props, not dynamic ones, but we don't know the exact type of speckleSection here - // this may not be the best way to do this - speckleSection["depth"] = rect.Height * scaleFactor; - speckleSection["width"] = rect.Width * scaleFactor; - - // dynamic props - speckleSection["centroidHorizontal"] = rect.CentroidHorizontal * scaleFactor; - speckleSection["centroidVertical"] = rect.CentroidVertical * scaleFactor; - } - if (revitSection is StructuralSectionRound round) - { - // static props - speckleSection["radius"] = round.Diameter / 2 * scaleFactor; - - // dynamic props - speckleSection["centroidHorizontal"] = round.CentroidHorizontal * scaleFactor; - speckleSection["centroidVertical"] = round.CentroidVertical * scaleFactor; - } - if (revitSection is StructuralSectionHotRolled hr) - { - // static props - speckleSection["flangeThickness"] = hr.FlangeThickness * scaleFactor; - speckleSection["webThickness"] = hr.WebThickness * scaleFactor; - - // dynamic props - speckleSection["flangeThicknessLocation"] = hr.FlangeThicknessLocation * scaleFactor; - speckleSection["webThicknessLocation"] = hr.WebThicknessLocation * scaleFactor; - speckleSection["webFillet"] = hr.WebFillet; - } - if (revitSection is StructuralSectionColdFormed cf) - { - //dynamic props - speckleSection["innerFillet"] = cf.InnerFillet * scaleFactor; - speckleSection["wallThickness"] = cf.WallNominalThickness * scaleFactor; - speckleSection["wallDesignThickness"] = cf.WallDesignThickness * scaleFactor; - } - if (revitSection is StructuralSectionGeneralI i) - { - // dynamic props - speckleSection["flangeFillet"] = i.FlangeFillet; - speckleSection["slopedFlangeAngle"] = i.SlopedFlangeAngle; - //speckleSection["flangeToeOfFillet"] = i.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - //speckleSection["webToeOfFillet"] = i.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - } - if (revitSection is StructuralSectionGeneralT t) - { - speckleSection["flangeFillet"] = t.FlangeFillet; - speckleSection["slopedFlangeAngle"] = t.SlopedFlangeAngle; - speckleSection["slopedWebAngle"] = t.SlopedWebAngle; - //speckleSection["flangeToeOfFillet"] = i.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - //speckleSection["webToeOfFillet"] = i.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - } - if (revitSection is StructuralSectionGeneralH h) - { - // static props - speckleSection["webThickness"] = h.WallNominalThickness * scaleFactor; - speckleSection["flangeThickness"] = h.WallNominalThickness * scaleFactor; - - //dynamic props - speckleSection["innerFillet"] = h.InnerFillet; - speckleSection["outerFillet"] = h.OuterFillet; - } - if (revitSection is StructuralSectionGeneralR r) - { - // static props - speckleSection["wallThickness"] = r.WallNominalThickness * scaleFactor; - - //dynamic props - speckleSection["wallDesignThickness"] = r.WallDesignThickness * scaleFactor; - } - if (revitSection is StructuralSectionGeneralW w) - { - // dynamic props - speckleSection["flangeFillet"] = w.FlangeFillet; - speckleSection["topWebFillet"] = w.TopWebFillet; - } - if (revitSection is StructuralSectionGeneralU u) - { - // dynamic props - speckleSection["flangeFillet"] = u.FlangeFillet; - speckleSection["slopedFlangeAngle"] = u.SlopedFlangeAngle; - //speckleSection["flangeToeOfFillet"] = u.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - //speckleSection["webToeOfFillet"] = u.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor - } - } - - private StructuralMaterial GetStructuralMaterial(Material material) - { - if (material == null) - return null; - - StructuralAsset materialAsset = null; - string name = null; - if (material.StructuralAssetId != ElementId.InvalidElementId) - { - materialAsset = ((PropertySetElement)material.Document.GetElement(material.StructuralAssetId)).GetStructuralAsset(); - - name = material.Document.GetElement(material.StructuralAssetId)?.Name; - } - var materialName = material.MaterialClass; - var materialType = GetMaterialType(materialName); - - var speckleMaterial = GetStructuralMaterial(materialType, materialAsset, name); - speckleMaterial.applicationId = material.UniqueId; - - return speckleMaterial; - } - - private StructuralMaterial GetStructuralMaterial(StructuralMaterialType materialType, StructuralAsset materialAsset, string name) - { - Structural.Materials.StructuralMaterial speckleMaterial = null; - - if (materialType == StructuralMaterialType.Undefined && materialAsset != null) - materialType = GetMaterialType(materialAsset); - - name ??= materialType.ToString(); - switch (materialType) - { - case StructuralMaterialType.Concrete: - var concreteMaterial = new Concrete - { - name = name, - materialType = Structural.MaterialType.Concrete, - }; - - if (materialAsset != null) - { - concreteMaterial.compressiveStrength = materialAsset.ConcreteCompression; // Newtons per foot meter - concreteMaterial.lightweight = materialAsset.Lightweight; - } - - speckleMaterial = concreteMaterial; - break; - case StructuralMaterialType.Steel: - var steelMaterial = new Steel - { - name = name, - materialType = Structural.MaterialType.Steel, - designCode = null, - codeYear = null, - maxStrain = 0, - dampingRatio = 0, - }; - - if (materialAsset != null) - { - steelMaterial.grade = materialAsset.Name; - steelMaterial.yieldStrength = materialAsset.MinimumYieldStress; // Newtons per foot meter - steelMaterial.ultimateStrength = materialAsset.MinimumTensileStrength; // Newtons per foot meter - } - - speckleMaterial = steelMaterial; - break; - case StructuralMaterialType.Wood: - var timberMaterial = new Timber - { - name = name, - materialType = Structural.MaterialType.Timber, - designCode = null, - codeYear = null, - dampingRatio = 0 - }; - - if (materialAsset != null) - { - timberMaterial.grade = materialAsset.WoodGrade; - timberMaterial.species = materialAsset.WoodSpecies; - timberMaterial["bendingStrength"] = materialAsset.WoodBendingStrength; - timberMaterial["parallelCompressionStrength"] = materialAsset.WoodParallelCompressionStrength; - timberMaterial["parallelShearStrength"] = materialAsset.WoodParallelShearStrength; - timberMaterial["perpendicularCompressionStrength"] = materialAsset.WoodPerpendicularCompressionStrength; - timberMaterial["perpendicularShearStrength"] = materialAsset.WoodPerpendicularShearStrength; - } - - speckleMaterial = timberMaterial; - break; - default: - var defaultMaterial = new Objects.Structural.Materials.StructuralMaterial - { - name = name, - }; - speckleMaterial = defaultMaterial; - break; - } - - // TODO: support non-isotropic materials - if (materialAsset != null) - { - // some of these are actually the dumbest units I've ever heard of - speckleMaterial.elasticModulus = materialAsset.YoungModulus.X; // Newtons per foot meter - speckleMaterial.poissonsRatio = materialAsset.PoissonRatio.X; // Unitless - speckleMaterial.shearModulus = materialAsset.ShearModulus.X; // Newtons per foot meter - speckleMaterial.density = materialAsset.Density; // kilograms per cubed feet - speckleMaterial.thermalExpansivity = materialAsset.ThermalExpansionCoefficient.X; // inverse Kelvin - } - - return speckleMaterial; - } - - private StructuralMaterialType GetMaterialType(string materialName) - { - StructuralMaterialType materialType = StructuralMaterialType.Undefined; - switch (materialName.ToLower()) - { - case "concrete": - materialType = StructuralMaterialType.Concrete; - break; - case "steel": - materialType = StructuralMaterialType.Steel; - break; - case "wood": - materialType = StructuralMaterialType.Wood; - break; - } - - return materialType; - } - - private StructuralMaterialType GetMaterialType(StructuralAsset materialAsset) - { - StructuralMaterialType materialType = StructuralMaterialType.Undefined; - switch (materialAsset?.StructuralAssetClass) - { - case StructuralAssetClass.Metal: - materialType = StructuralMaterialType.Steel; - break; - case StructuralAssetClass.Concrete: - materialType = StructuralMaterialType.Concrete; - break; - case StructuralAssetClass.Wood: - materialType = StructuralMaterialType.Wood; - break; - } - - return materialType; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalSurface.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalSurface.cs deleted file mode 100644 index 496d2a298f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertAnalyticalSurface.cs +++ /dev/null @@ -1,410 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using ConverterRevitShared.Models; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Properties; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Point = Objects.Geometry.Point; - - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public Objects.Geometry.Line GetBottomLine(List nodes) - { - Objects.Geometry.Line baseLine = new Objects.Geometry.Line(); - double lowest_elv = nodes.Min(nodes => nodes.basePoint.z); - List nodes1 = nodes.FindAll(node => node.basePoint.z.Equals(lowest_elv)); - if (nodes1.Count == 2) - { - var point1 = nodes1[0].basePoint; - var point2 = nodes1[1].basePoint; - baseLine = new Geometry.Line(point1, point2, point1.units); - return baseLine; - } - return null; - } - - public Objects.Geometry.Polycurve PolycurveFromTopology(List nodes) - { - Polycurve polycurve = new Polycurve(); - foreach (int index in Enumerable.Range(0, nodes.Count)) - { - if (index == nodes.Count - 1) - { - var point1 = nodes[index].basePoint; - var point2 = nodes[0].basePoint; - Geometry.Line segment = new Geometry.Line(point1, point2, point1.units); - polycurve.segments.Add(segment); - } - else - { - var point1 = nodes[index].basePoint; - var point2 = nodes[index + 1].basePoint; - Geometry.Line segment = new Geometry.Line(point1, point2, point1.units); - polycurve.segments.Add(segment); - } - } - return polycurve; - } - - public ApplicationObject AnalyticalSurfaceToNative(Element2D speckleElement) - { - var appObj = new ApplicationObject(speckleElement.id, speckleElement.speckle_type) { applicationId = speckleElement.applicationId }; - if (speckleElement.property is not Property2D prop2D) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "\"Property\" cannot be null"); - return appObj; - } - -#if REVIT2020 || REVIT2021 || REVIT2022 - appObj = CreatePhysicalMember(speckleElement); - // TODO: set properties? -#else - var elementType = GetElementType(speckleElement, appObj, out bool isExactMatch); - if (elementType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(Doc); - - // check for existing member - var docObj = GetExistingElementByApplicationId(speckleElement.applicationId); - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - AnalyticalPanel revitMember = null; - DB.Element physicalMember = null; - var isUpdate = false; - - if (docObj != null && docObj is AnalyticalPanel analyticalMember) - { - isUpdate = true; - revitMember = analyticalMember; - - // TODO check if there are openings in the panel - var polycurve = PolycurveFromTopology(speckleElement.topology); - var curveArray = CurveToNative(polycurve, true); - var curveLoop = CurveArrayToCurveLoop(curveArray); - analyticalMember.SetOuterContour(curveLoop); - - if (isExactMatch && analyticalToPhysicalManager.HasAssociation(revitMember.Id)) - { - //update type - var physicalMemberId = analyticalToPhysicalManager.GetAssociatedElementId(revitMember.Id); - physicalMember = Doc.GetElement(physicalMemberId); - - if (physicalMember.GetTypeId() != elementType.Id) - { - // collect info about current floor location and depth - var currentType = Doc.GetElement(physicalMember.GetTypeId()); - var currentTypeDepth = GetParamValue(currentType, BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM); - var currentHeightOffset = GetParamValue(physicalMember, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM); - - // change type - physicalMember.ChangeTypeId(elementType.Id); - - // make sure that the bottom of the floor remains in the same location - var newTypeDepth = GetParamValue(elementType, BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM); - TrySetParam(physicalMember, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM, currentHeightOffset + (newTypeDepth - currentTypeDepth)); - } - } - } - - //create analytical panel (floor or wall) - if (revitMember == null) - { - var polycurve = PolycurveFromTopology(speckleElement.topology); - var curveArray = CurveToNative(polycurve, true); - var curveLoop = CurveArrayToCurveLoop(curveArray); - revitMember = AnalyticalPanel.Create(Doc, curveLoop); - } - - // if there isn't an associated physical element to the analytical element, create it - if (!analyticalToPhysicalManager.HasAssociation(revitMember.Id)) - { - var physicalMemberAppObj = CreatePhysicalMember(speckleElement); - physicalMember = (DB.Element)physicalMemberAppObj.Converted.FirstOrDefault(); - analyticalToPhysicalManager.AddAssociation(revitMember.Id, physicalMember.Id); - - appObj.Update(createdId: physicalMember.UniqueId, convertedItem: physicalMember); - } - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitMember.UniqueId, convertedItem: revitMember); - -#endif - return appObj; - } - - private ApplicationObject CreatePhysicalMember(Element2D speckleElement) - { - var appObj = new ApplicationObject(speckleElement.id, speckleElement.speckle_type); - if (!(speckleElement.property is Property2D prop2D)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "\"Property\" cannot be null"); - return appObj; - } - - switch (prop2D.type) - { - case Structural.PropertyType2D.Wall: - var baseline = GetBottomLine(speckleElement.topology); - var lowestElvevation = speckleElement.topology.Min(node => node.basePoint.z); - var topElevation = speckleElement.topology.Max(node => node.basePoint.z); - var bottomNode = speckleElement.topology.Find(node => node.basePoint.z == lowestElvevation); - var topNode = speckleElement.topology.Find(node => node.basePoint.z == topElevation); - var bottemLevel = LevelFromPoint(PointToNative(bottomNode.basePoint)); - var topLevel = LevelFromPoint(PointToNative(topNode.basePoint)); - var revitWall = new RevitWall(speckleElement.property.name, speckleElement.property.name, baseline, bottemLevel, topLevel); -#if REVIT2020 || REVIT2021 || REVIT2022 - revitWall.applicationId = speckleElement.applicationId; -#endif - return WallToNative(revitWall); - - default: - var polycurve = PolycurveFromTopology(speckleElement.topology); - var level = LevelFromPoint(PointToNative(speckleElement.topology[0].basePoint)); - var speckleFloor = new BuiltElements.Floor(polycurve); - SetElementType(speckleFloor, speckleElement.property.name); -#if REVIT2020 || REVIT2021 || REVIT2022 - speckleFloor.applicationId = speckleElement.applicationId; -#endif - return FloorToNative(speckleFloor); - } - } - -#if REVIT2020 || REVIT2021 || REVIT2022 - private Element2D AnalyticalSurfaceToSpeckle(AnalyticalModelSurface revitSurface) - { - if (!revitSurface.IsEnabled()) - return new Element2D(); - - var speckleElement2D = new Element2D(); - var structuralElement = revitSurface.Document.GetElement(revitSurface.GetElementId()); - var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); - speckleElement2D.name = mark; - - var openings = GetOpeningsAsPolylineFromSurface(revitSurface).ToList(); - var edgePoints = GetSurfaceOuterLoop(revitSurface).ToList(); - - Element2DOutlineBuilder outlineBuilder = new(openings, edgePoints); - - speckleElement2D.openings = openings.Select(polyLine => new Polycurve(ModelUnits) - { - segments = new() { polyLine } - }) - .ToList(); - - speckleElement2D.topology = outlineBuilder - .GetOutline() - .Select(p => new Node(p)) - .ToList(); - - speckleElement2D.displayValue = GetElementDisplayValue(revitSurface); - - var prop = new Property2D(); - - // Material - DB.Material structMaterial = null; - double thickness = 0; - var memberType = MemberType2D.Generic2D; - - if (structuralElement is DB.Floor) - { - var floor = structuralElement as DB.Floor; - structMaterial = floor.Document.GetElement(floor.FloorType.StructuralMaterialId) as DB.Material; - thickness = GetParamValue(structuralElement, BuiltInParameter.STRUCTURAL_FLOOR_CORE_THICKNESS); - memberType = MemberType2D.Slab; - } - else if (structuralElement is DB.Wall) - { - var wall = structuralElement as DB.Wall; - structMaterial = wall.Document.GetElement(wall.WallType.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId()) as DB.Material; - thickness = ScaleToSpeckle(wall.WallType.Width); - memberType = MemberType2D.Wall; - } - - var speckleMaterial = GetStructuralMaterial(structMaterial); - - prop.material = speckleMaterial; - - prop.name = revitSurface.Document.GetElement(revitSurface.GetElementId()).Name; - //prop.type = memberType; - //prop.analysisType = Structural.AnalysisType2D.Shell; - prop.thickness = thickness; - - speckleElement2D.property = prop; - - GetAllRevitParamsAndIds(speckleElement2D, revitSurface); - - return speckleElement2D; - } - - private IEnumerable GetSurfaceOuterLoop(AnalyticalModelSurface surface) - { - IList loops = surface.GetLoops(AnalyticalLoopType.External); - foreach (XYZ xyz in EnumerateCurveLoopWithMostPoints(loops)) - { - yield return PointToSpeckle(xyz, surface.Document); - } - } - - private IEnumerable GetOpeningsAsPolylineFromSurface(AnalyticalModelSurface surface) - { - surface.GetOpenings(out ICollection openingIds); - foreach (ElementId openingId in openingIds) - { - foreach (CurveLoop loop in surface.GetOpeningLoops(openingId)) - { - IEnumerable points = EnumerateCurveLoopAsPoints(loop); - List coordinateList = points - .Select(p => PointToSpeckle(p, surface.Document)) - .SelectMany(specklePoint => specklePoint.ToList()) - .ToList(); - - // add back first point to close the polyline - coordinateList.Add(coordinateList[0]); - coordinateList.Add(coordinateList[1]); - coordinateList.Add(coordinateList[2]); - yield return new Polyline(coordinateList, ModelUnits); - } - } - } - - /// - /// Revit walls and floors can have multiple different areas that are part of the same wall. - /// This isn't currently supported by our object model, and currently it is not possible to return multiple - /// floors from floorToNative, so right now we're just converting the area that has the most line segments - /// - /// - /// - IEnumerable EnumerateCurveLoopWithMostPoints(IEnumerable curveLoops) - { - List curveLoopList = curveLoops.ToList(); - Dictionary loopCounts = new(); - foreach (var loop in curveLoopList) - { - loopCounts.Add(loop, loop.Count()); - } - - CurveLoop largestLoop = loopCounts.OrderByDescending(kvp => kvp.Value).First().Key; - return EnumerateCurveLoopAsPoints(largestLoop); - } - - IEnumerable EnumerateCurveLoopAsPoints(CurveLoop loop) - { - foreach (var curve in loop) - { - var points = curve.Tessellate(); - // here we are skipping the first point each time because - // it is always the same as the last point of the previous curve - foreach (var point in points.Skip(1)) - { - yield return point; - } - } - } -#else - private Element2D AnalyticalSurfaceToSpeckle(AnalyticalPanel revitSurface) - { - var speckleElement2D = new Element2D(); - - var structuralElement = revitSurface; - - var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); - speckleElement2D.name = mark; - - var edgeNodes = new List { }; - var loops = revitSurface.GetOuterContour(); - - var displayLine = new Polycurve(); - foreach (var loop in loops) - { - var coor = new List(); - - var points = loop.Tessellate(); - - foreach (var p in points.Skip(1)) - { - var vertex = PointToSpeckle(p, revitSurface.Document); - var edgeNode = new Node(vertex, null, null, null); - edgeNodes.Add(edgeNode); - } - - displayLine.segments.Add(CurveToSpeckle(loop, revitSurface.Document)); - } - - speckleElement2D.topology = edgeNodes; - var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(Doc); - if (analyticalToPhysicalManager.HasAssociation(revitSurface.Id)) - { - var physicalElementId = analyticalToPhysicalManager.GetAssociatedElementId(revitSurface.Id); - var physicalElement = Doc.GetElement(physicalElementId); - speckleElement2D.displayValue = GetElementDisplayValue(physicalElement); - } - - speckleElement2D.openings = GetOpenings(revitSurface); - - var prop = new Property2D(); - - // Material - DB.Material structMaterial = null; - double thickness = 0; - var memberType = MemberType2D.Generic2D; - - if (structuralElement.StructuralRole is AnalyticalStructuralRole.StructuralRoleFloor) - { - structMaterial = structuralElement.Document.GetElement(structuralElement.MaterialId) as DB.Material; - thickness = structuralElement.Thickness; - memberType = MemberType2D.Slab; - } - else if (structuralElement.StructuralRole is AnalyticalStructuralRole.StructuralRoleWall) - { - - structMaterial = structuralElement.Document.GetElement(structuralElement.MaterialId) as DB.Material; - thickness = structuralElement.Thickness; - memberType = MemberType2D.Wall; - } - - var speckleMaterial = GetStructuralMaterial(structMaterial); - prop.material = speckleMaterial; - - prop.name = structuralElement.Name; - //prop.type = memberType; - //prop.analysisType = Structural.AnalysisType2D.Shell; - prop.thickness = thickness; - - speckleElement2D.property = prop; - - GetAllRevitParamsAndIds(speckleElement2D, revitSurface); - - return speckleElement2D; - } - - private List GetOpenings(AnalyticalPanel revitSurface) - { - var openings = new List(); - foreach (var openingId in revitSurface.GetAnalyticalOpeningsIds()) - { - if (revitSurface.Document.GetElement(openingId) is not AnalyticalOpening opening) continue; - - var curveLoop = opening.GetOuterContour(); - openings.Add(CurveLoopToSpeckle(curveLoop, revitSurface.Document)); - } - return openings; - } -#endif - } - -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertArea.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertArea.cs deleted file mode 100644 index 745d8a0152..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertArea.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Linq; -using Autodesk.Revit.DB; -using DB = Autodesk.Revit.DB; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - //public List AreaToNative(BuiltElements.Area speckleArea) - //{ - // var revitRoom = GetExistingElementByApplicationId(speckleArea.applicationId) as DB.Area; - // var level = LevelToNative(speckleArea.level); - - - // //TODO: support updating rooms - // if (revitRoom != null) - // { - // Doc.Delete(revitRoom.Id); - // } - - // revitRoom = Doc.Create.NewArea(level, new UV(speckleArea.center.x, speckleArea.center.y)); - - // revitRoom.Name = speckleArea.name; - // revitRoom.Number = speckleArea.number; - - // SetInstanceParameters(revitRoom, speckleArea); - - // var placeholders = new List() - // { - // new ApplicationObject - // { - // applicationId = speckleArea.applicationId, - // ApplicationGeneratedId = revitRoom.UniqueId, - // NativeObject = revitRoom - // } - // }; - - // return placeholders; - - //} - - public BuiltElements.Area AreaToSpeckle(DB.Area revitArea) - { - var profiles = GetProfiles(revitArea); - - var speckleArea = new BuiltElements.Area(); - - speckleArea.name = revitArea.get_Parameter(BuiltInParameter.ROOM_NAME).AsString(); - speckleArea.number = revitArea.Number; - speckleArea.center = (Point)LocationToSpeckle(revitArea); - speckleArea.level = ConvertAndCacheLevel(revitArea, BuiltInParameter.ROOM_LEVEL_ID); - if (profiles.Any()) - speckleArea.outline = profiles[0]; - speckleArea.area = GetParamValue(revitArea, BuiltInParameter.ROOM_AREA); - if (profiles.Count > 1) - speckleArea.voids = profiles.Skip(1).ToList(); - - GetAllRevitParamsAndIds(speckleArea, revitArea); - - //no mesh seems to be retriavable, not even using the SpatialElementGeometryCalculator - //speckleArea.displayValue = GetElementDisplayValue(revitArea); - return speckleArea; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBeam.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBeam.cs deleted file mode 100644 index 638033d73e..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBeam.cs +++ /dev/null @@ -1,159 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - // CAUTION: this string needs to have the same values as in the connector - const string StructuralFraming = "Structural Framing"; - - public ApplicationObject BeamToNative(Beam speckleBeam, StructuralType structuralType = StructuralType.Beam) - { - var docObj = GetExistingElementByApplicationId(speckleBeam.applicationId); - var appObj = new ApplicationObject(speckleBeam.id, speckleBeam.speckle_type) - { - applicationId = speckleBeam.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (speckleBeam.baseLine == null) - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: "Only line based Beams are currently supported." - ); - return appObj; - } - - var familySymbol = GetElementType(speckleBeam, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var baseLine = CurveToNative(speckleBeam.baseLine).get_Item(0); - - var levelState = ApplicationObject.State.Unknown; - double baseOffset = 0.0; - DB.Level level = - (speckleBeam.level != null) - ? ConvertLevelToRevit(speckleBeam.level, out levelState) - : ConvertLevelToRevit(baseLine, out levelState, out baseOffset); - - //comes from revit or schema builder, has these props - var speckleRevitBeam = speckleBeam as RevitBeam; - if (speckleRevitBeam != null) - if (level != null) - level = GetLevelByName(speckleRevitBeam.level.name); - - DB.FamilyInstance revitBeam = null; - - var isUpdate = false; - - if (docObj != null) - { - try - { - var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; - - // if family changed, tough luck. delete and let us create a new one. - if (familySymbol.FamilyName != revitType.FamilyName) - { - Doc.Delete(docObj.Id); - } - else - { - revitBeam = (DB.FamilyInstance)docObj; - - // if we combine the following two statements, it results in an error that the beam is unable to be - // bent into position. For some reason separating the curve variable declaration and the curve setting - // fixes this issue. I'm not sure if this is a permanent fix. If not, then I think the solution is to - // disassociate the beam from the current workplane and then setting the new curve - var existingCurve = (revitBeam.Location as LocationCurve).Curve; - existingCurve = baseLine; - - // check for a type change - if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) - { - revitBeam.ChangeTypeId(familySymbol.Id); - } - } - isUpdate = true; - } - catch - { - //something went wrong, re-create it - } - } - - //create family instance - if (revitBeam == null) - { - revitBeam = Doc.Create.NewFamilyInstance(baseLine, familySymbol, level, structuralType); - // check for disallow join for beams in user settings - // currently, this setting only applies to beams being created - - if (Settings.ContainsKey("disallow-join") && !string.IsNullOrEmpty(Settings["disallow-join"])) - { - List joinSettings = new List(Regex.Split(Settings["disallow-join"], @"\,\ ")); - if (joinSettings.Contains(StructuralFraming)) - { - StructuralFramingUtils.DisallowJoinAtEnd(revitBeam, 0); - StructuralFramingUtils.DisallowJoinAtEnd(revitBeam, 1); - } - } - } - - //reference level, only for beams - TrySetParam(revitBeam, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM, level); - - if (speckleRevitBeam != null) - SetInstanceParameters(revitBeam, speckleRevitBeam); - else - TrySetParam(revitBeam, BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM, -baseOffset); - - // TODO: get sub families, it's a family! - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitBeam.UniqueId, convertedItem: revitBeam); - //appObj = SetHostedElements(speckleBeam, revitBeam, appObj); - return appObj; - } - - private Base BeamToSpeckle(DB.FamilyInstance revitBeam, out List notes) - { - notes = new List(); - var baseGeometry = LocationToSpeckle(revitBeam); - var baseLine = baseGeometry as ICurve; - if (baseLine == null) - { - notes.Add($"Beam has no valid baseline, converting as generic element"); - return RevitElementToSpeckle(revitBeam, out notes); - } - var symbol = revitBeam.Document.GetElement(revitBeam.GetTypeId()) as FamilySymbol; - - var speckleBeam = new RevitBeam(); - speckleBeam.family = symbol.FamilyName; - speckleBeam.type = revitBeam.Document.GetElement(revitBeam.GetTypeId()).Name; - speckleBeam.baseLine = baseLine; - speckleBeam.level = ConvertAndCacheLevel(revitBeam, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); - - speckleBeam.displayValue = GetElementDisplayValue(revitBeam); - - GetAllRevitParamsAndIds(speckleBeam, revitBeam); - - return speckleBeam; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBrace.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBrace.cs deleted file mode 100644 index 83346bf453..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBrace.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject BraceToNative(Brace speckleBrace) - { - //reuse ConversionLog.Addic in Beam class, at these are basically the same thing - if (speckleBrace is RevitBrace rb) - { - var speckleBeam = new RevitBeam - { - baseLine = rb.baseLine, - type = rb.type, - level = rb.level, - family = rb.family, - parameters = rb.parameters, - applicationId = rb.applicationId, - }; - - return BeamToNative(speckleBeam, StructuralType.Brace); - } - else - { - var speckleBeam = new Beam(); - speckleBeam.baseLine = speckleBrace.baseLine; - speckleBeam.applicationId = speckleBrace.applicationId; - return BeamToNative(speckleBeam, StructuralType.Brace); - } - } - - private Base BraceToSpeckle(DB.FamilyInstance myFamily, out List notes) - { - notes = new List(); - var myBeam = BeamToSpeckle(myFamily, out notes) as RevitBeam; - - var myBrace = new RevitBrace() - { - applicationId = myBeam.applicationId, - type = myBeam.type, - baseLine = myBeam.baseLine, - level = myBeam.level, - family = myBeam.family, - parameters = myBeam.parameters, - displayValue = myBeam.displayValue, - }; - - var dynamicProps = myBeam.GetMembers(DynamicBaseMemberType.Dynamic); - - foreach (var dp in dynamicProps) - myBrace[dp.Key] = dp.Value; - - return myBrace; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBuildingPad.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBuildingPad.cs deleted file mode 100644 index cfcab61e7f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBuildingPad.cs +++ /dev/null @@ -1,32 +0,0 @@ - -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB.Architecture; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - //NOTE: BuildingPad cannot be created from the API AFAIK - private BuildingPad BuildingPadToSpeckle(DB.BuildingPad revitPad) - { - var profiles = GetProfiles(revitPad); - - var specklePad = new BuildingPad(); - specklePad.type = revitPad.Document.GetElement(revitPad.GetTypeId()).Name; - specklePad.outline = profiles[0]; - if (profiles.Count > 1) - specklePad.voids = profiles.Skip(1).ToList(); - - specklePad.level = ConvertAndCacheLevel(revitPad, BuiltInParameter.LEVEL_PARAM); - - GetAllRevitParamsAndIds(specklePad, revitPad, new List { "LEVEL_PARAM" }); - - specklePad.displayValue = GetElementDisplayValue(revitPad); - - return specklePad; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCableTray.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCableTray.cs deleted file mode 100644 index 1a555bd635..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCableTray.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Electrical; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject CableTrayToNative(BuiltElements.CableTray speckleCableTray) - { - var speckleRevitCableTray = speckleCableTray as RevitCableTray; - - var docObj = GetExistingElementByApplicationId((speckleCableTray).applicationId); - var appObj = new ApplicationObject(speckleCableTray.id, speckleCableTray.speckle_type) { applicationId = speckleCableTray.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - var cableTrayType = GetElementType(speckleCableTray, appObj, out bool _); - if (cableTrayType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - Element cableTray = null; - if (speckleCableTray.baseCurve is Line) - { - DB.Line baseLine = LineToNative(speckleCableTray.baseCurve as Line); - XYZ startPoint = baseLine.GetEndPoint(0); - XYZ endPoint = baseLine.GetEndPoint(1); - DB.Level lineLevel = ConvertLevelToRevit(speckleRevitCableTray != null ? speckleRevitCableTray.level : LevelFromCurve(baseLine), out ApplicationObject.State levelState); - CableTray lineCableTray = CableTray.Create(Doc, cableTrayType.Id, startPoint, endPoint, lineLevel.Id); - cableTray = lineCableTray; - } - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"BaseCurve of type ${speckleCableTray.baseCurve.GetType()} cannot be used to create a Revit CableTray"); - return appObj; - } - - // deleting instead of updating for now! - if (docObj != null) - Doc.Delete(docObj.Id); - - if (speckleRevitCableTray != null) - { - TrySetParam(cableTray, BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM, speckleRevitCableTray.height, speckleRevitCableTray.units); - TrySetParam(cableTray, BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM, speckleRevitCableTray.width, speckleRevitCableTray.units); - TrySetParam(cableTray, BuiltInParameter.CURVE_ELEM_LENGTH, speckleRevitCableTray.length, speckleRevitCableTray.units); - SetInstanceParameters(cableTray, speckleRevitCableTray); - } - - CreateSystemConnections(speckleRevitCableTray.Connectors, cableTray, receivedObjectsCache); - - appObj.Update(status: ApplicationObject.State.Created, createdId: cableTray.UniqueId, convertedItem: cableTray); - return appObj; - } - - public BuiltElements.CableTray CableTrayToSpeckle(DB.Electrical.CableTray revitCableTray) - { - var baseGeometry = LocationToSpeckle(revitCableTray); - if (!(baseGeometry is Line baseLine)) - throw new Speckle.Core.Logging.SpeckleException("Only line based CableTrays are currently supported."); - - var cableTrayType = revitCableTray.Document.GetElement(revitCableTray.GetTypeId()) as CableTrayType; - - // SPECKLE CABLETRAY - var speckleCableTray = new RevitCableTray - { - family = cableTrayType.FamilyName, - type = cableTrayType.Name, - baseCurve = baseLine, - height = GetParamValue(revitCableTray, BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM), - width = GetParamValue(revitCableTray, BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM), - length = GetParamValue(revitCableTray, BuiltInParameter.CURVE_ELEM_LENGTH), - level = ConvertAndCacheLevel(revitCableTray, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitCableTray) - }; - - GetAllRevitParamsAndIds(speckleCableTray, revitCableTray, - new List - { - "RBS_CABLETRAY_HEIGHT_PARAM", "RBS_CABLETRAY_WIDTH_PARAM", "CURVE_ELEM_LENGTH", "RBS_START_LEVEL_PARAM" - }); - - foreach (var connector in revitCableTray.GetConnectorSet()) - { - speckleCableTray.Connectors.Add(ConnectorToSpeckle(connector)); - } - - return speckleCableTray; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCeiling.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCeiling.cs deleted file mode 100644 index 6fe7c07641..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCeiling.cs +++ /dev/null @@ -1,115 +0,0 @@ - -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using Ceiling = Objects.BuiltElements.Ceiling; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private RevitCeiling CeilingToSpeckle(DB.Ceiling revitCeiling, out List notes) - { - notes = new List(); -#if REVIT2020 || REVIT2021 - var profiles = GetProfiles(revitCeiling); -#else - var sketch = Doc.GetElement(revitCeiling.SketchId) as Sketch; - var profiles = GetSketchProfiles(sketch).Cast().ToList(); -#endif - var speckleCeiling = new RevitCeiling(); - speckleCeiling.type = revitCeiling.Document.GetElement(revitCeiling.GetTypeId()).Name; - speckleCeiling.outline = profiles[0]; - if (profiles.Count > 1) - speckleCeiling.voids = profiles.Skip(1).ToList(); - - speckleCeiling.level = ConvertAndCacheLevel(revitCeiling, BuiltInParameter.LEVEL_PARAM); - - GetAllRevitParamsAndIds(speckleCeiling, revitCeiling, new List { "LEVEL_PARAM" }); - - GetHostedElements(speckleCeiling, revitCeiling, out List hostedNotes); - if (hostedNotes.Any()) notes.AddRange(hostedNotes); //TODO: what are we doing here? - - speckleCeiling.displayValue = GetElementDisplayValue(revitCeiling); - - return speckleCeiling; - } - -#if REVIT2020 || REVIT2021 -#else - public ApplicationObject CeilingToNative(Ceiling speckleCeiling) - { - var docObj = GetExistingElementByApplicationId(speckleCeiling.applicationId); - var appObj = new ApplicationObject(speckleCeiling.id, speckleCeiling.speckle_type) { applicationId = speckleCeiling.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (speckleCeiling.outline == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Missing an outline curve."); - return appObj; - } - - var outline = CurveToNative(speckleCeiling.outline); - var profile = new CurveLoop(); - foreach (DB.Curve segment in outline) - profile.Append(segment); - - DB.Level level = null; - double slope = 0; - DB.Line slopeDirection = null; - var levelState = ApplicationObject.State.Unknown; - if (speckleCeiling is RevitCeiling speckleRevitCeiling) - { - level = ConvertLevelToRevit(speckleRevitCeiling.level, out levelState); - slope = speckleRevitCeiling.slope; - slopeDirection = (speckleRevitCeiling.slopeDirection != null) ? LineToNative(speckleRevitCeiling.slopeDirection) : null; - } - else - { - level = ConvertLevelToRevit(LevelFromCurve(outline.get_Item(0)), out levelState); - } - - var ceilingType = GetElementType(speckleCeiling, appObj, out bool _); - if (ceilingType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (docObj != null) - Doc.Delete(docObj.Id); - - DB.Ceiling revitCeiling; - - if (slope != 0 && slopeDirection != null) - revitCeiling = DB.Ceiling.Create(Doc, new List { profile }, ceilingType.Id, level.Id, slopeDirection, slope); - else - revitCeiling = DB.Ceiling.Create(Doc, new List { profile }, ceilingType.Id, level.Id); - - Doc.Regenerate(); - - try - { - CreateVoids(revitCeiling, speckleCeiling); - } - catch (Exception ex) - { - appObj.Update(logItem: $"Could not create openings: {ex.Message}"); - } - - SetInstanceParameters(revitCeiling, speckleCeiling); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitCeiling.UniqueId, convertedItem: revitCeiling); - //appObj = SetHostedElements(speckleCeiling, revitCeiling, appObj); - return appObj; - } -#endif - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertColumn.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertColumn.cs deleted file mode 100644 index a39aa44cd7..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertColumn.cs +++ /dev/null @@ -1,299 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using Column = Objects.BuiltElements.Column; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject ColumnToNative(Column speckleColumn) - { - var docObj = GetExistingElementByApplicationId(speckleColumn.applicationId); - var appObj = new ApplicationObject(speckleColumn.id, speckleColumn.speckle_type) - { - applicationId = speckleColumn.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (speckleColumn.baseLine == null) - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: "Only line based Beams are currently supported." - ); - return appObj; - } - - var familySymbol = GetElementType(speckleColumn, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var baseLine = CurveToNative(speckleColumn.baseLine).get_Item(0); - - // If the start point elevation is higher than the end point elevation, reverse the line. - if (baseLine.GetEndPoint(0).Z > baseLine.GetEndPoint(1).Z) - baseLine = DB.Line.CreateBound(baseLine.GetEndPoint(1), baseLine.GetEndPoint(0)); - - DB.FamilyInstance revitColumn = null; - //var structuralType = StructuralType.Column; - var isLineBased = true; - - var levelState = ApplicationObject.State.Unknown; - double baseOffset = 0.0; - DB.Level level = - (speckleColumn.level != null) - ? ConvertLevelToRevit(speckleColumn.level, out levelState) - : ConvertLevelToRevit(baseLine, out levelState, out baseOffset); - - var speckleRevitColumn = speckleColumn as RevitColumn; - - double topOffset = 0.0; - DB.Level topLevel = null; - if (speckleRevitColumn != null) - { - topLevel = ConvertLevelToRevit(speckleRevitColumn.topLevel, out levelState); - //structuralType = speckleRevitColumn.structural ? StructuralType.Column : StructuralType.NonStructural; - //non slanted columns are point based - isLineBased = speckleRevitColumn.isSlanted; - } - - if (topLevel == null) - topLevel = ConvertLevelToRevit(baseLine.GetEndPoint(1), out levelState, out topOffset); - - //try update existing - - bool isUpdate = false; - if (docObj != null) - { - try - { - var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; - - // if family changed, tough luck. delete and let us create a new one. - if (familySymbol.FamilyName != revitType.FamilyName) - Doc.Delete(docObj.Id); - else - { - revitColumn = (DB.FamilyInstance)docObj; - switch (revitColumn.Location) - { - case LocationCurve crv: - crv.Curve = baseLine; - break; - case LocationPoint pt: - pt.Point = baseLine.GetEndPoint(0); - break; - } - - // check for a type change - if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) - { - revitColumn.ChangeTypeId(familySymbol.Id); - } - } - isUpdate = true; - } - catch { } - } - - if (revitColumn == null && isLineBased) - { - revitColumn = Doc.Create.NewFamilyInstance(baseLine, familySymbol, level, StructuralType.Column); - if (revitColumn.Symbol.Family.FamilyPlacementType == FamilyPlacementType.CurveDrivenStructural) - { - StructuralFramingUtils.DisallowJoinAtEnd(revitColumn, 0); - StructuralFramingUtils.DisallowJoinAtEnd(revitColumn, 1); - } - } - - var start = baseLine.GetEndPoint(0); - var end = baseLine.GetEndPoint(1); - var basePoint = start.Z < end.Z ? start : end; // pick the lowest - //try with a point based column - if (speckleRevitColumn != null && revitColumn == null && !isLineBased) - revitColumn = Doc.Create.NewFamilyInstance(basePoint, familySymbol, level, StructuralType.NonStructural); - - //rotate - if (speckleRevitColumn != null && revitColumn != null) - { - var currentRotation = (revitColumn.Location as LocationPoint)?.Rotation; - - if (currentRotation != null && currentRotation != speckleRevitColumn.rotation) - { - var axis = DB.Line.CreateBound( - new XYZ(basePoint.X, basePoint.Y, 0), - new XYZ(basePoint.X, basePoint.Y, 10000) - ); - var s = (revitColumn.Location as LocationPoint).Rotate( - axis, - speckleRevitColumn.rotation - (double)currentRotation - ); - } - } - - if (revitColumn == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "revit column was null"); - return appObj; - } - - TrySetParam(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); - TrySetParam(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, topLevel); - - if (speckleRevitColumn != null) - { - if (speckleRevitColumn.handFlipped != revitColumn.HandFlipped) - revitColumn.flipHand(); - - if (speckleRevitColumn.facingFlipped != revitColumn.FacingFlipped) - revitColumn.flipFacing(); - - //don't change offset for slanted columns, it's automatic - if (!isLineBased) - SetOffsets( - revitColumn, - level, - topLevel, - ScaleToNative(speckleRevitColumn.baseOffset, speckleRevitColumn.units), - ScaleToNative(speckleRevitColumn.topOffset, speckleRevitColumn.units) - ); - - SetInstanceParameters(revitColumn, speckleRevitColumn); - } - else - { - // this case is always line based, don't change offset for line based columns, it's automatic - } - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitColumn.UniqueId, convertedItem: revitColumn); - // TODO: nested elements. - //appObj = SetHostedElements(speckleColumn, revitColumn, appObj); - return appObj; - } - - /// - /// Some families eg columns, need offsets to be set in a specific way. This tries to cover that. - /// - /// - /// - private void SetOffsets( - DB.FamilyInstance familyInstance, - Level level, - Level topLevel, - double baseOffset, - double topOffset - ) - { - var topOffsetParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - var baseOffsetParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - var baseLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - var topLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - - if (topLevelParam == null || baseLevelParam == null || baseOffsetParam == null || topOffsetParam == null) - return; - - // the column length cannot be 0 for even an instance or Revit will throw a fit. - // Make sure that setting the offset on one side of the column before setting the - // other side doesn't leave the length of the column as approximately 0 - var colHeightAfterBaseOffset = level.Elevation + baseOffset - topLevel.Elevation; - var colHeightAfterTopOffset = topLevel.Elevation + topOffset - level.Elevation; - - if (Math.Abs(colHeightAfterBaseOffset) > TOLERANCE) - { - baseOffsetParam.Set(baseOffset); - topOffsetParam.Set(topOffset); - } - else if (Math.Abs(colHeightAfterTopOffset) > TOLERANCE) - { - topOffsetParam.Set(topOffset); - baseOffsetParam.Set(baseOffset); - } - else - { - baseOffsetParam.Set(baseOffset / 2); // temporarily set this value to something else so the sides of the column can switch places - topOffsetParam.Set(topOffset); - baseOffsetParam.Set(baseOffset); - } - } - - public Base ColumnToSpeckle(DB.FamilyInstance revitColumn, out List notes) - { - notes = new List(); - var symbol = revitColumn.Document.GetElement(revitColumn.GetTypeId()) as FamilySymbol; - - var speckleColumn = new RevitColumn(); - speckleColumn.family = symbol.FamilyName; - speckleColumn.type = revitColumn.Document.GetElement(revitColumn.GetTypeId()).Name; - speckleColumn.level = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - speckleColumn.topLevel = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - speckleColumn.baseOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - speckleColumn.topOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - speckleColumn.facingFlipped = revitColumn.FacingFlipped; - speckleColumn.handFlipped = revitColumn.HandFlipped; - speckleColumn.isSlanted = revitColumn.IsSlantedColumn; - //speckleColumn.structural = revitColumn.StructuralType == StructuralType.Column; - - //geometry - var baseGeometry = LocationToSpeckle(revitColumn); - var baseLine = baseGeometry as ICurve; - - //make line from point and height - if (baseLine == null && baseGeometry is Point basePoint) - { - if ( - symbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased - || symbol.Family.FamilyPlacementType == FamilyPlacementType.WorkPlaneBased - ) - return RevitInstanceToSpeckle(revitColumn, out notes, null); - - var elevation = speckleColumn.topLevel.elevation; - baseLine = new Line( - basePoint, - new Point(basePoint.x, basePoint.y, elevation + speckleColumn.topOffset, ModelUnits), - ModelUnits - ); - } - - if (baseLine == null) - return RevitElementToSpeckle(revitColumn, out notes); - - speckleColumn.baseLine = baseLine; //all speckle columns should be line based - - GetAllRevitParamsAndIds( - speckleColumn, - revitColumn, - new List - { - "FAMILY_BASE_LEVEL_PARAM", - "FAMILY_TOP_LEVEL_PARAM", - "FAMILY_BASE_LEVEL_OFFSET_PARAM", - "FAMILY_TOP_LEVEL_OFFSET_PARAM", - "SCHEDULE_BASE_LEVEL_OFFSET_PARAM", - "SCHEDULE_TOP_LEVEL_OFFSET_PARAM" - } - ); - - if (revitColumn.Location is LocationPoint) - speckleColumn.rotation = ((LocationPoint)revitColumn.Location).Rotation; - - speckleColumn.displayValue = GetElementDisplayValue(revitColumn); - - return speckleColumn; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCombinableElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCombinableElement.cs deleted file mode 100644 index 8dadd9d83b..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCombinableElement.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - - public FreeformElement CombinableElementToSpeckle(CombinableElement combinableElement) - { - var cat = ((BuiltInCategory)combinableElement.Document.OwnerFamily.FamilyCategoryId.IntegerValue).ToString(); - - Options options = new Options(); - if (combinableElement is GenericForm gf && gf.Combinations.Size != 0) - { - //for receive and convert to native - options.IncludeNonVisibleObjects = true; - } - - var element = combinableElement.get_Geometry(options); - var geometries = new List(); - foreach (var obj in element) - { - switch (obj) - { - case Autodesk.Revit.DB.Mesh mesh: - geometries.Add(MeshToSpeckle(mesh, combinableElement.Document)); - break; - case Solid solid: // TODO Should be replaced with 'BrepToSpeckle' when it works. - geometries.AddRange(ConvertSolidsByRenderMaterial(new[] { solid }, combinableElement.Document)); - break; - } - } - var speckleForm = new FreeformElement(); - speckleForm.subcategory = cat; - speckleForm["type"] = combinableElement.Name; - speckleForm.baseGeometries = new List(); - - if (combinableElement is GenericForm) - { - speckleForm.baseGeometries = geometries; - GetAllRevitParamsAndIds(speckleForm, combinableElement); - } - - if (combinableElement is GeomCombination || (combinableElement is GenericForm genericForm && genericForm.Combinations.Size == 0)) - { - List displayValue = new List(); - foreach (Base geo in geometries) - { - switch (geo["displayValue"]) - { - case null: - //geo has no display value, we assume it is itself a valid displayValue - displayValue.Add(geo); - break; - - case Base b: - displayValue.Add(b); - break; - - case IEnumerable e: - displayValue.AddRange(e); - break; - } - } - - speckleForm.displayValue = displayValue; - } - - return speckleForm; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConduit.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConduit.cs deleted file mode 100644 index 9b90497af6..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConduit.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Electrical; -using Autodesk.Revit.DB.Mechanical; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject ConduitToNative(BuiltElements.Conduit speckleConduit) - { - var speckleRevitConduit = speckleConduit as RevitConduit; - - var docObj = GetExistingElementByApplicationId(speckleConduit.applicationId); - var appObj = new ApplicationObject(speckleConduit.id, speckleConduit.speckle_type) { applicationId = speckleConduit.applicationId }; - if (docObj != null && ReceiveMode == Speckle.Core.Kits.ReceiveMode.Ignore) - { - appObj.Update(status: ApplicationObject.State.Skipped, createdId: docObj.UniqueId, convertedItem: docObj); - return appObj; - } - - if (!(speckleConduit.baseCurve is Line)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"BaseCurve of type ${speckleConduit.baseCurve.GetType()} cannot be used to create a Revit Conduit"); - return appObj; - } - - var conduitType = GetElementType(speckleConduit, appObj, out bool _); - if (conduitType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - DB.Line baseLine = LineToNative(speckleConduit.baseCurve as Line); - XYZ startPoint = baseLine.GetEndPoint(0); - XYZ endPoint = baseLine.GetEndPoint(1); - DB.Level lineLevel = ConvertLevelToRevit(speckleRevitConduit != null ? speckleRevitConduit.level : LevelFromCurve(baseLine), out ApplicationObject.State levelState); - var conduit = Conduit.Create(Doc, conduitType.Id, startPoint, endPoint, lineLevel.Id); - - if (conduit == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Creation returned null"); - return appObj; - } - - // deleting instead of updating for now! - if (docObj != null) - Doc.Delete(docObj.Id); - - if (speckleRevitConduit != null) - { - TrySetParam(conduit, BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM, speckleRevitConduit.diameter, speckleRevitConduit.units); - TrySetParam(conduit, BuiltInParameter.CURVE_ELEM_LENGTH, speckleRevitConduit.length, speckleRevitConduit.units); - SetInstanceParameters(conduit, speckleRevitConduit); - } - - CreateSystemConnections(speckleRevitConduit.Connectors, conduit, receivedObjectsCache); - - appObj.Update(status: ApplicationObject.State.Created, createdId: conduit.UniqueId, convertedItem: conduit); - return appObj; - } - - public BuiltElements.Conduit ConduitToSpeckle(Conduit revitConduit) - { - var baseGeometry = LocationToSpeckle(revitConduit); - if (!(baseGeometry is Line baseLine)) - throw new Speckle.Core.Logging.SpeckleException("Only line based Conduits are currently supported."); - - var conduitType = revitConduit.Document.GetElement(revitConduit.GetTypeId()) as ConduitType; - - // SPECKLE CONDUIT - var speckleConduit = new RevitConduit - { - family = conduitType.FamilyName, - type = conduitType.Name, - baseCurve = baseLine, - diameter = GetParamValue(revitConduit, BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM), - length = GetParamValue(revitConduit, BuiltInParameter.CURVE_ELEM_LENGTH), - level = ConvertAndCacheLevel(revitConduit, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitConduit) - }; - - GetAllRevitParamsAndIds(speckleConduit, revitConduit, - new List - { - "RBS_CONDUIT_DIAMETER_PARAM", "CURVE_ELEM_LENGTH", "RBS_START_LEVEL_PARAM" - }); - - foreach (var connector in revitConduit.GetConnectorSet()) - { - speckleConduit.Connectors.Add(ConnectorToSpeckle(connector)); - } - - return speckleConduit; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConnector.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConnector.cs deleted file mode 100644 index 5455a13a12..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertConnector.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Linq; -using Autodesk.Revit.DB; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public RevitMEPConnector ConnectorToSpeckle(Connector connector) - { - var speckleMEPConnector = new RevitMEPConnector - { - applicationId = connector.GetUniqueApplicationId(), - origin = PointToSpeckle(connector.Origin, Doc), - shape = connector.Shape.ToString(), - systemName = connector.MEPSystem?.Name ?? connector.Owner.Category?.Name, - }; - - // some genius at Autodesk thought it would be a good idea for property getters to throw... - try - { - speckleMEPConnector.angle = connector.Angle; - } - catch { } - try - { - speckleMEPConnector.height = ScaleToSpeckle(connector.Height); - speckleMEPConnector.width = ScaleToSpeckle(connector.Width); - } - catch { } - try - { - speckleMEPConnector.radius = ScaleToSpeckle(connector.Radius); - } - catch { } - foreach (var reference in connector.AllRefs.Cast()) - { - if (connector.IsConnectedTo(reference)) - { - speckleMEPConnector.connectedConnectorIds.Add(reference.GetUniqueApplicationId()); - } - } - return speckleMEPConnector; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCurves.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCurves.cs deleted file mode 100644 index b6d83d1d8a..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertCurves.cs +++ /dev/null @@ -1,363 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit.Curve; -using Speckle.Core.Models; -using Alignment = Objects.BuiltElements.Alignment; -using DB = Autodesk.Revit.DB; -using DetailCurve = Objects.BuiltElements.Revit.Curve.DetailCurve; -using ModelCurve = Objects.BuiltElements.Revit.Curve.ModelCurve; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - #region speckle to native - public ApplicationObject CreateAppObject(string id, string applicationId, string speckle_type) - { - var docObjs = GetExistingElementsByApplicationId(applicationId); - var appObj = new ApplicationObject(id, speckle_type) { applicationId = applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObjs.FirstOrDefault(), appObj)) - return appObj; - - foreach (var docObj in docObjs) - { - if (docObj != null) - { - // TODO: try updating lines - Doc.Delete(docObj.Id); - } - } - - return appObj; - } - - public ApplicationObject AlignmentToNative(Alignment alignment) - { - var appObj = CreateAppObject(alignment.id, alignment.applicationId, alignment.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - var curves = CurveToNative(alignment.curves); - var curveEnumerator = curves.GetEnumerator(); - while (curveEnumerator.MoveNext() && curveEnumerator.Current != null) - { - var baseCurve = curveEnumerator.Current as DB.Curve; - DB.ModelCurve revitCurve = Doc.Create.NewModelCurve(baseCurve, NewSketchPlaneFromCurve(baseCurve, Doc)); - appObj.Update(createdId: revitCurve.UniqueId); - } - appObj.Update(status: ApplicationObject.State.Created); - return appObj; - } - - public ApplicationObject DetailCurveToNative(DetailCurve speckleCurve) - { - var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - var crvEnum = CurveToNative(speckleCurve.baseCurve).GetEnumerator(); - while (crvEnum.MoveNext() && crvEnum.Current != null) - { - var baseCurve = crvEnum.Current as DB.Curve; - DB.DetailCurve revitCurve = null; - try - { - revitCurve = Doc.Create.NewDetailCurve(Doc.ActiveView, baseCurve); - } - catch (Exception) - { - appObj.Update(logItem: $"Detail curve creation failed\nView is not valid for detail curve creation."); - continue; - } - - var lineStyles = revitCurve.GetLineStyleIds(); - var lineStyleId = lineStyles.FirstOrDefault(x => Doc.GetElement(x).Name == speckleCurve.lineStyle); - if (lineStyleId != null) - revitCurve.LineStyle = Doc.GetElement(lineStyleId); - - appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); - } - appObj.Update(status: ApplicationObject.State.Created, logItem: $"Created as {appObj.CreatedIds.Count} detail curves"); - return appObj; - } - - public ApplicationObject ModelCurveToNative(ModelCurve speckleCurve) - { - var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - var curves = CurveToNative(speckleCurve.baseCurve); - var curveEnumerator = curves.GetEnumerator(); - while (curveEnumerator.MoveNext() && curveEnumerator.Current != null) - { - var baseCurve = curveEnumerator.Current as DB.Curve; - DB.ModelCurve revitCurve = Doc.Create.NewModelCurve(baseCurve, NewSketchPlaneFromCurve(baseCurve, Doc)); - - var lineStyles = revitCurve.GetLineStyleIds(); - var lineStyleId = lineStyles.FirstOrDefault(x => Doc.GetElement(x).Name == speckleCurve.lineStyle); - if (lineStyleId != null) - revitCurve.LineStyle = Doc.GetElement(lineStyleId); - - appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); - } - appObj.Update(status: ApplicationObject.State.Created); - return appObj; - } - - // This is to support raw geometry being sent to Revit (eg from rhino, gh, autocad...) - public ApplicationObject ModelCurveToNative(ICurve speckleLine) - { - // if it comes from GH it doesn't have an applicationId, the use the hash id - if ((speckleLine as Base).applicationId == null) - (speckleLine as Base).applicationId = (speckleLine as Base).id; - - var speckleCurve = speckleLine as Base; - var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - try - { - return ModelCurvesFromEnumerator(CurveToNative(speckleLine).GetEnumerator(), speckleLine, appObj); - } - catch (Exception e) - { - // use display value if curve fails (prob a closed, periodic curve or a non-planar nurbs) - if (speckleLine is IDisplayValue d) - { - appObj.Update(logItem: $"Curve failed conversion (probably a closed period curve or non-planar nurbs): used polyline display value instead."); - return ModelCurvesFromEnumerator(CurveToNative(d.displayValue).GetEnumerator(), speckleLine, appObj); - } - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: e.Message); - return appObj; - } - } - } - - public ApplicationObject RoomBoundaryLineToNative(RoomBoundaryLine speckleCurve) - { - var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - var baseCurve = CurveToNative(speckleCurve.baseCurve); - - try - { - View drawingView = GetCurvePlanView(speckleCurve, out bool isTempView); - var revitCurve = Doc.Create.NewRoomBoundaryLines(NewSketchPlaneFromCurve(baseCurve.get_Item(0), Doc), baseCurve, drawingView).get_Item(0); - - // Delete the temp view after drawing - if (isTempView) - Doc.Delete(drawingView.Id); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitCurve.UniqueId, convertedItem: revitCurve); - } - catch (Exception) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "View is not valid for room boundary line creation."); - } - return appObj; - } - - public ApplicationObject SpaceSeparationLineToNative(SpaceSeparationLine speckleCurve) - { - var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); - if (appObj.Status == ApplicationObject.State.Skipped) - return appObj; - - var baseCurve = CurveToNative(speckleCurve.baseCurve); - - // try update existing (update model curve geometry curve based on speckle curve) - //if (docObj != null) - //{ - // try - // { - // var docCurve = docObj as DB.ModelCurve; - // var revitGeom = docCurve.GeometryCurve; - // var speckleGeom = baseCurve.get_Item(0); - // bool fullOverlap = speckleGeom.Intersect(revitGeom) == SetComparisonResult.Equal; - // if (!fullOverlap) - // docCurve.SetGeometryCurve(speckleGeom, false); - - // appObj.Update(status: ApplicationObject.State.Updated, createdId: docCurve.UniqueId, convertedItem: docCurve); - // return appObj; - // } - // catch - // { - // //delete and try to create new line as fallback - // Doc.Delete(docObj.Id); - // } - //} - - try - { - var res = Doc.Create.NewSpaceBoundaryLines(NewSketchPlaneFromCurve(baseCurve.get_Item(0), Doc), baseCurve, Doc.ActiveView).get_Item(0); - appObj.Update(status: ApplicationObject.State.Created, createdId: res.UniqueId, convertedItem: res); - } - catch (Exception) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "View is not valid for space separation line creation."); - } - return appObj; - } - - public ApplicationObject ModelCurvesFromEnumerator(IEnumerator curveEnum, ICurve speckleLine, ApplicationObject appObj) - { - while (curveEnum.MoveNext() && curveEnum.Current != null) - { - var curve = curveEnum.Current as DB.Curve; - // Curves must be bound in order to be valid model curves - if (!curve.IsBound) curve.MakeBound(speckleLine.domain.start ?? 0, speckleLine.domain.end ?? Math.PI * 2); - DB.ModelCurve revitCurve = null; - - if (Doc.IsFamilyDocument) - revitCurve = Doc.FamilyCreate.NewModelCurve(curve, NewSketchPlaneFromCurve(curve, Doc)); - else - revitCurve = Doc.Create.NewModelCurve(curve, NewSketchPlaneFromCurve(curve, Doc)); - - if (revitCurve != null) - appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); - } - if (appObj.CreatedIds.Count > 1) appObj.Update(logItem: $"Created as {appObj.CreatedIds.Count} model curves"); - appObj.Update(status: ApplicationObject.State.Created); - return appObj; - } - - #endregion - - #region native to speckle - - public ModelCurve ModelCurveToSpeckle(DB.ModelCurve revitCurve) - { - var speckleCurve = new ModelCurve(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document), revitCurve.LineStyle.Name); - speckleCurve.elementId = revitCurve.Id.ToString(); - speckleCurve.applicationId = revitCurve.UniqueId; - speckleCurve.units = ModelUnits; - return speckleCurve; - } - - public DetailCurve DetailCurveToSpeckle(DB.DetailCurve revitCurve) - { - var speckleCurve = new DetailCurve(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document), revitCurve.LineStyle.Name); - speckleCurve.elementId = revitCurve.Id.ToString(); - speckleCurve.applicationId = revitCurve.UniqueId; - speckleCurve.units = ModelUnits; - return speckleCurve; - } - - public RoomBoundaryLine RoomBoundaryLineToSpeckle(DB.ModelCurve revitCurve) - { - var speckleCurve = new RoomBoundaryLine(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document)); - speckleCurve.elementId = revitCurve.Id.ToString(); - speckleCurve.level = ConvertAndCacheLevel(revitCurve.LevelId, revitCurve.Document); - speckleCurve.applicationId = revitCurve.UniqueId; - speckleCurve.units = ModelUnits; - return speckleCurve; - } - - public SpaceSeparationLine SpaceSeparationLineToSpeckle(DB.ModelCurve revitCurve) - { - var speckleCurve = new SpaceSeparationLine(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document)); - speckleCurve.elementId = revitCurve.Id.ToString(); - speckleCurve.applicationId = revitCurve.UniqueId; - speckleCurve.units = ModelUnits; - return speckleCurve; - } - - #endregion - - /// - /// Credits: Grevit - /// Creates a new Sketch Plane from a Curve - /// https://github.com/grevit-dev/Grevit/blob/3c7a5cc198e00dfa4cc1e892edba7c7afd1a3f84/Grevit.Revit/Utilities.cs#L402 - /// - /// Curve to get plane from - /// Plane of the curve - private SketchPlane NewSketchPlaneFromCurve(DB.Curve curve, Document doc) - { - XYZ startPoint = curve.GetEndPoint(0); - XYZ endPoint = curve.GetEndPoint(1); - - // If Start end Endpoint are the same check further points. - int i = 2; - while (startPoint == endPoint && endPoint != null) - { - endPoint = curve.GetEndPoint(i); - i++; - } - - // Plane to return - DB.Plane plane; - - // If Z Values are equal the Plane is XY - if (startPoint.Z == endPoint.Z) - plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisZ, startPoint); - - // If X Values are equal the Plane is YZ - else if (startPoint.X == endPoint.X) - plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisX, startPoint); - - // If Y Values are equal the Plane is XZ - else if (startPoint.Y == endPoint.Y) - plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisY, startPoint); - - // Otherwise the Planes Normal Vector is not X,Y or Z. - // We draw lines from the Origin to each Point and use the Plane this one spans up. - else - { - CurveArray curves = new CurveArray(); - curves.Append(curve); - curves.Append(DB.Line.CreateBound(new XYZ(0, 0, 0), startPoint)); - curves.Append(DB.Line.CreateBound(endPoint, new XYZ(0, 0, 0))); - - plane = DB.Plane.CreateByThreePoints(startPoint, new XYZ(0, 0, 0), endPoint); - } - - return SketchPlane.Create(doc, plane); - } - - /// - /// Get a plan view associated to the curve level. - /// Will return the Doc.ActiveView If no appropriate view is found. - /// - /// A Speckle curve - /// A bool flag indicating if this view should be deleted after drawing the curve. - /// A Revit View. - private View GetCurvePlanView(RoomBoundaryLine speckleCurve, out bool isTempView) - { - View drawingView; - Level level = ConvertLevelToRevit(speckleCurve.level, out _); - ElementId viewId = level?.FindAssociatedPlanViewId(); - - // If there is a plan view associated to the curve level use it otherwise create a temp plan view - if (viewId != null && viewId != ElementId.InvalidElementId) - { - drawingView = Doc.GetElement(viewId) as ViewPlan; - isTempView = false; - } - else - { - drawingView = CreateViewPlan("temp", level.Id); - isTempView = true; - } - - // If plan view retrieval/creation still fail use the activeView as a last recourse - if (drawingView == null) - { - drawingView = Doc.ActiveView; - isTempView = false; - } - - return drawingView; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectShape.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectShape.cs deleted file mode 100644 index dc6c18dd3b..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectShape.cs +++ /dev/null @@ -1,252 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Objects.Other; -using Speckle.Core.Kits; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using DirectShape = Objects.BuiltElements.Revit.DirectShape; -using Mesh = Objects.Geometry.Mesh; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - /// - /// Attempts to convert a DirectShape to Revit according to the current ToNativeMeshSetting value. - /// - /// The direct shape to convert - /// An application placeholder object containing a DirectShape, DXF Import or Family containing DXF Import. - public ApplicationObject TryDirectShapeToNative(DirectShape o, ToNativeMeshSettingEnum fallbackSetting) - { - try - { - // Try to convert to direct shape, taking into account the current mesh settings - return DirectShapeToNative(o, fallbackSetting); - } - catch (FallbackToDxfException e) - { - Report.Log(e.Message); - // FallbackToDxf exception means we should attempt a DXF import instead. - switch (ToNativeMeshSetting) - { - case ToNativeMeshSettingEnum.DxfImport: - return DirectShapeToDxfImport(o); // DirectShape -> DXF - case ToNativeMeshSettingEnum.DxfImportInFamily: - return DirectShapeToDxfImportFamily(o); // DirectShape -> Family (DXF inside) - case ToNativeMeshSettingEnum.Default: - default: - // For anything else, try again with the default fallback (ugly meshes). - return DirectShapeToNative(o, ToNativeMeshSettingEnum.Default); - } - } - } - - public ApplicationObject TryDirectShapeToNative(Brep brep, ToNativeMeshSettingEnum fallbackSetting, RevitCategory cat = RevitCategory.GenericModel) - { - DirectShape ds = new( - $"Brep {brep.applicationId ?? brep.id}", - cat, - new List { brep }) - { applicationId = brep.applicationId, id = brep.id }; - return TryDirectShapeToNative(ds, fallbackSetting); - } - - public ApplicationObject TryDirectShapeToNative(Mesh mesh, ToNativeMeshSettingEnum fallbackSetting, RevitCategory cat = RevitCategory.GenericModel) - { - DirectShape ds = new( - $"Mesh {mesh.applicationId ?? mesh.id}", - cat, - new List { mesh }) - { applicationId = mesh.applicationId, id = mesh.id }; - return TryDirectShapeToNative(ds, fallbackSetting); - } - - public ApplicationObject TryDirectShapeToNative(ApplicationObject appObj, List meshes, ToNativeMeshSettingEnum fallbackSetting, RevitCategory cat = RevitCategory.GenericModel) - { - if (meshes.Count == 0) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Contained no meshes"); - return appObj; - } - - var ds = new DirectShape( - $"{appObj.Descriptor.Split(':').LastOrDefault() ?? "Meshes"} {appObj.applicationId}", - cat, - meshes.Cast().ToList()) - { applicationId = appObj.applicationId, id = appObj.OriginalId }; - - return TryDirectShapeToNative(ds, fallbackSetting); - } - - /// - /// The default DirectShape conversion method. Will return a Revit DirectShape with the containing geometry. - /// - /// - /// - /// - /// - public ApplicationObject DirectShapeToNative(DirectShape speckleDs, ToNativeMeshSettingEnum fallback) - { - // get any existing elements. This could be a DirectShape, OR another element if using fallback receive - var existingObj = GetExistingElementByApplicationId(speckleDs.applicationId ??= speckleDs.id); - var appObj = - new ApplicationObject(speckleDs.id, speckleDs.speckle_type) { applicationId = speckleDs.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(existingObj, appObj)) - return appObj; - - var converted = new List(); - - speckleDs.baseGeometries.ToList().ForEach(b => - { - switch (b) - { - case Brep brep: - try - { - var solid = BrepToNative(brep, out var notes); - converted.Add(solid); - } - catch (Exception e) - { - if (fallback != ToNativeMeshSettingEnum.Default) - throw new FallbackToDxfException( - "Failed to convert BREP to Solid. Falling back to DXF import as per settings.", e); - var mesh = brep.displayValue.SelectMany(m => - MeshToNative(m, parentMaterial: brep["renderMaterial"] as RenderMaterial)); - converted.AddRange(mesh); - } - - break; - case Mesh mesh: - if (fallback != ToNativeMeshSettingEnum.Default) - throw new FallbackToDxfException( - "DirectShape contains Mesh. Falling back to DXF import as per Settings."); - var rMesh = MeshToNative(mesh); - converted.AddRange(rMesh); - break; - case ICurve curve: - var rCurves = CurveToNative(curve, true); - for (var i = 0; i < rCurves.Size; i++) - converted.Add(rCurves.get_Item(i)); - break; - default: - appObj.Update( - logItem: $"Incompatible geometry type: {b.GetType()} is not supported in DirectShape conversions."); - break; - } - }); - - if (existingObj != null && existingObj is DB.DirectShape existingDS) // if it's a directShape, just update - { - existingDS.SetShape(converted); - appObj.Update(status: ApplicationObject.State.Updated, createdId: existingDS.UniqueId, - convertedItem: existingDS); - return appObj; - } - - //from 2.16 onwards use the builtInCategory field for direct shape fallback - BuiltInCategory bic = BuiltInCategory.OST_GenericModel; - if (!BuiltInCategory.TryParse(speckleDs["builtInCategory"] as string, out bic)) - { - //pre 2.16 or coming from grasshopper, using the enum - //TODO: move away from enum logic - if ((int)speckleDs.category != -1) - { - var bicName = Categories.GetBuiltInFromSchemaBuilderCategory(speckleDs.category); - _ = BuiltInCategory.TryParse(bicName, out bic); - } - } - - var cat = Doc.Settings.Categories.get_Item(bic); - - try - { - var revitDs = DB.DirectShape.CreateElement(Doc, cat.Id); - if (speckleDs.applicationId != null) - revitDs.ApplicationId = speckleDs.applicationId; - revitDs.ApplicationDataId = Guid.NewGuid().ToString(); - revitDs.SetShape(converted); - revitDs.Name = speckleDs.name; - SetInstanceParameters(revitDs, speckleDs); - // delete any existing objs - if (existingObj != null) - { - try - { - Doc.Delete(existingObj.Id); - } - catch (Exception e) - { - appObj.Log.Add($"Could not delete existing object: {e.Message}"); - } - } - appObj.Update(status: ApplicationObject.State.Created, createdId: revitDs.UniqueId, convertedItem: revitDs); - } - catch (Exception ex) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{ex.Message}"); - } - return appObj; - } - - private DirectShape DirectShapeToSpeckle(DB.DirectShape revitAc) - { - var cat = ((BuiltInCategory)revitAc.Category.Id.IntegerValue).ToString(); - var category = Categories.GetSchemaBuilderCategoryFromBuiltIn(cat); - var element = revitAc.get_Geometry(new Options()); - - var geometries = new List(); - foreach (var obj in element) - { - switch (obj) - { - case DB.Mesh mesh: - geometries.Add(MeshToSpeckle(mesh, revitAc.Document)); - break; - case Solid solid: // TODO Should be replaced with 'BrepToSpeckle' when it works. - geometries.AddRange(ConvertSolidsByRenderMaterial(new[] { solid }, revitAc.Document)); - break; - } - } - - var speckleAc = new DirectShape( - revitAc.Name, - category, - geometries - ); - - //Find display values in geometries - List displayValue = new List(); - foreach (Base geo in geometries) - { - switch (geo["displayValue"]) - { - case null: - //geo has no display value, we assume it is itself a valid displayValue - displayValue.Add(geo); - break; - - case Base b: - displayValue.Add(b); - break; - - case IEnumerable e: - displayValue.AddRange(e); - break; - } - } - - speckleAc.displayValue = displayValue; - GetAllRevitParamsAndIds(speckleAc, revitAc); - speckleAc["type"] = revitAc.Name; - return speckleAc; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectTeklaMeshElements.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectTeklaMeshElements.cs deleted file mode 100644 index 8f8a6b45c7..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDirectTeklaMeshElements.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.Other; -using System; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB; -using Mesh = Objects.Geometry.Mesh; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public IList TeklaMeshToNative(Mesh displayMesh){ - return MeshToNative(displayMesh); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDuct.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDuct.cs deleted file mode 100644 index 8568e18764..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDuct.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Mechanical; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; -using Polyline = Objects.Geometry.Polyline; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject DuctToNative(BuiltElements.Duct speckleDuct) - { - var speckleRevitDuct = speckleDuct as RevitDuct; - Element docObj = GetExistingElementByApplicationId(speckleDuct.applicationId); - var appObj = new ApplicationObject(speckleDuct.id, speckleDuct.speckle_type) { applicationId = speckleDuct.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - { - return appObj; - } - - string systemFamily = (speckleRevitDuct != null) ? speckleRevitDuct.systemName : ""; - List types = new FilteredElementCollector(Doc).WhereElementIsElementType() - .OfClass(typeof(MechanicalSystemType)).ToElements().Cast().ToList(); - var system = types.FirstOrDefault(x => x.Name == systemFamily); - if (system == null) - { - system = types.FirstOrDefault(); - appObj.Update(logItem: $"Duct type {systemFamily} not found; replaced with {system.Name}"); - } - - Element duct = null; - if (speckleDuct.baseCurve == null || speckleDuct.baseCurve is Line) - { - DuctType ductType = GetElementType(speckleDuct, appObj, out bool _); - if (ductType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - DB.Line baseLine = (speckleDuct.baseCurve != null) ? LineToNative(speckleDuct.baseCurve as Line) : LineToNative(speckleDuct.baseLine); - XYZ startPoint = baseLine.GetEndPoint(0); - XYZ endPoint = baseLine.GetEndPoint(1); - DB.Level lineLevel = ConvertLevelToRevit(speckleRevitDuct != null ? speckleRevitDuct.level : LevelFromCurve(baseLine), out ApplicationObject.State lineState); - DB.Mechanical.Duct lineDuct = DB.Mechanical.Duct.Create(Doc, system.Id, ductType.Id, lineLevel.Id, startPoint, endPoint); - duct = lineDuct; - } - else if (speckleDuct.baseCurve is Polyline polyline) - { - FlexDuctType ductType = GetElementType(speckleDuct, appObj, out bool _); - if (ductType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var speckleRevitFlexDuct = speckleDuct as RevitFlexDuct; - List points = polyline.GetPoints().Select(o => PointToNative(o)).ToList(); - DB.Level flexLevel = ConvertLevelToRevit(speckleRevitDuct != null ? speckleRevitDuct.level : LevelFromPoint(points.First()), out ApplicationObject.State flexState); - XYZ startTangent = VectorToNative(speckleRevitFlexDuct.startTangent); - XYZ endTangent = VectorToNative(speckleRevitFlexDuct.endTangent); - - DB.Mechanical.FlexDuct flexDuct = DB.Mechanical.FlexDuct.Create(Doc, system.Id, ductType.Id, flexLevel.Id, startTangent, endTangent, points); - duct = flexDuct; - } - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Duct BaseCurve of type ${speckleDuct.baseCurve.GetType()} cannot be used to create a Revit Duct"); - return appObj; - } - - // deleting instead of updating for now! - if (docObj != null) - { - Doc.Delete(docObj.Id); - } - - if (speckleRevitDuct != null) - { - TrySetParam(duct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, speckleRevitDuct.height, speckleRevitDuct.units); - TrySetParam(duct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, speckleRevitDuct.width, speckleRevitDuct.units); - TrySetParam(duct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, speckleRevitDuct.diameter, speckleRevitDuct.units); - TrySetParam(duct, BuiltInParameter.CURVE_ELEM_LENGTH, speckleRevitDuct.length, speckleRevitDuct.units); - TrySetParam(duct, BuiltInParameter.RBS_VELOCITY, speckleRevitDuct.velocity, speckleRevitDuct.units); - - SetInstanceParameters(duct, speckleRevitDuct); - - CreateSystemConnections(speckleRevitDuct.Connectors, duct, receivedObjectsCache); - } - - appObj.Update(status: ApplicationObject.State.Created, createdId: duct.UniqueId, convertedItem: duct); - return appObj; - } - - public BuiltElements.Duct DuctToSpeckle(DB.Mechanical.Duct revitDuct, out List notes) - { - notes = new List(); - var baseGeometry = LocationToSpeckle(revitDuct); - if (!(baseGeometry is Line baseLine)) - { - notes.Add("Only line based Ducts are currently supported."); - return null; - } - - // SPECKLE DUCT - var speckleDuct = new RevitDuct - { - family = revitDuct.DuctType.FamilyName, - type = revitDuct.DuctType.Name, - baseCurve = baseLine, - diameter = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, unitsOverride: ModelUnits), - height = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, unitsOverride: ModelUnits), - width = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, unitsOverride: ModelUnits), - length = GetParamValue(revitDuct, BuiltInParameter.CURVE_ELEM_LENGTH), - velocity = GetParamValue(revitDuct, BuiltInParameter.RBS_VELOCITY), - level = ConvertAndCacheLevel(revitDuct, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitDuct) - }; - - if (revitDuct.MEPSystem != null) - { - var material = ConverterRevit.GetMEPSystemMaterial(revitDuct); - if (material != null) - foreach (var mesh in speckleDuct.displayValue) - mesh["renderMaterial"] = material; - - var typeElem = revitDuct.Document.GetElement(revitDuct.MEPSystem.GetTypeId()); - speckleDuct.systemName = typeElem.Name; - } - - GetAllRevitParamsAndIds(speckleDuct, revitDuct, - new List - { - "RBS_CURVE_HEIGHT_PARAM", "RBS_CURVE_WIDTH_PARAM", "RBS_CURVE_DIAMETER_PARAM", "CURVE_ELEM_LENGTH", - "RBS_START_LEVEL_PARAM", "RBS_VELOCITY" - }); - - foreach (var connector in revitDuct.GetConnectorSet()) - { - speckleDuct.Connectors.Add(ConnectorToSpeckle(connector)); - } - - return speckleDuct; - } - - public BuiltElements.Duct DuctToSpeckle(FlexDuct revitDuct) - { - // create polyline from revitduct points - var polyline = new Polyline(); - polyline.value = PointsToFlatList(revitDuct.Points.Select(o => PointToSpeckle(o, revitDuct.Document))); - polyline.units = ModelUnits; - polyline.closed = false; - - // SPECKLE DUCT - var speckleDuct = new RevitFlexDuct - { - family = revitDuct.FlexDuctType.FamilyName, - type = revitDuct.FlexDuctType.Name, - baseCurve = polyline, - diameter = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, unitsOverride: ModelUnits), - height = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, unitsOverride: ModelUnits), - width = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, unitsOverride: ModelUnits), - length = GetParamValue(revitDuct, BuiltInParameter.CURVE_ELEM_LENGTH), - startTangent = VectorToSpeckle(revitDuct.StartTangent, revitDuct.Document), - endTangent = VectorToSpeckle(revitDuct.EndTangent, revitDuct.Document), - velocity = GetParamValue(revitDuct, BuiltInParameter.RBS_VELOCITY), - level = ConvertAndCacheLevel(revitDuct, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitDuct) - }; - - if (revitDuct.MEPSystem != null) - { - var material = ConverterRevit.GetMEPSystemMaterial(revitDuct); - if (material != null) - foreach (var mesh in speckleDuct.displayValue) - mesh["renderMaterial"] = material; - - var typeElem = revitDuct.Document.GetElement(revitDuct.MEPSystem.GetTypeId()); - speckleDuct.systemName = typeElem.Name; - } - - foreach (var connector in revitDuct.GetConnectorSet()) - { - speckleDuct.Connectors.Add(ConnectorToSpeckle(connector)); - } - - GetAllRevitParamsAndIds(speckleDuct, revitDuct, - new List - { - "RBS_CURVE_HEIGHT_PARAM", "RBS_CURVE_WIDTH_PARAM", "RBS_CURVE_DIAMETER_PARAM", "CURVE_ELEM_LENGTH", - "RBS_START_LEVEL_PARAM", "RBS_VELOCITY" - }); - - return speckleDuct; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFabricationPart.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFabricationPart.cs deleted file mode 100644 index 5ef5fab7ee..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFabricationPart.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using System.Collections.Generic; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - /// - /// Convert fabrication parts to speckle elements - /// - /// Fabrication part in Revit - /// Conversion notes for the exceptional cases - /// RevitElement which represents converted fabrication part as speckle object - public RevitElement FabricationPartToSpeckle(FabricationPart revitElement, out List notes) - { - return RevitElementToSpeckle(revitElement, out notes); - } - } -} \ No newline at end of file diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFaceWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFaceWall.cs deleted file mode 100644 index dd1a0a8836..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFaceWall.cs +++ /dev/null @@ -1,230 +0,0 @@ -using Autodesk.Revit.DB; -using ConverterRevitShared.Revit; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Speckle.Core.Models.Extensions; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - //TODO: delete temp family after creation - //TODO: allow updates to family..? - - //NOTE: FaceWalls cannot be updated, as well we can't seem to get their base face easily so they are ToNatvie only - public ApplicationObject FaceWallToNative(RevitFaceWall speckleWall) - { - FaceWall revitWall = GetExistingElementByApplicationId(speckleWall.applicationId) as FaceWall; - var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) { applicationId = speckleWall.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitWall, appObj)) - return appObj; - - if (speckleWall.surface == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Facewall surface was null"); - return appObj; - } - - if (revitWall != null) - Doc.Delete(revitWall.Id); - - var templatePath = GetTemplatePath("Mass"); - if (!File.Exists(templatePath)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not find file {Path.GetFileName(templatePath)}"); - return appObj; - } - - var tempMassFamilyPath = CreateMassFamily(templatePath, speckleWall.surface, speckleWall.applicationId); - Family fam; - Doc.LoadFamily(tempMassFamilyPath, new FamilyLoadOption(), out fam); - var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as FamilySymbol; - symbol.Activate(); - - try - { - File.Delete(tempMassFamilyPath); - } - catch { } - - var mass = Doc.Create.NewFamilyInstance(XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); - // NOTE: must set a schedule level! - // otherwise the wall creation will fail with "Could not create a face wall." - var level = new FilteredElementCollector(Doc) - .WhereElementIsNotElementType() - .OfCategory(BuiltInCategory.OST_Levels) // this throws a null error if user tries to recieve stream in a file with no levels - .ToElements().FirstOrDefault(); - - if (level == null) // create a new level at 0 if no levels could be retrieved from doc - level = Level.Create(Doc, 0); - - TrySetParam(mass, BuiltInParameter.INSTANCE_SCHEDULE_ONLY_LEVEL_PARAM, level); - - //must regenerate before getting the elem geometry - Doc.Regenerate(); - Reference faceRef = GetFaceRef(mass); - - var wallType = GetElementType(speckleWall, appObj, out bool _); - if (wallType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - if (!FaceWall.IsWallTypeValidForFaceWall(Doc, wallType.Id)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Wall type {wallType.Name} not valid for facewall"); - return appObj; - } - - revitWall = null; - try - { - revitWall = DB.FaceWall.Create(Doc, wallType.Id, GetWallLocationLine(speckleWall.locationLine), faceRef); - } - catch (Exception e) - { } - - if (revitWall == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Revit wall creation returned null"); - return appObj; - } - - Doc.Delete(mass.Id); - - SetInstanceParameters(revitWall, speckleWall); - appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); - //appObj = SetHostedElements(speckleWall, revitWall, appObj); - return appObj; - } - public ApplicationObject FaceWallToNativeV2(RevitFaceWall speckleWall) - { - var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) { applicationId = speckleWall.applicationId }; - try - { - var existing = GetExistingElementByApplicationId(speckleWall.applicationId) as FaceWall; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(existing, appObj)) - return appObj; - - if (speckleWall.brep == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "FaceWall geometry was null"); - return appObj; - } - - if (existing != null) - { - Doc.Delete(existing.Id); - } - - var wallType = GetElementType(speckleWall, appObj, out bool _); - if (wallType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (!FaceWall.IsWallTypeValidForFaceWall(Doc, wallType.Id)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Wall type {wallType.Name} not valid for FaceWall"); - return appObj; - } - - List notes = null; - var solid = BrepToNative(speckleWall.brep, out notes); - var faceReference = solid.Faces.get_Item(0); - var faceref = faceReference.Reference; - var freeform = CreateFreeformElementFamily(new List{solid}, speckleWall.id, "Mass"); - Doc.Regenerate(); - faceref = GetFaceRef(freeform); - var revitWall = FaceWall.Create(Doc, wallType.Id, GetWallLocationLine(speckleWall.locationLine), faceref); - //Doc.Delete(freeform.Id); - SetInstanceParameters(revitWall, speckleWall); - appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); - //appObj = SetHostedElements(speckleWall, revitWall, appObj); - return appObj; - } - catch (Exception e) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Revit wall creation failed: {e.Message}", log: new List{e.ToFormattedString()}); - return appObj; - } - } - - private Reference GetFaceRef(Element e) - { - var geomOption = e.Document.Application.Create.NewGeometryOptions(); - geomOption.ComputeReferences = true; - geomOption.IncludeNonVisibleObjects = true; - geomOption.DetailLevel = ViewDetailLevel.Fine; - - var ge = e.get_Geometry(geomOption); - - foreach (GeometryObject geomObj in ge) - { - Solid geomSolid = geomObj as Solid; - if (null != geomSolid) - foreach (Face geomFace in geomSolid.Faces) - if (FaceWall.IsValidFaceReferenceForFaceWall(e.Document, geomFace.Reference)) - return geomFace.Reference; - } - return null; - } - - private string CreateMassFamily(string famPath, Geometry.Surface surface, string name) - { - var famDoc = Doc.Application.NewFamilyDocument(famPath); - - using (Transaction t = new Transaction(famDoc, "Create Mass")) - { - t.Start(); - - try - { - var pointLists = surface.GetControlPoints(); - var curveArray = new ReferenceArrayArray(); - - foreach (var list in pointLists) - { - var arr = new ReferencePointArray(); - foreach (var point in list) - { - var refPt = famDoc.FamilyCreate.NewReferencePoint(PointToNative(point)); - arr.Append(refPt); - } - - var curve = famDoc.FamilyCreate.NewCurveByPoints(arr); - var referenceArray = new ReferenceArray(); - referenceArray.Append(curve.GeometryCurve.Reference); - curveArray.Append(referenceArray); - } - - var loft = famDoc.FamilyCreate.NewLoftForm(true, curveArray); - } - catch (Exception e) - { - - } - - t.Commit(); - } - var famName = "SpeckleMass_" + name; - string tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); - SaveAsOptions so = new SaveAsOptions(); - so.OverwriteExistingFile = true; - famDoc.SaveAs(tempFamilyPath, so); - famDoc.Close(); - Report.Log($"Created temp family {tempFamilyPath}"); - return tempFamilyPath; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFamilyInstance.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFamilyInstance.cs deleted file mode 100644 index 012abf6672..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFamilyInstance.cs +++ /dev/null @@ -1,877 +0,0 @@ -using System; -using System.Collections.Generic; -using System.DoubleNumerics; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Objects.Organization; -using RevitSharedResources.Helpers; -using RevitSharedResources.Helpers.Extensions; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Point = Objects.Geometry.Point; -using RevitInstance = Objects.Other.Revit.RevitInstance; -using RevitSymbolElementType = Objects.BuiltElements.Revit.RevitSymbolElementType; -using SHC = RevitSharedResources.Helpers.Categories; -using Vector = Objects.Geometry.Vector; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - /// - /// Entry point for all revit family conversions. - /// - /// - /// - public Base FamilyInstanceToSpeckle(DB.FamilyInstance revitFi, out List notes) - { - notes = new List(); - Base @base = null; - - //adaptive components - if (AdaptiveComponentInstanceUtils.IsAdaptiveComponentInstance(revitFi)) - @base = AdaptiveComponentToSpeckle(revitFi); - - //these elements come when the curtain wall is generated - //if they are contained in 'subelements' then they have already been accounted for from a wall - //else if they are mullions then convert them as a generic family instance but add a isUGridLine prop - bool? isUGridLine = null; - if (@base == null && - (revitFi.Category.Id.IntegerValue == (int)BuiltInCategory.OST_CurtainWallMullions - || revitFi.Category.Id.IntegerValue == (int)BuiltInCategory.OST_CurtainWallPanels)) - { - if (SubelementIds.Contains(revitFi.Id)) - return null; - else if (revitFi is Mullion mullion) - { - if (mullion.LocationCurve is DB.Line locationLine && locationLine.Direction != null) - { - var direction = locationLine.Direction; - // TODO: add support for more severly sloped mullions. This isn't very robust at the moment - isUGridLine = Math.Abs(direction.X) > Math.Abs(direction.Y); - } - } - else - //TODO: sort these so we consistently get sub-elements from the wall element in case also sub-elements are sent - SubelementIds.Add(revitFi.Id); - } - - //beams & braces - if (@base == null && SHC.StructuralFraming.BuiltInCategories.HasCategory(revitFi.Category)) - { - if (revitFi.StructuralType == StructuralType.Beam) - @base = BeamToSpeckle(revitFi, out notes); - else if (revitFi.StructuralType == StructuralType.Brace) - @base = BraceToSpeckle(revitFi, out notes); - } - - //columns - if ( - @base == null && SHC.Column.BuiltInCategories.HasCategory(revitFi.Category) - || revitFi.StructuralType == StructuralType.Column - ) - @base = ColumnToSpeckle(revitFi, out notes); - - // MEP elements - if (revitFi.MEPModel?.ConnectorManager?.Connectors?.Size > 0) - { - @base = MEPFamilyInstanceToSpeckle(revitFi); - } - - // curtain panels - if (revitFi is DB.Panel panel) - { - @base = PanelToSpeckle(panel); - } - - // elements - var baseGeometry = LocationToSpeckle(revitFi); - var basePoint = baseGeometry as Point; - if (@base == null && basePoint == null) - @base = RevitElementToSpeckle(revitFi, out notes); - - // point based, convert these as revit instances - if (@base == null) - { - @base = RevitInstanceToSpeckle(revitFi, out notes, null); - } - - // add additional props to base object - if (isUGridLine.HasValue) - @base["isUGridLine"] = isUGridLine.Value; - if (revitFi.Room != null) - @base["roomId"] = revitFi.Room.Id.ToString(); - if (revitFi.ToRoom != null) - @base["toRoomId"] = revitFi.ToRoom.Id.ToString(); - if (revitFi.FromRoom != null) - @base["fromRoomId"] = revitFi.FromRoom.Id.ToString(); - - - return @base; - } - - #region OLD family instancing - //TODO: deprecate when we no longer want to support receiving old commits with the `BuiltElements.Revit.FamilyInstance` class - public ApplicationObject FamilyInstanceToNative(BuiltElements.Revit.FamilyInstance speckleFi) - { - XYZ basePoint = PointToNative(speckleFi.basePoint); - DB.Level level = ConvertLevelToRevit(speckleFi.level, out ApplicationObject.State levelState); - DB.FamilyInstance familyInstance = null; - var isUpdate = false; - - var docObj = GetExistingElementByApplicationId(speckleFi.applicationId); - var appObj = new ApplicationObject(speckleFi.id, speckleFi.speckle_type) - { - applicationId = speckleFi.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - var familySymbol = GetElementType(speckleFi, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (docObj != null) - { - try - { - var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; - - // if family changed, tough luck. delete and let us create a new one. - if (familySymbol.FamilyName != revitType.FamilyName) - Doc.Delete(docObj.Id); - else - { - familyInstance = (DB.FamilyInstance)docObj; - - //NOTE: updating an element location is quite buggy in Revit! - //Let's say the first time an element is created its base point/curve is @ 10m and the Level is @ 0m - //the element will be created @ 0m - //but when this element is updated (let's say with no changes), it will jump @ 10m (unless there is a level change)! - //to avoid this behavior we're always setting the previous location Z coordinate when updating an element - //this means the Z coord of an element will only be set by its Level - //and by additional parameters as sill height, base offset etc - var newLocationPoint = new XYZ( - basePoint.X, - basePoint.Y, - (familyInstance.Location as LocationPoint).Point.Z - ); - - (familyInstance.Location as LocationPoint).Point = newLocationPoint; - - // BAND AID FIX ALERT - // this is one of the stranger issues I've encountered. When I set the location of a family instance - // it mostly works fine, but every so often it goes to a different location than the one I set - // it seems like just reassigning the location to the same thing we just assigned it to works - // I don't know why this is happening - if ((familyInstance.Location as LocationPoint).Point != newLocationPoint) - (familyInstance.Location as LocationPoint).Point = newLocationPoint; - - // check for a type change - if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) - { - familyInstance.ChangeTypeId(familySymbol.Id); - } - - TrySetParam(familyInstance, BuiltInParameter.FAMILY_LEVEL_PARAM, level); - TrySetParam(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); - } - isUpdate = true; - } - catch - { - //something went wrong, re-create it - } - } - - //create family instance - if (familyInstance == null) - { - //If the current host element is not null, it means we're coming from inside a nested conversion. - if (CurrentHostElement != null) - { - var isUGridLine = speckleFi["isUGridLine"] as bool? != null ? (bool)speckleFi["isUGridLine"] : false; - familyInstance = CreateHostedFamilyInstance(appObj, familySymbol, basePoint, level, isUGridLine); - } - //Otherwise, proceed as normal. - else - { - familyInstance = Doc.Create.NewFamilyInstance(basePoint, familySymbol, level, StructuralType.NonStructural); - } - } - - //required for face flipping to work! - Doc.Regenerate(); - - if (familyInstance.CanFlipHand && speckleFi.handFlipped != familyInstance.HandFlipped) - familyInstance.flipHand(); - - if (familyInstance.CanFlipFacing && speckleFi.facingFlipped != familyInstance.FacingFlipped) - familyInstance.flipFacing(); - - // NOTE: do not check for the CanRotate prop as it doesn't work (at least on some families I tried)! - // some point based families don't have a rotation, so keep this in a try catch - try - { - if (speckleFi.rotation != (familyInstance.Location as LocationPoint).Rotation) - { - var axis = DB.Line.CreateBound(new XYZ(basePoint.X, basePoint.Y, 0), new XYZ(basePoint.X, basePoint.Y, 1000)); - (familyInstance.Location as LocationPoint).Rotate( - axis, - speckleFi.rotation - (familyInstance.Location as LocationPoint).Rotation - ); - } - } - catch { } - - if ( - familySymbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased - && speckleFi["topLevel"] is Objects.BuiltElements.Level topLevel - ) - { - var revitTopLevel = ConvertLevelToRevit(topLevel, out ApplicationObject.State topLevelState); - TrySetParam(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, revitTopLevel); - } - - SetInstanceParameters(familyInstance, speckleFi); - if (speckleFi.mirrored) - appObj.Update( - logItem: $"Element with id {familyInstance.Id} should be mirrored, but a Revit API limitation prevented us from doing so." - ); - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: familyInstance.UniqueId, convertedItem: familyInstance); - return appObj; - } - - private DB.FamilyInstance CreateHostedFamilyInstance( - ApplicationObject appObj, - DB.FamilySymbol familySymbol, - XYZ insertionPoint, - DB.Level level, - bool isUGridLine = false - ) - { - DB.FamilyInstance familyInstance = null; - //If the current host element is not null, it means we're coming from inside a nested conversion. - - if (level == null) - level = Doc.GetElement(CurrentHostElement.LevelId) as DB.Level; - - // there are two (i think) main types of hosted elements which can be found with family.familyplacementtype - // the two placement types for hosted elements are onelevelbasedhosted and workplanebased - - if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBasedHosted) - { - familyInstance = Doc.Create.NewFamilyInstance( - insertionPoint, - familySymbol, - CurrentHostElement, - level, - StructuralType.NonStructural - ); - } - else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.WorkPlaneBased) - { - if (CurrentHostElement == null) - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Object is work plane based but does not have a host element" - ); - return null; - } - if (CurrentHostElement is Element el) - { - Doc.Regenerate(); - - Options op = new Options(); - op.ComputeReferences = true; - GeometryElement geomElement = el.get_Geometry(op); - Reference faceRef = null; - var planeDist = double.MaxValue; - - GetReferencePlane(geomElement, insertionPoint, ref faceRef, ref planeDist); - - XYZ norm = new XYZ(0, 0, 0); - familyInstance = Doc.Create.NewFamilyInstance(faceRef, insertionPoint, norm, familySymbol); - - // parameters - IList cutVoidsParams = familySymbol.Family.GetParameters("Cut with Voids When Loaded"); - IList lvlParams = familyInstance.GetParameters("Schedule Level"); - - if (cutVoidsParams.ElementAtOrDefault(0) != null && cutVoidsParams[0].AsInteger() == 1) - InstanceVoidCutUtils.AddInstanceVoidCut(Doc, el, familyInstance); - try - { - if (lvlParams.ElementAtOrDefault(0) != null) - lvlParams[0].Set(level.Id); // this can be null - } - catch { } - } - else if (CurrentHostElement is DB.Floor floor) - { - // TODO: support hosted elements on floors. Should be very similar to above implementation - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Work Plane based families on floors to be supported soon" - ); - return null; - } - } - else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased) - { - if (CurrentHostElement is FootPrintRoof roof) - { - // handle receiving mullions on a curtain roof - var curtainGrids = roof.CurtainGrids; - CurtainGrid lastGrid = null; - foreach (var curtainGrid in curtainGrids) - if (curtainGrid is CurtainGrid c) - lastGrid = c; - - if (lastGrid != null && isUGridLine) - { - var gridLine = lastGrid.AddGridLine(isUGridLine, insertionPoint, false); - foreach (var seg in gridLine.AllSegmentCurves) - gridLine.AddMullions(seg as Curve, familySymbol as MullionType, isUGridLine); - } - } - } - else - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Unsupported FamilyPlacementType {familySymbol.Family.FamilyPlacementType}" - ); - return null; - } - // try a catch all solution as a last resort - if (familyInstance == null) - { - try - { - familyInstance = Doc.Create.NewFamilyInstance( - insertionPoint, - familySymbol, - CurrentHostElement, - level, - StructuralType.NonStructural - ); - } - catch { } - } - - return familyInstance; - } - - #endregion - - private void GetReferencePlane( - GeometryElement geomElement, - XYZ basePoint, - ref Reference faceRef, - ref double planeDist - ) - { - foreach (var geom in geomElement) - { - if (geom is Solid solid) - { - FaceArray faceArray = solid.Faces; - - foreach (Face face in faceArray) - { - if (face is PlanarFace planarFace) - { - // some family instance base points may lie on the intersection of faces - // this makes it so family instance families can only be placed on the - // faces of walls - double D = - planarFace.FaceNormal.X * planarFace.Origin.X - + planarFace.FaceNormal.Y * planarFace.Origin.Y - + planarFace.FaceNormal.Z * planarFace.Origin.Z; - double PointD = - planarFace.FaceNormal.X * basePoint.X - + planarFace.FaceNormal.Y * basePoint.Y - + planarFace.FaceNormal.Z * basePoint.Z; - double value = Math.Abs(D - PointD); - double newPlaneDist = Math.Abs(D - PointD); - if (newPlaneDist < planeDist) - { - planeDist = newPlaneDist; - faceRef = planarFace.Reference; - } - } - } - } - else if (geom is GeometryInstance geomInst) - { - GeometryElement transformedGeom = geomInst.GetInstanceGeometry(geomInst.Transform); - GetReferencePlane(transformedGeom, basePoint, ref faceRef, ref planeDist); - } - } - } - - #region new instancing - - // transforms - private Other.Transform TransformToSpeckle( - Transform transform, - Document doc, - bool skipDocReferencePointTransform = false - ) - { - var externalTransform = transform; - - // get the reference point transform and apply if this is a top level instance - if (!skipDocReferencePointTransform) - { - var docTransform = GetDocReferencePointTransform(doc); - externalTransform = docTransform.Inverse.Multiply(transform); - } - - // translation - var tX = ScaleToSpeckle(externalTransform.Origin.X, ModelUnits); - var tY = ScaleToSpeckle(externalTransform.Origin.Y, ModelUnits); - var tZ = ScaleToSpeckle(externalTransform.Origin.Z, ModelUnits); - var t = new Vector(tX, tY, tZ, ModelUnits); - - // basis vectors - var vX = new Vector( - externalTransform.BasisX.X, - externalTransform.BasisX.Y, - externalTransform.BasisX.Z, - ModelUnits - ); - var vY = new Vector( - externalTransform.BasisY.X, - externalTransform.BasisY.Y, - externalTransform.BasisY.Z, - ModelUnits - ); - var vZ = new Vector( - externalTransform.BasisZ.X, - externalTransform.BasisZ.Y, - externalTransform.BasisZ.Z, - ModelUnits - ); - - // get the scale: TODO: do revit transforms ever have scaling? - var scale = transform.Scale; - - return new Other.Transform(vX, vY, vZ, t) { units = ModelUnits }; - } - - private Transform TransformToNative(Other.Transform transform) - { - var _transform = new Transform(Transform.Identity); - - // translation - if (transform.matrix.M44 == 0) - return _transform; - var tX = ScaleToNative(transform.matrix.M14 / transform.matrix.M44, transform.units); - var tY = ScaleToNative(transform.matrix.M24 / transform.matrix.M44, transform.units); - var tZ = ScaleToNative(transform.matrix.M34 / transform.matrix.M44, transform.units); - var t = new XYZ(tX, tY, tZ); - - // basis vectors - XYZ vX = new XYZ(transform.matrix.M11, transform.matrix.M21, transform.matrix.M31); - XYZ vY = new XYZ(transform.matrix.M12, transform.matrix.M22, transform.matrix.M32); - XYZ vZ = new XYZ(transform.matrix.M13, transform.matrix.M23, transform.matrix.M33); - - // apply to new transform - _transform.Origin = t; - _transform.BasisX = vX.Normalize(); - _transform.BasisY = vY.Normalize(); - _transform.BasisZ = vZ.Normalize(); - - // apply doc transform - var docTransform = GetDocReferencePointTransform(Doc); - var internalTransform = docTransform.Multiply(_transform); - - return internalTransform; - } - - // revit instances - public ApplicationObject RevitInstanceToNative(RevitInstance instance, ApplicationObject appObj = null) - { - DB.FamilyInstance familyInstance = null; - var docObj = GetExistingElementByApplicationId(instance.applicationId); - appObj ??= new ApplicationObject(instance.id, instance.speckle_type) { applicationId = instance.applicationId }; - var isUpdate = false; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - // get the definition - var definition = instance.definition as RevitSymbolElementType; - var familySymbol = GetElementType(definition, appObj, out bool isExactMatch); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_CurtainWallMullions) - || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_CurtainWallPanels)) - { - appObj.Update(logItem: "Revit cannot create standalone curtain panels or mullions", status: ApplicationObject.State.Skipped); - return appObj; - } - - // get the transform, insertion point, level, and placement type of the instance - var transform = TransformToNative(instance.transform); - DB.Level level = ConvertLevelToRevit(instance.level, out ApplicationObject.State levelState); - var insertionPoint = transform.OfPoint(XYZ.Zero); - FamilyPlacementType placement = Enum.TryParse( - definition.placementType, - true, - out FamilyPlacementType placementType - ) - ? placementType - : FamilyPlacementType.Invalid; - - // check for existing and update if so - if (docObj != null) - { - try - { - var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; - - // if family changed, tough luck. delete and let us create a new one. - if (familySymbol.FamilyName != revitType.FamilyName) - Doc.Delete(docObj.Id); - else - { - familyInstance = (DB.FamilyInstance)docObj; - - var newLocationPoint = new XYZ( - insertionPoint.X, - insertionPoint.Y, - (familyInstance.Location as LocationPoint).Point.Z - ); - (familyInstance.Location as LocationPoint).Point = newLocationPoint; - - // check for a type change - if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) - { - familyInstance.ChangeTypeId(familySymbol.Id); - } - - TrySetParam(familyInstance, BuiltInParameter.FAMILY_LEVEL_PARAM, level); - TrySetParam(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); - } - isUpdate = true; - } - catch - { - //something went wrong, re-create it - } - } - - //create family instance - - if (familyInstance == null) - { - switch (placement) - { - case FamilyPlacementType.OneLevelBasedHosted when CurrentHostElement != null: - familyInstance = Doc.Create.NewFamilyInstance( - insertionPoint, - familySymbol, - CurrentHostElement, - level, - StructuralType.NonStructural - ); - break; - - case FamilyPlacementType.WorkPlaneBased when CurrentHostElement != null: - Options op = new Options() { ComputeReferences = true }; - GeometryElement geomElement = CurrentHostElement.get_Geometry(op); - if (geomElement == null) - { - // if host geom was null, then regenerate document and that should fix it - Doc.Regenerate(); - geomElement = CurrentHostElement.get_Geometry(op); - // if regenerating didn't fix it then try generic method - // TODO: this won't be correct, maybe we should just throw an error? - if (geomElement == null) - { - goto default; - } - } - Reference faceRef = null; - var planeDist = double.MaxValue; - GetReferencePlane(geomElement, insertionPoint, ref faceRef, ref planeDist); - XYZ norm = new XYZ(0, 0, 0); - try - { - familyInstance = Doc.Create.NewFamilyInstance(faceRef, insertionPoint, norm, familySymbol); - } - catch (Exception e) - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Could not create WorkPlaneBased hosted instance: {e.Message}" - ); - return appObj; - } - // parameters - IList cutVoidsParams = familySymbol.Family.GetParameters("Cut with Voids When Loaded"); - IList lvlParams = familyInstance.GetParameters("Schedule Level"); - if (cutVoidsParams.ElementAtOrDefault(0) != null && cutVoidsParams[0].AsInteger() == 1) - InstanceVoidCutUtils.AddInstanceVoidCut(Doc, CurrentHostElement, familyInstance); - - if (lvlParams.ElementAtOrDefault(0) != null && level != null) - { - lvlParams[0].Set(level.Id); - } - - break; - - case FamilyPlacementType.OneLevelBased when CurrentHostElement is FootPrintRoof roof: // handle receiving mullions on a curtain roof - var curtainGrids = roof.CurtainGrids; - CurtainGrid lastGrid = null; - foreach (var curtainGrid in curtainGrids) - if (curtainGrid is CurtainGrid c) - lastGrid = c; - var isUGridLine = instance["isUGridLine"] as bool? != null ? (bool)instance["isUGridLine"] : false; - if (lastGrid != null && isUGridLine) - { - var gridLine = lastGrid.AddGridLine(isUGridLine, insertionPoint, false); - foreach (var seg in gridLine.AllSegmentCurves) - gridLine.AddMullions(seg as Curve, familySymbol as MullionType, isUGridLine); - } - break; - - default: - familyInstance = Doc.Create.NewFamilyInstance( - insertionPoint, - familySymbol, - level, - StructuralType.NonStructural - ); - break; - } - } - - if (familyInstance == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create instance"); - return appObj; - } - - Doc.Regenerate(); //required for mirroring and face flipping to work! - - if (instance.mirrored != familyInstance.Mirrored) - { - // mirroring - // note: mirroring a hosted instance via api will fail, thanks revit: there is workaround hack to group the element -> mirror -> ungroup - Group group = null; - try - { - group = CurrentHostElement != null ? Doc.Create.NewGroup(new[] { familyInstance.Id }) : null; - } - catch (Autodesk.Revit.Exceptions.InvalidOperationException) - { - // sometimes the group can't be made. Just try to mirror the element on its own - } - var elementToMirror = group != null ? new[] { group.Id } : new[] { familyInstance.Id }; - - try - { - ElementTransformUtils.MirrorElements( - Doc, - elementToMirror, - DB.Plane.CreateByNormalAndOrigin(transform.BasisY, insertionPoint), - false - ); - } - catch (Exception e) - { - appObj.Update(logItem: $"Instance could not be mirrored: {e.Message}"); - } - group?.UngroupMembers(); - } - - // face flipping must happen after mirroring - if (familyInstance.CanFlipHand && instance.handFlipped != familyInstance.HandFlipped) - familyInstance.flipHand(); - - if (familyInstance.CanFlipFacing && instance.facingFlipped != familyInstance.FacingFlipped) - familyInstance.flipFacing(); - - var currentTransform = familyInstance.GetTotalTransform(); - var desiredBasisX = new Vector(transform.BasisX.X, transform.BasisX.Y, transform.BasisX.Z); - var currentBasisX = new Vector(currentTransform.BasisX.X, currentTransform.BasisX.Y, currentTransform.BasisX.Z); - - // rotation about the z axis (signed) - var rotation = Math.Atan2( - Vector.DotProduct( - Vector.CrossProduct(desiredBasisX, currentBasisX), - new Vector(currentTransform.BasisZ.X, currentTransform.BasisZ.Y, currentTransform.BasisZ.Z) - ), - Vector.DotProduct(desiredBasisX, currentBasisX) - ); - - if (Math.Abs(rotation) > TOLERANCE && familyInstance.Location is LocationPoint location) - { - try // some point based families don't have a rotation, so keep this in a try catch - { - using var axis = DB.Line.CreateUnbound(location.Point, currentTransform.BasisZ); - location.Rotate(axis, -rotation); - } - catch (Exception e) - { - appObj.Update(logItem: $"Could not rotate created instance: {e.Message}"); - } - } - - SetInstanceParameters(familyInstance, instance); - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: familyInstance.UniqueId, convertedItem: familyInstance); - //appObj = SetHostedElements(instance, familyInstance, appObj); - return appObj; - } - - public RevitInstance RevitInstanceToSpeckle( - DB.FamilyInstance instance, - out List notes, - Transform parentTransform, - bool useParentTransform = false, - RevitInstance existingInstance = null - ) - { - notes = new List(); - - // get the transform - var instanceTransform = instance.GetTotalTransform(); - var localTransform = instanceTransform; - if (useParentTransform) // this is a nested instance, remove the parent transform from it and don't apply doc reference point transforms - { - localTransform = parentTransform.Inverse.Multiply(instanceTransform); - } - var transform = TransformToSpeckle(localTransform, instance.Document, useParentTransform); - - // get the definition base of this instance - RevitSymbolElementType definition = GetRevitInstanceDefinition( - instance, - out List definitionNotes, - instanceTransform - ); - notes.AddRange(definitionNotes); - - var _instance = existingInstance ?? new RevitInstance(); - _instance.transform = transform; - _instance.typedDefinition = definition; - _instance.level = ConvertAndCacheLevel(instance, BuiltInParameter.FAMILY_LEVEL_PARAM); - _instance.facingFlipped = instance.FacingFlipped; - _instance.handFlipped = instance.HandFlipped; - _instance.mirrored = instance.Mirrored; - - // if a family instance is twoLevelBased, then store the top level - if (instance.Symbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased) - { - _instance["topLevel"] = ConvertAndCacheLevel(instance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - _instance["topLevel"] ??= ConvertAndCacheLevel(instance, BuiltInParameter.SCHEDULE_TOP_LEVEL_PARAM); - } - - GetAllRevitParamsAndIds(_instance, instance); - - return _instance; - } - - /// - /// Converts the familysymbol into a revitsymbolelementtype - /// - /// - /// - /// - /// - /// TODO: could potentially optimize this for symbols with the same displayvalues by caching previously converted symbols - private RevitSymbolElementType GetRevitInstanceDefinition( - DB.FamilyInstance instance, - out List notes, - Transform parentTransform - ) - { - notes = new List(); - var symbol = - ElementTypeToSpeckle(instance.Document.GetElement(instance.GetTypeId()) as ElementType) - as RevitSymbolElementType; - if (symbol == null) - { - notes.Add($"Could not convert element type as FamilySymbol"); - return null; - } - - // get the displayvalue of the family symbol - try - { - var meshes = GetElementDisplayValue( - instance, - isConvertedAsInstance: true, - transform: parentTransform - ); - symbol.displayValue = meshes; - } - catch (Exception e) - { - notes.Add($"Could not retrieve display meshes: {e.Message}"); - } - - #region sub elements capture - - var subElementIds = instance.GetSubComponentIds(); - var convertedSubElements = new List(); - - foreach (var elemId in subElementIds) - { - var subElem = instance.Document.GetElement(elemId); - Base converted = null; - switch (subElem) - { - case DB.FamilyInstance o: - converted = RevitInstanceToSpeckle(o, out notes, parentTransform, true); - if (converted == null) - goto default; - break; - default: - converted = ConvertToSpeckle(subElem); - break; - } - if (converted != null) - { - convertedSubElements.Add(converted); - ConvertedObjects.Add(converted.applicationId); - } - } - - if (convertedSubElements.Any()) - { - symbol.elements = convertedSubElements; - } - #endregion - - var material = ConverterRevit.GetMEPSystemMaterial(instance); - - if (material != null) - foreach (var mesh in symbol.displayValue) - mesh["renderMaterial"] = material; - - return symbol; - } - #endregion - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFitting.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFitting.cs deleted file mode 100644 index 315a948784..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFitting.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Autodesk.Revit.DB; -using Speckle.Core.Kits; -using Speckle.Core.Models; -using Speckle.Core.Logging; -using System; -using ConverterRevitShared.Extensions; -using System.Linq; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public DB.FamilyInstance FittingToNative(RevitMEPFamilyInstance speckleRevitFitting, PartType partType, ApplicationObject appObj) - { - var docObj = GetExistingElementByApplicationId(speckleRevitFitting.applicationId); - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return null; - - var connectorInfo = ValidateConnectorsAndPopulateList(speckleRevitFitting); - - var familyInstance = TryCreateFitting(partType, docObj, connectorInfo) - ?? throw new SpeckleException($"{nameof(FittingToNative)} yeilded a null familyInstance"); - - var familySymbol = GetElementType(speckleRevitFitting, new ApplicationObject(null, null), out bool isExactMatch); - - if (isExactMatch && familyInstance.Symbol.Id.IntegerValue != familySymbol.Id.IntegerValue) - { - familyInstance.ChangeTypeId(familySymbol.Id); - } - - appObj.Update(status: ApplicationObject.State.Created, createdId: familyInstance.UniqueId, convertedItem: familyInstance); - - return familyInstance; - } - - private DB.FamilyInstance TryCreateFitting(PartType partType, Element docObj, List<(Element, int)> connectorInfo) - { - switch (partType) - { - case PartType.Elbow: - if (connectorInfo.Count != 2) - { - throw new SpeckleException($"A fitting with a partType of {nameof(PartType.Elbow)} must have 2 connectors, not {connectorInfo.Count}"); - } - if (ReceiveMode == ReceiveMode.Update && docObj != null) - { - Doc.Delete(docObj.Id); - } - return Doc.Create.NewElbowFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])); - case PartType.Transition: - if (connectorInfo.Count != 2) - { - throw new SpeckleException($"A fitting with a partType of {nameof(PartType.Transition)} must have 2 connectors, not {connectorInfo.Count}"); - } - if (ReceiveMode == ReceiveMode.Update && docObj != null) - { - Doc.Delete(docObj.Id); - } - var revitFitting = TryInSubtransaction( - () => Doc.Create.NewTransitionFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])), - ex => { } - ); - revitFitting ??= TryInSubtransaction( - () => Doc.Create.NewTransitionFitting(GetConnector(connectorInfo[1]), GetConnector(connectorInfo[0])), - ex => throw ex - ); - return revitFitting; - case PartType.Union: - if (connectorInfo.Count != 2) - { - throw new SpeckleException($"A fitting with a partType of {nameof(PartType.Union)} must have 2 connectors, not {connectorInfo.Count}"); - } - if (ReceiveMode == ReceiveMode.Update && docObj != null) - { - Doc.Delete(docObj.Id); - } - return Doc.Create.NewUnionFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])); - case PartType.Tee: - if (connectorInfo.Count != 3) - { - throw new SpeckleException($"A fitting with a partType of {nameof(PartType.Tee)} must have 3 connectors, not {connectorInfo.Count}"); - } - if (ReceiveMode == ReceiveMode.Update && docObj != null) - { - Doc.Delete(docObj.Id); - } - return Doc.Create.NewTeeFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1]), GetConnector(connectorInfo[2])); - case PartType.Cross: - if (connectorInfo.Count != 4) - { - throw new SpeckleException($"A fitting with a partType of {nameof(PartType.Cross)} must have 4 connectors, not {connectorInfo.Count}"); - } - if (ReceiveMode == ReceiveMode.Update && docObj != null) - { - Doc.Delete(docObj.Id); - } - return Doc.Create.NewCrossFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1]), GetConnector(connectorInfo[2]), GetConnector(connectorInfo[3])); - default: - throw new SpeckleException($"Method named {nameof(FittingToNative)} was not expecting an element with a partType of {partType}"); - } - } - - /// - /// Attempting to add a fitting between two connectors and rolling back a subtransaction will result in the - /// connector element references becomeing invalid. Therefore, instead of passing around the connector objects, - /// we're keeping track of the owner element and the connector id so we can retrieve the connector - /// connector id - /// - /// - /// - private Connector GetConnector((Element, int) connectorInfo) => connectorInfo.Item1 - .GetConnectorSet() - .First(c => c.Id == connectorInfo.Item2); - - private List<(Element, int)> ValidateConnectorsAndPopulateList(RevitMEPFamilyInstance speckleRevitFitting) - { - List<(Element, int)> connectors = new(); - foreach (var speckleRevitConnector in speckleRevitFitting.Connectors) - { - var con = FindNativeConnectorForSpeckleRevitConnector(speckleRevitConnector); - connectors.Add(con); - } - return connectors; - } - - private (Element, int) FindNativeConnectorForSpeckleRevitConnector(RevitMEPConnector speckleRevitConnector) - { - List exceptions = new(); - foreach (var (elementAppId, element, existingConnector) in GetRevitConnectorsThatConnectToSpeckleConnector( - speckleRevitConnector, - receivedObjectsCache)) - { - if (existingConnector != null) - { - // we only want one native connector per speckleRevitConnector so return if we find a match - return (element, existingConnector.Id); - } - else if (element != null) - { - // if the element is not null but the connector is, then the correct connector on the element could not - // be found by trying to compare locations of all the connectors on the element - exceptions.Add(new SpeckleException("Fitting found native element to connect to but could not find \"connector\" subelement which is needed for connection in Revit")); - } - else if (string.IsNullOrEmpty(elementAppId)) - { - exceptions.Add(new SpeckleException("A connector has a reference to a null applicationId")); - } - else if (ContextObjects.ContainsKey(elementAppId)) - { - // here a native element could not be found. Hopefully it is yet to be converted and we can - // try to convert the fitting later - throw new ConversionNotReadyException("All connectors must be converted before fitting"); - } - else - { - // TODO: the fitting doesn't exist in the incoming commit. Maybe we can add a placeholder? - exceptions.Add(new SpeckleException("The element that the fitting connects to is not in the incoming Commit object")); - } - } - throw new AggregateException(exceptions); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFloor.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFloor.cs deleted file mode 100644 index b785186449..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFloor.cs +++ /dev/null @@ -1,481 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using OG = Objects.Geometry; -using OO = Objects.Other; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject FloorToNative(BuiltElements.Floor speckleFloor) - { - var docObj = GetExistingElementByApplicationId(speckleFloor.applicationId); - var appObj = new ApplicationObject(speckleFloor.id, speckleFloor.speckle_type) - { - applicationId = speckleFloor.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (speckleFloor.outline == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Floor is missing an outline."); - return appObj; - } - - bool structural = false; - if (speckleFloor["structural"] is bool isStructural) - structural = isStructural; - - var levelState = ApplicationObject.State.Unknown; - double baseOffset = 0.0; - DB.Level level = - (speckleFloor.level != null) - ? ConvertLevelToRevit(speckleFloor.level, out levelState) - : ConvertLevelToRevit( - CurveToNative(speckleFloor.outline).get_Item(0), - out ApplicationObject.State state, - out baseOffset - ); - - double slope = 0; - DB.Line slopeDirection = null; - if (speckleFloor is RevitFloor speckleRevitFloor) - { - structural = speckleRevitFloor.structural; - slope = speckleRevitFloor.slope; - slopeDirection = - (speckleRevitFloor.slopeDirection != null) ? LineToNative(speckleRevitFloor.slopeDirection) : null; - } - - var flattenedOutline = GetFlattenedCurve(speckleFloor.outline, level.Elevation); - var outline = CurveToNative(flattenedOutline, true); - UnboundCurveIfSingle(outline); - - var floorType = GetElementType(speckleFloor, appObj, out bool _); - if (floorType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - // NOTE: I have not found a way to edit a slab outline properly, so whenever we bake, we renew the element. The closest thing would be: - // https://adndevbConversionLog.Add.typepad.com/aec/2013/10/change-the-boundary-of-floorsslabs.html - // This would only work if the floors have the same number (and type!!!) of outline curves. - - - if (docObj != null) - Doc.Delete(docObj.Id); - - DB.Floor revitFloor = null; - -#if (REVIT2020 || REVIT2021) - if (floorType == null) - { - if (slope != 0 && slopeDirection != null) - revitFloor = Doc.Create.NewSlab(outline, level, slopeDirection, slope, structural); - if (revitFloor == null) - revitFloor = Doc.Create.NewFloor(outline, structural); - } - else - { - if (slope != 0 && slopeDirection != null) - revitFloor = Doc.Create.NewSlab(outline, level, slopeDirection, slope, structural); - if (revitFloor == null) - revitFloor = Doc.Create.NewFloor(outline, floorType, level, structural); - } - -#else - if (floorType == null) - throw new SpeckleException("Floor needs a floor type"); - else - { - //from revit 2022 we can create openings in the floors! - var profile = new List { CurveArrayToCurveLoop(outline) }; - if (speckleFloor["voids"] != null && (speckleFloor["voids"] is List voids)) - { - foreach (var v in voids) - { - var opening = CurveArrayToCurveLoop(CurveToNative(v, true)); - profile.Add(opening); - } - } - - if (slope != 0 && slopeDirection != null) - revitFloor = Floor.Create(Doc, profile, floorType.Id, level.Id, structural, slopeDirection, slope); - if (revitFloor == null) - revitFloor = Floor.Create(Doc, profile, floorType.Id, level.Id, structural, null, 0); - } -#endif - if (speckleFloor is not RevitFloor) - TrySetParam(revitFloor, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM, -baseOffset); - - Doc.Regenerate(); - -#if (REVIT2020 || REVIT2021) - try - { - CreateVoids(revitFloor, speckleFloor); - } - catch (Exception ex) - { - appObj.Update(logItem: $"Could not create openings: {ex.Message}"); - } -#endif - - SetInstanceParameters(revitFloor, speckleFloor); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitFloor.UniqueId, convertedItem: revitFloor); - //appObj = SetHostedElements(speckleFloor, revitFloor, appObj); - return appObj; - } - - private RevitFloor FloorToSpeckle(DB.Floor revitFloor, out List notes) - { - notes = new List(); - var speckleFloor = new RevitFloor(); -#if REVIT2020 || REVIT2021 - var profiles = GetProfiles(revitFloor); -#else - var sketch = Doc.GetElement(revitFloor.SketchId) as Sketch; - var profiles = GetSketchProfiles(sketch).Cast().ToList(); -#endif - var type = revitFloor.Document.GetElement(revitFloor.GetTypeId()) as ElementType; - speckleFloor.family = type?.FamilyName; - speckleFloor.type = type?.Name; - speckleFloor.outline = profiles[0]; - if (profiles.Count > 1) - { - speckleFloor.voids = profiles.Skip(1).ToList(); - } - - speckleFloor.level = ConvertAndCacheLevel(revitFloor, BuiltInParameter.LEVEL_PARAM); - speckleFloor.structural = GetParamValue(revitFloor, BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL); - - // Divide by 100 to convert from percentage to unitless ratio (rise over run) - var slopeParam = GetParamValue(revitFloor, BuiltInParameter.ROOF_SLOPE) / 100; - - GetAllRevitParamsAndIds( - speckleFloor, - revitFloor, - new List { "LEVEL_PARAM", "FLOOR_PARAM_IS_STRUCTURAL", "ROOF_SLOPE" } - ); - - var slopeArrow = GetSlopeArrow(revitFloor); - if (slopeArrow != null) - { - var tail = GetSlopeArrowTail(slopeArrow, Doc); - var head = GetSlopeArrowHead(slopeArrow, Doc); - var tailOffset = GetSlopeArrowTailOffset(slopeArrow, Doc); - _ = GetSlopeArrowHeadOffset(slopeArrow, Doc, tailOffset, out var slope); - - slopeParam ??= slope; - speckleFloor.slope = (double)slopeParam; - - speckleFloor.slopeDirection = new Geometry.Line(tail, head); - if ( - speckleFloor["parameters"] is Base parameters - && parameters["FLOOR_HEIGHTABOVELEVEL_PARAM"] is BuiltElements.Revit.Parameter offsetParam - && offsetParam.value is double offset - ) - { - offsetParam.value = offset + tailOffset; - } - } - - speckleFloor.displayValue = GetElementDisplayValue(revitFloor); - - GetHostedElements(speckleFloor, revitFloor, out List hostedNotes); - if (hostedNotes.Any()) - notes.AddRange(hostedNotes); - return speckleFloor; - } - - // Nesting the various profiles into a polycurve segments. - // TODO: **These should be HORIZONTAL on the floor level!** otherwise sloped floors will not be converted back to native properly - private List GetProfiles(DB.CeilingAndFloor floor) - { - var profiles = new List(); - var faces = HostObjectUtils.GetTopFaces(floor); - Face face = floor.GetGeometryObjectFromReference(faces[0]) as Face; - var crvLoops = face.GetEdgesAsCurveLoops(); - foreach (var crvloop in crvLoops) - { - var poly = new Polycurve(ModelUnits); - foreach (var curve in crvloop) - { - var c = curve; - if (c == null) - continue; - - poly.segments.Add(CurveToSpeckle(c, floor.Document)); - } - profiles.Add(poly); - } - return profiles; - } - - // in order to create a revit floor, we need to pass it a flat profile so change all the z values - private ICurve GetFlattenedCurve(ICurve curve, double z) - { - // kind of a hack. Editing our speckle objects is so much easier than editing the revit objects - // so scale this z value from the model units to the incoming commit units and then those values will - // get scaled back to the model units when this entire outline gets scaled to native - - switch (curve) - { - case OG.Arc arc: - var normalUnit = arc.plane.normal.Unit(); - var normalAsPoint = new OG.Point(normalUnit.x, normalUnit.y, normalUnit.z); - var arcConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, arc.units); - - if (normalAsPoint.DistanceTo(new OG.Point(0, 0, 1)) < TOLERANCE) - { - var translation = new OG.Vector(0, 0, (z * arcConversionFactor) - arc.startPoint.z) { units = ModelUnits }; - var transform = new OO.Transform( - new OG.Vector(1, 0, 0), - new OG.Vector(0, 1, 0), - new OG.Vector(0, 0, 1), - translation - ); - _ = arc.TransformTo(transform, out OG.Arc newArc); - return newArc; - } - else - { - // sneakily replace the users arc with a curve 🤫. - // TODO: set knots in curve or apply more complex transforms to arc because this replacement is decent but not perfect - - var newPlane = new OG.Plane( - new OG.Point(arc.plane.origin.x, arc.plane.origin.y, arc.plane.origin.z), - arc.plane.normal, - arc.plane.xdir, - arc.plane.ydir - ); - var firstHalfArc = new OG.Arc( - newPlane, - arc.midPoint, - arc.startPoint, - arc.angleRadians / 2, - units: arc.units - ); - var secondHalfArc = new OG.Arc( - newPlane, - arc.endPoint, - arc.midPoint, - arc.angleRadians / 2, - units: arc.units - ); - var arcCurvePoints = new List - { - arc.startPoint.x, - arc.startPoint.y, - z * arcConversionFactor, - firstHalfArc.midPoint.x, - firstHalfArc.midPoint.y, - z * arcConversionFactor, - arc.midPoint.x, - arc.midPoint.y, - z * arcConversionFactor, - secondHalfArc.midPoint.x, - secondHalfArc.midPoint.y, - z * arcConversionFactor, - arc.endPoint.x, - arc.endPoint.y, - z * arcConversionFactor - }; - - var newArcCurve = new OG.Curve - { - points = arcCurvePoints, - weights = new List(Enumerable.Repeat(1.0, arcCurvePoints.Count)), - //knots = nurbs.knots, - //degree = nurbs.degree, - rational = false, - closed = false, - //newCurve.domain - //newCurve.length - units = arc.units - }; - - return newArcCurve; - } - - // Note: this method is untested. It seems Revit doesn't send circles... it sends two arcs instead. - // Other applications may send circles though... needs more testing - case OG.Circle circle: - if (!(circle.radius is double radius && radius > 0)) - { - throw new Exception($"Circle with id, {circle.id}, does not have a valid radius"); - } - var circleNormalUnit = circle.plane.normal.Unit(); - var circleNormalAsPoint = new OG.Point(circleNormalUnit.x, circleNormalUnit.y, circleNormalUnit.z); - var circleConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, circle.units); - - var flattenTransformCircle = new OO.Transform( - new Vector(1, 0, 0), - new Vector(0, 1, 0), - new Vector(0, 0, 0), - new Vector(0, 0, z * circleConversionFactor, units: circle.plane.units) - ); - - _ = circle.plane.TransformTo(flattenTransformCircle, out OG.Plane newCirclePlane); - - if (circleNormalAsPoint.DistanceTo(new OG.Point(0, 0, 1)) < TOLERANCE) - { - return new OG.Circle(newCirclePlane, radius, units: circle.units); - } - - newCirclePlane.xdir.Normalize(); - newCirclePlane.ydir.Normalize(); - newCirclePlane.normal = Vector.CrossProduct(newCirclePlane.xdir, newCirclePlane.ydir); - - // this is the formula for an angle between two vectors - // cos T = a . b / (|a| * |b|) - var rad1ScaleCircle = - Vector.DotProduct(circle.plane.xdir, newCirclePlane.xdir) - / (circle.plane.xdir.Length * newCirclePlane.xdir.Length); - - var rad2ScaleCircle = - Vector.DotProduct(circle.plane.ydir, newCirclePlane.ydir) - / (circle.plane.ydir.Length * newCirclePlane.ydir.Length); - - return new OG.Ellipse( - newCirclePlane, - radius * rad1ScaleCircle, - radius * rad2ScaleCircle, - units: circle.units - ); - - case OG.Curve nurbs: - var curvePoints = new List(); - var nurbsConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, nurbs.units); - for (var i = 0; i < nurbs.points.Count; i++) - { - if (i % 3 == 2) - curvePoints.Add(z * nurbsConversionFactor); - else - curvePoints.Add(nurbs.points[i]); - } - var newCurve = new OG.Curve - { - points = curvePoints, - weights = nurbs.weights, - knots = nurbs.knots, - degree = nurbs.degree, - rational = nurbs.rational, - closed = nurbs.closed, - //newCurve.domain - //newCurve.length - units = nurbs.units - }; - return newCurve; - - case OG.Ellipse ellipse: - if (!(ellipse.firstRadius is double firstRadius && firstRadius > 0)) - { - throw new Exception($"Ellipse with id, {ellipse.id}, does not have a valid first radius"); - } - if (!(ellipse.secondRadius is double secondRadius && secondRadius > 0)) - { - throw new Exception($"Ellipse with id, {ellipse.id}, does not have a valid second radius"); - } - var ellipseConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, ellipse.units); - var flattenTransform = new OO.Transform( - new Vector(1, 0, 0), - new Vector(0, 1, 0), - new Vector(0, 0, 0), - new Vector(0, 0, z * ellipseConversionFactor, units: ellipse.plane.units) - ); - - _ = ellipse.plane.TransformTo(flattenTransform, out OG.Plane newEllipsePlane); - - newEllipsePlane.xdir.Normalize(); - newEllipsePlane.ydir.Normalize(); - newEllipsePlane.normal = Vector.CrossProduct(newEllipsePlane.xdir, newEllipsePlane.ydir); - - // this is the formula for an angle between two vectors - // cos T = a . b / (|a| * |b|) - var rad1Scale = - Vector.DotProduct(ellipse.plane.xdir, newEllipsePlane.xdir) - / (ellipse.plane.xdir.Length * newEllipsePlane.xdir.Length); - - var rad2Scale = - Vector.DotProduct(ellipse.plane.ydir, newEllipsePlane.ydir) - / (ellipse.plane.ydir.Length * newEllipsePlane.ydir.Length); - - return new OG.Ellipse( - newEllipsePlane, - firstRadius * rad1Scale, - secondRadius * rad2Scale, - ellipse.domain, - ellipse.trimDomain, - units: ellipse.units - ); - - case OG.Line line: - return new OG.Line( - new OG.Point( - line.start.x, - line.start.y, - z * Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, line.start.units), - line.start.units - ), - new OG.Point( - line.end.x, - line.end.y, - z * Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, line.end.units), - line.end.units - ), - line.units - ); - - case OG.Polyline poly: - var polylinePonts = new List(); - var originalPolylinePoints = poly.GetPoints(); - var polyConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, poly.units); - for (var i = 0; i < originalPolylinePoints.Count; i++) - { - polylinePonts.Add(originalPolylinePoints[i].x); - polylinePonts.Add(originalPolylinePoints[i].y); - polylinePonts.Add(z * polyConversionFactor); - } - var newPolyline = new Polyline(polylinePonts, poly.units); - newPolyline.closed = poly.closed; - return newPolyline; - - case OG.Polycurve plc: - var newPolycurve = new Polycurve(plc.units); - foreach (var seg in plc.segments) - newPolycurve.segments.Add(GetFlattenedCurve(seg, z)); - return newPolycurve; - - //case OG.Spiral spiral: - } - throw new NotSupportedException($"Trying to flatten unsupported curve type, {curve.GetType()}"); - } - - public List GetSketchProfiles(Sketch sketch) - { - var profiles = new List(); - foreach (CurveArray curves in sketch.Profile) - { - var curveLoop = CurveArrayToCurveLoop(curves); - profiles.Add( - new OG.Polycurve { segments = curveLoop.Select(x => CurveToSpeckle(x, sketch.Document)).ToList() } - ); - } - - return profiles; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFreeformElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFreeformElement.cs deleted file mode 100644 index b534116cc6..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertFreeformElement.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Autodesk.Revit.DB; -using ConverterRevitShared.Revit; -using Objects.Geometry; -using Objects.Other; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Mesh = Objects.Geometry.Mesh; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject FreeformElementToNative(Objects.BuiltElements.Revit.FreeformElement freeformElement) - { - var appObj = new ApplicationObject(freeformElement.id, freeformElement.speckle_type) { applicationId = freeformElement.applicationId }; - - // 1. Convert the freeformElement geometry to native - var solids = new List(); - foreach (var geom in freeformElement.baseGeometries) - switch (geom) - { - case Brep brep: - try - { - var solid = BrepToNative(geom as Brep, out List brepNotes); - if (brepNotes.Count > 0) appObj.Update(log: brepNotes); - solids.Add(solid); - } - catch (Exception e) - { - appObj.Update(logItem: $"Could not convert brep to native, falling back to mesh representation: {e.Message}"); - var brepMeshSolids = GetSolidMeshes(brep.displayValue); - solids.AddRange(brepMeshSolids); - } - break; - case Objects.Geometry.Mesh mesh: - var meshSolids = MeshToNative(mesh, DB.TessellatedShapeBuilderTarget.Solid, DB.TessellatedShapeBuilderFallback.Abort, mesh["renderMaterial"] as RenderMaterial) - .Select(m => m as DB.Solid); - solids.AddRange(meshSolids); - break; - } - - var tempPath = CreateFreeformElementFamily(solids, freeformElement.id, out List notes, freeformElement); - appObj.Update(log: notes); - if (tempPath == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - Doc.LoadFamily(tempPath, new FamilyLoadOption(), out var fam); - var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; - symbol.Activate(); - try - { - File.Delete(tempPath); - } - catch { } - - FamilyInstance freeform; - if (Doc.IsFamilyDocument) - { - freeform = Doc.FamilyCreate.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); - } - else - { - freeform = Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); - } - - appObj.Update(status: ApplicationObject.State.Created, createdId: freeform.UniqueId, convertedItem: freeform); - SetInstanceParameters(freeform, freeformElement); - return appObj; - } - - public ApplicationObject FreeformElementToNativeFamily(Brep brep, Category cat = null) - { - var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; - var solids = new List(); - try - { - var solid = BrepToNative(brep, out List brepNotes); - if (brepNotes.Count > 0) appObj.Update(log: brepNotes); - solids.Add(solid); - } - catch (Exception e) - { - var meshes = GetSolidMeshes(brep.displayValue); - solids.AddRange(meshes); - } - - foreach (var s in solids) - { - var form = DB.FreeFormElement.Create(Doc, s); - if (cat != null) - form.Subcategory = cat; - appObj.Update(createdId: form.UniqueId, convertedItem: form); - } - - return appObj; - } - - public ApplicationObject FreeformElementToNativeFamily(Geometry.Mesh mesh) - { - var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; - var solids = new List(); - var d = MeshToNative(mesh, DB.TessellatedShapeBuilderTarget.Solid); - var revitMesh = - d.Select(m => m as DB.Solid); - solids.AddRange(revitMesh); - - foreach (var s in solids) - { - var form = DB.FreeFormElement.Create(Doc, s); - appObj.Update(createdId: form.UniqueId, convertedItem: s); - } - - return appObj; - } - - private IEnumerable GetSolidMeshes(IEnumerable meshes) - { - var allMeshes = meshes - .SelectMany( - m => MeshToNative(m, DB.TessellatedShapeBuilderTarget.Solid, DB.TessellatedShapeBuilderFallback.Abort) ?? new List()); - var notNull = allMeshes.Where(m => m != null); - var solids = notNull.Select(m => m as DB.Solid); - return solids; - } - - private ApplicationObject FreeformElementToNative(Brep brep) - { - var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; - var solids = new List(); - try - { - var solid = BrepToNative(brep, out List brepNotes); - if (brepNotes.Count > 0) appObj.Update(log: brepNotes); - solids.Add(solid); - } - catch (Exception e) - { - solids.AddRange(GetSolidMeshes(brep.displayValue)); - } - - var tempPath = CreateFreeformElementFamily(solids, brep.id, out List freeformNotes); - if (freeformNotes.Count > 0) appObj.Update(log: freeformNotes); - if (tempPath == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - Doc.LoadFamily(tempPath, new FamilyLoadOption(), out var fam); - var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; - symbol.Activate(); - - var freeform = Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); - - SetInstanceParameters(freeform, brep); - - appObj.Update(status: ApplicationObject.State.Created, createdId: freeform.UniqueId, convertedItem: freeform); - return appObj; - } - - private string CreateFreeformElementFamily(List solids, string name, out List notes, Objects.BuiltElements.Revit.FreeformElement freeformElement = null) - { - notes = new List(); - // FreeformElements can only be created in a family context. - // so we create a temporary family to hold it. - - var templatePath = GetTemplatePath("Generic Model"); - if (!File.Exists(templatePath)) - { - notes.Add($"Could not find Generic Model rft file - {templatePath}"); - return null; - } - - var famDoc = Doc.Application.NewFamilyDocument(templatePath); - - using (DB.Transaction t = new DB.Transaction(famDoc, "Create Freeform Elements")) - { - t.Start(); - - //by default free form elements are always generic models - Category cat = null; - if (freeformElement is not null && !string.IsNullOrEmpty(freeformElement.subcategory)) - { - BuiltInCategory bic = BuiltInCategory.OST_GenericModel; - cat = famDoc.Settings.Categories.get_Item(bic); - - //subcategory - if (cat.SubCategories.Contains(freeformElement.subcategory)) - { - cat = cat.SubCategories.get_Item(freeformElement.subcategory); - } - else - { - cat = famDoc.Settings.Categories.NewSubcategory(cat, freeformElement.subcategory); - } - } - - foreach (var s in solids) - { - var f = DB.FreeFormElement.Create(famDoc, s); - if (cat is not null) - { - f.Subcategory = cat; - } - } - - t.Commit(); - } - var famName = "SpeckleFreeform_" + name; - string tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); - var so = new DB.SaveAsOptions(); - so.OverwriteExistingFile = true; - famDoc.SaveAs(tempFamilyPath, so); - famDoc.Close(); - notes.Add($"Created temp family {tempFamilyPath}"); - return tempFamilyPath; - } - - private DB.FamilyInstance CreateFreeformElementFamily(List solids, string name, string templateName) - { - var templatePath = GetTemplatePath(templateName); - if (!File.Exists(templatePath)) - throw new FileNotFoundException($"Could not find Generic Model rft file - {templatePath}"); - - var famDoc = Doc.Application.NewFamilyDocument(templatePath); - - using (var t = new Transaction(famDoc, "Create Freeform Elements")) - { - t.Start(); - foreach (var s in solids) - FreeFormElement.Create(famDoc, s); - t.Commit(); - } - - var famName = "SpeckleFreeform_" + name; - var tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); - var so = new SaveAsOptions { OverwriteExistingFile = true }; - famDoc.SaveAs(tempFamilyPath, so); - famDoc.Close(); - - Doc.LoadFamily(tempFamilyPath, new FamilyLoadOption(), out var fam); - - var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as FamilySymbol; - symbol.Activate(); - return Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); - } - - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGeometry.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGeometry.cs deleted file mode 100644 index 7863a9a5c3..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGeometry.cs +++ /dev/null @@ -1,1376 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.DoubleNumerics; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.PointClouds; -using Objects.Converters.DxfConverter; -using Objects.Geometry; -using Objects.Other; -using Objects.Primitive; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using Arc = Objects.Geometry.Arc; -using Curve = Objects.Geometry.Curve; -using DB = Autodesk.Revit.DB; -using Ellipse = Objects.Geometry.Ellipse; -using Line = Objects.Geometry.Line; -using Mesh = Objects.Geometry.Mesh; -using Plane = Objects.Geometry.Plane; -using Point = Objects.Geometry.Point; -using Pointcloud = Objects.Geometry.Pointcloud; -using Spiral = Objects.Geometry.Spiral; -using Surface = Objects.Geometry.Surface; -using Transform = Objects.Other.Transform; -using Units = Speckle.Core.Kits.Units; -using Vector = Objects.Geometry.Vector; - -namespace Objects.Converter.Revit -{ - /// - ///Internal helper methods used for converison - /// - public partial class ConverterRevit - { - // Convenience methods point: - public double[] PointToArray(Point pt) - { - return new double[] { pt.x, pt.y, pt.z }; - } - - public List PointsToFlatList(IEnumerable points) - { - return points.SelectMany(PointToArray).ToList(); - } - - public object GeometryToNative(Base geom) - { - switch (geom) - { - case Point g: - return PointToNative(g); - case ICurve g: - return CurveToNative(g); - case Plane g: - return PlaneToNative(g); - case Vector g: - return VectorToNative(g); - - default: - throw new Speckle.Core.Logging.SpeckleException("Cannot convert Curve of type " + geom.GetType()); - } - } - - public XYZ PointToNative(Point pt) - { - var revitPoint = new XYZ( - ScaleToNative(pt.x, pt.units), - ScaleToNative(pt.y, pt.units), - ScaleToNative(pt.z, pt.units) - ); - var intPt = ToInternalCoordinates(revitPoint, true); - return intPt; - } - - public Point PointToSpeckle( - XYZ pt, - Document doc, - string units = null, - bool doNotTransformWithReferencePoint = false - ) - { - var u = units ?? ModelUnits; - - var extPt = doNotTransformWithReferencePoint ? pt : ToExternalCoordinates(pt, true, doc); - - var pointToSpeckle = new Point( - u == Units.None ? extPt.X : ScaleToSpeckle(extPt.X), - u == Units.None ? extPt.Y : ScaleToSpeckle(extPt.Y), - u == Units.None ? extPt.Z : ScaleToSpeckle(extPt.Z), - u - ); - return pointToSpeckle; - } - - public List PointListToNative(IList arr, string units = null) - { - if (arr.Count % 3 != 0) - throw new SpeckleException("Array malformed: length%3 != 0."); - - var u = units ?? ModelUnits; - - var points = new List(arr.Count / 3); - for (int i = 2; i < arr.Count; i += 3) - points.Add(new XYZ(ScaleToNative(arr[i - 2], u), ScaleToNative(arr[i - 1], u), ScaleToNative(arr[i], u))); - - return points; - } - - public Pointcloud PointcloudToSpeckle(PointCloudInstance pointcloud, string units = null) - { - var u = units ?? ModelUnits; - var boundingBox = pointcloud.get_BoundingBox(null); - var transform = pointcloud.GetTransform(); - - var minPlane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisZ, transform.OfPoint(boundingBox.Min)); - var filter = PointCloudFilterFactory.CreateMultiPlaneFilter(new List() { minPlane }); - var points = pointcloud.GetPoints(filter, 0.0001, 999999); // max limit is 1 mil but 1000000 throws error - - var _pointcloud = new Pointcloud(); - _pointcloud.points = points - .Select(o => PointToSpeckle(transform.OfPoint(o), pointcloud.Document, u)) - .SelectMany(o => new List() { o.x, o.y, o.z }) - .ToList(); - _pointcloud.colors = points.Select(o => o.Color).ToList(); - _pointcloud.units = u; - _pointcloud.bbox = BoxToSpeckle(boundingBox, pointcloud.Document, u); - - return _pointcloud; - } - - public Vector VectorToSpeckle( - XYZ pt, - Document doc, - string units = null, - bool doNotTransformWithReferencePoint = false - ) - { - var u = units ?? ModelUnits; - var extPt = doNotTransformWithReferencePoint ? pt : ToExternalCoordinates(pt, false, doc); - var pointToSpeckle = new Vector( - u == Units.None ? extPt.X : ScaleToSpeckle(extPt.X), - u == Units.None ? extPt.Y : ScaleToSpeckle(extPt.Y), - u == Units.None ? extPt.Z : ScaleToSpeckle(extPt.Z), - u - ); - return pointToSpeckle; - } - - public XYZ VectorToNative(Vector pt) - { - var revitVector = new XYZ( - ScaleToNative(pt.x, pt.units), - ScaleToNative(pt.y, pt.units), - ScaleToNative(pt.z, pt.units) - ); - var intV = ToInternalCoordinates(revitVector, false); - return intV; - } - - public DB.Plane PlaneToNative(Plane plane) - { - return DB.Plane.CreateByOriginAndBasis( - PointToNative(plane.origin), - VectorToNative(plane.xdir).Normalize(), - VectorToNative(plane.ydir).Normalize() - ); - } - - public Plane PlaneToSpeckle(DB.Plane plane, Document doc, string units = null) - { - var u = units ?? ModelUnits; - var origin = PointToSpeckle(plane.Origin, doc, u); - var normal = VectorToSpeckle(plane.Normal, doc, u); - var xdir = VectorToSpeckle(plane.XVec, doc, u); - var ydir = VectorToSpeckle(plane.YVec, doc, u); - - return new Plane(origin, normal, xdir, ydir, u); - } - - public DB.Line LineToNative(Line line) - { - return DB.Line.CreateBound(PointToNative(line.start), PointToNative(line.end)); - } - - public Line LineToSpeckle(DB.Line line, Document doc, string units = null) - { - var u = units ?? ModelUnits; - var l = new Line { units = u }; - l.start = PointToSpeckle(line.GetEndPoint(0), doc, u); - l.end = PointToSpeckle(line.GetEndPoint(1), doc, u); - l.domain = new Interval(line.GetEndParameter(0), line.GetEndParameter(1)); - - l.length = ScaleToSpeckle(line.Length); - return l; - } - - public Circle CircleToSpeckle(DB.Arc arc, Document doc, string units = null) - { - // see https://forums.autodesk.com/t5/revit-api-forum/how-to-retrieve-startangle-and-endangle-of-arc-object/td-p/7637128 - var u = units ?? ModelUnits; - var arcPlane = DB.Plane.CreateByNormalAndOrigin(arc.Normal, arc.Center); - - var c = new Circle( - PlaneToSpeckle(arcPlane, doc, u), - u == Units.None ? arc.Radius : ScaleToSpeckle(arc.Radius), - u - ); - c.length = ScaleToSpeckle(arc.Length); - return c; - } - - public DB.Arc CircleToNative(Circle circle) - { - var plane = PlaneToNative(circle.plane); - return DB.Arc.Create(plane, ScaleToNative((double)circle.radius, circle.units), 0, 2 * Math.PI); - } - - public DB.Arc ArcToNative(Arc arc) - { - double startAngle, - endAngle; - if (arc.startAngle > arc.endAngle) - { - startAngle = (double)arc.endAngle; - endAngle = (double)arc.startAngle; - } - else - { - startAngle = (double)arc.startAngle; - endAngle = (double)arc.endAngle; - } - var plane = PlaneToNative(arc.plane); - - if (Point.Distance(arc.startPoint, arc.endPoint) < 1E-6) - { - // Endpoints coincide, it's a circle. - return DB.Arc.Create(plane, ScaleToNative(arc.radius ?? 0, arc.units), startAngle, endAngle); - } - - return DB.Arc.Create(PointToNative(arc.startPoint), PointToNative(arc.endPoint), PointToNative(arc.midPoint)); - //return Arc.Create( plane.Origin, (double) arc.Radius * Scale, startAngle, endAngle, plane.XVec, plane.YVec ); - } - - public Arc ArcToSpeckle(DB.Arc arc, Document doc, string units = null) - { - var u = units ?? ModelUnits; - // see https://forums.autodesk.com/t5/revit-api-forum/how-to-retrieve-startangle-and-endangle-of-arc-object/td-p/7637128 - var arcPlane = DB.Plane.CreateByOriginAndBasis(arc.Center, arc.XDirection, arc.YDirection); - XYZ center = arc.Center; - - XYZ dir0 = (arc.GetEndPoint(0) - center).Normalize(); - XYZ dir1 = (arc.GetEndPoint(1) - center).Normalize(); - - XYZ start = arc.Evaluate(0, true); - XYZ end = arc.Evaluate(1, true); - XYZ mid = arc.Evaluate(0.5, true); - - double startAngle = arc.XDirection.AngleOnPlaneTo(dir0, arc.Normal); - double endAngle = arc.XDirection.AngleOnPlaneTo(dir1, arc.Normal); - - var a = new Arc( - PlaneToSpeckle(arcPlane, doc, u), - u == Units.None ? arc.Radius : ScaleToSpeckle(arc.Radius), - startAngle, - endAngle, - endAngle - startAngle, - u - ); - a.endPoint = PointToSpeckle(end, doc, u); - a.startPoint = PointToSpeckle(start, doc, u); - a.midPoint = PointToSpeckle(mid, doc, u); - a.length = ScaleToSpeckle(arc.Length); - a.domain = new Interval(arc.GetEndParameter(0), arc.GetEndParameter(1)); - - return a; - } - - public DB.Curve EllipseToNative(Ellipse ellipse) - { - //TODO: support ellipse arcs - using (DB.Plane basePlane = PlaneToNative(ellipse.plane)) - { - var e = DB.Ellipse.CreateCurve( - PointToNative(ellipse.plane.origin), - ScaleToNative((double)ellipse.firstRadius, ellipse.units), - ScaleToNative((double)ellipse.secondRadius, ellipse.units), - basePlane.XVec.Normalize(), - basePlane.YVec.Normalize(), - 0, - 2 * Math.PI - ); - e.MakeBound(ellipse.trimDomain?.start ?? 0, ellipse.trimDomain?.end ?? 2 * Math.PI); - return e; - } - } - - public Ellipse EllipseToSpeckle(DB.Ellipse ellipse, Document doc, string units = null) - { - var u = units ?? ModelUnits; - using ( - DB.Plane basePlane = DB.Plane.CreateByOriginAndBasis(ellipse.Center, ellipse.XDirection, ellipse.YDirection) - ) - { - var trim = ellipse.IsBound ? new Interval(ellipse.GetEndParameter(0), ellipse.GetEndParameter(1)) : null; - - var ellipseToSpeckle = new Ellipse( - PlaneToSpeckle(basePlane, doc, u), - u == Units.None ? ellipse.RadiusX : ScaleToSpeckle(ellipse.RadiusX), - u == Units.None ? ellipse.RadiusY : ScaleToSpeckle(ellipse.RadiusY), - new Interval(0, 2 * Math.PI), - trim, - u - ); - ellipseToSpeckle.length = ScaleToSpeckle(ellipse.Length); - ellipseToSpeckle.domain = new Interval(0, 1); - return ellipseToSpeckle; - } - } - - public Curve NurbsToSpeckle(DB.NurbSpline revitCurve, Document doc, string units = null) - { - var points = new List(); - foreach (var p in revitCurve.CtrlPoints) - { - var point = PointToSpeckle(p, doc, units); - points.AddRange(new List { point.x, point.y, point.z }); - } - - Curve speckleCurve = new Curve(); - speckleCurve.weights = revitCurve.Weights.Cast().ToList(); - speckleCurve.points = points; - speckleCurve.knots = revitCurve.Knots.Cast().ToList(); - ; - speckleCurve.degree = revitCurve.Degree; - //speckleCurve.periodic = revitCurve.Period; - speckleCurve.rational = revitCurve.isRational; - speckleCurve.closed = RevitVersionHelper.IsCurveClosed(revitCurve); - speckleCurve.units = units ?? ModelUnits; - speckleCurve.domain = new Interval(revitCurve.GetEndParameter(0), revitCurve.GetEndParameter(1)); - speckleCurve.length = ScaleToSpeckle(revitCurve.Length); - - var coords = revitCurve.Tessellate().SelectMany(xyz => PointToSpeckle(xyz, doc, units).ToList()).ToList(); - speckleCurve.displayValue = new Polyline(coords, units); - - return speckleCurve; - } - - public DB.Curve CurveToNative(Curve speckleCurve) - { - var pts = new List(); - for (int i = 0; i < speckleCurve.points.Count; i += 3) - { - //use PointToNative for conversion as that takes into account the Project Base Point - var point = new Point( - speckleCurve.points[i], - speckleCurve.points[i + 1], - speckleCurve.points[i + 2], - speckleCurve.units - ); - pts.Add(PointToNative(point)); - } - try - { - if ( - speckleCurve.knots != null - && speckleCurve.weights != null - && speckleCurve.knots.Any() - && speckleCurve.weights.Any() - ) - { - var weights = speckleCurve.weights.GetRange(0, pts.Count); - var speckleKnots = new List(speckleCurve.knots); - if (speckleKnots.Count != pts.Count + speckleCurve.degree + 1) - { - // Curve has rhino knots, repeat first and last. - speckleKnots.Insert(0, speckleKnots[0]); - speckleKnots.Add(speckleKnots[speckleKnots.Count - 1]); - } - - //var knots = speckleKnots.GetRange(0, pts.Count + speckleCurve.degree + 1); - var curve = NurbSpline.CreateCurve(speckleCurve.degree, speckleKnots, pts, weights); - return curve; - } - else - { - var weights = speckleCurve.weights.GetRange(0, pts.Count); - var curve = NurbSpline.CreateCurve(pts, weights); - return curve; - } - } - catch (Exception e) - { - if (e is Autodesk.Revit.Exceptions.ArgumentException) - throw; // prob a closed, periodic curve - return null; - } - } - - public CurveArray CurveToNative(List crvs) - { - CurveArray crvsArray = new CurveArray(); - foreach (var crv in crvs) - { - var crvEnumerator = CurveToNative(crv).GetEnumerator(); - while (crvEnumerator.MoveNext() && crvEnumerator.Current != null) - crvsArray.Append(crvEnumerator.Current as DB.Curve); - } - return crvsArray; - } - - /// - /// Recursively creates an ordered list of curves from a polycurve/polyline. - /// Please note that a polyline is broken down into lines. - /// - /// A speckle curve. - /// - public CurveArray CurveToNative(ICurve crv, bool splitIfClosed = false) - { - CurveArray curveArray = new CurveArray(); - switch (crv) - { - case Line line: - curveArray.Append(LineToNative(line)); - return curveArray; - - case Arc arc: - curveArray.Append(ArcToNative(arc)); - return curveArray; - - case Circle circle: - curveArray.Append(CircleToNative(circle)); - return curveArray; - - case Ellipse ellipse: - curveArray.Append(EllipseToNative(ellipse)); - return curveArray; - - case Spiral spiral: - return PolylineToNative(spiral.displayValue); - - case Curve nurbs: - var n = CurveToNative(nurbs); - if (IsCurveClosed(n) && splitIfClosed) - { - var split = SplitCurveInTwoHalves(n); - curveArray.Append(split.Item1); - curveArray.Append(split.Item2); - } - else - { - curveArray.Append(n); - } - return curveArray; - - case Polyline poly: - return PolylineToNative(poly); - - case Polycurve plc: - foreach (var seg in plc.segments) - { - // Enumerate all curves in the array to ensure polylines get fully converted. - var crvEnumerator = CurveToNative(seg).GetEnumerator(); - while (crvEnumerator.MoveNext() && crvEnumerator.Current != null) - curveArray.Append(crvEnumerator.Current as DB.Curve); - } - return curveArray; - default: - throw new Speckle.Core.Logging.SpeckleException("The provided geometry is not a valid curve"); - } - } - - //thanks Revit - public CurveLoop CurveArrayToCurveLoop(CurveArray array) - { - var loop = new CurveLoop(); - UnboundCurveIfSingle(array); - foreach (var item in array.Cast()) - loop.Append(item); - return loop; - } - - public ICurve CurveToSpeckle(DB.Curve curve, Document doc, string units = null) - { - var u = units ?? ModelUnits; - switch (curve) - { - case DB.Line line: - return LineToSpeckle(line, doc, u); - case DB.Arc arc: - if (!arc.IsBound) - { - return (CircleToSpeckle(arc, doc, u)); - } - return ArcToSpeckle(arc, doc, u); - case DB.Ellipse ellipse: - return EllipseToSpeckle(ellipse, doc, u); - case DB.NurbSpline nurbs: - return NurbsToSpeckle(nurbs, doc, u); - case DB.HermiteSpline spline: - return HermiteSplineToSpeckle(spline, doc, u); - default: - throw new Speckle.Core.Logging.SpeckleException("Cannot convert Curve of type " + curve.GetType()); - } - } - - public Polycurve CurveListToSpeckle(IList loop, Document doc, string units = null) - { - var polycurve = new Polycurve(); - polycurve.units = units ?? ModelUnits; - polycurve.closed = loop.First().GetEndPoint(0).DistanceTo(loop.Last().GetEndPoint(1)) < TOLERANCE; - polycurve.length = ScaleToSpeckle(loop.Sum(x => x.Length)); - polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x, doc))); - return polycurve; - } - - public Polycurve CurveLoopToSpeckle(CurveLoop loop, Document doc, string units = null) - { - var polycurve = new Polycurve(); - polycurve.units = units ?? ModelUnits; - polycurve.closed = !loop.IsOpen(); - polycurve.length = units == Units.None ? loop.GetExactLength() : ScaleToSpeckle(loop.GetExactLength()); - - polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x, doc))); - return polycurve; - } - - private ICurve HermiteSplineToSpeckle(HermiteSpline spline, Document doc, string units = null) - { - var nurbs = DB.NurbSpline.Create(spline); - return NurbsToSpeckle(nurbs, doc, units ?? ModelUnits); - } - - /// - /// Converts a Speckle into a . - /// - /// - /// This method will ensure that no lines smaller than the allowed length are created. - /// If small segments are encountered, the geometry will be modified to ensure all segments have minimum length and remain connected. - /// This will result in some vertices being ignored during conversion, which are logged in the report. - /// - /// The Speckle to convert to Revit - /// A Revit - public CurveArray PolylineToNative(Polyline polyline) - { - var appObj = new ApplicationObject(polyline.id, polyline.speckle_type) { applicationId = polyline.applicationId }; - var curveArray = new CurveArray(); - if (polyline.value.Count == 6) - { - // Polyline is actually a single line - TryAppendLineSafely(curveArray, new Line(polyline.value, polyline.units), appObj); - } - else - { - var pts = polyline.GetPoints(); - var lastPt = pts[0]; - for (var i = 1; i < pts.Count; i++) - { - var success = TryAppendLineSafely(curveArray, new Line(lastPt, pts[i], polyline.units), appObj); - if (success) - lastPt = pts[i]; - } - - if (polyline.closed) - { - TryAppendLineSafely(curveArray, new Line(pts[pts.Count - 1], pts[0], polyline.units), appObj); - } - } - return curveArray; - } - - public Polyline PolylineToSpeckle(PolyLine polyline, Document doc, string units = null) - { - var coords = polyline.GetCoordinates().SelectMany(coord => PointToSpeckle(coord, doc).ToList()).ToList(); - return new Polyline(coords, units ?? ModelUnits); - } - - public Box BoxToSpeckle(DB.BoundingBoxXYZ box, Document doc, string units = null) - { - // convert min and max pts to speckle first - var min = PointToSpeckle(box.Min, doc, units); - var max = PointToSpeckle(box.Max, doc, units); - - // get the base plane of the bounding box from the transform - var transform = box.Transform; - var plane = DB.Plane.CreateByOriginAndBasis( - transform.Origin, - transform.BasisX.Normalize(), - transform.BasisY.Normalize() - ); - - var _box = new Box() - { - xSize = new Interval(min.x, max.x), - ySize = new Interval(min.y, max.y), - zSize = new Interval(min.z, max.z), - basePlane = PlaneToSpeckle(plane, doc), - units = units ?? ModelUnits - }; - - return _box; - } - - public DB.BoundingBoxXYZ BoxToNative(Box box) - { - var boundingBox = new BoundingBoxXYZ(); - boundingBox.Min = PointToNative( - new Point((double)box.xSize.start, (double)box.ySize.start, (double)box.zSize.start) - ); - boundingBox.Max = PointToNative(new Point((double)box.xSize.end, (double)box.ySize.end, (double)box.zSize.end)); - return boundingBox; - } - - public Mesh MeshToSpeckle(DB.Mesh mesh, Document d, string units = null) - { - var vertices = new List(mesh.Vertices.Count * 3); - foreach (var vert in mesh.Vertices) - vertices.AddRange(PointToSpeckle(vert, d).ToList()); - - var faces = new List(mesh.NumTriangles * 4); - for (int i = 0; i < mesh.NumTriangles; i++) - { - var triangle = mesh.get_Triangle(i); - var A = triangle.get_Index(0); - var B = triangle.get_Index(1); - var C = triangle.get_Index(2); - faces.Add(3); - faces.AddRange(new int[] { (int)A, (int)B, (int)C }); - } - - var u = units ?? ModelUnits; - var speckleMesh = new Mesh(vertices, faces, units: u) - { - ["renderMaterial"] = RenderMaterialToSpeckle(d.GetElement(mesh.MaterialElementId) as DB.Material) - }; - - return speckleMesh; - } - - // Inspired by - // https://github.com/DynamoDS/DynamoRevit/blob/master/src/Libraries/RevitNodes/GeometryConversion/ProtoToRevitMesh.cs - public IList MeshToNative( - Mesh mesh, - TessellatedShapeBuilderTarget target = TessellatedShapeBuilderTarget.Mesh, - TessellatedShapeBuilderFallback fallback = TessellatedShapeBuilderFallback.Salvage, - RenderMaterial parentMaterial = null - ) - { - var tsb = new TessellatedShapeBuilder() - { - Fallback = fallback, - Target = target, - GraphicsStyleId = ElementId.InvalidElementId - }; - - var valid = tsb.AreTargetAndFallbackCompatible(target, fallback); - tsb.OpenConnectedFaceSet(target == TessellatedShapeBuilderTarget.Solid); - - var vertices = ArrayToPoints(mesh.vertices, mesh.units); - - ElementId materialId = RenderMaterialToNative(parentMaterial ?? (mesh["renderMaterial"] as RenderMaterial)); - - int i = 0; - while (i < mesh.faces.Count) - { - int n = mesh.faces[i]; - if (n < 3) - n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility - - var points = mesh.faces.GetRange(i + 1, n).Select(x => vertices[x]).ToArray(); - - if (IsNonPlanarQuad(points)) - { - //Non-planar quads will be triangulated as it's more desirable than `TessellatedShapeBuilder.Build`'s attempt to make them planar. - //TODO consider triangulating all n > 3 polygons that are non-planar - var triPoints = new List { points[0], points[1], points[3] }; - var face1 = new TessellatedFace(triPoints, materialId); - tsb.AddFace(face1); - - triPoints = new List { points[1], points[2], points[3] }; - ; - var face2 = new TessellatedFace(triPoints, materialId); - tsb.AddFace(face2); - } - else - { - var face = new TessellatedFace(points, materialId); - tsb.AddFace(face); - } - - i += n + 1; - } - - tsb.CloseConnectedFaceSet(); - try - { - tsb.Build(); - } - catch (Exception e) - { - Report.LogConversionError(e); - return null; - } - var result = tsb.GetBuildResult(); - return result.GetGeometricalObjects(); - - static bool IsNonPlanarQuad(IList points) - { - if (points.Count != 4) - return false; - - var matrix = new Matrix4x4( - points[0].X, points[1].X, points[2].X, points[3].X, - points[0].Y, points[1].Y, points[2].Y, points[3].Y, - points[0].Z, points[1].Z, points[2].Z, points[3].Z, - 1, 1, 1, 1 - ); - return matrix.GetDeterminant() != 0; - } - } - - public XYZ[] ArrayToPoints(IList arr, string units = null) - { - if (arr.Count % 3 != 0) - throw new Speckle.Core.Logging.SpeckleException("Array malformed: length%3 != 0."); - - XYZ[] points = new XYZ[arr.Count / 3]; - - for (int i = 2, k = 0; i < arr.Count; i += 3) - { - var point = new Point(arr[i - 2], arr[i - 1], arr[i], units); - points[k++] = PointToNative(point); - } - - return points; - } - - //https://github.com/DynamoDS/DynamoRevit/blob/f8206726d8a3aa5bf06f5dbf7ce8a732bb025c34/src/Libraries/RevitNodes/GeometryConversion/GeometryPrimitiveConverter.cs#L201 - public XYZ GetPerpendicular(XYZ xyz) - { - var ixn = xyz.Normalize(); - var xn = new XYZ(1, 0, 0); - - if (ixn.IsAlmostEqualTo(xn)) - { - xn = new XYZ(0, 1, 0); - } - else if (ixn.Negate().IsAlmostEqualTo(xn)) - { - xn = new XYZ(0, -1, 0); - } - - var cross = ixn.CrossProduct(xn); - - return cross.Normalize(); - } - - public Geometry.Surface FaceToSpeckle(DB.Face face, DB.BoundingBoxUV uvBox, Document doc, string units = null) - { -#if REVIT2020 - var surf = DB.ExportUtils.GetNurbsSurfaceDataForFace(face); -#else - var surf = DB.ExportUtils.GetNurbsSurfaceDataForSurface(face.GetSurface()); -#endif - var spcklSurface = NurbsSurfaceToSpeckle(surf, face.GetBoundingBox(), doc, units ?? ModelUnits); - return spcklSurface; - } - - public Surface NurbsSurfaceToSpeckle( - DB.NurbsSurfaceData surface, - DB.BoundingBoxUV uvBox, - Document doc, - string units = null - ) - { - var result = new Surface(); - - var unit = units ?? ModelUnits; - result.units = unit; - - result.degreeU = surface.DegreeU; - result.degreeV = surface.DegreeV; - - result.domainU = new Interval(0, 1); - result.domainV = new Interval(0, 1); - - var knotsU = surface.GetKnotsU().ToList(); - var knotsV = surface.GetKnotsV().ToList(); - - result.knotsU = knotsU.GetRange(1, knotsU.Count - 2); - result.knotsV = knotsV.GetRange(1, knotsV.Count - 2); - - var controlPointCountU = knotsU.Count - result.degreeU - 1; - var controlPointCountV = knotsV.Count - result.degreeV - 1; - - var controlPoints = surface.GetControlPoints(); - var weights = surface.GetWeights(); - - var points = new List>(); - for (var u = 0; u < controlPointCountU; u++) - { - var uOffset = u * controlPointCountV; - var row = new List(); - - for (var v = 0; v < controlPointCountV; v++) - { - var pt = controlPoints[uOffset + v]; - var extPt = ToExternalCoordinates(pt, true, doc); - if (surface.IsRational) - { - var w = weights[uOffset + v]; - var point = PointToSpeckle(extPt, doc, unit); - row.Add(new ControlPoint(point.x, point.y, point.z, w, unit)); - } - else - { - var point = PointToSpeckle(extPt, doc, unit); - row.Add(new ControlPoint(point.x, point.y, point.z, unit)); - } - } - points.Add(row); - } - - result.SetControlPoints(points); - - return result; - } - - public List BrepEdgeToNative(BrepEdge edge) - { - // TODO: Trim curve with domain. Unsure if this is necessary as all our curves are converted to NURBS on Rhino output. - var nativeCurveArray = CurveToNative(edge.Curve); - bool isTrimmed = - edge.Curve.domain != null - && edge.Domain != null - && (edge.Curve.domain.start != edge.Domain.start || edge.Curve.domain.end != edge.Domain.end); - if (nativeCurveArray.Size == 1) - { - var nativeCurve = nativeCurveArray.get_Item(0); - - if (edge.ProxyCurveIsReversed) - nativeCurve = nativeCurve.CreateReversed(); - - if (nativeCurve == null) - return new List(); - if (isTrimmed) - nativeCurve.MakeBound(edge.Domain.start ?? 0, edge.Domain.end ?? 1); - if (!nativeCurve.IsBound) - nativeCurve.MakeBound(0, nativeCurve.Period); - - if (IsCurveClosed(nativeCurve)) - { - var (first, second) = SplitCurveInTwoHalves(nativeCurve); - if (edge.ProxyCurveIsReversed) - { - first = first.CreateReversed(); - second = second.CreateReversed(); - } - var halfEdgeA = BRepBuilderEdgeGeometry.Create(first); - var halfEdgeB = BRepBuilderEdgeGeometry.Create(second); - return edge.ProxyCurveIsReversed - ? new List { halfEdgeA, halfEdgeB } - : new List { halfEdgeB, halfEdgeA }; - } - - // TODO: Remove short segments if smaller than 'Revit.ShortCurveTolerance'. - var fullEdge = BRepBuilderEdgeGeometry.Create(nativeCurve); - return new List { fullEdge }; - } - - var iterator = edge.ProxyCurveIsReversed - ? nativeCurveArray.ReverseIterator() - : nativeCurveArray.ForwardIterator(); - - var result = new List(); - while (iterator.MoveNext()) - { - var crv = iterator.Current as DB.Curve; - if (edge.ProxyCurveIsReversed) - crv = crv.CreateReversed(); - result.Add(BRepBuilderEdgeGeometry.Create(crv)); - } - - return result; - } - - public double[] ControlPointWeightsToNative(List> controlPoints) - { - var uCount = controlPoints.Count; - var vCount = controlPoints[0].Count; - var count = uCount * vCount; - var weights = new double[count]; - int p = 0; - - controlPoints.ForEach(row => row.ForEach(pt => weights[p++] = pt.weight)); - - return weights; - } - - public XYZ[] ControlPointsToNative(List> controlPoints) - { - var uCount = controlPoints.Count; - var vCount = controlPoints[0].Count; - var count = uCount * vCount; - var points = new DB.XYZ[count]; - int p = 0; - - controlPoints.ForEach( - row => - row.ForEach(pt => - { - var point = new Point(pt.x, pt.y, pt.z, pt.units); - points[p++] = PointToNative(point); - }) - ); - - return points; - } - - public double[] SurfaceKnotsToNative(List list) - { - var count = list.Count; - var knots = new double[count + 2]; - - int j = 0, - k = 0; - while (j < count) - knots[++k] = list[j++]; - - knots[0] = knots[1]; - knots[count + 1] = knots[count]; - - return knots; - } - - public BRepBuilderSurfaceGeometry SurfaceToNative(Surface surface) - { - var uvBox = new DB.BoundingBoxUV( - surface.knotsU[0], - surface.knotsV[0], - surface.knotsU[surface.knotsU.Count - 1], - surface.knotsV[surface.knotsV.Count - 1] - ); - var surfPts = surface.GetControlPoints(); - var uKnots = SurfaceKnotsToNative(surface.knotsU); - var vKnots = SurfaceKnotsToNative(surface.knotsV); - var cPts = ControlPointsToNative(surfPts); - - BRepBuilderSurfaceGeometry result; - if (!surface.rational) - { - result = DB.BRepBuilderSurfaceGeometry.CreateNURBSSurface( - surface.degreeU, - surface.degreeV, - uKnots, - vKnots, - cPts, - false, - uvBox - ); - } - else - { - var weights = ControlPointWeightsToNative(surfPts); - result = DB.BRepBuilderSurfaceGeometry.CreateNURBSSurface( - surface.degreeU, - surface.degreeV, - uKnots, - vKnots, - cPts, - weights, - false, - uvBox - ); - } - - return result; - } - - public Solid BrepToNative(Brep brep, out List notes) - { - //Make sure face references are calculated by revit - notes = new List(); - var bRepType = BRepType.OpenShell; - switch (brep.Orientation) - { - case BrepOrientation.Inward: - bRepType = BRepType.Void; - break; - case BrepOrientation.Outward: - bRepType = BRepType.Solid; - break; - } - - var materialId = RenderMaterialToNative(brep["renderMaterial"] as RenderMaterial); - using var builder = new BRepBuilder(bRepType); - - builder.SetAllowShortEdges(); - builder.AllowRemovalOfProblematicFaces(); - var brepEdges = new List[brep.Edges.Count]; - foreach (var face in brep.Faces) - { - try - { - var faceId = builder.AddFace(SurfaceToNative(face.Surface), face.OrientationReversed); - builder.SetFaceMaterialId(faceId, materialId); - - foreach (var loop in face.Loops) - { - try - { - var loopId = builder.AddLoop(faceId); - if (face.OrientationReversed) - loop.TrimIndices.Reverse(); - - foreach (var trim in loop.Trims) - { - try - { - if ( - trim.TrimType != BrepTrimType.Boundary - && trim.TrimType != BrepTrimType.Mated - && trim.TrimType != BrepTrimType.Seam - ) - continue; - if (trim.Edge == null) - continue; - - var edgeIds = brepEdges[trim.EdgeIndex]; - if (edgeIds == null) - { - // First time we see this edge, convert it and add - edgeIds = brepEdges[trim.EdgeIndex] = new List(); - var bRepBuilderGeometryIds = BrepEdgeToNative(trim.Edge).Select(edge => builder.AddEdge(edge)); - edgeIds.AddRange(bRepBuilderGeometryIds); - } - - var trimReversed = face.OrientationReversed ? !trim.IsReversed : trim.IsReversed; - if (trimReversed) - { - for (int e = edgeIds.Count - 1; e >= 0; --e) - if (builder.IsValidEdgeId(edgeIds[e])) - builder.AddCoEdge(loopId, edgeIds[e], true); - } - else - { - for (int e = 0; e < edgeIds.Count; ++e) - if (builder.IsValidEdgeId(edgeIds[e])) - builder.AddCoEdge(loopId, edgeIds[e], false); - } - } - catch (Exception e) - { - notes.Add( - $"Failed to create trim {loop.Trims.IndexOf(trim)} on loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}: {e.Message}" - ); - throw new SpeckleException( - $"Failed to create trim {loop.Trims.IndexOf(trim)} on loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" - ); - } - } - builder.FinishLoop(loopId); - } - catch (Exception e) - { - notes.Add(e.Message); - if (e is SpeckleException) - throw; - throw new SpeckleException( - $"Failed to create loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" - ); - } - } - builder.FinishFace(faceId); - } - catch (Exception e) - { - builder.Dispose(); - notes.Add(e.Message); - if (e is SpeckleException) - throw; - throw new SpeckleException( - $"Failed to create face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" - ); - } - } - - var bRepBuilderOutcome = builder.Finish(); - if (bRepBuilderOutcome == BRepBuilderOutcome.Failure) - return null; - - var isResultAvailable = builder.IsResultAvailable(); - if (!isResultAvailable) - return null; - var result = builder.GetResult(); - builder.Dispose(); - return result; - } - - public Brep BrepToSpeckle(Solid solid, Document d, string units = null) - { -#if REVIT2020 - - throw new Speckle.Core.Logging.SpeckleException("Converting BREPs to Speckle is currently only supported in Revit 2021 and above."); -#else - // TODO: Incomplete implementation!! - var u = units ?? ModelUnits; - var brep = new Brep(); - brep.units = u; - - if (solid is null || solid.Faces.IsEmpty) - return null; - - var faceIndex = 0; - var edgeIndex = 0; - var curve2dIndex = 0; - var curve3dIndex = 0; - var loopIndex = 0; - var trimIndex = 0; - var surfaceIndex = 0; - - var speckleFaces = new Dictionary(); - var speckleEdges = new Dictionary(); - var speckleEdgeIndexes = new Dictionary(); - var speckle3dCurves = new ICurve[solid.Edges.Size]; - var speckle2dCurves = new List(); - var speckleLoops = new List(); - var speckleTrims = new List(); - - foreach (var face in solid.Faces.Cast()) - { - var surface = FaceToSpeckle(face, d, out bool orientation, 0.0); - var iterator = face.EdgeLoops.ForwardIterator(); - var loopIndices = new List(); - - while (iterator.MoveNext()) - { - var loop = iterator.Current as EdgeArray; - var loopTrimIndices = new List(); - // Loop through the edges in the loop. - var loopIterator = loop.ForwardIterator(); - while (loopIterator.MoveNext()) - { - // Each edge should create a 2d curve, a 3d curve, a BrepTrim and a BrepEdge. - var edge = loopIterator.Current as Edge; - var faceA = edge.GetFace(0); - - // Determine what face side are we currently on. - var edgeSide = face == faceA ? 0 : 1; - - // Get curve, create trim and save index - var trim = edge.GetCurveUV(edgeSide); - var sTrim = new BrepTrim( - brep, - edgeIndex, - faceIndex, - loopIndex, - curve2dIndex, - 0, - BrepTrimType.Boundary, - edge.IsFlippedOnFace(edgeSide), - -1, - -1 - ); - var sTrimIndex = trimIndex; - loopTrimIndices.Add(sTrimIndex); - - // Add curve and trim, increase index counters. - speckle2dCurves.Add(CurveToSpeckle(trim.As3DCurveInXYPlane(), d, Units.None)); - speckleTrims.Add(sTrim); - curve2dIndex++; - trimIndex++; - - // Check if we have visited this edge before. - if (!speckleEdges.ContainsKey(edge)) - { - // First time we visit this edge, add 3d curve and create new BrepEdge. - var edgeCurve = edge.AsCurve(); - speckle3dCurves[curve3dIndex] = CurveToSpeckle(edgeCurve, d, u); - var sCurveIndex = curve3dIndex; - curve3dIndex++; - - // Create a trim with just one of the trimIndices set, the second one will be set on the opposite condition. - var sEdge = new BrepEdge( - brep, - sCurveIndex, - new[] { sTrimIndex }, - -1, - -1, - edge.IsFlippedOnFace(face), - null - ); - speckleEdges.Add(edge, sEdge); - speckleEdgeIndexes.Add(edge, edgeIndex); - edgeIndex++; - } - else - { - // Already visited this edge, skip curve 3d - var sEdge = speckleEdges[edge]; - var sEdgeIndex = speckleEdgeIndexes[edge]; - sTrim.EdgeIndex = sEdgeIndex; - - // Update trim indices with new item. - // TODO: Make this better. - var trimIndices = sEdge.TrimIndices.ToList(); - trimIndices.Append(sTrimIndex); //TODO Append is a pure function and the return is unused - sEdge.TrimIndices = trimIndices.ToArray(); - } - } - - var speckleLoop = new BrepLoop(brep, faceIndex, loopTrimIndices, BrepLoopType.Outer); - speckleLoops.Add(speckleLoop); - var sLoopIndex = loopIndex; - loopIndex++; - loopIndices.Add(sLoopIndex); - } - - speckleFaces.Add( - face, - new BrepFace(brep, surfaceIndex, loopIndices, loopIndices[0], !face.OrientationMatchesSurfaceOrientation) - ); - faceIndex++; - brep.Surfaces.Add(surface); - surfaceIndex++; - } - - // TODO: Revit has no brep vertices. Must call 'brep.SetVertices()' in rhino when provenance is revit. - // TODO: Set tolerances and flags in rhino when provenance is revit. - brep.Faces = speckleFaces.Values.ToList(); - brep.Curve2D = speckle2dCurves; - brep.Curve3D = speckle3dCurves.ToList(); - brep.Trims = speckleTrims; - brep.Edges = speckleEdges.Values.ToList(); - brep.Loops = speckleLoops; - brep.displayValue = ConvertSolidsByRenderMaterial(new[] { solid }, d); - return brep; - -#endif - } - - public Surface FaceToSpeckle( - DB.Face face, - Document doc, - out bool parametricOrientation, - double relativeTolerance = 0.0, - string units = null - ) - { - var u = units ?? ModelUnits; - using (var surface = face.GetSurface()) - parametricOrientation = surface.OrientationMatchesParametricOrientation; - - switch (face) - { - case null: - return null; - case PlanarFace planar: - return FaceToSpeckle(planar, relativeTolerance, u); - case ConicalFace conical: - return FaceToSpeckle(conical, relativeTolerance, u); - case CylindricalFace cylindrical: - return FaceToSpeckle(cylindrical, relativeTolerance, u); - case RevolvedFace revolved: - return FaceToSpeckle(revolved, relativeTolerance, u); - case RuledFace ruled: - return FaceToSpeckle(ruled, relativeTolerance, u); - case HermiteFace hermite: - return FaceToSpeckle(hermite, face.GetBoundingBox(), doc, u); - default: - throw new NotImplementedException(); - } - } - - public Surface FaceToSpeckle(PlanarFace planarFace, double tolerance, string units = null) - { - throw new NotImplementedException(); - } - - public Surface FaceToSpeckle(ConicalFace conicalFace, double tolerance, string units = null) - { - throw new NotImplementedException(); - } - - public Surface FaceToSpeckle(CylindricalFace cylindricalFace, double tolerance, string units = null) - { - throw new NotImplementedException(); - } - - public Surface FaceToSpeckle(RevolvedFace revolvedFace, double tolerance, string units = null) - { - throw new NotImplementedException(); - } - - public Surface FaceToSpeckle(RuledFace ruledFace, double tolerance, string units = null) - { - throw new NotImplementedException(); - } - - public int AddSurface( - Brep brep, - DB.Face face, - out List[] shells, - Dictionary brepEdges = null - ) - { - throw new NotImplementedException(); - } - - public void TrimSurface(Brep brep, int surface, bool orientationReversed, List[] shells) - { - // TODO: Incomplete method. - foreach (var shell in shells) - { - //var sFace = new BrepFace(brep,surface,null,null,orientationReversed); - - foreach (var loop in shell) - { - var brepLoop = 0; - var edgeCount = loop.edges.Count; - - for (int e = 0; e < edgeCount; ++e) - { - var brepEdge = loop.edges[e]; - var orientation = loop.orientation[e]; - if (orientation == 0) - continue; - - if (loop.trims.segments[e] is Curve trim) - { - brep.Curve2D.Add(trim); - // TODO: Missing stuff here! - } - } - } - } - throw new NotImplementedException(); - } - - public struct BrepBoundary - { - public BrepLoopType type; - public List edges; - public Polycurve trims; - public List orientation; - } - - public DirectShape BrepToDirectShape( - Brep brep, - out List notes, - BuiltInCategory cat = BuiltInCategory.OST_GenericModel - ) - { - var revitDs = DirectShape.CreateElement(Doc, new ElementId(cat)); - notes = new List(); - try - { - var solid = BrepToNative(brep, out notes); - if (solid == null) - { - notes.Add("Solid conversion returned null"); - throw new Speckle.Core.Logging.SpeckleException("Could not convert Brep to Solid"); - } - revitDs.SetShape(new List { solid }); - } - catch (Exception e) - { - notes.Add($"Failed to convert brep, using display value meshes instead."); - var meshes = brep.displayValue.SelectMany(m => MeshToNative(m)); - revitDs.SetShape(meshes.ToArray()); - } - return revitDs; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGridLine.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGridLine.cs deleted file mode 100644 index 7b728cda71..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGridLine.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject GridLineToNative(GridLine speckleGridline) - { - var revitGrid = GetExistingElementByApplicationId(speckleGridline.applicationId) as Grid; - var appObj = new ApplicationObject(speckleGridline.id, speckleGridline.speckle_type) { applicationId = speckleGridline.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitGrid, appObj)) - return appObj; - - var curve = CurveToNative(speckleGridline.baseLine).get_Item(0); - - //try update the gridline - var isUpdate = false; - if (revitGrid != null) - { - if (revitGrid.IsCurved) - Doc.Delete(revitGrid.Id); //not sure how to modify arc grids - - else - { - //dim's magic from 1.0 - var oldStart = revitGrid.Curve.GetEndPoint(0); - var oldEnd = revitGrid.Curve.GetEndPoint(1); - - var newStart = curve.GetEndPoint(0); - var newEnd = curve.GetEndPoint(1); - - //only update if it has changed - if (!(oldStart.DistanceTo(newStart) < TOLERANCE && oldEnd.DistanceTo(newEnd) < TOLERANCE)) - { - var translate = newStart.Subtract(oldStart); - ElementTransformUtils.MoveElement(Doc, revitGrid.Id, translate); - - var currentDirection = revitGrid.Curve.GetEndPoint(0).Subtract(revitGrid.Curve.GetEndPoint(1)).Normalize(); - var newDirection = newStart.Subtract(newEnd).Normalize(); - - var angle = newDirection.AngleTo(currentDirection); - - if (angle > 0.00001) - { - var crossProd = newDirection.CrossProduct(currentDirection).Z; - ElementTransformUtils.RotateElement(Doc, revitGrid.Id, Autodesk.Revit.DB.Line.CreateUnbound(newStart, XYZ.BasisZ), crossProd < 0 ? angle : -angle); - } - - try - { - var datumLine = revitGrid.GetCurvesInView(DatumExtentType.Model, Doc.ActiveView)[0]; - var datumLineZ = datumLine.GetEndPoint(0).Z; - //note the new datum line has endpoints flipped! - revitGrid.SetCurveInView(DatumExtentType.Model, Doc.ActiveView, Line.CreateBound(new XYZ(newEnd.X, newEnd.Y, datumLineZ), new XYZ(newStart.X, newStart.Y, datumLineZ))); - } - catch (Exception e) - { - appObj.Update(logItem: $"Error setting grid endpoints: {e.Message}"); - } - isUpdate = true; - } - } - } - - //create the grid - if (revitGrid == null) - { - if (curve is Arc a) - revitGrid = Grid.Create(Doc, a); - else if (curve is Line l) - revitGrid = Grid.Create(Doc, l); - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Curve type {curve.GetType().FullName} not supported for Grid"); - return appObj; - } - } - - if (!string.IsNullOrEmpty(speckleGridline.label)) - { - var names = new FilteredElementCollector(Doc).WhereElementIsElementType().OfClass(typeof(Grid)).ToElements().Cast().ToList().Select(x => x.Name); - if (!names.Contains(speckleGridline.label)) - revitGrid.Name = speckleGridline.label; - } - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitGrid.UniqueId, convertedItem: revitGrid); - return appObj; - } - - public GridLine GridLineToSpeckle(DB.Grid revitGridLine) - { - var speckleGridline = new GridLine(); - speckleGridline.baseLine = CurveToSpeckle(revitGridLine.Curve, revitGridLine.Document); - speckleGridline.label = revitGridLine.Name; - - //speckleGridline.elementId = revitCurve.Id.ToString(); this would need a RevitGridLine element - speckleGridline.applicationId = revitGridLine.UniqueId; - speckleGridline.units = ModelUnits; - return speckleGridline; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGroup.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGroup.cs deleted file mode 100644 index 1beaa695e1..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertGroup.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Mesh = Objects.Geometry.Mesh; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public Base GroupToSpeckle(Group revitGroup) - { - var elIdsToConvert = GetHostedElementIds(revitGroup); - if (!elIdsToConvert.Any()) - return null; - - var @base = new Base(); - @base["name"] = revitGroup.Name; - @base["type"] = "group"; - @base["level"] = ConvertAndCacheLevel(revitGroup, BuiltInParameter.GROUP_LEVEL); - - - AddHostedDependentElements(revitGroup, @base, elIdsToConvert.ToList()); - return @base; - } - - private void AddHostedDependentElements(Element revitElement, Base @base, List hostedIds) - { - // loop backward through the list so you can remove elements as you go through it - for (int i = hostedIds.Count - 1; i >= 0; i--) - { - var element = Doc.GetElement(hostedIds[i]); - // if it's already part of the selection, remove this element from the list of element - // we can't prevent the other element (with same id) to be converted, like we do for hosted elements - if (ContextObjects.ContainsKey(element.UniqueId)) - hostedIds.RemoveAt(i); - // otherwise, add the elements to the ContextObjects before converting them because a group - // may contain a wall that has a window, so we still want the window to search through the contextObjects - // and recognize that it's host, the wall, is listed in there and not to convert itself - else - ContextObjects.Add(element.UniqueId, new ApplicationObject(null, null) { applicationId = element.UniqueId }); - } - - GetHostedElementsFromIds(@base, revitElement, hostedIds, out List notes); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLevel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLevel.cs deleted file mode 100644 index 75572933f2..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLevel.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public DB.Level GetExistingLevelByName(IEnumerable docLevels, string name) - { - return docLevels.FirstOrDefault(x => x.Name == name); - } - - public DB.Level GetExistingLevelByElevation(IEnumerable docLevels, double elevation) - { - return docLevels.FirstOrDefault(l => Math.Abs(l.Elevation - (double)elevation) < TOLERANCE); - } - - public DB.Level GetExistingLevelByClosestElevation(IEnumerable docLevels, double elevation, out double elevationOffset) - { - elevationOffset = 0.0; - DB.Level level = docLevels.LastOrDefault(l => (l.Elevation < elevation + TOLERANCE)) ?? docLevels.FirstOrDefault(); - - if (level != null) - elevationOffset = level.Elevation - elevation; - - return level; - } - - public DB.Level ConvertLevelToRevit(XYZ point, out ApplicationObject.State state, out double elevationOffset) - { - var elevation = ElevationFromPoint(point); - return ConvertLevelToRevit(ObjectsLevelFromElevation(elevation), false, out state, out elevationOffset); - } - - public DB.Level ConvertLevelToRevit(Curve curve, out ApplicationObject.State state, out double elevationOffset) - { - var elevation = ElevationFromCurve(curve); - return ConvertLevelToRevit(ObjectsLevelFromElevation(elevation), false, out state, out elevationOffset); - } - - public DB.Level ConvertLevelToRevit(BuiltElements.Level speckleLevel, out ApplicationObject.State state) - { - double elevationOffset = 0.0; - return ConvertLevelToRevit(speckleLevel, true, out state, out elevationOffset); - } - - /// - /// Tries to find a level by ELEVATION only, otherwise it creates it. - /// Unless it was created before and we still have its app id in memory - /// Reason for not matching levels by name instead: - /// source file has L0 @0m and L1 @4m - /// dest file has L1 @0m and L2 @4m - /// attempting to move or rename levels would just be a mess, hence, we don't do that! - /// - /// - /// - public DB.Level ConvertLevelToRevit(BuiltElements.Level speckleLevel, bool exactElevation, out ApplicationObject.State state, out double elevationOffset) - { - state = ApplicationObject.State.Unknown; - elevationOffset = 0.0; - if (speckleLevel == null) return null; - - var docLevels = new FilteredElementCollector(Doc).OfClass(typeof(DB.Level)).ToElements().Cast(); - - bool elevationMatch = true; - //level by name component - if (speckleLevel is RevitLevel speckleRevitLevel && speckleRevitLevel.referenceOnly) - { - //see: https://speckle.community/t/revit-connector-levels-and-spaces/2824/5 - elevationMatch = false; - if (GetExistingLevelByName(docLevels, speckleLevel.name) is DB.Level existingLevelWithSameName) - return existingLevelWithSameName; - } - - DB.Level revitLevel = null; - var speckleLevelElevation = ScaleToNative((double)speckleLevel.elevation, speckleLevel.units); - - //the level has been received before (via schema builder probably) - //match by appid => update level - if (GetExistingElementByApplicationId(speckleLevel.applicationId) is DB.Level existingLevelAlreadyReceived) - { - revitLevel = existingLevelAlreadyReceived; - - revitLevel.Name = speckleLevel.name; - if (Math.Abs(revitLevel.Elevation - (double)speckleLevelElevation) >= TOLERANCE) - revitLevel.Elevation = speckleLevelElevation; - - state = ApplicationObject.State.Updated; - } - //match by elevation - else if (!exactElevation && elevationMatch && (GetExistingLevelByClosestElevation(docLevels, speckleLevelElevation, out elevationOffset) is DB.Level existingLevelWithClosestElevation)) - { - revitLevel = existingLevelWithClosestElevation; - state = ApplicationObject.State.Skipped; // state should be eliminated - } - //match by elevation - else if (elevationMatch && (GetExistingLevelByElevation(docLevels, speckleLevelElevation) is DB.Level existingLevelWithSameElevation)) - { - revitLevel = existingLevelWithSameElevation; - revitLevel.Name = speckleLevel.name; - state = ApplicationObject.State.Updated; - } - - else - { - // If we don't have an existing level, create it. - revitLevel = Level.Create(Doc, (double)speckleLevelElevation); - revitLevel.Name = speckleLevel.name; - - var rl = speckleLevel as RevitLevel; - if (rl != null && rl.createView) - CreateViewPlan(speckleLevel.name, revitLevel.Id); - - state = ApplicationObject.State.Created; - } - - return revitLevel; - } - - public ApplicationObject LevelToNative(BuiltElements.Level speckleLevel) - { - var revitLevel = ConvertLevelToRevit(speckleLevel, out ApplicationObject.State state); - var appObj = new ApplicationObject(speckleLevel.id, speckleLevel.speckle_type) { applicationId = speckleLevel.applicationId }; - appObj.Update(status: state, createdId: revitLevel.UniqueId, convertedItem: revitLevel); - return appObj; - } - - public RevitLevel LevelToSpeckle(DB.Level revitLevel) - { - var speckleLevel = new RevitLevel(); - - speckleLevel.elevation = ScaleToSpeckle(revitLevel.Elevation); - speckleLevel.name = revitLevel.Name; - speckleLevel.createView = true; - - GetAllRevitParamsAndIds(speckleLevel, revitLevel); - - return speckleLevel; - } - - public ViewPlan CreateViewPlan(string name, ElementId levelId) - { - var vt = new FilteredElementCollector(Doc).OfClass(typeof(ViewFamilyType)).Where(el => ((ViewFamilyType)el).ViewFamily == ViewFamily.FloorPlan).First(); - - var view = ViewPlan.Create(Doc, vt.Id, levelId); - try - { - view.Name = name; - } - catch { } - - Report.Log($"Created ViewPlan {view.Id}"); - - return view; - } - - private Level GetLevelByName(string name) - { - var collector = new FilteredElementCollector(Doc).OfClass(typeof(DB.Level)).ToElements().Cast(); - - //match by name - var revitLevel = collector.FirstOrDefault(x => x.Name == name); - if (revitLevel != null) - return revitLevel; - - //match by id? - revitLevel = collector.FirstOrDefault(x => x.Id.ToString() == name); - if (revitLevel != null) - return revitLevel; - - Report.LogConversionError(new Exception($"Could not find level `{name}`, a default level will be used.")); - - return collector.FirstOrDefault(); - } - - private RevitLevel ConvertAndCacheLevel(DB.Element elem, BuiltInParameter bip) - { - var param = elem.get_Parameter(bip); - - if (param == null || param.StorageType != StorageType.ElementId) - return null; - - return ConvertAndCacheLevel(param.AsElementId(), elem.Document); - } - - private RevitLevel ConvertAndCacheLevel(ElementId id, Document doc) - { - var level = doc.GetElement(id) as DB.Level; - - if (level == null) return null; - if (!Levels.ContainsKey(level.Name)) - Levels[level.Name] = LevelToSpeckle(level); - - return Levels[level.Name] as RevitLevel; - } - - private double ElevationFromPoint(XYZ point) - { - var p = PointToSpeckle(point, Doc); - return p.z; - } - - private RevitLevel LevelFromElevation(double z) - { - return new RevitLevel() { elevation = z, name = "Generated Level " + z, units = ModelUnits }; - } - - private Objects.BuiltElements.Level ObjectsLevelFromElevation(double z) - { - return new Objects.BuiltElements.Level() { elevation = z, name = "Generated Level " + z, units = ModelUnits }; - } - - private RevitLevel LevelFromPoint(XYZ point) - { - return LevelFromElevation(ElevationFromPoint(point)); - } - - private double ElevationFromCurve(Curve curve) - { - var start = curve.GetEndPoint(0); - var end = curve.GetEndPoint(1); - var point = start.Z < end.Z ? start : end; // pick the lowest - return ElevationFromPoint(point); - } - - private RevitLevel LevelFromCurve(Curve curve) - { - return LevelFromElevation(ElevationFromCurve(curve)); - } - - private Level GetFirstDocLevel() - { - var docLevels = new FilteredElementCollector(Doc).OfClass(typeof(Level)).ToElements().Cast(); - return docLevels.First(); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLocation.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLocation.cs deleted file mode 100644 index 716d546b21..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertLocation.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using RevitSharedResources.Helpers; -using RevitSharedResources.Helpers.Extensions; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; -using SHC = RevitSharedResources.Helpers.Categories; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public Base LocationToSpeckle(DB.Element revitElement) - { - if ( - revitElement is DB.FamilyInstance familyInstance - && familyInstance.Location is LocationPoint lp - && ( - SHC.Column.BuiltInCategories.HasCategory(familyInstance.Category) - || familyInstance.StructuralType == StructuralType.Column - ) - ) - { - //vertical columns are point based, and the point does not reflect the actual vertical location - return TryGetColumnLocationAsCurve(familyInstance, lp); - } - - var revitLocation = revitElement.Location; - switch (revitLocation) - { - case LocationCurve locationCurve: - { - var curve = locationCurve.Curve; - - //apply revit offset as transfrom - if (revitElement is DB.Wall) - { - var offset = revitElement.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble(); - XYZ vector = new XYZ(0, 0, offset); - Transform tf = Transform.CreateTranslation(vector); - curve = curve.CreateTransformed(tf); - } - - return CurveToSpeckle(curve, revitElement.Document) as Base; - } - case LocationPoint locationPoint: - { - return PointToSpeckle(locationPoint.Point, revitElement.Document); - } - // TODO what is the correct way to handle this? - case null: - return null; - - default: - return null; - } - } - - /// - /// Tries to to get the location of a column as a Curve - /// - /// - /// - /// - private Base TryGetColumnLocationAsCurve(DB.FamilyInstance familyInstance, LocationPoint locationPoint) - { - var point = PointToSpeckle(locationPoint.Point, familyInstance.Document); - - var baseOffset = GetParamValue(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - var baseLevel = ConvertAndCacheLevel(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - var topOffset = GetParamValue(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - var topLevel = ConvertAndCacheLevel(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - - if (baseLevel == null || topLevel == null) - { - SpeckleLog.Logger.Error( - "Failed to get baseCurve from vertical column because the baseLevel or topLevel (or both) parameters were null" - ); - return point; - } - - var baseLine = new Line( - new[] { point.x, point.y, baseLevel.elevation + baseOffset, point.x, point.y, topLevel.elevation + topOffset }, - ModelUnits - ); - baseLine.length = Math.Abs(baseLine.start.z - baseLine.end.z); - - return baseLine; - } - - /// - /// Checks whether the curve is vertical or not. - /// - /// - /// - private static bool IsVertical(DB.Curve curve) - { - var diffX = Math.Abs(curve.GetEndPoint(0).X - curve.GetEndPoint(1).X); - var diffY = Math.Abs(curve.GetEndPoint(0).Y - curve.GetEndPoint(1).Y); - - if (diffX < 0.1 && diffY < 0.1) - return true; - - return false; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMEPFamilyInstance.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMEPFamilyInstance.cs deleted file mode 100644 index 5c3214117f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMEPFamilyInstance.cs +++ /dev/null @@ -1,124 +0,0 @@ -using DB = Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Autodesk.Revit.DB; -using System.Linq; -using Objects.Organization; -using System; -using System.Collections.Generic; -using Speckle.Core.Models; -using Speckle.Core.Kits; -using RevitSharedResources.Models; -using Speckle.Core.Logging; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public List FittingPartTypes { get; } = new List() - { - PartType.Elbow, - PartType.Tee, - PartType.Cross, - PartType.Transition, - PartType.Union - }; - - public RevitMEPFamilyInstance MEPFamilyInstanceToSpeckle(DB.FamilyInstance familyInstance, RevitMEPFamilyInstance existingSpeckleObject = null) - { - var speckleFi = existingSpeckleObject ?? new RevitMEPFamilyInstance(); - - var partType = GetParamValue(familyInstance.Symbol.Family, BuiltInParameter.FAMILY_CONTENT_PART_TYPE); - speckleFi.RevitPartType = partType.ToString(); - - foreach (var connector in familyInstance.MEPModel?.ConnectorManager?.Connectors?.Cast()) - { - speckleFi.Connectors.Add(ConnectorToSpeckle(connector)); - } - - using var coarseOptions = new Options() { DetailLevel = ViewDetailLevel.Coarse }; - foreach (var curve in GetCurvesFromGeom(familyInstance.get_Geometry(coarseOptions))) - { - speckleFi.Curves.Add(CurveToSpeckle(curve, familyInstance.Document)); - } - - _ = RevitInstanceToSpeckle(familyInstance, out _, null, existingInstance: speckleFi); - return speckleFi; - } - - private IEnumerable GetCurvesFromGeom(GeometryElement geometryElement) - { - foreach (var geomObj in geometryElement) - { - switch (geomObj) - { - case DB.Curve curve: - yield return curve; - break; - case DB.GeometryInstance i: - foreach (var c in GetCurvesFromGeom(i.GetInstanceGeometry())) - { - yield return c; - } - break; - } - } - } - - public DB.FamilyInstance MEPFamilyInstanceToNative(RevitMEPFamilyInstance speckleFi, ApplicationObject appObj) - { - _ = RevitInstanceToNative(speckleFi, appObj); - var revitFi = (DB.FamilyInstance)appObj.Converted.First(); - - - CreateSystemConnections(speckleFi.Connectors, revitFi, receivedObjectsCache); - - return revitFi; - } - - public ApplicationObject FittingOrMEPInstanceToNative(RevitMEPFamilyInstance speckleFi) - { - var appObj = new ApplicationObject(speckleFi.id, speckleFi.speckle_type) { applicationId = speckleFi.applicationId }; - - if (Enum.TryParse(speckleFi.RevitPartType, out var partType) - && FittingPartTypes.Contains(partType)) - { - try - { - _ = FittingToNative(speckleFi, partType, appObj); - return appObj; - } - catch (ConversionNotReadyException) - { - var notReadyData = revitDocumentAggregateCache - .TryGetCacheOfType()? - .TryGet(speckleFi.id); - - if (notReadyData == null - || !notReadyData.HasValue - || notReadyData.Value.NumberOfTimesCaught < 2) - { - throw; - } - else - { - SpeckleLog.Logger.Error("Could not create fitting as part of the system. Reason: Speckle object of type RevitMEPFamilyInstance was waiting for an object to convert that never did. Converting as independent instance instead"); - appObj.Update(logItem: $"Could not create fitting as part of the system. Reason: Speckle object of type {speckleFi.GetType()} was waiting for an object to convert that never did. Converting as independent instance instead"); - _ = MEPFamilyInstanceToNative(speckleFi, appObj); - return appObj; - } - } - catch (Exception ex) - { - appObj.Update(logItem: $"Could not create fitting as part of the system. Reason: {ex.Message}. Converting as independent instance instead"); - _ = MEPFamilyInstanceToNative(speckleFi, appObj); - return appObj; - } - } - else - { - _ = MEPFamilyInstanceToNative(speckleFi, appObj); - return appObj; - } - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterial.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterial.cs deleted file mode 100644 index 68e96b88df..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterial.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Autodesk.Revit.DB.Structure; -using Speckle.Core.Kits; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public Objects.Other.Material MaterialToSpeckle(DB.Material revitmaterial) - { - var speckleMaterial = new Objects.Other.Revit.RevitMaterial(revitmaterial.Name, revitmaterial.MaterialCategory, revitmaterial.MaterialClass, revitmaterial.Shininess, - revitmaterial.Smoothness, revitmaterial.Transparency); - - GetAllRevitParamsAndIds(speckleMaterial, revitmaterial); - - Report.Log($"Converted Material{revitmaterial.Id}"); - return speckleMaterial; - } - - - - private Objects.Other.Material ConvertAndCacheMaterial(DB.ElementId id, DB.Document doc) - { - var material = doc.GetElement(id) as DB.Material; - - if (material == null) return null; - if (!Materials.ContainsKey(material.Name)) - { - Materials[material.Name] = MaterialToSpeckle(material); - } - return Materials[material.Name] as Objects.Other.Material; - } - } - -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs deleted file mode 100644 index c2df744013..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMaterialQuantities.cs +++ /dev/null @@ -1,162 +0,0 @@ -#nullable enable -using Autodesk.Revit.DB; -using ConverterRevitShared.Extensions; -using Objects.Other; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - /// - /// Material Quantities in Revit are stored in different ways and therefore need to be retrieved - /// using different methods. According to this forum post https://forums.autodesk.com/t5/revit-api-forum/method-getmaterialarea-appears-to-use-different-formulas-for/td-p/11988215 - /// "Hosts" (whatever that means) will return the area of a single side of the object while other - /// objects will return the combined area of every side of the element. Certain MEP element materials - /// are attached to the MEP system that the element belongs to. - /// - /// - /// - /// - public IEnumerable MaterialQuantitiesToSpeckle(DB.Element element, string units) - { - if (MaterialAreaAPICallWillReportSingleFace(element)) - { - return GetMaterialQuantitiesFromAPICall(element, units); - } - else if (MaterialIsAttachedToMEPSystem(element)) - { - MaterialQuantity quantity = GetMaterialQuantityForMEPElement(element, units); - return quantity == null ? Enumerable.Empty() : new List() { quantity }; - } - else - { - return GetMaterialQuantitiesFromSolids(element, units); - } - } - - private IEnumerable GetMaterialQuantitiesFromAPICall(DB.Element element, string units) - { - foreach (ElementId matId in element.GetMaterialIds(false)) - { - double volume = element.GetMaterialVolume(matId); - double area = element.GetMaterialArea(matId, false); - yield return CreateMaterialQuantity(element, matId, area, volume, units); - } - } - - private MaterialQuantity? GetMaterialQuantityForMEPElement(DB.Element element, string units) - { - DB.Material material = GetMEPSystemRevitMaterial(element); - if (material == null) - { - return null; - } - - DB.Options options = new() { DetailLevel = ViewDetailLevel.Fine }; - var (solids, _) = GetSolidsAndMeshesFromElement(element, options); - - (double area, double volume) = GetAreaAndVolumeFromSolids(solids); - return CreateMaterialQuantity(element, material.Id, area, volume, units); - } - - private IEnumerable GetMaterialQuantitiesFromSolids(DB.Element element, string units) - { - DB.Options options = new() { DetailLevel = ViewDetailLevel.Fine }; - var (solids, _) = GetSolidsAndMeshesFromElement(element, options); - - foreach (ElementId matId in GetMaterialsFromSolids(solids)) - { - (double area, double volume) = GetAreaAndVolumeFromSolids(solids, matId); - yield return CreateMaterialQuantity(element, matId, area, volume, units); - } - } - - private MaterialQuantity CreateMaterialQuantity( - Element element, - ElementId materialId, - double areaRevitInternalUnits, - double volumeRevitInternalUnits, - string units) - { - Other.Material speckleMaterial = ConvertAndCacheMaterial(materialId, element.Document); - double factor = ScaleToSpeckle(1); - double area = factor * factor * areaRevitInternalUnits; - double volume = factor * factor * factor * volumeRevitInternalUnits; - MaterialQuantity materialQuantity = new(speckleMaterial, volume, area, units); - - switch (element) - { - case DB.Architecture.Railing railing: - materialQuantity["length"] = railing.GetPath().Sum(e => e.Length) * factor; - break; - - case DB.Architecture.ContinuousRail continuousRail: - materialQuantity["length"] = continuousRail.GetPath().Sum(e => e.Length) * factor; - break; - - default: - if (LocationToSpeckle(element) is ICurve curve) - { - materialQuantity["length"] = curve.length; - } - break; - }; - - return materialQuantity; - } - - private (double, double) GetAreaAndVolumeFromSolids(List solids, ElementId? materialId = null) - { - if (materialId != null) - { - solids = solids - .Where( - solid => solid.Volume > 0 - && !solid.Faces.IsEmpty - && solid.Faces.get_Item(0).MaterialElementId == materialId) - .ToList(); - } - - double volume = solids.Sum(solid => solid.Volume); - IEnumerable areaOfLargestFaceInEachSolid = solids - .Select(solid => solid.Faces.Cast().Select(face => face.Area) - .Max()); - double area = areaOfLargestFaceInEachSolid.Sum(); - return (area, volume); - } - - private IEnumerable GetMaterialsFromSolids(List solids) - { - return solids - .Where(solid => solid.Volume > 0 && !solid.Faces.IsEmpty) - .Select(m => m.Faces.get_Item(0).MaterialElementId) - .Distinct(); - } - - private bool MaterialAreaAPICallWillReportSingleFace(Element element) - { - return element switch - { - DB.CeilingAndFloor - or DB.Wall - or DB.RoofBase => true, - _ => false - }; - } - - private bool MaterialIsAttachedToMEPSystem(Element element) - { - return element switch - { - DB.Mechanical.Duct - or DB.Mechanical.FlexDuct - or DB.Plumbing.Pipe - or DB.Plumbing.FlexPipe => true, - _ => false - }; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMeshUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMeshUtils.cs deleted file mode 100644 index 7e1c6a40a3..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertMeshUtils.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Collections.Generic; -using Autodesk.Revit.DB; -using Speckle.Core.Logging; -using DB = Autodesk.Revit.DB; -using Mesh = Objects.Geometry.Mesh; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public Options ViewSpecificOptions { get; set; } - - /// - /// We're caching a dictionary of graphic styles and their ids as it can be a costly operation doing Document.GetElement(solid.GraphicsStyleId) for every solid - /// - private Dictionary _graphicStyleCache = new Dictionary(); - - /// - /// Retreives the meshes on an element to use as the speckle displayvalue - /// - /// - /// Some FamilyInstance elements are treated as proper Instance objects, while others are not. For those being converted as Instance objects, retrieve their display value untransformed by the instance transform or by the selected document reference point. - /// - /// - /// See https://www.revitapidocs.com/2023/e0f15010-0e19-6216-e2f0-ab7978145daa.htm for a full Geometry Object inheritance - /// - public List GetElementDisplayValue( - DB.Element element, - Options options = null, - bool isConvertedAsInstance = false, - DB.Transform transform = null - ) - { - var displayMeshes = new List(); - - // test if the element is a group first - if (element is Group g) - { - foreach (var id in g.GetMemberIds()) - { - var groupMeshes = GetElementDisplayValue( - element.Document.GetElement(id), - options, - isConvertedAsInstance - ); - displayMeshes.AddRange(groupMeshes); - } - return displayMeshes; - } - - var (solids, meshes) = GetSolidsAndMeshesFromElement(element, options, transform); - - // convert meshes and solids - displayMeshes.AddRange(ConvertMeshesByRenderMaterial(meshes, element.Document, isConvertedAsInstance)); - displayMeshes.AddRange(ConvertSolidsByRenderMaterial(solids, element.Document, isConvertedAsInstance)); - - return displayMeshes; - } - - public (List, List) GetSolidsAndMeshesFromElement( - Element element, - Options options, - Transform? transform = null - ) - { - options = ViewSpecificOptions ?? options ?? new Options() { DetailLevel = DetailLevelSetting }; - - GeometryElement geom; - try - { - geom = element.get_Geometry(options); - } - catch (Autodesk.Revit.Exceptions.ArgumentException) - { - options.ComputeReferences = false; - geom = element.get_Geometry(options); - } - - var solids = new List(); - var meshes = new List(); - - if (geom != null) - { - // retrieves all meshes and solids from a geometry element - SortGeometry(element, solids, meshes, geom, transform?.Inverse); - } - - return (solids, meshes); - } - - private static void LogInstanceMeshRetrievalWarnings( - Element element, - int topLevelSolidsCount, - int topLevelMeshesCount, - int topLevelGeomElementCount, - int topLevelGeomInstanceCount, - bool hasSymbolGeom - ) - { - if (hasSymbolGeom) - { - if (topLevelSolidsCount > 0) - { - SpeckleLog.Logger.Warning("Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numSolids} top level solids. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", element.GetType(), element.UniqueId, topLevelSolidsCount); - } - if (topLevelMeshesCount > 0) - { - SpeckleLog.Logger.Warning("Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numMeshes} top level meshes. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", element.GetType(), element.UniqueId, topLevelMeshesCount); - } - if (topLevelGeomElementCount > 0) - { - SpeckleLog.Logger.Warning("Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numGeomElements} top level geometry elements. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", element.GetType(), element.UniqueId, topLevelGeomElementCount); - } - } - } - - /// - /// According to the remarks on the GeometryInstance class in the RevitAPIDocs, - /// https://www.revitapidocs.com/2024/fe25b14f-5866-ca0f-a660-c157484c3a56.htm, - /// a family instance geometryElement should have a top-level geometry instance when the symbol - /// does not have modified geometry (the docs say that modified geometry will not have a geom instance, - /// however in my experience, all family instances have a top-level geom instance, but if the family instance - /// is modified, then the geom instance won't contain any geometry.) - /// - /// This remark also leads me to think that a family instance will not have top-level solids and geom instances. - /// We are logging cases where this is not true. - /// - /// - /// - /// - /// - void SortGeometry( - Element element, - List solids, - List meshes, - GeometryElement geom, - Transform inverseTransform = null - ) - { - var topLevelSolidsCount = 0; - var topLevelMeshesCount = 0; - var topLevelGeomElementCount = 0; - var topLevelGeomInstanceCount = 0; - bool hasSymbolGeometry = false; - - foreach (GeometryObject geomObj in geom) - { - switch (geomObj) - { - case Solid solid: - // skip invalid solid - if (solid.Faces.Size == 0 - || Math.Abs(solid.SurfaceArea) == 0 - || IsSkippableGraphicStyle(solid.GraphicsStyleId, element.Document)) - { - continue; - } - - if (inverseTransform != null) - { - topLevelSolidsCount++; - solid = SolidUtils.CreateTransformed(solid, inverseTransform); - } - - solids.Add(solid); - break; - case DB.Mesh mesh: - if (IsSkippableGraphicStyle(mesh.GraphicsStyleId, element.Document)) continue; - - if (inverseTransform != null) - { - topLevelMeshesCount++; - mesh = mesh.get_Transformed(inverseTransform); - } - - meshes.Add(mesh); - break; - case GeometryInstance instance: - // element transforms should not be carried down into nested geometryInstances. - // Nested geomInstances should have their geom retreived with GetInstanceGeom, not GetSymbolGeom - if (inverseTransform != null) - { - topLevelGeomInstanceCount++; - SortGeometry(element, solids, meshes, instance.GetSymbolGeometry()); - if (meshes.Count > 0 || solids.Count > 0) - { - hasSymbolGeometry = true; - } - } - else - { - SortGeometry(element, solids, meshes, instance.GetInstanceGeometry()); - } - break; - case GeometryElement geometryElement: - if (inverseTransform != null) - { - topLevelGeomElementCount++; - } - SortGeometry(element, solids, meshes, geometryElement); - break; - } - } - - if (inverseTransform != null) - { - LogInstanceMeshRetrievalWarnings( - element, - topLevelSolidsCount, - topLevelMeshesCount, - topLevelGeomElementCount, - topLevelGeomInstanceCount, - hasSymbolGeometry); - } - } - - /// - /// Exclude light source cones and potentially other geometries by their graphic style - /// - /// - /// - /// - private bool IsSkippableGraphicStyle(ElementId id, Document doc) - { - if (!_graphicStyleCache.ContainsKey(id.ToString())) - _graphicStyleCache.Add(id.ToString(), doc.GetElement(id) as GraphicsStyle); - var graphicStyle = _graphicStyleCache[id.ToString()]; - - if ( - graphicStyle != null - && graphicStyle.GraphicsStyleCategory.Id.IntegerValue == (int)(BuiltInCategory.OST_LightingFixtureSource) - ) - return true; - return false; - } - - /// - /// Given a collection of , will create one per distinct - /// - /// - /// - /// - private List ConvertMeshesByRenderMaterial( - List meshes, - Document d, - bool doNotTransformWithReferencePoint = false - ) - { - MeshBuildHelper buildHelper = new MeshBuildHelper(); - - foreach (var mesh in meshes) - { - var revitMaterial = d.GetElement(mesh.MaterialElementId) as DB.Material; - Mesh speckleMesh = buildHelper.GetOrCreateMesh(revitMaterial, ModelUnits); - ConvertMeshData(mesh, speckleMesh.faces, speckleMesh.vertices, d, doNotTransformWithReferencePoint); - } - - return buildHelper.GetAllValidMeshes(); - } - - /// - /// Given a collection of , will create one per distinct - /// - /// - /// - /// - private List ConvertSolidsByRenderMaterial( - IEnumerable solids, - Document d, - bool doNotTransformWithReferencePoint = false - ) - { - MeshBuildHelper meshBuildHelper = new MeshBuildHelper(); - - var MeshMap = new Dictionary>(); - foreach (Solid solid in solids) - { - foreach (Face face in solid.Faces) - { - DB.Material faceMaterial = d.GetElement(face.MaterialElementId) as DB.Material; - Mesh m = meshBuildHelper.GetOrCreateMesh(faceMaterial, ModelUnits); - if (!MeshMap.ContainsKey(m)) - { - MeshMap.Add(m, new List()); - } - MeshMap[m].Add(face.Triangulate()); - } - } - - foreach (var meshData in MeshMap) - { - //It's cheaper to resize lists manually, since we would otherwise be resizing a lot! - int numberOfVertices = 0; - int numberOfFaces = 0; - foreach (DB.Mesh mesh in meshData.Value) - { - if (mesh == null) - continue; - numberOfVertices += mesh.Vertices.Count * 3; - numberOfFaces += mesh.NumTriangles * 4; - } - - meshData.Key.faces.Capacity = numberOfFaces; - meshData.Key.vertices.Capacity = numberOfVertices; - foreach (DB.Mesh mesh in meshData.Value) - { - if (mesh == null) - continue; - ConvertMeshData(mesh, meshData.Key.faces, meshData.Key.vertices, d, doNotTransformWithReferencePoint); - } - } - - return meshBuildHelper.GetAllValidMeshes(); - } - - /// - /// Given , will convert and add triangle data to and - /// - /// The revit mesh to convert - /// The faces list to add to - /// The vertices list to add to - private void ConvertMeshData( - DB.Mesh mesh, - List faces, - List vertices, - Document doc, - bool doNotTransformWithReferencePoint = false - ) - { - int faceIndexOffset = vertices.Count / 3; - - foreach (var vert in mesh.Vertices) - { - var (x, y, z) = PointToSpeckle(vert, doc, null, doNotTransformWithReferencePoint); - vertices.Add(x); - vertices.Add(y); - vertices.Add(z); - } - - for (int i = 0; i < mesh.NumTriangles; i++) - { - var triangle = mesh.get_Triangle(i); - - faces.Add(3); // TRIANGLE flag - faces.Add((int)triangle.get_Index(0) + faceIndexOffset); - faces.Add((int)triangle.get_Index(1) + faceIndexOffset); - faces.Add((int)triangle.get_Index(2) + faceIndexOffset); - } - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertModel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertModel.cs deleted file mode 100644 index a7ecfca3b3..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertModel.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Generic; -using Objects.Geometry; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Transform = Objects.Other.Transform; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - /// - /// Returns a object containing and location - /// information. This is intended to be used as the root commit object when sending to Speckle. - /// - /// the currently active document - /// true if project info should be added - /// - public Base ModelToSpeckle(DB.Document doc, bool sendProjectInfo = true) - { - var model = new Collection("Revit model", "model"); - // TODO: setting for whether or not to include project info - if (sendProjectInfo) - { - var info = ProjectInfoToSpeckle(doc.ProjectInformation); - info.latitude = doc.SiteLocation.Latitude; - info.longitude = doc.SiteLocation.Longitude; - info.siteName = doc.SiteLocation.PlaceName; - info.locations = ProjectLocationsToSpeckle(doc); - model["info"] = info; - } - - Report.Log($"Created Model Object"); - - return model; - } - - /// - /// Converts the Revit document's into a list of bases including the , - /// name, and true north angle (in radians) - /// - /// - /// - public List ProjectLocationsToSpeckle(DB.Document doc) - { - var locations = doc.ProjectLocations; - // TODO: do we need a location obj? - var spcklLocations = new List(); - foreach (DB.ProjectLocation location in locations) - { - var position = location.GetProjectPosition(DB.XYZ.Zero); - var revitTransform = DB.Transform.CreateRotation(DB.XYZ.BasisZ, position.Angle); - - var spcklLoc = new Base() { applicationId = location.UniqueId }; - var basisX = VectorToSpeckle(revitTransform.BasisX, doc); - var basisY = VectorToSpeckle(revitTransform.BasisY, doc); - var basisZ = VectorToSpeckle(revitTransform.BasisZ, doc); - var translation = new Vector( - ScaleToSpeckle(position.EastWest), - ScaleToSpeckle(position.NorthSouth), - ScaleToSpeckle(position.Elevation), - ModelUnits - ); - spcklLoc["transform"] = new Transform(basisX, basisY, basisZ, translation); - spcklLoc["name"] = location.Name; - spcklLoc["trueNorth"] = position.Angle; - spcklLocations.Add(spcklLoc); - } - - return spcklLocations; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertNetwork.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertNetwork.cs deleted file mode 100644 index 094337ae4a..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertNetwork.cs +++ /dev/null @@ -1,489 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Electrical; -using Autodesk.Revit.DB.Mechanical; -using Autodesk.Revit.DB.Plumbing; -using ConverterRevitShared.Revit; -using Objects.BuiltElements.Revit; -using Speckle.Core.Credentials; -using Speckle.Core.Models; -using Speckle.Newtonsoft.Json.Linq; -using DB = Autodesk.Revit.DB; -using Network = Objects.BuiltElements.Network; -using NetworkElement = Objects.BuiltElements.NetworkElement; -using NetworkLink = Objects.BuiltElements.NetworkLink; -using RevitNetworkElement = Objects.BuiltElements.Revit.RevitNetworkElement; -using RevitNetworkLink = Objects.BuiltElements.Revit.RevitNetworkLink; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject NetworkToNative(Network speckleNetwork) - { - var appObj = new ApplicationObject(speckleNetwork.id, speckleNetwork.speckle_type) { applicationId = speckleNetwork.applicationId }; - - speckleNetwork.elements.ForEach(e => e.network = speckleNetwork); - speckleNetwork.links.ForEach(l => l.network = speckleNetwork); - - // convert all the MEP trades and family instances except fittings - - var convertedElements = new Dictionary(); - var elements = speckleNetwork.elements.Cast().ToList(); - var notConnectorBasedCreationElements = elements.Where(e => !e.isConnectorBased).ToArray(); - foreach (var networkElement in notConnectorBasedCreationElements) - { - var element = networkElement.elements; - if (CanConvertToNative(element)) - { - var convAppObj = ConvertToNative(element) as ApplicationObject; - foreach (var obj in convAppObj.Converted) - { - var nativeElement = obj as Element; - appObj.Update(status: ApplicationObject.State.Created, createdId: nativeElement.UniqueId, convertedItem: nativeElement); - } - convertedElements.Add(networkElement.applicationId, convAppObj.Converted.First() as Element); - } - else - { - appObj.Update(status: ApplicationObject.State.Skipped, logItem: $"Receiving this object type is not supported in Revit"); - } - } - - // convert connector based creation elements, We use different way to create curve fittings such as elbow, - // transition, tee, union, cross then other family instances since creation are based on connectors, two, - // three or four depends on type of fitting. - - var connectorBasedCreationElements = elements.Where(e => e.isConnectorBased).ToArray(); - var convertedMEPCurves = convertedElements.Where(e => e.Value is MEPCurve).ToArray(); - foreach (var networkElement in connectorBasedCreationElements) - { - var familySymbol = GetElementType(networkElement.elements, appObj, out bool _); - if (familySymbol == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - continue; - } - - DB.FamilyInstance familyInstance = null; - - var tempCurves = new Dictionary(); - - foreach (var link in networkElement.links) - { - if (link is RevitNetworkLink revitLink && revitLink.needsPlaceholders) - { - var curve = CreateCurve(revitLink); - tempCurves.Add(revitLink.fittingIndex, curve); - } - } - - var connections = networkElement.links.Cast().ToDictionary( - l => l, - l => l.elements - .Cast() - .FirstOrDefault(e => e.applicationId != networkElement.applicationId - && e.isCurveBased)); - - var connection1 = connections.FirstOrDefault(c => c.Key.fittingIndex == 1); - var connection2 = connections.FirstOrDefault(c => c.Key.fittingIndex == 2); - var connection3 = connections.FirstOrDefault(c => c.Key.fittingIndex == 3); - var connection4 = connections.FirstOrDefault(c => c.Key.fittingIndex == 4); - - var element1 = connection1.Value != null ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection1.Value.applicationId).Value : tempCurves.FirstOrDefault(t => t.Key == 1).Value; - var element2 = connection2.Value != null ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection2.Value.applicationId).Value : tempCurves.FirstOrDefault(t => t.Key == 2).Value; - var element3 = connection3.Value != null ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection3.Value.applicationId).Value : tempCurves.FirstOrDefault(t => t.Key == 3).Value; - var element4 = connection4.Value != null ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection4.Value.applicationId).Value : tempCurves.FirstOrDefault(t => t.Key == 4).Value; - - var connector1 = element1 != null ? GetConnectorByPoint(element1, PointToNative(connection1.Key.origin)) : null; - var connector2 = element2 != null ? GetConnectorByPoint(element2, PointToNative(connection2.Key.origin)) : null; - var connector3 = element3 != null ? GetConnectorByPoint(element3, PointToNative(connection3.Key.origin)) : null; - var connector4 = element4 != null ? GetConnectorByPoint(element4, PointToNative(connection4.Key.origin)) : null; - - var partType = networkElement.elements["partType"] as string ?? "Unknown"; - if (partType.Contains("Elbow") && connector1 != null && connector2 != null) - familyInstance = Doc.Create.NewElbowFitting(connector1, connector2); - else if (partType.Contains("Transition") && connector1 != null && connector2 != null) - familyInstance = Doc.Create.NewTransitionFitting(connector1, connector2); - else if (partType.Contains("Union") && connector1 != null && connector2 != null) - familyInstance = Doc.Create.NewUnionFitting(connector1, connector2); - else if (partType.Contains("Tee") && connector1 != null && connector2 != null && connector3 != null) - familyInstance = Doc.Create.NewTeeFitting(connector1, connector2, connector3); - else if (partType.Contains("Cross") && connector1 != null && connector2 != null && connector3 != null && connector4 != null) - familyInstance = Doc.Create.NewCrossFitting(connector1, connector2, connector3, connector4); - else - { - var convAppObj = ConvertToNative(networkElement.elements) as ApplicationObject; - foreach (var obj in convAppObj.Converted) - { - var nativeElement = obj as Element; - appObj.Update(status: ApplicationObject.State.Created, createdId: nativeElement.UniqueId, convertedItem: nativeElement); - } - } - - if (familyInstance != null) - { - convertedElements.Add(networkElement.applicationId, familyInstance); - familyInstance?.ChangeTypeId(familySymbol.Id); - Doc.Delete(tempCurves.Select(c => c.Value.Id).ToList()); - - appObj.Update(status: ApplicationObject.State.Created, createdId: familyInstance.UniqueId, convertedItem: familyInstance); - } - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Family instance was null"); - } - } - - // check if all the elements are connected, some connectors may be unconnected - // due using of temp curves and until all the ones are created no way to connect - // them between each other - - var links = speckleNetwork.links.Cast().ToArray(); - foreach (var link in links) - { - if (link.isConnected && link.elements.Count == 2) - { - var firstElement = convertedElements.FirstOrDefault(e => e.Key == link.elements[0].applicationId).Value; - var secondElement = convertedElements.FirstOrDefault(e => e.Key == link.elements[1].applicationId).Value; - var origin = PointToNative(link.origin); - var firstConnector = GetConnectorByPoint(firstElement, origin); - var secondConnector = GetConnectorByPoint(secondElement, origin); - if (firstConnector != null - && secondConnector != null - && !firstConnector.IsConnected - && !secondConnector.IsConnected) - { - firstConnector.ConnectTo(secondConnector); - } - } - } - - return appObj; - } - - public Network NetworkToSpeckle(Element mepElement, out List notes) - { - Network speckleNetwork = new Network() { name = mepElement.Name, elements = new List(), links = new List() }; - - GetNetworkElements(speckleNetwork, mepElement, out notes); - - return speckleNetwork; - } - - /// - /// Gets the connected element of a MEP element and adds the to a Base object - /// - /// - /// - private void GetNetworkElements(Network @network, Element initialElement, out List notes) - { - CachedContextObjects = ContextObjects; - notes = new List(); - var networkConnections = new List(); - GetNetworkConnections(initialElement, ref networkConnections); - var groups = networkConnections.GroupBy(n => n.Owner.UniqueId).ToList(); - - foreach (var group in groups) - { - var element = Doc.GetElement(group.Key); - - if (ContextObjects.ContainsKey(element.UniqueId)) - ContextObjects.Remove(element.UniqueId); - else - continue; - - ApplicationObject reportObj = Report.ReportObjects.ContainsKey(element.UniqueId) ? Report.ReportObjects[element.UniqueId] : new ApplicationObject(element.UniqueId, element.GetType().ToString()); - - Base obj = null; - bool connectorBasedCreation = false; - switch (element) - { - case DB.FamilyInstance fi: - obj = FamilyInstanceToSpeckle(fi, out notes); - // test if this family instance is a fitting - var fittingCategories = new List { BuiltInCategory.OST_PipeFitting, BuiltInCategory.OST_DuctFitting, BuiltInCategory.OST_CableTrayFitting, BuiltInCategory.OST_ConduitFitting }; - if (fittingCategories.Any(c => (int)c == fi.Category.Id.IntegerValue)) - { - connectorBasedCreation = IsConnectorBasedCreation(fi); - var partType = (PartType)fi.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE).AsInteger(); - if (obj != null) obj["partType"] = partType.ToString(); - } - break; - case DB.Plumbing.Pipe pipe: - obj = PipeToSpeckle(pipe); - break; - case DB.Plumbing.FlexPipe flexpipe: - obj = PipeToSpeckle(flexpipe); - break; - case DB.Mechanical.Duct duct: - obj = DuctToSpeckle(duct, out notes); - break; - case DB.Mechanical.FlexDuct flexDuct: - obj = DuctToSpeckle(flexDuct); - break; - case DB.Electrical.CableTray cableTray: - obj = CableTrayToSpeckle(cableTray); - break; - case DB.Electrical.Conduit conduit: - obj = ConduitToSpeckle(conduit); - break; - default: - reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"Conversion not supported"); - Report.Log(reportObj); - continue; - } - - if (obj == null) - { - reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); - Report.Log(reportObj); - continue; - } - - reportObj.Update(status: ApplicationObject.State.Created, logItem: $"Attached as connected element to {initialElement.UniqueId}"); - @network.elements.Add(new RevitNetworkElement() - { - applicationId = element.UniqueId, - name = element.Name, - elements = obj, - linkIndices = new List(), - isConnectorBased = connectorBasedCreation, - isCurveBased = element is MEPCurve - }); - ConvertedObjects.Add(obj.applicationId); - - Report.Log(reportObj); - } - - foreach (var group in groups) - { - var connections = group.ToList(); - var ownerIndex = @network.elements.FindIndex(e => e.applicationId.Equals(group.Key)); - var ownerElement = @network.elements[ownerIndex]; - foreach (var connection in connections) - { - var link = new RevitNetworkLink() { name = connection.Name, network = @network, elementIndices = new List() }; - - link.elementIndices.Add(ownerIndex); - - var connector = connection.Connector; - - link.domain = connector.Domain.ToString(); - link.shape = connector.Shape.ToString(); - link.systemName = connector.Owner.Category.Name; - link.systemType = connector.MEPSystem != null ? Doc.GetElement(connector.MEPSystem.GetTypeId()).Name : ""; - - var origin = connection.Connector.Origin; - - link.origin = PointToSpeckle(origin, initialElement.Document); - link.fittingIndex = connector.Id; - link.direction = VectorToSpeckle(connector.CoordinateSystem.BasisZ, initialElement.Document); - link.isConnected = connection.IsConnected; - link.needsPlaceholders = connection.ConnectedToCurve(out MEPCurve curve) && IsWithinContext(curve); - link.diameter = connection.Diameter; - link.height = connection.Height; - link.width = connection.Width; - - // find index of the ref element - var refConnector = connection.RefConnector; - var refIndex = @network.elements.FindIndex(e => e.applicationId.Equals(refConnector?.Owner?.UniqueId)); - - // add it in case it exists - if (refIndex != -1) - link.elementIndices.Add(refIndex); - - @network.links.Add(link); - var linkIndex = @network.links.IndexOf(link); - ownerElement.linkIndices.Add(linkIndex); - } - } - - if (@network.elements.Any()) - notes.Add($"Converted and attached {@network.elements.Count} connected elements"); - } - - private void GetNetworkConnections(Element element, ref List networkConnections) - { - var connectionPairs = ConnectionPair.GetConnectionPairs(element); - foreach (var connectionPair in connectionPairs) - { - if (!networkConnections.Contains(connectionPair)) - { - networkConnections.Add(connectionPair); - var refElement = connectionPair.RefConnector?.Owner; - if (connectionPair.IsConnected && IsWithinContext(refElement)) - GetNetworkConnections(refElement, ref networkConnections); - } - } - } - - // for fitting family instances, retrieves the type of fitting and determines if it is connector based - private bool IsConnectorBasedCreation(DB.FamilyInstance familyInstance) - { - var connectors = GetConnectors(familyInstance).Cast().ToArray(); - return connectors.All(c => connectors.All(c1 => - (c1.Domain == Domain.DomainPiping && c1.PipeSystemType == c.PipeSystemType) || - (c1.Domain == Domain.DomainHvac && c1.DuctSystemType == c.DuctSystemType) || - (c1.Domain == Domain.DomainElectrical && c1.ElectricalSystemType == c.ElectricalSystemType) || - (c1.Domain == Domain.DomainCableTrayConduit))); - } - - private static Dictionary CachedContextObjects = null; - - private bool IsWithinContext(Element element) - { - return CachedContextObjects.ContainsKey(element?.UniqueId); - } - - private void GetConnectionPairs(Element element, ref List> connectionPairs, ref List elements) - { - var refss = ConnectionPair.GetConnectionPairs(element); - - foreach (var r in refss) - { - var isValid = r.IsValid(); - var isConnected = r.IsConnected; - } - var refs = GetRefConnectionPairs(element); - var refConnectionPairs = GetRefConnectionPairs(element). - Where(e => e.Item2 == null || ContextObjects.ContainsKey(e.Item2.Owner.UniqueId)).ToList(); - elements.Add(element); - foreach (var refConnectionPair in refs) - { - var connectedElement = refConnectionPair.Item2?.Owner; - if (connectedElement != null - && !elements.Any(e => e.UniqueId.Equals(connectedElement.UniqueId)) - && ContextObjects.ContainsKey(connectedElement.UniqueId)) - { - connectionPairs.Add(Tuple.Create(refConnectionPair.Item1, refConnectionPair.Item2, element)); - GetConnectionPairs(connectedElement, ref connectionPairs, ref elements); - } - else - { - connectionPairs.Add(Tuple.Create(refConnectionPair.Item1, null, element)); - } - } - } - - private static List> GetRefConnectionPairs(Element element) - { - var refConnectionPairs = new List>(); - var connectors = GetConnectors(element); - var connectorsIterator = connectors.ForwardIterator(); - connectorsIterator.Reset(); - while (connectorsIterator.MoveNext()) - { - var connector = connectorsIterator.Current as Connector; - if (connector != null && connector.IsConnected) - { - var refs = connector.AllRefs; - var refsIterator = refs.ForwardIterator(); - refsIterator.Reset(); - while (refsIterator.MoveNext()) - { - var refConnector = refsIterator.Current as Connector; - if (refConnector != null && !refConnector.Owner.Id.Equals(element.Id) && !(refConnector.Owner is MEPSystem)) - refConnectionPairs.Add(Tuple.Create(connector, refConnector)); - } - } - else - { - refConnectionPairs.Add(Tuple.Create(connector, null)); - } - } - return refConnectionPairs; - } - - private static ConnectorSet GetConnectors(Element e) - { - return e is MEPCurve curve ? - curve.ConnectorManager.Connectors : - (e as DB.FamilyInstance)?.MEPModel?.ConnectorManager?.Connectors ?? new ConnectorSet(); - } - - private Connector GetConnectorByPoint(Element element, XYZ point) - { - switch (element) - { - case MEPCurve o: - return o.ConnectorManager.Connectors.Cast().FirstOrDefault(c => c.Origin.IsAlmostEqualTo(point, 0.00001)); - case DB.FamilyInstance o: - return o.MEPModel?.ConnectorManager.Connectors.Cast().FirstOrDefault(c => c.Origin.IsAlmostEqualTo(point, 0.00001)); - default: - return null; - } - } - - private MEPCurve CreateCurve(RevitNetworkLink link) - { - var direction = VectorToNative(link.direction); - var start = PointToNative(link.origin); - var end = start.Add(direction.Multiply(2)); - - var sfi = link.elements.FirstOrDefault(e => e.elements is BuiltElements.Revit.FamilyInstance)?.elements as BuiltElements.Revit.FamilyInstance; - Level level = ConvertLevelToRevit(sfi.level, out ApplicationObject.State state); - - Domain domain = Enum.TryParse(link.domain, out domain) ? domain : Domain.DomainUndefined; - ConnectorProfileType profile = Enum.TryParse(link.shape, out profile) ? profile : ConnectorProfileType.Invalid; - - MEPCurveType curveType = null; - MEPCurve curve = null; - switch (domain) - { - case Domain.DomainHvac: - curveType = GetDefaultMEPCurveType(Doc, typeof(DuctType), profile); - if (curveType == null) goto default; - var mechanicalSystemType = new FilteredElementCollector(Doc).WhereElementIsElementType().OfClass(typeof(MechanicalSystemType)).ToElements().Cast().FirstOrDefault(x => x.Name == link.systemType); - curve = Duct.Create(Doc, mechanicalSystemType.Id, curveType.Id, level.Id, start, end); - if (curveType.Shape == ConnectorProfileType.Round) - { - curve.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).Set(link.diameter); - } - else - { - curve.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(link.width); - curve.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(link.height); - } - break; - case Domain.DomainPiping: - curveType = GetDefaultMEPCurveType(Doc, typeof(PipeType), profile); - if (curveType == null) goto default; - var pipingSystemType = new FilteredElementCollector(Doc).WhereElementIsElementType().OfClass(typeof(PipingSystemType)).ToElements().Cast().FirstOrDefault(x => x.Name == link.systemType); - curve = Pipe.Create(Doc, pipingSystemType.Id, curveType.Id, level.Id, start, end); - curve.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(link.diameter); - break; - case Domain.DomainCableTrayConduit: - if (profile == ConnectorProfileType.Rectangular) - { - curveType = GetDefaultMEPCurveType(Doc, typeof(CableTrayType), profile); - if (curveType == null) goto default; - curve = CableTray.Create(Doc, curveType.Id, start, end, level.Id); - curve.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(link.width); - curve.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(link.height); - } - else - { - curveType = GetDefaultMEPCurveType(Doc, typeof(ConduitType), profile); - if (curveType == null) goto default; - curve = Conduit.Create(Doc, curveType.Id, start, end, level.Id); - curve.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).Set(link.diameter); - } - break; - default: - return curve; - } - return curve; - } - - private static MEPCurveType GetDefaultMEPCurveType(Document doc, Type type, ConnectorProfileType shape) - { - return new FilteredElementCollector(doc) - .WhereElementIsElementType() - .OfClass(type) - .FirstOrDefault(t => t is MEPCurveType type && type.Shape == shape) as MEPCurveType; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertOpening.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertOpening.cs deleted file mode 100644 index 616afdbdbf..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertOpening.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject OpeningToNative(BuiltElements.Opening speckleOpening) - { - var baseCurves = CurveToNative(speckleOpening.outline); - - var docObj = GetExistingElementByApplicationId(speckleOpening.applicationId); - var appObj = new ApplicationObject(speckleOpening.id, speckleOpening.speckle_type) { applicationId = speckleOpening.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - if (docObj != null) - Doc.Delete(docObj.Id); - - Opening revitOpening = null; - - switch (speckleOpening) - { - case RevitWallOpening rwo: - { - // Prevent host element overriding as this will propagate upwards to other hosted elements in a wall :) - string elementId = null; - var hostElement = CurrentHostElement; - if (!(hostElement is Wall)) - { - // Try with the opening wall if it exists - if (rwo.host == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Host wall was null"); - return appObj; - } - Element existingElement; - try - { - existingElement = GetExistingElementByApplicationId(rwo.host.applicationId); - } - catch (Exception e) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not find the host wall: {e.Message}"); - return appObj; - } - - if (!(existingElement is Wall wall)) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"The host is not a wall"); - return appObj; - } - - hostElement = wall; - } - - var poly = rwo.outline as Polyline; - if (poly == null || !((poly.GetPoints().Count == 5 && poly.closed) || (poly.GetPoints().Count == 4 && !poly.closed))) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Curve outline for wall opening must be a rectangle-shaped polyline"); - return appObj; - } - - var points = poly.GetPoints().Select(PointToNative).ToList(); - revitOpening = Doc.Create.NewOpening((Wall)hostElement, points[0], points[2]); - break; - } - - case RevitVerticalOpening rvo: - { - if (CurrentHostElement == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Hosted vertical openings require a host family"); - return appObj; - } - revitOpening = Doc.Create.NewOpening(CurrentHostElement, baseCurves, true); - break; - } - - case RevitShaft rs: - { - var bottomLevel = ConvertLevelToRevit(rs.bottomLevel, out ApplicationObject.State bottomState); - var topLevel = ConvertLevelToRevit(rs.topLevel, out ApplicationObject.State topState); - revitOpening = Doc.Create.NewOpening(bottomLevel, topLevel, baseCurves); - TrySetParam(revitOpening, BuiltInParameter.WALL_USER_HEIGHT_PARAM, rs.height, rs.units); - - break; - } - - default: - if (CurrentHostElement as Wall != null) - { - var speckleOpeningOutline = speckleOpening.outline as Polyline; - if (speckleOpeningOutline == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Outline must be a rectangle-shaped polyline"); - return appObj; - } - var points = speckleOpeningOutline.GetPoints().Select(PointToNative).ToList(); - revitOpening = Doc.Create.NewOpening(CurrentHostElement as Wall, points[0], points[2]); - } - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Opening type not supported"); - return appObj; - } - break; - } - - if (speckleOpening is RevitOpening ro) - SetInstanceParameters(revitOpening, ro); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitOpening.UniqueId, convertedItem: revitOpening); - return appObj; - } - - public BuiltElements.Opening OpeningToSpeckle(DB.Opening revitOpening) - { - RevitOpening speckleOpening; - if (revitOpening.IsRectBoundary) - { - speckleOpening = new RevitWallOpening(); - - var poly = new Polyline(); - poly.value = new List(); - - //2 points: bottom left and top right - var btmLeft = PointToSpeckle(revitOpening.BoundaryRect[0], revitOpening.Document); - var topRight = PointToSpeckle(revitOpening.BoundaryRect[1], revitOpening.Document); - poly.value.AddRange(btmLeft.ToList()); - poly.value.AddRange(new Point(btmLeft.x, btmLeft.y, topRight.z, ModelUnits).ToList()); - poly.value.AddRange(topRight.ToList()); - poly.value.AddRange(new Point(topRight.x, topRight.y, btmLeft.z, ModelUnits).ToList()); - - poly.value.AddRange(btmLeft.ToList()); - // setting closed to true because we added the first point again. - poly.closed = true; - poly.units = ModelUnits; - speckleOpening.outline = poly; - } - else - { - if (revitOpening.Host != null) - { - //we can ignore vertical openings because they will be created when we try re-create voids in the roof / ceiling / floor outline - return null; - } - else - { - var shaftOpening = new RevitShaft(); - speckleOpening = shaftOpening; - if (revitOpening.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE) != null) - { - shaftOpening.topLevel = ConvertAndCacheLevel(revitOpening, BuiltInParameter.WALL_HEIGHT_TYPE); - shaftOpening.bottomLevel = ConvertAndCacheLevel(revitOpening, BuiltInParameter.WALL_BASE_CONSTRAINT); - shaftOpening.height = GetParamValue(revitOpening, BuiltInParameter.WALL_USER_HEIGHT_PARAM); - } - } - - var poly = new Polycurve(ModelUnits); - poly.segments = new List(); - foreach (DB.Curve curve in revitOpening.BoundaryCurves) - if (curve != null) - poly.segments.Add(CurveToSpeckle(curve, revitOpening.Document)); - - speckleOpening.outline = poly; - } - - speckleOpening["type"] = revitOpening.Name; - - GetAllRevitParamsAndIds(speckleOpening, revitOpening, - new List { "WALL_BASE_CONSTRAINT", "WALL_HEIGHT_TYPE", "WALL_USER_HEIGHT_PARAM" }); - return speckleOpening; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPanel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPanel.cs deleted file mode 100644 index bd12e0a2e2..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPanel.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject PanelToNative(RevitCurtainWallPanel specklePanel) - { - return new ApplicationObject(specklePanel.id, specklePanel.speckle_type) - { - Status = ApplicationObject.State.Skipped, - Log = new List() { "Revit does not support receive standalone curtain panels " } - }; - } - - public RevitCurtainWallPanel PanelToSpeckle(DB.Panel revitPanel) - { - RevitCurtainWallPanel panel = new(); - return (RevitCurtainWallPanel)RevitElementToSpeckle(revitPanel, out _, panel); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPipe.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPipe.cs deleted file mode 100644 index 741cbabd5f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPipe.cs +++ /dev/null @@ -1,236 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Plumbing; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using Curve = Objects.Geometry.Curve; -using DB = Autodesk.Revit.DB; -using Line = Objects.Geometry.Line; -using Polyline = Objects.Geometry.Polyline; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject PipeToNative(BuiltElements.Pipe specklePipe) - { - var speckleRevitPipe = specklePipe as RevitPipe; - - // check to see if pipe already exists in the doc - Element docObj = GetExistingElementByApplicationId(specklePipe.applicationId); - var appObj = new ApplicationObject(specklePipe.id, specklePipe.speckle_type) { applicationId = specklePipe.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - { - return appObj; - } - - // get system info - MEPCurveType pipeType = GetElementType(specklePipe, appObj, out bool _); - if (pipeType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - List systemTypes = new FilteredElementCollector(Doc).WhereElementIsElementType() - .OfClass(typeof(DB.Plumbing.PipingSystemType)).ToElements().Cast().ToList(); - var systemFamily = speckleRevitPipe?.systemType ?? ""; - ElementType system = systemTypes.FirstOrDefault(x => x.Name == speckleRevitPipe?.systemName) ?? - systemTypes.FirstOrDefault(x => x.Name == systemFamily); - if (system == null) - { - system = systemTypes.FirstOrDefault(); - appObj.Update(logItem: $"Pipe type {systemFamily} not found; replaced with {system.Name}"); - } - - Element pipe = null; - var levelState = ApplicationObject.State.Unknown; - switch (specklePipe.baseCurve) - { - case Line line: - DB.Line baseLine = LineToNative(line); - DB.Level level = ConvertLevelToRevit(speckleRevitPipe != null ? speckleRevitPipe.level : LevelFromCurve(baseLine), out levelState); - var linePipe = DB.Plumbing.Pipe.Create(Doc, system.Id, pipeType.Id, level.Id, baseLine.GetEndPoint(0), baseLine.GetEndPoint(1)); - if (docObj != null) - { - var lineSystem = linePipe.MEPSystem.Id; - linePipe = (DB.Plumbing.Pipe)docObj; - linePipe.SetSystemType(lineSystem); - ((LocationCurve)linePipe.Location).Curve = baseLine; - } - - pipe = linePipe; - break; - case Polyline _: - case Curve _: - var speckleRevitFlexPipe = specklePipe as RevitFlexPipe; - DB.Plumbing.FlexPipeType flexPipeType = null; - if (speckleRevitFlexPipe != null) - { - flexPipeType = GetElementType(speckleRevitFlexPipe, appObj, out bool _); - } - else - { - flexPipeType = GetElementType(specklePipe, appObj, out bool _); - } - - if (flexPipeType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - // get points - Polyline basePoly = specklePipe.baseCurve as Polyline; - if (specklePipe.baseCurve is Curve curve) - { - basePoly = curve.displayValue; - DB.Curve baseCurve = CurveToNative(curve); - XYZ start = baseCurve.GetEndPoint(0); - XYZ end = baseCurve.GetEndPoint(1); - } - - if (basePoly == null) - { - break; - } - - var polyPoints = basePoly.GetPoints().Select(o => PointToNative(o)).ToList(); - - // get tangents if they exist - XYZ startTangent = (speckleRevitFlexPipe != null) ? VectorToNative(speckleRevitFlexPipe.startTangent) : null; - XYZ endTangent = (speckleRevitFlexPipe != null) ? VectorToNative(speckleRevitFlexPipe.endTangent) : null; - - // get level - DB.Level flexPolyLevel = ConvertLevelToRevit(speckleRevitFlexPipe != null ? speckleRevitFlexPipe.level : LevelFromPoint(polyPoints.First()), out levelState); - - FlexPipe flexPolyPipe = (startTangent != null && endTangent != null) ? - DB.Plumbing.FlexPipe.Create(Doc, system.Id, flexPipeType.Id, flexPolyLevel.Id, startTangent, endTangent, polyPoints) : - DB.Plumbing.FlexPipe.Create(Doc, system.Id, flexPipeType.Id, flexPolyLevel.Id, polyPoints); - - // deleting instead of updating for now! - if (docObj != null) - { - Doc.Delete(docObj.Id); - } - - pipe = flexPolyPipe; - break; - default: - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Curve of type {specklePipe.baseCurve.GetType()} cannot be used to create a Revit Pipe"); - return appObj; - } - - if (speckleRevitPipe != null) - { - SetInstanceParameters(pipe, speckleRevitPipe); - CreateSystemConnections(speckleRevitPipe.Connectors, pipe, receivedObjectsCache); - } - - TrySetParam(pipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM, specklePipe.diameter, specklePipe.units); - - appObj.Update(status: ApplicationObject.State.Created, createdId: pipe.UniqueId, convertedItem: pipe); - return appObj; - } - - public BuiltElements.Pipe PipeToSpeckle(DB.Plumbing.Pipe revitPipe) - { - // geometry - var baseGeometry = LocationToSpeckle(revitPipe); - if (!(baseGeometry is Line baseLine)) - throw new Speckle.Core.Logging.SpeckleException("Only line based Pipes are currently supported."); - - // speckle pipe - var specklePipe = new RevitPipe - { - baseCurve = baseLine, - family = revitPipe.PipeType.FamilyName, - type = revitPipe.PipeType.Name, - systemName = revitPipe.MEPSystem.Name, - systemType = GetParamValue(revitPipe, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM), - diameter = GetParamValue(revitPipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM), - length = GetParamValue(revitPipe, BuiltInParameter.CURVE_ELEM_LENGTH), - level = ConvertAndCacheLevel(revitPipe, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitPipe) - }; - - var material = ConverterRevit.GetMEPSystemMaterial(revitPipe); - if (material != null) - foreach (var mesh in specklePipe.displayValue) - mesh["renderMaterial"] = material; - - GetAllRevitParamsAndIds(specklePipe, revitPipe, new List - { - "RBS_PIPING_SYSTEM_TYPE_PARAM", - "RBS_SYSTEM_CLASSIFICATION_PARAM", - "RBS_SYSTEM_NAME_PARAM", - "RBS_PIPE_DIAMETER_PARAM", - "CURVE_ELEM_LENGTH", - "RBS_START_LEVEL_PARAM", - "RBS_CURVE_HOR_OFFSET_PARAM", - "RBS_CURVE_VERT_OFFSET_PARAM", - "RBS_PIPE_BOTTOM_ELEVATION", - "RBS_PIPE_TOP_ELEVATION" - }); - - foreach (var connector in revitPipe.GetConnectorSet()) - { - specklePipe.Connectors.Add(ConnectorToSpeckle(connector)); - } - - return specklePipe; - } - public BuiltElements.Pipe PipeToSpeckle(DB.Plumbing.FlexPipe revitPipe) - { - // create polyline from revitpipe points - var polyline = new Polyline(); - polyline.value = PointsToFlatList(revitPipe.Points.Select(o => PointToSpeckle(o, revitPipe.Document))); - polyline.units = ModelUnits; - polyline.closed = false; - - // speckle pipe - var specklePipe = new RevitFlexPipe - { - baseCurve = polyline, - family = revitPipe.FlexPipeType.FamilyName, - type = revitPipe.FlexPipeType.Name, - systemName = revitPipe.MEPSystem.Name, - systemType = GetParamValue(revitPipe, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM), - diameter = GetParamValue(revitPipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM), - length = GetParamValue(revitPipe, BuiltInParameter.CURVE_ELEM_LENGTH), - startTangent = VectorToSpeckle(revitPipe.StartTangent, revitPipe.Document), - endTangent = VectorToSpeckle(revitPipe.EndTangent, revitPipe.Document), - level = ConvertAndCacheLevel(revitPipe, BuiltInParameter.RBS_START_LEVEL_PARAM), - displayValue = GetElementDisplayValue(revitPipe) - }; - - var material = ConverterRevit.GetMEPSystemMaterial(revitPipe); - - if (material != null) - foreach (var mesh in specklePipe.displayValue) - mesh["renderMaterial"] = material; - - GetAllRevitParamsAndIds(specklePipe, revitPipe, new List - { - "RBS_SYSTEM_CLASSIFICATION_PARAM", - "RBS_PIPING_SYSTEM_TYPE_PARAM", - "RBS_SYSTEM_NAME_PARAM", - "RBS_PIPE_DIAMETER_PARAM", - "CURVE_ELEM_LENGTH", - "RBS_START_LEVEL_PARAM", - }); - - foreach (var connector in revitPipe.GetConnectorSet()) - { - specklePipe.Connectors.Add(ConnectorToSpeckle(connector)); - } - - return specklePipe; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPolygonElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPolygonElement.cs deleted file mode 100644 index 1c4eee4844..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertPolygonElement.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Objects.GIS; -using Speckle.Core.Models; -using Speckle.Core.Models.GraphTraversal; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject PolygonElementToNative(PolygonElement polygonElement) - { - var speckleDirectShape = new Objects.BuiltElements.Revit.DirectShape() - { - applicationId = polygonElement.applicationId ??= Guid.NewGuid().ToString(), - baseGeometries = new List(), - parameters = new Base(), - name = "", - category = RevitCategory.GenericModel - }; - - var traversal = new GraphTraversal(DefaultTraversal.DefaultRule); - var meshes = traversal - .Traverse(polygonElement) - .Select(tc => tc.current) - .Where(b => b is Mesh); - - speckleDirectShape.baseGeometries.AddRange(meshes); - - foreach (var kvp in polygonElement.attributes.GetMembers()) - { - speckleDirectShape.parameters[kvp.Key] = new Objects.BuiltElements.Revit.Parameter() - { - name = kvp.Key, - value = kvp.Value - }; - } - - return DirectShapeToNative(speckleDirectShape, ToNativeMeshSettingEnum.Default); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProfileWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProfileWall.cs deleted file mode 100644 index de38dbea02..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProfileWall.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject ProfileWallToNative(RevitProfileWall speckleRevitWall) - { - var revitWall = GetExistingElementByApplicationId(speckleRevitWall.applicationId) as DB.Wall; - var appObj = new ApplicationObject(speckleRevitWall.id, speckleRevitWall.speckle_type) { applicationId = speckleRevitWall.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitWall, appObj)) - return appObj; - - if (speckleRevitWall.profile == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Does not have a profile."); - return appObj; - } - - var wallType = GetElementType(speckleRevitWall, appObj, out bool _); - if (wallType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - // Level level = null; - var structural = speckleRevitWall.structural; - var profile = new List(); - var minZ = double.MaxValue; - for (var i = 0; i < CurveToNative(speckleRevitWall.profile).Size; i++) - { - var curve = CurveToNative(speckleRevitWall.profile).get_Item(i); - profile.Add(curve); - if (curve.GetEndPoint(0).Z < minZ) - minZ = curve.GetEndPoint(0).Z; - if (curve.GetEndPoint(1).Z < minZ) - minZ = curve.GetEndPoint(1).Z; - } - - //cannot update - if (revitWall != null) - Doc.Delete(revitWall.Id); - - revitWall = DB.Wall.Create(Doc, profile, structural); - - if (revitWall == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Wall creation returned null"); - return appObj; - } - - var level = ConvertLevelToRevit(speckleRevitWall.level, out ApplicationObject.State levelState); - TrySetParam(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT, level); - - var offset = minZ - level.Elevation; - TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, offset); - - if (revitWall.WallType.Name != wallType.Name) - revitWall.ChangeTypeId(wallType.Id); - - SetInstanceParameters(revitWall, speckleRevitWall); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); - //appObj = SetHostedElements(speckleRevitWall, revitWall, appObj); - return appObj; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProjectInfo.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProjectInfo.cs deleted file mode 100644 index 905e6961be..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertProjectInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ - -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Speckle.Core.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB; -using ProjectInfo = Objects.BuiltElements.Revit.ProjectInfo; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private ProjectInfo ProjectInfoToSpeckle(DB.ProjectInfo revitInfo) - { - var speckleInfo = new ProjectInfo - { - address = revitInfo.Address, - author = revitInfo.Author, - buildingName = revitInfo.BuildingName, - clientName = revitInfo.ClientName, - issueDate = revitInfo.IssueDate, - name = revitInfo.Name, - number = revitInfo.Number, - organizationDescription = revitInfo.OrganizationDescription, - organizationName = revitInfo.OrganizationName, - status = revitInfo.Status - }; - Report.Log($"Converted ProjectInfo"); - return speckleInfo; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRailing.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRailing.cs deleted file mode 100644 index 338f9c39a1..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRailing.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Architecture; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject RailingToNative(BuiltElements.Revit.RevitRailing speckleRailing) - { - var revitRailing = GetExistingElementByApplicationId(speckleRailing.applicationId) as Railing; - var appObj = new ApplicationObject(speckleRailing.id, speckleRailing.speckle_type) { applicationId = speckleRailing.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitRailing, appObj)) - return appObj; - - if (speckleRailing.path == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Path was null"); - return appObj; - } - - var railingType = GetElementType(speckleRailing, appObj, out bool isExactMatch); - if (railingType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - Level level = ConvertLevelToRevit(speckleRailing.level, out ApplicationObject.State levelState); - if (level == null) //we currently don't support railings hosted on stairs, and these have null level - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Level was null"); - return appObj; - } - - var baseCurve = CurveArrayToCurveLoop(CurveToNative(speckleRailing.path)); - - //if it's a new element, we don't need to update certain properties - bool isUpdate = true; - if (revitRailing == null) - { - isUpdate = false; - revitRailing = Railing.Create(Doc, baseCurve, railingType.Id, level.Id); - } - if (revitRailing == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); - return appObj; - } - - if (isExactMatch && revitRailing.GetTypeId() != railingType.Id) - { - revitRailing.ChangeTypeId(railingType.Id); - } - - if (speckleRailing.topRail != null) - { - var topRailType = GetElementType(speckleRailing.topRail, appObj, out bool isTopRailExactMatch); - - if (GetParamValue(railingType, BuiltInParameter.RAILING_SYSTEM_HAS_TOP_RAIL) == 0) - TrySetParam(railingType, BuiltInParameter.RAILING_SYSTEM_HAS_TOP_RAIL, 1); - - if (topRailType != null && isTopRailExactMatch) - railingType.TopRailType = topRailType.Id; - - } - - - if (isUpdate) - { - revitRailing.SetPath(baseCurve); - TrySetParam(revitRailing, BuiltInParameter.WALL_BASE_CONSTRAINT, level); - } - - if (speckleRailing.flipped != revitRailing.Flipped) - revitRailing.Flip(); - - SetInstanceParameters(revitRailing, speckleRailing); - - if (speckleRailing.topRail != null) - { - // This call to regenerate is to reflect the generation - // of the TopRail element associated with the Railing element - Doc.Regenerate(); - - var revitTopRail = Doc.GetElement(revitRailing.TopRail); - - SetInstanceParameters(revitTopRail, speckleRailing.topRail); - } - - var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: status, createdId: revitRailing.UniqueId, convertedItem: revitRailing); - Doc.Regenerate(); - return appObj; - } - - //TODO: host railings, where possible - private RevitRailing RailingToSpeckle(Railing revitRailing) - { - var railingType = revitRailing.Document.GetElement(revitRailing.GetTypeId()) as RailingType; - var speckleRailing = new RevitRailing(); - //speckleRailing.family = railingType.FamilyName; - speckleRailing.type = railingType.Name; - speckleRailing.level = ConvertAndCacheLevel(revitRailing, BuiltInParameter.STAIRS_RAILING_BASE_LEVEL_PARAM); - speckleRailing.path = CurveListToSpeckle(revitRailing.GetPath(), revitRailing.Document); - - GetAllRevitParamsAndIds(speckleRailing, revitRailing, new List { "STAIRS_RAILING_BASE_LEVEL_PARAM" }); - - speckleRailing.displayValue = GetElementDisplayValue(revitRailing); - - if (revitRailing.TopRail != ElementId.InvalidElementId) - { - - if (ContextObjects.ContainsKey(revitRailing.UniqueId)) - { - ContextObjects.Remove(revitRailing.UniqueId); - } - - var revitTopRail = revitRailing.Document.GetElement(revitRailing.TopRail) as TopRail; - - if (ContextObjects.ContainsKey(revitTopRail.UniqueId)) - { - ContextObjects.Remove(revitTopRail.UniqueId); - } - - if (CanConvertToSpeckle(revitTopRail)) - { - speckleRailing.topRail = TopRailToSpeckle(revitTopRail); - - //ensure top rail mesh is visible in viewer - //currently only the top level displayValue is visualized (or anything under 'elements') - //if this leads to duplicated meshes in some cases, we might need to remove the display mesh form the TopRail element - speckleRailing.displayValue.AddRange(speckleRailing.topRail.displayValue); - ConvertedObjects.Add(speckleRailing.topRail.applicationId); - } - } - return speckleRailing; - } - - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRebar.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRebar.cs deleted file mode 100644 index d47ede0c55..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRebar.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Autodesk.Revit.Exceptions; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using Speckle.Newtonsoft.Json.Linq; -using DB = Autodesk.Revit.DB; -using Vector = Objects.Geometry.Vector; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - // rebar - public ApplicationObject RebarToNative(RevitRebarGroup speckleRebar) - { - var docObj = GetExistingElementByApplicationId(speckleRebar.applicationId); - var appObj = new ApplicationObject(speckleRebar.id, speckleRebar.speckle_type) - { - applicationId = speckleRebar.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - { - return appObj; - } - - // return failed if rebar shape is null or has no curves - var barShape = speckleRebar.shape as RevitRebarShape; - if (barShape == null || !barShape.curves.Any()) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Rebar shape is null or has no curves."); - return appObj; - } - - // return failed if no valid host - if (CurrentHostElement is null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Host element was null."); - return appObj; - } - - // get rebar type and style - var barType = GetElementType(speckleRebar, appObj, out bool isExactMatch); - if (barType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (speckleRebar.shape.rebarType == RebarType.Unknown) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: ("Unknown bar type (stirrup or standard).")); - return appObj; - } - - RebarStyle barStyle = - speckleRebar.shape.rebarType == RebarType.Standard ? RebarStyle.Standard : RebarStyle.StirrupTie; - - // get start and end hooks and orientations - var speckleStartHook = speckleRebar.startHook as RevitRebarHook; - RebarHookType startHook = null; - RebarHookOrientation startHookOrientation = RebarHookOrientation.Right; - if (speckleStartHook != null) - { - startHook = RebarHookToNative(speckleStartHook); - Enum.TryParse(speckleStartHook.orientation, out startHookOrientation); - } - - var speckleEndHook = speckleRebar.endHook as RevitRebarHook; - RebarHookType endHook = null; - RebarHookOrientation endHookOrientation = RebarHookOrientation.Right; - if (speckleEndHook != null) - { - endHook = RebarHookToNative(speckleEndHook); - Enum.TryParse(speckleEndHook.orientation, out endHookOrientation); - } - - // get the shape curves - List curves = barShape.curves.SelectMany(o => CurveToNative(o).Cast()).ToList(); - if (curves is null || !curves.Any()) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not convert any shape curves"); - return appObj; - } - - // get the rebar plane norm from the curves - XYZ normal = XYZ.BasisZ; - if (speckleRebar.normal is not null) - { - normal = VectorToNative(speckleRebar.normal); - } - - // create the rebar - DB.Structure.Rebar rebar = null; - try - { - rebar = DB.Structure.Rebar.CreateFromCurves( - Doc, - barStyle, - barType, - startHook, - endHook, - CurrentHostElement, - normal, - curves, - startHookOrientation, - endHookOrientation, - true, - true - ); - } - catch (Exception e) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: e.Message); - return appObj; - } - - SetInstanceParameters(rebar, speckleRebar); - - // set additional params - if (speckleRebar.barPositions > 0) - { - rebar.NumberOfBarPositions = speckleRebar.barPositions; - } - - // deleting instead of updating for now! - if (docObj != null) - Doc.Delete(docObj.Id); - - appObj.Update(status: ApplicationObject.State.Created, createdId: rebar.UniqueId, convertedItem: rebar); - - return appObj; - } - - private RevitRebarGroup RebarToSpeckle(DB.Structure.Rebar revitRebar) - { - // skip freeform rebar for now: not supported by RevitRebarGroup class - // this is because freeform rebar with bent workshop has multiple shapes - if (revitRebar.GetAllRebarShapeIds().Count > 1) - { - return null; - } - - // get type - var type = revitRebar.Document.GetElement(revitRebar.GetTypeId()) as ElementType; - - // get the rebar shape - // `GetShapeId()` will throw if it is a freeform rebar with a bent workshop, - // but this case should already be handled by the `GetAllRebarShapeIds().Count` test above - var revitShape = revitRebar.Document.GetElement(revitRebar.GetShapeId()) as DB.Structure.RebarShape; - RevitRebarShape speckleShape = new(); - if (revitShape != null) - { - speckleShape = RebarShapeToSpeckle(revitShape); - } - -#if REVIT2020 || REVIT2021 - speckleShape.barDiameter = revitRebar.GetBendData().BarDiameter; -#else - speckleShape.barDiameter = revitRebar.GetBendData().BarModelDiameter; -#endif - - // get the rebar hooks - DB.ElementId revitStartHookId = revitRebar.GetHookTypeId(0); - RevitRebarHook speckleStartHook = null; - double hookBendRadius = revitRebar.GetBendData().HookBendRadius; - if (revitStartHookId != ElementId.InvalidElementId) - { - var revitStartHook = revitRebar.Document.GetElement(revitStartHookId) as RebarHookType; - speckleStartHook = RebarHookToSpeckle( - revitStartHook, - revitRebar.GetHookOrientation(0).ToString(), - hookBendRadius - ); - } - - DB.ElementId revitEndHookId = revitRebar.GetHookTypeId(1); - RevitRebarHook speckleEndHook = null; - if (revitEndHookId != ElementId.InvalidElementId) - { - var revitEndHook = revitRebar.Document.GetElement(revitEndHookId) as RebarHookType; - speckleEndHook = RebarHookToSpeckle(revitEndHook, revitRebar.GetHookOrientation(1).ToString(), hookBendRadius); - } - - // get the layout rule - this determines exceptions that may be thrown by accessing invalid props - bool isSingleLayout = revitRebar.LayoutRule == RebarLayoutRule.Single; - - // get centerline curves for display value - RebarShapeDrivenAccessor accessor = null; - if (revitRebar.IsRebarShapeDriven()) - { - accessor = revitRebar.GetShapeDrivenAccessor(); - } - - // .GetCenterlineCurves() always returns the bar in the first position (even if it is excluded) for shape driven rebar groups - IList firstPositionCurves = revitRebar.GetCenterlineCurves( - true, - false, - false, - MultiplanarOption.IncludeAllMultiplanarCurves, - 0 - ); - - List centerlines = new(); - for (int i = 0; i < revitRebar.NumberOfBarPositions; i++) - { - // skip end bars that are excluded - if (!isSingleLayout) - { - if ( - !revitRebar.IncludeFirstBar && i == 0 - || !revitRebar.IncludeLastBar && i == revitRebar.NumberOfBarPositions - 1 - ) - { - continue; - } - } - - // for non-shape-driven rebar, compute the centerline at each position - if (accessor is null) - { - IList revitCurves = revitRebar.GetCenterlineCurves( - true, - false, - false, - MultiplanarOption.IncludeAllMultiplanarCurves, - i - ); - centerlines.AddRange(revitCurves.Select(o => CurveToSpeckle(o, revitRebar.Document)).ToList()); - } - // for shape-driven rebar, get the transformed first position curves at this position - else - { - var transform = accessor.GetBarPositionTransform(i); - centerlines.AddRange( - firstPositionCurves - .Select(o => CurveToSpeckle(o.CreateTransformed(transform), revitRebar.Document)) - .ToList() - ); - } - } - - // get plane normal of rebar group - // the normal prop was deprecated in revit 2018, and the accessor normal is suggested as a replacement - // unclear how non-shape-driven rebar set normals are retrieved or computed. - Vector normal = null; - if (accessor != null) - { - normal = VectorToSpeckle(accessor.Normal, revitRebar.Document); - } - - // create speckle rebar - RevitRebarGroup speckleRebar = - new() - { - shape = speckleShape, - number = revitRebar.Quantity, - startHook = speckleStartHook, - endHook = speckleEndHook, - hasFirstBar = isSingleLayout ? true : revitRebar.IncludeFirstBar, - hasLastBar = isSingleLayout ? true : revitRebar.IncludeLastBar, - volume = revitRebar.Volume, - family = type?.FamilyName, - type = type?.Name, - normal = normal, - barPositions = revitRebar.NumberOfBarPositions, - displayValue = centerlines - }; - - // skip display value as meshes for now - // GetElementDisplayValue(revitRebar, SolidDisplayValueOptions); - GetAllRevitParamsAndIds(speckleRebar, revitRebar); - - return speckleRebar; - } - - // rebar shape - private RevitRebarShape RebarShapeToSpeckle(DB.Structure.RebarShape revitRebarShape) - { - // get the type of the shape - RebarType rebarType = RebarType.Unknown; - switch (revitRebarShape.RebarStyle) - { - case RebarStyle.Standard: - rebarType = RebarType.Standard; - break; - case RebarStyle.StirrupTie: - rebarType = RebarType.StirrupPolygonal; - break; - } - - // get the curves representing the default values of the shape - List curves = revitRebarShape - .GetCurvesForBrowser() - .Select(o => CurveToSpeckle(o, revitRebarShape.Document)) - .ToList(); - - RevitRebarShape speckleRebarShape = - new() - { - name = revitRebarShape.Name, - curves = curves, - rebarType = rebarType - }; - - GetAllRevitParamsAndIds(speckleRebarShape, revitRebarShape); - - return speckleRebarShape; - } - - // rebar hook - private RebarHookType RebarHookToNative(RevitRebarHook speckleRebarHook) - { - double multiplier = - speckleRebarHook.multiplier != null && speckleRebarHook.multiplier > 0 ? speckleRebarHook.multiplier : 10; // default to 10 if invalid multiplier - var revitRebarHook = RebarHookType.Create(Doc, speckleRebarHook.angle, multiplier); - - SetInstanceParameters(revitRebarHook, speckleRebarHook); - - return revitRebarHook; - } - - private RevitRebarHook RebarHookToSpeckle(RebarHookType revitRebarHook, string orientation, double radius) - { - RevitRebarHook speckleRebarHook = - new() - { - multiplier = revitRebarHook.StraightLineMultiplier, - angle = revitRebarHook.HookAngle, - orientation = orientation, - radius = radius - }; - - GetAllRevitParamsAndIds(speckleRebarHook, revitRebarHook); - - return speckleRebarHook; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRevitElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRevitElement.cs deleted file mode 100644 index 738a852cd7..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRevitElement.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.Collections.Generic; - -using Autodesk.Revit.DB; - -using Speckle.Core.Models; - -using Objects.BuiltElements.Revit; -using RevitElementType = Objects.BuiltElements.Revit.RevitElementType; -using System.Linq; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public RevitElement RevitElementToSpeckle(Element revitElement, out List notes, RevitElement speckleElement = null) - { - notes = new List(); - var symbol = revitElement.Document.GetElement(revitElement.GetTypeId()) as FamilySymbol; - - speckleElement ??= new RevitElement(); - if (symbol != null) - { - speckleElement.family = symbol.FamilyName; - speckleElement.type = symbol.Name; - } - else - { - speckleElement.type = revitElement.Name; - } - - var baseGeometry = LocationToSpeckle(revitElement); - if (baseGeometry is Geometry.Point point) - speckleElement["basePoint"] = point; - else if (baseGeometry is Geometry.Line line) - speckleElement["baseLine"] = line; - - speckleElement.category = revitElement.Category.Name; - - GetHostedElements(speckleElement, revitElement, out notes); - - var displayValue = GetElementDisplayValue(revitElement); - - if (!displayValue.Any()) - notes.Add( - "Element does not have visible geometry. It will be sent to Speckle but won't be visible in the viewer." - ); - else - speckleElement.displayValue = displayValue; - - GetAllRevitParamsAndIds(speckleElement, revitElement); - - return speckleElement; - } - - public RevitElementType ElementTypeToSpeckle(ElementType revitType) - { - var type = revitType.Name; - var family = revitType.FamilyName; - var category = revitType.Category.Name; - RevitElementType speckleType = null; - - switch (revitType) - { - case FamilySymbol o: - var symbolType = new RevitSymbolElementType() - { - type = type, - family = family, - category = category - }; - symbolType.placementType = o.Family?.FamilyPlacementType.ToString(); - speckleType = symbolType; - break; - case MEPCurveType o: - var mepType = new RevitMepElementType() - { - type = type, - family = family, - category = category - }; - mepType.shape = o.Shape.ToString(); - speckleType = mepType; - break; - default: - speckleType = new RevitElementType() - { - type = type, - family = family, - category = category - }; - break; - } - - GetAllRevitParamsAndIds(speckleType, revitType); - - return speckleType; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoof.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoof.cs deleted file mode 100644 index 446f9aaee1..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoof.cs +++ /dev/null @@ -1,485 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Architecture; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit.RevitRoof; -using Objects.Geometry; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using FamilyInstance = Objects.BuiltElements.Revit.FamilyInstance; -using Line = Objects.Geometry.Line; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject RoofToNative(Roof speckleRoof) - { - Element docObj = GetExistingElementByApplicationId((speckleRoof).applicationId); - var appObj = new ApplicationObject(speckleRoof.id, speckleRoof.speckle_type) - { - applicationId = speckleRoof.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - { - return appObj; - } - - // outline is required for footprint roofs - // referenceLine is required for for Extrusion roofs - CurveArray roofCurve = null; - if (speckleRoof is RevitExtrusionRoof extrusionRoof) - { - if (extrusionRoof.referenceLine is null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Extrusion roof profile was null"); - return appObj; - } - roofCurve = CurveToNative(extrusionRoof.referenceLine); - } - else - { - if (speckleRoof.outline is null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Roof outline was null"); - return appObj; - } - roofCurve = CurveToNative(speckleRoof.outline); - } - - // retrieve the level - var levelState = ApplicationObject.State.Unknown; - double baseOffset = 0.0; - DB.Level level = speckleRoof.level is not null - ? ConvertLevelToRevit(speckleRoof.level, out levelState) - : roofCurve is not null - ? ConvertLevelToRevit(roofCurve.get_Item(0), out levelState, out baseOffset) - : null; - - var speckleRevitRoof = speckleRoof as RevitRoof; - - var roofType = GetElementType(speckleRoof, appObj, out bool _); - if (roofType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - if (docObj != null) - { - Doc.Delete(docObj.Id); - } - - DB.RoofBase revitRoof = null; - switch (speckleRoof) - { - case RevitExtrusionRoof speckleExtrusionRoof: - { - // get the norm - var referenceLine = LineToNative(speckleExtrusionRoof.referenceLine); - var norm = GetPerpendicular(referenceLine.GetEndPoint(0) - referenceLine.GetEndPoint(1)).Negate(); - ReferencePlane plane = Doc.Create.NewReferencePlane( - referenceLine.GetEndPoint(0), - referenceLine.GetEndPoint(1), - norm, - Doc.ActiveView - ); - - //create floor without a type with the profile - var start = ScaleToNative(speckleExtrusionRoof.start, speckleExtrusionRoof.units); - var end = ScaleToNative(speckleExtrusionRoof.end, speckleExtrusionRoof.units); - revitRoof = Doc.Create.NewExtrusionRoof(roofCurve, plane, level, roofType, start, end); - - // sometimes Revit flips the roof so the start offset is the end and vice versa. - // In that case, delete the created roof, flip the referencePlane and recreate it. - var actualStart = GetParamValue(revitRoof, BuiltInParameter.EXTRUSION_START_PARAM); - if (actualStart - speckleExtrusionRoof.end < TOLERANCE) - { - Doc.Delete(revitRoof.Id); - plane.Flip(); - revitRoof = Doc.Create.NewExtrusionRoof(roofCurve, plane, level, roofType, start, end); - } - break; - } - case RevitFootprintRoof speckleFootprintRoof: - { - ModelCurveArray curveArray = new ModelCurveArray(); - var revitFootprintRoof = Doc.Create.NewFootPrintRoof(roofCurve, level, roofType, out curveArray); - - // if the roof is a curtain roof then set the mullions at the borders - var nestedElements = speckleFootprintRoof.elements; - if (revitFootprintRoof.CurtainGrids != null && nestedElements is not null && nestedElements.Count != 0) - { - // TODO: Create a new type instead of overriding the type. This could affect other elements - var param = roofType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER1_GRID1); - var type = Doc.GetElement(param.AsElementId()); - if (type == null) - { - // assuming first mullion is the desired mullion for the whole roof... - var mullionType = GetElementType( - nestedElements.First(b => b is FamilyInstance f), - appObj, - out bool _ - ); - if (mullionType != null) - { - TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER1_GRID1, mullionType); - TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER1_GRID2, mullionType); - TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER2_GRID1, mullionType); - TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER2_GRID2, mullionType); - } - } - } - var poly = speckleFootprintRoof.outline as Polycurve; - bool hasSlopedSide = false; - if (poly != null) - { - for (var i = 0; i < curveArray.Size; i++) - { - var isSloped = ((Base)poly.segments[i])["isSloped"] as bool?; - var slopeAngle = ((Base)poly.segments[i])["slopeAngle"] as double?; - var offset = ((Base)poly.segments[i])["offset"] as double?; - - if (isSloped != null) - { - revitFootprintRoof.set_DefinesSlope(curveArray.get_Item(i), isSloped == true); - if (slopeAngle != null && isSloped == true) - { - // slope is set using actual slope (rise / run) for this method - revitFootprintRoof.set_SlopeAngle( - curveArray.get_Item(i), - Math.Tan((double)slopeAngle * Math.PI / 180) - ); - hasSlopedSide = true; - } - } - - if (offset != null) - revitFootprintRoof.set_Offset( - curveArray.get_Item(i), - ScaleToNative((double)offset, speckleFootprintRoof.units) - ); - } - } - - //this is for schema builder specifically - //if no roof edge has a slope defined but a slope angle is defined on the roof - //set each edge to have that slope - if (!hasSlopedSide && speckleFootprintRoof.slope != null && speckleFootprintRoof.slope != 0) - { - for (var i = 0; i < curveArray.Size; i++) - revitFootprintRoof.set_DefinesSlope(curveArray.get_Item(i), true); - - TrySetParam(revitFootprintRoof, BuiltInParameter.ROOF_SLOPE, (double)speckleFootprintRoof.slope); - } - - if (speckleFootprintRoof.cutOffLevel != null) - { - var cutOffLevel = ConvertLevelToRevit(speckleFootprintRoof.cutOffLevel, out levelState); - TrySetParam(revitFootprintRoof, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM, cutOffLevel); - } - - revitRoof = revitFootprintRoof; - break; - } - default: - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: "Roof type not supported, please try with RevitExtrusionRoof or RevitFootprintRoof" - ); - return appObj; - } - - Doc.Regenerate(); - - try - { - CreateVoids(revitRoof, speckleRoof); - } - catch (Exception ex) - { - appObj.Update(logItem: $"Could not create openings: {ex.Message}"); - } - - if (speckleRevitRoof != null) - { - SetInstanceParameters(revitRoof, speckleRevitRoof); - } - else - { - TrySetParam(revitRoof, BuiltInParameter.ROOF_LEVEL_OFFSET_PARAM, -baseOffset); - } - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitRoof.UniqueId, convertedItem: revitRoof); - - Doc.Regenerate(); - - return appObj; - } - - private Roof RoofToSpeckle(DB.RoofBase revitRoof, out List notes) - { - notes = new List(); - List profiles = null; - - var speckleRoof = new RevitRoof(); - - switch (revitRoof) - { - //assigning correct type for when going back in Revit - case FootPrintRoof footPrintRoof: - { - var speckleFootprintRoof = new RevitFootprintRoof - { - level = ConvertAndCacheLevel(footPrintRoof, BuiltInParameter.ROOF_BASE_LEVEL_PARAM), - cutOffLevel = ConvertAndCacheLevel(footPrintRoof, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM), - slope = GetParamValue(footPrintRoof, BuiltInParameter.ROOF_SLOPE) //NOTE: can be null if the sides have different slopes - }; - - var slopeArrow = GetSlopeArrow(footPrintRoof); - if (slopeArrow != null) - { - var tail = GetSlopeArrowTail(slopeArrow, Doc); - var head = GetSlopeArrowHead(slopeArrow, Doc); - var tailOffset = GetSlopeArrowTailOffset(slopeArrow, Doc); - var headOffset = GetSlopeArrowHeadOffset(slopeArrow, Doc, tailOffset, out _); - - var newTail = new Geometry.Point(tail.x, tail.y, tailOffset); - var newHead = new Geometry.Point(head.x, head.y, headOffset); - profiles = GetProfiles(revitRoof, newTail, newHead); - } - - speckleRoof = speckleFootprintRoof; - break; - } - case ExtrusionRoof revitExtrusionRoof: - { - var speckleExtrusionRoof = new RevitExtrusionRoof - { - start = GetParamValue(revitExtrusionRoof, BuiltInParameter.EXTRUSION_START_PARAM), - end = GetParamValue(revitExtrusionRoof, BuiltInParameter.EXTRUSION_END_PARAM) - }; - var plane = revitExtrusionRoof.GetProfile().get_Item(0).SketchPlane.GetPlane(); - speckleExtrusionRoof.referenceLine = new Line( - PointToSpeckle(plane.Origin.Add(plane.XVec.Normalize().Negate()), revitRoof.Document), - PointToSpeckle(plane.Origin, revitRoof.Document), - ModelUnits - ); //TODO: test! - speckleExtrusionRoof.level = ConvertAndCacheLevel( - revitExtrusionRoof, - BuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM - ); - speckleRoof = speckleExtrusionRoof; - break; - } - } - var elementType = revitRoof.Document.GetElement(revitRoof.GetTypeId()) as ElementType; - speckleRoof.type = elementType.Name; - speckleRoof.family = elementType.FamilyName; - - if (profiles == null) - profiles = GetProfiles(revitRoof); - - // TODO handle case if not one of our supported roofs - if (profiles.Any()) - { - speckleRoof.outline = profiles[0]; - if (profiles.Count > 1) - speckleRoof.voids = profiles.Skip(1).ToList(); - } - - GetAllRevitParamsAndIds( - speckleRoof, - revitRoof, - new List - { - "ROOF_CONSTRAINT_LEVEL_PARAM", - "ROOF_BASE_LEVEL_PARAM", - "ROOF_UPTO_LEVEL_PARAM", - "EXTRUSION_START_PARAM", - "EXTRUSION_END_PARAM", - "ROOF_SLOPE" - } - ); - - speckleRoof.displayValue = GetElementDisplayValue(revitRoof); - - GetHostedElements(speckleRoof, revitRoof, out List hostedNotes); - if (hostedNotes.Any()) - notes.AddRange(hostedNotes); - return speckleRoof; - } - - //Nesting the various profiles into a polycurve segments - private List GetProfiles(DB.RoofBase roof, Geometry.Point tailPoint = null, Geometry.Point headPoint = null) - { - // TODO handle case if not one of our supported roofs - var profiles = new List(); - - switch (roof) - { - case FootPrintRoof footprint: - { - ModelCurveArrArray crvLoops = footprint.GetProfiles(); - ModelCurve definesRoofSlope = null; - double roofSlope = 0; - - // if headpoint and tailpoint are not null, it means that the user is using a - // slope arrow to define the slope. Slope arrows are not creatable via the api - // so we have to translate that into sloped segments. - // if the user's slope arrow is not perpendicular to the segment that it is attached to - // then it will not work (this is just a limitation of sloped segments in Revit) - // see this api wish https://forums.autodesk.com/t5/revit-ideas/api-access-to-create-amp-modify-slope-arrow/idi-p/6700081 - if (tailPoint != null && headPoint != null) - { - for (var i = 0; i < crvLoops.Size; i++) - { - if (definesRoofSlope != null) - break; - - var crvLoop = crvLoops.get_Item(i); - var poly = new Polycurve(ModelUnits); - foreach (DB.ModelCurve curve in crvLoop) - { - if (curve == null) - continue; - if (!(curve.Location is DB.LocationCurve c)) - continue; - if (!(c.Curve is DB.Line line)) - continue; - - var start = PointToSpeckle(line.GetEndPoint(0), roof.Document); - var end = PointToSpeckle(line.GetEndPoint(1), roof.Document); - - if (!IsBetween(start, end, tailPoint)) - continue; - - if (!CheckOrtho(start.x, start.y, end.x, end.y, tailPoint.x, tailPoint.y, headPoint.x, headPoint.y)) - break; - - definesRoofSlope = curve; - var distance = Math.Sqrt( - (Math.Pow(headPoint.x - tailPoint.x, 2) + Math.Pow(headPoint.y - tailPoint.y, 2)) - ); - roofSlope = Math.Atan((headPoint.z - tailPoint.z) / distance) * 180 / Math.PI; - break; - } - } - } - - for (var i = 0; i < crvLoops.Size; i++) - { - var crvLoop = crvLoops.get_Item(i); - var poly = new Polycurve(ModelUnits); - foreach (DB.ModelCurve curve in crvLoop) - { - if (curve == null) - continue; - - var segment = CurveToSpeckle(curve.GeometryCurve, roof.Document) as Base; //it's a safe casting - if (definesRoofSlope != null && curve == definesRoofSlope) - { - segment["slopeAngle"] = roofSlope; - segment["isSloped"] = true; - segment["offset"] = tailPoint.z; - } - else - { - segment["slopeAngle"] = GetParamValue(curve, BuiltInParameter.ROOF_SLOPE); - segment["isSloped"] = GetParamValue(curve, BuiltInParameter.ROOF_CURVE_IS_SLOPE_DEFINING); - segment["offset"] = GetParamValue(curve, BuiltInParameter.ROOF_CURVE_HEIGHT_OFFSET); - } - poly.segments.Add(segment as ICurve); - - //roud profiles are returned duplicated! - if (curve is ModelArc arc && RevitVersionHelper.IsCurveClosed(arc.GeometryCurve)) - break; - } - profiles.Add(poly); - } - - break; - } - case ExtrusionRoof extrusion: - { - var crvloop = extrusion.GetProfile(); - var poly = new Polycurve(ModelUnits); - foreach (DB.ModelCurve curve in crvloop) - { - if (curve == null) - continue; - - poly.segments.Add(CurveToSpeckle(curve.GeometryCurve, roof.Document)); - } - profiles.Add(poly); - break; - } - } - return profiles; - } - - // checks if point c is between a and b - private bool IsBetween(Geometry.Point a, Geometry.Point b, Geometry.Point c) - { - var crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y); - - // compare versus epsilon for floating point values, or != 0 if using integers - if (Math.Abs(crossproduct) > TOLERANCE) - return false; - - var dotProduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y) * (b.y - a.y); - if (dotProduct < 0) - return false; - - var squaredLengthBA = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); - if (dotProduct > squaredLengthBA) - return false; - - return true; - } - - private bool CheckOrtho(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) - { - double m1, - m2; - - // Both lines have infinite slope - if (Math.Abs(x2 - x1) < TOLERANCE && Math.Abs(x4 - x3) < TOLERANCE) - return false; - // Only line 1 has infinite slope - else if (Math.Abs(x2 - x1) < TOLERANCE) - { - m2 = (y4 - y3) / (x4 - x3); - if (Math.Abs(m2) < TOLERANCE) - return true; - else - return false; - } - // Only line 2 has infinite slope - else if (Math.Abs(x4 - x3) < TOLERANCE) - { - m1 = (y2 - y1) / (x2 - x1); - if (Math.Abs(m1) < TOLERANCE) - return true; - else - return false; - } - else - { - // Find slopes of the lines - m1 = (y2 - y1) / (x2 - x1); - m2 = (y4 - y3) / (x4 - x3); - - // Check if their product is -1 - if (Math.Abs(m1 * m2 + 1) < TOLERANCE) - return true; - else - return false; - } - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoom.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoom.cs deleted file mode 100644 index 7b3fe4cb11..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertRoom.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.BuiltElements; -using Speckle.Core.Models; -using System.Collections.Generic; -using System.Linq; -using DB = Autodesk.Revit.DB.Architecture; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject RoomToNative(Room speckleRoom) - { - var revitRoom = GetExistingElementByApplicationId(speckleRoom.applicationId) as DB.Room; - var appObj = new ApplicationObject(speckleRoom.id, speckleRoom.speckle_type) - { - applicationId = speckleRoom.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitRoom, appObj)) - return appObj; - - var level = ConvertLevelToRevit(speckleRoom.level, out ApplicationObject.State levelState); - - var isUpdate = true; - if (revitRoom == null) - { - var basePoint = PointToNative(speckleRoom.basePoint); - - // set computation level of Level based on the bottom elevation of the Room (Rooms can have offset elevation from Levels) - // it is not guaranteed that the final computation level will fit for all the Rooms, however not generating extra levels is preferred - if (level.get_Parameter(BuiltInParameter.LEVEL_ROOM_COMPUTATION_HEIGHT).AsDouble() < basePoint.Z) - { - TrySetParam(level, BuiltInParameter.LEVEL_ROOM_COMPUTATION_HEIGHT, basePoint.Z); - } - - revitRoom = Doc.Create.NewRoom(level, new UV(basePoint.X, basePoint.Y)); - isUpdate = false; - } - - revitRoom.Name = speckleRoom.name; - revitRoom.Number = speckleRoom.number; - - if (speckleRoom.height > 0.0) - TrySetParam( - revitRoom, - BuiltInParameter.ROOM_UPPER_OFFSET, - ScaleToNative(speckleRoom.height, speckleRoom.units) - ); - - SetInstanceParameters(revitRoom, speckleRoom); - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitRoom.UniqueId, convertedItem: revitRoom); - return appObj; - } - - public BuiltElements.Room RoomToSpeckle(DB.Room revitRoom) - { - var profiles = GetProfiles(revitRoom); - - var speckleRoom = new Room(); - - speckleRoom.name = revitRoom.get_Parameter(BuiltInParameter.ROOM_NAME).AsString(); - speckleRoom.number = revitRoom.Number; - speckleRoom.basePoint = (Point)LocationToSpeckle(revitRoom); - speckleRoom.level = ConvertAndCacheLevel(revitRoom, BuiltInParameter.ROOM_LEVEL_ID); - if (profiles.Any()) - speckleRoom.outline = profiles[0]; - speckleRoom.area = GetParamValue(revitRoom, BuiltInParameter.ROOM_AREA); - if (profiles.Count > 1) - speckleRoom.voids = profiles.Skip(1).ToList(); - - GetAllRevitParamsAndIds(speckleRoom, revitRoom); - - speckleRoom.displayValue = GetElementDisplayValue(revitRoom); - var phase = Doc.GetElement(revitRoom.get_Parameter(BuiltInParameter.ROOM_PHASE).AsElementId()); - if (phase != null) - { - speckleRoom["phaseCreated"] = phase.Name; - } - - return speckleRoom; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertSpace.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertSpace.cs deleted file mode 100644 index e6d9facd89..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertSpace.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB.Mechanical; -using Level = Autodesk.Revit.DB.Level; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject SpaceToNative(Space speckleSpace) - { - var appObj = new ApplicationObject(speckleSpace.id, speckleSpace.speckle_type) - { - applicationId = speckleSpace.applicationId - }; - - var revitSpace = GetExistingElementByApplicationId(speckleSpace.applicationId) as DB.Space; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitSpace, appObj)) - return appObj; - - // Determine Space Location - if (speckleSpace.basePoint is null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Space Base Point was null"); - return appObj; - } - - var level = ConvertLevelToRevit(speckleSpace.level, out _); - var basePoint = PointToNative(speckleSpace.basePoint); - var upperLimit = ConvertLevelToRevit(speckleSpace.topLevel, out _); - - // no target phase found, it will use the active view phase anyway - var targetPhase = DetermineTargetPhase(speckleSpace, revitSpace); - var activeViewPhase = DetermineActiveViewPhase(); - - // even though the API documented to allow for spaces to be created in any phase, - // it is not possible to create on any phase but the Active View phase - var activeViewPhaseName = activeViewPhase?.Name; - var targetPhaseName = targetPhase?.Name; - - if (activeViewPhase.Id != targetPhase.Id) - { - appObj.Update( - logItem: $"Space Phase {targetPhase.Name} not selected in the Active View.", - status: ApplicationObject.State.Skipped - ); - return appObj; - // return null; - } - - revitSpace = CreateRevitSpaceIfNeeded(speckleSpace, revitSpace, targetPhase, level, basePoint); - - if (revitSpace == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var revitZone = revitSpace.Zone; - revitZone = CreateRevitZoneIfNeeded(speckleSpace, revitZone, targetPhase, level); - - // if a relevant zone exists add space to it - if (revitZone != null) - { - var currentSpaces = revitZone.Spaces; - - // if the space is already in the zone, do nothing. - if (!currentSpaces.Contains(revitSpace)) - { - var spaceSet = new DB.SpaceSet(); - spaceSet.Insert(revitSpace); - revitZone.AddSpaces(spaceSet); - } - } - - revitSpace.Name = speckleSpace.name; - revitSpace.Number = speckleSpace.number; - - SetSpaceLimits(speckleSpace, upperLimit, revitSpace); - SetSpaceType(speckleSpace, revitSpace); - SetInstanceParameters(revitSpace, speckleSpace); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitSpace.UniqueId, convertedItem: revitSpace); - return appObj; - } - - /// - /// Sets the type of the Revit space based on the provided Speckle space. - /// - /// The Space object from the Speckle system. - /// The Revit Space object to update. - /// - /// The method will try to set the Revit space type based on the Speckle space type. - /// If the Speckle space type is not recognized, it will default to 'NoSpaceType'. - /// - private static void SetSpaceType(Space speckleSpace, DB.Space revitSpace) - { - if (string.IsNullOrEmpty(speckleSpace.spaceType)) - return; - revitSpace.SpaceType = Enum.TryParse(speckleSpace.spaceType, out DB.SpaceType spaceType) - ? spaceType - : DB.SpaceType.NoSpaceType; - } - - /// - /// Sets the upper limit and offsets for a Revit space based on a Speckle space. - /// - /// The Speckle Space object containing the upper limit and offset information. - /// The Element object representing the upper limit level. - /// The Revit Space object to be updated. - /// - /// The method will attempt to set the upper limit and offsets for the Revit space. - /// If an upper limit is not specified, the method will return early without making changes. - /// - private void SetSpaceLimits(Space speckleSpace, Element upperLimit, DB.Space revitSpace) - { - if (upperLimit == null) - return; - - TrySetParam(revitSpace, BuiltInParameter.ROOM_UPPER_LEVEL, upperLimit); - - revitSpace.LimitOffset = ScaleToNative(speckleSpace.topOffset, speckleSpace.units); - revitSpace.BaseOffset = ScaleToNative(speckleSpace.baseOffset, speckleSpace.units); - } - - /// - /// Handles the Revit Space based on the provided Speckle Space and target phase. - /// - /// The Space object from the Speckle system. - /// The existing Revit Space object. This may be modified by the method. - /// The target Phase object. - /// The Level object associated with the space. - /// The base point for the space. - /// The modified or newly created Revit Space object. - private DB.Space CreateRevitSpaceIfNeeded( - Space speckleSpace, - DB.Space revitSpace, - Phase targetPhase, - Level level, - XYZ basePoint - ) - { - // Main logic - if (revitSpace == null) - { - revitSpace = CreateNewSpace(level, targetPhase, new UV(basePoint.X, basePoint.Y), speckleSpace.level.name); - - if (revitSpace == null) - { - return null; - } - } - else if (revitSpace.Area == 0 && revitSpace.Location == null) - { - Doc.Delete(revitSpace.Id); - - revitSpace = CreateNewSpace(level, targetPhase, new UV(basePoint.X, basePoint.Y), speckleSpace.level.name); - } - - return revitSpace; - } - - /// - /// Creates a new RevitSpace based on the provided parameters. - /// - /// The level for the new space. - /// The target phase for the new space. If null, the active view phase will be used. - /// The base point (UV coordinates) for the new space. - /// The name of the level. Used to determine if the space has a location. - /// The newly created RevitSpace, or null if the space could not be created. - private DB.Space CreateNewSpace(Level level, Phase targetPhase, UV basePoint, string levelName) - { - if (targetPhase == null) - { - return string.IsNullOrEmpty(levelName) || basePoint == null - ? null - : Doc.Create.NewSpace(level, new UV(basePoint.U, basePoint.V)); - } - - return string.IsNullOrEmpty(levelName) // has no location - ? Doc.Create.NewSpace(targetPhase) - : Doc.Create.NewSpace(level, targetPhase, new UV(basePoint.U, basePoint.V)); - } - - /// - /// Determines the target phase for a space based on available information. - /// - /// The Space object from the Speckle system. - /// The Space object from the Revit system. - /// The determined target Phase object. - /// - /// The method tries to determine the target phase based on the following priority: - /// 1. Phase from the Speckle space (if it exists). - /// 2. Phase from the existing Revit space (if it exists). - /// 3. Phase from the active view in Revit. - /// - private Phase DetermineTargetPhase(Space speckleSpace, DB.Space revitSpace) - { - // Get all phases - var phases = Doc.Phases.Cast().ToList(); - - // Determine existing space phase, if any - Phase existingSpacePhase = null; - if (revitSpace != null) - { - string existingSpacePhaseName = revitSpace.get_Parameter(BuiltInParameter.ROOM_PHASE).AsValueString(); - existingSpacePhase = phases.FirstOrDefault(x => x.Name == existingSpacePhaseName); - } - - // Determine target phase - // Priority: speckleSpace phase > existing space phase > active view phase - string targetPhaseName = speckleSpace.phaseName; - var targetPhase = phases.FirstOrDefault(x => x.Name == targetPhaseName) ?? existingSpacePhase; - - return targetPhase; - } - - private Phase DetermineActiveViewPhase(IEnumerable phases = null) - { - phases ??= Doc.Phases.Cast(); - - // Determine active view phase - var activeViewPhaseName = Doc.ActiveView.get_Parameter(BuiltInParameter.VIEW_PHASE).AsValueString(); - return phases.FirstOrDefault(x => x.Name == activeViewPhaseName); - } - - public Space SpaceToSpeckle(DB.Space revitSpace) - { - var profiles = GetProfiles(revitSpace); - - var speckleSpace = new Space - { - name = revitSpace.Name, - number = revitSpace.Number, - basePoint = (Point)LocationToSpeckle(revitSpace), - level = ConvertAndCacheLevel(revitSpace.LevelId, revitSpace.Document), - topLevel = ConvertAndCacheLevel( - revitSpace.get_Parameter(BuiltInParameter.ROOM_UPPER_LEVEL).AsElementId(), - revitSpace.Document - ), - baseOffset = GetParamValue(revitSpace, BuiltInParameter.ROOM_LOWER_OFFSET), - topOffset = GetParamValue(revitSpace, BuiltInParameter.ROOM_UPPER_OFFSET), - outline = profiles.Count != 0 ? profiles[0] : null, - area = GetParamValue(revitSpace, BuiltInParameter.ROOM_AREA), - volume = GetParamValue(revitSpace, BuiltInParameter.ROOM_VOLUME), - spaceType = revitSpace.SpaceType.ToString(), - displayValue = GetElementDisplayValue(revitSpace) - }; - - if (profiles.Count > 1) - speckleSpace.voids = profiles.Skip(1).ToList(); - - // Spaces are typically associated with a Room, but not always - if (revitSpace.Room != null) - speckleSpace["roomId"] = revitSpace.Room.Id.ToString(); - - // Zones are stored as a Space prop despite being a parent object, so we need to convert it here - speckleSpace.zone = revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType(out _) - .GetOrAdd(revitSpace.Zone.Name, () => ZoneToSpeckle(revitSpace.Zone), out _); - - GetAllRevitParamsAndIds(speckleSpace, revitSpace); - - // Special Phase handling for Spaces, phase is found as a parameter on the Space object, not a property - var phase = Doc.GetElement(revitSpace.get_Parameter(BuiltInParameter.ROOM_PHASE).AsElementId()); - if (phase != null) - { - speckleSpace.phaseName = phase.Name; - } - - return speckleSpace; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStair.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStair.cs deleted file mode 100644 index 9ddf63173f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStair.cs +++ /dev/null @@ -1,94 +0,0 @@ - -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Architecture; -using Objects.BuiltElements.Revit; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - //NOTE: we are currently only converting Stairs ToSpeckle - //a ToNative method might come later on! - private RevitStair StairToSpeckle(Stairs revitStair) - { - var stairType = revitStair.Document.GetElement(revitStair.GetTypeId()) as StairsType; - var speckleStair = new RevitStair(); - speckleStair.family = stairType.FamilyName; - speckleStair.type = stairType.Name; - speckleStair.level = ConvertAndCacheLevel(revitStair, BuiltInParameter.STAIRS_BASE_LEVEL_PARAM); - speckleStair.topLevel = ConvertAndCacheLevel(revitStair, BuiltInParameter.STAIRS_TOP_LEVEL_PARAM); - speckleStair.riserHeight = ScaleToSpeckle(revitStair.ActualRiserHeight); - speckleStair.risersNumber = revitStair.ActualRisersNumber; - speckleStair.treadDepth = ScaleToSpeckle(revitStair.ActualTreadDepth); - speckleStair.treadsNumber = revitStair.ActualTreadsNumber; - speckleStair.baseElevation = ScaleToSpeckle(revitStair.BaseElevation); - speckleStair.topElevation = ScaleToSpeckle(revitStair.TopElevation); - speckleStair.height = ScaleToSpeckle(revitStair.Height); - speckleStair.numberOfStories = revitStair.NumberOfStories; - - speckleStair.runs = revitStair.GetStairsRuns().Select(x => StairRunToSpeckle(revitStair.Document.GetElement(x) as StairsRun)).ToList(); - speckleStair.landings = revitStair.GetStairsLandings().Select(x => StairLandingToSpeckle(revitStair.Document.GetElement(x) as StairsLanding)).ToList(); - speckleStair.supports = revitStair.GetStairsSupports().Select(x => StairSupportToSpeckle(revitStair.Document.GetElement(x))).ToList(); - - GetAllRevitParamsAndIds(speckleStair, revitStair, new List { "STAIRS_BASE_LEVEL_PARAM", "STAIRS_TOP_LEVEL_PARAM" }); - - speckleStair.displayValue = GetElementDisplayValue(revitStair); - - return speckleStair; - } - - private RevitStairRun StairRunToSpeckle(StairsRun revitStairRun) - { - var stairType = revitStairRun.Document.GetElement(revitStairRun.GetTypeId()) as StairsRunType; - var run = new RevitStairRun(); - run.family = stairType.FamilyName; - run.type = stairType.Name; - run.risersNumber = revitStairRun.ActualRisersNumber; - run.runWidth = ScaleToSpeckle(revitStairRun.ActualRunWidth); - run.treadsNumber = revitStairRun.ActualTreadsNumber; - run.height = ScaleToSpeckle(revitStairRun.Height); - run.baseElevation = ScaleToSpeckle(revitStairRun.BaseElevation); - run.topElevation = ScaleToSpeckle(revitStairRun.TopElevation); - run.beginsWithRiser = revitStairRun.BeginsWithRiser; - run.endsWithRiser = revitStairRun.EndsWithRiser; - run.extensionBelowRiserBase = ScaleToSpeckle(revitStairRun.ExtensionBelowRiserBase); - run.extensionBelowTreadBase = ScaleToSpeckle(revitStairRun.ExtensionBelowTreadBase); - run.runStyle = revitStairRun.StairsRunStyle.ToString(); - run.units = ModelUnits; - run.path = CurveLoopToSpeckle(revitStairRun.GetStairsPath(), revitStairRun.Document); - run.outline = CurveLoopToSpeckle(revitStairRun.GetFootprintBoundary(), revitStairRun.Document); - - GetAllRevitParamsAndIds(run, revitStairRun); - return run; - } - - private RevitStairLanding StairLandingToSpeckle(StairsLanding revitStairLanding) - { - var stairType = revitStairLanding.Document.GetElement(revitStairLanding.GetTypeId()) as StairsLandingType; - var landing = new RevitStairLanding(); - landing.family = stairType.FamilyName; - landing.type = stairType.Name; - landing.isAutomaticLanding = revitStairLanding.IsAutomaticLanding; - landing.thickness = revitStairLanding.Thickness; - landing.baseElevation = ScaleToSpeckle(revitStairLanding.BaseElevation); - landing.units = ModelUnits; - landing.outline = CurveLoopToSpeckle(revitStairLanding.GetFootprintBoundary(), revitStairLanding.Document); - - GetAllRevitParamsAndIds(landing, revitStairLanding); - return landing; - } - - private RevitStairSupport StairSupportToSpeckle(Element revitStairSupport) - { - var stairType = revitStairSupport.Document.GetElement(revitStairSupport.GetTypeId()) as ElementType; - var support = new RevitStairSupport(); - support.family = stairType.FamilyName; - support.type = stairType.Name; - - GetAllRevitParamsAndIds(support, revitStairSupport); - return support; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralConnectionHandlers.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralConnectionHandlers.cs deleted file mode 100644 index ef318e895f..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralConnectionHandlers.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using System.Collections.Generic; -using DB = Autodesk.Revit.DB; -using Structure = Autodesk.Revit.DB.Structure; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private ApplicationObject StructuralConnectionHandlerToNative(StructuralConnectionHandler speckleConnectionHandler) - { - // I think the code below is mostly what we need to get this working. However, the - // StructuralConnectionHandler has a one to many relationship and we need to make sure - // that every object that the connection is connected to has been converted before - // this object is converted. Therefore I'm waiting on Jedd's new traversal function to make this - // a reality for me before implementing the receiveToNative method. - - //var docObj = GetExistingElementByApplicationId(speckleConnectionHandler.applicationId); - //var appObj = new ApplicationObject(speckleConnectionHandler.id, speckleConnectionHandler.speckle_type) { applicationId = speckleConnectionHandler.applicationId }; - - //// skip if element already exists in doc & receive mode is set to ignore - //if (IsIgnore(docObj, appObj, out appObj)) - // return appObj; - - //if (!GetElementType(speckleConnectionHandler, appObj, out Structure.StructuralConnectionHandlerType connectionType)) - //{ - // appObj.Update(status: ApplicationObject.State.Failed, logItem: "Unable to find a valid connection type in the Revit project"); - // return appObj; - //} - - //if (docObj != null) - //{ - // // TODO: Replace with actual update logic here - // Doc.Delete(docObj.Id); - //} - - //var elIds = new List(); - //foreach (var speckleEl in speckleConnectionHandler.connectedElements) - //{ - // var revitEl = GetExistingElementByApplicationId(speckleEl.applicationId); - // if (revitEl != null) - // elIds.Add(revitEl.Id); - //} - - //Structure.StructuralConnectionHandler.Create(Doc, elIds, connectionType.Id); - //appObj.Update(status: ApplicationObject.State.Created); - //return appObj; - - return null; - } - private Base StructuralConnectionHandlerToSpeckle(DB.Structure.StructuralConnectionHandler revitConnection) - { - var type = revitConnection.Document.GetElement(revitConnection.GetTypeId()) as Structure.StructuralConnectionHandlerType; - - //var connectedElements = revitConnection.GetConnectedElementIds(); - - var speckleConnection = new StructuralConnectionHandler() { - family = type.FamilyName, - type = type.Name, - //connectedElements = connectedElements - }; - - // Structural Connection Handlers are (supposedly) view specific which requires getting mesh by view - // TODO: not guarenteed that the active view is what we need (3D view with fine detail where the element is visible - speckleConnection.displayValue = GetElementDisplayValue(revitConnection, new DB.Options() { View = Doc.ActiveView }); - - GetAllRevitParamsAndIds(speckleConnection, revitConnection); - - return speckleConnection; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralModel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralModel.cs deleted file mode 100644 index 99faf20a84..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertStructuralModel.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Objects.Structural.Geometry; -using Vector = Objects.Geometry.Vector; -using Plane = Objects.Geometry.Plane; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Objects.Structural.Analysis; -using Objects.Structural.CSI.Geometry; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject StructuralModelToNative(Model speckleStructModel) - { - var lengthUnits = speckleStructModel.specs.settings.modelUnits.length; - var appObj = new ApplicationObject(speckleStructModel.id, speckleStructModel.speckle_type) { applicationId = speckleStructModel.applicationId }; - foreach (Node node in speckleStructModel.nodes) - { - var _node = AnalyticalNodeToNative(node); - appObj.Update(createdIds: _node.CreatedIds, converted: _node.Converted); - } - foreach (var element in speckleStructModel.elements) - { - - if (element is Element1D element1D) - { - element1D.units = lengthUnits; - try - { - if (element is CSIElement1D csiElement1D) - { - var _csiStick = AnalyticalStickToNative(csiElement1D); - appObj.Update(createdIds: _csiStick.CreatedIds, converted: _csiStick.Converted); - } - else - { - var _stick = AnalyticalStickToNative((Element1D)element); - appObj.Update(createdIds: _stick.CreatedIds, converted: _stick.Converted); - } - } - catch { } - } - else - { - try - { - if (element is CSIElement2D csiElement2D) - { - var _csiStick = AnalyticalSurfaceToNative(csiElement2D); - appObj.Update(createdIds: _csiStick.CreatedIds, converted: _csiStick.Converted); - } - else - { - var _stick = AnalyticalSurfaceToNative((Element2D)element); - appObj.Update(createdIds: _stick.CreatedIds, converted: _stick.Converted); - } - } - catch { } - } - } - - return appObj; - } - - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTeklaObjects.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTeklaObjects.cs deleted file mode 100644 index 248e103d8e..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTeklaObjects.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Structure; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Objects.Structural.Geometry; -using Objects.Structural.Properties; -using Objects.Structural.Properties.Profiles; -using Objects.Structural.Materials; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject TeklaBeamToNative(BuiltElements.TeklaStructures.TeklaBeam teklaBeam, StructuralType structuralType = StructuralType.Beam) - { - var appObj = new ApplicationObject(teklaBeam.id, teklaBeam.speckle_type) { applicationId = teklaBeam.applicationId }; - - RevitBeam revitBeam = new RevitBeam(); - //This only works for CSIC sections now for sure. Need to test on other sections - revitBeam.type = teklaBeam.profile.name.Replace('X', 'x'); - revitBeam.baseLine = teklaBeam.baseLine; - //Beam beam = new Beam(teklaBeam.baseLine); - appObj = BeamToNative(revitBeam); - //DB.FamilyInstance nativeRevitBeam = (DB.FamilyInstance)placeholders[0].NativeObject; - return appObj; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopRail.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopRail.cs deleted file mode 100644 index 84e52b2ade..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopRail.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Architecture; -using Objects.BuiltElements.Revit; -using System.Collections.Generic; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private RevitTopRail TopRailToSpeckle(TopRail revitTopRail) - { - var topRailType = revitTopRail.Document.GetElement(revitTopRail.GetTypeId()) as TopRailType; - var speckleTopRail = new RevitTopRail - { - type = topRailType.Name, - displayValue = GetElementDisplayValue(revitTopRail) - }; - - GetAllRevitParamsAndIds(speckleTopRail, revitTopRail, new List { }); - - Report.Log($"Converted TopRail {revitTopRail.Id}"); - - return speckleTopRail; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopography.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopography.cs deleted file mode 100644 index bb607d3efe..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertTopography.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Autodesk.Revit.DB; -using Autodesk.Revit.DB.Architecture; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Objects.Utils; -using Speckle.Core.Models; -using System.Collections.Generic; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject TopographyToNative(Topography speckleSurface) - { - var docObj = GetExistingElementByApplicationId(((Base)speckleSurface).applicationId); - var appObj = new ApplicationObject(speckleSurface.id, speckleSurface.speckle_type) { applicationId = speckleSurface.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - var pts = new List(); - var pointTuplesList = new List<(double, double)>(); - var facets = new List(); - foreach (Geometry.Mesh displayMesh in speckleSurface.displayValue) - { - // triangulate the mesh first since revit Topography can only accept triangulated meshes - displayMesh.TriangulateMesh(); - - pts.Capacity += displayMesh.vertices.Count / 3; - for (int i = 0; i < displayMesh.vertices.Count; i += 3) - { - // add a check for duplicate points, if 'keepXYDuplicates' is false - var ptTuple = (displayMesh.vertices[i], displayMesh.vertices[i + 1]); - if (!pointTuplesList.Contains(ptTuple)) - { - pointTuplesList.Add(ptTuple); - var point = new Geometry.Point(displayMesh.vertices[i], displayMesh.vertices[i + 1], displayMesh.vertices[i + 2], displayMesh.units); - pts.Add(PointToNative(point)); - } - } - } - - if (docObj != null) - Doc.Delete(docObj.Id); - - var revitSurface = TopographySurface.Create(Doc, pts); - if (speckleSurface is RevitTopography rt) - SetInstanceParameters(revitSurface, rt); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitSurface.UniqueId, convertedItem: revitSurface); - return appObj; - } - - public RevitTopography TopographyToSpeckle(TopographySurface revitTopo) - { - var speckleTopo = new RevitTopography(); - speckleTopo.displayValue = GetElementDisplayValue(revitTopo); - GetAllRevitParamsAndIds(speckleTopo, revitTopo); - return speckleTopo; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertToposolid.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertToposolid.cs deleted file mode 100644 index f4fc692887..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertToposolid.cs +++ /dev/null @@ -1,109 +0,0 @@ -#if (REVIT2024) - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -using OG = Objects.Geometry; -using OO = Objects.Other; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject ToposolidToNative(RevitToposolid fromSpeckle) - { - string name = null; - ApplicationObject appObj = null; - - var docObj = GetExistingElementByApplicationId(fromSpeckle.applicationId); - appObj = new ApplicationObject(fromSpeckle.id, fromSpeckle.speckle_type) - { - applicationId = fromSpeckle.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - // get the curves and the points - var curveLoops = new List(); - foreach (var curveArray in fromSpeckle.profiles) - { - curveLoops.Add(CurveArrayToCurveLoop(CurveToNative(curveArray.segments))); - } - - var points = fromSpeckle.points.Select(x => PointToNative(x)).ToList(); - - // NOTE: if the level is null this will not create - // there maybe something more elegant we can do to automatically drop to direct shape - DB.Level level = ConvertLevelToRevit(fromSpeckle.level, out ApplicationObject.State state); - - var topoSolidType = GetElementType(fromSpeckle, appObj, out bool _); - - Toposolid revitToposolid = null; - if (points.Count > 0) - { - revitToposolid = Toposolid.Create(Doc, curveLoops, points, topoSolidType.Id, level?.Id); - } - else - { - revitToposolid = Toposolid.Create(Doc, curveLoops, topoSolidType.Id, level?.Id); - } - - SetInstanceParameters(revitToposolid, fromSpeckle); - - appObj.Update(status: ApplicationObject.State.Created, createdId: revitToposolid.UniqueId, convertedItem: revitToposolid); - - return appObj; - } - - private RevitToposolid ToposolidToSpeckle(Toposolid topoSolid, out List notes) - { - var toSpeckle = new RevitToposolid(); - notes = new List(); - - // we will store the list of interior points in order to recreate the Toposolid - var slabShapeEditor = topoSolid.GetSlabShapeEditor(); - var vertices = slabShapeEditor.SlabShapeVertices; - toSpeckle.points = vertices.Cast() - .Select(x => PointToSpeckle(x.Position, Doc)) - .ToList(); - - var sketch = Doc.GetElement(topoSolid.SketchId) as Sketch; - toSpeckle.profiles = GetSketchProfiles(sketch); - - var type = topoSolid.Document.GetElement(topoSolid.GetTypeId()) as ElementType; - - toSpeckle.level = ConvertAndCacheLevel(topoSolid, BuiltInParameter.LEVEL_PARAM); - toSpeckle.family = type?.FamilyName; - toSpeckle.type = type?.Name; - - GetAllRevitParamsAndIds( - toSpeckle, - topoSolid, - new List - { - "LEVEL_PARAM", - } - ); - - toSpeckle.displayValue = GetElementDisplayValue( - topoSolid, - new Options() { DetailLevel = ViewDetailLevel.Fine }); - - GetHostedElements(toSpeckle, topoSolid, out List hostedNotes); - if (hostedNotes.Any()) - notes.AddRange(hostedNotes); - - return toSpeckle; - } - } -} - -#endif diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.Schedule.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.Schedule.cs deleted file mode 100644 index 0f629cc336..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.Schedule.cs +++ /dev/null @@ -1,575 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.Organization; -using RevitSharedResources.Models; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - #region ToNative - private ApplicationObject DataTableToNative(DataTable speckleTable) - { - var docObj = GetExistingElementByApplicationId(speckleTable.applicationId); - var appObj = new ApplicationObject(speckleTable.id, speckleTable.speckle_type) - { - applicationId = speckleTable.applicationId - }; - - if (docObj == null) - { - throw new NotSupportedException("Creating brand new schedules is currently not supported"); - } - - if (docObj is not ViewSchedule revitSchedule) - { - throw new Exception( - $"Existing element with UniqueId = {docObj.UniqueId} is of the type {docObj.GetType()}, not of the expected type, DB.ViewSchedule" - ); - } - - var speckleIndexToRevitParameterDataMap = new Dictionary(); - foreach (var columnInfo in RevitScheduleUtils.ScheduleColumnIteration(revitSchedule)) - { - AddToIndexToScheduleMap(columnInfo, speckleTable, speckleIndexToRevitParameterDataMap); - } - - var originalTableIds = new FilteredElementCollector(Doc, revitSchedule.Id).ToElementIds(); - foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) - { - UpdateDataInRow(rowInfo, originalTableIds, revitSchedule, speckleTable, speckleIndexToRevitParameterDataMap); - } - - appObj.Update(convertedItem: docObj, createdId: docObj.UniqueId, status: ApplicationObject.State.Updated); - return appObj; - } - - private static void AddToIndexToScheduleMap( - ScheduleColumnIterationInfo info, - DataTable speckleTable, - Dictionary speckleIndexToRevitParameterDataMap - ) - { - var fieldInt = info.field.ParameterId.IntegerValue; - - var incomingColumnIndex = -1; - for (var i = 0; i < speckleTable.columnMetadata.Count; i++) - { - long? paramId = null; - if (speckleTable.columnMetadata[i]["BuiltInParameterInteger"] is int paramIdInt) - { - paramId = paramIdInt; - } - if (speckleTable.columnMetadata[i]["BuiltInParameterInteger"] is long paramIdLong) - { - paramId = paramIdLong; - } - - if (paramId == null) - { - continue; - } - if (paramId != fieldInt) - { - continue; - } - - incomingColumnIndex = i; - break; - } - - if (incomingColumnIndex == -1) - { - return; - } - - if (!(speckleTable.columnMetadata[incomingColumnIndex]["FieldType"] is string fieldType)) - { - throw new Exception("Column does not have prop metadata. FieldType is missing"); - } - - var scheduleData = new RevitParameterData - { - ColumnIndex = info.columnIndex - info.numHiddenFields, - Parameter = (BuiltInParameter)fieldInt, - IsTypeParam = fieldType == "ElementType" - }; - speckleIndexToRevitParameterDataMap.Add(incomingColumnIndex, scheduleData); - } - - private void UpdateDataInRow( - ScheduleRowIterationInfo info, - ICollection originalTableIds, - ViewSchedule revitSchedule, - DataTable speckleTable, - Dictionary speckleIndexToRevitParameterDataMap - ) - { - var elementIds = ElementApplicationIdsInRow( - info.rowIndex, - info.section, - originalTableIds, - revitSchedule, - info.tableSection - ) - .ToList(); - - if (elementIds.Count == 0) - { - return; - } - - var speckleObjectRowIndex = speckleTable.rowMetadata.FindIndex( - b => b["RevitApplicationIds"] is IList list && list.Contains(elementIds.First()) - ); - - foreach (var kvp in speckleIndexToRevitParameterDataMap) - { - var speckleObjectColumnIndex = kvp.Key; - var revitScheduleData = kvp.Value; - - var existingValue = revitSchedule.GetCellText(info.tableSection, info.rowIndex, revitScheduleData.ColumnIndex); - var newValue = speckleTable.data[speckleObjectRowIndex][speckleObjectColumnIndex]; - if (existingValue == newValue.ToString()) - { - continue; - } - - if (revitScheduleData.IsTypeParam) - { - Element element = null; - foreach (var id in elementIds) - { - element = Doc.GetElement(elementIds.First()); - if (element != null) - { - break; - } - } - if (element == null) - { - return; - } - - var elementType = Doc.GetElement(element.GetTypeId()); - TrySetParam(elementType, revitScheduleData.Parameter, newValue, "none"); - } - else - { - foreach (var id in elementIds) - { - var element = Doc.GetElement(id); - if (element == null) - continue; - - TrySetParam(element, revitScheduleData.Parameter, newValue, "none"); - } - } - } - } - - #endregion - - #region ToSpeckle - private DataTable ScheduleToSpeckle(DB.ViewSchedule revitSchedule) - { - var speckleTable = new DataTable { applicationId = revitSchedule.UniqueId }; - - var originalTableIds = new FilteredElementCollector(Doc, revitSchedule.Id).ToElementIds(); - - var skippedIndicies = new Dictionary>(); - var columnHeaders = new List(); - - DefineColumnMetadata(revitSchedule, speckleTable, originalTableIds, columnHeaders); - - var headerIndexArray = GetTableHeaderIndexArray(revitSchedule, columnHeaders); - - PopulateDataTableRows(revitSchedule, speckleTable, originalTableIds, headerIndexArray, columnHeaders); - - if (!revitSchedule.Definition.ShowHeaders) - { - AddHeaderRow(speckleTable, columnHeaders); - } - - return speckleTable; - } - - private void AddHeaderRow(DataTable speckleTable, List headers) - { - speckleTable.AddRow(metadata: new Base(), index: speckleTable.headerRowIndex, headers.ToArray()); - } - - private void DefineColumnMetadata( - ViewSchedule revitSchedule, - DataTable speckleTable, - ICollection originalTableIds, - List columnHeaders - ) - { - Element firstElement = null; - Element firstType = null; - if (originalTableIds.Count > 0) - { - firstElement = Doc.GetElement(originalTableIds.First()); - firstType = Doc.GetElement(firstElement.GetTypeId()); - } - - foreach (var columnInfo in RevitScheduleUtils.ScheduleColumnIteration(revitSchedule)) - { - AddColumnMetadataToDataTable(columnInfo, revitSchedule, speckleTable, columnHeaders, firstType, firstElement); - } - } - - private static void AddColumnMetadataToDataTable( - ScheduleColumnIterationInfo info, - ViewSchedule revitSchedule, - DataTable speckleTable, - List columnHeaders, - Element firstType, - Element firstElement - ) - { - // add column header to list for potential future use - columnHeaders.Add(info.field.ColumnHeading); - - var builtInParameter = (BuiltInParameter)info.field.ParameterId.IntegerValue; - - var columnMetadata = new Base(); - columnMetadata["BuiltInParameterInteger"] = info.field.ParameterId.IntegerValue; - columnMetadata["FieldType"] = info.field.FieldType.ToString(); - - Parameter param; - if (info.field.FieldType == ScheduleFieldType.ElementType) - { - if (firstType != null) - { - param = firstType.get_Parameter(builtInParameter); - columnMetadata["IsReadOnly"] = param?.IsReadOnly; - } - } - else if (info.field.FieldType == ScheduleFieldType.Instance) - { - if (firstElement != null) - { - param = firstElement.get_Parameter(builtInParameter); - columnMetadata["IsReadOnly"] = param?.IsReadOnly; - } - } - else - { - var scheduleCategory = (BuiltInCategory)revitSchedule.Definition.CategoryId.IntegerValue; - SpeckleLog.Logger.Warning( - "Schedule of category, {scheduleCategory}, contains field of type {builtInParameter} which has an unsupported field type, {fieldType}", - scheduleCategory, - builtInParameter, - info.field.FieldType.ToString() - ); - } - speckleTable.DefineColumn(columnMetadata); - } - - private void PopulateDataTableRows( - ViewSchedule revitSchedule, - DataTable speckleTable, - ICollection originalTableIds, - int[] columnHeaderIndexArray, - List columnHeaders - ) - { - var minHeaderIndex = columnHeaderIndexArray.Min(); - var maxHeaderIndex = columnHeaderIndexArray.Max(); - speckleTable.headerRowIndex = maxHeaderIndex; - foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) - { - var rowValues = new List(); - - if (rowInfo.masterRowIndex == maxHeaderIndex) - { - rowValues = columnHeaders; - } - else - { - rowValues = GetRowValues(revitSchedule, rowInfo.tableSection, rowInfo.columnCount, rowInfo.rowIndex); - } - - if (rowInfo.masterRowIndex >= minHeaderIndex && rowInfo.masterRowIndex < maxHeaderIndex) - { - for (var i = 0; i < rowInfo.columnCount; i++) - { - if (columnHeaderIndexArray[i] == rowInfo.masterRowIndex) - { - rowValues[i] = string.Empty; - } - } - } - - var rowAdded = AddRowToSpeckleTable( - revitSchedule, - speckleTable, - originalTableIds, - rowInfo.tableSection, - rowInfo.section, - rowValues, - rowInfo.rowIndex - ); - if (!rowAdded && rowInfo.masterRowIndex < maxHeaderIndex) - { - speckleTable.headerRowIndex--; - } - } - } - - private int[] GetTableHeaderIndexArray(ViewSchedule revitSchedule, List columnHeaders) - { - if (!revitSchedule.Definition.ShowHeaders) - { - return TransactionManager.ExecuteInTemporaryTransaction( - () => - { - revitSchedule.Definition.ShowHeaders = true; - return GetHeaderIndexArrayFromScheduleWithHeaders(revitSchedule, columnHeaders); - }, - revitSchedule.Document - ); - } - - return GetHeaderIndexArrayFromScheduleWithHeaders(revitSchedule, columnHeaders); - } - - private static int[] GetHeaderIndexArrayFromScheduleWithHeaders( - ViewSchedule revitSchedule, - List columnHeaders - ) - { - string nextCellValue = null; - var headerIndexArray = new int[columnHeaders.Count]; - var headersSetArray = new bool[columnHeaders.Count]; - foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) - { - if (rowInfo.columnCount != columnHeaders.Count) - { - continue; - } - - for (var columnIndex = 0; columnIndex < rowInfo.columnCount; columnIndex++) - { - if (headersSetArray[columnIndex]) - { - continue; - } - - var cellValue = revitSchedule.GetCellText(rowInfo.tableSection, rowInfo.rowIndex, columnIndex); - if (cellValue != columnHeaders[columnIndex]) - { - continue; - } - - headerIndexArray[columnIndex] = rowInfo.masterRowIndex; - headersSetArray[columnIndex] = true; - - if (!headersSetArray.Where(o => o == false).Any()) - { - return headerIndexArray; - } - } - } - return Enumerable.Repeat(0, columnHeaders.Count).ToArray(); - } - - private bool AddRowToSpeckleTable( - ViewSchedule revitSchedule, - DataTable speckleTable, - ICollection originalTableIds, - SectionType tableSection, - TableSectionData section, - List rowValues, - int rowIndex - ) - { - if (!rowValues.Where(s => !string.IsNullOrEmpty(s)).Any()) - { - return false; - } - var metadata = new Base(); - metadata["RevitApplicationIds"] = ElementApplicationIdsInRow( - rowIndex, - section, - originalTableIds, - revitSchedule, - tableSection - ) - .ToList(); - - try - { - speckleTable.AddRow(metadata: metadata, objects: rowValues.ToArray()); - } - catch (ArgumentException) - { - // trying to add an invalid row. Just don't add it and continue to the next - return false; - } - - return true; - } - - private static List GetRowValues( - ViewSchedule revitSchedule, - SectionType tableSection, - int columnCount, - int rowIndex - ) - { - var rowData = new List(); - for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) - { - rowData.Add(revitSchedule.GetCellText(tableSection, rowIndex, columnIndex)); - } - - return rowData; - } - #endregion - - public static IEnumerable ElementApplicationIdsInRow( - int rowNumber, - TableSectionData section, - ICollection orginialTableIds, - DB.ViewSchedule revitSchedule, - SectionType tableSection - ) - { - var remainingIdsInRow = TransactionManager.ExecuteInTemporaryTransaction( - () => - { - section.RemoveRow(rowNumber); - return new FilteredElementCollector(revitSchedule.Document, revitSchedule.Id).ToElementIds().ToList(); - }, - revitSchedule.Document - ); - - // the section must be recomputed here because of our hacky row deleting trick - var table = revitSchedule.GetTableData(); - section = table.GetSectionData(tableSection); - - if (remainingIdsInRow == null || remainingIdsInRow.Count == orginialTableIds.Count) - { - yield break; - } - - foreach (var id in orginialTableIds) - { - if (remainingIdsInRow.Contains(id)) - continue; - yield return revitSchedule.Document.GetElement(id).UniqueId; - } - } - } - - public struct RevitParameterData - { - public int ColumnIndex; - public BuiltInParameter Parameter; - public bool IsTypeParam; - } - - public struct ScheduleRowIterationInfo - { - public SectionType tableSection; - public TableSectionData section; - public int rowIndex; - public int columnCount; - public int masterRowIndex; - } - - public struct ScheduleColumnIterationInfo - { - public ScheduleField field; - public int columnIndex; - public int columnCount; - public int numHiddenFields; - } - - public static class RevitScheduleUtils - { - public static IEnumerable ScheduleRowIteration( - ViewSchedule revitSchedule, - Dictionary> skippedIndicies = null - ) - { - var masterRowIndex = 0; - - foreach (SectionType tableSection in Enum.GetValues(typeof(SectionType))) - { - // the table must be recomputed here because of our hacky row deleting trick - var table = revitSchedule.GetTableData(); - var section = table.GetSectionData(tableSection); - - if (section == null) - { - continue; - } - var rowCount = section.NumberOfRows; - var columnCount = section.NumberOfColumns; - - for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - yield return new ScheduleRowIterationInfo - { - tableSection = tableSection, - section = section, - rowIndex = rowIndex, - columnCount = columnCount, - masterRowIndex = masterRowIndex - }; - - if ( - skippedIndicies == null - || !skippedIndicies.TryGetValue(tableSection, out var indicies) - || !indicies.Contains(rowIndex) - ) - { - // this "skippedIndicies" dict contains the indicies that contain only empty values - // these values were skipped when adding them to the DataTable, so the indicies of the revitSchedule - // and the Speckle DataTable will differ at these indicies (and all subsequent indicies) - - // therefore we only want to increment the masterRowIndex if this row was added to the Speckle DataTable - masterRowIndex++; - } - } - } - } - - public static IEnumerable ScheduleColumnIteration(ViewSchedule revitSchedule) - { - var scheduleFieldOrder = revitSchedule.Definition.GetFieldOrder(); - var numHiddenFields = 0; - - for (var columnIndex = 0; columnIndex < scheduleFieldOrder.Count; columnIndex++) - { - var field = revitSchedule.Definition.GetField(scheduleFieldOrder[columnIndex]); - - // we cannot get the values for hidden fields, so we need to subtract one from the index that is passed to - // tableView.GetCellText. - if (field.IsHidden) - { - numHiddenFields++; - continue; - } - - yield return new ScheduleColumnIterationInfo - { - field = field, - columnIndex = columnIndex, - columnCount = scheduleFieldOrder.Count, - numHiddenFields = numHiddenFields - }; - } - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.cs deleted file mode 100644 index 1a74af2d7d..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertView.cs +++ /dev/null @@ -1,246 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using Autodesk.Revit.DB; -using Speckle.Core.Logging; -using Speckle.Core.Kits; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using View = Objects.BuiltElements.View; -using View3D = Objects.BuiltElements.View3D; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private List excludedParameters = new List() - { - "VIEW_NAME", // param value is already stored in name prop of view and setting this param can cause errors - }; - public Base ViewToSpeckle(DB.View revitView) - { - switch (revitView) - { - case DB.View3D o: - return View3DToSpeckle(o); - case DB.ViewSchedule o: - return ScheduleToSpeckle(o); - default: - var speckleView = new View(); - GetAllRevitParamsAndIds(speckleView, revitView, excludedParameters); - Report.Log($"Converted View {revitView.ViewType} {revitView.Id}"); - return speckleView; - } - } - public View View3DToSpeckle(DB.View3D revitView) - { - switch (revitView.ViewType) - { - case ViewType.FloorPlan: - break; - case ViewType.CeilingPlan: - break; - case ViewType.Elevation: - break; - case ViewType.Section: - break; - case ViewType.ThreeD: - break; - default: - break; - } - - var speckleView = new View(); - - if (revitView is DB.View3D rv3d) - { - // some views have null origin, not sure why, but for now we just ignore them and don't bother the user - if (rv3d.Origin == null) - throw new ConversionSkippedException($"Views with no origin are not supported"); - - // get orientation - var forward = rv3d.GetSavedOrientation().ForwardDirection; // this is unit vector - var up = rv3d.GetSavedOrientation().UpDirection; // this is unit vector - - // get target - var target = PointToSpeckle(CalculateTarget(rv3d, forward), revitView.Document); - - speckleView = new View3D - { - origin = PointToSpeckle(rv3d.Origin, revitView.Document), - forwardDirection = VectorToSpeckle(forward, revitView.Document, Speckle.Core.Kits.Units.None), - upDirection = VectorToSpeckle(up, revitView.Document, Speckle.Core.Kits.Units.None), - target = target, - isOrthogonal = !rv3d.IsPerspective, - boundingBox = BoxToSpeckle(rv3d.CropBox, revitView.Document), - name = revitView.Name - }; - - // set props - AttachViewParams(speckleView, rv3d); - } - - GetAllRevitParamsAndIds(speckleView, revitView, excludedParameters); - Report.Log($"Converted View {revitView.ViewType} {revitView.Id}"); - return speckleView; - } - - public ApplicationObject ViewToNative(View3D speckleView) - { - var appObj = new ApplicationObject(speckleView.id, speckleView.speckle_type) { applicationId = speckleView.applicationId }; - - DB.View3D view = null; - var viewNameSplit = speckleView.name.Split('-'); - - // get orientation - var up = new XYZ(speckleView.upDirection.x, speckleView.upDirection.y, speckleView.upDirection.z).Normalize(); //unit vector - var forward = new XYZ(speckleView.forwardDirection.x, speckleView.forwardDirection.y, speckleView.forwardDirection.z).Normalize(); - if (Math.Round(up.DotProduct(forward), 3) != 0) // will throw error if vectors are not perpendicular - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "The up and forward vectors for this view are not perpendicular."); - return appObj; - } - var orientation = new ViewOrientation3D(PointToNative(speckleView.origin), up, forward); - - var editViewName = EditViewName(speckleView.name, "SpeckleView"); - // get the existing view with this name, if there is one - view = new FilteredElementCollector(Doc) - .WhereElementIsNotElementType() - .OfClass(typeof(DB.View3D)) - .Cast() - .FirstOrDefault(o => o.Name == editViewName); - - if (view == null) - { - // get view3d type - var viewType = new FilteredElementCollector(Doc) - .WhereElementIsElementType() - .OfClass(typeof(ViewFamilyType)) - .ToElements() - .Cast() - .FirstOrDefault(o => o.ViewFamily == ViewFamily.ThreeDimensional); - - // create view - if (speckleView.isOrthogonal) - view = DB.View3D.CreateIsometric(Doc, viewType.Id); - else - view = DB.View3D.CreatePerspective(Doc, viewType.Id); - - view.Name = editViewName; - appObj.Update(status: ApplicationObject.State.Created); - } - else if (view.IsLocked) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"View named {editViewName} is locked and cannot be modified."); - return appObj; - } - else - appObj.Update(status: ApplicationObject.State.Updated); - - // set props - view.SetOrientation(orientation); - view.SaveOrientationAndLock(); - - if (view.IsValidObject) - SetInstanceParameters(view, speckleView, excludedParameters); - view = SetViewParams(view, speckleView); - - appObj.Update(createdId: view.UniqueId, convertedItem: view); - return appObj; - } - - private void AttachViewParams(View speckleView, DB.View view) - { - // display - speckleView["display"] = view.DisplayStyle.ToString(); - - // crop - speckleView["cropped"] = view.CropBoxActive.ToString(); - } - - private DB.View3D SetViewParams(DB.View3D view, Base speckleView) - { - // display - var display = speckleView["display"] as string; - if (display != null) - { - var style = Enum.Parse(typeof(DisplayStyle), display); - view.DisplayStyle = (style != null) ? (DisplayStyle)style : DisplayStyle.Wireframe; - } - - // crop - var crop = speckleView["cropped"] as string; - if (crop != null) - if (bool.TryParse(crop, out bool IsCropped)) - view.CropBoxActive = IsCropped; - - return view; - } - - private XYZ CalculateTarget(DB.View3D view, XYZ forward) - { - var target = view.Origin.Add(forward * (view.CropBox.Max.Z - view.CropBox.Min.Z)); - var targetElevation = view.get_Parameter(BuiltInParameter.VIEWER_TARGET_ELEVATION).AsDouble(); - if (target.Z != targetElevation) // check if target matches stored elevation - { - double magnitude = (targetElevation - view.Origin.Z) / forward.Z; - target = view.Origin.Add(forward * magnitude); - } - return target; - } - - private string EditViewName(string name, string prefix = null) - { - var viewNameSplit = name.Split('-'); - // if the name already starts with the prefix, don't add the prefix again - if (viewNameSplit.Length > 0 && viewNameSplit.First() == prefix) - return name; - - var newName = name; - // append commit info as prefix - if (prefix != null) - newName = prefix + "-" + name; - - // Check for invalid characters in view name - var results = new Regex("[\\{\\}\\[\\]\\:|;<>?`~]") - .Match(newName); - - // If none, fast exit - if (results.Length <= 0) - return newName; - - // Name contains invalid characters, replace accordingly. - var corrected = Regex.Replace(newName, "[\\{\\[]", "("); - corrected = Regex.Replace(corrected, "[\\}\\]]", ")"); - corrected = Regex.Replace(corrected, "[\\:|;<>?`~]", "-"); - - Report.Log($@"Renamed view {name} to {corrected} due to invalid characters."); - - return corrected; - } - - /// - /// Converts a Speckle comment camera coordinates into Revit's - /// First three values are the camera's position, second three the target - /// - /// - /// - public DB.ViewOrientation3D ViewOrientation3DToNative(Base baseCamera) - { - //hacky but the current comments camera is not a Base object - var speckleCamera = baseCamera["coordinates"] as List; - var position = new Objects.Geometry.Point(speckleCamera[0], speckleCamera[1], speckleCamera[2]); - var target = new Objects.Geometry.Point(speckleCamera[3], speckleCamera[4], speckleCamera[5]); - - - var cameraTarget = PointToNative(target); - var cameraPosition = PointToNative(position); - var cameraDirection = (cameraTarget.Subtract(cameraPosition)).Normalize(); - var cameraUpVector = cameraDirection.CrossProduct(XYZ.BasisZ).CrossProduct(cameraDirection); - - - return new ViewOrientation3D(cameraPosition, cameraUpVector, cameraDirection); - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWall.cs deleted file mode 100644 index 4c3449ceb5..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWall.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using RevitSharedResources.Models; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB; -using Mesh = Objects.Geometry.Mesh; -using OG = Objects.Geometry; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - // CAUTION: these strings need to have the same values as in the connector - const string StructuralWalls = "Structural Walls"; - const string ArchitecturalWalls = "Achitectural Walls"; - - public ApplicationObject WallToNative(BuiltElements.Wall speckleWall) - { - var revitWall = GetExistingElementByApplicationId(speckleWall.applicationId) as DB.Wall; - var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) - { - applicationId = speckleWall.applicationId - }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(revitWall, appObj)) - return appObj; - - if (speckleWall.baseLine == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Baseline was null"); - return appObj; - } - - var wallType = GetElementType(speckleWall, appObj, out bool isExactMatch); - if (wallType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - var baseCurve = CurveToNative(speckleWall.baseLine).get_Item(0); - - List joinSettings = new List(); - - if (Settings.ContainsKey("disallow-join") && !string.IsNullOrEmpty(Settings["disallow-join"])) - joinSettings = new List(Regex.Split(Settings["disallow-join"], @"\,\ ")); - - var levelState = ApplicationObject.State.Unknown; - double baseOffset = 0.0; - Level level = - (speckleWall.level != null) - ? ConvertLevelToRevit(speckleWall.level, out levelState) - : ConvertLevelToRevit(baseCurve, out levelState, out baseOffset); - - var structural = false; - if (speckleWall is RevitWall speckleRevitWall) - { - structural = speckleRevitWall.structural; - } - - //if it's a new element, we don't need to update certain properties - bool isUpdate = true; - if (revitWall == null) - { - isUpdate = false; - revitWall = DB.Wall.Create(Doc, baseCurve, wallType.Id, level.Id, 1, 0, false, structural); - if (joinSettings.Contains(StructuralWalls) && structural) - { - WallUtils.DisallowWallJoinAtEnd(revitWall, 0); - WallUtils.DisallowWallJoinAtEnd(revitWall, 1); - } - if (joinSettings.Contains(ArchitecturalWalls) && !structural) - { - WallUtils.DisallowWallJoinAtEnd(revitWall, 0); - WallUtils.DisallowWallJoinAtEnd(revitWall, 1); - } - } - if (revitWall == null) - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); - return appObj; - } - - //is structural update - TrySetParam(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT, structural); - - if (isExactMatch && revitWall.WallType.Name != wallType.Name) - { - revitWall.ChangeTypeId(wallType.Id); - } - - if (isUpdate) - { - // walls behave very strangly while joined - // if a wall is joined and you try to move it to a location where it isn't touching the joined wall, - // then it will move only one end of the wall and the other will stay joined - // therefore, disallow joins while changing the wall and then reallow the joins if need be - WallUtils.DisallowWallJoinAtEnd(revitWall, 0); - WallUtils.DisallowWallJoinAtEnd(revitWall, 1); - - //NOTE: updating an element location can be buggy if the baseline and level elevation don't match - //Let's say the first time an element is created its base point/curve is @ 10m and the Level is @ 0m - //the element will be created @ 0m - //but when this element is updated (let's say with no changes), it will jump @ 10m (unless there is a level change)! - //to avoid this behavior we're moving the base curve to match the level elevation - var newz = baseCurve.GetEndPoint(0).Z; - var offset = level.Elevation - newz; - var newCurve = baseCurve; - if (Math.Abs(offset) > TOLERANCE) // level and curve are not at the same height - newCurve = baseCurve.CreateTransformed(Transform.CreateTranslation(new XYZ(0, 0, offset))); - - ((LocationCurve)revitWall.Location).Curve = newCurve; - - TrySetParam(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT, level); - - // now that we've moved the wall, rejoin the wall ends - if (!joinSettings.Contains(StructuralWalls) && structural) - { - WallUtils.AllowWallJoinAtEnd(revitWall, 0); - WallUtils.AllowWallJoinAtEnd(revitWall, 1); - } - if (!joinSettings.Contains(ArchitecturalWalls) && !structural) - { - WallUtils.AllowWallJoinAtEnd(revitWall, 0); - WallUtils.AllowWallJoinAtEnd(revitWall, 1); - } - } - - if (speckleWall is RevitWall spklRevitWall) - { - if (spklRevitWall.flipped != revitWall.Flipped) - revitWall.Flip(); - - if (spklRevitWall.topLevel != null) - { - var topLevel = ConvertLevelToRevit(spklRevitWall.topLevel, out levelState); - TrySetParam(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE, topLevel); - } - else - { - TrySetParam(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM, speckleWall.height, speckleWall.units); - } - - TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, spklRevitWall.baseOffset, speckleWall.units); - TrySetParam(revitWall, BuiltInParameter.WALL_TOP_OFFSET, spklRevitWall.topOffset, speckleWall.units); - } - else - { - // Set wall unconnected height. - TrySetParam(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM, speckleWall.height, speckleWall.units); - - TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, -baseOffset); - } - - SetInstanceParameters(revitWall, speckleWall); - - var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: state, createdId: revitWall.UniqueId, convertedItem: revitWall); - - SetWallVoids(revitWall, speckleWall); - //appObj = SetHostedElements(speckleWall, revitWall, appObj); - return appObj; - } - - public Base WallToSpeckle(DB.Wall revitWall, out List notes) - { - notes = new List(); - var baseGeometry = LocationToSpeckle(revitWall); - if (baseGeometry is Geometry.Point) - return RevitElementToSpeckle(revitWall, out notes); - - RevitWall speckleWall = new RevitWall(); - speckleWall.family = revitWall.WallType.FamilyName.ToString(); - speckleWall.type = revitWall.WallType.Name; - speckleWall.baseLine = (ICurve)baseGeometry; - speckleWall.level = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT); - speckleWall.topLevel = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE); - speckleWall.height = GetParamValue(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM); - speckleWall.baseOffset = GetParamValue(revitWall, BuiltInParameter.WALL_BASE_OFFSET); - speckleWall.topOffset = GetParamValue(revitWall, BuiltInParameter.WALL_TOP_OFFSET); - speckleWall.structural = GetParamValue(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); - speckleWall.flipped = revitWall.Flipped; - - //CreateVoids(revitWall, speckleWall); - - if (revitWall.CurtainGrid is not CurtainGrid grid) - { - if (revitWall.IsStackedWall) - { - var wallMembers = revitWall.GetStackedWallMemberIds().Select(id => (Wall)revitWall.Document.GetElement(id)); - speckleWall.elements = new List(); - foreach (var wall in wallMembers) - speckleWall.elements.Add(WallToSpeckle(wall, out List stackedWallNotes)); - } - - speckleWall.displayValue = GetElementDisplayValue(revitWall); - } - else - { - speckleWall.displayValue = new List(); // avoids null value for curtain walls - AddHostedDependentElements( - revitWall, - speckleWall, - GetSubsetOfElementsInView(BuiltInCategory.OST_CurtainWallMullions, grid.GetMullionIds()).ToList() - ); - AddHostedDependentElements( - revitWall, - speckleWall, - GetSubsetOfElementsInView(BuiltInCategory.OST_CurtainWallPanels, grid.GetPanelIds()).ToList() - ); - } - - GetAllRevitParamsAndIds( - speckleWall, - revitWall, - new List - { - "WALL_USER_HEIGHT_PARAM", - "WALL_BASE_OFFSET", - "WALL_TOP_OFFSET", - "WALL_BASE_CONSTRAINT", - "WALL_HEIGHT_TYPE", - "WALL_STRUCTURAL_SIGNIFICANT" - } - ); - - GetWallVoids(speckleWall, revitWall); - GetHostedElements(speckleWall, revitWall, out List hostedNotes); - if (hostedNotes.Any()) - notes.AddRange(hostedNotes); - return speckleWall; - } - - private IEnumerable GetSubsetOfElementsInView(BuiltInCategory category, IEnumerable children) - { - if (ViewSpecificOptions == null) - { - return children; - } - - var allSubelementsInView = revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType>(out _) - .GetOrAdd( - category.ToString(), - () => - { - using var filter = new ElementCategoryFilter(category); - using var collector = new FilteredElementCollector(Doc, ViewSpecificOptions.View.Id); - - return new HashSet(collector.WhereElementIsNotElementType().WherePasses(filter).ToElementIds()); - }, - out _ - ); - - return children.Where(allSubelementsInView.Contains); - } - - //this is to prevent duplicated panels & mullions from being sent in curtain walls - //might need improvement in the future - //see https://github.com/specklesystems/speckle-sharp/issues/1197 - private List SubelementIds = new List(); - - private void GetWallVoids(Base speckleElement, Wall wall) - { -#if !REVIT2020 && !REVIT2021 - var profile = ((Sketch)Doc.GetElement(wall.SketchId))?.Profile; - - if (profile == null) - return; - - var voidsList = new List(); - for (var i = 1; i < profile.Size; i++) - { - var segments = CurveListToSpeckle(profile.get_Item(i).Cast().ToList(), wall.Document); - if (segments.segments.Count() > 2) - voidsList.Add(segments); - } - if (voidsList.Count > 0) - speckleElement["voids"] = voidsList; -#endif - } - - private void SetWallVoids(Wall wall, Base speckleElement) - { -#if !REVIT2020 && !REVIT2021 - if (speckleElement["voids"] == null || !(speckleElement["voids"] is IList voidCurves)) - return; - - if (wall.SketchId.IntegerValue == -1) - { - Doc.Regenerate(); - wall.CreateProfileSketch(); - } - else - { - // TODO: actually update the profile in order to keep the user's dimensions - wall.RemoveProfileSketch(); - wall.CreateProfileSketch(); - } - - // need to regen doc in order for the sketch to have an id - Doc.Regenerate(); - var sketch = (Sketch)Doc.GetElement(wall.SketchId); - - transactionManager.Commit(); - var sketchEditScope = new SketchEditScope(Doc, "Add profile to the sketch"); - sketchEditScope.Start(sketch.Id); - transactionManager.StartSubtransaction(); - - foreach (var obj in voidCurves) - { - if (!(obj is ICurve @void)) - continue; - - var curveArray = CurveToNative(@void, true); - Doc.Create.NewModelCurveArray(curveArray, sketch.SketchPlane); - } - if (transactionManager.Commit() != TransactionStatus.Committed) - sketchEditScope.Cancel(); - - try - { - sketchEditScope.Commit(new ErrorEater()); - } - catch (Exception ex) - { - if (sketchEditScope.IsActive) - { - sketchEditScope.Cancel(); - } - } - finally - { - transactionManager.StartSubtransaction(); - } -#endif - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWire.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWire.cs deleted file mode 100644 index e822bde06a..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertWire.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Autodesk.Revit.DB; -using ConverterRevitShared.Extensions; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using Speckle.Core.Logging; -using Speckle.Core.Models; -using Curve = Objects.Geometry.Curve; -using DB = Autodesk.Revit.DB; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject WireToNative(BuiltElements.Wire speckleWire) - { - var speckleRevitWire = speckleWire as RevitWire; - - var docObj = GetExistingElementByApplicationId(speckleWire.applicationId); - var appObj = new ApplicationObject(speckleWire.id, speckleWire.speckle_type) { applicationId = speckleWire.applicationId }; - - // skip if element already exists in doc & receive mode is set to ignore - if (IsIgnore(docObj, appObj)) - return appObj; - - var wiringType = speckleRevitWire?.wiringType == "Chamfer" - ? DB.Electrical.WiringType.Chamfer - : DB.Electrical.WiringType.Arc; - var wireType = GetElementType(speckleWire, appObj, out bool _); - if (wireType == null) - { - appObj.Update(status: ApplicationObject.State.Failed); - return appObj; - } - - // get construction points (if wire is from Revit, these are not the same as the geometry points) - var points = new List(); - if (speckleRevitWire != null) - points = PointListToNative(speckleRevitWire.constructionPoints, speckleRevitWire.units); - else - { - foreach (var segment in speckleWire.segments) - { - switch (segment) - { - case Curve curve: - points.AddRange(PointListToNative(curve.points)); - break; - case Polyline line: - points.AddRange(PointListToNative(line.value)); - break; - default: // what other curves should be supported? currently just the ones you can create from revit - appObj.Update(logItem: $"Wire segment geometry of type {segment.GetType()} not currently supported"); - break; - } - } - } - - DB.Electrical.Wire wire = null; - if (docObj != null) - { - wire = (DB.Electrical.Wire)docObj; - // if the number of vertices doesn't match, we need to create a new wire - if (wire.NumberOfVertices != points.Count) - wire = null; - } - - // update points if we can - if (wire != null) - for (var i = 0; i < wire.NumberOfVertices; i++) - { - if (points[i].IsAlmostEqualTo(wire.GetVertex(i))) - continue; // borks if we set the same point - wire.SetVertex(i, points[i]); - } - var isUpdate = wire != null; - // create a new one if there isn't one to update - wire ??= DB.Electrical.Wire.Create(Doc, wireType.Id, Doc.ActiveView.Id, - wiringType, - points, null, null); - - if (speckleRevitWire != null) - SetInstanceParameters(wire, speckleRevitWire); - else - { - appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); - return appObj; - } - - CreateSystemConnections(speckleRevitWire.Connectors, wire, receivedObjectsCache); - - var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; - appObj.Update(status: status, createdId: wire.UniqueId, convertedItem: wire); - return appObj; - } - - public BuiltElements.Wire WireToSpeckle(DB.Electrical.Wire revitWire) - { - var speckleWire = new RevitWire - { - family = revitWire.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM).AsValueString(), - type = revitWire.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString(), - wiringType = revitWire.get_Parameter(BuiltInParameter.RBS_ELEC_WIRE_TYPE).AsValueString(), - level = ConvertAndCacheLevel(revitWire.ReferenceLevel.Id, revitWire.Document) - }; - - // construction geometry for creating the wire on receive (doesn't match geometry points 🙃) - var points = new List(); - for (var i = 0; i < revitWire.NumberOfVertices; i++) - points.AddRange(PointToSpeckle(revitWire.GetVertex(i), revitWire.Document).ToList()); - speckleWire.constructionPoints = points; - - // geometry - var start = ((LocationCurve)revitWire.Location).Curve.GetEndPoint(0); - speckleWire.segments = new List(); - var view = (View)revitWire.Document.GetElement(revitWire.OwnerViewId); - var segmentList = revitWire.get_Geometry(new Options { View = view }).ToList(); - foreach (var segment in segmentList) - // transform and convert the geometry segments - switch (segment) - { - case DB.PolyLine polyLine: - var revitLine = polyLine.GetTransformed(Transform.CreateTranslation(new XYZ(0, 0, start.Z))); - var line = PolylineToSpeckle(revitLine, revitWire.Document); - speckleWire.segments.Add(line); - break; - case DB.NurbSpline nurbSpline: - var revitCurve = nurbSpline.CreateTransformed( - Transform.CreateTranslation(new XYZ(0, 0, start.Z))); - // add display value - var curve = (Curve)CurveToSpeckle(revitCurve, revitWire.Document); - var polyCoords = revitCurve.Tessellate().SelectMany(pt => PointToSpeckle(pt, revitWire.Document).ToList()).ToList(); - curve.displayValue = new Polyline(polyCoords, ModelUnits); - speckleWire.segments.Add(curve); - break; - } - - GetAllRevitParamsAndIds(speckleWire, revitWire, new List()); - foreach (var connector in revitWire.GetConnectorSet()) - { - speckleWire.Connectors.Add(ConnectorToSpeckle(connector)); - } - return speckleWire; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertZone.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertZone.cs deleted file mode 100644 index 8b2dd81fd5..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertZone.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Linq; -using Autodesk.Revit.DB; -using Objects.BuiltElements; -using Objects.BuiltElements.Revit; -using Speckle.Core.Models; -using DB = Autodesk.Revit.DB.Mechanical; -using Level = Autodesk.Revit.DB.Level; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject ZoneToNative(RevitZone speckleZone) - { - var revitZone = ConvertZoneToRevit(speckleZone, out ApplicationObject.State state); - var appObj = new ApplicationObject(speckleZone.id, speckleZone.speckle_type) - { - applicationId = speckleZone.applicationId - }; - appObj.Update(status: state, createdId: revitZone.UniqueId, convertedItem: revitZone); - return appObj; - } - - public DB.Zone ConvertZoneToRevit(RevitZone speckleZone, out ApplicationObject.State state) - { - state = ApplicationObject.State.Unknown; - - if (speckleZone == null) - return null; - - var revitZone = GetExistingZone(speckleZone); - - var targetPhase = DetermineTargetPhase(speckleZone, revitZone); - - var revitZoneLevel = ConvertLevelToRevit(speckleZone.level, out _); - if (revitZone == null) - { - DB.Zone sameNameZone = GetZoneWithSameName(speckleZone); - - if (sameNameZone != null && sameNameZone.Phase.Name == speckleZone.phaseName) - { - revitZone = sameNameZone; - } - else - { - if (sameNameZone != null) - { - Doc.Delete(sameNameZone.Id); - Doc.Regenerate(); - } - - revitZone = CreateRevitZone(revitZoneLevel, targetPhase, speckleZone.name); - } - } - else - { - revitZone.Name = speckleZone.name; - } - - SetInstanceParameters(revitZone, speckleZone); - - var getSameNameZone = GetZoneWithSameName(speckleZone); - - state = ApplicationObject.State.Updated; - - return revitZone; - } - - private DB.Zone GetExistingZone(RevitZone speckleZone) - { - return GetExistingElementByApplicationId(speckleZone.applicationId) as DB.Zone; - } - - private DB.Zone GetZoneWithSameName(RevitZone speckleZone) - { - var docZones = new FilteredElementCollector(Doc).OfClass(typeof(DB.Zone)).ToElements().Cast(); - - return docZones.FirstOrDefault(x => x.Name == speckleZone.name); - } - - public DB.Zone CreateRevitZone(Level revitZoneLevel, Phase targetPhase, string zoneName = null) - { - var newZone = Doc.Create.NewZone(revitZoneLevel, targetPhase); - - if (zoneName != null) - newZone.Name = zoneName; - Doc.Regenerate(); - return newZone; - } - - /// - /// Determines the target phase for a space based on available information. - /// - /// The Space object from the Speckle system. - /// The Space object from the Revit system. - /// The determined target Phase object. - /// - /// The method tries to determine the target phase based on the following priority: - /// 1. Phase from the Speckle space (if it exists). - /// 2. Phase from the existing Revit space (if it exists). - /// 3. Phase from the active view in Revit. - /// - private Phase DetermineTargetPhase(RevitZone speckleZone, DB.Zone revitZone) - { - // Get all phases - var phases = Doc.Phases.Cast(); - - // Determine existing space phase, if any - Phase existingZonePhase = null; - if (revitZone != null) - { - string existingZonePhaseName = revitZone.Phase.ToString(); - existingZonePhase = phases.FirstOrDefault(x => x.Name == existingZonePhaseName); - } - - // Determine active view phase - string activeViewPhaseName = Doc.ActiveView.get_Parameter(BuiltInParameter.VIEW_PHASE).AsValueString(); - var activeViewPhase = phases.FirstOrDefault(x => x.Name == activeViewPhaseName); - - // Determine target phase - // Priority: speckleSpace phase > existing space phase > active view phase - string targetPhaseName = speckleZone.phaseName; - var targetPhase = phases.FirstOrDefault(x => x.Name == targetPhaseName) ?? existingZonePhase ?? activeViewPhase; - - return targetPhase; - } - - /// - /// Handles the Revit Zone based on the provided Speckle Space and target phase. - /// - /// The Space object from the Speckle system. - /// The existing Revit Zone object. This may be modified by the method. - /// The target Phase object. - /// The Level object associated with the space. - /// The modified or newly created Revit Zone object. - private DB.Zone CreateRevitZoneIfNeeded(Space speckleSpace, DB.Zone revitZone, Phase targetPhase, Level level) - { - var zoneName = speckleSpace.zone != null ? speckleSpace.zone.name : speckleSpace.zoneName; // zoneName is the previous property retained here for backwards compatibility. - - if (revitZone == null && !string.IsNullOrEmpty(zoneName)) - { - revitZone = ConvertZoneToRevit(speckleSpace.zone, out _); - } - else if (revitZone != null && revitZone.Phase.Name != targetPhase.Name) - { - Doc.Delete(revitZone.Id); - - revitZone = string.IsNullOrEmpty(speckleSpace.zone.name) - ? ConvertZoneToRevit(speckleSpace.zone, out _) - : CreateRevitZone(level, targetPhase); - - revitZone.Name = speckleSpace.zone.name; - } - - return revitZone; - } - - public RevitZone ZoneToSpeckle(DB.Zone revitZone) - { - var speckleZone = new RevitZone - { - name = revitZone.Name, - area = GetParamValue(revitZone, BuiltInParameter.ROOM_AREA), - volume = GetParamValue(revitZone, BuiltInParameter.ROOM_VOLUME), - perimeter = GetParamValue(revitZone, BuiltInParameter.ZONE_PERIMETER), - serviceType = revitZone.ServiceType.ToString() - }; - - var level = revitZone.Spaces.Cast().Select(x => x.Level).First(); - - if (level != null) - speckleZone.level = LevelToSpeckle(level); - - GetAllRevitParamsAndIds(speckleZone, revitZone); - - // No implicit displayValue - // speckleZone.displayValue = GetElementDisplayValue(revitSpace); - - speckleZone["phaseName"] = revitZone.Phase.Name; - - return speckleZone; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/Units.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/Units.cs deleted file mode 100644 index 6bf3fed706..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/Units.cs +++ /dev/null @@ -1,258 +0,0 @@ -using Autodesk.Revit.DB; -using ConverterRevitShared.Extensions; -using RevitSharedResources.Interfaces; -using Speckle.Core.Logging; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - private string _modelUnits; - -#if REVIT2020 - public string ModelUnits - { - get - { - if (string.IsNullOrEmpty(_modelUnits)) - { - _modelUnits = UnitsToSpeckle(RevitLengthTypeId); - } - return _modelUnits; - } - } - - private DisplayUnitType _revitUnitsTypeId = DisplayUnitType.DUT_UNDEFINED; - public DisplayUnitType RevitLengthTypeId - { - get - { - if (_revitUnitsTypeId == DisplayUnitType.DUT_UNDEFINED) - { - var fo = Doc.GetUnits().GetFormatOptions(UnitType.UT_Length); - _revitUnitsTypeId = fo.DisplayUnits; - } - return _revitUnitsTypeId; - } - } - - /// - /// Converts Speckle length values to internal ones - /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToNative - /// as that takes into account the Project Base Location - /// - /// - /// - /// - public double ScaleToNative(double value, string units) - { - return UnitUtils.ConvertToInternalUnits(value, UnitsToNative(units)); - } - - /// - /// Converts Speckle length values to internal ones - /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToNative - /// as that takes into account the Project Base Location - /// - /// - /// - /// - public double ScaleToNative(double value, DisplayUnitType units) - { - return UnitUtils.ConvertToInternalUnits(value, units); - } - - /// - /// Converts internal length values to Speckle ones - /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToSpeckle - /// as that takes into account the Project Base Location - /// - /// - /// - /// - public double ScaleToSpeckle(double value) - { - return ScaleToSpeckle(value, RevitLengthTypeId); - } - - public static double ScaleToSpeckle(double value, DisplayUnitType unitType) - { - return UnitUtils.ConvertFromInternalUnits(value, unitType); - } - - public static double ScaleToSpeckle(double value, DisplayUnitType unitType, IRevitDocumentAggregateCache cache) - { - return ScaleToSpeckle(value, unitType); - } - - public static double ScaleToSpeckle(double value, string units) - { - return ScaleToSpeckle(value, UnitsToNative(units)); - } - - private string UnitsToSpeckle(DisplayUnitType type) - { - switch (type) - { - case DisplayUnitType.DUT_MILLIMETERS: - return Speckle.Core.Kits.Units.Millimeters; - case DisplayUnitType.DUT_CENTIMETERS: - return Speckle.Core.Kits.Units.Centimeters; - case DisplayUnitType.DUT_METERS: - return Speckle.Core.Kits.Units.Meters; - case DisplayUnitType.DUT_METERS_CENTIMETERS: - return Speckle.Core.Kits.Units.Meters; - case DisplayUnitType.DUT_DECIMAL_INCHES: - return Speckle.Core.Kits.Units.Inches; - case DisplayUnitType.DUT_DECIMAL_FEET: - return Speckle.Core.Kits.Units.Feet; - case DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES: - return Speckle.Core.Kits.Units.Feet; - case DisplayUnitType.DUT_FRACTIONAL_INCHES: - return Speckle.Core.Kits.Units.Inches; - default: - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{type}\" is unsupported."); - } - - } - - public static DisplayUnitType UnitsToNative(string units) - { - switch (units) - { - case Speckle.Core.Kits.Units.Millimeters: - return DisplayUnitType.DUT_MILLIMETERS; - case Speckle.Core.Kits.Units.Centimeters: - return DisplayUnitType.DUT_CENTIMETERS; - case Speckle.Core.Kits.Units.Meters: - return DisplayUnitType.DUT_METERS; - case Speckle.Core.Kits.Units.Inches: - return DisplayUnitType.DUT_DECIMAL_INCHES; - case Speckle.Core.Kits.Units.Feet: - return DisplayUnitType.DUT_DECIMAL_FEET; - default: - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); - } - } - private static string UnitsToNativeString(DisplayUnitType unitType) - { - return unitType.ToString(); - } -#else - public string ModelUnits - { - get - { - if (string.IsNullOrEmpty(_modelUnits)) - { - _modelUnits = UnitsToSpeckle(RevitLengthTypeId.TypeId); - } - return _modelUnits; - } - } - - private ForgeTypeId _revitUnitsTypeId; - public ForgeTypeId RevitLengthTypeId - { - get - { - if (_revitUnitsTypeId == null) - { - var fo = Doc.GetUnits().GetFormatOptions(SpecTypeId.Length); - _revitUnitsTypeId = fo.GetUnitTypeId(); - } - return _revitUnitsTypeId; - } - } - - public static double ScaleToNative(double value, string units) - { - if (string.IsNullOrEmpty(units)) - return value; - return UnitUtils.ConvertToInternalUnits(value, UnitsToNative(units)); - } - - private double? defaultConversionFactor; - - public double ScaleToSpeckle(double value) - { - defaultConversionFactor ??= ScaleToSpeckle(1, RevitLengthTypeId); - return value * defaultConversionFactor.Value; - } - - public static double ScaleToSpeckle(double value, string units) - { - return ScaleToSpeckle(value, UnitsToNative(units)); - } - - public static double ScaleToSpeckle(double value, ForgeTypeId forgeTypeId) - { - // our current profiling shows that the method "ConvertFromInternalUnits" is a huge bottleneck - // in the ScaleToSpeckle(double) method, but not here. This is because the former method is called - // roughly 12 times more often than this function - return UnitUtils.ConvertFromInternalUnits(value, forgeTypeId); - } - - //new units api introduced in 2021, bleah - public string UnitsToSpeckle(string typeId) - { - if (typeId == UnitTypeId.Millimeters.TypeId) - return Speckle.Core.Kits.Units.Millimeters; - else if (typeId == UnitTypeId.Centimeters.TypeId) - return Speckle.Core.Kits.Units.Centimeters; - else if (typeId == UnitTypeId.Meters.TypeId || typeId == UnitTypeId.MetersCentimeters.TypeId) - return Speckle.Core.Kits.Units.Meters; - else if (typeId == UnitTypeId.Inches.TypeId || typeId == UnitTypeId.FractionalInches.TypeId) - return Speckle.Core.Kits.Units.Inches; - else if (typeId == UnitTypeId.Feet.TypeId || typeId == UnitTypeId.FeetFractionalInches.TypeId) - return Speckle.Core.Kits.Units.Feet; - - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{typeId}\" is unsupported."); - } - - public static string UnitsToNativeString(string units) - { - return UnitsToNativeString(UnitsToNative(units)); - } - - public static string UnitsToNativeString(ForgeTypeId forgeTypeId) - { - return forgeTypeId.TypeId; - } - - public static ForgeTypeId UnitsToNative(string units) - { - var u = Speckle.Core.Kits.Units.GetUnitsFromString(units); - switch (u) - { - case Speckle.Core.Kits.Units.Millimeters: - return UnitTypeId.Millimeters; - case Speckle.Core.Kits.Units.Centimeters: - return UnitTypeId.Centimeters; - case Speckle.Core.Kits.Units.Meters: - return UnitTypeId.Meters; - case Speckle.Core.Kits.Units.Inches: - return UnitTypeId.Inches; - case Speckle.Core.Kits.Units.Feet: - return UnitTypeId.Feet; - default: - throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); - } - } -#endif - - public static bool TryGetUnitsFromString(string units, out string? result) - { - try - { - result = Speckle.Core.Kits.Units.GetUnitsFromString(units); - return !string.IsNullOrEmpty(result); - } - catch (SpeckleException) - { - result = null; - return false; - } - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/UpdateParameter.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/UpdateParameter.cs deleted file mode 100644 index c93b910e8c..0000000000 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/UpdateParameter.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Autodesk.Revit.DB; -using Objects.BuiltElements.Revit; -using Objects.Geometry; -using System.Collections.Generic; -using System.Linq; -using Speckle.Core.Helpers; -using Speckle.Core.Models; - -namespace Objects.Converter.Revit -{ - public partial class ConverterRevit - { - public ApplicationObject UpdateParameter(ParameterUpdater paramUpdater) - { - //the below does not work because ApplicationIds are stored within a stream - //try to get element using ApplicationId - //this will only work if the element has been successfully been received in Revit before - //var element = GetExistingElementByApplicationId(paramUpdater.revitId); - - var appObj = new ApplicationObject(paramUpdater.id, paramUpdater.speckle_type) - { - applicationId = paramUpdater.applicationId - }; - Element element = null; - - //try to get element using ElementId - if (int.TryParse(paramUpdater.elementId, out int intId)) - { - var elemId = new ElementId(intId); - element = Doc.GetElement(elemId); - } - - //try to get element using UniqueId - element ??= Doc.GetElement(paramUpdater.elementId); - - if (element != null) - { - SetInstanceParameters(element, paramUpdater); - appObj.Update( - status: ApplicationObject.State.Updated, - logItem: $"Successfully updated instance parameters for element {paramUpdater.elementId}" - ); - } - else - { - appObj.Update( - status: ApplicationObject.State.Failed, - logItem: $"Could not find element to update: Element Id = {paramUpdater.elementId}" - ); - } - - return appObj; - } - } -} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAdaptiveComponent.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAdaptiveComponent.cs new file mode 100644 index 0000000000..3bc9090bf5 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAdaptiveComponent.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject AdaptiveComponentToNative(AdaptiveComponent speckleAc) + { + var docObj = GetExistingElementByApplicationId(speckleAc.applicationId); + var appObj = new ApplicationObject(speckleAc.id, speckleAc.speckle_type) + { + applicationId = speckleAc.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + string familyName = speckleAc["family"] as string != null ? speckleAc["family"] as string : ""; + + var familySymbol = GetElementType(speckleAc, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (!isExactMatch) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not find adaptive component {familyName}"); + return appObj; + } + + DB.FamilyInstance revitAc = null; + var isUpdate = false; + //try update existing + if (docObj != null) + { + try + { + var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; + + // if family changed, tough luck. delete and let us create a new one. + if (familyName != revitType.FamilyName) + { + Doc.Delete(docObj.Id); + } + else + { + revitAc = (DB.FamilyInstance)docObj; + + // check for a type change + if (speckleAc.type != null && speckleAc.type != revitType.Name) + { + revitAc.ChangeTypeId(familySymbol.Id); + } + } + + isUpdate = true; + } + catch + { + //something went wrong, re-create it + } + } + + //create family instance + if (revitAc == null) + { + revitAc = AdaptiveComponentInstanceUtils.CreateAdaptiveComponentInstance(Doc, familySymbol); + } + + SetAdaptivePoints(revitAc, speckleAc.basePoints, out List notes); + AdaptiveComponentInstanceUtils.SetInstanceFlipped(revitAc, speckleAc.flipped); + + SetInstanceParameters(revitAc, speckleAc); + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitAc.UniqueId, convertedItem: revitAc, log: notes); + return appObj; + } + + private AdaptiveComponent AdaptiveComponentToSpeckle(DB.FamilyInstance revitAc) + { + var speckleAc = new AdaptiveComponent(); + + var symbol = revitAc.Document.GetElement(revitAc.GetTypeId()) as FamilySymbol; + + speckleAc.family = symbol.FamilyName; + speckleAc.type = revitAc.Document.GetElement(revitAc.GetTypeId()).Name; + + speckleAc.basePoints = GetAdaptivePoints(revitAc); + speckleAc.flipped = AdaptiveComponentInstanceUtils.IsInstanceFlipped(revitAc); + speckleAc.displayValue = GetElementDisplayValue(revitAc); + + GetAllRevitParamsAndIds(speckleAc, revitAc); + Report.Log($"Converted AdaptiveComponent {revitAc.Id}"); + return speckleAc; + } + + private void SetAdaptivePoints(DB.FamilyInstance revitAc, List points, out List notes) + { + notes = new List(); + var pointIds = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(revitAc).ToList(); + + if (pointIds.Count != points.Count) + { + notes.Add("Adaptive family error: wrong number of points supplied"); + return; + } + + //set adaptive points + for (int i = 0; i < pointIds.Count; i++) + { + var point = Doc.GetElement(pointIds[i]) as ReferencePoint; + point.Position = PointToNative(points[i]); + } + } + + private List GetAdaptivePoints(DB.FamilyInstance revitAc) + { + var pointIds = AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(revitAc).ToList(); + var points = new List(); + for (int i = 0; i < pointIds.Count; i++) + { + var point = revitAc.Document.GetElement(pointIds[i]) as ReferencePoint; + points.Add(PointToSpeckle(point.Position, revitAc.Document)); + } + return points; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalNode.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalNode.cs new file mode 100644 index 0000000000..a5e8f9cd1e --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalNode.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Objects.Structural.Geometry; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Plane = Objects.Geometry.Plane; +using Vector = Objects.Geometry.Vector; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject AnalyticalNodeToNative(Node speckleNode) + { + return new ApplicationObject(speckleNode.id, speckleNode.speckle_type) + { + applicationId = speckleNode.applicationId + }; + } + + private Node AnalyticalNodeToSpeckle(ReferencePoint revitNode) + { + var cs = revitNode.GetCoordinateSystem(); + var localAxis = new Plane( + PointToSpeckle(cs.Origin, revitNode.Document), + VectorToSpeckle(cs.BasisZ, revitNode.Document), + VectorToSpeckle(cs.BasisX, revitNode.Document), + VectorToSpeckle(cs.BasisY, revitNode.Document) + ); + var basePoint = PointToSpeckle(cs.Origin, revitNode.Document); // alternative to revitNode.Position + //var speckleNode = new Node(basePoint, revitNode.Name, null, localAxis); + var speckleNode = new Node(); + + GetAllRevitParamsAndIds(speckleNode, revitNode); + + return speckleNode; + } + + private Base BoundaryConditionsToSpeckle(BoundaryConditions revitBoundary) + { + var points = new List { }; + var nodes = new List { }; + + var cs = revitBoundary.GetDegreesOfFreedomCoordinateSystem(); + var localAxis = new Plane( + PointToSpeckle(cs.Origin, revitBoundary.Document), + VectorToSpeckle(cs.BasisZ, revitBoundary.Document), + VectorToSpeckle(cs.BasisX, revitBoundary.Document), + VectorToSpeckle(cs.BasisY, revitBoundary.Document) + ); + + var restraintType = revitBoundary.GetBoundaryConditionsType(); + var state = 0; + switch (restraintType) + { + case BoundaryConditionsType.Point: + var point = revitBoundary.Point; + points.Add(point); + state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET); // 1 fixed, 2 pinned, 3 roller, 4 user/variable + break; + case BoundaryConditionsType.Line: + var curve = revitBoundary.GetCurve(); + points.Add(curve.GetEndPoint(0)); + points.Add(curve.GetEndPoint(1)); + state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET_LINEAR); + break; + case BoundaryConditionsType.Area: + var loops = revitBoundary.GetLoops(); + foreach (var loop in loops) + { + foreach (var areaCurve in loop) + { + points.Add(areaCurve.GetEndPoint(1)); + } + } + + points = points.Distinct().ToList(); + state = GetParamValue(revitBoundary, BuiltInParameter.BOUNDARY_PARAM_PRESET_AREA); + break; + default: + break; + } + + var restraint = GetRestraintCode(revitBoundary, restraintType, state); + + foreach (var point in points) + { + var speckleNode = new Node(); + //var speckleNode = new Node(PointToSpeckle(point), null, restraint, localAxis); + + GetAllRevitParamsAndIds(speckleNode, revitBoundary); + + nodes.Add(speckleNode); + } + + var speckleBoundaryCondition = new Base(); + if (nodes.Count > 1) + { + speckleBoundaryCondition["nodes"] = nodes; + } + else + { + speckleBoundaryCondition = nodes[0]; + } + + return speckleBoundaryCondition; + } + + private Restraint GetRestraintCode(DB.Element elem, BoundaryConditionsType type, int presetState) + { + if (presetState == 0) + { + return new Restraint(RestraintType.Fixed); + } + else if (presetState == 1) + { + return new Restraint(RestraintType.Pinned); + } + else if (presetState == 2) + { + return new Restraint(RestraintType.Roller); + } + + var boundaryParams = new BuiltInParameter[] + { + BuiltInParameter.BOUNDARY_DIRECTION_X, + BuiltInParameter.BOUNDARY_DIRECTION_Y, + BuiltInParameter.BOUNDARY_DIRECTION_Z, + BuiltInParameter.BOUNDARY_DIRECTION_ROT_X, + BuiltInParameter.BOUNDARY_DIRECTION_ROT_Y, + BuiltInParameter.BOUNDARY_DIRECTION_ROT_Z + }; + + var springValueParams = new BuiltInParameter[] + { + BuiltInParameter.BOUNDARY_RESTRAINT_X, + BuiltInParameter.BOUNDARY_RESTRAINT_Y, + BuiltInParameter.BOUNDARY_RESTRAINT_Z, + BuiltInParameter.BOUNDARY_RESTRAINT_ROT_X, + BuiltInParameter.BOUNDARY_RESTRAINT_ROT_Y, + BuiltInParameter.BOUNDARY_RESTRAINT_ROT_Z, + }; + + var linSpringValueParams = new BuiltInParameter[] + { + BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_X, + BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_Y, + BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_Z, + BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_ROT_X, + }; + + var areaSpingValueParams = new BuiltInParameter[] + { + BuiltInParameter.BOUNDARY_AREA_RESTRAINT_X, + BuiltInParameter.BOUNDARY_AREA_RESTRAINT_Y, + BuiltInParameter.BOUNDARY_AREA_RESTRAINT_Z, + BuiltInParameter.BOUNDARY_LINEAR_RESTRAINT_ROT_X, + }; + + string code = ""; + var springStiffness = new double[6]; + for (int i = 0; i < boundaryParams.Length; i++) + { + var value = GetParamValue(elem, boundaryParams[i]); + switch (value) + { + case 0: + code = code + "F"; //fixed + break; + case 1: + code = code + "R"; //released + break; + case 2: + code = code + "K"; //spring + if (type == BoundaryConditionsType.Line) + { + switch (boundaryParams[i]) + { + case BuiltInParameter.BOUNDARY_DIRECTION_X: + springStiffness[i] = GetParamValue(elem, linSpringValueParams[0]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_Y: + springStiffness[i] = GetParamValue(elem, linSpringValueParams[1]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_Z: + springStiffness[i] = GetParamValue(elem, linSpringValueParams[2]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_ROT_X: + springStiffness[i] = GetParamValue(elem, linSpringValueParams[3]); // kN-m/°/m + break; + default: + springStiffness[i] = 0; + break; + } + } + else if (type == BoundaryConditionsType.Area) + { + switch (boundaryParams[i]) + { + case BuiltInParameter.BOUNDARY_DIRECTION_X: + springStiffness[i] = GetParamValue(elem, areaSpingValueParams[0]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_Y: + springStiffness[i] = GetParamValue(elem, areaSpingValueParams[1]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_Z: + springStiffness[i] = GetParamValue(elem, areaSpingValueParams[2]); // kN/m² + break; + case BuiltInParameter.BOUNDARY_DIRECTION_ROT_X: + springStiffness[i] = GetParamValue(elem, areaSpingValueParams[3]); // kN-m/°/m + break; + default: + springStiffness[i] = 0; + break; + } + } + else + { + springStiffness[i] = GetParamValue(elem, springValueParams[i]); + } + + break; + default: + return null; + } + } + + var restraint = new Restraint( + code, + springStiffness[0], + springStiffness[1], + springStiffness[2], + springStiffness[3], + springStiffness[4], + springStiffness[5] + ); + + return restraint; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalStick.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalStick.cs new file mode 100644 index 0000000000..1e96026fd4 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalStick.cs @@ -0,0 +1,786 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Autodesk.Revit.DB.Structure.StructuralSections; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Objects.Structural.Geometry; +using Objects.Structural.Materials; +using Objects.Structural.Properties; +using Objects.Structural.Properties.Profiles; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject AnalyticalStickToNative(Element1D speckleStick) + { + ApplicationObject appObj = null; + XYZ offset1 = VectorToNative(speckleStick.end1Offset ?? new Geometry.Vector(0, 0, 0)); + XYZ offset2 = VectorToNative(speckleStick.end2Offset ?? new Geometry.Vector(0, 0, 0)); + +#if REVIT2020 || REVIT2021 || REVIT2022 + appObj = CreatePhysicalMember(speckleStick); + DB.FamilyInstance physicalMember = (DB.FamilyInstance)appObj.Converted.FirstOrDefault(); + SetAnalyticalProps(physicalMember, speckleStick, offset1, offset2); +#else + var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager( + Doc + ); + + // check for existing member + var docObj = GetExistingElementByApplicationId(speckleStick.applicationId); + appObj = new ApplicationObject(speckleStick.id, speckleStick.speckle_type) + { + applicationId = speckleStick.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (speckleStick.baseLine == null) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "Only line based Analytical Members are currently supported." + ); + return appObj; + } + + var baseLine = CurveToNative(speckleStick.baseLine).get_Item(0); + DB.Level level = null; + + level ??= ConvertLevelToRevit(LevelFromCurve(baseLine), out ApplicationObject.State levelState); + var isUpdate = false; + + var familySymbol = GetElementType(speckleStick, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + AnalyticalMember revitMember = null; + DB.FamilyInstance physicalMember = null; + + if (docObj != null && docObj is AnalyticalMember analyticalMember) + { + // update location + var currentCurve = analyticalMember.GetCurve(); + var p0 = currentCurve.GetEndPoint(0); + + if (p0.DistanceTo(baseLine.GetEndPoint(0)) > p0.DistanceTo(baseLine.GetEndPoint(1))) + { + analyticalMember.SetCurve(baseLine.CreateReversed()); + } + else + { + analyticalMember.SetCurve(baseLine); + } + + if (isExactMatch) + { + //update type + if ( + familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralColumns) + || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralFraming) + ) + { + analyticalMember.SectionTypeId = familySymbol.Id; + } + isUpdate = true; + revitMember = analyticalMember; + + if (analyticalToPhysicalManager.HasAssociation(revitMember.Id)) + { + var physicalMemberId = analyticalToPhysicalManager.GetAssociatedElementId(revitMember.Id); + physicalMember = (DB.FamilyInstance)Doc.GetElement(physicalMemberId); + if (physicalMember.Symbol != familySymbol) + { + physicalMember.Symbol = familySymbol; + } + } + } + } + + //create family instance + if (revitMember == null) + { + revitMember = AnalyticalMember.Create(Doc, baseLine); + //set type + if ( + familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralColumns) + || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_StructuralFraming) + ) + { + revitMember.SectionTypeId = familySymbol.Id; + } + } + + // set or update analytical properties + SetAnalyticalProps(revitMember, speckleStick, offset1, offset2); + + // if there isn't an associated physical element to the analytical element, create it + if (!analyticalToPhysicalManager.HasAssociation(revitMember.Id)) + { + var physicalMemberAppObj = CreatePhysicalMember(speckleStick); + physicalMember = (DB.FamilyInstance)physicalMemberAppObj.Converted.FirstOrDefault(); + analyticalToPhysicalManager.AddAssociation(revitMember.Id, physicalMember.Id); + + appObj.Update(createdId: physicalMember.UniqueId, convertedItem: physicalMember); + } + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitMember.UniqueId, convertedItem: revitMember); +#endif + return appObj; + } + + private ApplicationObject CreatePhysicalMember(Element1D speckleStick) + { + ApplicationObject appObj = null; + XYZ offset1 = VectorToNative(speckleStick.end1Offset ?? new Geometry.Vector(0, 0, 0)); + XYZ offset2 = VectorToNative(speckleStick.end2Offset ?? new Geometry.Vector(0, 0, 0)); + + var propertyName = speckleStick.property?.name; + + //This only works for CSIC sections now for sure. Need to test on other sections + if (!string.IsNullOrEmpty(propertyName)) + { + propertyName = propertyName.Replace('X', 'x'); + } + + switch (speckleStick.type) + { + case ElementType1D.Beam: + RevitBeam revitBeam = new(); + revitBeam.type = propertyName; + revitBeam.baseLine = speckleStick.baseLine; +#if REVIT2020 || REVIT2021 || REVIT2022 + revitBeam.applicationId = speckleStick.applicationId; +#endif + appObj = BeamToNative(revitBeam); + + return appObj; + + case ElementType1D.Brace: + Brace speckleBrace = new(); + SetElementType(speckleBrace, propertyName); + speckleBrace.baseLine = speckleStick.baseLine; + speckleBrace.units = speckleStick.units; +#if REVIT2020 || REVIT2021 || REVIT2022 + speckleBrace.applicationId = speckleStick.applicationId; +#endif + appObj = BraceToNative(speckleBrace); + + return appObj; + + case ElementType1D.Column: + Column speckleColumn = new(); + SetElementType(speckleColumn, propertyName); + speckleColumn.baseLine = speckleStick.baseLine; + speckleColumn.units = speckleStick.units; +#if REVIT2020 || REVIT2021 || REVIT2022 + speckleColumn.applicationId = speckleStick.applicationId; +#endif + appObj = ColumnToNative(speckleColumn); + + return appObj; + } + return appObj; + } + + private void SetAnalyticalProps(Element element, Element1D element1d, XYZ offset1, XYZ offset2) + { + Func releaseConvert = rel => rel == 'R'; + +#if REVIT2020 || REVIT2021 || REVIT2022 + var analyticalModel = (AnalyticalModelStick)element.GetAnalyticalModel(); + analyticalModel.SetReleases(true, releaseConvert(element1d.end1Releases.code[0]), releaseConvert(element1d.end1Releases.code[1]), releaseConvert(element1d.end1Releases.code[2]), releaseConvert(element1d.end1Releases.code[3]), releaseConvert(element1d.end1Releases.code[4]), releaseConvert(element1d.end1Releases.code[5])); + analyticalModel.SetReleases(false, releaseConvert(element1d.end2Releases.code[0]), releaseConvert(element1d.end2Releases.code[1]), releaseConvert(element1d.end2Releases.code[2]), releaseConvert(element1d.end2Releases.code[3]), releaseConvert(element1d.end2Releases.code[4]), releaseConvert(element1d.end2Releases.code[5])); + analyticalModel.SetOffset(AnalyticalElementSelector.StartOrBase, offset1); + analyticalModel.SetOffset(AnalyticalElementSelector.EndOrTop, offset2); +#else + if (element is AnalyticalMember analyticalMember) + { + analyticalMember.SetReleaseConditions( + new ReleaseConditions( + true, + releaseConvert(element1d.end1Releases.code[0]), + releaseConvert(element1d.end1Releases.code[1]), + releaseConvert(element1d.end1Releases.code[2]), + releaseConvert(element1d.end1Releases.code[3]), + releaseConvert(element1d.end1Releases.code[4]), + releaseConvert(element1d.end1Releases.code[5]) + ) + ); + analyticalMember.SetReleaseConditions( + new ReleaseConditions( + false, + releaseConvert(element1d.end2Releases.code[0]), + releaseConvert(element1d.end2Releases.code[1]), + releaseConvert(element1d.end2Releases.code[2]), + releaseConvert(element1d.end2Releases.code[3]), + releaseConvert(element1d.end2Releases.code[4]), + releaseConvert(element1d.end2Releases.code[5]) + ) + ); + } + //TODO Set offsets +#endif + } + +#if REVIT2020 || REVIT2021 || REVIT2022 + private Element1D AnalyticalStickToSpeckle(AnalyticalModelStick revitStick) + { + if (!revitStick.IsEnabled()) + { + return new Element1D(); + } + + var speckleElement1D = new Element1D(); + switch (revitStick.Category.Name) + { + case "Analytical Columns": + speckleElement1D.type = ElementType1D.Column; + break; + case "Analytical Beams": + speckleElement1D.type = ElementType1D.Beam; + break; + case "Analytical Braces": + speckleElement1D.type = ElementType1D.Brace; + break; + default: + speckleElement1D.type = ElementType1D.Other; + break; + } + + var curves = revitStick.GetCurves(AnalyticalCurveType.RigidLinkHead).ToList(); + curves.AddRange(revitStick.GetCurves(AnalyticalCurveType.ActiveCurves)); + curves.AddRange(revitStick.GetCurves(AnalyticalCurveType.RigidLinkTail)); + + if (curves.Count > 1) + { + speckleElement1D.baseLine = null; + } + else + { + speckleElement1D.baseLine = CurveToSpeckle(curves[0], revitStick.Document) as Objects.Geometry.Line; + } + + + var coordinateSystem = revitStick.GetLocalCoordinateSystem(); + if (coordinateSystem != null) + { + speckleElement1D.localAxis = new Geometry.Plane(PointToSpeckle(coordinateSystem.Origin, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisZ, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisX, revitStick.Document), VectorToSpeckle(coordinateSystem.BasisY, revitStick.Document)); + } + + var startOffset = revitStick.GetOffset(AnalyticalElementSelector.StartOrBase); + var endOffset = revitStick.GetOffset(AnalyticalElementSelector.EndOrTop); + speckleElement1D.end1Offset = VectorToSpeckle(startOffset, revitStick.Document); + speckleElement1D.end2Offset = VectorToSpeckle(endOffset, revitStick.Document); + + SetEndReleases(revitStick, ref speckleElement1D); + + var prop = new Property1D(); + + var stickFamily = (Autodesk.Revit.DB.FamilyInstance)revitStick.Document.GetElement(revitStick.GetElementId()); + + var speckleSection = GetSectionProfile(stickFamily.Symbol); + + var structMat = (DB.Material)stickFamily.Document.GetElement(stickFamily.StructuralMaterialId); + if (structMat == null) + { + structMat = (DB.Material)stickFamily.Document.GetElement(stickFamily.Symbol.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId()); + } + + + prop.profile = speckleSection; + prop.material = GetStructuralMaterial(structMat); + prop.name = revitStick.Document.GetElement(revitStick.GetElementId()).Name; + prop.applicationId = stickFamily.Symbol.UniqueId; + + var structuralElement = revitStick.Document.GetElement(revitStick.GetElementId()); + var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); + + if (revitStick is AnalyticalModelColumn) + { + speckleElement1D.type = ElementType1D.Column; + //prop.memberType = MemberType.Column; + var locationMark = GetParamValue(structuralElement, BuiltInParameter.COLUMN_LOCATION_MARK); + if (locationMark == null) + { + speckleElement1D.name = mark; + } + else + { + speckleElement1D.name = locationMark; + } + } + else + { + prop.memberType = MemberType.Beam; + speckleElement1D.name = mark; + } + + speckleElement1D.property = prop; + + GetAllRevitParamsAndIds(speckleElement1D, revitStick); + speckleElement1D.displayValue = GetElementDisplayValue(revitStick.Document.GetElement(revitStick.GetElementId())); + return speckleElement1D; + } + +#else + private Element1D AnalyticalStickToSpeckle(AnalyticalMember revitStick) + { + var speckleElement1D = new Element1D(); + switch (revitStick.StructuralRole) + { + case AnalyticalStructuralRole.StructuralRoleColumn: + speckleElement1D.type = ElementType1D.Column; + break; + case AnalyticalStructuralRole.StructuralRoleBeam: + speckleElement1D.type = ElementType1D.Beam; + break; + case AnalyticalStructuralRole.StructuralRoleMember: + speckleElement1D.type = ElementType1D.Brace; + break; + default: + speckleElement1D.type = ElementType1D.Other; + break; + } + + speckleElement1D.baseLine = CurveToSpeckle(revitStick.GetCurve(), revitStick.Document) as Objects.Geometry.Line; + + SetEndReleases(revitStick, ref speckleElement1D); + + var prop = new Property1D(); + + var stickFamily = (Autodesk.Revit.DB.FamilySymbol)revitStick.Document.GetElement(revitStick.SectionTypeId); + + var speckleSection = GetSectionProfile(stickFamily); + + var structMat = (DB.Material)stickFamily.Document.GetElement(revitStick.MaterialId); + if (structMat == null) + { + structMat = (DB.Material) + stickFamily.Document.GetElement( + stickFamily.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId() + ); + } + + prop.profile = speckleSection; + prop.material = GetStructuralMaterial(structMat); + prop.name = stickFamily.Name; + + var mark = GetParamValue(stickFamily, BuiltInParameter.ALL_MODEL_MARK); + + //TODO: how to differenciate between column and beam? + + //if (revitStick is AnalyticalModelColumn) + //{ + // speckleElement1D.type = ElementType1D.Column; + // //prop.memberType = MemberType.Column; + // var locationMark = GetParamValue(stickFamily, BuiltInParameter.COLUMN_LOCATION_MARK); + // if (locationMark == null) + // speckleElement1D.name = mark; + // else + // speckleElement1D.name = locationMark; + //} + //else + //{ + prop.memberType = MemberType.Beam; + speckleElement1D.name = mark; + //} + + speckleElement1D.property = prop; + + GetAllRevitParamsAndIds(speckleElement1D, revitStick); + + var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager( + Doc + ); + if (analyticalToPhysicalManager.HasAssociation(revitStick.Id)) + { + var physicalElementId = analyticalToPhysicalManager.GetAssociatedElementId(revitStick.Id); + var physicalElement = Doc.GetElement(physicalElementId); + speckleElement1D.displayValue = GetElementDisplayValue(physicalElement); + } + + return speckleElement1D; + } +#endif + + private void SetEndReleases(Element revitStick, ref Element1D speckleElement1D) + { + var startRelease = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_START_RELEASE_TYPE); + var endRelease = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_END_RELEASE_TYPE); + if (startRelease == 0) + { + speckleElement1D.end1Releases = new Restraint(RestraintType.Fixed); + } + else + { + var botReleaseX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FX) == 1 ? "R" : "F"; + var botReleaseY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FY) == 1 ? "R" : "F"; + var botReleaseZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_FZ) == 1 ? "R" : "F"; + var botReleaseXX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MX) == 1 ? "R" : "F"; + var botReleaseYY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MY) == 1 ? "R" : "F"; + var botReleaseZZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_BOTTOM_RELEASE_MZ) == 1 ? "R" : "F"; + + string botReleaseCode = botReleaseX + botReleaseY + botReleaseZ + botReleaseXX + botReleaseYY + botReleaseZZ; + speckleElement1D.end1Releases = new Restraint(botReleaseCode); + } + + if (endRelease == 0) + { + speckleElement1D.end2Releases = new Restraint(RestraintType.Fixed); + } + else + { + var topReleaseX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FX) == 1 ? "R" : "F"; + var topReleaseY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FY) == 1 ? "R" : "F"; + var topReleaseZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_FZ) == 1 ? "R" : "F"; + var topReleaseXX = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MX) == 1 ? "R" : "F"; + var topReleaseYY = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MY) == 1 ? "R" : "F"; + var topReleaseZZ = GetParamValue(revitStick, BuiltInParameter.STRUCTURAL_TOP_RELEASE_MZ) == 1 ? "R" : "F"; + + string topReleaseCode = topReleaseX + topReleaseY + topReleaseZ + topReleaseXX + topReleaseYY + topReleaseZZ; + speckleElement1D.end2Releases = new Restraint(topReleaseCode); + } + } + + private SectionProfile GetSectionProfile(FamilySymbol familySymbol) + { + var revitSection = familySymbol.GetStructuralSection(); + if (revitSection == null) + { + return null; + } + + // check section profile cache + if (SectionProfiles.Keys.Contains(familySymbol.Name)) + { + return SectionProfiles[familySymbol.Name]; + } + + var speckleSection = new SectionProfile(); + + // note to future self, the StructuralSectionGeneralShape prop is sometimes null so it isn't reliable to use + // therefore switch on the object itself instead + switch (revitSection) + { + case StructuralSectionIWelded _: // Built up wide flange + case StructuralSectionIWideFlange _: // I shaped wide flange + case StructuralSectionGeneralI _: // General Double T shape + speckleSection = new ISection(); + break; + case StructuralSectionGeneralT _: // General Tee shape + speckleSection = new Tee(); + break; + case StructuralSectionGeneralH _: // Rectangular Pipe structural sections + case StructuralSectionGeneralF _: // Flat Bar structural sections + speckleSection = new Rectangular(); + break; + case StructuralSectionGeneralR _: // Pipe structural sections + case StructuralSectionGeneralS _: // Round Bar structural sections + speckleSection = new Circular(); + break; + case StructuralSectionGeneralW _: // Angle structural sections + speckleSection = new Angle(); + break; + case StructuralSectionGeneralU _: // Channel structural sections + speckleSection = new Channel(); + break; + + //case StructuralSectionGeneralLA o: + //case StructuralSectionColdFormed o: + //case StructuralSectionUserDefined o: + //case StructuralSectionGeneralLZ o: + + // keep these two last. They are last resorts + case StructuralSectionRectangular _: + speckleSection = new Rectangular(); + break; + case StructuralSectionRound _: + speckleSection = new Circular(); + break; + } + + SetStructuralSectionProps(revitSection, speckleSection); + + speckleSection.units = ModelUnits; + speckleSection.name = familySymbol.Name; + + SectionProfiles.Add(familySymbol.Name, speckleSection); + + return speckleSection; + } + + private void SetStructuralSectionProps(StructuralSection revitSection, SectionProfile speckleSection) + { + var scaleFactor = ScaleToSpeckle(1); + var scaleFactor2 = scaleFactor * scaleFactor; + + //TODO we need to support setting other units than just length + if (revitSection is StructuralSection _) + { + // static props + //TODO change this prop, Iyy can mean different things + speckleSection.Iyy = revitSection.MomentOfInertiaStrongAxis * scaleFactor2; + speckleSection.Izz = revitSection.MomentOfInertiaWeakAxis * scaleFactor2; + speckleSection.weight = revitSection.NominalWeight / scaleFactor; + speckleSection.area = revitSection.SectionArea * scaleFactor2; + speckleSection.J = revitSection.TorsionalMomentOfInertia * scaleFactor2 * scaleFactor2; + } + if (revitSection is StructuralSectionRectangular rect) + { + // these should be a static props, not dynamic ones, but we don't know the exact type of speckleSection here + // this may not be the best way to do this + speckleSection["depth"] = rect.Height * scaleFactor; + speckleSection["width"] = rect.Width * scaleFactor; + + // dynamic props + speckleSection["centroidHorizontal"] = rect.CentroidHorizontal * scaleFactor; + speckleSection["centroidVertical"] = rect.CentroidVertical * scaleFactor; + } + if (revitSection is StructuralSectionRound round) + { + // static props + speckleSection["radius"] = round.Diameter / 2 * scaleFactor; + + // dynamic props + speckleSection["centroidHorizontal"] = round.CentroidHorizontal * scaleFactor; + speckleSection["centroidVertical"] = round.CentroidVertical * scaleFactor; + } + if (revitSection is StructuralSectionHotRolled hr) + { + // static props + speckleSection["flangeThickness"] = hr.FlangeThickness * scaleFactor; + speckleSection["webThickness"] = hr.WebThickness * scaleFactor; + + // dynamic props + speckleSection["flangeThicknessLocation"] = hr.FlangeThicknessLocation * scaleFactor; + speckleSection["webThicknessLocation"] = hr.WebThicknessLocation * scaleFactor; + speckleSection["webFillet"] = hr.WebFillet; + } + if (revitSection is StructuralSectionColdFormed cf) + { + //dynamic props + speckleSection["innerFillet"] = cf.InnerFillet * scaleFactor; + speckleSection["wallThickness"] = cf.WallNominalThickness * scaleFactor; + speckleSection["wallDesignThickness"] = cf.WallDesignThickness * scaleFactor; + } + if (revitSection is StructuralSectionGeneralI i) + { + // dynamic props + speckleSection["flangeFillet"] = i.FlangeFillet; + speckleSection["slopedFlangeAngle"] = i.SlopedFlangeAngle; + //speckleSection["flangeToeOfFillet"] = i.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + //speckleSection["webToeOfFillet"] = i.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + } + if (revitSection is StructuralSectionGeneralT t) + { + speckleSection["flangeFillet"] = t.FlangeFillet; + speckleSection["slopedFlangeAngle"] = t.SlopedFlangeAngle; + speckleSection["slopedWebAngle"] = t.SlopedWebAngle; + //speckleSection["flangeToeOfFillet"] = i.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + //speckleSection["webToeOfFillet"] = i.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + } + if (revitSection is StructuralSectionGeneralH h) + { + // static props + speckleSection["webThickness"] = h.WallNominalThickness * scaleFactor; + speckleSection["flangeThickness"] = h.WallNominalThickness * scaleFactor; + + //dynamic props + speckleSection["innerFillet"] = h.InnerFillet; + speckleSection["outerFillet"] = h.OuterFillet; + } + if (revitSection is StructuralSectionGeneralR r) + { + // static props + speckleSection["wallThickness"] = r.WallNominalThickness * scaleFactor; + + //dynamic props + speckleSection["wallDesignThickness"] = r.WallDesignThickness * scaleFactor; + } + if (revitSection is StructuralSectionGeneralW w) + { + // dynamic props + speckleSection["flangeFillet"] = w.FlangeFillet; + speckleSection["topWebFillet"] = w.TopWebFillet; + } + if (revitSection is StructuralSectionGeneralU u) + { + // dynamic props + speckleSection["flangeFillet"] = u.FlangeFillet; + speckleSection["slopedFlangeAngle"] = u.SlopedFlangeAngle; + //speckleSection["flangeToeOfFillet"] = u.FlangeToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + //speckleSection["webToeOfFillet"] = u.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor + } + } + + private StructuralMaterial GetStructuralMaterial(Material material) + { + if (material == null) + { + return null; + } + + StructuralAsset materialAsset = null; + string name = null; + if (material.StructuralAssetId != ElementId.InvalidElementId) + { + materialAsset = ( + (PropertySetElement)material.Document.GetElement(material.StructuralAssetId) + ).GetStructuralAsset(); + + name = material.Document.GetElement(material.StructuralAssetId)?.Name; + } + var materialName = material.MaterialClass; + var materialType = GetMaterialType(materialName); + + var speckleMaterial = GetStructuralMaterial(materialType, materialAsset, name); + speckleMaterial.applicationId = material.UniqueId; + + return speckleMaterial; + } + + private StructuralMaterial GetStructuralMaterial( + StructuralMaterialType materialType, + StructuralAsset materialAsset, + string name + ) + { + Structural.Materials.StructuralMaterial speckleMaterial = null; + + if (materialType == StructuralMaterialType.Undefined && materialAsset != null) + { + materialType = GetMaterialType(materialAsset); + } + + name ??= materialType.ToString(); + switch (materialType) + { + case StructuralMaterialType.Concrete: + var concreteMaterial = new Concrete { name = name, materialType = Structural.MaterialType.Concrete, }; + + if (materialAsset != null) + { + concreteMaterial.compressiveStrength = materialAsset.ConcreteCompression; // Newtons per foot meter + concreteMaterial.lightweight = materialAsset.Lightweight; + } + + speckleMaterial = concreteMaterial; + break; + case StructuralMaterialType.Steel: + var steelMaterial = new Steel + { + name = name, + materialType = Structural.MaterialType.Steel, + designCode = null, + codeYear = null, + maxStrain = 0, + dampingRatio = 0, + }; + + if (materialAsset != null) + { + steelMaterial.grade = materialAsset.Name; + steelMaterial.yieldStrength = materialAsset.MinimumYieldStress; // Newtons per foot meter + steelMaterial.ultimateStrength = materialAsset.MinimumTensileStrength; // Newtons per foot meter + } + + speckleMaterial = steelMaterial; + break; + case StructuralMaterialType.Wood: + var timberMaterial = new Timber + { + name = name, + materialType = Structural.MaterialType.Timber, + designCode = null, + codeYear = null, + dampingRatio = 0 + }; + + if (materialAsset != null) + { + timberMaterial.grade = materialAsset.WoodGrade; + timberMaterial.species = materialAsset.WoodSpecies; + timberMaterial["bendingStrength"] = materialAsset.WoodBendingStrength; + timberMaterial["parallelCompressionStrength"] = materialAsset.WoodParallelCompressionStrength; + timberMaterial["parallelShearStrength"] = materialAsset.WoodParallelShearStrength; + timberMaterial["perpendicularCompressionStrength"] = materialAsset.WoodPerpendicularCompressionStrength; + timberMaterial["perpendicularShearStrength"] = materialAsset.WoodPerpendicularShearStrength; + } + + speckleMaterial = timberMaterial; + break; + default: + var defaultMaterial = new Objects.Structural.Materials.StructuralMaterial { name = name, }; + speckleMaterial = defaultMaterial; + break; + } + + // TODO: support non-isotropic materials + if (materialAsset != null) + { + // some of these are actually the dumbest units I've ever heard of + speckleMaterial.elasticModulus = materialAsset.YoungModulus.X; // Newtons per foot meter + speckleMaterial.poissonsRatio = materialAsset.PoissonRatio.X; // Unitless + speckleMaterial.shearModulus = materialAsset.ShearModulus.X; // Newtons per foot meter + speckleMaterial.density = materialAsset.Density; // kilograms per cubed feet + speckleMaterial.thermalExpansivity = materialAsset.ThermalExpansionCoefficient.X; // inverse Kelvin + } + + return speckleMaterial; + } + + private StructuralMaterialType GetMaterialType(string materialName) + { + StructuralMaterialType materialType = StructuralMaterialType.Undefined; + switch (materialName.ToLower()) + { + case "concrete": + materialType = StructuralMaterialType.Concrete; + break; + case "steel": + materialType = StructuralMaterialType.Steel; + break; + case "wood": + materialType = StructuralMaterialType.Wood; + break; + } + + return materialType; + } + + private StructuralMaterialType GetMaterialType(StructuralAsset materialAsset) + { + StructuralMaterialType materialType = StructuralMaterialType.Undefined; + switch (materialAsset?.StructuralAssetClass) + { + case StructuralAssetClass.Metal: + materialType = StructuralMaterialType.Steel; + break; + case StructuralAssetClass.Concrete: + materialType = StructuralMaterialType.Concrete; + break; + case StructuralAssetClass.Wood: + materialType = StructuralMaterialType.Wood; + break; + } + + return materialType; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalSurface.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalSurface.cs new file mode 100644 index 0000000000..415b0dcaf8 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertAnalyticalSurface.cs @@ -0,0 +1,436 @@ +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using ConverterRevitShared.Models; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Properties; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public Objects.Geometry.Line GetBottomLine(List nodes) + { + Objects.Geometry.Line baseLine = new(); + double lowest_elv = nodes.Min(nodes => nodes.basePoint.z); + List nodes1 = nodes.FindAll(node => node.basePoint.z.Equals(lowest_elv)); + if (nodes1.Count == 2) + { + var point1 = nodes1[0].basePoint; + var point2 = nodes1[1].basePoint; + baseLine = new Geometry.Line(point1, point2, point1.units); + return baseLine; + } + return null; + } + + public Objects.Geometry.Polycurve PolycurveFromTopology(List nodes) + { + Polycurve polycurve = new(); + foreach (int index in Enumerable.Range(0, nodes.Count)) + { + if (index == nodes.Count - 1) + { + var point1 = nodes[index].basePoint; + var point2 = nodes[0].basePoint; + Geometry.Line segment = new(point1, point2, point1.units); + polycurve.segments.Add(segment); + } + else + { + var point1 = nodes[index].basePoint; + var point2 = nodes[index + 1].basePoint; + Geometry.Line segment = new(point1, point2, point1.units); + polycurve.segments.Add(segment); + } + } + return polycurve; + } + + public ApplicationObject AnalyticalSurfaceToNative(Element2D speckleElement) + { + var appObj = new ApplicationObject(speckleElement.id, speckleElement.speckle_type) + { + applicationId = speckleElement.applicationId + }; + if (speckleElement.property is not Property2D prop2D) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "\"Property\" cannot be null"); + return appObj; + } + +#if REVIT2020 || REVIT2021 || REVIT2022 + appObj = CreatePhysicalMember(speckleElement); + // TODO: set properties? +#else + var elementType = GetElementType(speckleElement, appObj, out bool isExactMatch); + if (elementType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager( + Doc + ); + + // check for existing member + var docObj = GetExistingElementByApplicationId(speckleElement.applicationId); + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + AnalyticalPanel revitMember = null; + DB.Element physicalMember = null; + var isUpdate = false; + + if (docObj != null && docObj is AnalyticalPanel analyticalMember) + { + isUpdate = true; + revitMember = analyticalMember; + + // TODO check if there are openings in the panel + var polycurve = PolycurveFromTopology(speckleElement.topology); + var curveArray = CurveToNative(polycurve, true); + var curveLoop = CurveArrayToCurveLoop(curveArray); + analyticalMember.SetOuterContour(curveLoop); + + if (isExactMatch && analyticalToPhysicalManager.HasAssociation(revitMember.Id)) + { + //update type + var physicalMemberId = analyticalToPhysicalManager.GetAssociatedElementId(revitMember.Id); + physicalMember = Doc.GetElement(physicalMemberId); + + if (physicalMember.GetTypeId() != elementType.Id) + { + // collect info about current floor location and depth + var currentType = Doc.GetElement(physicalMember.GetTypeId()); + var currentTypeDepth = GetParamValue( + currentType, + BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM + ); + var currentHeightOffset = GetParamValue( + physicalMember, + BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM + ); + + // change type + physicalMember.ChangeTypeId(elementType.Id); + + // make sure that the bottom of the floor remains in the same location + var newTypeDepth = GetParamValue(elementType, BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM); + TrySetParam( + physicalMember, + BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM, + currentHeightOffset + (newTypeDepth - currentTypeDepth) + ); + } + } + } + + //create analytical panel (floor or wall) + if (revitMember == null) + { + var polycurve = PolycurveFromTopology(speckleElement.topology); + var curveArray = CurveToNative(polycurve, true); + var curveLoop = CurveArrayToCurveLoop(curveArray); + revitMember = AnalyticalPanel.Create(Doc, curveLoop); + } + + // if there isn't an associated physical element to the analytical element, create it + if (!analyticalToPhysicalManager.HasAssociation(revitMember.Id)) + { + var physicalMemberAppObj = CreatePhysicalMember(speckleElement); + physicalMember = (DB.Element)physicalMemberAppObj.Converted.FirstOrDefault(); + analyticalToPhysicalManager.AddAssociation(revitMember.Id, physicalMember.Id); + + appObj.Update(createdId: physicalMember.UniqueId, convertedItem: physicalMember); + } + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitMember.UniqueId, convertedItem: revitMember); + +#endif + return appObj; + } + + private ApplicationObject CreatePhysicalMember(Element2D speckleElement) + { + var appObj = new ApplicationObject(speckleElement.id, speckleElement.speckle_type); + if (!(speckleElement.property is Property2D prop2D)) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "\"Property\" cannot be null"); + return appObj; + } + + switch (prop2D.type) + { + case Structural.PropertyType2D.Wall: + var baseline = GetBottomLine(speckleElement.topology); + var lowestElvevation = speckleElement.topology.Min(node => node.basePoint.z); + var topElevation = speckleElement.topology.Max(node => node.basePoint.z); + var bottomNode = speckleElement.topology.Find(node => node.basePoint.z == lowestElvevation); + var topNode = speckleElement.topology.Find(node => node.basePoint.z == topElevation); + var bottemLevel = LevelFromPoint(PointToNative(bottomNode.basePoint)); + var topLevel = LevelFromPoint(PointToNative(topNode.basePoint)); + var revitWall = new RevitWall( + speckleElement.property.name, + speckleElement.property.name, + baseline, + bottemLevel, + topLevel + ); +#if REVIT2020 || REVIT2021 || REVIT2022 + revitWall.applicationId = speckleElement.applicationId; +#endif + return WallToNative(revitWall); + + default: + var polycurve = PolycurveFromTopology(speckleElement.topology); + var level = LevelFromPoint(PointToNative(speckleElement.topology[0].basePoint)); + var speckleFloor = new BuiltElements.Floor(polycurve); + SetElementType(speckleFloor, speckleElement.property.name); +#if REVIT2020 || REVIT2021 || REVIT2022 + speckleFloor.applicationId = speckleElement.applicationId; +#endif + return FloorToNative(speckleFloor); + } + } + +#if REVIT2020 || REVIT2021 || REVIT2022 + private Element2D AnalyticalSurfaceToSpeckle(AnalyticalModelSurface revitSurface) + { + if (!revitSurface.IsEnabled()) + { + return new Element2D(); + } + + var speckleElement2D = new Element2D(); + var structuralElement = revitSurface.Document.GetElement(revitSurface.GetElementId()); + var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); + speckleElement2D.name = mark; + + var openings = GetOpeningsAsPolylineFromSurface(revitSurface).ToList(); + var edgePoints = GetSurfaceOuterLoop(revitSurface).ToList(); + + Element2DOutlineBuilder outlineBuilder = new(openings, edgePoints); + + speckleElement2D.openings = openings.Select(polyLine => new Polycurve(ModelUnits) + { + segments = new() { polyLine } + }) + .ToList(); + + speckleElement2D.topology = outlineBuilder + .GetOutline() + .Select(p => new Node(p)) + .ToList(); + + speckleElement2D.displayValue = GetElementDisplayValue(revitSurface); + + var prop = new Property2D(); + + // Material + DB.Material structMaterial = null; + double thickness = 0; + var memberType = MemberType2D.Generic2D; + + if (structuralElement is DB.Floor) + { + var floor = structuralElement as DB.Floor; + structMaterial = floor.Document.GetElement(floor.FloorType.StructuralMaterialId) as DB.Material; + thickness = GetParamValue(structuralElement, BuiltInParameter.STRUCTURAL_FLOOR_CORE_THICKNESS); + memberType = MemberType2D.Slab; + } + else if (structuralElement is DB.Wall) + { + var wall = structuralElement as DB.Wall; + structMaterial = wall.Document.GetElement(wall.WallType.get_Parameter(BuiltInParameter.STRUCTURAL_MATERIAL_PARAM).AsElementId()) as DB.Material; + thickness = ScaleToSpeckle(wall.WallType.Width); + memberType = MemberType2D.Wall; + } + + var speckleMaterial = GetStructuralMaterial(structMaterial); + + prop.material = speckleMaterial; + + prop.name = revitSurface.Document.GetElement(revitSurface.GetElementId()).Name; + //prop.type = memberType; + //prop.analysisType = Structural.AnalysisType2D.Shell; + prop.thickness = thickness; + + speckleElement2D.property = prop; + + GetAllRevitParamsAndIds(speckleElement2D, revitSurface); + + return speckleElement2D; + } + + private IEnumerable GetSurfaceOuterLoop(AnalyticalModelSurface surface) + { + IList loops = surface.GetLoops(AnalyticalLoopType.External); + foreach (XYZ xyz in EnumerateCurveLoopWithMostPoints(loops)) + { + yield return PointToSpeckle(xyz, surface.Document); + } + } + + private IEnumerable GetOpeningsAsPolylineFromSurface(AnalyticalModelSurface surface) + { + surface.GetOpenings(out ICollection openingIds); + foreach (ElementId openingId in openingIds) + { + foreach (CurveLoop loop in surface.GetOpeningLoops(openingId)) + { + IEnumerable points = EnumerateCurveLoopAsPoints(loop); + List coordinateList = points + .Select(p => PointToSpeckle(p, surface.Document)) + .SelectMany(specklePoint => specklePoint.ToList()) + .ToList(); + + // add back first point to close the polyline + coordinateList.Add(coordinateList[0]); + coordinateList.Add(coordinateList[1]); + coordinateList.Add(coordinateList[2]); + yield return new Polyline(coordinateList, ModelUnits); + } + } + } + + /// + /// Revit walls and floors can have multiple different areas that are part of the same wall. + /// This isn't currently supported by our object model, and currently it is not possible to return multiple + /// floors from floorToNative, so right now we're just converting the area that has the most line segments + /// + /// + /// + IEnumerable EnumerateCurveLoopWithMostPoints(IEnumerable curveLoops) + { + List curveLoopList = curveLoops.ToList(); + Dictionary loopCounts = new(); + foreach (var loop in curveLoopList) + { + loopCounts.Add(loop, loop.Count()); + } + + CurveLoop largestLoop = loopCounts.OrderByDescending(kvp => kvp.Value).First().Key; + return EnumerateCurveLoopAsPoints(largestLoop); + } + + IEnumerable EnumerateCurveLoopAsPoints(CurveLoop loop) + { + foreach (var curve in loop) + { + var points = curve.Tessellate(); + // here we are skipping the first point each time because + // it is always the same as the last point of the previous curve + foreach (var point in points.Skip(1)) + { + yield return point; + } + } + } +#else + private Element2D AnalyticalSurfaceToSpeckle(AnalyticalPanel revitSurface) + { + var speckleElement2D = new Element2D(); + + var structuralElement = revitSurface; + + var mark = GetParamValue(structuralElement, BuiltInParameter.ALL_MODEL_MARK); + speckleElement2D.name = mark; + + var edgeNodes = new List { }; + var loops = revitSurface.GetOuterContour(); + + var displayLine = new Polycurve(); + foreach (var loop in loops) + { + var coor = new List(); + + var points = loop.Tessellate(); + + foreach (var p in points.Skip(1)) + { + var vertex = PointToSpeckle(p, revitSurface.Document); + var edgeNode = new Node(vertex, null, null, null); + edgeNodes.Add(edgeNode); + } + + displayLine.segments.Add(CurveToSpeckle(loop, revitSurface.Document)); + } + + speckleElement2D.topology = edgeNodes; + var analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager( + Doc + ); + if (analyticalToPhysicalManager.HasAssociation(revitSurface.Id)) + { + var physicalElementId = analyticalToPhysicalManager.GetAssociatedElementId(revitSurface.Id); + var physicalElement = Doc.GetElement(physicalElementId); + speckleElement2D.displayValue = GetElementDisplayValue(physicalElement); + } + + speckleElement2D.openings = GetOpenings(revitSurface); + + var prop = new Property2D(); + + // Material + DB.Material structMaterial = null; + double thickness = 0; + var memberType = MemberType2D.Generic2D; + + if (structuralElement.StructuralRole is AnalyticalStructuralRole.StructuralRoleFloor) + { + structMaterial = structuralElement.Document.GetElement(structuralElement.MaterialId) as DB.Material; + thickness = structuralElement.Thickness; + memberType = MemberType2D.Slab; + } + else if (structuralElement.StructuralRole is AnalyticalStructuralRole.StructuralRoleWall) + { + structMaterial = structuralElement.Document.GetElement(structuralElement.MaterialId) as DB.Material; + thickness = structuralElement.Thickness; + memberType = MemberType2D.Wall; + } + + var speckleMaterial = GetStructuralMaterial(structMaterial); + prop.material = speckleMaterial; + + prop.name = structuralElement.Name; + //prop.type = memberType; + //prop.analysisType = Structural.AnalysisType2D.Shell; + prop.thickness = thickness; + + speckleElement2D.property = prop; + + GetAllRevitParamsAndIds(speckleElement2D, revitSurface); + + return speckleElement2D; + } + + private List GetOpenings(AnalyticalPanel revitSurface) + { + var openings = new List(); + foreach (var openingId in revitSurface.GetAnalyticalOpeningsIds()) + { + if (revitSurface.Document.GetElement(openingId) is not AnalyticalOpening opening) + { + continue; + } + + var curveLoop = opening.GetOuterContour(); + openings.Add(CurveLoopToSpeckle(curveLoop, revitSurface.Document)); + } + return openings; + } +#endif +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertArea.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertArea.cs new file mode 100644 index 0000000000..7d3e199be0 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertArea.cs @@ -0,0 +1,70 @@ +using System.Linq; +using Autodesk.Revit.DB; +using DB = Autodesk.Revit.DB; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + //public List AreaToNative(BuiltElements.Area speckleArea) + //{ + // var revitRoom = GetExistingElementByApplicationId(speckleArea.applicationId) as DB.Area; + // var level = LevelToNative(speckleArea.level); + + + // //TODO: support updating rooms + // if (revitRoom != null) + // { + // Doc.Delete(revitRoom.Id); + // } + + // revitRoom = Doc.Create.NewArea(level, new UV(speckleArea.center.x, speckleArea.center.y)); + + // revitRoom.Name = speckleArea.name; + // revitRoom.Number = speckleArea.number; + + // SetInstanceParameters(revitRoom, speckleArea); + + // var placeholders = new List() + // { + // new ApplicationObject + // { + // applicationId = speckleArea.applicationId, + // ApplicationGeneratedId = revitRoom.UniqueId, + // NativeObject = revitRoom + // } + // }; + + // return placeholders; + + //} + + public BuiltElements.Area AreaToSpeckle(DB.Area revitArea) + { + var profiles = GetProfiles(revitArea); + + var speckleArea = new BuiltElements.Area(); + + speckleArea.name = revitArea.get_Parameter(BuiltInParameter.ROOM_NAME).AsString(); + speckleArea.number = revitArea.Number; + speckleArea.center = (Point)LocationToSpeckle(revitArea); + speckleArea.level = ConvertAndCacheLevel(revitArea, BuiltInParameter.ROOM_LEVEL_ID); + if (profiles.Any()) + { + speckleArea.outline = profiles[0]; + } + + speckleArea.area = GetParamValue(revitArea, BuiltInParameter.ROOM_AREA); + if (profiles.Count > 1) + { + speckleArea.voids = profiles.Skip(1).ToList(); + } + + GetAllRevitParamsAndIds(speckleArea, revitArea); + + //no mesh seems to be retriavable, not even using the SpatialElementGeometryCalculator + //speckleArea.displayValue = GetElementDisplayValue(revitArea); + return speckleArea; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBeam.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBeam.cs new file mode 100644 index 0000000000..5fd6f2e476 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBeam.cs @@ -0,0 +1,165 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + // CAUTION: this string needs to have the same values as in the connector + const string StructuralFraming = "Structural Framing"; + + public ApplicationObject BeamToNative(Beam speckleBeam, StructuralType structuralType = StructuralType.Beam) + { + var docObj = GetExistingElementByApplicationId(speckleBeam.applicationId); + var appObj = new ApplicationObject(speckleBeam.id, speckleBeam.speckle_type) + { + applicationId = speckleBeam.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (speckleBeam.baseLine == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Only line based Beams are currently supported."); + return appObj; + } + + var familySymbol = GetElementType(speckleBeam, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var baseLine = CurveToNative(speckleBeam.baseLine).get_Item(0); + + var levelState = ApplicationObject.State.Unknown; + double baseOffset = 0.0; + DB.Level level = + (speckleBeam.level != null) + ? ConvertLevelToRevit(speckleBeam.level, out levelState) + : ConvertLevelToRevit(baseLine, out levelState, out baseOffset); + + //comes from revit or schema builder, has these props + var speckleRevitBeam = speckleBeam as RevitBeam; + if (speckleRevitBeam != null) + { + if (level != null) + { + level = GetLevelByName(speckleRevitBeam.level.name); + } + } + + DB.FamilyInstance revitBeam = null; + + var isUpdate = false; + + if (docObj != null) + { + try + { + var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; + + // if family changed, tough luck. delete and let us create a new one. + if (familySymbol.FamilyName != revitType.FamilyName) + { + Doc.Delete(docObj.Id); + } + else + { + revitBeam = (DB.FamilyInstance)docObj; + + // if we combine the following two statements, it results in an error that the beam is unable to be + // bent into position. For some reason separating the curve variable declaration and the curve setting + // fixes this issue. I'm not sure if this is a permanent fix. If not, then I think the solution is to + // disassociate the beam from the current workplane and then setting the new curve + var existingCurve = (revitBeam.Location as LocationCurve).Curve; + existingCurve = baseLine; + + // check for a type change + if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) + { + revitBeam.ChangeTypeId(familySymbol.Id); + } + } + isUpdate = true; + } + catch + { + //something went wrong, re-create it + } + } + + //create family instance + if (revitBeam == null) + { + revitBeam = Doc.Create.NewFamilyInstance(baseLine, familySymbol, level, structuralType); + // check for disallow join for beams in user settings + // currently, this setting only applies to beams being created + + if (Settings.ContainsKey("disallow-join") && !string.IsNullOrEmpty(Settings["disallow-join"])) + { + List joinSettings = new(Regex.Split(Settings["disallow-join"], @"\,\ ")); + if (joinSettings.Contains(StructuralFraming)) + { + StructuralFramingUtils.DisallowJoinAtEnd(revitBeam, 0); + StructuralFramingUtils.DisallowJoinAtEnd(revitBeam, 1); + } + } + } + + //reference level, only for beams + TrySetParam(revitBeam, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM, level); + + if (speckleRevitBeam != null) + { + SetInstanceParameters(revitBeam, speckleRevitBeam); + } + else + { + TrySetParam(revitBeam, BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM, -baseOffset); + } + + // TODO: get sub families, it's a family! + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitBeam.UniqueId, convertedItem: revitBeam); + //appObj = SetHostedElements(speckleBeam, revitBeam, appObj); + return appObj; + } + + private Base BeamToSpeckle(DB.FamilyInstance revitBeam, out List notes) + { + notes = new List(); + var baseGeometry = LocationToSpeckle(revitBeam); + var baseLine = baseGeometry as ICurve; + if (baseLine == null) + { + notes.Add($"Beam has no valid baseline, converting as generic element"); + return RevitElementToSpeckle(revitBeam, out notes); + } + var symbol = revitBeam.Document.GetElement(revitBeam.GetTypeId()) as FamilySymbol; + + var speckleBeam = new RevitBeam(); + speckleBeam.family = symbol.FamilyName; + speckleBeam.type = revitBeam.Document.GetElement(revitBeam.GetTypeId()).Name; + speckleBeam.baseLine = baseLine; + speckleBeam.level = ConvertAndCacheLevel(revitBeam, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); + + speckleBeam.displayValue = GetElementDisplayValue(revitBeam); + + GetAllRevitParamsAndIds(speckleBeam, revitBeam); + + return speckleBeam; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBlock.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBlock.cs similarity index 99% rename from Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBlock.cs rename to Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBlock.cs index f0cca29564..0543ae3a7a 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertBlock.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBlock.cs @@ -31,7 +31,10 @@ public ApplicationObject MappedBlockWrapperToNative(MappedBlockWrapper blockWrap { blockWrapper.instance.typedDefinition["category"] = blockWrapper.category; if (blockWrapper.nameOverride != null) + { blockWrapper.instance.typedDefinition.name = blockWrapper.nameOverride; + } + return BlockInstanceToNative(blockWrapper.instance); } @@ -48,7 +51,9 @@ public ApplicationObject BlockInstanceToNative(BlockInstance instance) // skip if element already exists in doc & receive mode is set to ignore if (IsIgnore(docObj, appObj)) + { return appObj; + } var isUpdate = false; if (docObj != null && ReceiveMode == ReceiveMode.Update) @@ -183,13 +188,17 @@ private static void AssignCategoryToFamilyDoc(DB.Document famDoc, string? catego // Get the RevitCategory from a string value var success = Enum.TryParse(categoryName, out RevitFamilyCategory cat); if (!success) + { cat = RevitFamilyCategory.GenericModel; + } // Get the BuiltInCategory corresponding to the RevitCategory var catName = Categories.GetBuiltInFromSchemaBuilderCategory(cat); success = Enum.TryParse(catName, out DB.BuiltInCategory bic); if (!success) + { bic = DB.BuiltInCategory.OST_GenericModel; + } // Get the actual category from the document DB.Category familyCategory = famDoc.Settings.Categories.get_Item(bic); @@ -228,7 +237,10 @@ private static void PopulateFamilyWithBlockDefinitionGeometry(DB.Document famDoc using DB.Transaction t = new(famDoc, $"Create geometry for block definition"); t.Start(); foreach (var o in geometry) + { converter.ConvertToNativeObject(o); + } + t.Commit(); } @@ -247,9 +259,15 @@ private static void PopulateFamilyWithBlockDefinitionGeometry(DB.Document famDoc // TODO: For now, we're just picking the first. var element = Doc.GetElement(family.GetFamilySymbolIds().First()); if (element is not DB.FamilySymbol symbol) + { return null; + } + if (!symbol.IsActive) + { symbol.Activate(); + } + return symbol; } @@ -277,7 +295,10 @@ private DB.Document CreateNewFamilyTemplateDoc(string name = "Block") { var templatePath = GetTemplatePath(name); if (!File.Exists(templatePath)) + { throw new FileNotFoundException($"Could not find '{name}.rft' template file - {templatePath}"); + } + return Doc.Application.NewFamilyDocument(templatePath); } @@ -307,8 +328,12 @@ private DB.Document CreateNewFamilyTemplateDoc(string name = "Block") var families = collector.OfClass(typeof(DB.Family)).ToElements(); foreach (DB.Element elem in families) + { if (elem is DB.Family fam && fam.Name == familyName) + { return fam; // Cast to Family and return if the names match + } + } return null; // Return null if not found } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs new file mode 100644 index 0000000000..0613b4d8ab --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs @@ -0,0 +1,63 @@ +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject BraceToNative(Brace speckleBrace) + { + //reuse ConversionLog.Addic in Beam class, at these are basically the same thing + if (speckleBrace is RevitBrace rb) + { + var speckleBeam = new RevitBeam + { + baseLine = rb.baseLine, + type = rb.type, + level = rb.level, + family = rb.family, + parameters = rb.parameters, + applicationId = rb.applicationId, + }; + + return BeamToNative(speckleBeam, StructuralType.Brace); + } + else + { + var speckleBeam = new Beam(); + speckleBeam.baseLine = speckleBrace.baseLine; + speckleBeam.applicationId = speckleBrace.applicationId; + return BeamToNative(speckleBeam, StructuralType.Brace); + } + } + + private Base BraceToSpeckle(DB.FamilyInstance myFamily, out List notes) + { + notes = new List(); + var myBeam = BeamToSpeckle(myFamily, out notes) as RevitBeam; + + var myBrace = new RevitBrace() + { + applicationId = myBeam.applicationId, + type = myBeam.type, + baseLine = myBeam.baseLine, + level = myBeam.level, + family = myBeam.family, + parameters = myBeam.parameters, + displayValue = myBeam.displayValue, + }; + + var dynamicProps = myBeam.GetMembers(DynamicBaseMemberType.Dynamic); + + foreach (var dp in dynamicProps) + { + myBrace[dp.Key] = dp.Value; + } + + return myBrace; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBuildingPad.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBuildingPad.cs new file mode 100644 index 0000000000..d512ee597a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBuildingPad.cs @@ -0,0 +1,32 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB.Architecture; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + //NOTE: BuildingPad cannot be created from the API AFAIK + private BuildingPad BuildingPadToSpeckle(DB.BuildingPad revitPad) + { + var profiles = GetProfiles(revitPad); + + var specklePad = new BuildingPad(); + specklePad.type = revitPad.Document.GetElement(revitPad.GetTypeId()).Name; + specklePad.outline = profiles[0]; + if (profiles.Count > 1) + { + specklePad.voids = profiles.Skip(1).ToList(); + } + + specklePad.level = ConvertAndCacheLevel(revitPad, BuiltInParameter.LEVEL_PARAM); + + GetAllRevitParamsAndIds(specklePad, revitPad, new List { "LEVEL_PARAM" }); + + specklePad.displayValue = GetElementDisplayValue(revitPad); + + return specklePad; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCableTray.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCableTray.cs new file mode 100644 index 0000000000..cab6afeb13 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCableTray.cs @@ -0,0 +1,137 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Electrical; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject CableTrayToNative(BuiltElements.CableTray speckleCableTray) + { + var speckleRevitCableTray = speckleCableTray as RevitCableTray; + + var docObj = GetExistingElementByApplicationId((speckleCableTray).applicationId); + var appObj = new ApplicationObject(speckleCableTray.id, speckleCableTray.speckle_type) + { + applicationId = speckleCableTray.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + var cableTrayType = GetElementType(speckleCableTray, appObj, out bool _); + if (cableTrayType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + Element cableTray = null; + if (speckleCableTray.baseCurve is Line) + { + DB.Line baseLine = LineToNative(speckleCableTray.baseCurve as Line); + XYZ startPoint = baseLine.GetEndPoint(0); + XYZ endPoint = baseLine.GetEndPoint(1); + DB.Level lineLevel = ConvertLevelToRevit( + speckleRevitCableTray != null ? speckleRevitCableTray.level : LevelFromCurve(baseLine), + out ApplicationObject.State levelState + ); + CableTray lineCableTray = CableTray.Create(Doc, cableTrayType.Id, startPoint, endPoint, lineLevel.Id); + cableTray = lineCableTray; + } + else + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"BaseCurve of type ${speckleCableTray.baseCurve.GetType()} cannot be used to create a Revit CableTray" + ); + return appObj; + } + + // deleting instead of updating for now! + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + if (speckleRevitCableTray != null) + { + TrySetParam( + cableTray, + BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM, + speckleRevitCableTray.height, + speckleRevitCableTray.units + ); + TrySetParam( + cableTray, + BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM, + speckleRevitCableTray.width, + speckleRevitCableTray.units + ); + TrySetParam( + cableTray, + BuiltInParameter.CURVE_ELEM_LENGTH, + speckleRevitCableTray.length, + speckleRevitCableTray.units + ); + SetInstanceParameters(cableTray, speckleRevitCableTray); + } + + CreateSystemConnections(speckleRevitCableTray.Connectors, cableTray, receivedObjectsCache); + + appObj.Update(status: ApplicationObject.State.Created, createdId: cableTray.UniqueId, convertedItem: cableTray); + return appObj; + } + + public BuiltElements.CableTray CableTrayToSpeckle(DB.Electrical.CableTray revitCableTray) + { + var baseGeometry = LocationToSpeckle(revitCableTray); + if (!(baseGeometry is Line baseLine)) + { + throw new Speckle.Core.Logging.SpeckleException("Only line based CableTrays are currently supported."); + } + + var cableTrayType = revitCableTray.Document.GetElement(revitCableTray.GetTypeId()) as CableTrayType; + + // SPECKLE CABLETRAY + var speckleCableTray = new RevitCableTray + { + family = cableTrayType.FamilyName, + type = cableTrayType.Name, + baseCurve = baseLine, + height = GetParamValue(revitCableTray, BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM), + width = GetParamValue(revitCableTray, BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM), + length = GetParamValue(revitCableTray, BuiltInParameter.CURVE_ELEM_LENGTH), + level = ConvertAndCacheLevel(revitCableTray, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitCableTray) + }; + + GetAllRevitParamsAndIds( + speckleCableTray, + revitCableTray, + new List + { + "RBS_CABLETRAY_HEIGHT_PARAM", + "RBS_CABLETRAY_WIDTH_PARAM", + "CURVE_ELEM_LENGTH", + "RBS_START_LEVEL_PARAM" + } + ); + + foreach (var connector in revitCableTray.GetConnectorSet()) + { + speckleCableTray.Connectors.Add(ConnectorToSpeckle(connector)); + } + + return speckleCableTray; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCeiling.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCeiling.cs new file mode 100644 index 0000000000..49b3148eec --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCeiling.cs @@ -0,0 +1,143 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using Ceiling = Objects.BuiltElements.Ceiling; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private RevitCeiling CeilingToSpeckle(DB.Ceiling revitCeiling, out List notes) + { + notes = new List(); +#if REVIT2020 || REVIT2021 + var profiles = GetProfiles(revitCeiling); +#else + var sketch = Doc.GetElement(revitCeiling.SketchId) as Sketch; + var profiles = GetSketchProfiles(sketch).Cast().ToList(); +#endif + var speckleCeiling = new RevitCeiling(); + speckleCeiling.type = revitCeiling.Document.GetElement(revitCeiling.GetTypeId()).Name; + speckleCeiling.outline = profiles[0]; + if (profiles.Count > 1) + { + speckleCeiling.voids = profiles.Skip(1).ToList(); + } + + speckleCeiling.level = ConvertAndCacheLevel(revitCeiling, BuiltInParameter.LEVEL_PARAM); + + GetAllRevitParamsAndIds(speckleCeiling, revitCeiling, new List { "LEVEL_PARAM" }); + + GetHostedElements(speckleCeiling, revitCeiling, out List hostedNotes); + if (hostedNotes.Any()) + { + notes.AddRange(hostedNotes); //TODO: what are we doing here? + } + + speckleCeiling.displayValue = GetElementDisplayValue(revitCeiling); + + return speckleCeiling; + } + +#if REVIT2020 || REVIT2021 +#else + public ApplicationObject CeilingToNative(Ceiling speckleCeiling) + { + var docObj = GetExistingElementByApplicationId(speckleCeiling.applicationId); + var appObj = new ApplicationObject(speckleCeiling.id, speckleCeiling.speckle_type) + { + applicationId = speckleCeiling.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (speckleCeiling.outline == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Missing an outline curve."); + return appObj; + } + + var outline = CurveToNative(speckleCeiling.outline); + var profile = new CurveLoop(); + foreach (DB.Curve segment in outline) + { + profile.Append(segment); + } + + DB.Level level = null; + double slope = 0; + DB.Line slopeDirection = null; + var levelState = ApplicationObject.State.Unknown; + if (speckleCeiling is RevitCeiling speckleRevitCeiling) + { + level = ConvertLevelToRevit(speckleRevitCeiling.level, out levelState); + slope = speckleRevitCeiling.slope; + slopeDirection = + (speckleRevitCeiling.slopeDirection != null) ? LineToNative(speckleRevitCeiling.slopeDirection) : null; + } + else + { + level = ConvertLevelToRevit(LevelFromCurve(outline.get_Item(0)), out levelState); + } + + var ceilingType = GetElementType(speckleCeiling, appObj, out bool _); + if (ceilingType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + DB.Ceiling revitCeiling; + + if (slope != 0 && slopeDirection != null) + { + revitCeiling = DB.Ceiling.Create( + Doc, + new List { profile }, + ceilingType.Id, + level.Id, + slopeDirection, + slope + ); + } + else + { + revitCeiling = DB.Ceiling.Create(Doc, new List { profile }, ceilingType.Id, level.Id); + } + + Doc.Regenerate(); + + try + { + CreateVoids(revitCeiling, speckleCeiling); + } + catch (Exception ex) + { + appObj.Update(logItem: $"Could not create openings: {ex.Message}"); + } + + SetInstanceParameters(revitCeiling, speckleCeiling); + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: revitCeiling.UniqueId, + convertedItem: revitCeiling + ); + //appObj = SetHostedElements(speckleCeiling, revitCeiling, appObj); + return appObj; + } +#endif +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs new file mode 100644 index 0000000000..3c23c6ebec --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs @@ -0,0 +1,316 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using Column = Objects.BuiltElements.Column; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject ColumnToNative(Column speckleColumn) + { + var docObj = GetExistingElementByApplicationId(speckleColumn.applicationId); + var appObj = new ApplicationObject(speckleColumn.id, speckleColumn.speckle_type) + { + applicationId = speckleColumn.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (speckleColumn.baseLine == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Only line based Beams are currently supported."); + return appObj; + } + + var familySymbol = GetElementType(speckleColumn, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var baseLine = CurveToNative(speckleColumn.baseLine).get_Item(0); + + // If the start point elevation is higher than the end point elevation, reverse the line. + if (baseLine.GetEndPoint(0).Z > baseLine.GetEndPoint(1).Z) + { + baseLine = DB.Line.CreateBound(baseLine.GetEndPoint(1), baseLine.GetEndPoint(0)); + } + + DB.FamilyInstance revitColumn = null; + //var structuralType = StructuralType.Column; + var isLineBased = true; + + var levelState = ApplicationObject.State.Unknown; + double baseOffset = 0.0; + DB.Level level = + (speckleColumn.level != null) + ? ConvertLevelToRevit(speckleColumn.level, out levelState) + : ConvertLevelToRevit(baseLine, out levelState, out baseOffset); + + var speckleRevitColumn = speckleColumn as RevitColumn; + + double topOffset = 0.0; + DB.Level topLevel = null; + if (speckleRevitColumn != null) + { + topLevel = ConvertLevelToRevit(speckleRevitColumn.topLevel, out levelState); + //structuralType = speckleRevitColumn.structural ? StructuralType.Column : StructuralType.NonStructural; + //non slanted columns are point based + isLineBased = speckleRevitColumn.isSlanted; + } + + if (topLevel == null) + { + topLevel = ConvertLevelToRevit(baseLine.GetEndPoint(1), out levelState, out topOffset); + } + + //try update existing + + bool isUpdate = false; + if (docObj != null) + { + try + { + var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; + + // if family changed, tough luck. delete and let us create a new one. + if (familySymbol.FamilyName != revitType.FamilyName) + { + Doc.Delete(docObj.Id); + } + else + { + revitColumn = (DB.FamilyInstance)docObj; + switch (revitColumn.Location) + { + case LocationCurve crv: + crv.Curve = baseLine; + break; + case LocationPoint pt: + pt.Point = baseLine.GetEndPoint(0); + break; + } + + // check for a type change + if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) + { + revitColumn.ChangeTypeId(familySymbol.Id); + } + } + isUpdate = true; + } + catch { } + } + + if (revitColumn == null && isLineBased) + { + revitColumn = Doc.Create.NewFamilyInstance(baseLine, familySymbol, level, StructuralType.Column); + if (revitColumn.Symbol.Family.FamilyPlacementType == FamilyPlacementType.CurveDrivenStructural) + { + StructuralFramingUtils.DisallowJoinAtEnd(revitColumn, 0); + StructuralFramingUtils.DisallowJoinAtEnd(revitColumn, 1); + } + } + + var start = baseLine.GetEndPoint(0); + var end = baseLine.GetEndPoint(1); + var basePoint = start.Z < end.Z ? start : end; // pick the lowest + //try with a point based column + if (speckleRevitColumn != null && revitColumn == null && !isLineBased) + { + revitColumn = Doc.Create.NewFamilyInstance(basePoint, familySymbol, level, StructuralType.NonStructural); + } + + //rotate + if (speckleRevitColumn != null && revitColumn != null) + { + var currentRotation = (revitColumn.Location as LocationPoint)?.Rotation; + + if (currentRotation != null && currentRotation != speckleRevitColumn.rotation) + { + var axis = DB.Line.CreateBound(new XYZ(basePoint.X, basePoint.Y, 0), new XYZ(basePoint.X, basePoint.Y, 10000)); + var s = (revitColumn.Location as LocationPoint).Rotate( + axis, + speckleRevitColumn.rotation - (double)currentRotation + ); + } + } + + if (revitColumn == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "revit column was null"); + return appObj; + } + + TrySetParam(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); + TrySetParam(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, topLevel); + + if (speckleRevitColumn != null) + { + if (speckleRevitColumn.handFlipped != revitColumn.HandFlipped) + { + revitColumn.flipHand(); + } + + if (speckleRevitColumn.facingFlipped != revitColumn.FacingFlipped) + { + revitColumn.flipFacing(); + } + + //don't change offset for slanted columns, it's automatic + if (!isLineBased) + { + SetOffsets( + revitColumn, + level, + topLevel, + ScaleToNative(speckleRevitColumn.baseOffset, speckleRevitColumn.units), + ScaleToNative(speckleRevitColumn.topOffset, speckleRevitColumn.units) + ); + } + + SetInstanceParameters(revitColumn, speckleRevitColumn); + } + else + { + // this case is always line based, don't change offset for line based columns, it's automatic + } + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitColumn.UniqueId, convertedItem: revitColumn); + // TODO: nested elements. + //appObj = SetHostedElements(speckleColumn, revitColumn, appObj); + return appObj; + } + + /// + /// Some families eg columns, need offsets to be set in a specific way. This tries to cover that. + /// + /// + /// + private void SetOffsets( + DB.FamilyInstance familyInstance, + Level level, + Level topLevel, + double baseOffset, + double topOffset + ) + { + var topOffsetParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); + var baseOffsetParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + var baseLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + var topLevelParam = familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + + if (topLevelParam == null || baseLevelParam == null || baseOffsetParam == null || topOffsetParam == null) + { + return; + } + + // the column length cannot be 0 for even an instance or Revit will throw a fit. + // Make sure that setting the offset on one side of the column before setting the + // other side doesn't leave the length of the column as approximately 0 + var colHeightAfterBaseOffset = level.Elevation + baseOffset - topLevel.Elevation; + var colHeightAfterTopOffset = topLevel.Elevation + topOffset - level.Elevation; + + if (Math.Abs(colHeightAfterBaseOffset) > TOLERANCE) + { + baseOffsetParam.Set(baseOffset); + topOffsetParam.Set(topOffset); + } + else if (Math.Abs(colHeightAfterTopOffset) > TOLERANCE) + { + topOffsetParam.Set(topOffset); + baseOffsetParam.Set(baseOffset); + } + else + { + baseOffsetParam.Set(baseOffset / 2); // temporarily set this value to something else so the sides of the column can switch places + topOffsetParam.Set(topOffset); + baseOffsetParam.Set(baseOffset); + } + } + + public Base ColumnToSpeckle(DB.FamilyInstance revitColumn, out List notes) + { + notes = new List(); + var symbol = revitColumn.Document.GetElement(revitColumn.GetTypeId()) as FamilySymbol; + + var speckleColumn = new RevitColumn(); + speckleColumn.family = symbol.FamilyName; + speckleColumn.type = revitColumn.Document.GetElement(revitColumn.GetTypeId()).Name; + speckleColumn.level = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + speckleColumn.topLevel = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + speckleColumn.baseOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + speckleColumn.topOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); + speckleColumn.facingFlipped = revitColumn.FacingFlipped; + speckleColumn.handFlipped = revitColumn.HandFlipped; + speckleColumn.isSlanted = revitColumn.IsSlantedColumn; + //speckleColumn.structural = revitColumn.StructuralType == StructuralType.Column; + + //geometry + var baseGeometry = LocationToSpeckle(revitColumn); + var baseLine = baseGeometry as ICurve; + + //make line from point and height + if (baseLine == null && baseGeometry is Point basePoint) + { + if ( + symbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased + || symbol.Family.FamilyPlacementType == FamilyPlacementType.WorkPlaneBased + ) + { + return RevitInstanceToSpeckle(revitColumn, out notes, null); + } + + var elevation = speckleColumn.topLevel.elevation; + baseLine = new Line( + basePoint, + new Point(basePoint.x, basePoint.y, elevation + speckleColumn.topOffset, ModelUnits), + ModelUnits + ); + } + + if (baseLine == null) + { + return RevitElementToSpeckle(revitColumn, out notes); + } + + speckleColumn.baseLine = baseLine; //all speckle columns should be line based + + GetAllRevitParamsAndIds( + speckleColumn, + revitColumn, + new List + { + "FAMILY_BASE_LEVEL_PARAM", + "FAMILY_TOP_LEVEL_PARAM", + "FAMILY_BASE_LEVEL_OFFSET_PARAM", + "FAMILY_TOP_LEVEL_OFFSET_PARAM", + "SCHEDULE_BASE_LEVEL_OFFSET_PARAM", + "SCHEDULE_TOP_LEVEL_OFFSET_PARAM" + } + ); + + if (revitColumn.Location is LocationPoint) + { + speckleColumn.rotation = ((LocationPoint)revitColumn.Location).Rotation; + } + + speckleColumn.displayValue = GetElementDisplayValue(revitColumn); + + return speckleColumn; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCombinableElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCombinableElement.cs new file mode 100644 index 0000000000..a31d8f53ba --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCombinableElement.cs @@ -0,0 +1,77 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public FreeformElement CombinableElementToSpeckle(CombinableElement combinableElement) + { + var cat = ((BuiltInCategory)combinableElement.Document.OwnerFamily.FamilyCategoryId.IntegerValue).ToString(); + + Options options = new(); + if (combinableElement is GenericForm gf && gf.Combinations.Size != 0) + { + //for receive and convert to native + options.IncludeNonVisibleObjects = true; + } + + var element = combinableElement.get_Geometry(options); + var geometries = new List(); + foreach (var obj in element) + { + switch (obj) + { + case Autodesk.Revit.DB.Mesh mesh: + geometries.Add(MeshToSpeckle(mesh, combinableElement.Document)); + break; + case Solid solid: // TODO Should be replaced with 'BrepToSpeckle' when it works. + geometries.AddRange(ConvertSolidsByRenderMaterial(new[] { solid }, combinableElement.Document)); + break; + } + } + var speckleForm = new FreeformElement(); + speckleForm.subcategory = cat; + speckleForm["type"] = combinableElement.Name; + speckleForm.baseGeometries = new List(); + + if (combinableElement is GenericForm) + { + speckleForm.baseGeometries = geometries; + GetAllRevitParamsAndIds(speckleForm, combinableElement); + } + + if ( + combinableElement is GeomCombination + || (combinableElement is GenericForm genericForm && genericForm.Combinations.Size == 0) + ) + { + List displayValue = new(); + foreach (Base geo in geometries) + { + switch (geo["displayValue"]) + { + case null: + //geo has no display value, we assume it is itself a valid displayValue + displayValue.Add(geo); + break; + + case Base b: + displayValue.Add(b); + break; + + case IEnumerable e: + displayValue.AddRange(e); + break; + } + } + + speckleForm.displayValue = displayValue; + } + + return speckleForm; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConduit.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConduit.cs new file mode 100644 index 0000000000..bce79de458 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConduit.cs @@ -0,0 +1,120 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Electrical; +using Autodesk.Revit.DB.Mechanical; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject ConduitToNative(BuiltElements.Conduit speckleConduit) + { + var speckleRevitConduit = speckleConduit as RevitConduit; + + var docObj = GetExistingElementByApplicationId(speckleConduit.applicationId); + var appObj = new ApplicationObject(speckleConduit.id, speckleConduit.speckle_type) + { + applicationId = speckleConduit.applicationId + }; + if (docObj != null && ReceiveMode == Speckle.Core.Kits.ReceiveMode.Ignore) + { + appObj.Update(status: ApplicationObject.State.Skipped, createdId: docObj.UniqueId, convertedItem: docObj); + return appObj; + } + + if (!(speckleConduit.baseCurve is Line)) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"BaseCurve of type ${speckleConduit.baseCurve.GetType()} cannot be used to create a Revit Conduit" + ); + return appObj; + } + + var conduitType = GetElementType(speckleConduit, appObj, out bool _); + if (conduitType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + DB.Line baseLine = LineToNative(speckleConduit.baseCurve as Line); + XYZ startPoint = baseLine.GetEndPoint(0); + XYZ endPoint = baseLine.GetEndPoint(1); + DB.Level lineLevel = ConvertLevelToRevit( + speckleRevitConduit != null ? speckleRevitConduit.level : LevelFromCurve(baseLine), + out ApplicationObject.State levelState + ); + var conduit = Conduit.Create(Doc, conduitType.Id, startPoint, endPoint, lineLevel.Id); + + if (conduit == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Creation returned null"); + return appObj; + } + + // deleting instead of updating for now! + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + if (speckleRevitConduit != null) + { + TrySetParam( + conduit, + BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM, + speckleRevitConduit.diameter, + speckleRevitConduit.units + ); + TrySetParam(conduit, BuiltInParameter.CURVE_ELEM_LENGTH, speckleRevitConduit.length, speckleRevitConduit.units); + SetInstanceParameters(conduit, speckleRevitConduit); + } + + CreateSystemConnections(speckleRevitConduit.Connectors, conduit, receivedObjectsCache); + + appObj.Update(status: ApplicationObject.State.Created, createdId: conduit.UniqueId, convertedItem: conduit); + return appObj; + } + + public BuiltElements.Conduit ConduitToSpeckle(Conduit revitConduit) + { + var baseGeometry = LocationToSpeckle(revitConduit); + if (!(baseGeometry is Line baseLine)) + { + throw new Speckle.Core.Logging.SpeckleException("Only line based Conduits are currently supported."); + } + + var conduitType = revitConduit.Document.GetElement(revitConduit.GetTypeId()) as ConduitType; + + // SPECKLE CONDUIT + var speckleConduit = new RevitConduit + { + family = conduitType.FamilyName, + type = conduitType.Name, + baseCurve = baseLine, + diameter = GetParamValue(revitConduit, BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM), + length = GetParamValue(revitConduit, BuiltInParameter.CURVE_ELEM_LENGTH), + level = ConvertAndCacheLevel(revitConduit, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitConduit) + }; + + GetAllRevitParamsAndIds( + speckleConduit, + revitConduit, + new List { "RBS_CONDUIT_DIAMETER_PARAM", "CURVE_ELEM_LENGTH", "RBS_START_LEVEL_PARAM" } + ); + + foreach (var connector in revitConduit.GetConnectorSet()) + { + speckleConduit.Connectors.Add(ConnectorToSpeckle(connector)); + } + + return speckleConduit; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConnector.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConnector.cs new file mode 100644 index 0000000000..4104c7404e --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertConnector.cs @@ -0,0 +1,46 @@ +using System.Linq; +using Autodesk.Revit.DB; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public RevitMEPConnector ConnectorToSpeckle(Connector connector) + { + var speckleMEPConnector = new RevitMEPConnector + { + applicationId = connector.GetUniqueApplicationId(), + origin = PointToSpeckle(connector.Origin, Doc), + shape = connector.Shape.ToString(), + systemName = connector.MEPSystem?.Name ?? connector.Owner.Category?.Name, + }; + + // some genius at Autodesk thought it would be a good idea for property getters to throw... + try + { + speckleMEPConnector.angle = connector.Angle; + } + catch { } + try + { + speckleMEPConnector.height = ScaleToSpeckle(connector.Height); + speckleMEPConnector.width = ScaleToSpeckle(connector.Width); + } + catch { } + try + { + speckleMEPConnector.radius = ScaleToSpeckle(connector.Radius); + } + catch { } + foreach (var reference in connector.AllRefs.Cast()) + { + if (connector.IsConnectedTo(reference)) + { + speckleMEPConnector.connectedConnectorIds.Add(reference.GetUniqueApplicationId()); + } + } + return speckleMEPConnector; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCurves.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCurves.cs new file mode 100644 index 0000000000..805715c83d --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertCurves.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit.Curve; +using Speckle.Core.Models; +using Alignment = Objects.BuiltElements.Alignment; +using DB = Autodesk.Revit.DB; +using DetailCurve = Objects.BuiltElements.Revit.Curve.DetailCurve; +using ModelCurve = Objects.BuiltElements.Revit.Curve.ModelCurve; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + #region speckle to native + public ApplicationObject CreateAppObject(string id, string applicationId, string speckle_type) + { + var docObjs = GetExistingElementsByApplicationId(applicationId); + var appObj = new ApplicationObject(id, speckle_type) { applicationId = applicationId }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObjs.FirstOrDefault(), appObj)) + { + return appObj; + } + + foreach (var docObj in docObjs) + { + if (docObj != null) + { + // TODO: try updating lines + Doc.Delete(docObj.Id); + } + } + + return appObj; + } + + public ApplicationObject AlignmentToNative(Alignment alignment) + { + var appObj = CreateAppObject(alignment.id, alignment.applicationId, alignment.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + var curves = CurveToNative(alignment.curves); + var curveEnumerator = curves.GetEnumerator(); + while (curveEnumerator.MoveNext() && curveEnumerator.Current != null) + { + var baseCurve = curveEnumerator.Current as DB.Curve; + DB.ModelCurve revitCurve = Doc.Create.NewModelCurve(baseCurve, NewSketchPlaneFromCurve(baseCurve, Doc)); + appObj.Update(createdId: revitCurve.UniqueId); + } + appObj.Update(status: ApplicationObject.State.Created); + return appObj; + } + + public ApplicationObject DetailCurveToNative(DetailCurve speckleCurve) + { + var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + var crvEnum = CurveToNative(speckleCurve.baseCurve).GetEnumerator(); + while (crvEnum.MoveNext() && crvEnum.Current != null) + { + var baseCurve = crvEnum.Current as DB.Curve; + DB.DetailCurve revitCurve = null; + try + { + revitCurve = Doc.Create.NewDetailCurve(Doc.ActiveView, baseCurve); + } + catch (Exception) + { + appObj.Update(logItem: $"Detail curve creation failed\nView is not valid for detail curve creation."); + continue; + } + + var lineStyles = revitCurve.GetLineStyleIds(); + var lineStyleId = lineStyles.FirstOrDefault(x => Doc.GetElement(x).Name == speckleCurve.lineStyle); + if (lineStyleId != null) + { + revitCurve.LineStyle = Doc.GetElement(lineStyleId); + } + + appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); + } + appObj.Update( + status: ApplicationObject.State.Created, + logItem: $"Created as {appObj.CreatedIds.Count} detail curves" + ); + return appObj; + } + + public ApplicationObject ModelCurveToNative(ModelCurve speckleCurve) + { + var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + var curves = CurveToNative(speckleCurve.baseCurve); + var curveEnumerator = curves.GetEnumerator(); + while (curveEnumerator.MoveNext() && curveEnumerator.Current != null) + { + var baseCurve = curveEnumerator.Current as DB.Curve; + DB.ModelCurve revitCurve = Doc.Create.NewModelCurve(baseCurve, NewSketchPlaneFromCurve(baseCurve, Doc)); + + var lineStyles = revitCurve.GetLineStyleIds(); + var lineStyleId = lineStyles.FirstOrDefault(x => Doc.GetElement(x).Name == speckleCurve.lineStyle); + if (lineStyleId != null) + { + revitCurve.LineStyle = Doc.GetElement(lineStyleId); + } + + appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); + } + appObj.Update(status: ApplicationObject.State.Created); + return appObj; + } + + // This is to support raw geometry being sent to Revit (eg from rhino, gh, autocad...) + public ApplicationObject ModelCurveToNative(ICurve speckleLine) + { + // if it comes from GH it doesn't have an applicationId, the use the hash id + if ((speckleLine as Base).applicationId == null) + { + (speckleLine as Base).applicationId = (speckleLine as Base).id; + } + + var speckleCurve = speckleLine as Base; + var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + try + { + return ModelCurvesFromEnumerator(CurveToNative(speckleLine).GetEnumerator(), speckleLine, appObj); + } + catch (Exception e) + { + // use display value if curve fails (prob a closed, periodic curve or a non-planar nurbs) + if (speckleLine is IDisplayValue d) + { + appObj.Update( + logItem: $"Curve failed conversion (probably a closed period curve or non-planar nurbs): used polyline display value instead." + ); + return ModelCurvesFromEnumerator(CurveToNative(d.displayValue).GetEnumerator(), speckleLine, appObj); + } + else + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: e.Message); + return appObj; + } + } + } + + public ApplicationObject RoomBoundaryLineToNative(RoomBoundaryLine speckleCurve) + { + var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + var baseCurve = CurveToNative(speckleCurve.baseCurve); + + try + { + View drawingView = GetCurvePlanView(speckleCurve, out bool isTempView); + var revitCurve = Doc.Create + .NewRoomBoundaryLines(NewSketchPlaneFromCurve(baseCurve.get_Item(0), Doc), baseCurve, drawingView) + .get_Item(0); + + // Delete the temp view after drawing + if (isTempView) + { + Doc.Delete(drawingView.Id); + } + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitCurve.UniqueId, convertedItem: revitCurve); + } + catch (Exception) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "View is not valid for room boundary line creation." + ); + } + return appObj; + } + + public ApplicationObject SpaceSeparationLineToNative(SpaceSeparationLine speckleCurve) + { + var appObj = CreateAppObject(speckleCurve.id, speckleCurve.applicationId, speckleCurve.speckle_type); + if (appObj.Status == ApplicationObject.State.Skipped) + { + return appObj; + } + + var baseCurve = CurveToNative(speckleCurve.baseCurve); + + // try update existing (update model curve geometry curve based on speckle curve) + //if (docObj != null) + //{ + // try + // { + // var docCurve = docObj as DB.ModelCurve; + // var revitGeom = docCurve.GeometryCurve; + // var speckleGeom = baseCurve.get_Item(0); + // bool fullOverlap = speckleGeom.Intersect(revitGeom) == SetComparisonResult.Equal; + // if (!fullOverlap) + // docCurve.SetGeometryCurve(speckleGeom, false); + + // appObj.Update(status: ApplicationObject.State.Updated, createdId: docCurve.UniqueId, convertedItem: docCurve); + // return appObj; + // } + // catch + // { + // //delete and try to create new line as fallback + // Doc.Delete(docObj.Id); + // } + //} + + try + { + var res = Doc.Create + .NewSpaceBoundaryLines(NewSketchPlaneFromCurve(baseCurve.get_Item(0), Doc), baseCurve, Doc.ActiveView) + .get_Item(0); + appObj.Update(status: ApplicationObject.State.Created, createdId: res.UniqueId, convertedItem: res); + } + catch (Exception) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "View is not valid for space separation line creation." + ); + } + return appObj; + } + + public ApplicationObject ModelCurvesFromEnumerator( + IEnumerator curveEnum, + ICurve speckleLine, + ApplicationObject appObj + ) + { + while (curveEnum.MoveNext() && curveEnum.Current != null) + { + var curve = curveEnum.Current as DB.Curve; + // Curves must be bound in order to be valid model curves + if (!curve.IsBound) + { + curve.MakeBound(speckleLine.domain.start ?? 0, speckleLine.domain.end ?? Math.PI * 2); + } + + DB.ModelCurve revitCurve = null; + + if (Doc.IsFamilyDocument) + { + revitCurve = Doc.FamilyCreate.NewModelCurve(curve, NewSketchPlaneFromCurve(curve, Doc)); + } + else + { + revitCurve = Doc.Create.NewModelCurve(curve, NewSketchPlaneFromCurve(curve, Doc)); + } + + if (revitCurve != null) + { + appObj.Update(createdId: revitCurve.UniqueId, convertedItem: revitCurve); + } + } + if (appObj.CreatedIds.Count > 1) + { + appObj.Update(logItem: $"Created as {appObj.CreatedIds.Count} model curves"); + } + + appObj.Update(status: ApplicationObject.State.Created); + return appObj; + } + + #endregion + + #region native to speckle + + public ModelCurve ModelCurveToSpeckle(DB.ModelCurve revitCurve) + { + var speckleCurve = new ModelCurve( + CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document), + revitCurve.LineStyle.Name + ); + speckleCurve.elementId = revitCurve.Id.ToString(); + speckleCurve.applicationId = revitCurve.UniqueId; + speckleCurve.units = ModelUnits; + return speckleCurve; + } + + public DetailCurve DetailCurveToSpeckle(DB.DetailCurve revitCurve) + { + var speckleCurve = new DetailCurve( + CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document), + revitCurve.LineStyle.Name + ); + speckleCurve.elementId = revitCurve.Id.ToString(); + speckleCurve.applicationId = revitCurve.UniqueId; + speckleCurve.units = ModelUnits; + return speckleCurve; + } + + public RoomBoundaryLine RoomBoundaryLineToSpeckle(DB.ModelCurve revitCurve) + { + var speckleCurve = new RoomBoundaryLine(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document)); + speckleCurve.elementId = revitCurve.Id.ToString(); + speckleCurve.level = ConvertAndCacheLevel(revitCurve.LevelId, revitCurve.Document); + speckleCurve.applicationId = revitCurve.UniqueId; + speckleCurve.units = ModelUnits; + return speckleCurve; + } + + public SpaceSeparationLine SpaceSeparationLineToSpeckle(DB.ModelCurve revitCurve) + { + var speckleCurve = new SpaceSeparationLine(CurveToSpeckle(revitCurve.GeometryCurve, revitCurve.Document)); + speckleCurve.elementId = revitCurve.Id.ToString(); + speckleCurve.applicationId = revitCurve.UniqueId; + speckleCurve.units = ModelUnits; + return speckleCurve; + } + + #endregion + + /// + /// Credits: Grevit + /// Creates a new Sketch Plane from a Curve + /// https://github.com/grevit-dev/Grevit/blob/3c7a5cc198e00dfa4cc1e892edba7c7afd1a3f84/Grevit.Revit/Utilities.cs#L402 + /// + /// Curve to get plane from + /// Plane of the curve + private SketchPlane NewSketchPlaneFromCurve(DB.Curve curve, Document doc) + { + XYZ startPoint = curve.GetEndPoint(0); + XYZ endPoint = curve.GetEndPoint(1); + + // If Start end Endpoint are the same check further points. + int i = 2; + while (startPoint == endPoint && endPoint != null) + { + endPoint = curve.GetEndPoint(i); + i++; + } + + // Plane to return + DB.Plane plane; + + // If Z Values are equal the Plane is XY + if (startPoint.Z == endPoint.Z) + { + plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisZ, startPoint); + } + // If X Values are equal the Plane is YZ + else if (startPoint.X == endPoint.X) + { + plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisX, startPoint); + } + // If Y Values are equal the Plane is XZ + else if (startPoint.Y == endPoint.Y) + { + plane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisY, startPoint); + } + // Otherwise the Planes Normal Vector is not X,Y or Z. + // We draw lines from the Origin to each Point and use the Plane this one spans up. + else + { + CurveArray curves = new(); + curves.Append(curve); + curves.Append(DB.Line.CreateBound(new XYZ(0, 0, 0), startPoint)); + curves.Append(DB.Line.CreateBound(endPoint, new XYZ(0, 0, 0))); + + plane = DB.Plane.CreateByThreePoints(startPoint, new XYZ(0, 0, 0), endPoint); + } + + return SketchPlane.Create(doc, plane); + } + + /// + /// Get a plan view associated to the curve level. + /// Will return the Doc.ActiveView If no appropriate view is found. + /// + /// A Speckle curve + /// A bool flag indicating if this view should be deleted after drawing the curve. + /// A Revit View. + private View GetCurvePlanView(RoomBoundaryLine speckleCurve, out bool isTempView) + { + View drawingView; + Level level = ConvertLevelToRevit(speckleCurve.level, out _); + ElementId viewId = level?.FindAssociatedPlanViewId(); + + // If there is a plan view associated to the curve level use it otherwise create a temp plan view + if (viewId != null && viewId != ElementId.InvalidElementId) + { + drawingView = Doc.GetElement(viewId) as ViewPlan; + isTempView = false; + } + else + { + drawingView = CreateViewPlan("temp", level.Id); + isTempView = true; + } + + // If plan view retrieval/creation still fail use the activeView as a last recourse + if (drawingView == null) + { + drawingView = Doc.ActiveView; + isTempView = false; + } + + return drawingView; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectShape.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectShape.cs new file mode 100644 index 0000000000..f8174ee5f5 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectShape.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Objects.Other; +using Speckle.Core.Kits; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using DirectShape = Objects.BuiltElements.Revit.DirectShape; +using Mesh = Objects.Geometry.Mesh; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + /// + /// Attempts to convert a DirectShape to Revit according to the current ToNativeMeshSetting value. + /// + /// The direct shape to convert + /// An application placeholder object containing a DirectShape, DXF Import or Family containing DXF Import. + public ApplicationObject TryDirectShapeToNative(DirectShape o, ToNativeMeshSettingEnum fallbackSetting) + { + try + { + // Try to convert to direct shape, taking into account the current mesh settings + return DirectShapeToNative(o, fallbackSetting); + } + catch (FallbackToDxfException e) + { + Report.Log(e.Message); + // FallbackToDxf exception means we should attempt a DXF import instead. + switch (ToNativeMeshSetting) + { + case ToNativeMeshSettingEnum.DxfImport: + return DirectShapeToDxfImport(o); // DirectShape -> DXF + case ToNativeMeshSettingEnum.DxfImportInFamily: + return DirectShapeToDxfImportFamily(o); // DirectShape -> Family (DXF inside) + case ToNativeMeshSettingEnum.Default: + default: + // For anything else, try again with the default fallback (ugly meshes). + return DirectShapeToNative(o, ToNativeMeshSettingEnum.Default); + } + } + } + + public ApplicationObject TryDirectShapeToNative( + Brep brep, + ToNativeMeshSettingEnum fallbackSetting, + RevitCategory cat = RevitCategory.GenericModel + ) + { + DirectShape ds = + new($"Brep {brep.applicationId ?? brep.id}", cat, new List { brep }) + { + applicationId = brep.applicationId, + id = brep.id + }; + return TryDirectShapeToNative(ds, fallbackSetting); + } + + public ApplicationObject TryDirectShapeToNative( + Mesh mesh, + ToNativeMeshSettingEnum fallbackSetting, + RevitCategory cat = RevitCategory.GenericModel + ) + { + DirectShape ds = + new($"Mesh {mesh.applicationId ?? mesh.id}", cat, new List { mesh }) + { + applicationId = mesh.applicationId, + id = mesh.id + }; + return TryDirectShapeToNative(ds, fallbackSetting); + } + + public ApplicationObject TryDirectShapeToNative( + ApplicationObject appObj, + List meshes, + ToNativeMeshSettingEnum fallbackSetting, + RevitCategory cat = RevitCategory.GenericModel + ) + { + if (meshes.Count == 0) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Contained no meshes"); + return appObj; + } + + var ds = new DirectShape( + $"{appObj.Descriptor.Split(':').LastOrDefault() ?? "Meshes"} {appObj.applicationId}", + cat, + meshes.Cast().ToList() + ) + { + applicationId = appObj.applicationId, + id = appObj.OriginalId + }; + + return TryDirectShapeToNative(ds, fallbackSetting); + } + + /// + /// The default DirectShape conversion method. Will return a Revit DirectShape with the containing geometry. + /// + /// + /// + /// + /// + public ApplicationObject DirectShapeToNative(DirectShape speckleDs, ToNativeMeshSettingEnum fallback) + { + // get any existing elements. This could be a DirectShape, OR another element if using fallback receive + var existingObj = GetExistingElementByApplicationId(speckleDs.applicationId ??= speckleDs.id); + var appObj = new ApplicationObject(speckleDs.id, speckleDs.speckle_type) + { + applicationId = speckleDs.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(existingObj, appObj)) + { + return appObj; + } + + var converted = new List(); + + speckleDs.baseGeometries + .ToList() + .ForEach(b => + { + switch (b) + { + case Brep brep: + try + { + var solid = BrepToNative(brep, out var notes); + converted.Add(solid); + } + catch (Exception e) + { + if (fallback != ToNativeMeshSettingEnum.Default) + { + throw new FallbackToDxfException( + "Failed to convert BREP to Solid. Falling back to DXF import as per settings.", + e + ); + } + + var mesh = brep.displayValue.SelectMany( + m => MeshToNative(m, parentMaterial: brep["renderMaterial"] as RenderMaterial) + ); + converted.AddRange(mesh); + } + + break; + case Mesh mesh: + if (fallback != ToNativeMeshSettingEnum.Default) + { + throw new FallbackToDxfException( + "DirectShape contains Mesh. Falling back to DXF import as per Settings." + ); + } + + var rMesh = MeshToNative(mesh); + converted.AddRange(rMesh); + break; + case ICurve curve: + var rCurves = CurveToNative(curve, true); + for (var i = 0; i < rCurves.Size; i++) + { + converted.Add(rCurves.get_Item(i)); + } + + break; + default: + appObj.Update( + logItem: $"Incompatible geometry type: {b.GetType()} is not supported in DirectShape conversions." + ); + break; + } + }); + + if (existingObj != null && existingObj is DB.DirectShape existingDS) // if it's a directShape, just update + { + existingDS.SetShape(converted); + appObj.Update(status: ApplicationObject.State.Updated, createdId: existingDS.UniqueId, convertedItem: existingDS); + return appObj; + } + + //from 2.16 onwards use the builtInCategory field for direct shape fallback + BuiltInCategory bic = BuiltInCategory.OST_GenericModel; + if (!BuiltInCategory.TryParse(speckleDs["builtInCategory"] as string, out bic)) + { + //pre 2.16 or coming from grasshopper, using the enum + //TODO: move away from enum logic + if ((int)speckleDs.category != -1) + { + var bicName = Categories.GetBuiltInFromSchemaBuilderCategory(speckleDs.category); + _ = BuiltInCategory.TryParse(bicName, out bic); + } + } + + var cat = Doc.Settings.Categories.get_Item(bic); + + try + { + var revitDs = DB.DirectShape.CreateElement(Doc, cat.Id); + if (speckleDs.applicationId != null) + { + revitDs.ApplicationId = speckleDs.applicationId; + } + + revitDs.ApplicationDataId = Guid.NewGuid().ToString(); + revitDs.SetShape(converted); + revitDs.Name = speckleDs.name; + SetInstanceParameters(revitDs, speckleDs); + // delete any existing objs + if (existingObj != null) + { + try + { + Doc.Delete(existingObj.Id); + } + catch (Exception e) + { + appObj.Log.Add($"Could not delete existing object: {e.Message}"); + } + } + appObj.Update(status: ApplicationObject.State.Created, createdId: revitDs.UniqueId, convertedItem: revitDs); + } + catch (Exception ex) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"{ex.Message}"); + } + return appObj; + } + + private DirectShape DirectShapeToSpeckle(DB.DirectShape revitAc) + { + var cat = ((BuiltInCategory)revitAc.Category.Id.IntegerValue).ToString(); + var category = Categories.GetSchemaBuilderCategoryFromBuiltIn(cat); + var element = revitAc.get_Geometry(new Options()); + + var geometries = new List(); + foreach (var obj in element) + { + switch (obj) + { + case DB.Mesh mesh: + geometries.Add(MeshToSpeckle(mesh, revitAc.Document)); + break; + case Solid solid: // TODO Should be replaced with 'BrepToSpeckle' when it works. + geometries.AddRange(ConvertSolidsByRenderMaterial(new[] { solid }, revitAc.Document)); + break; + } + } + + var speckleAc = new DirectShape(revitAc.Name, category, geometries); + + //Find display values in geometries + List displayValue = new(); + foreach (Base geo in geometries) + { + switch (geo["displayValue"]) + { + case null: + //geo has no display value, we assume it is itself a valid displayValue + displayValue.Add(geo); + break; + + case Base b: + displayValue.Add(b); + break; + + case IEnumerable e: + displayValue.AddRange(e); + break; + } + } + + speckleAc.displayValue = displayValue; + GetAllRevitParamsAndIds(speckleAc, revitAc); + speckleAc["type"] = revitAc.Name; + return speckleAc; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectTeklaMeshElements.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectTeklaMeshElements.cs new file mode 100644 index 0000000000..f60246dce6 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDirectTeklaMeshElements.cs @@ -0,0 +1,17 @@ +using Autodesk.Revit.DB; +using Objects.Other; +using System; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB; +using Mesh = Objects.Geometry.Mesh; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public IList TeklaMeshToNative(Mesh displayMesh) + { + return MeshToNative(displayMesh); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDisplayableObject.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDisplayableObject.cs similarity index 99% rename from Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDisplayableObject.cs rename to Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDisplayableObject.cs index 86266cf0eb..23f4d00266 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/ConvertDisplayableObject.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDisplayableObject.cs @@ -59,7 +59,9 @@ public string GetSpeckleObjectBuiltInCategory(Base @object) { //from 2.16 onwards we're passing the BuiltInCategory on every object if (@object["builtInCategory"] is not null) + { return @object["builtInCategory"] as string; + } if (RevitCategory.TryParse(@object["category"] as string, out RevitCategory category)) { @@ -98,7 +100,6 @@ public string GetSpeckleObjectBuiltInCategory(Base @object) return BuiltInCategory.OST_CableTray.ToString(); default: return BuiltInCategory.OST_GenericModel.ToString(); - } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDuct.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDuct.cs new file mode 100644 index 0000000000..a69c4253cf --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertDuct.cs @@ -0,0 +1,259 @@ +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Mechanical; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; +using Polyline = Objects.Geometry.Polyline; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject DuctToNative(BuiltElements.Duct speckleDuct) + { + var speckleRevitDuct = speckleDuct as RevitDuct; + Element docObj = GetExistingElementByApplicationId(speckleDuct.applicationId); + var appObj = new ApplicationObject(speckleDuct.id, speckleDuct.speckle_type) + { + applicationId = speckleDuct.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + string systemFamily = (speckleRevitDuct != null) ? speckleRevitDuct.systemName : ""; + List types = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(MechanicalSystemType)) + .ToElements() + .Cast() + .ToList(); + var system = types.FirstOrDefault(x => x.Name == systemFamily); + if (system == null) + { + system = types.FirstOrDefault(); + appObj.Update(logItem: $"Duct type {systemFamily} not found; replaced with {system.Name}"); + } + + Element duct = null; + if (speckleDuct.baseCurve == null || speckleDuct.baseCurve is Line) + { + DuctType ductType = GetElementType(speckleDuct, appObj, out bool _); + if (ductType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + DB.Line baseLine = + (speckleDuct.baseCurve != null) + ? LineToNative(speckleDuct.baseCurve as Line) + : LineToNative(speckleDuct.baseLine); + XYZ startPoint = baseLine.GetEndPoint(0); + XYZ endPoint = baseLine.GetEndPoint(1); + DB.Level lineLevel = ConvertLevelToRevit( + speckleRevitDuct != null ? speckleRevitDuct.level : LevelFromCurve(baseLine), + out ApplicationObject.State lineState + ); + DB.Mechanical.Duct lineDuct = DB.Mechanical.Duct.Create( + Doc, + system.Id, + ductType.Id, + lineLevel.Id, + startPoint, + endPoint + ); + duct = lineDuct; + } + else if (speckleDuct.baseCurve is Polyline polyline) + { + FlexDuctType ductType = GetElementType(speckleDuct, appObj, out bool _); + if (ductType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var speckleRevitFlexDuct = speckleDuct as RevitFlexDuct; + List points = polyline.GetPoints().Select(o => PointToNative(o)).ToList(); + DB.Level flexLevel = ConvertLevelToRevit( + speckleRevitDuct != null ? speckleRevitDuct.level : LevelFromPoint(points.First()), + out ApplicationObject.State flexState + ); + XYZ startTangent = VectorToNative(speckleRevitFlexDuct.startTangent); + XYZ endTangent = VectorToNative(speckleRevitFlexDuct.endTangent); + + DB.Mechanical.FlexDuct flexDuct = DB.Mechanical.FlexDuct.Create( + Doc, + system.Id, + ductType.Id, + flexLevel.Id, + startTangent, + endTangent, + points + ); + duct = flexDuct; + } + else + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Duct BaseCurve of type ${speckleDuct.baseCurve.GetType()} cannot be used to create a Revit Duct" + ); + return appObj; + } + + // deleting instead of updating for now! + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + if (speckleRevitDuct != null) + { + TrySetParam(duct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, speckleRevitDuct.height, speckleRevitDuct.units); + TrySetParam(duct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, speckleRevitDuct.width, speckleRevitDuct.units); + TrySetParam(duct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, speckleRevitDuct.diameter, speckleRevitDuct.units); + TrySetParam(duct, BuiltInParameter.CURVE_ELEM_LENGTH, speckleRevitDuct.length, speckleRevitDuct.units); + TrySetParam(duct, BuiltInParameter.RBS_VELOCITY, speckleRevitDuct.velocity, speckleRevitDuct.units); + + SetInstanceParameters(duct, speckleRevitDuct); + + CreateSystemConnections(speckleRevitDuct.Connectors, duct, receivedObjectsCache); + } + + appObj.Update(status: ApplicationObject.State.Created, createdId: duct.UniqueId, convertedItem: duct); + return appObj; + } + + public BuiltElements.Duct DuctToSpeckle(DB.Mechanical.Duct revitDuct, out List notes) + { + notes = new List(); + var baseGeometry = LocationToSpeckle(revitDuct); + if (!(baseGeometry is Line baseLine)) + { + notes.Add("Only line based Ducts are currently supported."); + return null; + } + + // SPECKLE DUCT + var speckleDuct = new RevitDuct + { + family = revitDuct.DuctType.FamilyName, + type = revitDuct.DuctType.Name, + baseCurve = baseLine, + diameter = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, unitsOverride: ModelUnits), + height = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, unitsOverride: ModelUnits), + width = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, unitsOverride: ModelUnits), + length = GetParamValue(revitDuct, BuiltInParameter.CURVE_ELEM_LENGTH), + velocity = GetParamValue(revitDuct, BuiltInParameter.RBS_VELOCITY), + level = ConvertAndCacheLevel(revitDuct, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitDuct) + }; + + if (revitDuct.MEPSystem != null) + { + var material = ConverterRevit.GetMEPSystemMaterial(revitDuct); + if (material != null) + { + foreach (var mesh in speckleDuct.displayValue) + { + mesh["renderMaterial"] = material; + } + } + + var typeElem = revitDuct.Document.GetElement(revitDuct.MEPSystem.GetTypeId()); + speckleDuct.systemName = typeElem.Name; + } + + GetAllRevitParamsAndIds( + speckleDuct, + revitDuct, + new List + { + "RBS_CURVE_HEIGHT_PARAM", + "RBS_CURVE_WIDTH_PARAM", + "RBS_CURVE_DIAMETER_PARAM", + "CURVE_ELEM_LENGTH", + "RBS_START_LEVEL_PARAM", + "RBS_VELOCITY" + } + ); + + foreach (var connector in revitDuct.GetConnectorSet()) + { + speckleDuct.Connectors.Add(ConnectorToSpeckle(connector)); + } + + return speckleDuct; + } + + public BuiltElements.Duct DuctToSpeckle(FlexDuct revitDuct) + { + // create polyline from revitduct points + var polyline = new Polyline(); + polyline.value = PointsToFlatList(revitDuct.Points.Select(o => PointToSpeckle(o, revitDuct.Document))); + polyline.units = ModelUnits; + polyline.closed = false; + + // SPECKLE DUCT + var speckleDuct = new RevitFlexDuct + { + family = revitDuct.FlexDuctType.FamilyName, + type = revitDuct.FlexDuctType.Name, + baseCurve = polyline, + diameter = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM, unitsOverride: ModelUnits), + height = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM, unitsOverride: ModelUnits), + width = GetParamValue(revitDuct, BuiltInParameter.RBS_CURVE_WIDTH_PARAM, unitsOverride: ModelUnits), + length = GetParamValue(revitDuct, BuiltInParameter.CURVE_ELEM_LENGTH), + startTangent = VectorToSpeckle(revitDuct.StartTangent, revitDuct.Document), + endTangent = VectorToSpeckle(revitDuct.EndTangent, revitDuct.Document), + velocity = GetParamValue(revitDuct, BuiltInParameter.RBS_VELOCITY), + level = ConvertAndCacheLevel(revitDuct, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitDuct) + }; + + if (revitDuct.MEPSystem != null) + { + var material = ConverterRevit.GetMEPSystemMaterial(revitDuct); + if (material != null) + { + foreach (var mesh in speckleDuct.displayValue) + { + mesh["renderMaterial"] = material; + } + } + + var typeElem = revitDuct.Document.GetElement(revitDuct.MEPSystem.GetTypeId()); + speckleDuct.systemName = typeElem.Name; + } + + foreach (var connector in revitDuct.GetConnectorSet()) + { + speckleDuct.Connectors.Add(ConnectorToSpeckle(connector)); + } + + GetAllRevitParamsAndIds( + speckleDuct, + revitDuct, + new List + { + "RBS_CURVE_HEIGHT_PARAM", + "RBS_CURVE_WIDTH_PARAM", + "RBS_CURVE_DIAMETER_PARAM", + "CURVE_ELEM_LENGTH", + "RBS_START_LEVEL_PARAM", + "RBS_VELOCITY" + } + ); + + return speckleDuct; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFabricationPart.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFabricationPart.cs new file mode 100644 index 0000000000..99c27e1f9c --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFabricationPart.cs @@ -0,0 +1,19 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using System.Collections.Generic; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + /// + /// Convert fabrication parts to speckle elements + /// + /// Fabrication part in Revit + /// Conversion notes for the exceptional cases + /// RevitElement which represents converted fabrication part as speckle object + public RevitElement FabricationPartToSpeckle(FabricationPart revitElement, out List notes) + { + return RevitElementToSpeckle(revitElement, out notes); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFaceWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFaceWall.cs new file mode 100644 index 0000000000..eca96e0e34 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFaceWall.cs @@ -0,0 +1,260 @@ +using Autodesk.Revit.DB; +using ConverterRevitShared.Revit; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Speckle.Core.Models.Extensions; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + //TODO: delete temp family after creation + //TODO: allow updates to family..? + + //NOTE: FaceWalls cannot be updated, as well we can't seem to get their base face easily so they are ToNatvie only + public ApplicationObject FaceWallToNative(RevitFaceWall speckleWall) + { + FaceWall revitWall = GetExistingElementByApplicationId(speckleWall.applicationId) as FaceWall; + var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) + { + applicationId = speckleWall.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitWall, appObj)) + { + return appObj; + } + + if (speckleWall.surface == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Facewall surface was null"); + return appObj; + } + + if (revitWall != null) + { + Doc.Delete(revitWall.Id); + } + + var templatePath = GetTemplatePath("Mass"); + if (!File.Exists(templatePath)) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Could not find file {Path.GetFileName(templatePath)}" + ); + return appObj; + } + + var tempMassFamilyPath = CreateMassFamily(templatePath, speckleWall.surface, speckleWall.applicationId); + Family fam; + Doc.LoadFamily(tempMassFamilyPath, new FamilyLoadOption(), out fam); + var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as FamilySymbol; + symbol.Activate(); + + try + { + File.Delete(tempMassFamilyPath); + } + catch { } + + var mass = Doc.Create.NewFamilyInstance(XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + // NOTE: must set a schedule level! + // otherwise the wall creation will fail with "Could not create a face wall." + var level = new FilteredElementCollector(Doc) + .WhereElementIsNotElementType() + .OfCategory(BuiltInCategory.OST_Levels) // this throws a null error if user tries to recieve stream in a file with no levels + .ToElements() + .FirstOrDefault(); + + if (level == null) // create a new level at 0 if no levels could be retrieved from doc + { + level = Level.Create(Doc, 0); + } + + TrySetParam(mass, BuiltInParameter.INSTANCE_SCHEDULE_ONLY_LEVEL_PARAM, level); + + //must regenerate before getting the elem geometry + Doc.Regenerate(); + Reference faceRef = GetFaceRef(mass); + + var wallType = GetElementType(speckleWall, appObj, out bool _); + if (wallType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + if (!FaceWall.IsWallTypeValidForFaceWall(Doc, wallType.Id)) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Wall type {wallType.Name} not valid for facewall" + ); + return appObj; + } + + revitWall = null; + try + { + revitWall = DB.FaceWall.Create(Doc, wallType.Id, GetWallLocationLine(speckleWall.locationLine), faceRef); + } + catch (Exception e) { } + + if (revitWall == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Revit wall creation returned null"); + return appObj; + } + + Doc.Delete(mass.Id); + + SetInstanceParameters(revitWall, speckleWall); + appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); + //appObj = SetHostedElements(speckleWall, revitWall, appObj); + return appObj; + } + + public ApplicationObject FaceWallToNativeV2(RevitFaceWall speckleWall) + { + var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) + { + applicationId = speckleWall.applicationId + }; + try + { + var existing = GetExistingElementByApplicationId(speckleWall.applicationId) as FaceWall; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(existing, appObj)) + { + return appObj; + } + + if (speckleWall.brep == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "FaceWall geometry was null"); + return appObj; + } + + if (existing != null) + { + Doc.Delete(existing.Id); + } + + var wallType = GetElementType(speckleWall, appObj, out bool _); + if (wallType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (!FaceWall.IsWallTypeValidForFaceWall(Doc, wallType.Id)) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Wall type {wallType.Name} not valid for FaceWall" + ); + return appObj; + } + + List notes = null; + var solid = BrepToNative(speckleWall.brep, out notes); + var faceReference = solid.Faces.get_Item(0); + var faceref = faceReference.Reference; + var freeform = CreateFreeformElementFamily(new List { solid }, speckleWall.id, "Mass"); + Doc.Regenerate(); + faceref = GetFaceRef(freeform); + var revitWall = FaceWall.Create(Doc, wallType.Id, GetWallLocationLine(speckleWall.locationLine), faceref); + //Doc.Delete(freeform.Id); + SetInstanceParameters(revitWall, speckleWall); + appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); + //appObj = SetHostedElements(speckleWall, revitWall, appObj); + return appObj; + } + catch (Exception e) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Revit wall creation failed: {e.Message}", + log: new List { e.ToFormattedString() } + ); + return appObj; + } + } + + private Reference GetFaceRef(Element e) + { + var geomOption = e.Document.Application.Create.NewGeometryOptions(); + geomOption.ComputeReferences = true; + geomOption.IncludeNonVisibleObjects = true; + geomOption.DetailLevel = ViewDetailLevel.Fine; + + var ge = e.get_Geometry(geomOption); + + foreach (GeometryObject geomObj in ge) + { + Solid geomSolid = geomObj as Solid; + if (null != geomSolid) + { + foreach (Face geomFace in geomSolid.Faces) + { + if (FaceWall.IsValidFaceReferenceForFaceWall(e.Document, geomFace.Reference)) + { + return geomFace.Reference; + } + } + } + } + return null; + } + + private string CreateMassFamily(string famPath, Geometry.Surface surface, string name) + { + var famDoc = Doc.Application.NewFamilyDocument(famPath); + + using (Transaction t = new(famDoc, "Create Mass")) + { + t.Start(); + + try + { + var pointLists = surface.GetControlPoints(); + var curveArray = new ReferenceArrayArray(); + + foreach (var list in pointLists) + { + var arr = new ReferencePointArray(); + foreach (var point in list) + { + var refPt = famDoc.FamilyCreate.NewReferencePoint(PointToNative(point)); + arr.Append(refPt); + } + + var curve = famDoc.FamilyCreate.NewCurveByPoints(arr); + var referenceArray = new ReferenceArray(); + referenceArray.Append(curve.GeometryCurve.Reference); + curveArray.Append(referenceArray); + } + + var loft = famDoc.FamilyCreate.NewLoftForm(true, curveArray); + } + catch (Exception e) { } + + t.Commit(); + } + var famName = "SpeckleMass_" + name; + string tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); + SaveAsOptions so = new(); + so.OverwriteExistingFile = true; + famDoc.SaveAs(tempFamilyPath, so); + famDoc.Close(); + Report.Log($"Created temp family {tempFamilyPath}"); + return tempFamilyPath; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFamilyInstance.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFamilyInstance.cs new file mode 100644 index 0000000000..eb091e7f7a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFamilyInstance.cs @@ -0,0 +1,937 @@ +using System; +using System.Collections.Generic; +using System.DoubleNumerics; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Objects.Organization; +using RevitSharedResources.Helpers; +using RevitSharedResources.Helpers.Extensions; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Point = Objects.Geometry.Point; +using RevitInstance = Objects.Other.Revit.RevitInstance; +using RevitSymbolElementType = Objects.BuiltElements.Revit.RevitSymbolElementType; +using SHC = RevitSharedResources.Helpers.Categories; +using Vector = Objects.Geometry.Vector; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + /// + /// Entry point for all revit family conversions. + /// + /// + /// + public Base FamilyInstanceToSpeckle(DB.FamilyInstance revitFi, out List notes) + { + notes = new List(); + Base @base = null; + + //adaptive components + if (AdaptiveComponentInstanceUtils.IsAdaptiveComponentInstance(revitFi)) + { + @base = AdaptiveComponentToSpeckle(revitFi); + } + + //these elements come when the curtain wall is generated + //if they are contained in 'subelements' then they have already been accounted for from a wall + //else if they are mullions then convert them as a generic family instance but add a isUGridLine prop + bool? isUGridLine = null; + if ( + @base == null + && ( + revitFi.Category.Id.IntegerValue == (int)BuiltInCategory.OST_CurtainWallMullions + || revitFi.Category.Id.IntegerValue == (int)BuiltInCategory.OST_CurtainWallPanels + ) + ) + { + if (SubelementIds.Contains(revitFi.Id)) + { + return null; + } + else if (revitFi is Mullion mullion) + { + if (mullion.LocationCurve is DB.Line locationLine && locationLine.Direction != null) + { + var direction = locationLine.Direction; + // TODO: add support for more severly sloped mullions. This isn't very robust at the moment + isUGridLine = Math.Abs(direction.X) > Math.Abs(direction.Y); + } + } + else + { + //TODO: sort these so we consistently get sub-elements from the wall element in case also sub-elements are sent + SubelementIds.Add(revitFi.Id); + } + } + + //beams & braces + if (@base == null && SHC.StructuralFraming.BuiltInCategories.HasCategory(revitFi.Category)) + { + if (revitFi.StructuralType == StructuralType.Beam) + { + @base = BeamToSpeckle(revitFi, out notes); + } + else if (revitFi.StructuralType == StructuralType.Brace) + { + @base = BraceToSpeckle(revitFi, out notes); + } + } + + //columns + if ( + @base == null && SHC.Column.BuiltInCategories.HasCategory(revitFi.Category) + || revitFi.StructuralType == StructuralType.Column + ) + { + @base = ColumnToSpeckle(revitFi, out notes); + } + + // MEP elements + if (revitFi.MEPModel?.ConnectorManager?.Connectors?.Size > 0) + { + @base = MEPFamilyInstanceToSpeckle(revitFi); + } + + // curtain panels + if (revitFi is DB.Panel panel) + { + @base = PanelToSpeckle(panel); + } + + // elements + var baseGeometry = LocationToSpeckle(revitFi); + var basePoint = baseGeometry as Point; + if (@base == null && basePoint == null) + { + @base = RevitElementToSpeckle(revitFi, out notes); + } + + // point based, convert these as revit instances + if (@base == null) + { + @base = RevitInstanceToSpeckle(revitFi, out notes, null); + } + + // add additional props to base object + if (isUGridLine.HasValue) + { + @base["isUGridLine"] = isUGridLine.Value; + } + + if (revitFi.Room != null) + { + @base["roomId"] = revitFi.Room.Id.ToString(); + } + + if (revitFi.ToRoom != null) + { + @base["toRoomId"] = revitFi.ToRoom.Id.ToString(); + } + + if (revitFi.FromRoom != null) + { + @base["fromRoomId"] = revitFi.FromRoom.Id.ToString(); + } + + return @base; + } + + #region OLD family instancing + //TODO: deprecate when we no longer want to support receiving old commits with the `BuiltElements.Revit.FamilyInstance` class + public ApplicationObject FamilyInstanceToNative(BuiltElements.Revit.FamilyInstance speckleFi) + { + XYZ basePoint = PointToNative(speckleFi.basePoint); + DB.Level level = ConvertLevelToRevit(speckleFi.level, out ApplicationObject.State levelState); + DB.FamilyInstance familyInstance = null; + var isUpdate = false; + + var docObj = GetExistingElementByApplicationId(speckleFi.applicationId); + var appObj = new ApplicationObject(speckleFi.id, speckleFi.speckle_type) + { + applicationId = speckleFi.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + var familySymbol = GetElementType(speckleFi, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (docObj != null) + { + try + { + var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; + + // if family changed, tough luck. delete and let us create a new one. + if (familySymbol.FamilyName != revitType.FamilyName) + { + Doc.Delete(docObj.Id); + } + else + { + familyInstance = (DB.FamilyInstance)docObj; + + //NOTE: updating an element location is quite buggy in Revit! + //Let's say the first time an element is created its base point/curve is @ 10m and the Level is @ 0m + //the element will be created @ 0m + //but when this element is updated (let's say with no changes), it will jump @ 10m (unless there is a level change)! + //to avoid this behavior we're always setting the previous location Z coordinate when updating an element + //this means the Z coord of an element will only be set by its Level + //and by additional parameters as sill height, base offset etc + var newLocationPoint = new XYZ(basePoint.X, basePoint.Y, (familyInstance.Location as LocationPoint).Point.Z); + + (familyInstance.Location as LocationPoint).Point = newLocationPoint; + + // BAND AID FIX ALERT + // this is one of the stranger issues I've encountered. When I set the location of a family instance + // it mostly works fine, but every so often it goes to a different location than the one I set + // it seems like just reassigning the location to the same thing we just assigned it to works + // I don't know why this is happening + if ((familyInstance.Location as LocationPoint).Point != newLocationPoint) + { + (familyInstance.Location as LocationPoint).Point = newLocationPoint; + } + + // check for a type change + if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) + { + familyInstance.ChangeTypeId(familySymbol.Id); + } + + TrySetParam(familyInstance, BuiltInParameter.FAMILY_LEVEL_PARAM, level); + TrySetParam(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); + } + isUpdate = true; + } + catch + { + //something went wrong, re-create it + } + } + + //create family instance + if (familyInstance == null) + { + //If the current host element is not null, it means we're coming from inside a nested conversion. + if (CurrentHostElement != null) + { + var isUGridLine = speckleFi["isUGridLine"] as bool? != null ? (bool)speckleFi["isUGridLine"] : false; + familyInstance = CreateHostedFamilyInstance(appObj, familySymbol, basePoint, level, isUGridLine); + } + //Otherwise, proceed as normal. + else + { + familyInstance = Doc.Create.NewFamilyInstance(basePoint, familySymbol, level, StructuralType.NonStructural); + } + } + + //required for face flipping to work! + Doc.Regenerate(); + + if (familyInstance.CanFlipHand && speckleFi.handFlipped != familyInstance.HandFlipped) + { + familyInstance.flipHand(); + } + + if (familyInstance.CanFlipFacing && speckleFi.facingFlipped != familyInstance.FacingFlipped) + { + familyInstance.flipFacing(); + } + + // NOTE: do not check for the CanRotate prop as it doesn't work (at least on some families I tried)! + // some point based families don't have a rotation, so keep this in a try catch + try + { + if (speckleFi.rotation != (familyInstance.Location as LocationPoint).Rotation) + { + var axis = DB.Line.CreateBound(new XYZ(basePoint.X, basePoint.Y, 0), new XYZ(basePoint.X, basePoint.Y, 1000)); + (familyInstance.Location as LocationPoint).Rotate( + axis, + speckleFi.rotation - (familyInstance.Location as LocationPoint).Rotation + ); + } + } + catch { } + + if ( + familySymbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased + && speckleFi["topLevel"] is Objects.BuiltElements.Level topLevel + ) + { + var revitTopLevel = ConvertLevelToRevit(topLevel, out ApplicationObject.State topLevelState); + TrySetParam(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, revitTopLevel); + } + + SetInstanceParameters(familyInstance, speckleFi); + if (speckleFi.mirrored) + { + appObj.Update( + logItem: $"Element with id {familyInstance.Id} should be mirrored, but a Revit API limitation prevented us from doing so." + ); + } + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: familyInstance.UniqueId, convertedItem: familyInstance); + return appObj; + } + + private DB.FamilyInstance CreateHostedFamilyInstance( + ApplicationObject appObj, + DB.FamilySymbol familySymbol, + XYZ insertionPoint, + DB.Level level, + bool isUGridLine = false + ) + { + DB.FamilyInstance familyInstance = null; + //If the current host element is not null, it means we're coming from inside a nested conversion. + + if (level == null) + { + level = Doc.GetElement(CurrentHostElement.LevelId) as DB.Level; + } + + // there are two (i think) main types of hosted elements which can be found with family.familyplacementtype + // the two placement types for hosted elements are onelevelbasedhosted and workplanebased + + if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBasedHosted) + { + familyInstance = Doc.Create.NewFamilyInstance( + insertionPoint, + familySymbol, + CurrentHostElement, + level, + StructuralType.NonStructural + ); + } + else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.WorkPlaneBased) + { + if (CurrentHostElement == null) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Object is work plane based but does not have a host element" + ); + return null; + } + if (CurrentHostElement is Element el) + { + Doc.Regenerate(); + + Options op = new(); + op.ComputeReferences = true; + GeometryElement geomElement = el.get_Geometry(op); + Reference faceRef = null; + var planeDist = double.MaxValue; + + GetReferencePlane(geomElement, insertionPoint, ref faceRef, ref planeDist); + + XYZ norm = new(0, 0, 0); + familyInstance = Doc.Create.NewFamilyInstance(faceRef, insertionPoint, norm, familySymbol); + + // parameters + IList cutVoidsParams = familySymbol.Family.GetParameters("Cut with Voids When Loaded"); + IList lvlParams = familyInstance.GetParameters("Schedule Level"); + + if (cutVoidsParams.ElementAtOrDefault(0) != null && cutVoidsParams[0].AsInteger() == 1) + { + InstanceVoidCutUtils.AddInstanceVoidCut(Doc, el, familyInstance); + } + + try + { + if (lvlParams.ElementAtOrDefault(0) != null) + { + lvlParams[0].Set(level.Id); // this can be null + } + } + catch { } + } + else if (CurrentHostElement is DB.Floor floor) + { + // TODO: support hosted elements on floors. Should be very similar to above implementation + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Work Plane based families on floors to be supported soon" + ); + return null; + } + } + else if (familySymbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased) + { + if (CurrentHostElement is FootPrintRoof roof) + { + // handle receiving mullions on a curtain roof + var curtainGrids = roof.CurtainGrids; + CurtainGrid lastGrid = null; + foreach (var curtainGrid in curtainGrids) + { + if (curtainGrid is CurtainGrid c) + { + lastGrid = c; + } + } + + if (lastGrid != null && isUGridLine) + { + var gridLine = lastGrid.AddGridLine(isUGridLine, insertionPoint, false); + foreach (var seg in gridLine.AllSegmentCurves) + { + gridLine.AddMullions(seg as Curve, familySymbol as MullionType, isUGridLine); + } + } + } + } + else + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Unsupported FamilyPlacementType {familySymbol.Family.FamilyPlacementType}" + ); + return null; + } + // try a catch all solution as a last resort + if (familyInstance == null) + { + try + { + familyInstance = Doc.Create.NewFamilyInstance( + insertionPoint, + familySymbol, + CurrentHostElement, + level, + StructuralType.NonStructural + ); + } + catch { } + } + + return familyInstance; + } + + #endregion + + private void GetReferencePlane( + GeometryElement geomElement, + XYZ basePoint, + ref Reference faceRef, + ref double planeDist + ) + { + foreach (var geom in geomElement) + { + if (geom is Solid solid) + { + FaceArray faceArray = solid.Faces; + + foreach (Face face in faceArray) + { + if (face is PlanarFace planarFace) + { + // some family instance base points may lie on the intersection of faces + // this makes it so family instance families can only be placed on the + // faces of walls + double D = + planarFace.FaceNormal.X * planarFace.Origin.X + + planarFace.FaceNormal.Y * planarFace.Origin.Y + + planarFace.FaceNormal.Z * planarFace.Origin.Z; + double PointD = + planarFace.FaceNormal.X * basePoint.X + + planarFace.FaceNormal.Y * basePoint.Y + + planarFace.FaceNormal.Z * basePoint.Z; + double value = Math.Abs(D - PointD); + double newPlaneDist = Math.Abs(D - PointD); + if (newPlaneDist < planeDist) + { + planeDist = newPlaneDist; + faceRef = planarFace.Reference; + } + } + } + } + else if (geom is GeometryInstance geomInst) + { + GeometryElement transformedGeom = geomInst.GetInstanceGeometry(geomInst.Transform); + GetReferencePlane(transformedGeom, basePoint, ref faceRef, ref planeDist); + } + } + } + + #region new instancing + + // transforms + private Other.Transform TransformToSpeckle( + Transform transform, + Document doc, + bool skipDocReferencePointTransform = false + ) + { + var externalTransform = transform; + + // get the reference point transform and apply if this is a top level instance + if (!skipDocReferencePointTransform) + { + var docTransform = GetDocReferencePointTransform(doc); + externalTransform = docTransform.Inverse.Multiply(transform); + } + + // translation + var tX = ScaleToSpeckle(externalTransform.Origin.X, ModelUnits); + var tY = ScaleToSpeckle(externalTransform.Origin.Y, ModelUnits); + var tZ = ScaleToSpeckle(externalTransform.Origin.Z, ModelUnits); + var t = new Vector(tX, tY, tZ, ModelUnits); + + // basis vectors + var vX = new Vector(externalTransform.BasisX.X, externalTransform.BasisX.Y, externalTransform.BasisX.Z, ModelUnits); + var vY = new Vector(externalTransform.BasisY.X, externalTransform.BasisY.Y, externalTransform.BasisY.Z, ModelUnits); + var vZ = new Vector(externalTransform.BasisZ.X, externalTransform.BasisZ.Y, externalTransform.BasisZ.Z, ModelUnits); + + // get the scale: TODO: do revit transforms ever have scaling? + var scale = transform.Scale; + + return new Other.Transform(vX, vY, vZ, t) { units = ModelUnits }; + } + + private Transform TransformToNative(Other.Transform transform) + { + var _transform = new Transform(Transform.Identity); + + // translation + if (transform.matrix.M44 == 0) + { + return _transform; + } + + var tX = ScaleToNative(transform.matrix.M14 / transform.matrix.M44, transform.units); + var tY = ScaleToNative(transform.matrix.M24 / transform.matrix.M44, transform.units); + var tZ = ScaleToNative(transform.matrix.M34 / transform.matrix.M44, transform.units); + var t = new XYZ(tX, tY, tZ); + + // basis vectors + XYZ vX = new(transform.matrix.M11, transform.matrix.M21, transform.matrix.M31); + XYZ vY = new(transform.matrix.M12, transform.matrix.M22, transform.matrix.M32); + XYZ vZ = new(transform.matrix.M13, transform.matrix.M23, transform.matrix.M33); + + // apply to new transform + _transform.Origin = t; + _transform.BasisX = vX.Normalize(); + _transform.BasisY = vY.Normalize(); + _transform.BasisZ = vZ.Normalize(); + + // apply doc transform + var docTransform = GetDocReferencePointTransform(Doc); + var internalTransform = docTransform.Multiply(_transform); + + return internalTransform; + } + + // revit instances + public ApplicationObject RevitInstanceToNative(RevitInstance instance, ApplicationObject appObj = null) + { + DB.FamilyInstance familyInstance = null; + var docObj = GetExistingElementByApplicationId(instance.applicationId); + appObj ??= new ApplicationObject(instance.id, instance.speckle_type) { applicationId = instance.applicationId }; + var isUpdate = false; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + // get the definition + var definition = instance.definition as RevitSymbolElementType; + var familySymbol = GetElementType(definition, appObj, out bool isExactMatch); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if ( + familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_CurtainWallMullions) + || familySymbol.Category.EqualsBuiltInCategory(BuiltInCategory.OST_CurtainWallPanels) + ) + { + appObj.Update( + logItem: "Revit cannot create standalone curtain panels or mullions", + status: ApplicationObject.State.Skipped + ); + return appObj; + } + + // get the transform, insertion point, level, and placement type of the instance + var transform = TransformToNative(instance.transform); + DB.Level level = ConvertLevelToRevit(instance.level, out ApplicationObject.State levelState); + var insertionPoint = transform.OfPoint(XYZ.Zero); + FamilyPlacementType placement = Enum.TryParse( + definition.placementType, + true, + out FamilyPlacementType placementType + ) + ? placementType + : FamilyPlacementType.Invalid; + + // check for existing and update if so + if (docObj != null) + { + try + { + var revitType = Doc.GetElement(docObj.GetTypeId()) as ElementType; + + // if family changed, tough luck. delete and let us create a new one. + if (familySymbol.FamilyName != revitType.FamilyName) + { + Doc.Delete(docObj.Id); + } + else + { + familyInstance = (DB.FamilyInstance)docObj; + + var newLocationPoint = new XYZ( + insertionPoint.X, + insertionPoint.Y, + (familyInstance.Location as LocationPoint).Point.Z + ); + (familyInstance.Location as LocationPoint).Point = newLocationPoint; + + // check for a type change + if (isExactMatch && revitType.Id.IntegerValue != familySymbol.Id.IntegerValue) + { + familyInstance.ChangeTypeId(familySymbol.Id); + } + + TrySetParam(familyInstance, BuiltInParameter.FAMILY_LEVEL_PARAM, level); + TrySetParam(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM, level); + } + isUpdate = true; + } + catch + { + //something went wrong, re-create it + } + } + + //create family instance + + if (familyInstance == null) + { + switch (placement) + { + case FamilyPlacementType.OneLevelBasedHosted when CurrentHostElement != null: + familyInstance = Doc.Create.NewFamilyInstance( + insertionPoint, + familySymbol, + CurrentHostElement, + level, + StructuralType.NonStructural + ); + break; + + case FamilyPlacementType.WorkPlaneBased when CurrentHostElement != null: + Options op = new() { ComputeReferences = true }; + GeometryElement geomElement = CurrentHostElement.get_Geometry(op); + if (geomElement == null) + { + // if host geom was null, then regenerate document and that should fix it + Doc.Regenerate(); + geomElement = CurrentHostElement.get_Geometry(op); + // if regenerating didn't fix it then try generic method + // TODO: this won't be correct, maybe we should just throw an error? + if (geomElement == null) + { + goto default; + } + } + Reference faceRef = null; + var planeDist = double.MaxValue; + GetReferencePlane(geomElement, insertionPoint, ref faceRef, ref planeDist); + XYZ norm = new(0, 0, 0); + try + { + familyInstance = Doc.Create.NewFamilyInstance(faceRef, insertionPoint, norm, familySymbol); + } + catch (Exception e) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Could not create WorkPlaneBased hosted instance: {e.Message}" + ); + return appObj; + } + // parameters + IList cutVoidsParams = familySymbol.Family.GetParameters("Cut with Voids When Loaded"); + IList lvlParams = familyInstance.GetParameters("Schedule Level"); + if (cutVoidsParams.ElementAtOrDefault(0) != null && cutVoidsParams[0].AsInteger() == 1) + { + InstanceVoidCutUtils.AddInstanceVoidCut(Doc, CurrentHostElement, familyInstance); + } + + if (lvlParams.ElementAtOrDefault(0) != null && level != null) + { + lvlParams[0].Set(level.Id); + } + + break; + + case FamilyPlacementType.OneLevelBased when CurrentHostElement is FootPrintRoof roof: // handle receiving mullions on a curtain roof + var curtainGrids = roof.CurtainGrids; + CurtainGrid lastGrid = null; + foreach (var curtainGrid in curtainGrids) + { + if (curtainGrid is CurtainGrid c) + { + lastGrid = c; + } + } + + var isUGridLine = instance["isUGridLine"] as bool? != null ? (bool)instance["isUGridLine"] : false; + if (lastGrid != null && isUGridLine) + { + var gridLine = lastGrid.AddGridLine(isUGridLine, insertionPoint, false); + foreach (var seg in gridLine.AllSegmentCurves) + { + gridLine.AddMullions(seg as Curve, familySymbol as MullionType, isUGridLine); + } + } + break; + + default: + familyInstance = Doc.Create.NewFamilyInstance( + insertionPoint, + familySymbol, + level, + StructuralType.NonStructural + ); + break; + } + } + + if (familyInstance == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create instance"); + return appObj; + } + + Doc.Regenerate(); //required for mirroring and face flipping to work! + + if (instance.mirrored != familyInstance.Mirrored) + { + // mirroring + // note: mirroring a hosted instance via api will fail, thanks revit: there is workaround hack to group the element -> mirror -> ungroup + Group group = null; + try + { + group = CurrentHostElement != null ? Doc.Create.NewGroup(new[] { familyInstance.Id }) : null; + } + catch (Autodesk.Revit.Exceptions.InvalidOperationException) + { + // sometimes the group can't be made. Just try to mirror the element on its own + } + var elementToMirror = group != null ? new[] { group.Id } : new[] { familyInstance.Id }; + + try + { + ElementTransformUtils.MirrorElements( + Doc, + elementToMirror, + DB.Plane.CreateByNormalAndOrigin(transform.BasisY, insertionPoint), + false + ); + } + catch (Exception e) + { + appObj.Update(logItem: $"Instance could not be mirrored: {e.Message}"); + } + group?.UngroupMembers(); + } + + // face flipping must happen after mirroring + if (familyInstance.CanFlipHand && instance.handFlipped != familyInstance.HandFlipped) + { + familyInstance.flipHand(); + } + + if (familyInstance.CanFlipFacing && instance.facingFlipped != familyInstance.FacingFlipped) + { + familyInstance.flipFacing(); + } + + var currentTransform = familyInstance.GetTotalTransform(); + var desiredBasisX = new Vector(transform.BasisX.X, transform.BasisX.Y, transform.BasisX.Z); + var currentBasisX = new Vector(currentTransform.BasisX.X, currentTransform.BasisX.Y, currentTransform.BasisX.Z); + + // rotation about the z axis (signed) + var rotation = Math.Atan2( + Vector.DotProduct( + Vector.CrossProduct(desiredBasisX, currentBasisX), + new Vector(currentTransform.BasisZ.X, currentTransform.BasisZ.Y, currentTransform.BasisZ.Z) + ), + Vector.DotProduct(desiredBasisX, currentBasisX) + ); + + if (Math.Abs(rotation) > TOLERANCE && familyInstance.Location is LocationPoint location) + { + try // some point based families don't have a rotation, so keep this in a try catch + { + using var axis = DB.Line.CreateUnbound(location.Point, currentTransform.BasisZ); + location.Rotate(axis, -rotation); + } + catch (Exception e) + { + appObj.Update(logItem: $"Could not rotate created instance: {e.Message}"); + } + } + + SetInstanceParameters(familyInstance, instance); + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: familyInstance.UniqueId, convertedItem: familyInstance); + //appObj = SetHostedElements(instance, familyInstance, appObj); + return appObj; + } + + public RevitInstance RevitInstanceToSpeckle( + DB.FamilyInstance instance, + out List notes, + Transform parentTransform, + bool useParentTransform = false, + RevitInstance existingInstance = null + ) + { + notes = new List(); + + // get the transform + var instanceTransform = instance.GetTotalTransform(); + var localTransform = instanceTransform; + if (useParentTransform) // this is a nested instance, remove the parent transform from it and don't apply doc reference point transforms + { + localTransform = parentTransform.Inverse.Multiply(instanceTransform); + } + var transform = TransformToSpeckle(localTransform, instance.Document, useParentTransform); + + // get the definition base of this instance + RevitSymbolElementType definition = GetRevitInstanceDefinition( + instance, + out List definitionNotes, + instanceTransform + ); + notes.AddRange(definitionNotes); + + var _instance = existingInstance ?? new RevitInstance(); + _instance.transform = transform; + _instance.typedDefinition = definition; + _instance.level = ConvertAndCacheLevel(instance, BuiltInParameter.FAMILY_LEVEL_PARAM); + _instance.facingFlipped = instance.FacingFlipped; + _instance.handFlipped = instance.HandFlipped; + _instance.mirrored = instance.Mirrored; + + // if a family instance is twoLevelBased, then store the top level + if (instance.Symbol.Family.FamilyPlacementType == FamilyPlacementType.TwoLevelsBased) + { + _instance["topLevel"] = ConvertAndCacheLevel(instance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + _instance["topLevel"] ??= ConvertAndCacheLevel(instance, BuiltInParameter.SCHEDULE_TOP_LEVEL_PARAM); + } + + GetAllRevitParamsAndIds(_instance, instance); + + return _instance; + } + + /// + /// Converts the familysymbol into a revitsymbolelementtype + /// + /// + /// + /// + /// + /// TODO: could potentially optimize this for symbols with the same displayvalues by caching previously converted symbols + private RevitSymbolElementType GetRevitInstanceDefinition( + DB.FamilyInstance instance, + out List notes, + Transform parentTransform + ) + { + notes = new List(); + var symbol = + ElementTypeToSpeckle(instance.Document.GetElement(instance.GetTypeId()) as ElementType) as RevitSymbolElementType; + if (symbol == null) + { + notes.Add($"Could not convert element type as FamilySymbol"); + return null; + } + + // get the displayvalue of the family symbol + try + { + var meshes = GetElementDisplayValue(instance, isConvertedAsInstance: true, transform: parentTransform); + symbol.displayValue = meshes; + } + catch (Exception e) + { + notes.Add($"Could not retrieve display meshes: {e.Message}"); + } + + #region sub elements capture + + var subElementIds = instance.GetSubComponentIds(); + var convertedSubElements = new List(); + + foreach (var elemId in subElementIds) + { + var subElem = instance.Document.GetElement(elemId); + Base converted = null; + switch (subElem) + { + case DB.FamilyInstance o: + converted = RevitInstanceToSpeckle(o, out notes, parentTransform, true); + if (converted == null) + { + goto default; + } + + break; + default: + converted = ConvertToSpeckle(subElem); + break; + } + if (converted != null) + { + convertedSubElements.Add(converted); + ConvertedObjects.Add(converted.applicationId); + } + } + + if (convertedSubElements.Any()) + { + symbol.elements = convertedSubElements; + } + #endregion + + var material = ConverterRevit.GetMEPSystemMaterial(instance); + + if (material != null) + { + foreach (var mesh in symbol.displayValue) + { + mesh["renderMaterial"] = material; + } + } + + return symbol; + } + #endregion +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFitting.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFitting.cs new file mode 100644 index 0000000000..8a7111fa2a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFitting.cs @@ -0,0 +1,210 @@ +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Autodesk.Revit.DB; +using Speckle.Core.Kits; +using Speckle.Core.Models; +using Speckle.Core.Logging; +using System; +using ConverterRevitShared.Extensions; +using System.Linq; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public DB.FamilyInstance FittingToNative( + RevitMEPFamilyInstance speckleRevitFitting, + PartType partType, + ApplicationObject appObj + ) + { + var docObj = GetExistingElementByApplicationId(speckleRevitFitting.applicationId); + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return null; + } + + var connectorInfo = ValidateConnectorsAndPopulateList(speckleRevitFitting); + + var familyInstance = + TryCreateFitting(partType, docObj, connectorInfo) + ?? throw new SpeckleException($"{nameof(FittingToNative)} yeilded a null familyInstance"); + + var familySymbol = GetElementType( + speckleRevitFitting, + new ApplicationObject(null, null), + out bool isExactMatch + ); + + if (isExactMatch && familyInstance.Symbol.Id.IntegerValue != familySymbol.Id.IntegerValue) + { + familyInstance.ChangeTypeId(familySymbol.Id); + } + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: familyInstance.UniqueId, + convertedItem: familyInstance + ); + + return familyInstance; + } + + private DB.FamilyInstance TryCreateFitting(PartType partType, Element docObj, List<(Element, int)> connectorInfo) + { + switch (partType) + { + case PartType.Elbow: + if (connectorInfo.Count != 2) + { + throw new SpeckleException( + $"A fitting with a partType of {nameof(PartType.Elbow)} must have 2 connectors, not {connectorInfo.Count}" + ); + } + if (ReceiveMode == ReceiveMode.Update && docObj != null) + { + Doc.Delete(docObj.Id); + } + return Doc.Create.NewElbowFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])); + case PartType.Transition: + if (connectorInfo.Count != 2) + { + throw new SpeckleException( + $"A fitting with a partType of {nameof(PartType.Transition)} must have 2 connectors, not {connectorInfo.Count}" + ); + } + if (ReceiveMode == ReceiveMode.Update && docObj != null) + { + Doc.Delete(docObj.Id); + } + var revitFitting = TryInSubtransaction( + () => Doc.Create.NewTransitionFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])), + ex => { } + ); + revitFitting ??= TryInSubtransaction( + () => Doc.Create.NewTransitionFitting(GetConnector(connectorInfo[1]), GetConnector(connectorInfo[0])), + ex => throw ex + ); + return revitFitting; + case PartType.Union: + if (connectorInfo.Count != 2) + { + throw new SpeckleException( + $"A fitting with a partType of {nameof(PartType.Union)} must have 2 connectors, not {connectorInfo.Count}" + ); + } + if (ReceiveMode == ReceiveMode.Update && docObj != null) + { + Doc.Delete(docObj.Id); + } + return Doc.Create.NewUnionFitting(GetConnector(connectorInfo[0]), GetConnector(connectorInfo[1])); + case PartType.Tee: + if (connectorInfo.Count != 3) + { + throw new SpeckleException( + $"A fitting with a partType of {nameof(PartType.Tee)} must have 3 connectors, not {connectorInfo.Count}" + ); + } + if (ReceiveMode == ReceiveMode.Update && docObj != null) + { + Doc.Delete(docObj.Id); + } + return Doc.Create.NewTeeFitting( + GetConnector(connectorInfo[0]), + GetConnector(connectorInfo[1]), + GetConnector(connectorInfo[2]) + ); + case PartType.Cross: + if (connectorInfo.Count != 4) + { + throw new SpeckleException( + $"A fitting with a partType of {nameof(PartType.Cross)} must have 4 connectors, not {connectorInfo.Count}" + ); + } + if (ReceiveMode == ReceiveMode.Update && docObj != null) + { + Doc.Delete(docObj.Id); + } + return Doc.Create.NewCrossFitting( + GetConnector(connectorInfo[0]), + GetConnector(connectorInfo[1]), + GetConnector(connectorInfo[2]), + GetConnector(connectorInfo[3]) + ); + default: + throw new SpeckleException( + $"Method named {nameof(FittingToNative)} was not expecting an element with a partType of {partType}" + ); + } + } + + /// + /// Attempting to add a fitting between two connectors and rolling back a subtransaction will result in the + /// connector element references becomeing invalid. Therefore, instead of passing around the connector objects, + /// we're keeping track of the owner element and the connector id so we can retrieve the connector + /// connector id + /// + /// + /// + private Connector GetConnector((Element, int) connectorInfo) => + connectorInfo.Item1.GetConnectorSet().First(c => c.Id == connectorInfo.Item2); + + private List<(Element, int)> ValidateConnectorsAndPopulateList(RevitMEPFamilyInstance speckleRevitFitting) + { + List<(Element, int)> connectors = new(); + foreach (var speckleRevitConnector in speckleRevitFitting.Connectors) + { + var con = FindNativeConnectorForSpeckleRevitConnector(speckleRevitConnector); + connectors.Add(con); + } + return connectors; + } + + private (Element, int) FindNativeConnectorForSpeckleRevitConnector(RevitMEPConnector speckleRevitConnector) + { + List exceptions = new(); + foreach ( + var (elementAppId, element, existingConnector) in GetRevitConnectorsThatConnectToSpeckleConnector( + speckleRevitConnector, + receivedObjectsCache + ) + ) + { + if (existingConnector != null) + { + // we only want one native connector per speckleRevitConnector so return if we find a match + return (element, existingConnector.Id); + } + else if (element != null) + { + // if the element is not null but the connector is, then the correct connector on the element could not + // be found by trying to compare locations of all the connectors on the element + exceptions.Add( + new SpeckleException( + "Fitting found native element to connect to but could not find \"connector\" subelement which is needed for connection in Revit" + ) + ); + } + else if (string.IsNullOrEmpty(elementAppId)) + { + exceptions.Add(new SpeckleException("A connector has a reference to a null applicationId")); + } + else if (ContextObjects.ContainsKey(elementAppId)) + { + // here a native element could not be found. Hopefully it is yet to be converted and we can + // try to convert the fitting later + throw new ConversionNotReadyException("All connectors must be converted before fitting"); + } + else + { + // TODO: the fitting doesn't exist in the incoming commit. Maybe we can add a placeholder? + exceptions.Add( + new SpeckleException("The element that the fitting connects to is not in the incoming Commit object") + ); + } + } + throw new AggregateException(exceptions); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFloor.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFloor.cs new file mode 100644 index 0000000000..8adcedcd38 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFloor.cs @@ -0,0 +1,498 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using OG = Objects.Geometry; +using OO = Objects.Other; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject FloorToNative(BuiltElements.Floor speckleFloor) + { + var docObj = GetExistingElementByApplicationId(speckleFloor.applicationId); + var appObj = new ApplicationObject(speckleFloor.id, speckleFloor.speckle_type) + { + applicationId = speckleFloor.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (speckleFloor.outline == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Floor is missing an outline."); + return appObj; + } + + bool structural = false; + if (speckleFloor["structural"] is bool isStructural) + { + structural = isStructural; + } + + var levelState = ApplicationObject.State.Unknown; + double baseOffset = 0.0; + DB.Level level = + (speckleFloor.level != null) + ? ConvertLevelToRevit(speckleFloor.level, out levelState) + : ConvertLevelToRevit( + CurveToNative(speckleFloor.outline).get_Item(0), + out ApplicationObject.State state, + out baseOffset + ); + + double slope = 0; + DB.Line slopeDirection = null; + if (speckleFloor is RevitFloor speckleRevitFloor) + { + structural = speckleRevitFloor.structural; + slope = speckleRevitFloor.slope; + slopeDirection = + (speckleRevitFloor.slopeDirection != null) ? LineToNative(speckleRevitFloor.slopeDirection) : null; + } + + var flattenedOutline = GetFlattenedCurve(speckleFloor.outline, level.Elevation); + var outline = CurveToNative(flattenedOutline, true); + UnboundCurveIfSingle(outline); + + var floorType = GetElementType(speckleFloor, appObj, out bool _); + if (floorType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + // NOTE: I have not found a way to edit a slab outline properly, so whenever we bake, we renew the element. The closest thing would be: + // https://adndevbConversionLog.Add.typepad.com/aec/2013/10/change-the-boundary-of-floorsslabs.html + // This would only work if the floors have the same number (and type!!!) of outline curves. + + + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + DB.Floor revitFloor = null; + +#if (REVIT2020 || REVIT2021) + if (floorType == null) + { + if (slope != 0 && slopeDirection != null) + { + revitFloor = Doc.Create.NewSlab(outline, level, slopeDirection, slope, structural); + } + + if (revitFloor == null) + { + revitFloor = Doc.Create.NewFloor(outline, structural); + } + } + else + { + if (slope != 0 && slopeDirection != null) + { + revitFloor = Doc.Create.NewSlab(outline, level, slopeDirection, slope, structural); + } + + if (revitFloor == null) + { + revitFloor = Doc.Create.NewFloor(outline, floorType, level, structural); + } + } + +#else + if (floorType == null) + { + throw new SpeckleException("Floor needs a floor type"); + } + else + { + //from revit 2022 we can create openings in the floors! + var profile = new List { CurveArrayToCurveLoop(outline) }; + if (speckleFloor["voids"] != null && (speckleFloor["voids"] is List voids)) + { + foreach (var v in voids) + { + var opening = CurveArrayToCurveLoop(CurveToNative(v, true)); + profile.Add(opening); + } + } + + if (slope != 0 && slopeDirection != null) + { + revitFloor = Floor.Create(Doc, profile, floorType.Id, level.Id, structural, slopeDirection, slope); + } + + if (revitFloor == null) + { + revitFloor = Floor.Create(Doc, profile, floorType.Id, level.Id, structural, null, 0); + } + } +#endif + if (speckleFloor is not RevitFloor) + { + TrySetParam(revitFloor, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM, -baseOffset); + } + + Doc.Regenerate(); + +#if (REVIT2020 || REVIT2021) + try + { + CreateVoids(revitFloor, speckleFloor); + } + catch (Exception ex) + { + appObj.Update(logItem: $"Could not create openings: {ex.Message}"); + } +#endif + + SetInstanceParameters(revitFloor, speckleFloor); + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitFloor.UniqueId, convertedItem: revitFloor); + //appObj = SetHostedElements(speckleFloor, revitFloor, appObj); + return appObj; + } + + private RevitFloor FloorToSpeckle(DB.Floor revitFloor, out List notes) + { + notes = new List(); + var speckleFloor = new RevitFloor(); +#if REVIT2020 || REVIT2021 + var profiles = GetProfiles(revitFloor); +#else + var sketch = Doc.GetElement(revitFloor.SketchId) as Sketch; + var profiles = GetSketchProfiles(sketch).Cast().ToList(); +#endif + var type = revitFloor.Document.GetElement(revitFloor.GetTypeId()) as ElementType; + speckleFloor.family = type?.FamilyName; + speckleFloor.type = type?.Name; + speckleFloor.outline = profiles[0]; + if (profiles.Count > 1) + { + speckleFloor.voids = profiles.Skip(1).ToList(); + } + + speckleFloor.level = ConvertAndCacheLevel(revitFloor, BuiltInParameter.LEVEL_PARAM); + speckleFloor.structural = GetParamValue(revitFloor, BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL); + + // Divide by 100 to convert from percentage to unitless ratio (rise over run) + var slopeParam = GetParamValue(revitFloor, BuiltInParameter.ROOF_SLOPE) / 100; + + GetAllRevitParamsAndIds( + speckleFloor, + revitFloor, + new List { "LEVEL_PARAM", "FLOOR_PARAM_IS_STRUCTURAL", "ROOF_SLOPE" } + ); + + var slopeArrow = GetSlopeArrow(revitFloor); + if (slopeArrow != null) + { + var tail = GetSlopeArrowTail(slopeArrow, Doc); + var head = GetSlopeArrowHead(slopeArrow, Doc); + var tailOffset = GetSlopeArrowTailOffset(slopeArrow, Doc); + _ = GetSlopeArrowHeadOffset(slopeArrow, Doc, tailOffset, out var slope); + + slopeParam ??= slope; + speckleFloor.slope = (double)slopeParam; + + speckleFloor.slopeDirection = new Geometry.Line(tail, head); + if ( + speckleFloor["parameters"] is Base parameters + && parameters["FLOOR_HEIGHTABOVELEVEL_PARAM"] is BuiltElements.Revit.Parameter offsetParam + && offsetParam.value is double offset + ) + { + offsetParam.value = offset + tailOffset; + } + } + + speckleFloor.displayValue = GetElementDisplayValue(revitFloor); + + GetHostedElements(speckleFloor, revitFloor, out List hostedNotes); + if (hostedNotes.Any()) + { + notes.AddRange(hostedNotes); + } + + return speckleFloor; + } + + // Nesting the various profiles into a polycurve segments. + // TODO: **These should be HORIZONTAL on the floor level!** otherwise sloped floors will not be converted back to native properly + private List GetProfiles(DB.CeilingAndFloor floor) + { + var profiles = new List(); + var faces = HostObjectUtils.GetTopFaces(floor); + Face face = floor.GetGeometryObjectFromReference(faces[0]) as Face; + var crvLoops = face.GetEdgesAsCurveLoops(); + foreach (var crvloop in crvLoops) + { + var poly = new Polycurve(ModelUnits); + foreach (var curve in crvloop) + { + var c = curve; + if (c == null) + { + continue; + } + + poly.segments.Add(CurveToSpeckle(c, floor.Document)); + } + profiles.Add(poly); + } + return profiles; + } + + // in order to create a revit floor, we need to pass it a flat profile so change all the z values + private ICurve GetFlattenedCurve(ICurve curve, double z) + { + // kind of a hack. Editing our speckle objects is so much easier than editing the revit objects + // so scale this z value from the model units to the incoming commit units and then those values will + // get scaled back to the model units when this entire outline gets scaled to native + + switch (curve) + { + case OG.Arc arc: + var normalUnit = arc.plane.normal.Unit(); + var normalAsPoint = new OG.Point(normalUnit.x, normalUnit.y, normalUnit.z); + var arcConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, arc.units); + + if (normalAsPoint.DistanceTo(new OG.Point(0, 0, 1)) < TOLERANCE) + { + var translation = new OG.Vector(0, 0, (z * arcConversionFactor) - arc.startPoint.z) { units = ModelUnits }; + var transform = new OO.Transform( + new OG.Vector(1, 0, 0), + new OG.Vector(0, 1, 0), + new OG.Vector(0, 0, 1), + translation + ); + _ = arc.TransformTo(transform, out OG.Arc newArc); + return newArc; + } + else + { + // sneakily replace the users arc with a curve 🤫. + // TODO: set knots in curve or apply more complex transforms to arc because this replacement is decent but not perfect + + var newPlane = new OG.Plane( + new OG.Point(arc.plane.origin.x, arc.plane.origin.y, arc.plane.origin.z), + arc.plane.normal, + arc.plane.xdir, + arc.plane.ydir + ); + var firstHalfArc = new OG.Arc(newPlane, arc.midPoint, arc.startPoint, arc.angleRadians / 2, units: arc.units); + var secondHalfArc = new OG.Arc(newPlane, arc.endPoint, arc.midPoint, arc.angleRadians / 2, units: arc.units); + var arcCurvePoints = new List + { + arc.startPoint.x, + arc.startPoint.y, + z * arcConversionFactor, + firstHalfArc.midPoint.x, + firstHalfArc.midPoint.y, + z * arcConversionFactor, + arc.midPoint.x, + arc.midPoint.y, + z * arcConversionFactor, + secondHalfArc.midPoint.x, + secondHalfArc.midPoint.y, + z * arcConversionFactor, + arc.endPoint.x, + arc.endPoint.y, + z * arcConversionFactor + }; + + var newArcCurve = new OG.Curve + { + points = arcCurvePoints, + weights = new List(Enumerable.Repeat(1.0, arcCurvePoints.Count)), + //knots = nurbs.knots, + //degree = nurbs.degree, + rational = false, + closed = false, + //newCurve.domain + //newCurve.length + units = arc.units + }; + + return newArcCurve; + } + + // Note: this method is untested. It seems Revit doesn't send circles... it sends two arcs instead. + // Other applications may send circles though... needs more testing + case OG.Circle circle: + if (!(circle.radius is double radius && radius > 0)) + { + throw new Exception($"Circle with id, {circle.id}, does not have a valid radius"); + } + var circleNormalUnit = circle.plane.normal.Unit(); + var circleNormalAsPoint = new OG.Point(circleNormalUnit.x, circleNormalUnit.y, circleNormalUnit.z); + var circleConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, circle.units); + + var flattenTransformCircle = new OO.Transform( + new Vector(1, 0, 0), + new Vector(0, 1, 0), + new Vector(0, 0, 0), + new Vector(0, 0, z * circleConversionFactor, units: circle.plane.units) + ); + + _ = circle.plane.TransformTo(flattenTransformCircle, out OG.Plane newCirclePlane); + + if (circleNormalAsPoint.DistanceTo(new OG.Point(0, 0, 1)) < TOLERANCE) + { + return new OG.Circle(newCirclePlane, radius, units: circle.units); + } + + newCirclePlane.xdir.Normalize(); + newCirclePlane.ydir.Normalize(); + newCirclePlane.normal = Vector.CrossProduct(newCirclePlane.xdir, newCirclePlane.ydir); + + // this is the formula for an angle between two vectors + // cos T = a . b / (|a| * |b|) + var rad1ScaleCircle = + Vector.DotProduct(circle.plane.xdir, newCirclePlane.xdir) + / (circle.plane.xdir.Length * newCirclePlane.xdir.Length); + + var rad2ScaleCircle = + Vector.DotProduct(circle.plane.ydir, newCirclePlane.ydir) + / (circle.plane.ydir.Length * newCirclePlane.ydir.Length); + + return new OG.Ellipse(newCirclePlane, radius * rad1ScaleCircle, radius * rad2ScaleCircle, units: circle.units); + + case OG.Curve nurbs: + var curvePoints = new List(); + var nurbsConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, nurbs.units); + for (var i = 0; i < nurbs.points.Count; i++) + { + if (i % 3 == 2) + { + curvePoints.Add(z * nurbsConversionFactor); + } + else + { + curvePoints.Add(nurbs.points[i]); + } + } + var newCurve = new OG.Curve + { + points = curvePoints, + weights = nurbs.weights, + knots = nurbs.knots, + degree = nurbs.degree, + rational = nurbs.rational, + closed = nurbs.closed, + //newCurve.domain + //newCurve.length + units = nurbs.units + }; + return newCurve; + + case OG.Ellipse ellipse: + if (!(ellipse.firstRadius is double firstRadius && firstRadius > 0)) + { + throw new Exception($"Ellipse with id, {ellipse.id}, does not have a valid first radius"); + } + if (!(ellipse.secondRadius is double secondRadius && secondRadius > 0)) + { + throw new Exception($"Ellipse with id, {ellipse.id}, does not have a valid second radius"); + } + var ellipseConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, ellipse.units); + var flattenTransform = new OO.Transform( + new Vector(1, 0, 0), + new Vector(0, 1, 0), + new Vector(0, 0, 0), + new Vector(0, 0, z * ellipseConversionFactor, units: ellipse.plane.units) + ); + + _ = ellipse.plane.TransformTo(flattenTransform, out OG.Plane newEllipsePlane); + + newEllipsePlane.xdir.Normalize(); + newEllipsePlane.ydir.Normalize(); + newEllipsePlane.normal = Vector.CrossProduct(newEllipsePlane.xdir, newEllipsePlane.ydir); + + // this is the formula for an angle between two vectors + // cos T = a . b / (|a| * |b|) + var rad1Scale = + Vector.DotProduct(ellipse.plane.xdir, newEllipsePlane.xdir) + / (ellipse.plane.xdir.Length * newEllipsePlane.xdir.Length); + + var rad2Scale = + Vector.DotProduct(ellipse.plane.ydir, newEllipsePlane.ydir) + / (ellipse.plane.ydir.Length * newEllipsePlane.ydir.Length); + + return new OG.Ellipse( + newEllipsePlane, + firstRadius * rad1Scale, + secondRadius * rad2Scale, + ellipse.domain, + ellipse.trimDomain, + units: ellipse.units + ); + + case OG.Line line: + return new OG.Line( + new OG.Point( + line.start.x, + line.start.y, + z * Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, line.start.units), + line.start.units + ), + new OG.Point( + line.end.x, + line.end.y, + z * Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, line.end.units), + line.end.units + ), + line.units + ); + + case OG.Polyline poly: + var polylinePonts = new List(); + var originalPolylinePoints = poly.GetPoints(); + var polyConversionFactor = Speckle.Core.Kits.Units.GetConversionFactor(ModelUnits, poly.units); + for (var i = 0; i < originalPolylinePoints.Count; i++) + { + polylinePonts.Add(originalPolylinePoints[i].x); + polylinePonts.Add(originalPolylinePoints[i].y); + polylinePonts.Add(z * polyConversionFactor); + } + var newPolyline = new Polyline(polylinePonts, poly.units); + newPolyline.closed = poly.closed; + return newPolyline; + + case OG.Polycurve plc: + var newPolycurve = new Polycurve(plc.units); + foreach (var seg in plc.segments) + { + newPolycurve.segments.Add(GetFlattenedCurve(seg, z)); + } + + return newPolycurve; + + //case OG.Spiral spiral: + } + throw new NotSupportedException($"Trying to flatten unsupported curve type, {curve.GetType()}"); + } + + public List GetSketchProfiles(Sketch sketch) + { + var profiles = new List(); + foreach (CurveArray curves in sketch.Profile) + { + var curveLoop = CurveArrayToCurveLoop(curves); + profiles.Add(new OG.Polycurve { segments = curveLoop.Select(x => CurveToSpeckle(x, sketch.Document)).ToList() }); + } + + return profiles; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFreeformElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFreeformElement.cs new file mode 100644 index 0000000000..34c4db6a21 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertFreeformElement.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Autodesk.Revit.DB; +using ConverterRevitShared.Revit; +using Objects.Geometry; +using Objects.Other; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Mesh = Objects.Geometry.Mesh; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject FreeformElementToNative(Objects.BuiltElements.Revit.FreeformElement freeformElement) + { + var appObj = new ApplicationObject(freeformElement.id, freeformElement.speckle_type) + { + applicationId = freeformElement.applicationId + }; + + // 1. Convert the freeformElement geometry to native + var solids = new List(); + foreach (var geom in freeformElement.baseGeometries) + { + switch (geom) + { + case Brep brep: + try + { + var solid = BrepToNative(geom as Brep, out List brepNotes); + if (brepNotes.Count > 0) + { + appObj.Update(log: brepNotes); + } + + solids.Add(solid); + } + catch (Exception e) + { + appObj.Update( + logItem: $"Could not convert brep to native, falling back to mesh representation: {e.Message}" + ); + var brepMeshSolids = GetSolidMeshes(brep.displayValue); + solids.AddRange(brepMeshSolids); + } + break; + case Objects.Geometry.Mesh mesh: + var meshSolids = MeshToNative( + mesh, + DB.TessellatedShapeBuilderTarget.Solid, + DB.TessellatedShapeBuilderFallback.Abort, + mesh["renderMaterial"] as RenderMaterial + ) + .Select(m => m as DB.Solid); + solids.AddRange(meshSolids); + break; + } + } + + var tempPath = CreateFreeformElementFamily(solids, freeformElement.id, out List notes, freeformElement); + appObj.Update(log: notes); + if (tempPath == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + Doc.LoadFamily(tempPath, new FamilyLoadOption(), out var fam); + var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; + symbol.Activate(); + try + { + File.Delete(tempPath); + } + catch { } + + FamilyInstance freeform; + if (Doc.IsFamilyDocument) + { + freeform = Doc.FamilyCreate.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + } + else + { + freeform = Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + } + + appObj.Update(status: ApplicationObject.State.Created, createdId: freeform.UniqueId, convertedItem: freeform); + SetInstanceParameters(freeform, freeformElement); + return appObj; + } + + public ApplicationObject FreeformElementToNativeFamily(Brep brep, Category cat = null) + { + var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; + var solids = new List(); + try + { + var solid = BrepToNative(brep, out List brepNotes); + if (brepNotes.Count > 0) + { + appObj.Update(log: brepNotes); + } + + solids.Add(solid); + } + catch (Exception e) + { + var meshes = GetSolidMeshes(brep.displayValue); + solids.AddRange(meshes); + } + + foreach (var s in solids) + { + var form = DB.FreeFormElement.Create(Doc, s); + if (cat != null) + { + form.Subcategory = cat; + } + + appObj.Update(createdId: form.UniqueId, convertedItem: form); + } + + return appObj; + } + + public ApplicationObject FreeformElementToNativeFamily(Geometry.Mesh mesh) + { + var appObj = new ApplicationObject(mesh.id, mesh.speckle_type) { applicationId = mesh.applicationId }; + var solids = new List(); + var d = MeshToNative(mesh, DB.TessellatedShapeBuilderTarget.Solid); + var revitMesh = d.Select(m => m as DB.Solid); + solids.AddRange(revitMesh); + + foreach (var s in solids) + { + var form = DB.FreeFormElement.Create(Doc, s); + appObj.Update(createdId: form.UniqueId, convertedItem: s); + } + + return appObj; + } + + private IEnumerable GetSolidMeshes(IEnumerable meshes) + { + var allMeshes = meshes.SelectMany( + m => + MeshToNative(m, DB.TessellatedShapeBuilderTarget.Solid, DB.TessellatedShapeBuilderFallback.Abort) + ?? new List() + ); + var notNull = allMeshes.Where(m => m != null); + var solids = notNull.Select(m => m as DB.Solid); + return solids; + } + + private ApplicationObject FreeformElementToNative(Brep brep) + { + var appObj = new ApplicationObject(brep.id, brep.speckle_type) { applicationId = brep.applicationId }; + var solids = new List(); + try + { + var solid = BrepToNative(brep, out List brepNotes); + if (brepNotes.Count > 0) + { + appObj.Update(log: brepNotes); + } + + solids.Add(solid); + } + catch (Exception e) + { + solids.AddRange(GetSolidMeshes(brep.displayValue)); + } + + var tempPath = CreateFreeformElementFamily(solids, brep.id, out List freeformNotes); + if (freeformNotes.Count > 0) + { + appObj.Update(log: freeformNotes); + } + + if (tempPath == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + Doc.LoadFamily(tempPath, new FamilyLoadOption(), out var fam); + var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as DB.FamilySymbol; + symbol.Activate(); + + var freeform = Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + + SetInstanceParameters(freeform, brep); + + appObj.Update(status: ApplicationObject.State.Created, createdId: freeform.UniqueId, convertedItem: freeform); + return appObj; + } + + private string CreateFreeformElementFamily( + List solids, + string name, + out List notes, + Objects.BuiltElements.Revit.FreeformElement freeformElement = null + ) + { + notes = new List(); + // FreeformElements can only be created in a family context. + // so we create a temporary family to hold it. + + var templatePath = GetTemplatePath("Generic Model"); + if (!File.Exists(templatePath)) + { + notes.Add($"Could not find Generic Model rft file - {templatePath}"); + return null; + } + + var famDoc = Doc.Application.NewFamilyDocument(templatePath); + + using (DB.Transaction t = new(famDoc, "Create Freeform Elements")) + { + t.Start(); + + //by default free form elements are always generic models + Category cat = null; + if (freeformElement is not null && !string.IsNullOrEmpty(freeformElement.subcategory)) + { + BuiltInCategory bic = BuiltInCategory.OST_GenericModel; + cat = famDoc.Settings.Categories.get_Item(bic); + + //subcategory + if (cat.SubCategories.Contains(freeformElement.subcategory)) + { + cat = cat.SubCategories.get_Item(freeformElement.subcategory); + } + else + { + cat = famDoc.Settings.Categories.NewSubcategory(cat, freeformElement.subcategory); + } + } + + foreach (var s in solids) + { + var f = DB.FreeFormElement.Create(famDoc, s); + if (cat is not null) + { + f.Subcategory = cat; + } + } + + t.Commit(); + } + var famName = "SpeckleFreeform_" + name; + string tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); + var so = new DB.SaveAsOptions(); + so.OverwriteExistingFile = true; + famDoc.SaveAs(tempFamilyPath, so); + famDoc.Close(); + notes.Add($"Created temp family {tempFamilyPath}"); + return tempFamilyPath; + } + + private DB.FamilyInstance CreateFreeformElementFamily(List solids, string name, string templateName) + { + var templatePath = GetTemplatePath(templateName); + if (!File.Exists(templatePath)) + { + throw new FileNotFoundException($"Could not find Generic Model rft file - {templatePath}"); + } + + var famDoc = Doc.Application.NewFamilyDocument(templatePath); + + using (var t = new Transaction(famDoc, "Create Freeform Elements")) + { + t.Start(); + foreach (var s in solids) + { + FreeFormElement.Create(famDoc, s); + } + + t.Commit(); + } + + var famName = "SpeckleFreeform_" + name; + var tempFamilyPath = Path.Combine(Path.GetTempPath(), famName + ".rfa"); + var so = new SaveAsOptions { OverwriteExistingFile = true }; + famDoc.SaveAs(tempFamilyPath, so); + famDoc.Close(); + + Doc.LoadFamily(tempFamilyPath, new FamilyLoadOption(), out var fam); + + var symbol = Doc.GetElement(fam.GetFamilySymbolIds().First()) as FamilySymbol; + symbol.Activate(); + return Doc.Create.NewFamilyInstance(DB.XYZ.Zero, symbol, DB.Structure.StructuralType.NonStructural); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGeometry.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGeometry.cs new file mode 100644 index 0000000000..16d8fc6a65 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGeometry.cs @@ -0,0 +1,1437 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.DoubleNumerics; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.PointClouds; +using Objects.Converters.DxfConverter; +using Objects.Geometry; +using Objects.Other; +using Objects.Primitive; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using Arc = Objects.Geometry.Arc; +using Curve = Objects.Geometry.Curve; +using DB = Autodesk.Revit.DB; +using Ellipse = Objects.Geometry.Ellipse; +using Line = Objects.Geometry.Line; +using Mesh = Objects.Geometry.Mesh; +using Plane = Objects.Geometry.Plane; +using Point = Objects.Geometry.Point; +using Pointcloud = Objects.Geometry.Pointcloud; +using Spiral = Objects.Geometry.Spiral; +using Surface = Objects.Geometry.Surface; +using Transform = Objects.Other.Transform; +using Units = Speckle.Core.Kits.Units; +using Vector = Objects.Geometry.Vector; + +namespace Objects.Converter.Revit; + +/// +///Internal helper methods used for converison +/// +public partial class ConverterRevit +{ + // Convenience methods point: + public double[] PointToArray(Point pt) + { + return new double[] { pt.x, pt.y, pt.z }; + } + + public List PointsToFlatList(IEnumerable points) + { + return points.SelectMany(PointToArray).ToList(); + } + + public object GeometryToNative(Base geom) + { + switch (geom) + { + case Point g: + return PointToNative(g); + case ICurve g: + return CurveToNative(g); + case Plane g: + return PlaneToNative(g); + case Vector g: + return VectorToNative(g); + + default: + throw new Speckle.Core.Logging.SpeckleException("Cannot convert Curve of type " + geom.GetType()); + } + } + + public XYZ PointToNative(Point pt) + { + var revitPoint = new XYZ( + ScaleToNative(pt.x, pt.units), + ScaleToNative(pt.y, pt.units), + ScaleToNative(pt.z, pt.units) + ); + var intPt = ToInternalCoordinates(revitPoint, true); + return intPt; + } + + public Point PointToSpeckle(XYZ pt, Document doc, string units = null, bool doNotTransformWithReferencePoint = false) + { + var u = units ?? ModelUnits; + + var extPt = doNotTransformWithReferencePoint ? pt : ToExternalCoordinates(pt, true, doc); + + var pointToSpeckle = new Point( + u == Units.None ? extPt.X : ScaleToSpeckle(extPt.X), + u == Units.None ? extPt.Y : ScaleToSpeckle(extPt.Y), + u == Units.None ? extPt.Z : ScaleToSpeckle(extPt.Z), + u + ); + return pointToSpeckle; + } + + public List PointListToNative(IList arr, string units = null) + { + if (arr.Count % 3 != 0) + { + throw new SpeckleException("Array malformed: length%3 != 0."); + } + + var u = units ?? ModelUnits; + + var points = new List(arr.Count / 3); + for (int i = 2; i < arr.Count; i += 3) + { + points.Add(new XYZ(ScaleToNative(arr[i - 2], u), ScaleToNative(arr[i - 1], u), ScaleToNative(arr[i], u))); + } + + return points; + } + + public Pointcloud PointcloudToSpeckle(PointCloudInstance pointcloud, string units = null) + { + var u = units ?? ModelUnits; + var boundingBox = pointcloud.get_BoundingBox(null); + var transform = pointcloud.GetTransform(); + + var minPlane = DB.Plane.CreateByNormalAndOrigin(XYZ.BasisZ, transform.OfPoint(boundingBox.Min)); + var filter = PointCloudFilterFactory.CreateMultiPlaneFilter(new List() { minPlane }); + var points = pointcloud.GetPoints(filter, 0.0001, 999999); // max limit is 1 mil but 1000000 throws error + + var _pointcloud = new Pointcloud(); + _pointcloud.points = points + .Select(o => PointToSpeckle(transform.OfPoint(o), pointcloud.Document, u)) + .SelectMany(o => new List() { o.x, o.y, o.z }) + .ToList(); + _pointcloud.colors = points.Select(o => o.Color).ToList(); + _pointcloud.units = u; + _pointcloud.bbox = BoxToSpeckle(boundingBox, pointcloud.Document, u); + + return _pointcloud; + } + + public Vector VectorToSpeckle( + XYZ pt, + Document doc, + string units = null, + bool doNotTransformWithReferencePoint = false + ) + { + var u = units ?? ModelUnits; + var extPt = doNotTransformWithReferencePoint ? pt : ToExternalCoordinates(pt, false, doc); + var pointToSpeckle = new Vector( + u == Units.None ? extPt.X : ScaleToSpeckle(extPt.X), + u == Units.None ? extPt.Y : ScaleToSpeckle(extPt.Y), + u == Units.None ? extPt.Z : ScaleToSpeckle(extPt.Z), + u + ); + return pointToSpeckle; + } + + public XYZ VectorToNative(Vector pt) + { + var revitVector = new XYZ( + ScaleToNative(pt.x, pt.units), + ScaleToNative(pt.y, pt.units), + ScaleToNative(pt.z, pt.units) + ); + var intV = ToInternalCoordinates(revitVector, false); + return intV; + } + + public DB.Plane PlaneToNative(Plane plane) + { + return DB.Plane.CreateByOriginAndBasis( + PointToNative(plane.origin), + VectorToNative(plane.xdir).Normalize(), + VectorToNative(plane.ydir).Normalize() + ); + } + + public Plane PlaneToSpeckle(DB.Plane plane, Document doc, string units = null) + { + var u = units ?? ModelUnits; + var origin = PointToSpeckle(plane.Origin, doc, u); + var normal = VectorToSpeckle(plane.Normal, doc, u); + var xdir = VectorToSpeckle(plane.XVec, doc, u); + var ydir = VectorToSpeckle(plane.YVec, doc, u); + + return new Plane(origin, normal, xdir, ydir, u); + } + + public DB.Line LineToNative(Line line) + { + return DB.Line.CreateBound(PointToNative(line.start), PointToNative(line.end)); + } + + public Line LineToSpeckle(DB.Line line, Document doc, string units = null) + { + var u = units ?? ModelUnits; + var l = new Line { units = u }; + l.start = PointToSpeckle(line.GetEndPoint(0), doc, u); + l.end = PointToSpeckle(line.GetEndPoint(1), doc, u); + l.domain = new Interval(line.GetEndParameter(0), line.GetEndParameter(1)); + + l.length = ScaleToSpeckle(line.Length); + return l; + } + + public Circle CircleToSpeckle(DB.Arc arc, Document doc, string units = null) + { + // see https://forums.autodesk.com/t5/revit-api-forum/how-to-retrieve-startangle-and-endangle-of-arc-object/td-p/7637128 + var u = units ?? ModelUnits; + var arcPlane = DB.Plane.CreateByNormalAndOrigin(arc.Normal, arc.Center); + + var c = new Circle(PlaneToSpeckle(arcPlane, doc, u), u == Units.None ? arc.Radius : ScaleToSpeckle(arc.Radius), u); + c.length = ScaleToSpeckle(arc.Length); + return c; + } + + public DB.Arc CircleToNative(Circle circle) + { + var plane = PlaneToNative(circle.plane); + return DB.Arc.Create(plane, ScaleToNative((double)circle.radius, circle.units), 0, 2 * Math.PI); + } + + public DB.Arc ArcToNative(Arc arc) + { + double startAngle, + endAngle; + if (arc.startAngle > arc.endAngle) + { + startAngle = (double)arc.endAngle; + endAngle = (double)arc.startAngle; + } + else + { + startAngle = (double)arc.startAngle; + endAngle = (double)arc.endAngle; + } + var plane = PlaneToNative(arc.plane); + + if (Point.Distance(arc.startPoint, arc.endPoint) < 1E-6) + { + // Endpoints coincide, it's a circle. + return DB.Arc.Create(plane, ScaleToNative(arc.radius ?? 0, arc.units), startAngle, endAngle); + } + + return DB.Arc.Create(PointToNative(arc.startPoint), PointToNative(arc.endPoint), PointToNative(arc.midPoint)); + //return Arc.Create( plane.Origin, (double) arc.Radius * Scale, startAngle, endAngle, plane.XVec, plane.YVec ); + } + + public Arc ArcToSpeckle(DB.Arc arc, Document doc, string units = null) + { + var u = units ?? ModelUnits; + // see https://forums.autodesk.com/t5/revit-api-forum/how-to-retrieve-startangle-and-endangle-of-arc-object/td-p/7637128 + var arcPlane = DB.Plane.CreateByOriginAndBasis(arc.Center, arc.XDirection, arc.YDirection); + XYZ center = arc.Center; + + XYZ dir0 = (arc.GetEndPoint(0) - center).Normalize(); + XYZ dir1 = (arc.GetEndPoint(1) - center).Normalize(); + + XYZ start = arc.Evaluate(0, true); + XYZ end = arc.Evaluate(1, true); + XYZ mid = arc.Evaluate(0.5, true); + + double startAngle = arc.XDirection.AngleOnPlaneTo(dir0, arc.Normal); + double endAngle = arc.XDirection.AngleOnPlaneTo(dir1, arc.Normal); + + var a = new Arc( + PlaneToSpeckle(arcPlane, doc, u), + u == Units.None ? arc.Radius : ScaleToSpeckle(arc.Radius), + startAngle, + endAngle, + endAngle - startAngle, + u + ); + a.endPoint = PointToSpeckle(end, doc, u); + a.startPoint = PointToSpeckle(start, doc, u); + a.midPoint = PointToSpeckle(mid, doc, u); + a.length = ScaleToSpeckle(arc.Length); + a.domain = new Interval(arc.GetEndParameter(0), arc.GetEndParameter(1)); + + return a; + } + + public DB.Curve EllipseToNative(Ellipse ellipse) + { + //TODO: support ellipse arcs + using (DB.Plane basePlane = PlaneToNative(ellipse.plane)) + { + var e = DB.Ellipse.CreateCurve( + PointToNative(ellipse.plane.origin), + ScaleToNative((double)ellipse.firstRadius, ellipse.units), + ScaleToNative((double)ellipse.secondRadius, ellipse.units), + basePlane.XVec.Normalize(), + basePlane.YVec.Normalize(), + 0, + 2 * Math.PI + ); + e.MakeBound(ellipse.trimDomain?.start ?? 0, ellipse.trimDomain?.end ?? 2 * Math.PI); + return e; + } + } + + public Ellipse EllipseToSpeckle(DB.Ellipse ellipse, Document doc, string units = null) + { + var u = units ?? ModelUnits; + using (DB.Plane basePlane = DB.Plane.CreateByOriginAndBasis(ellipse.Center, ellipse.XDirection, ellipse.YDirection)) + { + var trim = ellipse.IsBound ? new Interval(ellipse.GetEndParameter(0), ellipse.GetEndParameter(1)) : null; + + var ellipseToSpeckle = new Ellipse( + PlaneToSpeckle(basePlane, doc, u), + u == Units.None ? ellipse.RadiusX : ScaleToSpeckle(ellipse.RadiusX), + u == Units.None ? ellipse.RadiusY : ScaleToSpeckle(ellipse.RadiusY), + new Interval(0, 2 * Math.PI), + trim, + u + ); + ellipseToSpeckle.length = ScaleToSpeckle(ellipse.Length); + ellipseToSpeckle.domain = new Interval(0, 1); + return ellipseToSpeckle; + } + } + + public Curve NurbsToSpeckle(DB.NurbSpline revitCurve, Document doc, string units = null) + { + var points = new List(); + foreach (var p in revitCurve.CtrlPoints) + { + var point = PointToSpeckle(p, doc, units); + points.AddRange(new List { point.x, point.y, point.z }); + } + + Curve speckleCurve = new(); + speckleCurve.weights = revitCurve.Weights.Cast().ToList(); + speckleCurve.points = points; + speckleCurve.knots = revitCurve.Knots.Cast().ToList(); + ; + speckleCurve.degree = revitCurve.Degree; + //speckleCurve.periodic = revitCurve.Period; + speckleCurve.rational = revitCurve.isRational; + speckleCurve.closed = RevitVersionHelper.IsCurveClosed(revitCurve); + speckleCurve.units = units ?? ModelUnits; + speckleCurve.domain = new Interval(revitCurve.GetEndParameter(0), revitCurve.GetEndParameter(1)); + speckleCurve.length = ScaleToSpeckle(revitCurve.Length); + + var coords = revitCurve.Tessellate().SelectMany(xyz => PointToSpeckle(xyz, doc, units).ToList()).ToList(); + speckleCurve.displayValue = new Polyline(coords, units); + + return speckleCurve; + } + + public DB.Curve CurveToNative(Curve speckleCurve) + { + var pts = new List(); + for (int i = 0; i < speckleCurve.points.Count; i += 3) + { + //use PointToNative for conversion as that takes into account the Project Base Point + var point = new Point( + speckleCurve.points[i], + speckleCurve.points[i + 1], + speckleCurve.points[i + 2], + speckleCurve.units + ); + pts.Add(PointToNative(point)); + } + try + { + if ( + speckleCurve.knots != null + && speckleCurve.weights != null + && speckleCurve.knots.Any() + && speckleCurve.weights.Any() + ) + { + var weights = speckleCurve.weights.GetRange(0, pts.Count); + var speckleKnots = new List(speckleCurve.knots); + if (speckleKnots.Count != pts.Count + speckleCurve.degree + 1) + { + // Curve has rhino knots, repeat first and last. + speckleKnots.Insert(0, speckleKnots[0]); + speckleKnots.Add(speckleKnots[speckleKnots.Count - 1]); + } + + //var knots = speckleKnots.GetRange(0, pts.Count + speckleCurve.degree + 1); + var curve = NurbSpline.CreateCurve(speckleCurve.degree, speckleKnots, pts, weights); + return curve; + } + else + { + var weights = speckleCurve.weights.GetRange(0, pts.Count); + var curve = NurbSpline.CreateCurve(pts, weights); + return curve; + } + } + catch (Exception e) + { + if (e is Autodesk.Revit.Exceptions.ArgumentException) + { + throw; // prob a closed, periodic curve + } + + return null; + } + } + + public CurveArray CurveToNative(List crvs) + { + CurveArray crvsArray = new(); + foreach (var crv in crvs) + { + var crvEnumerator = CurveToNative(crv).GetEnumerator(); + while (crvEnumerator.MoveNext() && crvEnumerator.Current != null) + { + crvsArray.Append(crvEnumerator.Current as DB.Curve); + } + } + return crvsArray; + } + + /// + /// Recursively creates an ordered list of curves from a polycurve/polyline. + /// Please note that a polyline is broken down into lines. + /// + /// A speckle curve. + /// + public CurveArray CurveToNative(ICurve crv, bool splitIfClosed = false) + { + CurveArray curveArray = new(); + switch (crv) + { + case Line line: + curveArray.Append(LineToNative(line)); + return curveArray; + + case Arc arc: + curveArray.Append(ArcToNative(arc)); + return curveArray; + + case Circle circle: + curveArray.Append(CircleToNative(circle)); + return curveArray; + + case Ellipse ellipse: + curveArray.Append(EllipseToNative(ellipse)); + return curveArray; + + case Spiral spiral: + return PolylineToNative(spiral.displayValue); + + case Curve nurbs: + var n = CurveToNative(nurbs); + if (IsCurveClosed(n) && splitIfClosed) + { + var split = SplitCurveInTwoHalves(n); + curveArray.Append(split.Item1); + curveArray.Append(split.Item2); + } + else + { + curveArray.Append(n); + } + return curveArray; + + case Polyline poly: + return PolylineToNative(poly); + + case Polycurve plc: + foreach (var seg in plc.segments) + { + // Enumerate all curves in the array to ensure polylines get fully converted. + var crvEnumerator = CurveToNative(seg).GetEnumerator(); + while (crvEnumerator.MoveNext() && crvEnumerator.Current != null) + { + curveArray.Append(crvEnumerator.Current as DB.Curve); + } + } + return curveArray; + default: + throw new Speckle.Core.Logging.SpeckleException("The provided geometry is not a valid curve"); + } + } + + //thanks Revit + public CurveLoop CurveArrayToCurveLoop(CurveArray array) + { + var loop = new CurveLoop(); + UnboundCurveIfSingle(array); + foreach (var item in array.Cast()) + { + loop.Append(item); + } + + return loop; + } + + public ICurve CurveToSpeckle(DB.Curve curve, Document doc, string units = null) + { + var u = units ?? ModelUnits; + switch (curve) + { + case DB.Line line: + return LineToSpeckle(line, doc, u); + case DB.Arc arc: + if (!arc.IsBound) + { + return (CircleToSpeckle(arc, doc, u)); + } + return ArcToSpeckle(arc, doc, u); + case DB.Ellipse ellipse: + return EllipseToSpeckle(ellipse, doc, u); + case DB.NurbSpline nurbs: + return NurbsToSpeckle(nurbs, doc, u); + case DB.HermiteSpline spline: + return HermiteSplineToSpeckle(spline, doc, u); + default: + throw new Speckle.Core.Logging.SpeckleException("Cannot convert Curve of type " + curve.GetType()); + } + } + + public Polycurve CurveListToSpeckle(IList loop, Document doc, string units = null) + { + var polycurve = new Polycurve(); + polycurve.units = units ?? ModelUnits; + polycurve.closed = loop.First().GetEndPoint(0).DistanceTo(loop.Last().GetEndPoint(1)) < TOLERANCE; + polycurve.length = ScaleToSpeckle(loop.Sum(x => x.Length)); + polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x, doc))); + return polycurve; + } + + public Polycurve CurveLoopToSpeckle(CurveLoop loop, Document doc, string units = null) + { + var polycurve = new Polycurve(); + polycurve.units = units ?? ModelUnits; + polycurve.closed = !loop.IsOpen(); + polycurve.length = units == Units.None ? loop.GetExactLength() : ScaleToSpeckle(loop.GetExactLength()); + + polycurve.segments.AddRange(loop.Select(x => CurveToSpeckle(x, doc))); + return polycurve; + } + + private ICurve HermiteSplineToSpeckle(HermiteSpline spline, Document doc, string units = null) + { + var nurbs = DB.NurbSpline.Create(spline); + return NurbsToSpeckle(nurbs, doc, units ?? ModelUnits); + } + + /// + /// Converts a Speckle into a . + /// + /// + /// This method will ensure that no lines smaller than the allowed length are created. + /// If small segments are encountered, the geometry will be modified to ensure all segments have minimum length and remain connected. + /// This will result in some vertices being ignored during conversion, which are logged in the report. + /// + /// The Speckle to convert to Revit + /// A Revit + public CurveArray PolylineToNative(Polyline polyline) + { + var appObj = new ApplicationObject(polyline.id, polyline.speckle_type) { applicationId = polyline.applicationId }; + var curveArray = new CurveArray(); + if (polyline.value.Count == 6) + { + // Polyline is actually a single line + TryAppendLineSafely(curveArray, new Line(polyline.value, polyline.units), appObj); + } + else + { + var pts = polyline.GetPoints(); + var lastPt = pts[0]; + for (var i = 1; i < pts.Count; i++) + { + var success = TryAppendLineSafely(curveArray, new Line(lastPt, pts[i], polyline.units), appObj); + if (success) + { + lastPt = pts[i]; + } + } + + if (polyline.closed) + { + TryAppendLineSafely(curveArray, new Line(pts[pts.Count - 1], pts[0], polyline.units), appObj); + } + } + return curveArray; + } + + public Polyline PolylineToSpeckle(PolyLine polyline, Document doc, string units = null) + { + var coords = polyline.GetCoordinates().SelectMany(coord => PointToSpeckle(coord, doc).ToList()).ToList(); + return new Polyline(coords, units ?? ModelUnits); + } + + public Box BoxToSpeckle(DB.BoundingBoxXYZ box, Document doc, string units = null) + { + // convert min and max pts to speckle first + var min = PointToSpeckle(box.Min, doc, units); + var max = PointToSpeckle(box.Max, doc, units); + + // get the base plane of the bounding box from the transform + var transform = box.Transform; + var plane = DB.Plane.CreateByOriginAndBasis( + transform.Origin, + transform.BasisX.Normalize(), + transform.BasisY.Normalize() + ); + + var _box = new Box() + { + xSize = new Interval(min.x, max.x), + ySize = new Interval(min.y, max.y), + zSize = new Interval(min.z, max.z), + basePlane = PlaneToSpeckle(plane, doc), + units = units ?? ModelUnits + }; + + return _box; + } + + public DB.BoundingBoxXYZ BoxToNative(Box box) + { + var boundingBox = new BoundingBoxXYZ(); + boundingBox.Min = PointToNative( + new Point((double)box.xSize.start, (double)box.ySize.start, (double)box.zSize.start) + ); + boundingBox.Max = PointToNative(new Point((double)box.xSize.end, (double)box.ySize.end, (double)box.zSize.end)); + return boundingBox; + } + + public Mesh MeshToSpeckle(DB.Mesh mesh, Document d, string units = null) + { + var vertices = new List(mesh.Vertices.Count * 3); + foreach (var vert in mesh.Vertices) + { + vertices.AddRange(PointToSpeckle(vert, d).ToList()); + } + + var faces = new List(mesh.NumTriangles * 4); + for (int i = 0; i < mesh.NumTriangles; i++) + { + var triangle = mesh.get_Triangle(i); + var A = triangle.get_Index(0); + var B = triangle.get_Index(1); + var C = triangle.get_Index(2); + faces.Add(3); + faces.AddRange(new int[] { (int)A, (int)B, (int)C }); + } + + var u = units ?? ModelUnits; + var speckleMesh = new Mesh(vertices, faces, units: u) + { + ["renderMaterial"] = RenderMaterialToSpeckle(d.GetElement(mesh.MaterialElementId) as DB.Material) + }; + + return speckleMesh; + } + + // Inspired by + // https://github.com/DynamoDS/DynamoRevit/blob/master/src/Libraries/RevitNodes/GeometryConversion/ProtoToRevitMesh.cs + public IList MeshToNative( + Mesh mesh, + TessellatedShapeBuilderTarget target = TessellatedShapeBuilderTarget.Mesh, + TessellatedShapeBuilderFallback fallback = TessellatedShapeBuilderFallback.Salvage, + RenderMaterial parentMaterial = null + ) + { + var tsb = new TessellatedShapeBuilder() + { + Fallback = fallback, + Target = target, + GraphicsStyleId = ElementId.InvalidElementId + }; + + var valid = tsb.AreTargetAndFallbackCompatible(target, fallback); + tsb.OpenConnectedFaceSet(target == TessellatedShapeBuilderTarget.Solid); + + var vertices = ArrayToPoints(mesh.vertices, mesh.units); + + ElementId materialId = RenderMaterialToNative(parentMaterial ?? (mesh["renderMaterial"] as RenderMaterial)); + + int i = 0; + while (i < mesh.faces.Count) + { + int n = mesh.faces[i]; + if (n < 3) + { + n += 3; // 0 -> 3, 1 -> 4 to preserve backwards compatibility + } + + var points = mesh.faces.GetRange(i + 1, n).Select(x => vertices[x]).ToArray(); + + if (IsNonPlanarQuad(points)) + { + //Non-planar quads will be triangulated as it's more desirable than `TessellatedShapeBuilder.Build`'s attempt to make them planar. + //TODO consider triangulating all n > 3 polygons that are non-planar + var triPoints = new List { points[0], points[1], points[3] }; + var face1 = new TessellatedFace(triPoints, materialId); + tsb.AddFace(face1); + + triPoints = new List { points[1], points[2], points[3] }; + ; + var face2 = new TessellatedFace(triPoints, materialId); + tsb.AddFace(face2); + } + else + { + var face = new TessellatedFace(points, materialId); + tsb.AddFace(face); + } + + i += n + 1; + } + + tsb.CloseConnectedFaceSet(); + try + { + tsb.Build(); + } + catch (Exception e) + { + Report.LogConversionError(e); + return null; + } + var result = tsb.GetBuildResult(); + return result.GetGeometricalObjects(); + + static bool IsNonPlanarQuad(IList points) + { + if (points.Count != 4) + { + return false; + } + + var matrix = new Matrix4x4( + points[0].X, + points[1].X, + points[2].X, + points[3].X, + points[0].Y, + points[1].Y, + points[2].Y, + points[3].Y, + points[0].Z, + points[1].Z, + points[2].Z, + points[3].Z, + 1, + 1, + 1, + 1 + ); + return matrix.GetDeterminant() != 0; + } + } + + public XYZ[] ArrayToPoints(IList arr, string units = null) + { + if (arr.Count % 3 != 0) + { + throw new Speckle.Core.Logging.SpeckleException("Array malformed: length%3 != 0."); + } + + XYZ[] points = new XYZ[arr.Count / 3]; + + for (int i = 2, k = 0; i < arr.Count; i += 3) + { + var point = new Point(arr[i - 2], arr[i - 1], arr[i], units); + points[k++] = PointToNative(point); + } + + return points; + } + + //https://github.com/DynamoDS/DynamoRevit/blob/f8206726d8a3aa5bf06f5dbf7ce8a732bb025c34/src/Libraries/RevitNodes/GeometryConversion/GeometryPrimitiveConverter.cs#L201 + public XYZ GetPerpendicular(XYZ xyz) + { + var ixn = xyz.Normalize(); + var xn = new XYZ(1, 0, 0); + + if (ixn.IsAlmostEqualTo(xn)) + { + xn = new XYZ(0, 1, 0); + } + else if (ixn.Negate().IsAlmostEqualTo(xn)) + { + xn = new XYZ(0, -1, 0); + } + + var cross = ixn.CrossProduct(xn); + + return cross.Normalize(); + } + + public Geometry.Surface FaceToSpeckle(DB.Face face, DB.BoundingBoxUV uvBox, Document doc, string units = null) + { +#if REVIT2020 + var surf = DB.ExportUtils.GetNurbsSurfaceDataForFace(face); +#else + var surf = DB.ExportUtils.GetNurbsSurfaceDataForSurface(face.GetSurface()); +#endif + var spcklSurface = NurbsSurfaceToSpeckle(surf, face.GetBoundingBox(), doc, units ?? ModelUnits); + return spcklSurface; + } + + public Surface NurbsSurfaceToSpeckle( + DB.NurbsSurfaceData surface, + DB.BoundingBoxUV uvBox, + Document doc, + string units = null + ) + { + var result = new Surface(); + + var unit = units ?? ModelUnits; + result.units = unit; + + result.degreeU = surface.DegreeU; + result.degreeV = surface.DegreeV; + + result.domainU = new Interval(0, 1); + result.domainV = new Interval(0, 1); + + var knotsU = surface.GetKnotsU().ToList(); + var knotsV = surface.GetKnotsV().ToList(); + + result.knotsU = knotsU.GetRange(1, knotsU.Count - 2); + result.knotsV = knotsV.GetRange(1, knotsV.Count - 2); + + var controlPointCountU = knotsU.Count - result.degreeU - 1; + var controlPointCountV = knotsV.Count - result.degreeV - 1; + + var controlPoints = surface.GetControlPoints(); + var weights = surface.GetWeights(); + + var points = new List>(); + for (var u = 0; u < controlPointCountU; u++) + { + var uOffset = u * controlPointCountV; + var row = new List(); + + for (var v = 0; v < controlPointCountV; v++) + { + var pt = controlPoints[uOffset + v]; + var extPt = ToExternalCoordinates(pt, true, doc); + if (surface.IsRational) + { + var w = weights[uOffset + v]; + var point = PointToSpeckle(extPt, doc, unit); + row.Add(new ControlPoint(point.x, point.y, point.z, w, unit)); + } + else + { + var point = PointToSpeckle(extPt, doc, unit); + row.Add(new ControlPoint(point.x, point.y, point.z, unit)); + } + } + points.Add(row); + } + + result.SetControlPoints(points); + + return result; + } + + public List BrepEdgeToNative(BrepEdge edge) + { + // TODO: Trim curve with domain. Unsure if this is necessary as all our curves are converted to NURBS on Rhino output. + var nativeCurveArray = CurveToNative(edge.Curve); + bool isTrimmed = + edge.Curve.domain != null + && edge.Domain != null + && (edge.Curve.domain.start != edge.Domain.start || edge.Curve.domain.end != edge.Domain.end); + if (nativeCurveArray.Size == 1) + { + var nativeCurve = nativeCurveArray.get_Item(0); + + if (edge.ProxyCurveIsReversed) + { + nativeCurve = nativeCurve.CreateReversed(); + } + + if (nativeCurve == null) + { + return new List(); + } + + if (isTrimmed) + { + nativeCurve.MakeBound(edge.Domain.start ?? 0, edge.Domain.end ?? 1); + } + + if (!nativeCurve.IsBound) + { + nativeCurve.MakeBound(0, nativeCurve.Period); + } + + if (IsCurveClosed(nativeCurve)) + { + var (first, second) = SplitCurveInTwoHalves(nativeCurve); + if (edge.ProxyCurveIsReversed) + { + first = first.CreateReversed(); + second = second.CreateReversed(); + } + var halfEdgeA = BRepBuilderEdgeGeometry.Create(first); + var halfEdgeB = BRepBuilderEdgeGeometry.Create(second); + return edge.ProxyCurveIsReversed + ? new List { halfEdgeA, halfEdgeB } + : new List { halfEdgeB, halfEdgeA }; + } + + // TODO: Remove short segments if smaller than 'Revit.ShortCurveTolerance'. + var fullEdge = BRepBuilderEdgeGeometry.Create(nativeCurve); + return new List { fullEdge }; + } + + var iterator = edge.ProxyCurveIsReversed ? nativeCurveArray.ReverseIterator() : nativeCurveArray.ForwardIterator(); + + var result = new List(); + while (iterator.MoveNext()) + { + var crv = iterator.Current as DB.Curve; + if (edge.ProxyCurveIsReversed) + { + crv = crv.CreateReversed(); + } + + result.Add(BRepBuilderEdgeGeometry.Create(crv)); + } + + return result; + } + + public double[] ControlPointWeightsToNative(List> controlPoints) + { + var uCount = controlPoints.Count; + var vCount = controlPoints[0].Count; + var count = uCount * vCount; + var weights = new double[count]; + int p = 0; + + controlPoints.ForEach(row => row.ForEach(pt => weights[p++] = pt.weight)); + + return weights; + } + + public XYZ[] ControlPointsToNative(List> controlPoints) + { + var uCount = controlPoints.Count; + var vCount = controlPoints[0].Count; + var count = uCount * vCount; + var points = new DB.XYZ[count]; + int p = 0; + + controlPoints.ForEach( + row => + row.ForEach(pt => + { + var point = new Point(pt.x, pt.y, pt.z, pt.units); + points[p++] = PointToNative(point); + }) + ); + + return points; + } + + public double[] SurfaceKnotsToNative(List list) + { + var count = list.Count; + var knots = new double[count + 2]; + + int j = 0, + k = 0; + while (j < count) + { + knots[++k] = list[j++]; + } + + knots[0] = knots[1]; + knots[count + 1] = knots[count]; + + return knots; + } + + public BRepBuilderSurfaceGeometry SurfaceToNative(Surface surface) + { + var uvBox = new DB.BoundingBoxUV( + surface.knotsU[0], + surface.knotsV[0], + surface.knotsU[surface.knotsU.Count - 1], + surface.knotsV[surface.knotsV.Count - 1] + ); + var surfPts = surface.GetControlPoints(); + var uKnots = SurfaceKnotsToNative(surface.knotsU); + var vKnots = SurfaceKnotsToNative(surface.knotsV); + var cPts = ControlPointsToNative(surfPts); + + BRepBuilderSurfaceGeometry result; + if (!surface.rational) + { + result = DB.BRepBuilderSurfaceGeometry.CreateNURBSSurface( + surface.degreeU, + surface.degreeV, + uKnots, + vKnots, + cPts, + false, + uvBox + ); + } + else + { + var weights = ControlPointWeightsToNative(surfPts); + result = DB.BRepBuilderSurfaceGeometry.CreateNURBSSurface( + surface.degreeU, + surface.degreeV, + uKnots, + vKnots, + cPts, + weights, + false, + uvBox + ); + } + + return result; + } + + public Solid BrepToNative(Brep brep, out List notes) + { + //Make sure face references are calculated by revit + notes = new List(); + var bRepType = BRepType.OpenShell; + switch (brep.Orientation) + { + case BrepOrientation.Inward: + bRepType = BRepType.Void; + break; + case BrepOrientation.Outward: + bRepType = BRepType.Solid; + break; + } + + var materialId = RenderMaterialToNative(brep["renderMaterial"] as RenderMaterial); + using var builder = new BRepBuilder(bRepType); + + builder.SetAllowShortEdges(); + builder.AllowRemovalOfProblematicFaces(); + var brepEdges = new List[brep.Edges.Count]; + foreach (var face in brep.Faces) + { + try + { + var faceId = builder.AddFace(SurfaceToNative(face.Surface), face.OrientationReversed); + builder.SetFaceMaterialId(faceId, materialId); + + foreach (var loop in face.Loops) + { + try + { + var loopId = builder.AddLoop(faceId); + if (face.OrientationReversed) + { + loop.TrimIndices.Reverse(); + } + + foreach (var trim in loop.Trims) + { + try + { + if ( + trim.TrimType != BrepTrimType.Boundary + && trim.TrimType != BrepTrimType.Mated + && trim.TrimType != BrepTrimType.Seam + ) + { + continue; + } + + if (trim.Edge == null) + { + continue; + } + + var edgeIds = brepEdges[trim.EdgeIndex]; + if (edgeIds == null) + { + // First time we see this edge, convert it and add + edgeIds = brepEdges[trim.EdgeIndex] = new List(); + var bRepBuilderGeometryIds = BrepEdgeToNative(trim.Edge).Select(edge => builder.AddEdge(edge)); + edgeIds.AddRange(bRepBuilderGeometryIds); + } + + var trimReversed = face.OrientationReversed ? !trim.IsReversed : trim.IsReversed; + if (trimReversed) + { + for (int e = edgeIds.Count - 1; e >= 0; --e) + { + if (builder.IsValidEdgeId(edgeIds[e])) + { + builder.AddCoEdge(loopId, edgeIds[e], true); + } + } + } + else + { + for (int e = 0; e < edgeIds.Count; ++e) + { + if (builder.IsValidEdgeId(edgeIds[e])) + { + builder.AddCoEdge(loopId, edgeIds[e], false); + } + } + } + } + catch (Exception e) + { + notes.Add( + $"Failed to create trim {loop.Trims.IndexOf(trim)} on loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}: {e.Message}" + ); + throw new SpeckleException( + $"Failed to create trim {loop.Trims.IndexOf(trim)} on loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" + ); + } + } + builder.FinishLoop(loopId); + } + catch (Exception e) + { + notes.Add(e.Message); + if (e is SpeckleException) + { + throw; + } + + throw new SpeckleException( + $"Failed to create loop {face.Loops.IndexOf(loop)} on face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" + ); + } + } + builder.FinishFace(faceId); + } + catch (Exception e) + { + builder.Dispose(); + notes.Add(e.Message); + if (e is SpeckleException) + { + throw; + } + + throw new SpeckleException( + $"Failed to create face {brep.Faces.IndexOf(face)} on brep with id {brep.id}\n Reason: {e.Message}" + ); + } + } + + var bRepBuilderOutcome = builder.Finish(); + if (bRepBuilderOutcome == BRepBuilderOutcome.Failure) + { + return null; + } + + var isResultAvailable = builder.IsResultAvailable(); + if (!isResultAvailable) + { + return null; + } + + var result = builder.GetResult(); + builder.Dispose(); + return result; + } + + public Brep BrepToSpeckle(Solid solid, Document d, string units = null) + { +#if REVIT2020 + + throw new Speckle.Core.Logging.SpeckleException("Converting BREPs to Speckle is currently only supported in Revit 2021 and above."); +#else + // TODO: Incomplete implementation!! + var u = units ?? ModelUnits; + var brep = new Brep(); + brep.units = u; + + if (solid is null || solid.Faces.IsEmpty) + { + return null; + } + + var faceIndex = 0; + var edgeIndex = 0; + var curve2dIndex = 0; + var curve3dIndex = 0; + var loopIndex = 0; + var trimIndex = 0; + var surfaceIndex = 0; + + var speckleFaces = new Dictionary(); + var speckleEdges = new Dictionary(); + var speckleEdgeIndexes = new Dictionary(); + var speckle3dCurves = new ICurve[solid.Edges.Size]; + var speckle2dCurves = new List(); + var speckleLoops = new List(); + var speckleTrims = new List(); + + foreach (var face in solid.Faces.Cast()) + { + var surface = FaceToSpeckle(face, d, out bool orientation, 0.0); + var iterator = face.EdgeLoops.ForwardIterator(); + var loopIndices = new List(); + + while (iterator.MoveNext()) + { + var loop = iterator.Current as EdgeArray; + var loopTrimIndices = new List(); + // Loop through the edges in the loop. + var loopIterator = loop.ForwardIterator(); + while (loopIterator.MoveNext()) + { + // Each edge should create a 2d curve, a 3d curve, a BrepTrim and a BrepEdge. + var edge = loopIterator.Current as Edge; + var faceA = edge.GetFace(0); + + // Determine what face side are we currently on. + var edgeSide = face == faceA ? 0 : 1; + + // Get curve, create trim and save index + var trim = edge.GetCurveUV(edgeSide); + var sTrim = new BrepTrim( + brep, + edgeIndex, + faceIndex, + loopIndex, + curve2dIndex, + 0, + BrepTrimType.Boundary, + edge.IsFlippedOnFace(edgeSide), + -1, + -1 + ); + var sTrimIndex = trimIndex; + loopTrimIndices.Add(sTrimIndex); + + // Add curve and trim, increase index counters. + speckle2dCurves.Add(CurveToSpeckle(trim.As3DCurveInXYPlane(), d, Units.None)); + speckleTrims.Add(sTrim); + curve2dIndex++; + trimIndex++; + + // Check if we have visited this edge before. + if (!speckleEdges.ContainsKey(edge)) + { + // First time we visit this edge, add 3d curve and create new BrepEdge. + var edgeCurve = edge.AsCurve(); + speckle3dCurves[curve3dIndex] = CurveToSpeckle(edgeCurve, d, u); + var sCurveIndex = curve3dIndex; + curve3dIndex++; + + // Create a trim with just one of the trimIndices set, the second one will be set on the opposite condition. + var sEdge = new BrepEdge(brep, sCurveIndex, new[] { sTrimIndex }, -1, -1, edge.IsFlippedOnFace(face), null); + speckleEdges.Add(edge, sEdge); + speckleEdgeIndexes.Add(edge, edgeIndex); + edgeIndex++; + } + else + { + // Already visited this edge, skip curve 3d + var sEdge = speckleEdges[edge]; + var sEdgeIndex = speckleEdgeIndexes[edge]; + sTrim.EdgeIndex = sEdgeIndex; + + // Update trim indices with new item. + // TODO: Make this better. + var trimIndices = sEdge.TrimIndices.ToList(); + trimIndices.Append(sTrimIndex); //TODO Append is a pure function and the return is unused + sEdge.TrimIndices = trimIndices.ToArray(); + } + } + + var speckleLoop = new BrepLoop(brep, faceIndex, loopTrimIndices, BrepLoopType.Outer); + speckleLoops.Add(speckleLoop); + var sLoopIndex = loopIndex; + loopIndex++; + loopIndices.Add(sLoopIndex); + } + + speckleFaces.Add( + face, + new BrepFace(brep, surfaceIndex, loopIndices, loopIndices[0], !face.OrientationMatchesSurfaceOrientation) + ); + faceIndex++; + brep.Surfaces.Add(surface); + surfaceIndex++; + } + + // TODO: Revit has no brep vertices. Must call 'brep.SetVertices()' in rhino when provenance is revit. + // TODO: Set tolerances and flags in rhino when provenance is revit. + brep.Faces = speckleFaces.Values.ToList(); + brep.Curve2D = speckle2dCurves; + brep.Curve3D = speckle3dCurves.ToList(); + brep.Trims = speckleTrims; + brep.Edges = speckleEdges.Values.ToList(); + brep.Loops = speckleLoops; + brep.displayValue = ConvertSolidsByRenderMaterial(new[] { solid }, d); + return brep; + +#endif + } + + public Surface FaceToSpeckle( + DB.Face face, + Document doc, + out bool parametricOrientation, + double relativeTolerance = 0.0, + string units = null + ) + { + var u = units ?? ModelUnits; + using (var surface = face.GetSurface()) + { + parametricOrientation = surface.OrientationMatchesParametricOrientation; + } + + switch (face) + { + case null: + return null; + case PlanarFace planar: + return FaceToSpeckle(planar, relativeTolerance, u); + case ConicalFace conical: + return FaceToSpeckle(conical, relativeTolerance, u); + case CylindricalFace cylindrical: + return FaceToSpeckle(cylindrical, relativeTolerance, u); + case RevolvedFace revolved: + return FaceToSpeckle(revolved, relativeTolerance, u); + case RuledFace ruled: + return FaceToSpeckle(ruled, relativeTolerance, u); + case HermiteFace hermite: + return FaceToSpeckle(hermite, face.GetBoundingBox(), doc, u); + default: + throw new NotImplementedException(); + } + } + + public Surface FaceToSpeckle(PlanarFace planarFace, double tolerance, string units = null) + { + throw new NotImplementedException(); + } + + public Surface FaceToSpeckle(ConicalFace conicalFace, double tolerance, string units = null) + { + throw new NotImplementedException(); + } + + public Surface FaceToSpeckle(CylindricalFace cylindricalFace, double tolerance, string units = null) + { + throw new NotImplementedException(); + } + + public Surface FaceToSpeckle(RevolvedFace revolvedFace, double tolerance, string units = null) + { + throw new NotImplementedException(); + } + + public Surface FaceToSpeckle(RuledFace ruledFace, double tolerance, string units = null) + { + throw new NotImplementedException(); + } + + public int AddSurface( + Brep brep, + DB.Face face, + out List[] shells, + Dictionary brepEdges = null + ) + { + throw new NotImplementedException(); + } + + public void TrimSurface(Brep brep, int surface, bool orientationReversed, List[] shells) + { + // TODO: Incomplete method. + foreach (var shell in shells) + { + //var sFace = new BrepFace(brep,surface,null,null,orientationReversed); + + foreach (var loop in shell) + { + var brepLoop = 0; + var edgeCount = loop.edges.Count; + + for (int e = 0; e < edgeCount; ++e) + { + var brepEdge = loop.edges[e]; + var orientation = loop.orientation[e]; + if (orientation == 0) + { + continue; + } + + if (loop.trims.segments[e] is Curve trim) + { + brep.Curve2D.Add(trim); + // TODO: Missing stuff here! + } + } + } + } + throw new NotImplementedException(); + } + + public struct BrepBoundary + { + public BrepLoopType type; + public List edges; + public Polycurve trims; + public List orientation; + } + + public DirectShape BrepToDirectShape( + Brep brep, + out List notes, + BuiltInCategory cat = BuiltInCategory.OST_GenericModel + ) + { + var revitDs = DirectShape.CreateElement(Doc, new ElementId(cat)); + notes = new List(); + try + { + var solid = BrepToNative(brep, out notes); + if (solid == null) + { + notes.Add("Solid conversion returned null"); + throw new Speckle.Core.Logging.SpeckleException("Could not convert Brep to Solid"); + } + revitDs.SetShape(new List { solid }); + } + catch (Exception e) + { + notes.Add($"Failed to convert brep, using display value meshes instead."); + var meshes = brep.displayValue.SelectMany(m => MeshToNative(m)); + revitDs.SetShape(meshes.ToArray()); + } + return revitDs; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGridLine.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGridLine.cs new file mode 100644 index 0000000000..a5d8709ccb --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGridLine.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject GridLineToNative(GridLine speckleGridline) + { + var revitGrid = GetExistingElementByApplicationId(speckleGridline.applicationId) as Grid; + var appObj = new ApplicationObject(speckleGridline.id, speckleGridline.speckle_type) + { + applicationId = speckleGridline.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitGrid, appObj)) + { + return appObj; + } + + var curve = CurveToNative(speckleGridline.baseLine).get_Item(0); + + //try update the gridline + var isUpdate = false; + if (revitGrid != null) + { + if (revitGrid.IsCurved) + { + Doc.Delete(revitGrid.Id); //not sure how to modify arc grids + } + else + { + //dim's magic from 1.0 + var oldStart = revitGrid.Curve.GetEndPoint(0); + var oldEnd = revitGrid.Curve.GetEndPoint(1); + + var newStart = curve.GetEndPoint(0); + var newEnd = curve.GetEndPoint(1); + + //only update if it has changed + if (!(oldStart.DistanceTo(newStart) < TOLERANCE && oldEnd.DistanceTo(newEnd) < TOLERANCE)) + { + var translate = newStart.Subtract(oldStart); + ElementTransformUtils.MoveElement(Doc, revitGrid.Id, translate); + + var currentDirection = revitGrid.Curve.GetEndPoint(0).Subtract(revitGrid.Curve.GetEndPoint(1)).Normalize(); + var newDirection = newStart.Subtract(newEnd).Normalize(); + + var angle = newDirection.AngleTo(currentDirection); + + if (angle > 0.00001) + { + var crossProd = newDirection.CrossProduct(currentDirection).Z; + ElementTransformUtils.RotateElement( + Doc, + revitGrid.Id, + Autodesk.Revit.DB.Line.CreateUnbound(newStart, XYZ.BasisZ), + crossProd < 0 ? angle : -angle + ); + } + + try + { + var datumLine = revitGrid.GetCurvesInView(DatumExtentType.Model, Doc.ActiveView)[0]; + var datumLineZ = datumLine.GetEndPoint(0).Z; + //note the new datum line has endpoints flipped! + revitGrid.SetCurveInView( + DatumExtentType.Model, + Doc.ActiveView, + Line.CreateBound(new XYZ(newEnd.X, newEnd.Y, datumLineZ), new XYZ(newStart.X, newStart.Y, datumLineZ)) + ); + } + catch (Exception e) + { + appObj.Update(logItem: $"Error setting grid endpoints: {e.Message}"); + } + isUpdate = true; + } + } + } + + //create the grid + if (revitGrid == null) + { + if (curve is Arc a) + { + revitGrid = Grid.Create(Doc, a); + } + else if (curve is Line l) + { + revitGrid = Grid.Create(Doc, l); + } + else + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Curve type {curve.GetType().FullName} not supported for Grid" + ); + return appObj; + } + } + + if (!string.IsNullOrEmpty(speckleGridline.label)) + { + var names = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(Grid)) + .ToElements() + .Cast() + .ToList() + .Select(x => x.Name); + if (!names.Contains(speckleGridline.label)) + { + revitGrid.Name = speckleGridline.label; + } + } + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitGrid.UniqueId, convertedItem: revitGrid); + return appObj; + } + + public GridLine GridLineToSpeckle(DB.Grid revitGridLine) + { + var speckleGridline = new GridLine(); + speckleGridline.baseLine = CurveToSpeckle(revitGridLine.Curve, revitGridLine.Document); + speckleGridline.label = revitGridLine.Name; + + //speckleGridline.elementId = revitCurve.Id.ToString(); this would need a RevitGridLine element + speckleGridline.applicationId = revitGridLine.UniqueId; + speckleGridline.units = ModelUnits; + return speckleGridline; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGroup.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGroup.cs new file mode 100644 index 0000000000..563aac28df --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertGroup.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Mesh = Objects.Geometry.Mesh; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public Base GroupToSpeckle(Group revitGroup) + { + var elIdsToConvert = GetHostedElementIds(revitGroup); + if (!elIdsToConvert.Any()) + { + return null; + } + + var @base = new Base(); + @base["name"] = revitGroup.Name; + @base["type"] = "group"; + @base["level"] = ConvertAndCacheLevel(revitGroup, BuiltInParameter.GROUP_LEVEL); + + AddHostedDependentElements(revitGroup, @base, elIdsToConvert.ToList()); + return @base; + } + + private void AddHostedDependentElements(Element revitElement, Base @base, List hostedIds) + { + // loop backward through the list so you can remove elements as you go through it + for (int i = hostedIds.Count - 1; i >= 0; i--) + { + var element = Doc.GetElement(hostedIds[i]); + // if it's already part of the selection, remove this element from the list of element + // we can't prevent the other element (with same id) to be converted, like we do for hosted elements + if (ContextObjects.ContainsKey(element.UniqueId)) + { + hostedIds.RemoveAt(i); + } + // otherwise, add the elements to the ContextObjects before converting them because a group + // may contain a wall that has a window, so we still want the window to search through the contextObjects + // and recognize that it's host, the wall, is listed in there and not to convert itself + else + { + ContextObjects.Add(element.UniqueId, new ApplicationObject(null, null) { applicationId = element.UniqueId }); + } + } + + GetHostedElementsFromIds(@base, revitElement, hostedIds, out List notes); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLevel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLevel.cs new file mode 100644 index 0000000000..7363371ea7 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLevel.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public DB.Level GetExistingLevelByName(IEnumerable docLevels, string name) + { + return docLevels.FirstOrDefault(x => x.Name == name); + } + + public DB.Level GetExistingLevelByElevation(IEnumerable docLevels, double elevation) + { + return docLevels.FirstOrDefault(l => Math.Abs(l.Elevation - (double)elevation) < TOLERANCE); + } + + public DB.Level GetExistingLevelByClosestElevation( + IEnumerable docLevels, + double elevation, + out double elevationOffset + ) + { + elevationOffset = 0.0; + DB.Level level = docLevels.LastOrDefault(l => (l.Elevation < elevation + TOLERANCE)) ?? docLevels.FirstOrDefault(); + + if (level != null) + { + elevationOffset = level.Elevation - elevation; + } + + return level; + } + + public DB.Level ConvertLevelToRevit(XYZ point, out ApplicationObject.State state, out double elevationOffset) + { + var elevation = ElevationFromPoint(point); + return ConvertLevelToRevit(ObjectsLevelFromElevation(elevation), false, out state, out elevationOffset); + } + + public DB.Level ConvertLevelToRevit(Curve curve, out ApplicationObject.State state, out double elevationOffset) + { + var elevation = ElevationFromCurve(curve); + return ConvertLevelToRevit(ObjectsLevelFromElevation(elevation), false, out state, out elevationOffset); + } + + public DB.Level ConvertLevelToRevit(BuiltElements.Level speckleLevel, out ApplicationObject.State state) + { + double elevationOffset = 0.0; + return ConvertLevelToRevit(speckleLevel, true, out state, out elevationOffset); + } + + /// + /// Tries to find a level by ELEVATION only, otherwise it creates it. + /// Unless it was created before and we still have its app id in memory + /// Reason for not matching levels by name instead: + /// source file has L0 @0m and L1 @4m + /// dest file has L1 @0m and L2 @4m + /// attempting to move or rename levels would just be a mess, hence, we don't do that! + /// + /// + /// + public DB.Level ConvertLevelToRevit( + BuiltElements.Level speckleLevel, + bool exactElevation, + out ApplicationObject.State state, + out double elevationOffset + ) + { + state = ApplicationObject.State.Unknown; + elevationOffset = 0.0; + if (speckleLevel == null) + { + return null; + } + + var docLevels = new FilteredElementCollector(Doc).OfClass(typeof(DB.Level)).ToElements().Cast(); + + bool elevationMatch = true; + //level by name component + if (speckleLevel is RevitLevel speckleRevitLevel && speckleRevitLevel.referenceOnly) + { + //see: https://speckle.community/t/revit-connector-levels-and-spaces/2824/5 + elevationMatch = false; + if (GetExistingLevelByName(docLevels, speckleLevel.name) is DB.Level existingLevelWithSameName) + { + return existingLevelWithSameName; + } + } + + DB.Level revitLevel = null; + var speckleLevelElevation = ScaleToNative((double)speckleLevel.elevation, speckleLevel.units); + + //the level has been received before (via schema builder probably) + //match by appid => update level + if (GetExistingElementByApplicationId(speckleLevel.applicationId) is DB.Level existingLevelAlreadyReceived) + { + revitLevel = existingLevelAlreadyReceived; + + revitLevel.Name = speckleLevel.name; + if (Math.Abs(revitLevel.Elevation - (double)speckleLevelElevation) >= TOLERANCE) + { + revitLevel.Elevation = speckleLevelElevation; + } + + state = ApplicationObject.State.Updated; + } + //match by elevation + else if ( + !exactElevation + && elevationMatch + && ( + GetExistingLevelByClosestElevation(docLevels, speckleLevelElevation, out elevationOffset) + is DB.Level existingLevelWithClosestElevation + ) + ) + { + revitLevel = existingLevelWithClosestElevation; + state = ApplicationObject.State.Skipped; // state should be eliminated + } + //match by elevation + else if ( + elevationMatch + && (GetExistingLevelByElevation(docLevels, speckleLevelElevation) is DB.Level existingLevelWithSameElevation) + ) + { + revitLevel = existingLevelWithSameElevation; + revitLevel.Name = speckleLevel.name; + state = ApplicationObject.State.Updated; + } + else + { + // If we don't have an existing level, create it. + revitLevel = Level.Create(Doc, (double)speckleLevelElevation); + revitLevel.Name = speckleLevel.name; + + var rl = speckleLevel as RevitLevel; + if (rl != null && rl.createView) + { + CreateViewPlan(speckleLevel.name, revitLevel.Id); + } + + state = ApplicationObject.State.Created; + } + + return revitLevel; + } + + public ApplicationObject LevelToNative(BuiltElements.Level speckleLevel) + { + var revitLevel = ConvertLevelToRevit(speckleLevel, out ApplicationObject.State state); + var appObj = new ApplicationObject(speckleLevel.id, speckleLevel.speckle_type) + { + applicationId = speckleLevel.applicationId + }; + appObj.Update(status: state, createdId: revitLevel.UniqueId, convertedItem: revitLevel); + return appObj; + } + + public RevitLevel LevelToSpeckle(DB.Level revitLevel) + { + var speckleLevel = new RevitLevel(); + + speckleLevel.elevation = ScaleToSpeckle(revitLevel.Elevation); + speckleLevel.name = revitLevel.Name; + speckleLevel.createView = true; + + GetAllRevitParamsAndIds(speckleLevel, revitLevel); + + return speckleLevel; + } + + public ViewPlan CreateViewPlan(string name, ElementId levelId) + { + var vt = new FilteredElementCollector(Doc) + .OfClass(typeof(ViewFamilyType)) + .Where(el => ((ViewFamilyType)el).ViewFamily == ViewFamily.FloorPlan) + .First(); + + var view = ViewPlan.Create(Doc, vt.Id, levelId); + try + { + view.Name = name; + } + catch { } + + Report.Log($"Created ViewPlan {view.Id}"); + + return view; + } + + private Level GetLevelByName(string name) + { + var collector = new FilteredElementCollector(Doc).OfClass(typeof(DB.Level)).ToElements().Cast(); + + //match by name + var revitLevel = collector.FirstOrDefault(x => x.Name == name); + if (revitLevel != null) + { + return revitLevel; + } + + //match by id? + revitLevel = collector.FirstOrDefault(x => x.Id.ToString() == name); + if (revitLevel != null) + { + return revitLevel; + } + + Report.LogConversionError(new Exception($"Could not find level `{name}`, a default level will be used.")); + + return collector.FirstOrDefault(); + } + + private RevitLevel ConvertAndCacheLevel(DB.Element elem, BuiltInParameter bip) + { + var param = elem.get_Parameter(bip); + + if (param == null || param.StorageType != StorageType.ElementId) + { + return null; + } + + return ConvertAndCacheLevel(param.AsElementId(), elem.Document); + } + + private RevitLevel ConvertAndCacheLevel(ElementId id, Document doc) + { + var level = doc.GetElement(id) as DB.Level; + + if (level == null) + { + return null; + } + + if (!Levels.ContainsKey(level.Name)) + { + Levels[level.Name] = LevelToSpeckle(level); + } + + return Levels[level.Name] as RevitLevel; + } + + private double ElevationFromPoint(XYZ point) + { + var p = PointToSpeckle(point, Doc); + return p.z; + } + + private RevitLevel LevelFromElevation(double z) + { + return new RevitLevel() + { + elevation = z, + name = "Generated Level " + z, + units = ModelUnits + }; + } + + private Objects.BuiltElements.Level ObjectsLevelFromElevation(double z) + { + return new Objects.BuiltElements.Level() + { + elevation = z, + name = "Generated Level " + z, + units = ModelUnits + }; + } + + private RevitLevel LevelFromPoint(XYZ point) + { + return LevelFromElevation(ElevationFromPoint(point)); + } + + private double ElevationFromCurve(Curve curve) + { + var start = curve.GetEndPoint(0); + var end = curve.GetEndPoint(1); + var point = start.Z < end.Z ? start : end; // pick the lowest + return ElevationFromPoint(point); + } + + private RevitLevel LevelFromCurve(Curve curve) + { + return LevelFromElevation(ElevationFromCurve(curve)); + } + + private Level GetFirstDocLevel() + { + var docLevels = new FilteredElementCollector(Doc).OfClass(typeof(Level)).ToElements().Cast(); + return docLevels.First(); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLocation.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLocation.cs new file mode 100644 index 0000000000..c0c879afd9 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertLocation.cs @@ -0,0 +1,111 @@ +using System; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using RevitSharedResources.Helpers; +using RevitSharedResources.Helpers.Extensions; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; +using SHC = RevitSharedResources.Helpers.Categories; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public Base LocationToSpeckle(DB.Element revitElement) + { + if ( + revitElement is DB.FamilyInstance familyInstance + && familyInstance.Location is LocationPoint lp + && ( + SHC.Column.BuiltInCategories.HasCategory(familyInstance.Category) + || familyInstance.StructuralType == StructuralType.Column + ) + ) + { + //vertical columns are point based, and the point does not reflect the actual vertical location + return TryGetColumnLocationAsCurve(familyInstance, lp); + } + + var revitLocation = revitElement.Location; + switch (revitLocation) + { + case LocationCurve locationCurve: + { + var curve = locationCurve.Curve; + + //apply revit offset as transfrom + if (revitElement is DB.Wall) + { + var offset = revitElement.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble(); + XYZ vector = new(0, 0, offset); + Transform tf = Transform.CreateTranslation(vector); + curve = curve.CreateTransformed(tf); + } + + return CurveToSpeckle(curve, revitElement.Document) as Base; + } + case LocationPoint locationPoint: + { + return PointToSpeckle(locationPoint.Point, revitElement.Document); + } + // TODO what is the correct way to handle this? + case null: + return null; + + default: + return null; + } + } + + /// + /// Tries to to get the location of a column as a Curve + /// + /// + /// + /// + private Base TryGetColumnLocationAsCurve(DB.FamilyInstance familyInstance, LocationPoint locationPoint) + { + var point = PointToSpeckle(locationPoint.Point, familyInstance.Document); + + var baseOffset = GetParamValue(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + var baseLevel = ConvertAndCacheLevel(familyInstance, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + var topOffset = GetParamValue(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); + var topLevel = ConvertAndCacheLevel(familyInstance, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + + if (baseLevel == null || topLevel == null) + { + SpeckleLog.Logger.Error( + "Failed to get baseCurve from vertical column because the baseLevel or topLevel (or both) parameters were null" + ); + return point; + } + + var baseLine = new Line( + new[] { point.x, point.y, baseLevel.elevation + baseOffset, point.x, point.y, topLevel.elevation + topOffset }, + ModelUnits + ); + baseLine.length = Math.Abs(baseLine.start.z - baseLine.end.z); + + return baseLine; + } + + /// + /// Checks whether the curve is vertical or not. + /// + /// + /// + private static bool IsVertical(DB.Curve curve) + { + var diffX = Math.Abs(curve.GetEndPoint(0).X - curve.GetEndPoint(1).X); + var diffY = Math.Abs(curve.GetEndPoint(0).Y - curve.GetEndPoint(1).Y); + + if (diffX < 0.1 && diffY < 0.1) + { + return true; + } + + return false; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMEPFamilyInstance.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMEPFamilyInstance.cs new file mode 100644 index 0000000000..b0cc368fd4 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMEPFamilyInstance.cs @@ -0,0 +1,125 @@ +using DB = Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Autodesk.Revit.DB; +using System.Linq; +using Objects.Organization; +using System; +using System.Collections.Generic; +using Speckle.Core.Models; +using Speckle.Core.Kits; +using RevitSharedResources.Models; +using Speckle.Core.Logging; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public List FittingPartTypes { get; } = + new List() { PartType.Elbow, PartType.Tee, PartType.Cross, PartType.Transition, PartType.Union }; + + public RevitMEPFamilyInstance MEPFamilyInstanceToSpeckle( + DB.FamilyInstance familyInstance, + RevitMEPFamilyInstance existingSpeckleObject = null + ) + { + var speckleFi = existingSpeckleObject ?? new RevitMEPFamilyInstance(); + + var partType = GetParamValue(familyInstance.Symbol.Family, BuiltInParameter.FAMILY_CONTENT_PART_TYPE); + speckleFi.RevitPartType = partType.ToString(); + + foreach (var connector in familyInstance.MEPModel?.ConnectorManager?.Connectors?.Cast()) + { + speckleFi.Connectors.Add(ConnectorToSpeckle(connector)); + } + + using var coarseOptions = new Options() { DetailLevel = ViewDetailLevel.Coarse }; + foreach (var curve in GetCurvesFromGeom(familyInstance.get_Geometry(coarseOptions))) + { + speckleFi.Curves.Add(CurveToSpeckle(curve, familyInstance.Document)); + } + + _ = RevitInstanceToSpeckle(familyInstance, out _, null, existingInstance: speckleFi); + return speckleFi; + } + + private IEnumerable GetCurvesFromGeom(GeometryElement geometryElement) + { + foreach (var geomObj in geometryElement) + { + switch (geomObj) + { + case DB.Curve curve: + yield return curve; + break; + case DB.GeometryInstance i: + foreach (var c in GetCurvesFromGeom(i.GetInstanceGeometry())) + { + yield return c; + } + break; + } + } + } + + public DB.FamilyInstance MEPFamilyInstanceToNative(RevitMEPFamilyInstance speckleFi, ApplicationObject appObj) + { + _ = RevitInstanceToNative(speckleFi, appObj); + var revitFi = (DB.FamilyInstance)appObj.Converted.First(); + + CreateSystemConnections(speckleFi.Connectors, revitFi, receivedObjectsCache); + + return revitFi; + } + + public ApplicationObject FittingOrMEPInstanceToNative(RevitMEPFamilyInstance speckleFi) + { + var appObj = new ApplicationObject(speckleFi.id, speckleFi.speckle_type) + { + applicationId = speckleFi.applicationId + }; + + if (Enum.TryParse(speckleFi.RevitPartType, out var partType) && FittingPartTypes.Contains(partType)) + { + try + { + _ = FittingToNative(speckleFi, partType, appObj); + return appObj; + } + catch (ConversionNotReadyException) + { + var notReadyData = revitDocumentAggregateCache + .TryGetCacheOfType() + ?.TryGet(speckleFi.id); + + if (notReadyData == null || !notReadyData.HasValue || notReadyData.Value.NumberOfTimesCaught < 2) + { + throw; + } + else + { + SpeckleLog.Logger.Error( + "Could not create fitting as part of the system. Reason: Speckle object of type RevitMEPFamilyInstance was waiting for an object to convert that never did. Converting as independent instance instead" + ); + appObj.Update( + logItem: $"Could not create fitting as part of the system. Reason: Speckle object of type {speckleFi.GetType()} was waiting for an object to convert that never did. Converting as independent instance instead" + ); + _ = MEPFamilyInstanceToNative(speckleFi, appObj); + return appObj; + } + } + catch (Exception ex) + { + appObj.Update( + logItem: $"Could not create fitting as part of the system. Reason: {ex.Message}. Converting as independent instance instead" + ); + _ = MEPFamilyInstanceToNative(speckleFi, appObj); + return appObj; + } + } + else + { + _ = MEPFamilyInstanceToNative(speckleFi, appObj); + return appObj; + } + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterial.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterial.cs new file mode 100644 index 0000000000..09c143ba07 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterial.cs @@ -0,0 +1,45 @@ +using Autodesk.Revit.DB.Structure; +using Speckle.Core.Kits; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public Objects.Other.Material MaterialToSpeckle(DB.Material revitmaterial) + { + var speckleMaterial = new Objects.Other.Revit.RevitMaterial( + revitmaterial.Name, + revitmaterial.MaterialCategory, + revitmaterial.MaterialClass, + revitmaterial.Shininess, + revitmaterial.Smoothness, + revitmaterial.Transparency + ); + + GetAllRevitParamsAndIds(speckleMaterial, revitmaterial); + + Report.Log($"Converted Material{revitmaterial.Id}"); + return speckleMaterial; + } + + private Objects.Other.Material ConvertAndCacheMaterial(DB.ElementId id, DB.Document doc) + { + var material = doc.GetElement(id) as DB.Material; + + if (material == null) + { + return null; + } + + if (!Materials.ContainsKey(material.Name)) + { + Materials[material.Name] = MaterialToSpeckle(material); + } + return Materials[material.Name] as Objects.Other.Material; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterialQuantities.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterialQuantities.cs new file mode 100644 index 0000000000..8c8a232732 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMaterialQuantities.cs @@ -0,0 +1,157 @@ +#nullable enable +using Autodesk.Revit.DB; +using ConverterRevitShared.Extensions; +using Objects.Other; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + /// + /// Material Quantities in Revit are stored in different ways and therefore need to be retrieved + /// using different methods. According to this forum post https://forums.autodesk.com/t5/revit-api-forum/method-getmaterialarea-appears-to-use-different-formulas-for/td-p/11988215 + /// "Hosts" (whatever that means) will return the area of a single side of the object while other + /// objects will return the combined area of every side of the element. Certain MEP element materials + /// are attached to the MEP system that the element belongs to. + /// + /// + /// + /// + public IEnumerable MaterialQuantitiesToSpeckle(DB.Element element, string units) + { + if (MaterialAreaAPICallWillReportSingleFace(element)) + { + return GetMaterialQuantitiesFromAPICall(element, units); + } + else if (MaterialIsAttachedToMEPSystem(element)) + { + MaterialQuantity quantity = GetMaterialQuantityForMEPElement(element, units); + return quantity == null ? Enumerable.Empty() : new List() { quantity }; + } + else + { + return GetMaterialQuantitiesFromSolids(element, units); + } + } + + private IEnumerable GetMaterialQuantitiesFromAPICall(DB.Element element, string units) + { + foreach (ElementId matId in element.GetMaterialIds(false)) + { + double volume = element.GetMaterialVolume(matId); + double area = element.GetMaterialArea(matId, false); + yield return CreateMaterialQuantity(element, matId, area, volume, units); + } + } + + private MaterialQuantity? GetMaterialQuantityForMEPElement(DB.Element element, string units) + { + DB.Material material = GetMEPSystemRevitMaterial(element); + if (material == null) + { + return null; + } + + DB.Options options = new() { DetailLevel = ViewDetailLevel.Fine }; + var (solids, _) = GetSolidsAndMeshesFromElement(element, options); + + (double area, double volume) = GetAreaAndVolumeFromSolids(solids); + return CreateMaterialQuantity(element, material.Id, area, volume, units); + } + + private IEnumerable GetMaterialQuantitiesFromSolids(DB.Element element, string units) + { + DB.Options options = new() { DetailLevel = ViewDetailLevel.Fine }; + var (solids, _) = GetSolidsAndMeshesFromElement(element, options); + + foreach (ElementId matId in GetMaterialsFromSolids(solids)) + { + (double area, double volume) = GetAreaAndVolumeFromSolids(solids, matId); + yield return CreateMaterialQuantity(element, matId, area, volume, units); + } + } + + private MaterialQuantity CreateMaterialQuantity( + Element element, + ElementId materialId, + double areaRevitInternalUnits, + double volumeRevitInternalUnits, + string units + ) + { + Other.Material speckleMaterial = ConvertAndCacheMaterial(materialId, element.Document); + double factor = ScaleToSpeckle(1); + double area = factor * factor * areaRevitInternalUnits; + double volume = factor * factor * factor * volumeRevitInternalUnits; + MaterialQuantity materialQuantity = new(speckleMaterial, volume, area, units); + + switch (element) + { + case DB.Architecture.Railing railing: + materialQuantity["length"] = railing.GetPath().Sum(e => e.Length) * factor; + break; + + case DB.Architecture.ContinuousRail continuousRail: + materialQuantity["length"] = continuousRail.GetPath().Sum(e => e.Length) * factor; + break; + + default: + if (LocationToSpeckle(element) is ICurve curve) + { + materialQuantity["length"] = curve.length; + } + break; + } + ; + + return materialQuantity; + } + + private (double, double) GetAreaAndVolumeFromSolids(List solids, ElementId? materialId = null) + { + if (materialId != null) + { + solids = solids + .Where( + solid => solid.Volume > 0 && !solid.Faces.IsEmpty && solid.Faces.get_Item(0).MaterialElementId == materialId + ) + .ToList(); + } + + double volume = solids.Sum(solid => solid.Volume); + IEnumerable areaOfLargestFaceInEachSolid = solids.Select( + solid => solid.Faces.Cast().Select(face => face.Area).Max() + ); + double area = areaOfLargestFaceInEachSolid.Sum(); + return (area, volume); + } + + private IEnumerable GetMaterialsFromSolids(List solids) + { + return solids + .Where(solid => solid.Volume > 0 && !solid.Faces.IsEmpty) + .Select(m => m.Faces.get_Item(0).MaterialElementId) + .Distinct(); + } + + private bool MaterialAreaAPICallWillReportSingleFace(Element element) + { + return element switch + { + DB.CeilingAndFloor or DB.Wall or DB.RoofBase => true, + _ => false + }; + } + + private bool MaterialIsAttachedToMEPSystem(Element element) + { + return element switch + { + DB.Mechanical.Duct or DB.Mechanical.FlexDuct or DB.Plumbing.Pipe or DB.Plumbing.FlexPipe => true, + _ => false + }; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMeshUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMeshUtils.cs new file mode 100644 index 0000000000..12526d4a39 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertMeshUtils.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using Autodesk.Revit.DB; +using Speckle.Core.Logging; +using DB = Autodesk.Revit.DB; +using Mesh = Objects.Geometry.Mesh; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public Options ViewSpecificOptions { get; set; } + + /// + /// We're caching a dictionary of graphic styles and their ids as it can be a costly operation doing Document.GetElement(solid.GraphicsStyleId) for every solid + /// + private Dictionary _graphicStyleCache = new(); + + /// + /// Retreives the meshes on an element to use as the speckle displayvalue + /// + /// + /// Some FamilyInstance elements are treated as proper Instance objects, while others are not. For those being converted as Instance objects, retrieve their display value untransformed by the instance transform or by the selected document reference point. + /// + /// + /// See https://www.revitapidocs.com/2023/e0f15010-0e19-6216-e2f0-ab7978145daa.htm for a full Geometry Object inheritance + /// + public List GetElementDisplayValue( + DB.Element element, + Options options = null, + bool isConvertedAsInstance = false, + DB.Transform transform = null + ) + { + var displayMeshes = new List(); + + // test if the element is a group first + if (element is Group g) + { + foreach (var id in g.GetMemberIds()) + { + var groupMeshes = GetElementDisplayValue(element.Document.GetElement(id), options, isConvertedAsInstance); + displayMeshes.AddRange(groupMeshes); + } + return displayMeshes; + } + + var (solids, meshes) = GetSolidsAndMeshesFromElement(element, options, transform); + + // convert meshes and solids + displayMeshes.AddRange(ConvertMeshesByRenderMaterial(meshes, element.Document, isConvertedAsInstance)); + displayMeshes.AddRange(ConvertSolidsByRenderMaterial(solids, element.Document, isConvertedAsInstance)); + + return displayMeshes; + } + + public (List, List) GetSolidsAndMeshesFromElement( + Element element, + Options options, + Transform? transform = null + ) + { + options = ViewSpecificOptions ?? options ?? new Options() { DetailLevel = DetailLevelSetting }; + + GeometryElement geom; + try + { + geom = element.get_Geometry(options); + } + catch (Autodesk.Revit.Exceptions.ArgumentException) + { + options.ComputeReferences = false; + geom = element.get_Geometry(options); + } + + var solids = new List(); + var meshes = new List(); + + if (geom != null) + { + // retrieves all meshes and solids from a geometry element + SortGeometry(element, solids, meshes, geom, transform?.Inverse); + } + + return (solids, meshes); + } + + private static void LogInstanceMeshRetrievalWarnings( + Element element, + int topLevelSolidsCount, + int topLevelMeshesCount, + int topLevelGeomElementCount, + int topLevelGeomInstanceCount, + bool hasSymbolGeom + ) + { + if (hasSymbolGeom) + { + if (topLevelSolidsCount > 0) + { + SpeckleLog.Logger.Warning( + "Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numSolids} top level solids. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", + element.GetType(), + element.UniqueId, + topLevelSolidsCount + ); + } + if (topLevelMeshesCount > 0) + { + SpeckleLog.Logger.Warning( + "Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numMeshes} top level meshes. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", + element.GetType(), + element.UniqueId, + topLevelMeshesCount + ); + } + if (topLevelGeomElementCount > 0) + { + SpeckleLog.Logger.Warning( + "Element of type {elementType} with uniqueId {uniqueId} has valid symbol geometry and {numGeomElements} top level geometry elements. See comment on method SortInstanceGeometry for link to RevitAPI docs that leads us to believe this shouldn't happen", + element.GetType(), + element.UniqueId, + topLevelGeomElementCount + ); + } + } + } + + /// + /// According to the remarks on the GeometryInstance class in the RevitAPIDocs, + /// https://www.revitapidocs.com/2024/fe25b14f-5866-ca0f-a660-c157484c3a56.htm, + /// a family instance geometryElement should have a top-level geometry instance when the symbol + /// does not have modified geometry (the docs say that modified geometry will not have a geom instance, + /// however in my experience, all family instances have a top-level geom instance, but if the family instance + /// is modified, then the geom instance won't contain any geometry.) + /// + /// This remark also leads me to think that a family instance will not have top-level solids and geom instances. + /// We are logging cases where this is not true. + /// + /// + /// + /// + /// + void SortGeometry( + Element element, + List solids, + List meshes, + GeometryElement geom, + Transform inverseTransform = null + ) + { + var topLevelSolidsCount = 0; + var topLevelMeshesCount = 0; + var topLevelGeomElementCount = 0; + var topLevelGeomInstanceCount = 0; + bool hasSymbolGeometry = false; + + foreach (GeometryObject geomObj in geom) + { + switch (geomObj) + { + case Solid solid: + // skip invalid solid + if ( + solid.Faces.Size == 0 + || Math.Abs(solid.SurfaceArea) == 0 + || IsSkippableGraphicStyle(solid.GraphicsStyleId, element.Document) + ) + { + continue; + } + + if (inverseTransform != null) + { + topLevelSolidsCount++; + solid = SolidUtils.CreateTransformed(solid, inverseTransform); + } + + solids.Add(solid); + break; + case DB.Mesh mesh: + if (IsSkippableGraphicStyle(mesh.GraphicsStyleId, element.Document)) + { + continue; + } + + if (inverseTransform != null) + { + topLevelMeshesCount++; + mesh = mesh.get_Transformed(inverseTransform); + } + + meshes.Add(mesh); + break; + case GeometryInstance instance: + // element transforms should not be carried down into nested geometryInstances. + // Nested geomInstances should have their geom retreived with GetInstanceGeom, not GetSymbolGeom + if (inverseTransform != null) + { + topLevelGeomInstanceCount++; + SortGeometry(element, solids, meshes, instance.GetSymbolGeometry()); + if (meshes.Count > 0 || solids.Count > 0) + { + hasSymbolGeometry = true; + } + } + else + { + SortGeometry(element, solids, meshes, instance.GetInstanceGeometry()); + } + break; + case GeometryElement geometryElement: + if (inverseTransform != null) + { + topLevelGeomElementCount++; + } + SortGeometry(element, solids, meshes, geometryElement); + break; + } + } + + if (inverseTransform != null) + { + LogInstanceMeshRetrievalWarnings( + element, + topLevelSolidsCount, + topLevelMeshesCount, + topLevelGeomElementCount, + topLevelGeomInstanceCount, + hasSymbolGeometry + ); + } + } + + /// + /// Exclude light source cones and potentially other geometries by their graphic style + /// + /// + /// + /// + private bool IsSkippableGraphicStyle(ElementId id, Document doc) + { + if (!_graphicStyleCache.ContainsKey(id.ToString())) + { + _graphicStyleCache.Add(id.ToString(), doc.GetElement(id) as GraphicsStyle); + } + + var graphicStyle = _graphicStyleCache[id.ToString()]; + + if ( + graphicStyle != null + && graphicStyle.GraphicsStyleCategory.Id.IntegerValue == (int)(BuiltInCategory.OST_LightingFixtureSource) + ) + { + return true; + } + + return false; + } + + /// + /// Given a collection of , will create one per distinct + /// + /// + /// + /// + private List ConvertMeshesByRenderMaterial( + List meshes, + Document d, + bool doNotTransformWithReferencePoint = false + ) + { + MeshBuildHelper buildHelper = new(); + + foreach (var mesh in meshes) + { + var revitMaterial = d.GetElement(mesh.MaterialElementId) as DB.Material; + Mesh speckleMesh = buildHelper.GetOrCreateMesh(revitMaterial, ModelUnits); + ConvertMeshData(mesh, speckleMesh.faces, speckleMesh.vertices, d, doNotTransformWithReferencePoint); + } + + return buildHelper.GetAllValidMeshes(); + } + + /// + /// Given a collection of , will create one per distinct + /// + /// + /// + /// + private List ConvertSolidsByRenderMaterial( + IEnumerable solids, + Document d, + bool doNotTransformWithReferencePoint = false + ) + { + MeshBuildHelper meshBuildHelper = new(); + + var MeshMap = new Dictionary>(); + foreach (Solid solid in solids) + { + foreach (Face face in solid.Faces) + { + DB.Material faceMaterial = d.GetElement(face.MaterialElementId) as DB.Material; + Mesh m = meshBuildHelper.GetOrCreateMesh(faceMaterial, ModelUnits); + if (!MeshMap.ContainsKey(m)) + { + MeshMap.Add(m, new List()); + } + MeshMap[m].Add(face.Triangulate()); + } + } + + foreach (var meshData in MeshMap) + { + //It's cheaper to resize lists manually, since we would otherwise be resizing a lot! + int numberOfVertices = 0; + int numberOfFaces = 0; + foreach (DB.Mesh mesh in meshData.Value) + { + if (mesh == null) + { + continue; + } + + numberOfVertices += mesh.Vertices.Count * 3; + numberOfFaces += mesh.NumTriangles * 4; + } + + meshData.Key.faces.Capacity = numberOfFaces; + meshData.Key.vertices.Capacity = numberOfVertices; + foreach (DB.Mesh mesh in meshData.Value) + { + if (mesh == null) + { + continue; + } + + ConvertMeshData(mesh, meshData.Key.faces, meshData.Key.vertices, d, doNotTransformWithReferencePoint); + } + } + + return meshBuildHelper.GetAllValidMeshes(); + } + + /// + /// Given , will convert and add triangle data to and + /// + /// The revit mesh to convert + /// The faces list to add to + /// The vertices list to add to + private void ConvertMeshData( + DB.Mesh mesh, + List faces, + List vertices, + Document doc, + bool doNotTransformWithReferencePoint = false + ) + { + int faceIndexOffset = vertices.Count / 3; + + foreach (var vert in mesh.Vertices) + { + var (x, y, z) = PointToSpeckle(vert, doc, null, doNotTransformWithReferencePoint); + vertices.Add(x); + vertices.Add(y); + vertices.Add(z); + } + + for (int i = 0; i < mesh.NumTriangles; i++) + { + var triangle = mesh.get_Triangle(i); + + faces.Add(3); // TRIANGLE flag + faces.Add((int)triangle.get_Index(0) + faceIndexOffset); + faces.Add((int)triangle.get_Index(1) + faceIndexOffset); + faces.Add((int)triangle.get_Index(2) + faceIndexOffset); + } + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertModel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertModel.cs new file mode 100644 index 0000000000..7c1db95cd6 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertModel.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using Objects.Geometry; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Transform = Objects.Other.Transform; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + /// + /// Returns a object containing and location + /// information. This is intended to be used as the root commit object when sending to Speckle. + /// + /// the currently active document + /// true if project info should be added + /// + public Base ModelToSpeckle(DB.Document doc, bool sendProjectInfo = true) + { + var model = new Collection("Revit model", "model"); + // TODO: setting for whether or not to include project info + if (sendProjectInfo) + { + var info = ProjectInfoToSpeckle(doc.ProjectInformation); + info.latitude = doc.SiteLocation.Latitude; + info.longitude = doc.SiteLocation.Longitude; + info.siteName = doc.SiteLocation.PlaceName; + info.locations = ProjectLocationsToSpeckle(doc); + model["info"] = info; + } + + Report.Log($"Created Model Object"); + + return model; + } + + /// + /// Converts the Revit document's into a list of bases including the , + /// name, and true north angle (in radians) + /// + /// + /// + public List ProjectLocationsToSpeckle(DB.Document doc) + { + var locations = doc.ProjectLocations; + // TODO: do we need a location obj? + var spcklLocations = new List(); + foreach (DB.ProjectLocation location in locations) + { + var position = location.GetProjectPosition(DB.XYZ.Zero); + var revitTransform = DB.Transform.CreateRotation(DB.XYZ.BasisZ, position.Angle); + + var spcklLoc = new Base() { applicationId = location.UniqueId }; + var basisX = VectorToSpeckle(revitTransform.BasisX, doc); + var basisY = VectorToSpeckle(revitTransform.BasisY, doc); + var basisZ = VectorToSpeckle(revitTransform.BasisZ, doc); + var translation = new Vector( + ScaleToSpeckle(position.EastWest), + ScaleToSpeckle(position.NorthSouth), + ScaleToSpeckle(position.Elevation), + ModelUnits + ); + spcklLoc["transform"] = new Transform(basisX, basisY, basisZ, translation); + spcklLoc["name"] = location.Name; + spcklLoc["trueNorth"] = position.Angle; + spcklLocations.Add(spcklLoc); + } + + return spcklLocations; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertNetwork.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertNetwork.cs new file mode 100644 index 0000000000..8eddc6f844 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertNetwork.cs @@ -0,0 +1,623 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Electrical; +using Autodesk.Revit.DB.Mechanical; +using Autodesk.Revit.DB.Plumbing; +using ConverterRevitShared.Revit; +using Objects.BuiltElements.Revit; +using Speckle.Core.Credentials; +using Speckle.Core.Models; +using Speckle.Newtonsoft.Json.Linq; +using DB = Autodesk.Revit.DB; +using Network = Objects.BuiltElements.Network; +using NetworkElement = Objects.BuiltElements.NetworkElement; +using NetworkLink = Objects.BuiltElements.NetworkLink; +using RevitNetworkElement = Objects.BuiltElements.Revit.RevitNetworkElement; +using RevitNetworkLink = Objects.BuiltElements.Revit.RevitNetworkLink; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject NetworkToNative(Network speckleNetwork) + { + var appObj = new ApplicationObject(speckleNetwork.id, speckleNetwork.speckle_type) + { + applicationId = speckleNetwork.applicationId + }; + + speckleNetwork.elements.ForEach(e => e.network = speckleNetwork); + speckleNetwork.links.ForEach(l => l.network = speckleNetwork); + + // convert all the MEP trades and family instances except fittings + + var convertedElements = new Dictionary(); + var elements = speckleNetwork.elements.Cast().ToList(); + var notConnectorBasedCreationElements = elements.Where(e => !e.isConnectorBased).ToArray(); + foreach (var networkElement in notConnectorBasedCreationElements) + { + var element = networkElement.elements; + if (CanConvertToNative(element)) + { + var convAppObj = ConvertToNative(element) as ApplicationObject; + foreach (var obj in convAppObj.Converted) + { + var nativeElement = obj as Element; + appObj.Update( + status: ApplicationObject.State.Created, + createdId: nativeElement.UniqueId, + convertedItem: nativeElement + ); + } + convertedElements.Add(networkElement.applicationId, convAppObj.Converted.First() as Element); + } + else + { + appObj.Update( + status: ApplicationObject.State.Skipped, + logItem: $"Receiving this object type is not supported in Revit" + ); + } + } + + // convert connector based creation elements, We use different way to create curve fittings such as elbow, + // transition, tee, union, cross then other family instances since creation are based on connectors, two, + // three or four depends on type of fitting. + + var connectorBasedCreationElements = elements.Where(e => e.isConnectorBased).ToArray(); + var convertedMEPCurves = convertedElements.Where(e => e.Value is MEPCurve).ToArray(); + foreach (var networkElement in connectorBasedCreationElements) + { + var familySymbol = GetElementType(networkElement.elements, appObj, out bool _); + if (familySymbol == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + continue; + } + + DB.FamilyInstance familyInstance = null; + + var tempCurves = new Dictionary(); + + foreach (var link in networkElement.links) + { + if (link is RevitNetworkLink revitLink && revitLink.needsPlaceholders) + { + var curve = CreateCurve(revitLink); + tempCurves.Add(revitLink.fittingIndex, curve); + } + } + + var connections = networkElement.links + .Cast() + .ToDictionary( + l => l, + l => + l.elements + .Cast() + .FirstOrDefault(e => e.applicationId != networkElement.applicationId && e.isCurveBased) + ); + + var connection1 = connections.FirstOrDefault(c => c.Key.fittingIndex == 1); + var connection2 = connections.FirstOrDefault(c => c.Key.fittingIndex == 2); + var connection3 = connections.FirstOrDefault(c => c.Key.fittingIndex == 3); + var connection4 = connections.FirstOrDefault(c => c.Key.fittingIndex == 4); + + var element1 = + connection1.Value != null + ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection1.Value.applicationId).Value + : tempCurves.FirstOrDefault(t => t.Key == 1).Value; + var element2 = + connection2.Value != null + ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection2.Value.applicationId).Value + : tempCurves.FirstOrDefault(t => t.Key == 2).Value; + var element3 = + connection3.Value != null + ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection3.Value.applicationId).Value + : tempCurves.FirstOrDefault(t => t.Key == 3).Value; + var element4 = + connection4.Value != null + ? convertedMEPCurves.FirstOrDefault(e => e.Key == connection4.Value.applicationId).Value + : tempCurves.FirstOrDefault(t => t.Key == 4).Value; + + var connector1 = element1 != null ? GetConnectorByPoint(element1, PointToNative(connection1.Key.origin)) : null; + var connector2 = element2 != null ? GetConnectorByPoint(element2, PointToNative(connection2.Key.origin)) : null; + var connector3 = element3 != null ? GetConnectorByPoint(element3, PointToNative(connection3.Key.origin)) : null; + var connector4 = element4 != null ? GetConnectorByPoint(element4, PointToNative(connection4.Key.origin)) : null; + + var partType = networkElement.elements["partType"] as string ?? "Unknown"; + if (partType.Contains("Elbow") && connector1 != null && connector2 != null) + { + familyInstance = Doc.Create.NewElbowFitting(connector1, connector2); + } + else if (partType.Contains("Transition") && connector1 != null && connector2 != null) + { + familyInstance = Doc.Create.NewTransitionFitting(connector1, connector2); + } + else if (partType.Contains("Union") && connector1 != null && connector2 != null) + { + familyInstance = Doc.Create.NewUnionFitting(connector1, connector2); + } + else if (partType.Contains("Tee") && connector1 != null && connector2 != null && connector3 != null) + { + familyInstance = Doc.Create.NewTeeFitting(connector1, connector2, connector3); + } + else if ( + partType.Contains("Cross") + && connector1 != null + && connector2 != null + && connector3 != null + && connector4 != null + ) + { + familyInstance = Doc.Create.NewCrossFitting(connector1, connector2, connector3, connector4); + } + else + { + var convAppObj = ConvertToNative(networkElement.elements) as ApplicationObject; + foreach (var obj in convAppObj.Converted) + { + var nativeElement = obj as Element; + appObj.Update( + status: ApplicationObject.State.Created, + createdId: nativeElement.UniqueId, + convertedItem: nativeElement + ); + } + } + + if (familyInstance != null) + { + convertedElements.Add(networkElement.applicationId, familyInstance); + familyInstance?.ChangeTypeId(familySymbol.Id); + Doc.Delete(tempCurves.Select(c => c.Value.Id).ToList()); + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: familyInstance.UniqueId, + convertedItem: familyInstance + ); + } + else + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Family instance was null"); + } + } + + // check if all the elements are connected, some connectors may be unconnected + // due using of temp curves and until all the ones are created no way to connect + // them between each other + + var links = speckleNetwork.links.Cast().ToArray(); + foreach (var link in links) + { + if (link.isConnected && link.elements.Count == 2) + { + var firstElement = convertedElements.FirstOrDefault(e => e.Key == link.elements[0].applicationId).Value; + var secondElement = convertedElements.FirstOrDefault(e => e.Key == link.elements[1].applicationId).Value; + var origin = PointToNative(link.origin); + var firstConnector = GetConnectorByPoint(firstElement, origin); + var secondConnector = GetConnectorByPoint(secondElement, origin); + if ( + firstConnector != null + && secondConnector != null + && !firstConnector.IsConnected + && !secondConnector.IsConnected + ) + { + firstConnector.ConnectTo(secondConnector); + } + } + } + + return appObj; + } + + public Network NetworkToSpeckle(Element mepElement, out List notes) + { + Network speckleNetwork = + new() + { + name = mepElement.Name, + elements = new List(), + links = new List() + }; + + GetNetworkElements(speckleNetwork, mepElement, out notes); + + return speckleNetwork; + } + + /// + /// Gets the connected element of a MEP element and adds the to a Base object + /// + /// + /// + private void GetNetworkElements(Network @network, Element initialElement, out List notes) + { + CachedContextObjects = ContextObjects; + notes = new List(); + var networkConnections = new List(); + GetNetworkConnections(initialElement, ref networkConnections); + var groups = networkConnections.GroupBy(n => n.Owner.UniqueId).ToList(); + + foreach (var group in groups) + { + var element = Doc.GetElement(group.Key); + + if (ContextObjects.ContainsKey(element.UniqueId)) + { + ContextObjects.Remove(element.UniqueId); + } + else + { + continue; + } + + ApplicationObject reportObj = Report.ReportObjects.ContainsKey(element.UniqueId) + ? Report.ReportObjects[element.UniqueId] + : new ApplicationObject(element.UniqueId, element.GetType().ToString()); + + Base obj = null; + bool connectorBasedCreation = false; + switch (element) + { + case DB.FamilyInstance fi: + obj = FamilyInstanceToSpeckle(fi, out notes); + // test if this family instance is a fitting + var fittingCategories = new List + { + BuiltInCategory.OST_PipeFitting, + BuiltInCategory.OST_DuctFitting, + BuiltInCategory.OST_CableTrayFitting, + BuiltInCategory.OST_ConduitFitting + }; + if (fittingCategories.Any(c => (int)c == fi.Category.Id.IntegerValue)) + { + connectorBasedCreation = IsConnectorBasedCreation(fi); + var partType = (PartType) + fi.Symbol.Family.get_Parameter(BuiltInParameter.FAMILY_CONTENT_PART_TYPE).AsInteger(); + if (obj != null) + { + obj["partType"] = partType.ToString(); + } + } + break; + case DB.Plumbing.Pipe pipe: + obj = PipeToSpeckle(pipe); + break; + case DB.Plumbing.FlexPipe flexpipe: + obj = PipeToSpeckle(flexpipe); + break; + case DB.Mechanical.Duct duct: + obj = DuctToSpeckle(duct, out notes); + break; + case DB.Mechanical.FlexDuct flexDuct: + obj = DuctToSpeckle(flexDuct); + break; + case DB.Electrical.CableTray cableTray: + obj = CableTrayToSpeckle(cableTray); + break; + case DB.Electrical.Conduit conduit: + obj = ConduitToSpeckle(conduit); + break; + default: + reportObj.Update(status: ApplicationObject.State.Skipped, logItem: $"Conversion not supported"); + Report.Log(reportObj); + continue; + } + + if (obj == null) + { + reportObj.Update(status: ApplicationObject.State.Failed, logItem: $"Conversion returned null"); + Report.Log(reportObj); + continue; + } + + reportObj.Update( + status: ApplicationObject.State.Created, + logItem: $"Attached as connected element to {initialElement.UniqueId}" + ); + @network.elements.Add( + new RevitNetworkElement() + { + applicationId = element.UniqueId, + name = element.Name, + elements = obj, + linkIndices = new List(), + isConnectorBased = connectorBasedCreation, + isCurveBased = element is MEPCurve + } + ); + ConvertedObjects.Add(obj.applicationId); + + Report.Log(reportObj); + } + + foreach (var group in groups) + { + var connections = group.ToList(); + var ownerIndex = @network.elements.FindIndex(e => e.applicationId.Equals(group.Key)); + var ownerElement = @network.elements[ownerIndex]; + foreach (var connection in connections) + { + var link = new RevitNetworkLink() + { + name = connection.Name, + network = @network, + elementIndices = new List() + }; + + link.elementIndices.Add(ownerIndex); + + var connector = connection.Connector; + + link.domain = connector.Domain.ToString(); + link.shape = connector.Shape.ToString(); + link.systemName = connector.Owner.Category.Name; + link.systemType = connector.MEPSystem != null ? Doc.GetElement(connector.MEPSystem.GetTypeId()).Name : ""; + + var origin = connection.Connector.Origin; + + link.origin = PointToSpeckle(origin, initialElement.Document); + link.fittingIndex = connector.Id; + link.direction = VectorToSpeckle(connector.CoordinateSystem.BasisZ, initialElement.Document); + link.isConnected = connection.IsConnected; + link.needsPlaceholders = connection.ConnectedToCurve(out MEPCurve curve) && IsWithinContext(curve); + link.diameter = connection.Diameter; + link.height = connection.Height; + link.width = connection.Width; + + // find index of the ref element + var refConnector = connection.RefConnector; + var refIndex = @network.elements.FindIndex(e => e.applicationId.Equals(refConnector?.Owner?.UniqueId)); + + // add it in case it exists + if (refIndex != -1) + { + link.elementIndices.Add(refIndex); + } + + @network.links.Add(link); + var linkIndex = @network.links.IndexOf(link); + ownerElement.linkIndices.Add(linkIndex); + } + } + + if (@network.elements.Any()) + { + notes.Add($"Converted and attached {@network.elements.Count} connected elements"); + } + } + + private void GetNetworkConnections(Element element, ref List networkConnections) + { + var connectionPairs = ConnectionPair.GetConnectionPairs(element); + foreach (var connectionPair in connectionPairs) + { + if (!networkConnections.Contains(connectionPair)) + { + networkConnections.Add(connectionPair); + var refElement = connectionPair.RefConnector?.Owner; + if (connectionPair.IsConnected && IsWithinContext(refElement)) + { + GetNetworkConnections(refElement, ref networkConnections); + } + } + } + } + + // for fitting family instances, retrieves the type of fitting and determines if it is connector based + private bool IsConnectorBasedCreation(DB.FamilyInstance familyInstance) + { + var connectors = GetConnectors(familyInstance).Cast().ToArray(); + return connectors.All( + c => + connectors.All( + c1 => + (c1.Domain == Domain.DomainPiping && c1.PipeSystemType == c.PipeSystemType) + || (c1.Domain == Domain.DomainHvac && c1.DuctSystemType == c.DuctSystemType) + || (c1.Domain == Domain.DomainElectrical && c1.ElectricalSystemType == c.ElectricalSystemType) + || (c1.Domain == Domain.DomainCableTrayConduit) + ) + ); + } + + private static Dictionary CachedContextObjects = null; + + private bool IsWithinContext(Element element) + { + return CachedContextObjects.ContainsKey(element?.UniqueId); + } + + private void GetConnectionPairs( + Element element, + ref List> connectionPairs, + ref List elements + ) + { + var refss = ConnectionPair.GetConnectionPairs(element); + + foreach (var r in refss) + { + var isValid = r.IsValid(); + var isConnected = r.IsConnected; + } + var refs = GetRefConnectionPairs(element); + var refConnectionPairs = GetRefConnectionPairs(element) + .Where(e => e.Item2 == null || ContextObjects.ContainsKey(e.Item2.Owner.UniqueId)) + .ToList(); + elements.Add(element); + foreach (var refConnectionPair in refs) + { + var connectedElement = refConnectionPair.Item2?.Owner; + if ( + connectedElement != null + && !elements.Any(e => e.UniqueId.Equals(connectedElement.UniqueId)) + && ContextObjects.ContainsKey(connectedElement.UniqueId) + ) + { + connectionPairs.Add(Tuple.Create(refConnectionPair.Item1, refConnectionPair.Item2, element)); + GetConnectionPairs(connectedElement, ref connectionPairs, ref elements); + } + else + { + connectionPairs.Add(Tuple.Create(refConnectionPair.Item1, null, element)); + } + } + } + + private static List> GetRefConnectionPairs(Element element) + { + var refConnectionPairs = new List>(); + var connectors = GetConnectors(element); + var connectorsIterator = connectors.ForwardIterator(); + connectorsIterator.Reset(); + while (connectorsIterator.MoveNext()) + { + var connector = connectorsIterator.Current as Connector; + if (connector != null && connector.IsConnected) + { + var refs = connector.AllRefs; + var refsIterator = refs.ForwardIterator(); + refsIterator.Reset(); + while (refsIterator.MoveNext()) + { + var refConnector = refsIterator.Current as Connector; + if (refConnector != null && !refConnector.Owner.Id.Equals(element.Id) && !(refConnector.Owner is MEPSystem)) + { + refConnectionPairs.Add(Tuple.Create(connector, refConnector)); + } + } + } + else + { + refConnectionPairs.Add(Tuple.Create(connector, null)); + } + } + return refConnectionPairs; + } + + private static ConnectorSet GetConnectors(Element e) + { + return e is MEPCurve curve + ? curve.ConnectorManager.Connectors + : (e as DB.FamilyInstance)?.MEPModel?.ConnectorManager?.Connectors ?? new ConnectorSet(); + } + + private Connector GetConnectorByPoint(Element element, XYZ point) + { + switch (element) + { + case MEPCurve o: + return o.ConnectorManager.Connectors + .Cast() + .FirstOrDefault(c => c.Origin.IsAlmostEqualTo(point, 0.00001)); + case DB.FamilyInstance o: + return o.MEPModel?.ConnectorManager.Connectors + .Cast() + .FirstOrDefault(c => c.Origin.IsAlmostEqualTo(point, 0.00001)); + default: + return null; + } + } + + private MEPCurve CreateCurve(RevitNetworkLink link) + { + var direction = VectorToNative(link.direction); + var start = PointToNative(link.origin); + var end = start.Add(direction.Multiply(2)); + + var sfi = + link.elements.FirstOrDefault(e => e.elements is BuiltElements.Revit.FamilyInstance)?.elements + as BuiltElements.Revit.FamilyInstance; + Level level = ConvertLevelToRevit(sfi.level, out ApplicationObject.State state); + + Domain domain = Enum.TryParse(link.domain, out domain) ? domain : Domain.DomainUndefined; + ConnectorProfileType profile = Enum.TryParse(link.shape, out profile) ? profile : ConnectorProfileType.Invalid; + + MEPCurveType curveType = null; + MEPCurve curve = null; + switch (domain) + { + case Domain.DomainHvac: + curveType = GetDefaultMEPCurveType(Doc, typeof(DuctType), profile); + if (curveType == null) + { + goto default; + } + + var mechanicalSystemType = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(MechanicalSystemType)) + .ToElements() + .Cast() + .FirstOrDefault(x => x.Name == link.systemType); + curve = Duct.Create(Doc, mechanicalSystemType.Id, curveType.Id, level.Id, start, end); + if (curveType.Shape == ConnectorProfileType.Round) + { + curve.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).Set(link.diameter); + } + else + { + curve.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(link.width); + curve.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(link.height); + } + break; + case Domain.DomainPiping: + curveType = GetDefaultMEPCurveType(Doc, typeof(PipeType), profile); + if (curveType == null) + { + goto default; + } + + var pipingSystemType = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(PipingSystemType)) + .ToElements() + .Cast() + .FirstOrDefault(x => x.Name == link.systemType); + curve = Pipe.Create(Doc, pipingSystemType.Id, curveType.Id, level.Id, start, end); + curve.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(link.diameter); + break; + case Domain.DomainCableTrayConduit: + if (profile == ConnectorProfileType.Rectangular) + { + curveType = GetDefaultMEPCurveType(Doc, typeof(CableTrayType), profile); + if (curveType == null) + { + goto default; + } + + curve = CableTray.Create(Doc, curveType.Id, start, end, level.Id); + curve.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(link.width); + curve.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(link.height); + } + else + { + curveType = GetDefaultMEPCurveType(Doc, typeof(ConduitType), profile); + if (curveType == null) + { + goto default; + } + + curve = Conduit.Create(Doc, curveType.Id, start, end, level.Id); + curve.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).Set(link.diameter); + } + break; + default: + return curve; + } + return curve; + } + + private static MEPCurveType GetDefaultMEPCurveType(Document doc, Type type, ConnectorProfileType shape) + { + return new FilteredElementCollector(doc) + .WhereElementIsElementType() + .OfClass(type) + .FirstOrDefault(t => t is MEPCurveType type && type.Shape == shape) as MEPCurveType; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertOpening.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertOpening.cs new file mode 100644 index 0000000000..7d8abe3fcc --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertOpening.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject OpeningToNative(BuiltElements.Opening speckleOpening) + { + var baseCurves = CurveToNative(speckleOpening.outline); + + var docObj = GetExistingElementByApplicationId(speckleOpening.applicationId); + var appObj = new ApplicationObject(speckleOpening.id, speckleOpening.speckle_type) + { + applicationId = speckleOpening.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + Opening revitOpening = null; + + switch (speckleOpening) + { + case RevitWallOpening rwo: + { + // Prevent host element overriding as this will propagate upwards to other hosted elements in a wall :) + string elementId = null; + var hostElement = CurrentHostElement; + if (!(hostElement is Wall)) + { + // Try with the opening wall if it exists + if (rwo.host == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Host wall was null"); + return appObj; + } + Element existingElement; + try + { + existingElement = GetExistingElementByApplicationId(rwo.host.applicationId); + } + catch (Exception e) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Could not find the host wall: {e.Message}" + ); + return appObj; + } + + if (!(existingElement is Wall wall)) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"The host is not a wall"); + return appObj; + } + + hostElement = wall; + } + + var poly = rwo.outline as Polyline; + if ( + poly == null + || !((poly.GetPoints().Count == 5 && poly.closed) || (poly.GetPoints().Count == 4 && !poly.closed)) + ) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Curve outline for wall opening must be a rectangle-shaped polyline" + ); + return appObj; + } + + var points = poly.GetPoints().Select(PointToNative).ToList(); + revitOpening = Doc.Create.NewOpening((Wall)hostElement, points[0], points[2]); + break; + } + + case RevitVerticalOpening rvo: + { + if (CurrentHostElement == null) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Hosted vertical openings require a host family" + ); + return appObj; + } + revitOpening = Doc.Create.NewOpening(CurrentHostElement, baseCurves, true); + break; + } + + case RevitShaft rs: + { + var bottomLevel = ConvertLevelToRevit(rs.bottomLevel, out ApplicationObject.State bottomState); + var topLevel = ConvertLevelToRevit(rs.topLevel, out ApplicationObject.State topState); + revitOpening = Doc.Create.NewOpening(bottomLevel, topLevel, baseCurves); + TrySetParam(revitOpening, BuiltInParameter.WALL_USER_HEIGHT_PARAM, rs.height, rs.units); + + break; + } + + default: + if (CurrentHostElement as Wall != null) + { + var speckleOpeningOutline = speckleOpening.outline as Polyline; + if (speckleOpeningOutline == null) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "Outline must be a rectangle-shaped polyline" + ); + return appObj; + } + var points = speckleOpeningOutline.GetPoints().Select(PointToNative).ToList(); + revitOpening = Doc.Create.NewOpening(CurrentHostElement as Wall, points[0], points[2]); + } + else + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Opening type not supported"); + return appObj; + } + break; + } + + if (speckleOpening is RevitOpening ro) + { + SetInstanceParameters(revitOpening, ro); + } + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: revitOpening.UniqueId, + convertedItem: revitOpening + ); + return appObj; + } + + public BuiltElements.Opening OpeningToSpeckle(DB.Opening revitOpening) + { + RevitOpening speckleOpening; + if (revitOpening.IsRectBoundary) + { + speckleOpening = new RevitWallOpening(); + + var poly = new Polyline(); + poly.value = new List(); + + //2 points: bottom left and top right + var btmLeft = PointToSpeckle(revitOpening.BoundaryRect[0], revitOpening.Document); + var topRight = PointToSpeckle(revitOpening.BoundaryRect[1], revitOpening.Document); + poly.value.AddRange(btmLeft.ToList()); + poly.value.AddRange(new Point(btmLeft.x, btmLeft.y, topRight.z, ModelUnits).ToList()); + poly.value.AddRange(topRight.ToList()); + poly.value.AddRange(new Point(topRight.x, topRight.y, btmLeft.z, ModelUnits).ToList()); + + poly.value.AddRange(btmLeft.ToList()); + // setting closed to true because we added the first point again. + poly.closed = true; + poly.units = ModelUnits; + speckleOpening.outline = poly; + } + else + { + if (revitOpening.Host != null) + { + //we can ignore vertical openings because they will be created when we try re-create voids in the roof / ceiling / floor outline + return null; + } + else + { + var shaftOpening = new RevitShaft(); + speckleOpening = shaftOpening; + if (revitOpening.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE) != null) + { + shaftOpening.topLevel = ConvertAndCacheLevel(revitOpening, BuiltInParameter.WALL_HEIGHT_TYPE); + shaftOpening.bottomLevel = ConvertAndCacheLevel(revitOpening, BuiltInParameter.WALL_BASE_CONSTRAINT); + shaftOpening.height = GetParamValue(revitOpening, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + } + } + + var poly = new Polycurve(ModelUnits); + poly.segments = new List(); + foreach (DB.Curve curve in revitOpening.BoundaryCurves) + { + if (curve != null) + { + poly.segments.Add(CurveToSpeckle(curve, revitOpening.Document)); + } + } + + speckleOpening.outline = poly; + } + + speckleOpening["type"] = revitOpening.Name; + + GetAllRevitParamsAndIds( + speckleOpening, + revitOpening, + new List { "WALL_BASE_CONSTRAINT", "WALL_HEIGHT_TYPE", "WALL_USER_HEIGHT_PARAM" } + ); + return speckleOpening; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPanel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPanel.cs new file mode 100644 index 0000000000..b6450f9433 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPanel.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject PanelToNative(RevitCurtainWallPanel specklePanel) + { + return new ApplicationObject(specklePanel.id, specklePanel.speckle_type) + { + Status = ApplicationObject.State.Skipped, + Log = new List() { "Revit does not support receive standalone curtain panels " } + }; + } + + public RevitCurtainWallPanel PanelToSpeckle(DB.Panel revitPanel) + { + RevitCurtainWallPanel panel = new(); + return (RevitCurtainWallPanel)RevitElementToSpeckle(revitPanel, out _, panel); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPipe.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPipe.cs new file mode 100644 index 0000000000..9775e79b29 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPipe.cs @@ -0,0 +1,287 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Plumbing; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using Curve = Objects.Geometry.Curve; +using DB = Autodesk.Revit.DB; +using Line = Objects.Geometry.Line; +using Polyline = Objects.Geometry.Polyline; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject PipeToNative(BuiltElements.Pipe specklePipe) + { + var speckleRevitPipe = specklePipe as RevitPipe; + + // check to see if pipe already exists in the doc + Element docObj = GetExistingElementByApplicationId(specklePipe.applicationId); + var appObj = new ApplicationObject(specklePipe.id, specklePipe.speckle_type) + { + applicationId = specklePipe.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + // get system info + MEPCurveType pipeType = GetElementType(specklePipe, appObj, out bool _); + if (pipeType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + List systemTypes = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(DB.Plumbing.PipingSystemType)) + .ToElements() + .Cast() + .ToList(); + var systemFamily = speckleRevitPipe?.systemType ?? ""; + ElementType system = + systemTypes.FirstOrDefault(x => x.Name == speckleRevitPipe?.systemName) + ?? systemTypes.FirstOrDefault(x => x.Name == systemFamily); + if (system == null) + { + system = systemTypes.FirstOrDefault(); + appObj.Update(logItem: $"Pipe type {systemFamily} not found; replaced with {system.Name}"); + } + + Element pipe = null; + var levelState = ApplicationObject.State.Unknown; + switch (specklePipe.baseCurve) + { + case Line line: + DB.Line baseLine = LineToNative(line); + DB.Level level = ConvertLevelToRevit( + speckleRevitPipe != null ? speckleRevitPipe.level : LevelFromCurve(baseLine), + out levelState + ); + var linePipe = DB.Plumbing.Pipe.Create( + Doc, + system.Id, + pipeType.Id, + level.Id, + baseLine.GetEndPoint(0), + baseLine.GetEndPoint(1) + ); + if (docObj != null) + { + var lineSystem = linePipe.MEPSystem.Id; + linePipe = (DB.Plumbing.Pipe)docObj; + linePipe.SetSystemType(lineSystem); + ((LocationCurve)linePipe.Location).Curve = baseLine; + } + + pipe = linePipe; + break; + case Polyline _: + case Curve _: + var speckleRevitFlexPipe = specklePipe as RevitFlexPipe; + DB.Plumbing.FlexPipeType flexPipeType = null; + if (speckleRevitFlexPipe != null) + { + flexPipeType = GetElementType(speckleRevitFlexPipe, appObj, out bool _); + } + else + { + flexPipeType = GetElementType(specklePipe, appObj, out bool _); + } + + if (flexPipeType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + // get points + Polyline basePoly = specklePipe.baseCurve as Polyline; + if (specklePipe.baseCurve is Curve curve) + { + basePoly = curve.displayValue; + DB.Curve baseCurve = CurveToNative(curve); + XYZ start = baseCurve.GetEndPoint(0); + XYZ end = baseCurve.GetEndPoint(1); + } + + if (basePoly == null) + { + break; + } + + var polyPoints = basePoly.GetPoints().Select(o => PointToNative(o)).ToList(); + + // get tangents if they exist + XYZ startTangent = (speckleRevitFlexPipe != null) ? VectorToNative(speckleRevitFlexPipe.startTangent) : null; + XYZ endTangent = (speckleRevitFlexPipe != null) ? VectorToNative(speckleRevitFlexPipe.endTangent) : null; + + // get level + DB.Level flexPolyLevel = ConvertLevelToRevit( + speckleRevitFlexPipe != null ? speckleRevitFlexPipe.level : LevelFromPoint(polyPoints.First()), + out levelState + ); + + FlexPipe flexPolyPipe = + (startTangent != null && endTangent != null) + ? DB.Plumbing.FlexPipe.Create( + Doc, + system.Id, + flexPipeType.Id, + flexPolyLevel.Id, + startTangent, + endTangent, + polyPoints + ) + : DB.Plumbing.FlexPipe.Create(Doc, system.Id, flexPipeType.Id, flexPolyLevel.Id, polyPoints); + + // deleting instead of updating for now! + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + pipe = flexPolyPipe; + break; + default: + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Curve of type {specklePipe.baseCurve.GetType()} cannot be used to create a Revit Pipe" + ); + return appObj; + } + + if (speckleRevitPipe != null) + { + SetInstanceParameters(pipe, speckleRevitPipe); + CreateSystemConnections(speckleRevitPipe.Connectors, pipe, receivedObjectsCache); + } + + TrySetParam(pipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM, specklePipe.diameter, specklePipe.units); + + appObj.Update(status: ApplicationObject.State.Created, createdId: pipe.UniqueId, convertedItem: pipe); + return appObj; + } + + public BuiltElements.Pipe PipeToSpeckle(DB.Plumbing.Pipe revitPipe) + { + // geometry + var baseGeometry = LocationToSpeckle(revitPipe); + if (!(baseGeometry is Line baseLine)) + { + throw new Speckle.Core.Logging.SpeckleException("Only line based Pipes are currently supported."); + } + + // speckle pipe + var specklePipe = new RevitPipe + { + baseCurve = baseLine, + family = revitPipe.PipeType.FamilyName, + type = revitPipe.PipeType.Name, + systemName = revitPipe.MEPSystem.Name, + systemType = GetParamValue(revitPipe, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM), + diameter = GetParamValue(revitPipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM), + length = GetParamValue(revitPipe, BuiltInParameter.CURVE_ELEM_LENGTH), + level = ConvertAndCacheLevel(revitPipe, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitPipe) + }; + + var material = ConverterRevit.GetMEPSystemMaterial(revitPipe); + if (material != null) + { + foreach (var mesh in specklePipe.displayValue) + { + mesh["renderMaterial"] = material; + } + } + + GetAllRevitParamsAndIds( + specklePipe, + revitPipe, + new List + { + "RBS_PIPING_SYSTEM_TYPE_PARAM", + "RBS_SYSTEM_CLASSIFICATION_PARAM", + "RBS_SYSTEM_NAME_PARAM", + "RBS_PIPE_DIAMETER_PARAM", + "CURVE_ELEM_LENGTH", + "RBS_START_LEVEL_PARAM", + "RBS_CURVE_HOR_OFFSET_PARAM", + "RBS_CURVE_VERT_OFFSET_PARAM", + "RBS_PIPE_BOTTOM_ELEVATION", + "RBS_PIPE_TOP_ELEVATION" + } + ); + + foreach (var connector in revitPipe.GetConnectorSet()) + { + specklePipe.Connectors.Add(ConnectorToSpeckle(connector)); + } + + return specklePipe; + } + + public BuiltElements.Pipe PipeToSpeckle(DB.Plumbing.FlexPipe revitPipe) + { + // create polyline from revitpipe points + var polyline = new Polyline(); + polyline.value = PointsToFlatList(revitPipe.Points.Select(o => PointToSpeckle(o, revitPipe.Document))); + polyline.units = ModelUnits; + polyline.closed = false; + + // speckle pipe + var specklePipe = new RevitFlexPipe + { + baseCurve = polyline, + family = revitPipe.FlexPipeType.FamilyName, + type = revitPipe.FlexPipeType.Name, + systemName = revitPipe.MEPSystem.Name, + systemType = GetParamValue(revitPipe, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM), + diameter = GetParamValue(revitPipe, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM), + length = GetParamValue(revitPipe, BuiltInParameter.CURVE_ELEM_LENGTH), + startTangent = VectorToSpeckle(revitPipe.StartTangent, revitPipe.Document), + endTangent = VectorToSpeckle(revitPipe.EndTangent, revitPipe.Document), + level = ConvertAndCacheLevel(revitPipe, BuiltInParameter.RBS_START_LEVEL_PARAM), + displayValue = GetElementDisplayValue(revitPipe) + }; + + var material = ConverterRevit.GetMEPSystemMaterial(revitPipe); + + if (material != null) + { + foreach (var mesh in specklePipe.displayValue) + { + mesh["renderMaterial"] = material; + } + } + + GetAllRevitParamsAndIds( + specklePipe, + revitPipe, + new List + { + "RBS_SYSTEM_CLASSIFICATION_PARAM", + "RBS_PIPING_SYSTEM_TYPE_PARAM", + "RBS_SYSTEM_NAME_PARAM", + "RBS_PIPE_DIAMETER_PARAM", + "CURVE_ELEM_LENGTH", + "RBS_START_LEVEL_PARAM", + } + ); + + foreach (var connector in revitPipe.GetConnectorSet()) + { + specklePipe.Connectors.Add(ConnectorToSpeckle(connector)); + } + + return specklePipe; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPolygonElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPolygonElement.cs new file mode 100644 index 0000000000..890662766e --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertPolygonElement.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Objects.GIS; +using Speckle.Core.Models; +using Speckle.Core.Models.GraphTraversal; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject PolygonElementToNative(PolygonElement polygonElement) + { + var speckleDirectShape = new Objects.BuiltElements.Revit.DirectShape() + { + applicationId = polygonElement.applicationId ??= Guid.NewGuid().ToString(), + baseGeometries = new List(), + parameters = new Base(), + name = "", + category = RevitCategory.GenericModel + }; + + var traversal = new GraphTraversal(DefaultTraversal.DefaultRule); + var meshes = traversal.Traverse(polygonElement).Select(tc => tc.current).Where(b => b is Mesh); + + speckleDirectShape.baseGeometries.AddRange(meshes); + + foreach (var kvp in polygonElement.attributes.GetMembers()) + { + speckleDirectShape.parameters[kvp.Key] = new Objects.BuiltElements.Revit.Parameter() + { + name = kvp.Key, + value = kvp.Value + }; + } + + return DirectShapeToNative(speckleDirectShape, ToNativeMeshSettingEnum.Default); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProfileWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProfileWall.cs new file mode 100644 index 0000000000..e39786b68e --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProfileWall.cs @@ -0,0 +1,89 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject ProfileWallToNative(RevitProfileWall speckleRevitWall) + { + var revitWall = GetExistingElementByApplicationId(speckleRevitWall.applicationId) as DB.Wall; + var appObj = new ApplicationObject(speckleRevitWall.id, speckleRevitWall.speckle_type) + { + applicationId = speckleRevitWall.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitWall, appObj)) + { + return appObj; + } + + if (speckleRevitWall.profile == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Does not have a profile."); + return appObj; + } + + var wallType = GetElementType(speckleRevitWall, appObj, out bool _); + if (wallType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + // Level level = null; + var structural = speckleRevitWall.structural; + var profile = new List(); + var minZ = double.MaxValue; + for (var i = 0; i < CurveToNative(speckleRevitWall.profile).Size; i++) + { + var curve = CurveToNative(speckleRevitWall.profile).get_Item(i); + profile.Add(curve); + if (curve.GetEndPoint(0).Z < minZ) + { + minZ = curve.GetEndPoint(0).Z; + } + + if (curve.GetEndPoint(1).Z < minZ) + { + minZ = curve.GetEndPoint(1).Z; + } + } + + //cannot update + if (revitWall != null) + { + Doc.Delete(revitWall.Id); + } + + revitWall = DB.Wall.Create(Doc, profile, structural); + + if (revitWall == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Wall creation returned null"); + return appObj; + } + + var level = ConvertLevelToRevit(speckleRevitWall.level, out ApplicationObject.State levelState); + TrySetParam(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT, level); + + var offset = minZ - level.Elevation; + TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, offset); + + if (revitWall.WallType.Name != wallType.Name) + { + revitWall.ChangeTypeId(wallType.Id); + } + + SetInstanceParameters(revitWall, speckleRevitWall); + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitWall.UniqueId, convertedItem: revitWall); + //appObj = SetHostedElements(speckleRevitWall, revitWall, appObj); + return appObj; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProjectInfo.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProjectInfo.cs new file mode 100644 index 0000000000..e18c049f7a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertProjectInfo.cs @@ -0,0 +1,33 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Speckle.Core.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB; +using ProjectInfo = Objects.BuiltElements.Revit.ProjectInfo; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private ProjectInfo ProjectInfoToSpeckle(DB.ProjectInfo revitInfo) + { + var speckleInfo = new ProjectInfo + { + address = revitInfo.Address, + author = revitInfo.Author, + buildingName = revitInfo.BuildingName, + clientName = revitInfo.ClientName, + issueDate = revitInfo.IssueDate, + name = revitInfo.Name, + number = revitInfo.Number, + organizationDescription = revitInfo.OrganizationDescription, + organizationName = revitInfo.OrganizationName, + status = revitInfo.Status + }; + Report.Log($"Converted ProjectInfo"); + return speckleInfo; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRailing.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRailing.cs new file mode 100644 index 0000000000..4033454997 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRailing.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Architecture; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject RailingToNative(BuiltElements.Revit.RevitRailing speckleRailing) + { + var revitRailing = GetExistingElementByApplicationId(speckleRailing.applicationId) as Railing; + var appObj = new ApplicationObject(speckleRailing.id, speckleRailing.speckle_type) + { + applicationId = speckleRailing.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitRailing, appObj)) + { + return appObj; + } + + if (speckleRailing.path == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Path was null"); + return appObj; + } + + var railingType = GetElementType(speckleRailing, appObj, out bool isExactMatch); + if (railingType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + Level level = ConvertLevelToRevit(speckleRailing.level, out ApplicationObject.State levelState); + if (level == null) //we currently don't support railings hosted on stairs, and these have null level + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Level was null"); + return appObj; + } + + var baseCurve = CurveArrayToCurveLoop(CurveToNative(speckleRailing.path)); + + //if it's a new element, we don't need to update certain properties + bool isUpdate = true; + if (revitRailing == null) + { + isUpdate = false; + revitRailing = Railing.Create(Doc, baseCurve, railingType.Id, level.Id); + } + if (revitRailing == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); + return appObj; + } + + if (isExactMatch && revitRailing.GetTypeId() != railingType.Id) + { + revitRailing.ChangeTypeId(railingType.Id); + } + + if (speckleRailing.topRail != null) + { + var topRailType = GetElementType(speckleRailing.topRail, appObj, out bool isTopRailExactMatch); + + if (GetParamValue(railingType, BuiltInParameter.RAILING_SYSTEM_HAS_TOP_RAIL) == 0) + { + TrySetParam(railingType, BuiltInParameter.RAILING_SYSTEM_HAS_TOP_RAIL, 1); + } + + if (topRailType != null && isTopRailExactMatch) + { + railingType.TopRailType = topRailType.Id; + } + } + + if (isUpdate) + { + revitRailing.SetPath(baseCurve); + TrySetParam(revitRailing, BuiltInParameter.WALL_BASE_CONSTRAINT, level); + } + + if (speckleRailing.flipped != revitRailing.Flipped) + { + revitRailing.Flip(); + } + + SetInstanceParameters(revitRailing, speckleRailing); + + if (speckleRailing.topRail != null) + { + // This call to regenerate is to reflect the generation + // of the TopRail element associated with the Railing element + Doc.Regenerate(); + + var revitTopRail = Doc.GetElement(revitRailing.TopRail); + + SetInstanceParameters(revitTopRail, speckleRailing.topRail); + } + + var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: status, createdId: revitRailing.UniqueId, convertedItem: revitRailing); + Doc.Regenerate(); + return appObj; + } + + //TODO: host railings, where possible + private RevitRailing RailingToSpeckle(Railing revitRailing) + { + var railingType = revitRailing.Document.GetElement(revitRailing.GetTypeId()) as RailingType; + var speckleRailing = new RevitRailing(); + //speckleRailing.family = railingType.FamilyName; + speckleRailing.type = railingType.Name; + speckleRailing.level = ConvertAndCacheLevel(revitRailing, BuiltInParameter.STAIRS_RAILING_BASE_LEVEL_PARAM); + speckleRailing.path = CurveListToSpeckle(revitRailing.GetPath(), revitRailing.Document); + + GetAllRevitParamsAndIds(speckleRailing, revitRailing, new List { "STAIRS_RAILING_BASE_LEVEL_PARAM" }); + + speckleRailing.displayValue = GetElementDisplayValue(revitRailing); + + if (revitRailing.TopRail != ElementId.InvalidElementId) + { + if (ContextObjects.ContainsKey(revitRailing.UniqueId)) + { + ContextObjects.Remove(revitRailing.UniqueId); + } + + var revitTopRail = revitRailing.Document.GetElement(revitRailing.TopRail) as TopRail; + + if (ContextObjects.ContainsKey(revitTopRail.UniqueId)) + { + ContextObjects.Remove(revitTopRail.UniqueId); + } + + if (CanConvertToSpeckle(revitTopRail)) + { + speckleRailing.topRail = TopRailToSpeckle(revitTopRail); + + //ensure top rail mesh is visible in viewer + //currently only the top level displayValue is visualized (or anything under 'elements') + //if this leads to duplicated meshes in some cases, we might need to remove the display mesh form the TopRail element + speckleRailing.displayValue.AddRange(speckleRailing.topRail.displayValue); + ConvertedObjects.Add(speckleRailing.topRail.applicationId); + } + } + return speckleRailing; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRebar.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRebar.cs new file mode 100644 index 0000000000..976420e928 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRebar.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Autodesk.Revit.Exceptions; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using Speckle.Newtonsoft.Json.Linq; +using DB = Autodesk.Revit.DB; +using Vector = Objects.Geometry.Vector; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + // rebar + public ApplicationObject RebarToNative(RevitRebarGroup speckleRebar) + { + var docObj = GetExistingElementByApplicationId(speckleRebar.applicationId); + var appObj = new ApplicationObject(speckleRebar.id, speckleRebar.speckle_type) + { + applicationId = speckleRebar.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + // return failed if rebar shape is null or has no curves + var barShape = speckleRebar.shape as RevitRebarShape; + if (barShape == null || !barShape.curves.Any()) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Rebar shape is null or has no curves."); + return appObj; + } + + // return failed if no valid host + if (CurrentHostElement is null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Host element was null."); + return appObj; + } + + // get rebar type and style + var barType = GetElementType(speckleRebar, appObj, out bool isExactMatch); + if (barType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (speckleRebar.shape.rebarType == RebarType.Unknown) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: ("Unknown bar type (stirrup or standard).")); + return appObj; + } + + RebarStyle barStyle = + speckleRebar.shape.rebarType == RebarType.Standard ? RebarStyle.Standard : RebarStyle.StirrupTie; + + // get start and end hooks and orientations + var speckleStartHook = speckleRebar.startHook as RevitRebarHook; + RebarHookType startHook = null; + RebarHookOrientation startHookOrientation = RebarHookOrientation.Right; + if (speckleStartHook != null) + { + startHook = RebarHookToNative(speckleStartHook); + Enum.TryParse(speckleStartHook.orientation, out startHookOrientation); + } + + var speckleEndHook = speckleRebar.endHook as RevitRebarHook; + RebarHookType endHook = null; + RebarHookOrientation endHookOrientation = RebarHookOrientation.Right; + if (speckleEndHook != null) + { + endHook = RebarHookToNative(speckleEndHook); + Enum.TryParse(speckleEndHook.orientation, out endHookOrientation); + } + + // get the shape curves + List curves = barShape.curves.SelectMany(o => CurveToNative(o).Cast()).ToList(); + if (curves is null || !curves.Any()) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not convert any shape curves"); + return appObj; + } + + // get the rebar plane norm from the curves + XYZ normal = XYZ.BasisZ; + if (speckleRebar.normal is not null) + { + normal = VectorToNative(speckleRebar.normal); + } + + // create the rebar + DB.Structure.Rebar rebar = null; + try + { + rebar = DB.Structure.Rebar.CreateFromCurves( + Doc, + barStyle, + barType, + startHook, + endHook, + CurrentHostElement, + normal, + curves, + startHookOrientation, + endHookOrientation, + true, + true + ); + } + catch (Exception e) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: e.Message); + return appObj; + } + + SetInstanceParameters(rebar, speckleRebar); + + // set additional params + if (speckleRebar.barPositions > 0) + { + rebar.NumberOfBarPositions = speckleRebar.barPositions; + } + + // deleting instead of updating for now! + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + appObj.Update(status: ApplicationObject.State.Created, createdId: rebar.UniqueId, convertedItem: rebar); + + return appObj; + } + + private RevitRebarGroup RebarToSpeckle(DB.Structure.Rebar revitRebar) + { + // skip freeform rebar for now: not supported by RevitRebarGroup class + // this is because freeform rebar with bent workshop has multiple shapes + if (revitRebar.GetAllRebarShapeIds().Count > 1) + { + return null; + } + + // get type + var type = revitRebar.Document.GetElement(revitRebar.GetTypeId()) as ElementType; + + // get the rebar shape + // `GetShapeId()` will throw if it is a freeform rebar with a bent workshop, + // but this case should already be handled by the `GetAllRebarShapeIds().Count` test above + var revitShape = revitRebar.Document.GetElement(revitRebar.GetShapeId()) as DB.Structure.RebarShape; + RevitRebarShape speckleShape = new(); + if (revitShape != null) + { + speckleShape = RebarShapeToSpeckle(revitShape); + } + +#if REVIT2020 || REVIT2021 + speckleShape.barDiameter = revitRebar.GetBendData().BarDiameter; +#else + speckleShape.barDiameter = revitRebar.GetBendData().BarModelDiameter; +#endif + + // get the rebar hooks + DB.ElementId revitStartHookId = revitRebar.GetHookTypeId(0); + RevitRebarHook speckleStartHook = null; + double hookBendRadius = revitRebar.GetBendData().HookBendRadius; + if (revitStartHookId != ElementId.InvalidElementId) + { + var revitStartHook = revitRebar.Document.GetElement(revitStartHookId) as RebarHookType; + speckleStartHook = RebarHookToSpeckle( + revitStartHook, + revitRebar.GetHookOrientation(0).ToString(), + hookBendRadius + ); + } + + DB.ElementId revitEndHookId = revitRebar.GetHookTypeId(1); + RevitRebarHook speckleEndHook = null; + if (revitEndHookId != ElementId.InvalidElementId) + { + var revitEndHook = revitRebar.Document.GetElement(revitEndHookId) as RebarHookType; + speckleEndHook = RebarHookToSpeckle(revitEndHook, revitRebar.GetHookOrientation(1).ToString(), hookBendRadius); + } + + // get the layout rule - this determines exceptions that may be thrown by accessing invalid props + bool isSingleLayout = revitRebar.LayoutRule == RebarLayoutRule.Single; + + // get centerline curves for display value + RebarShapeDrivenAccessor accessor = null; + if (revitRebar.IsRebarShapeDriven()) + { + accessor = revitRebar.GetShapeDrivenAccessor(); + } + + // .GetCenterlineCurves() always returns the bar in the first position (even if it is excluded) for shape driven rebar groups + IList firstPositionCurves = revitRebar.GetCenterlineCurves( + true, + false, + false, + MultiplanarOption.IncludeAllMultiplanarCurves, + 0 + ); + + List centerlines = new(); + for (int i = 0; i < revitRebar.NumberOfBarPositions; i++) + { + // skip end bars that are excluded + if (!isSingleLayout) + { + if ( + !revitRebar.IncludeFirstBar && i == 0 + || !revitRebar.IncludeLastBar && i == revitRebar.NumberOfBarPositions - 1 + ) + { + continue; + } + } + + // for non-shape-driven rebar, compute the centerline at each position + if (accessor is null) + { + IList revitCurves = revitRebar.GetCenterlineCurves( + true, + false, + false, + MultiplanarOption.IncludeAllMultiplanarCurves, + i + ); + centerlines.AddRange(revitCurves.Select(o => CurveToSpeckle(o, revitRebar.Document)).ToList()); + } + // for shape-driven rebar, get the transformed first position curves at this position + else + { + var transform = accessor.GetBarPositionTransform(i); + centerlines.AddRange( + firstPositionCurves.Select(o => CurveToSpeckle(o.CreateTransformed(transform), revitRebar.Document)).ToList() + ); + } + } + + // get plane normal of rebar group + // the normal prop was deprecated in revit 2018, and the accessor normal is suggested as a replacement + // unclear how non-shape-driven rebar set normals are retrieved or computed. + Vector normal = null; + if (accessor != null) + { + normal = VectorToSpeckle(accessor.Normal, revitRebar.Document); + } + + // create speckle rebar + RevitRebarGroup speckleRebar = + new() + { + shape = speckleShape, + number = revitRebar.Quantity, + startHook = speckleStartHook, + endHook = speckleEndHook, + hasFirstBar = isSingleLayout ? true : revitRebar.IncludeFirstBar, + hasLastBar = isSingleLayout ? true : revitRebar.IncludeLastBar, + volume = revitRebar.Volume, + family = type?.FamilyName, + type = type?.Name, + normal = normal, + barPositions = revitRebar.NumberOfBarPositions, + displayValue = centerlines + }; + + // skip display value as meshes for now + // GetElementDisplayValue(revitRebar, SolidDisplayValueOptions); + GetAllRevitParamsAndIds(speckleRebar, revitRebar); + + return speckleRebar; + } + + // rebar shape + private RevitRebarShape RebarShapeToSpeckle(DB.Structure.RebarShape revitRebarShape) + { + // get the type of the shape + RebarType rebarType = RebarType.Unknown; + switch (revitRebarShape.RebarStyle) + { + case RebarStyle.Standard: + rebarType = RebarType.Standard; + break; + case RebarStyle.StirrupTie: + rebarType = RebarType.StirrupPolygonal; + break; + } + + // get the curves representing the default values of the shape + List curves = revitRebarShape + .GetCurvesForBrowser() + .Select(o => CurveToSpeckle(o, revitRebarShape.Document)) + .ToList(); + + RevitRebarShape speckleRebarShape = + new() + { + name = revitRebarShape.Name, + curves = curves, + rebarType = rebarType + }; + + GetAllRevitParamsAndIds(speckleRebarShape, revitRebarShape); + + return speckleRebarShape; + } + + // rebar hook + private RebarHookType RebarHookToNative(RevitRebarHook speckleRebarHook) + { + double multiplier = + speckleRebarHook.multiplier != null && speckleRebarHook.multiplier > 0 ? speckleRebarHook.multiplier : 10; // default to 10 if invalid multiplier + var revitRebarHook = RebarHookType.Create(Doc, speckleRebarHook.angle, multiplier); + + SetInstanceParameters(revitRebarHook, speckleRebarHook); + + return revitRebarHook; + } + + private RevitRebarHook RebarHookToSpeckle(RebarHookType revitRebarHook, string orientation, double radius) + { + RevitRebarHook speckleRebarHook = + new() + { + multiplier = revitRebarHook.StraightLineMultiplier, + angle = revitRebarHook.HookAngle, + orientation = orientation, + radius = radius + }; + + GetAllRevitParamsAndIds(speckleRebarHook, revitRebarHook); + + return speckleRebarHook; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRevitElement.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRevitElement.cs new file mode 100644 index 0000000000..dcb3ae86a1 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRevitElement.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; + +using Autodesk.Revit.DB; + +using Speckle.Core.Models; + +using Objects.BuiltElements.Revit; +using RevitElementType = Objects.BuiltElements.Revit.RevitElementType; +using System.Linq; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public RevitElement RevitElementToSpeckle( + Element revitElement, + out List notes, + RevitElement speckleElement = null + ) + { + notes = new List(); + var symbol = revitElement.Document.GetElement(revitElement.GetTypeId()) as FamilySymbol; + + speckleElement ??= new RevitElement(); + if (symbol != null) + { + speckleElement.family = symbol.FamilyName; + speckleElement.type = symbol.Name; + } + else + { + speckleElement.type = revitElement.Name; + } + + var baseGeometry = LocationToSpeckle(revitElement); + if (baseGeometry is Geometry.Point point) + { + speckleElement["basePoint"] = point; + } + else if (baseGeometry is Geometry.Line line) + { + speckleElement["baseLine"] = line; + } + + speckleElement.category = revitElement.Category.Name; + + GetHostedElements(speckleElement, revitElement, out notes); + + var displayValue = GetElementDisplayValue(revitElement); + + if (!displayValue.Any()) + { + notes.Add( + "Element does not have visible geometry. It will be sent to Speckle but won't be visible in the viewer." + ); + } + else + { + speckleElement.displayValue = displayValue; + } + + GetAllRevitParamsAndIds(speckleElement, revitElement); + + return speckleElement; + } + + public RevitElementType ElementTypeToSpeckle(ElementType revitType) + { + var type = revitType.Name; + var family = revitType.FamilyName; + var category = revitType.Category.Name; + RevitElementType speckleType = null; + + switch (revitType) + { + case FamilySymbol o: + var symbolType = new RevitSymbolElementType() + { + type = type, + family = family, + category = category + }; + symbolType.placementType = o.Family?.FamilyPlacementType.ToString(); + speckleType = symbolType; + break; + case MEPCurveType o: + var mepType = new RevitMepElementType() + { + type = type, + family = family, + category = category + }; + mepType.shape = o.Shape.ToString(); + speckleType = mepType; + break; + default: + speckleType = new RevitElementType() + { + type = type, + family = family, + category = category + }; + break; + } + + GetAllRevitParamsAndIds(speckleType, revitType); + + return speckleType; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoof.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoof.cs new file mode 100644 index 0000000000..0ccfd8b411 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoof.cs @@ -0,0 +1,532 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Architecture; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit.RevitRoof; +using Objects.Geometry; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using FamilyInstance = Objects.BuiltElements.Revit.FamilyInstance; +using Line = Objects.Geometry.Line; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject RoofToNative(Roof speckleRoof) + { + Element docObj = GetExistingElementByApplicationId((speckleRoof).applicationId); + var appObj = new ApplicationObject(speckleRoof.id, speckleRoof.speckle_type) + { + applicationId = speckleRoof.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + // outline is required for footprint roofs + // referenceLine is required for for Extrusion roofs + CurveArray roofCurve = null; + if (speckleRoof is RevitExtrusionRoof extrusionRoof) + { + if (extrusionRoof.referenceLine is null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Extrusion roof profile was null"); + return appObj; + } + roofCurve = CurveToNative(extrusionRoof.referenceLine); + } + else + { + if (speckleRoof.outline is null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Roof outline was null"); + return appObj; + } + roofCurve = CurveToNative(speckleRoof.outline); + } + + // retrieve the level + var levelState = ApplicationObject.State.Unknown; + double baseOffset = 0.0; + DB.Level level = speckleRoof.level is not null + ? ConvertLevelToRevit(speckleRoof.level, out levelState) + : roofCurve is not null + ? ConvertLevelToRevit(roofCurve.get_Item(0), out levelState, out baseOffset) + : null; + + var speckleRevitRoof = speckleRoof as RevitRoof; + + var roofType = GetElementType(speckleRoof, appObj, out bool _); + if (roofType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + DB.RoofBase revitRoof = null; + switch (speckleRoof) + { + case RevitExtrusionRoof speckleExtrusionRoof: + { + // get the norm + var referenceLine = LineToNative(speckleExtrusionRoof.referenceLine); + var norm = GetPerpendicular(referenceLine.GetEndPoint(0) - referenceLine.GetEndPoint(1)).Negate(); + ReferencePlane plane = Doc.Create.NewReferencePlane( + referenceLine.GetEndPoint(0), + referenceLine.GetEndPoint(1), + norm, + Doc.ActiveView + ); + + //create floor without a type with the profile + var start = ScaleToNative(speckleExtrusionRoof.start, speckleExtrusionRoof.units); + var end = ScaleToNative(speckleExtrusionRoof.end, speckleExtrusionRoof.units); + revitRoof = Doc.Create.NewExtrusionRoof(roofCurve, plane, level, roofType, start, end); + + // sometimes Revit flips the roof so the start offset is the end and vice versa. + // In that case, delete the created roof, flip the referencePlane and recreate it. + var actualStart = GetParamValue(revitRoof, BuiltInParameter.EXTRUSION_START_PARAM); + if (actualStart - speckleExtrusionRoof.end < TOLERANCE) + { + Doc.Delete(revitRoof.Id); + plane.Flip(); + revitRoof = Doc.Create.NewExtrusionRoof(roofCurve, plane, level, roofType, start, end); + } + break; + } + case RevitFootprintRoof speckleFootprintRoof: + { + ModelCurveArray curveArray = new(); + var revitFootprintRoof = Doc.Create.NewFootPrintRoof(roofCurve, level, roofType, out curveArray); + + // if the roof is a curtain roof then set the mullions at the borders + var nestedElements = speckleFootprintRoof.elements; + if (revitFootprintRoof.CurtainGrids != null && nestedElements is not null && nestedElements.Count != 0) + { + // TODO: Create a new type instead of overriding the type. This could affect other elements + var param = roofType.get_Parameter(BuiltInParameter.AUTO_MULLION_BORDER1_GRID1); + var type = Doc.GetElement(param.AsElementId()); + if (type == null) + { + // assuming first mullion is the desired mullion for the whole roof... + var mullionType = GetElementType( + nestedElements.First(b => b is FamilyInstance f), + appObj, + out bool _ + ); + if (mullionType != null) + { + TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER1_GRID1, mullionType); + TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER1_GRID2, mullionType); + TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER2_GRID1, mullionType); + TrySetParam(roofType, BuiltInParameter.AUTO_MULLION_BORDER2_GRID2, mullionType); + } + } + } + var poly = speckleFootprintRoof.outline as Polycurve; + bool hasSlopedSide = false; + if (poly != null) + { + for (var i = 0; i < curveArray.Size; i++) + { + var isSloped = ((Base)poly.segments[i])["isSloped"] as bool?; + var slopeAngle = ((Base)poly.segments[i])["slopeAngle"] as double?; + var offset = ((Base)poly.segments[i])["offset"] as double?; + + if (isSloped != null) + { + revitFootprintRoof.set_DefinesSlope(curveArray.get_Item(i), isSloped == true); + if (slopeAngle != null && isSloped == true) + { + // slope is set using actual slope (rise / run) for this method + revitFootprintRoof.set_SlopeAngle(curveArray.get_Item(i), Math.Tan((double)slopeAngle * Math.PI / 180)); + hasSlopedSide = true; + } + } + + if (offset != null) + { + revitFootprintRoof.set_Offset( + curveArray.get_Item(i), + ScaleToNative((double)offset, speckleFootprintRoof.units) + ); + } + } + } + + //this is for schema builder specifically + //if no roof edge has a slope defined but a slope angle is defined on the roof + //set each edge to have that slope + if (!hasSlopedSide && speckleFootprintRoof.slope != null && speckleFootprintRoof.slope != 0) + { + for (var i = 0; i < curveArray.Size; i++) + { + revitFootprintRoof.set_DefinesSlope(curveArray.get_Item(i), true); + } + + TrySetParam(revitFootprintRoof, BuiltInParameter.ROOF_SLOPE, (double)speckleFootprintRoof.slope); + } + + if (speckleFootprintRoof.cutOffLevel != null) + { + var cutOffLevel = ConvertLevelToRevit(speckleFootprintRoof.cutOffLevel, out levelState); + TrySetParam(revitFootprintRoof, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM, cutOffLevel); + } + + revitRoof = revitFootprintRoof; + break; + } + default: + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "Roof type not supported, please try with RevitExtrusionRoof or RevitFootprintRoof" + ); + return appObj; + } + + Doc.Regenerate(); + + try + { + CreateVoids(revitRoof, speckleRoof); + } + catch (Exception ex) + { + appObj.Update(logItem: $"Could not create openings: {ex.Message}"); + } + + if (speckleRevitRoof != null) + { + SetInstanceParameters(revitRoof, speckleRevitRoof); + } + else + { + TrySetParam(revitRoof, BuiltInParameter.ROOF_LEVEL_OFFSET_PARAM, -baseOffset); + } + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitRoof.UniqueId, convertedItem: revitRoof); + + Doc.Regenerate(); + + return appObj; + } + + private Roof RoofToSpeckle(DB.RoofBase revitRoof, out List notes) + { + notes = new List(); + List profiles = null; + + var speckleRoof = new RevitRoof(); + + switch (revitRoof) + { + //assigning correct type for when going back in Revit + case FootPrintRoof footPrintRoof: + { + var speckleFootprintRoof = new RevitFootprintRoof + { + level = ConvertAndCacheLevel(footPrintRoof, BuiltInParameter.ROOF_BASE_LEVEL_PARAM), + cutOffLevel = ConvertAndCacheLevel(footPrintRoof, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM), + slope = GetParamValue(footPrintRoof, BuiltInParameter.ROOF_SLOPE) //NOTE: can be null if the sides have different slopes + }; + + var slopeArrow = GetSlopeArrow(footPrintRoof); + if (slopeArrow != null) + { + var tail = GetSlopeArrowTail(slopeArrow, Doc); + var head = GetSlopeArrowHead(slopeArrow, Doc); + var tailOffset = GetSlopeArrowTailOffset(slopeArrow, Doc); + var headOffset = GetSlopeArrowHeadOffset(slopeArrow, Doc, tailOffset, out _); + + var newTail = new Geometry.Point(tail.x, tail.y, tailOffset); + var newHead = new Geometry.Point(head.x, head.y, headOffset); + profiles = GetProfiles(revitRoof, newTail, newHead); + } + + speckleRoof = speckleFootprintRoof; + break; + } + case ExtrusionRoof revitExtrusionRoof: + { + var speckleExtrusionRoof = new RevitExtrusionRoof + { + start = GetParamValue(revitExtrusionRoof, BuiltInParameter.EXTRUSION_START_PARAM), + end = GetParamValue(revitExtrusionRoof, BuiltInParameter.EXTRUSION_END_PARAM) + }; + var plane = revitExtrusionRoof.GetProfile().get_Item(0).SketchPlane.GetPlane(); + speckleExtrusionRoof.referenceLine = new Line( + PointToSpeckle(plane.Origin.Add(plane.XVec.Normalize().Negate()), revitRoof.Document), + PointToSpeckle(plane.Origin, revitRoof.Document), + ModelUnits + ); //TODO: test! + speckleExtrusionRoof.level = ConvertAndCacheLevel( + revitExtrusionRoof, + BuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM + ); + speckleRoof = speckleExtrusionRoof; + break; + } + } + var elementType = revitRoof.Document.GetElement(revitRoof.GetTypeId()) as ElementType; + speckleRoof.type = elementType.Name; + speckleRoof.family = elementType.FamilyName; + + if (profiles == null) + { + profiles = GetProfiles(revitRoof); + } + + // TODO handle case if not one of our supported roofs + if (profiles.Any()) + { + speckleRoof.outline = profiles[0]; + if (profiles.Count > 1) + { + speckleRoof.voids = profiles.Skip(1).ToList(); + } + } + + GetAllRevitParamsAndIds( + speckleRoof, + revitRoof, + new List + { + "ROOF_CONSTRAINT_LEVEL_PARAM", + "ROOF_BASE_LEVEL_PARAM", + "ROOF_UPTO_LEVEL_PARAM", + "EXTRUSION_START_PARAM", + "EXTRUSION_END_PARAM", + "ROOF_SLOPE" + } + ); + + speckleRoof.displayValue = GetElementDisplayValue(revitRoof); + + GetHostedElements(speckleRoof, revitRoof, out List hostedNotes); + if (hostedNotes.Any()) + { + notes.AddRange(hostedNotes); + } + + return speckleRoof; + } + + //Nesting the various profiles into a polycurve segments + private List GetProfiles(DB.RoofBase roof, Geometry.Point tailPoint = null, Geometry.Point headPoint = null) + { + // TODO handle case if not one of our supported roofs + var profiles = new List(); + + switch (roof) + { + case FootPrintRoof footprint: + { + ModelCurveArrArray crvLoops = footprint.GetProfiles(); + ModelCurve definesRoofSlope = null; + double roofSlope = 0; + + // if headpoint and tailpoint are not null, it means that the user is using a + // slope arrow to define the slope. Slope arrows are not creatable via the api + // so we have to translate that into sloped segments. + // if the user's slope arrow is not perpendicular to the segment that it is attached to + // then it will not work (this is just a limitation of sloped segments in Revit) + // see this api wish https://forums.autodesk.com/t5/revit-ideas/api-access-to-create-amp-modify-slope-arrow/idi-p/6700081 + if (tailPoint != null && headPoint != null) + { + for (var i = 0; i < crvLoops.Size; i++) + { + if (definesRoofSlope != null) + { + break; + } + + var crvLoop = crvLoops.get_Item(i); + var poly = new Polycurve(ModelUnits); + foreach (DB.ModelCurve curve in crvLoop) + { + if (curve == null) + { + continue; + } + + if (!(curve.Location is DB.LocationCurve c)) + { + continue; + } + + if (!(c.Curve is DB.Line line)) + { + continue; + } + + var start = PointToSpeckle(line.GetEndPoint(0), roof.Document); + var end = PointToSpeckle(line.GetEndPoint(1), roof.Document); + + if (!IsBetween(start, end, tailPoint)) + { + continue; + } + + if (!CheckOrtho(start.x, start.y, end.x, end.y, tailPoint.x, tailPoint.y, headPoint.x, headPoint.y)) + { + break; + } + + definesRoofSlope = curve; + var distance = Math.Sqrt( + (Math.Pow(headPoint.x - tailPoint.x, 2) + Math.Pow(headPoint.y - tailPoint.y, 2)) + ); + roofSlope = Math.Atan((headPoint.z - tailPoint.z) / distance) * 180 / Math.PI; + break; + } + } + } + + for (var i = 0; i < crvLoops.Size; i++) + { + var crvLoop = crvLoops.get_Item(i); + var poly = new Polycurve(ModelUnits); + foreach (DB.ModelCurve curve in crvLoop) + { + if (curve == null) + { + continue; + } + + var segment = CurveToSpeckle(curve.GeometryCurve, roof.Document) as Base; //it's a safe casting + if (definesRoofSlope != null && curve == definesRoofSlope) + { + segment["slopeAngle"] = roofSlope; + segment["isSloped"] = true; + segment["offset"] = tailPoint.z; + } + else + { + segment["slopeAngle"] = GetParamValue(curve, BuiltInParameter.ROOF_SLOPE); + segment["isSloped"] = GetParamValue(curve, BuiltInParameter.ROOF_CURVE_IS_SLOPE_DEFINING); + segment["offset"] = GetParamValue(curve, BuiltInParameter.ROOF_CURVE_HEIGHT_OFFSET); + } + poly.segments.Add(segment as ICurve); + + //roud profiles are returned duplicated! + if (curve is ModelArc arc && RevitVersionHelper.IsCurveClosed(arc.GeometryCurve)) + { + break; + } + } + profiles.Add(poly); + } + + break; + } + case ExtrusionRoof extrusion: + { + var crvloop = extrusion.GetProfile(); + var poly = new Polycurve(ModelUnits); + foreach (DB.ModelCurve curve in crvloop) + { + if (curve == null) + { + continue; + } + + poly.segments.Add(CurveToSpeckle(curve.GeometryCurve, roof.Document)); + } + profiles.Add(poly); + break; + } + } + return profiles; + } + + // checks if point c is between a and b + private bool IsBetween(Geometry.Point a, Geometry.Point b, Geometry.Point c) + { + var crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y); + + // compare versus epsilon for floating point values, or != 0 if using integers + if (Math.Abs(crossproduct) > TOLERANCE) + { + return false; + } + + var dotProduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y) * (b.y - a.y); + if (dotProduct < 0) + { + return false; + } + + var squaredLengthBA = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); + if (dotProduct > squaredLengthBA) + { + return false; + } + + return true; + } + + private bool CheckOrtho(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) + { + double m1, + m2; + + // Both lines have infinite slope + if (Math.Abs(x2 - x1) < TOLERANCE && Math.Abs(x4 - x3) < TOLERANCE) + { + return false; + } + // Only line 1 has infinite slope + else if (Math.Abs(x2 - x1) < TOLERANCE) + { + m2 = (y4 - y3) / (x4 - x3); + if (Math.Abs(m2) < TOLERANCE) + { + return true; + } + else + { + return false; + } + } + // Only line 2 has infinite slope + else if (Math.Abs(x4 - x3) < TOLERANCE) + { + m1 = (y2 - y1) / (x2 - x1); + if (Math.Abs(m1) < TOLERANCE) + { + return true; + } + else + { + return false; + } + } + else + { + // Find slopes of the lines + m1 = (y2 - y1) / (x2 - x1); + m2 = (y4 - y3) / (x4 - x3); + + // Check if their product is -1 + if (Math.Abs(m1 * m2 + 1) < TOLERANCE) + { + return true; + } + else + { + return false; + } + } + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoom.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoom.cs new file mode 100644 index 0000000000..a8976a02aa --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertRoom.cs @@ -0,0 +1,92 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements; +using Speckle.Core.Models; +using System.Collections.Generic; +using System.Linq; +using DB = Autodesk.Revit.DB.Architecture; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject RoomToNative(Room speckleRoom) + { + var revitRoom = GetExistingElementByApplicationId(speckleRoom.applicationId) as DB.Room; + var appObj = new ApplicationObject(speckleRoom.id, speckleRoom.speckle_type) + { + applicationId = speckleRoom.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitRoom, appObj)) + { + return appObj; + } + + var level = ConvertLevelToRevit(speckleRoom.level, out ApplicationObject.State levelState); + + var isUpdate = true; + if (revitRoom == null) + { + var basePoint = PointToNative(speckleRoom.basePoint); + + // set computation level of Level based on the bottom elevation of the Room (Rooms can have offset elevation from Levels) + // it is not guaranteed that the final computation level will fit for all the Rooms, however not generating extra levels is preferred + if (level.get_Parameter(BuiltInParameter.LEVEL_ROOM_COMPUTATION_HEIGHT).AsDouble() < basePoint.Z) + { + TrySetParam(level, BuiltInParameter.LEVEL_ROOM_COMPUTATION_HEIGHT, basePoint.Z); + } + + revitRoom = Doc.Create.NewRoom(level, new UV(basePoint.X, basePoint.Y)); + isUpdate = false; + } + + revitRoom.Name = speckleRoom.name; + revitRoom.Number = speckleRoom.number; + + if (speckleRoom.height > 0.0) + { + TrySetParam(revitRoom, BuiltInParameter.ROOM_UPPER_OFFSET, ScaleToNative(speckleRoom.height, speckleRoom.units)); + } + + SetInstanceParameters(revitRoom, speckleRoom); + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitRoom.UniqueId, convertedItem: revitRoom); + return appObj; + } + + public BuiltElements.Room RoomToSpeckle(DB.Room revitRoom) + { + var profiles = GetProfiles(revitRoom); + + var speckleRoom = new Room(); + + speckleRoom.name = revitRoom.get_Parameter(BuiltInParameter.ROOM_NAME).AsString(); + speckleRoom.number = revitRoom.Number; + speckleRoom.basePoint = (Point)LocationToSpeckle(revitRoom); + speckleRoom.level = ConvertAndCacheLevel(revitRoom, BuiltInParameter.ROOM_LEVEL_ID); + if (profiles.Any()) + { + speckleRoom.outline = profiles[0]; + } + + speckleRoom.area = GetParamValue(revitRoom, BuiltInParameter.ROOM_AREA); + if (profiles.Count > 1) + { + speckleRoom.voids = profiles.Skip(1).ToList(); + } + + GetAllRevitParamsAndIds(speckleRoom, revitRoom); + + speckleRoom.displayValue = GetElementDisplayValue(revitRoom); + var phase = Doc.GetElement(revitRoom.get_Parameter(BuiltInParameter.ROOM_PHASE).AsElementId()); + if (phase != null) + { + speckleRoom["phaseCreated"] = phase.Name; + } + + return speckleRoom; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertSpace.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertSpace.cs new file mode 100644 index 0000000000..328c7c4db8 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertSpace.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB.Mechanical; +using Level = Autodesk.Revit.DB.Level; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject SpaceToNative(Space speckleSpace) + { + var appObj = new ApplicationObject(speckleSpace.id, speckleSpace.speckle_type) + { + applicationId = speckleSpace.applicationId + }; + + var revitSpace = GetExistingElementByApplicationId(speckleSpace.applicationId) as DB.Space; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitSpace, appObj)) + { + return appObj; + } + + // Determine Space Location + if (speckleSpace.basePoint is null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Space Base Point was null"); + return appObj; + } + + var level = ConvertLevelToRevit(speckleSpace.level, out _); + var basePoint = PointToNative(speckleSpace.basePoint); + var upperLimit = ConvertLevelToRevit(speckleSpace.topLevel, out _); + + // no target phase found, it will use the active view phase anyway + var targetPhase = DetermineTargetPhase(speckleSpace, revitSpace); + var activeViewPhase = DetermineActiveViewPhase(); + + // even though the API documented to allow for spaces to be created in any phase, + // it is not possible to create on any phase but the Active View phase + var activeViewPhaseName = activeViewPhase?.Name; + var targetPhaseName = targetPhase?.Name; + + if (activeViewPhase.Id != targetPhase.Id) + { + appObj.Update( + logItem: $"Space Phase {targetPhase.Name} not selected in the Active View.", + status: ApplicationObject.State.Skipped + ); + return appObj; + // return null; + } + + revitSpace = CreateRevitSpaceIfNeeded(speckleSpace, revitSpace, targetPhase, level, basePoint); + + if (revitSpace == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var revitZone = revitSpace.Zone; + revitZone = CreateRevitZoneIfNeeded(speckleSpace, revitZone, targetPhase, level); + + // if a relevant zone exists add space to it + if (revitZone != null) + { + var currentSpaces = revitZone.Spaces; + + // if the space is already in the zone, do nothing. + if (!currentSpaces.Contains(revitSpace)) + { + var spaceSet = new DB.SpaceSet(); + spaceSet.Insert(revitSpace); + revitZone.AddSpaces(spaceSet); + } + } + + revitSpace.Name = speckleSpace.name; + revitSpace.Number = speckleSpace.number; + + SetSpaceLimits(speckleSpace, upperLimit, revitSpace); + SetSpaceType(speckleSpace, revitSpace); + SetInstanceParameters(revitSpace, speckleSpace); + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitSpace.UniqueId, convertedItem: revitSpace); + return appObj; + } + + /// + /// Sets the type of the Revit space based on the provided Speckle space. + /// + /// The Space object from the Speckle system. + /// The Revit Space object to update. + /// + /// The method will try to set the Revit space type based on the Speckle space type. + /// If the Speckle space type is not recognized, it will default to 'NoSpaceType'. + /// + private static void SetSpaceType(Space speckleSpace, DB.Space revitSpace) + { + if (string.IsNullOrEmpty(speckleSpace.spaceType)) + { + return; + } + + revitSpace.SpaceType = Enum.TryParse(speckleSpace.spaceType, out DB.SpaceType spaceType) + ? spaceType + : DB.SpaceType.NoSpaceType; + } + + /// + /// Sets the upper limit and offsets for a Revit space based on a Speckle space. + /// + /// The Speckle Space object containing the upper limit and offset information. + /// The Element object representing the upper limit level. + /// The Revit Space object to be updated. + /// + /// The method will attempt to set the upper limit and offsets for the Revit space. + /// If an upper limit is not specified, the method will return early without making changes. + /// + private void SetSpaceLimits(Space speckleSpace, Element upperLimit, DB.Space revitSpace) + { + if (upperLimit == null) + { + return; + } + + TrySetParam(revitSpace, BuiltInParameter.ROOM_UPPER_LEVEL, upperLimit); + + revitSpace.LimitOffset = ScaleToNative(speckleSpace.topOffset, speckleSpace.units); + revitSpace.BaseOffset = ScaleToNative(speckleSpace.baseOffset, speckleSpace.units); + } + + /// + /// Handles the Revit Space based on the provided Speckle Space and target phase. + /// + /// The Space object from the Speckle system. + /// The existing Revit Space object. This may be modified by the method. + /// The target Phase object. + /// The Level object associated with the space. + /// The base point for the space. + /// The modified or newly created Revit Space object. + private DB.Space CreateRevitSpaceIfNeeded( + Space speckleSpace, + DB.Space revitSpace, + Phase targetPhase, + Level level, + XYZ basePoint + ) + { + // Main logic + if (revitSpace == null) + { + revitSpace = CreateNewSpace(level, targetPhase, new UV(basePoint.X, basePoint.Y), speckleSpace.level.name); + + if (revitSpace == null) + { + return null; + } + } + else if (revitSpace.Area == 0 && revitSpace.Location == null) + { + Doc.Delete(revitSpace.Id); + + revitSpace = CreateNewSpace(level, targetPhase, new UV(basePoint.X, basePoint.Y), speckleSpace.level.name); + } + + return revitSpace; + } + + /// + /// Creates a new RevitSpace based on the provided parameters. + /// + /// The level for the new space. + /// The target phase for the new space. If null, the active view phase will be used. + /// The base point (UV coordinates) for the new space. + /// The name of the level. Used to determine if the space has a location. + /// The newly created RevitSpace, or null if the space could not be created. + private DB.Space CreateNewSpace(Level level, Phase targetPhase, UV basePoint, string levelName) + { + if (targetPhase == null) + { + return string.IsNullOrEmpty(levelName) || basePoint == null + ? null + : Doc.Create.NewSpace(level, new UV(basePoint.U, basePoint.V)); + } + + return string.IsNullOrEmpty(levelName) // has no location + ? Doc.Create.NewSpace(targetPhase) + : Doc.Create.NewSpace(level, targetPhase, new UV(basePoint.U, basePoint.V)); + } + + /// + /// Determines the target phase for a space based on available information. + /// + /// The Space object from the Speckle system. + /// The Space object from the Revit system. + /// The determined target Phase object. + /// + /// The method tries to determine the target phase based on the following priority: + /// 1. Phase from the Speckle space (if it exists). + /// 2. Phase from the existing Revit space (if it exists). + /// 3. Phase from the active view in Revit. + /// + private Phase DetermineTargetPhase(Space speckleSpace, DB.Space revitSpace) + { + // Get all phases + var phases = Doc.Phases.Cast().ToList(); + + // Determine existing space phase, if any + Phase existingSpacePhase = null; + if (revitSpace != null) + { + string existingSpacePhaseName = revitSpace.get_Parameter(BuiltInParameter.ROOM_PHASE).AsValueString(); + existingSpacePhase = phases.FirstOrDefault(x => x.Name == existingSpacePhaseName); + } + + // Determine target phase + // Priority: speckleSpace phase > existing space phase > active view phase + string targetPhaseName = speckleSpace.phaseName; + var targetPhase = phases.FirstOrDefault(x => x.Name == targetPhaseName) ?? existingSpacePhase; + + return targetPhase; + } + + private Phase DetermineActiveViewPhase(IEnumerable phases = null) + { + phases ??= Doc.Phases.Cast(); + + // Determine active view phase + var activeViewPhaseName = Doc.ActiveView.get_Parameter(BuiltInParameter.VIEW_PHASE).AsValueString(); + return phases.FirstOrDefault(x => x.Name == activeViewPhaseName); + } + + public Space SpaceToSpeckle(DB.Space revitSpace) + { + var profiles = GetProfiles(revitSpace); + + var speckleSpace = new Space + { + name = revitSpace.Name, + number = revitSpace.Number, + basePoint = (Point)LocationToSpeckle(revitSpace), + level = ConvertAndCacheLevel(revitSpace.LevelId, revitSpace.Document), + topLevel = ConvertAndCacheLevel( + revitSpace.get_Parameter(BuiltInParameter.ROOM_UPPER_LEVEL).AsElementId(), + revitSpace.Document + ), + baseOffset = GetParamValue(revitSpace, BuiltInParameter.ROOM_LOWER_OFFSET), + topOffset = GetParamValue(revitSpace, BuiltInParameter.ROOM_UPPER_OFFSET), + outline = profiles.Count != 0 ? profiles[0] : null, + area = GetParamValue(revitSpace, BuiltInParameter.ROOM_AREA), + volume = GetParamValue(revitSpace, BuiltInParameter.ROOM_VOLUME), + spaceType = revitSpace.SpaceType.ToString(), + displayValue = GetElementDisplayValue(revitSpace) + }; + + if (profiles.Count > 1) + { + speckleSpace.voids = profiles.Skip(1).ToList(); + } + + // Spaces are typically associated with a Room, but not always + if (revitSpace.Room != null) + { + speckleSpace["roomId"] = revitSpace.Room.Id.ToString(); + } + + // Zones are stored as a Space prop despite being a parent object, so we need to convert it here + speckleSpace.zone = revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType(out _) + .GetOrAdd(revitSpace.Zone.Name, () => ZoneToSpeckle(revitSpace.Zone), out _); + + GetAllRevitParamsAndIds(speckleSpace, revitSpace); + + // Special Phase handling for Spaces, phase is found as a parameter on the Space object, not a property + var phase = Doc.GetElement(revitSpace.get_Parameter(BuiltInParameter.ROOM_PHASE).AsElementId()); + if (phase != null) + { + speckleSpace.phaseName = phase.Name; + } + + return speckleSpace; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStair.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStair.cs new file mode 100644 index 0000000000..6e9411e4f3 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStair.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Architecture; +using Objects.BuiltElements.Revit; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + //NOTE: we are currently only converting Stairs ToSpeckle + //a ToNative method might come later on! + private RevitStair StairToSpeckle(Stairs revitStair) + { + var stairType = revitStair.Document.GetElement(revitStair.GetTypeId()) as StairsType; + var speckleStair = new RevitStair(); + speckleStair.family = stairType.FamilyName; + speckleStair.type = stairType.Name; + speckleStair.level = ConvertAndCacheLevel(revitStair, BuiltInParameter.STAIRS_BASE_LEVEL_PARAM); + speckleStair.topLevel = ConvertAndCacheLevel(revitStair, BuiltInParameter.STAIRS_TOP_LEVEL_PARAM); + speckleStair.riserHeight = ScaleToSpeckle(revitStair.ActualRiserHeight); + speckleStair.risersNumber = revitStair.ActualRisersNumber; + speckleStair.treadDepth = ScaleToSpeckle(revitStair.ActualTreadDepth); + speckleStair.treadsNumber = revitStair.ActualTreadsNumber; + speckleStair.baseElevation = ScaleToSpeckle(revitStair.BaseElevation); + speckleStair.topElevation = ScaleToSpeckle(revitStair.TopElevation); + speckleStair.height = ScaleToSpeckle(revitStair.Height); + speckleStair.numberOfStories = revitStair.NumberOfStories; + + speckleStair.runs = revitStair + .GetStairsRuns() + .Select(x => StairRunToSpeckle(revitStair.Document.GetElement(x) as StairsRun)) + .ToList(); + speckleStair.landings = revitStair + .GetStairsLandings() + .Select(x => StairLandingToSpeckle(revitStair.Document.GetElement(x) as StairsLanding)) + .ToList(); + speckleStair.supports = revitStair + .GetStairsSupports() + .Select(x => StairSupportToSpeckle(revitStair.Document.GetElement(x))) + .ToList(); + + GetAllRevitParamsAndIds( + speckleStair, + revitStair, + new List { "STAIRS_BASE_LEVEL_PARAM", "STAIRS_TOP_LEVEL_PARAM" } + ); + + speckleStair.displayValue = GetElementDisplayValue(revitStair); + + return speckleStair; + } + + private RevitStairRun StairRunToSpeckle(StairsRun revitStairRun) + { + var stairType = revitStairRun.Document.GetElement(revitStairRun.GetTypeId()) as StairsRunType; + var run = new RevitStairRun(); + run.family = stairType.FamilyName; + run.type = stairType.Name; + run.risersNumber = revitStairRun.ActualRisersNumber; + run.runWidth = ScaleToSpeckle(revitStairRun.ActualRunWidth); + run.treadsNumber = revitStairRun.ActualTreadsNumber; + run.height = ScaleToSpeckle(revitStairRun.Height); + run.baseElevation = ScaleToSpeckle(revitStairRun.BaseElevation); + run.topElevation = ScaleToSpeckle(revitStairRun.TopElevation); + run.beginsWithRiser = revitStairRun.BeginsWithRiser; + run.endsWithRiser = revitStairRun.EndsWithRiser; + run.extensionBelowRiserBase = ScaleToSpeckle(revitStairRun.ExtensionBelowRiserBase); + run.extensionBelowTreadBase = ScaleToSpeckle(revitStairRun.ExtensionBelowTreadBase); + run.runStyle = revitStairRun.StairsRunStyle.ToString(); + run.units = ModelUnits; + run.path = CurveLoopToSpeckle(revitStairRun.GetStairsPath(), revitStairRun.Document); + run.outline = CurveLoopToSpeckle(revitStairRun.GetFootprintBoundary(), revitStairRun.Document); + + GetAllRevitParamsAndIds(run, revitStairRun); + return run; + } + + private RevitStairLanding StairLandingToSpeckle(StairsLanding revitStairLanding) + { + var stairType = revitStairLanding.Document.GetElement(revitStairLanding.GetTypeId()) as StairsLandingType; + var landing = new RevitStairLanding(); + landing.family = stairType.FamilyName; + landing.type = stairType.Name; + landing.isAutomaticLanding = revitStairLanding.IsAutomaticLanding; + landing.thickness = revitStairLanding.Thickness; + landing.baseElevation = ScaleToSpeckle(revitStairLanding.BaseElevation); + landing.units = ModelUnits; + landing.outline = CurveLoopToSpeckle(revitStairLanding.GetFootprintBoundary(), revitStairLanding.Document); + + GetAllRevitParamsAndIds(landing, revitStairLanding); + return landing; + } + + private RevitStairSupport StairSupportToSpeckle(Element revitStairSupport) + { + var stairType = revitStairSupport.Document.GetElement(revitStairSupport.GetTypeId()) as ElementType; + var support = new RevitStairSupport(); + support.family = stairType.FamilyName; + support.type = stairType.Name; + + GetAllRevitParamsAndIds(support, revitStairSupport); + return support; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralConnectionHandlers.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralConnectionHandlers.cs new file mode 100644 index 0000000000..15190b2e81 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralConnectionHandlers.cs @@ -0,0 +1,78 @@ +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using System.Collections.Generic; +using DB = Autodesk.Revit.DB; +using Structure = Autodesk.Revit.DB.Structure; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private ApplicationObject StructuralConnectionHandlerToNative(StructuralConnectionHandler speckleConnectionHandler) + { + // I think the code below is mostly what we need to get this working. However, the + // StructuralConnectionHandler has a one to many relationship and we need to make sure + // that every object that the connection is connected to has been converted before + // this object is converted. Therefore I'm waiting on Jedd's new traversal function to make this + // a reality for me before implementing the receiveToNative method. + + //var docObj = GetExistingElementByApplicationId(speckleConnectionHandler.applicationId); + //var appObj = new ApplicationObject(speckleConnectionHandler.id, speckleConnectionHandler.speckle_type) { applicationId = speckleConnectionHandler.applicationId }; + + //// skip if element already exists in doc & receive mode is set to ignore + //if (IsIgnore(docObj, appObj, out appObj)) + // return appObj; + + //if (!GetElementType(speckleConnectionHandler, appObj, out Structure.StructuralConnectionHandlerType connectionType)) + //{ + // appObj.Update(status: ApplicationObject.State.Failed, logItem: "Unable to find a valid connection type in the Revit project"); + // return appObj; + //} + + //if (docObj != null) + //{ + // // TODO: Replace with actual update logic here + // Doc.Delete(docObj.Id); + //} + + //var elIds = new List(); + //foreach (var speckleEl in speckleConnectionHandler.connectedElements) + //{ + // var revitEl = GetExistingElementByApplicationId(speckleEl.applicationId); + // if (revitEl != null) + // elIds.Add(revitEl.Id); + //} + + //Structure.StructuralConnectionHandler.Create(Doc, elIds, connectionType.Id); + //appObj.Update(status: ApplicationObject.State.Created); + //return appObj; + + return null; + } + + private Base StructuralConnectionHandlerToSpeckle(DB.Structure.StructuralConnectionHandler revitConnection) + { + var type = + revitConnection.Document.GetElement(revitConnection.GetTypeId()) as Structure.StructuralConnectionHandlerType; + + //var connectedElements = revitConnection.GetConnectedElementIds(); + + var speckleConnection = new StructuralConnectionHandler() + { + family = type.FamilyName, + type = type.Name, + //connectedElements = connectedElements + }; + + // Structural Connection Handlers are (supposedly) view specific which requires getting mesh by view + // TODO: not guarenteed that the active view is what we need (3D view with fine detail where the element is visible + speckleConnection.displayValue = GetElementDisplayValue( + revitConnection, + new DB.Options() { View = Doc.ActiveView } + ); + + GetAllRevitParamsAndIds(speckleConnection, revitConnection); + + return speckleConnection; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralModel.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralModel.cs new file mode 100644 index 0000000000..48863a6d89 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertStructuralModel.cs @@ -0,0 +1,73 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Objects.Structural.Geometry; +using Vector = Objects.Geometry.Vector; +using Plane = Objects.Geometry.Plane; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Objects.Structural.Analysis; +using Objects.Structural.CSI.Geometry; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject StructuralModelToNative(Model speckleStructModel) + { + var lengthUnits = speckleStructModel.specs.settings.modelUnits.length; + var appObj = new ApplicationObject(speckleStructModel.id, speckleStructModel.speckle_type) + { + applicationId = speckleStructModel.applicationId + }; + foreach (Node node in speckleStructModel.nodes) + { + var _node = AnalyticalNodeToNative(node); + appObj.Update(createdIds: _node.CreatedIds, converted: _node.Converted); + } + foreach (var element in speckleStructModel.elements) + { + if (element is Element1D element1D) + { + element1D.units = lengthUnits; + try + { + if (element is CSIElement1D csiElement1D) + { + var _csiStick = AnalyticalStickToNative(csiElement1D); + appObj.Update(createdIds: _csiStick.CreatedIds, converted: _csiStick.Converted); + } + else + { + var _stick = AnalyticalStickToNative((Element1D)element); + appObj.Update(createdIds: _stick.CreatedIds, converted: _stick.Converted); + } + } + catch { } + } + else + { + try + { + if (element is CSIElement2D csiElement2D) + { + var _csiStick = AnalyticalSurfaceToNative(csiElement2D); + appObj.Update(createdIds: _csiStick.CreatedIds, converted: _csiStick.Converted); + } + else + { + var _stick = AnalyticalSurfaceToNative((Element2D)element); + appObj.Update(createdIds: _stick.CreatedIds, converted: _stick.Converted); + } + } + catch { } + } + } + + return appObj; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTeklaObjects.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTeklaObjects.cs new file mode 100644 index 0000000000..5bf29c6c4a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTeklaObjects.cs @@ -0,0 +1,38 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Structure; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Objects.Structural.Geometry; +using Objects.Structural.Properties; +using Objects.Structural.Properties.Profiles; +using Objects.Structural.Materials; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject TeklaBeamToNative( + BuiltElements.TeklaStructures.TeklaBeam teklaBeam, + StructuralType structuralType = StructuralType.Beam + ) + { + var appObj = new ApplicationObject(teklaBeam.id, teklaBeam.speckle_type) + { + applicationId = teklaBeam.applicationId + }; + + RevitBeam revitBeam = new(); + //This only works for CSIC sections now for sure. Need to test on other sections + revitBeam.type = teklaBeam.profile.name.Replace('X', 'x'); + revitBeam.baseLine = teklaBeam.baseLine; + //Beam beam = new Beam(teklaBeam.baseLine); + appObj = BeamToNative(revitBeam); + //DB.FamilyInstance nativeRevitBeam = (DB.FamilyInstance)placeholders[0].NativeObject; + return appObj; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopRail.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopRail.cs new file mode 100644 index 0000000000..f21c6528c4 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopRail.cs @@ -0,0 +1,25 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Architecture; +using Objects.BuiltElements.Revit; +using System.Collections.Generic; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private RevitTopRail TopRailToSpeckle(TopRail revitTopRail) + { + var topRailType = revitTopRail.Document.GetElement(revitTopRail.GetTypeId()) as TopRailType; + var speckleTopRail = new RevitTopRail + { + type = topRailType.Name, + displayValue = GetElementDisplayValue(revitTopRail) + }; + + GetAllRevitParamsAndIds(speckleTopRail, revitTopRail, new List { }); + + Report.Log($"Converted TopRail {revitTopRail.Id}"); + + return speckleTopRail; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopography.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopography.cs new file mode 100644 index 0000000000..eeb252e5bc --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertTopography.cs @@ -0,0 +1,80 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.DB.Architecture; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Objects.Utils; +using Speckle.Core.Models; +using System.Collections.Generic; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject TopographyToNative(Topography speckleSurface) + { + var docObj = GetExistingElementByApplicationId(((Base)speckleSurface).applicationId); + var appObj = new ApplicationObject(speckleSurface.id, speckleSurface.speckle_type) + { + applicationId = speckleSurface.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + var pts = new List(); + var pointTuplesList = new List<(double, double)>(); + var facets = new List(); + foreach (Geometry.Mesh displayMesh in speckleSurface.displayValue) + { + // triangulate the mesh first since revit Topography can only accept triangulated meshes + displayMesh.TriangulateMesh(); + + pts.Capacity += displayMesh.vertices.Count / 3; + for (int i = 0; i < displayMesh.vertices.Count; i += 3) + { + // add a check for duplicate points, if 'keepXYDuplicates' is false + var ptTuple = (displayMesh.vertices[i], displayMesh.vertices[i + 1]); + if (!pointTuplesList.Contains(ptTuple)) + { + pointTuplesList.Add(ptTuple); + var point = new Geometry.Point( + displayMesh.vertices[i], + displayMesh.vertices[i + 1], + displayMesh.vertices[i + 2], + displayMesh.units + ); + pts.Add(PointToNative(point)); + } + } + } + + if (docObj != null) + { + Doc.Delete(docObj.Id); + } + + var revitSurface = TopographySurface.Create(Doc, pts); + if (speckleSurface is RevitTopography rt) + { + SetInstanceParameters(revitSurface, rt); + } + + appObj.Update( + status: ApplicationObject.State.Created, + createdId: revitSurface.UniqueId, + convertedItem: revitSurface + ); + return appObj; + } + + public RevitTopography TopographyToSpeckle(TopographySurface revitTopo) + { + var speckleTopo = new RevitTopography(); + speckleTopo.displayValue = GetElementDisplayValue(revitTopo); + GetAllRevitParamsAndIds(speckleTopo, revitTopo); + return speckleTopo; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertToposolid.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertToposolid.cs new file mode 100644 index 0000000000..ab7ff33d79 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertToposolid.cs @@ -0,0 +1,112 @@ +#if (REVIT2024) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +using OG = Objects.Geometry; +using OO = Objects.Other; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject ToposolidToNative(RevitToposolid fromSpeckle) + { + string name = null; + ApplicationObject appObj = null; + + var docObj = GetExistingElementByApplicationId(fromSpeckle.applicationId); + appObj = new ApplicationObject(fromSpeckle.id, fromSpeckle.speckle_type) + { + applicationId = fromSpeckle.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + // get the curves and the points + var curveLoops = new List(); + foreach (var curveArray in fromSpeckle.profiles) + { + curveLoops.Add(CurveArrayToCurveLoop(CurveToNative(curveArray.segments))); + } + + var points = fromSpeckle.points.Select(x => PointToNative(x)).ToList(); + + // NOTE: if the level is null this will not create + // there maybe something more elegant we can do to automatically drop to direct shape + DB.Level level = ConvertLevelToRevit(fromSpeckle.level, out ApplicationObject.State state); + + var topoSolidType = GetElementType(fromSpeckle, appObj, out bool _); + + Toposolid revitToposolid = null; + if (points.Count > 0) + { + revitToposolid = Toposolid.Create(Doc, curveLoops, points, topoSolidType.Id, level?.Id); + } + else + { + revitToposolid = Toposolid.Create(Doc, curveLoops, topoSolidType.Id, level?.Id); + } + + SetInstanceParameters(revitToposolid, fromSpeckle); + + appObj.Update(status: ApplicationObject.State.Created, createdId: revitToposolid.UniqueId, convertedItem: revitToposolid); + + return appObj; + } + + private RevitToposolid ToposolidToSpeckle(Toposolid topoSolid, out List notes) + { + var toSpeckle = new RevitToposolid(); + notes = new List(); + + // we will store the list of interior points in order to recreate the Toposolid + var slabShapeEditor = topoSolid.GetSlabShapeEditor(); + var vertices = slabShapeEditor.SlabShapeVertices; + toSpeckle.points = vertices.Cast() + .Select(x => PointToSpeckle(x.Position, Doc)) + .ToList(); + + var sketch = Doc.GetElement(topoSolid.SketchId) as Sketch; + toSpeckle.profiles = GetSketchProfiles(sketch); + + var type = topoSolid.Document.GetElement(topoSolid.GetTypeId()) as ElementType; + + toSpeckle.level = ConvertAndCacheLevel(topoSolid, BuiltInParameter.LEVEL_PARAM); + toSpeckle.family = type?.FamilyName; + toSpeckle.type = type?.Name; + + GetAllRevitParamsAndIds( + toSpeckle, + topoSolid, + new List + { + "LEVEL_PARAM", + } + ); + + toSpeckle.displayValue = GetElementDisplayValue( + topoSolid, + new Options() { DetailLevel = ViewDetailLevel.Fine }); + + GetHostedElements(toSpeckle, topoSolid, out List hostedNotes); + if (hostedNotes.Any()) + { + notes.AddRange(hostedNotes); + } + + return toSpeckle; + } +} + +#endif diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.Schedule.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.Schedule.cs new file mode 100644 index 0000000000..2dc43fefce --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.Schedule.cs @@ -0,0 +1,579 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.Organization; +using RevitSharedResources.Models; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + #region ToNative + private ApplicationObject DataTableToNative(DataTable speckleTable) + { + var docObj = GetExistingElementByApplicationId(speckleTable.applicationId); + var appObj = new ApplicationObject(speckleTable.id, speckleTable.speckle_type) + { + applicationId = speckleTable.applicationId + }; + + if (docObj == null) + { + throw new NotSupportedException("Creating brand new schedules is currently not supported"); + } + + if (docObj is not ViewSchedule revitSchedule) + { + throw new Exception( + $"Existing element with UniqueId = {docObj.UniqueId} is of the type {docObj.GetType()}, not of the expected type, DB.ViewSchedule" + ); + } + + var speckleIndexToRevitParameterDataMap = new Dictionary(); + foreach (var columnInfo in RevitScheduleUtils.ScheduleColumnIteration(revitSchedule)) + { + AddToIndexToScheduleMap(columnInfo, speckleTable, speckleIndexToRevitParameterDataMap); + } + + var originalTableIds = new FilteredElementCollector(Doc, revitSchedule.Id).ToElementIds(); + foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) + { + UpdateDataInRow(rowInfo, originalTableIds, revitSchedule, speckleTable, speckleIndexToRevitParameterDataMap); + } + + appObj.Update(convertedItem: docObj, createdId: docObj.UniqueId, status: ApplicationObject.State.Updated); + return appObj; + } + + private static void AddToIndexToScheduleMap( + ScheduleColumnIterationInfo info, + DataTable speckleTable, + Dictionary speckleIndexToRevitParameterDataMap + ) + { + var fieldInt = info.field.ParameterId.IntegerValue; + + var incomingColumnIndex = -1; + for (var i = 0; i < speckleTable.columnMetadata.Count; i++) + { + long? paramId = null; + if (speckleTable.columnMetadata[i]["BuiltInParameterInteger"] is int paramIdInt) + { + paramId = paramIdInt; + } + if (speckleTable.columnMetadata[i]["BuiltInParameterInteger"] is long paramIdLong) + { + paramId = paramIdLong; + } + + if (paramId == null) + { + continue; + } + if (paramId != fieldInt) + { + continue; + } + + incomingColumnIndex = i; + break; + } + + if (incomingColumnIndex == -1) + { + return; + } + + if (!(speckleTable.columnMetadata[incomingColumnIndex]["FieldType"] is string fieldType)) + { + throw new Exception("Column does not have prop metadata. FieldType is missing"); + } + + var scheduleData = new RevitParameterData + { + ColumnIndex = info.columnIndex - info.numHiddenFields, + Parameter = (BuiltInParameter)fieldInt, + IsTypeParam = fieldType == "ElementType" + }; + speckleIndexToRevitParameterDataMap.Add(incomingColumnIndex, scheduleData); + } + + private void UpdateDataInRow( + ScheduleRowIterationInfo info, + ICollection originalTableIds, + ViewSchedule revitSchedule, + DataTable speckleTable, + Dictionary speckleIndexToRevitParameterDataMap + ) + { + var elementIds = ElementApplicationIdsInRow( + info.rowIndex, + info.section, + originalTableIds, + revitSchedule, + info.tableSection + ) + .ToList(); + + if (elementIds.Count == 0) + { + return; + } + + var speckleObjectRowIndex = speckleTable.rowMetadata.FindIndex( + b => b["RevitApplicationIds"] is IList list && list.Contains(elementIds.First()) + ); + + foreach (var kvp in speckleIndexToRevitParameterDataMap) + { + var speckleObjectColumnIndex = kvp.Key; + var revitScheduleData = kvp.Value; + + var existingValue = revitSchedule.GetCellText(info.tableSection, info.rowIndex, revitScheduleData.ColumnIndex); + var newValue = speckleTable.data[speckleObjectRowIndex][speckleObjectColumnIndex]; + if (existingValue == newValue.ToString()) + { + continue; + } + + if (revitScheduleData.IsTypeParam) + { + Element element = null; + foreach (var id in elementIds) + { + element = Doc.GetElement(elementIds.First()); + if (element != null) + { + break; + } + } + if (element == null) + { + return; + } + + var elementType = Doc.GetElement(element.GetTypeId()); + TrySetParam(elementType, revitScheduleData.Parameter, newValue, "none"); + } + else + { + foreach (var id in elementIds) + { + var element = Doc.GetElement(id); + if (element == null) + { + continue; + } + + TrySetParam(element, revitScheduleData.Parameter, newValue, "none"); + } + } + } + } + + #endregion + + #region ToSpeckle + private DataTable ScheduleToSpeckle(DB.ViewSchedule revitSchedule) + { + var speckleTable = new DataTable { applicationId = revitSchedule.UniqueId }; + + var originalTableIds = new FilteredElementCollector(Doc, revitSchedule.Id).ToElementIds(); + + var skippedIndicies = new Dictionary>(); + var columnHeaders = new List(); + + DefineColumnMetadata(revitSchedule, speckleTable, originalTableIds, columnHeaders); + + var headerIndexArray = GetTableHeaderIndexArray(revitSchedule, columnHeaders); + + PopulateDataTableRows(revitSchedule, speckleTable, originalTableIds, headerIndexArray, columnHeaders); + + if (!revitSchedule.Definition.ShowHeaders) + { + AddHeaderRow(speckleTable, columnHeaders); + } + + return speckleTable; + } + + private void AddHeaderRow(DataTable speckleTable, List headers) + { + speckleTable.AddRow(metadata: new Base(), index: speckleTable.headerRowIndex, headers.ToArray()); + } + + private void DefineColumnMetadata( + ViewSchedule revitSchedule, + DataTable speckleTable, + ICollection originalTableIds, + List columnHeaders + ) + { + Element firstElement = null; + Element firstType = null; + if (originalTableIds.Count > 0) + { + firstElement = Doc.GetElement(originalTableIds.First()); + firstType = Doc.GetElement(firstElement.GetTypeId()); + } + + foreach (var columnInfo in RevitScheduleUtils.ScheduleColumnIteration(revitSchedule)) + { + AddColumnMetadataToDataTable(columnInfo, revitSchedule, speckleTable, columnHeaders, firstType, firstElement); + } + } + + private static void AddColumnMetadataToDataTable( + ScheduleColumnIterationInfo info, + ViewSchedule revitSchedule, + DataTable speckleTable, + List columnHeaders, + Element firstType, + Element firstElement + ) + { + // add column header to list for potential future use + columnHeaders.Add(info.field.ColumnHeading); + + var builtInParameter = (BuiltInParameter)info.field.ParameterId.IntegerValue; + + var columnMetadata = new Base(); + columnMetadata["BuiltInParameterInteger"] = info.field.ParameterId.IntegerValue; + columnMetadata["FieldType"] = info.field.FieldType.ToString(); + + Parameter param; + if (info.field.FieldType == ScheduleFieldType.ElementType) + { + if (firstType != null) + { + param = firstType.get_Parameter(builtInParameter); + columnMetadata["IsReadOnly"] = param?.IsReadOnly; + } + } + else if (info.field.FieldType == ScheduleFieldType.Instance) + { + if (firstElement != null) + { + param = firstElement.get_Parameter(builtInParameter); + columnMetadata["IsReadOnly"] = param?.IsReadOnly; + } + } + else + { + var scheduleCategory = (BuiltInCategory)revitSchedule.Definition.CategoryId.IntegerValue; + SpeckleLog.Logger.Warning( + "Schedule of category, {scheduleCategory}, contains field of type {builtInParameter} which has an unsupported field type, {fieldType}", + scheduleCategory, + builtInParameter, + info.field.FieldType.ToString() + ); + } + speckleTable.DefineColumn(columnMetadata); + } + + private void PopulateDataTableRows( + ViewSchedule revitSchedule, + DataTable speckleTable, + ICollection originalTableIds, + int[] columnHeaderIndexArray, + List columnHeaders + ) + { + var minHeaderIndex = columnHeaderIndexArray.Min(); + var maxHeaderIndex = columnHeaderIndexArray.Max(); + speckleTable.headerRowIndex = maxHeaderIndex; + foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) + { + var rowValues = new List(); + + if (rowInfo.masterRowIndex == maxHeaderIndex) + { + rowValues = columnHeaders; + } + else + { + rowValues = GetRowValues(revitSchedule, rowInfo.tableSection, rowInfo.columnCount, rowInfo.rowIndex); + } + + if (rowInfo.masterRowIndex >= minHeaderIndex && rowInfo.masterRowIndex < maxHeaderIndex) + { + for (var i = 0; i < rowInfo.columnCount; i++) + { + if (columnHeaderIndexArray[i] == rowInfo.masterRowIndex) + { + rowValues[i] = string.Empty; + } + } + } + + var rowAdded = AddRowToSpeckleTable( + revitSchedule, + speckleTable, + originalTableIds, + rowInfo.tableSection, + rowInfo.section, + rowValues, + rowInfo.rowIndex + ); + if (!rowAdded && rowInfo.masterRowIndex < maxHeaderIndex) + { + speckleTable.headerRowIndex--; + } + } + } + + private int[] GetTableHeaderIndexArray(ViewSchedule revitSchedule, List columnHeaders) + { + if (!revitSchedule.Definition.ShowHeaders) + { + return TransactionManager.ExecuteInTemporaryTransaction( + () => + { + revitSchedule.Definition.ShowHeaders = true; + return GetHeaderIndexArrayFromScheduleWithHeaders(revitSchedule, columnHeaders); + }, + revitSchedule.Document + ); + } + + return GetHeaderIndexArrayFromScheduleWithHeaders(revitSchedule, columnHeaders); + } + + private static int[] GetHeaderIndexArrayFromScheduleWithHeaders( + ViewSchedule revitSchedule, + List columnHeaders + ) + { + string nextCellValue = null; + var headerIndexArray = new int[columnHeaders.Count]; + var headersSetArray = new bool[columnHeaders.Count]; + foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) + { + if (rowInfo.columnCount != columnHeaders.Count) + { + continue; + } + + for (var columnIndex = 0; columnIndex < rowInfo.columnCount; columnIndex++) + { + if (headersSetArray[columnIndex]) + { + continue; + } + + var cellValue = revitSchedule.GetCellText(rowInfo.tableSection, rowInfo.rowIndex, columnIndex); + if (cellValue != columnHeaders[columnIndex]) + { + continue; + } + + headerIndexArray[columnIndex] = rowInfo.masterRowIndex; + headersSetArray[columnIndex] = true; + + if (!headersSetArray.Where(o => o == false).Any()) + { + return headerIndexArray; + } + } + } + return Enumerable.Repeat(0, columnHeaders.Count).ToArray(); + } + + private bool AddRowToSpeckleTable( + ViewSchedule revitSchedule, + DataTable speckleTable, + ICollection originalTableIds, + SectionType tableSection, + TableSectionData section, + List rowValues, + int rowIndex + ) + { + if (!rowValues.Where(s => !string.IsNullOrEmpty(s)).Any()) + { + return false; + } + var metadata = new Base(); + metadata["RevitApplicationIds"] = ElementApplicationIdsInRow( + rowIndex, + section, + originalTableIds, + revitSchedule, + tableSection + ) + .ToList(); + + try + { + speckleTable.AddRow(metadata: metadata, objects: rowValues.ToArray()); + } + catch (ArgumentException) + { + // trying to add an invalid row. Just don't add it and continue to the next + return false; + } + + return true; + } + + private static List GetRowValues( + ViewSchedule revitSchedule, + SectionType tableSection, + int columnCount, + int rowIndex + ) + { + var rowData = new List(); + for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) + { + rowData.Add(revitSchedule.GetCellText(tableSection, rowIndex, columnIndex)); + } + + return rowData; + } + #endregion + + public static IEnumerable ElementApplicationIdsInRow( + int rowNumber, + TableSectionData section, + ICollection orginialTableIds, + DB.ViewSchedule revitSchedule, + SectionType tableSection + ) + { + var remainingIdsInRow = TransactionManager.ExecuteInTemporaryTransaction( + () => + { + section.RemoveRow(rowNumber); + return new FilteredElementCollector(revitSchedule.Document, revitSchedule.Id).ToElementIds().ToList(); + }, + revitSchedule.Document + ); + + // the section must be recomputed here because of our hacky row deleting trick + var table = revitSchedule.GetTableData(); + section = table.GetSectionData(tableSection); + + if (remainingIdsInRow == null || remainingIdsInRow.Count == orginialTableIds.Count) + { + yield break; + } + + foreach (var id in orginialTableIds) + { + if (remainingIdsInRow.Contains(id)) + { + continue; + } + + yield return revitSchedule.Document.GetElement(id).UniqueId; + } + } +} + +public struct RevitParameterData +{ + public int ColumnIndex; + public BuiltInParameter Parameter; + public bool IsTypeParam; +} + +public struct ScheduleRowIterationInfo +{ + public SectionType tableSection; + public TableSectionData section; + public int rowIndex; + public int columnCount; + public int masterRowIndex; +} + +public struct ScheduleColumnIterationInfo +{ + public ScheduleField field; + public int columnIndex; + public int columnCount; + public int numHiddenFields; +} + +public static class RevitScheduleUtils +{ + public static IEnumerable ScheduleRowIteration( + ViewSchedule revitSchedule, + Dictionary> skippedIndicies = null + ) + { + var masterRowIndex = 0; + + foreach (SectionType tableSection in Enum.GetValues(typeof(SectionType))) + { + // the table must be recomputed here because of our hacky row deleting trick + var table = revitSchedule.GetTableData(); + var section = table.GetSectionData(tableSection); + + if (section == null) + { + continue; + } + var rowCount = section.NumberOfRows; + var columnCount = section.NumberOfColumns; + + for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) + { + yield return new ScheduleRowIterationInfo + { + tableSection = tableSection, + section = section, + rowIndex = rowIndex, + columnCount = columnCount, + masterRowIndex = masterRowIndex + }; + + if ( + skippedIndicies == null + || !skippedIndicies.TryGetValue(tableSection, out var indicies) + || !indicies.Contains(rowIndex) + ) + { + // this "skippedIndicies" dict contains the indicies that contain only empty values + // these values were skipped when adding them to the DataTable, so the indicies of the revitSchedule + // and the Speckle DataTable will differ at these indicies (and all subsequent indicies) + + // therefore we only want to increment the masterRowIndex if this row was added to the Speckle DataTable + masterRowIndex++; + } + } + } + } + + public static IEnumerable ScheduleColumnIteration(ViewSchedule revitSchedule) + { + var scheduleFieldOrder = revitSchedule.Definition.GetFieldOrder(); + var numHiddenFields = 0; + + for (var columnIndex = 0; columnIndex < scheduleFieldOrder.Count; columnIndex++) + { + var field = revitSchedule.Definition.GetField(scheduleFieldOrder[columnIndex]); + + // we cannot get the values for hidden fields, so we need to subtract one from the index that is passed to + // tableView.GetCellText. + if (field.IsHidden) + { + numHiddenFields++; + continue; + } + + yield return new ScheduleColumnIterationInfo + { + field = field, + columnIndex = columnIndex, + columnCount = scheduleFieldOrder.Count, + numHiddenFields = numHiddenFields + }; + } + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.cs new file mode 100644 index 0000000000..045bfc262f --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertView.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Autodesk.Revit.DB; +using Speckle.Core.Logging; +using Speckle.Core.Kits; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using View = Objects.BuiltElements.View; +using View3D = Objects.BuiltElements.View3D; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private List excludedParameters = + new() + { + "VIEW_NAME", // param value is already stored in name prop of view and setting this param can cause errors + }; + + public Base ViewToSpeckle(DB.View revitView) + { + switch (revitView) + { + case DB.View3D o: + return View3DToSpeckle(o); + case DB.ViewSchedule o: + return ScheduleToSpeckle(o); + default: + var speckleView = new View(); + GetAllRevitParamsAndIds(speckleView, revitView, excludedParameters); + Report.Log($"Converted View {revitView.ViewType} {revitView.Id}"); + return speckleView; + } + } + + public View View3DToSpeckle(DB.View3D revitView) + { + switch (revitView.ViewType) + { + case ViewType.FloorPlan: + break; + case ViewType.CeilingPlan: + break; + case ViewType.Elevation: + break; + case ViewType.Section: + break; + case ViewType.ThreeD: + break; + default: + break; + } + + var speckleView = new View(); + + if (revitView is DB.View3D rv3d) + { + // some views have null origin, not sure why, but for now we just ignore them and don't bother the user + if (rv3d.Origin == null) + { + throw new ConversionSkippedException($"Views with no origin are not supported"); + } + + // get orientation + var forward = rv3d.GetSavedOrientation().ForwardDirection; // this is unit vector + var up = rv3d.GetSavedOrientation().UpDirection; // this is unit vector + + // get target + var target = PointToSpeckle(CalculateTarget(rv3d, forward), revitView.Document); + + speckleView = new View3D + { + origin = PointToSpeckle(rv3d.Origin, revitView.Document), + forwardDirection = VectorToSpeckle(forward, revitView.Document, Speckle.Core.Kits.Units.None), + upDirection = VectorToSpeckle(up, revitView.Document, Speckle.Core.Kits.Units.None), + target = target, + isOrthogonal = !rv3d.IsPerspective, + boundingBox = BoxToSpeckle(rv3d.CropBox, revitView.Document), + name = revitView.Name + }; + + // set props + AttachViewParams(speckleView, rv3d); + } + + GetAllRevitParamsAndIds(speckleView, revitView, excludedParameters); + Report.Log($"Converted View {revitView.ViewType} {revitView.Id}"); + return speckleView; + } + + public ApplicationObject ViewToNative(View3D speckleView) + { + var appObj = new ApplicationObject(speckleView.id, speckleView.speckle_type) + { + applicationId = speckleView.applicationId + }; + + DB.View3D view = null; + var viewNameSplit = speckleView.name.Split('-'); + + // get orientation + var up = new XYZ(speckleView.upDirection.x, speckleView.upDirection.y, speckleView.upDirection.z).Normalize(); //unit vector + var forward = new XYZ( + speckleView.forwardDirection.x, + speckleView.forwardDirection.y, + speckleView.forwardDirection.z + ).Normalize(); + if (Math.Round(up.DotProduct(forward), 3) != 0) // will throw error if vectors are not perpendicular + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: "The up and forward vectors for this view are not perpendicular." + ); + return appObj; + } + var orientation = new ViewOrientation3D(PointToNative(speckleView.origin), up, forward); + + var editViewName = EditViewName(speckleView.name, "SpeckleView"); + // get the existing view with this name, if there is one + view = new FilteredElementCollector(Doc) + .WhereElementIsNotElementType() + .OfClass(typeof(DB.View3D)) + .Cast() + .FirstOrDefault(o => o.Name == editViewName); + + if (view == null) + { + // get view3d type + var viewType = new FilteredElementCollector(Doc) + .WhereElementIsElementType() + .OfClass(typeof(ViewFamilyType)) + .ToElements() + .Cast() + .FirstOrDefault(o => o.ViewFamily == ViewFamily.ThreeDimensional); + + // create view + if (speckleView.isOrthogonal) + { + view = DB.View3D.CreateIsometric(Doc, viewType.Id); + } + else + { + view = DB.View3D.CreatePerspective(Doc, viewType.Id); + } + + view.Name = editViewName; + appObj.Update(status: ApplicationObject.State.Created); + } + else if (view.IsLocked) + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"View named {editViewName} is locked and cannot be modified." + ); + return appObj; + } + else + { + appObj.Update(status: ApplicationObject.State.Updated); + } + + // set props + view.SetOrientation(orientation); + view.SaveOrientationAndLock(); + + if (view.IsValidObject) + { + SetInstanceParameters(view, speckleView, excludedParameters); + } + + view = SetViewParams(view, speckleView); + + appObj.Update(createdId: view.UniqueId, convertedItem: view); + return appObj; + } + + private void AttachViewParams(View speckleView, DB.View view) + { + // display + speckleView["display"] = view.DisplayStyle.ToString(); + + // crop + speckleView["cropped"] = view.CropBoxActive.ToString(); + } + + private DB.View3D SetViewParams(DB.View3D view, Base speckleView) + { + // display + var display = speckleView["display"] as string; + if (display != null) + { + var style = Enum.Parse(typeof(DisplayStyle), display); + view.DisplayStyle = (style != null) ? (DisplayStyle)style : DisplayStyle.Wireframe; + } + + // crop + var crop = speckleView["cropped"] as string; + if (crop != null) + { + if (bool.TryParse(crop, out bool IsCropped)) + { + view.CropBoxActive = IsCropped; + } + } + + return view; + } + + private XYZ CalculateTarget(DB.View3D view, XYZ forward) + { + var target = view.Origin.Add(forward * (view.CropBox.Max.Z - view.CropBox.Min.Z)); + var targetElevation = view.get_Parameter(BuiltInParameter.VIEWER_TARGET_ELEVATION).AsDouble(); + if (target.Z != targetElevation) // check if target matches stored elevation + { + double magnitude = (targetElevation - view.Origin.Z) / forward.Z; + target = view.Origin.Add(forward * magnitude); + } + return target; + } + + private string EditViewName(string name, string prefix = null) + { + var viewNameSplit = name.Split('-'); + // if the name already starts with the prefix, don't add the prefix again + if (viewNameSplit.Length > 0 && viewNameSplit.First() == prefix) + { + return name; + } + + var newName = name; + // append commit info as prefix + if (prefix != null) + { + newName = prefix + "-" + name; + } + + // Check for invalid characters in view name + var results = new Regex("[\\{\\}\\[\\]\\:|;<>?`~]").Match(newName); + + // If none, fast exit + if (results.Length <= 0) + { + return newName; + } + + // Name contains invalid characters, replace accordingly. + var corrected = Regex.Replace(newName, "[\\{\\[]", "("); + corrected = Regex.Replace(corrected, "[\\}\\]]", ")"); + corrected = Regex.Replace(corrected, "[\\:|;<>?`~]", "-"); + + Report.Log($@"Renamed view {name} to {corrected} due to invalid characters."); + + return corrected; + } + + /// + /// Converts a Speckle comment camera coordinates into Revit's + /// First three values are the camera's position, second three the target + /// + /// + /// + public DB.ViewOrientation3D ViewOrientation3DToNative(Base baseCamera) + { + //hacky but the current comments camera is not a Base object + var speckleCamera = baseCamera["coordinates"] as List; + var position = new Objects.Geometry.Point(speckleCamera[0], speckleCamera[1], speckleCamera[2]); + var target = new Objects.Geometry.Point(speckleCamera[3], speckleCamera[4], speckleCamera[5]); + + var cameraTarget = PointToNative(target); + var cameraPosition = PointToNative(position); + var cameraDirection = (cameraTarget.Subtract(cameraPosition)).Normalize(); + var cameraUpVector = cameraDirection.CrossProduct(XYZ.BasisZ).CrossProduct(cameraDirection); + + return new ViewOrientation3D(cameraPosition, cameraUpVector, cameraDirection); + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs new file mode 100644 index 0000000000..6046ac0b7a --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using RevitSharedResources.Models; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB; +using Mesh = Objects.Geometry.Mesh; +using OG = Objects.Geometry; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + // CAUTION: these strings need to have the same values as in the connector + const string StructuralWalls = "Structural Walls"; + const string ArchitecturalWalls = "Achitectural Walls"; + + public ApplicationObject WallToNative(BuiltElements.Wall speckleWall) + { + var revitWall = GetExistingElementByApplicationId(speckleWall.applicationId) as DB.Wall; + var appObj = new ApplicationObject(speckleWall.id, speckleWall.speckle_type) + { + applicationId = speckleWall.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(revitWall, appObj)) + { + return appObj; + } + + if (speckleWall.baseLine == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Baseline was null"); + return appObj; + } + + var wallType = GetElementType(speckleWall, appObj, out bool isExactMatch); + if (wallType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + var baseCurve = CurveToNative(speckleWall.baseLine).get_Item(0); + + List joinSettings = new(); + + if (Settings.ContainsKey("disallow-join") && !string.IsNullOrEmpty(Settings["disallow-join"])) + { + joinSettings = new List(Regex.Split(Settings["disallow-join"], @"\,\ ")); + } + + var levelState = ApplicationObject.State.Unknown; + double baseOffset = 0.0; + Level level = + (speckleWall.level != null) + ? ConvertLevelToRevit(speckleWall.level, out levelState) + : ConvertLevelToRevit(baseCurve, out levelState, out baseOffset); + + var structural = false; + if (speckleWall is RevitWall speckleRevitWall) + { + structural = speckleRevitWall.structural; + } + + //if it's a new element, we don't need to update certain properties + bool isUpdate = true; + if (revitWall == null) + { + isUpdate = false; + revitWall = DB.Wall.Create(Doc, baseCurve, wallType.Id, level.Id, 1, 0, false, structural); + if (joinSettings.Contains(StructuralWalls) && structural) + { + WallUtils.DisallowWallJoinAtEnd(revitWall, 0); + WallUtils.DisallowWallJoinAtEnd(revitWall, 1); + } + if (joinSettings.Contains(ArchitecturalWalls) && !structural) + { + WallUtils.DisallowWallJoinAtEnd(revitWall, 0); + WallUtils.DisallowWallJoinAtEnd(revitWall, 1); + } + } + if (revitWall == null) + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); + return appObj; + } + + //is structural update + TrySetParam(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT, structural); + + if (isExactMatch && revitWall.WallType.Name != wallType.Name) + { + revitWall.ChangeTypeId(wallType.Id); + } + + if (isUpdate) + { + // walls behave very strangly while joined + // if a wall is joined and you try to move it to a location where it isn't touching the joined wall, + // then it will move only one end of the wall and the other will stay joined + // therefore, disallow joins while changing the wall and then reallow the joins if need be + WallUtils.DisallowWallJoinAtEnd(revitWall, 0); + WallUtils.DisallowWallJoinAtEnd(revitWall, 1); + + //NOTE: updating an element location can be buggy if the baseline and level elevation don't match + //Let's say the first time an element is created its base point/curve is @ 10m and the Level is @ 0m + //the element will be created @ 0m + //but when this element is updated (let's say with no changes), it will jump @ 10m (unless there is a level change)! + //to avoid this behavior we're moving the base curve to match the level elevation + var newz = baseCurve.GetEndPoint(0).Z; + var offset = level.Elevation - newz; + var newCurve = baseCurve; + if (Math.Abs(offset) > TOLERANCE) // level and curve are not at the same height + { + newCurve = baseCurve.CreateTransformed(Transform.CreateTranslation(new XYZ(0, 0, offset))); + } + + ((LocationCurve)revitWall.Location).Curve = newCurve; + + TrySetParam(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT, level); + + // now that we've moved the wall, rejoin the wall ends + if (!joinSettings.Contains(StructuralWalls) && structural) + { + WallUtils.AllowWallJoinAtEnd(revitWall, 0); + WallUtils.AllowWallJoinAtEnd(revitWall, 1); + } + if (!joinSettings.Contains(ArchitecturalWalls) && !structural) + { + WallUtils.AllowWallJoinAtEnd(revitWall, 0); + WallUtils.AllowWallJoinAtEnd(revitWall, 1); + } + } + + if (speckleWall is RevitWall spklRevitWall) + { + if (spklRevitWall.flipped != revitWall.Flipped) + { + revitWall.Flip(); + } + + if (spklRevitWall.topLevel != null) + { + var topLevel = ConvertLevelToRevit(spklRevitWall.topLevel, out levelState); + TrySetParam(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE, topLevel); + } + else + { + TrySetParam(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM, speckleWall.height, speckleWall.units); + } + + TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, spklRevitWall.baseOffset, speckleWall.units); + TrySetParam(revitWall, BuiltInParameter.WALL_TOP_OFFSET, spklRevitWall.topOffset, speckleWall.units); + } + else + { + // Set wall unconnected height. + TrySetParam(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM, speckleWall.height, speckleWall.units); + + TrySetParam(revitWall, BuiltInParameter.WALL_BASE_OFFSET, -baseOffset); + } + + SetInstanceParameters(revitWall, speckleWall); + + var state = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: state, createdId: revitWall.UniqueId, convertedItem: revitWall); + + SetWallVoids(revitWall, speckleWall); + //appObj = SetHostedElements(speckleWall, revitWall, appObj); + return appObj; + } + + public Base WallToSpeckle(DB.Wall revitWall, out List notes) + { + notes = new List(); + var baseGeometry = LocationToSpeckle(revitWall); + if (baseGeometry is Geometry.Point) + { + return RevitElementToSpeckle(revitWall, out notes); + } + + RevitWall speckleWall = new(); + speckleWall.family = revitWall.WallType.FamilyName.ToString(); + speckleWall.type = revitWall.WallType.Name; + speckleWall.baseLine = (ICurve)baseGeometry; + speckleWall.level = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT); + speckleWall.topLevel = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE); + speckleWall.height = GetParamValue(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + speckleWall.baseOffset = GetParamValue(revitWall, BuiltInParameter.WALL_BASE_OFFSET); + speckleWall.topOffset = GetParamValue(revitWall, BuiltInParameter.WALL_TOP_OFFSET); + speckleWall.structural = GetParamValue(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); + speckleWall.flipped = revitWall.Flipped; + + //CreateVoids(revitWall, speckleWall); + + if (revitWall.CurtainGrid is not CurtainGrid grid) + { + if (revitWall.IsStackedWall) + { + var wallMembers = revitWall.GetStackedWallMemberIds().Select(id => (Wall)revitWall.Document.GetElement(id)); + speckleWall.elements = new List(); + foreach (var wall in wallMembers) + { + speckleWall.elements.Add(WallToSpeckle(wall, out List stackedWallNotes)); + } + } + + speckleWall.displayValue = GetElementDisplayValue(revitWall); + } + else + { + speckleWall.displayValue = new List(); // avoids null value for curtain walls + AddHostedDependentElements( + revitWall, + speckleWall, + GetSubsetOfElementsInView(BuiltInCategory.OST_CurtainWallMullions, grid.GetMullionIds()).ToList() + ); + AddHostedDependentElements( + revitWall, + speckleWall, + GetSubsetOfElementsInView(BuiltInCategory.OST_CurtainWallPanels, grid.GetPanelIds()).ToList() + ); + } + + GetAllRevitParamsAndIds( + speckleWall, + revitWall, + new List + { + "WALL_USER_HEIGHT_PARAM", + "WALL_BASE_OFFSET", + "WALL_TOP_OFFSET", + "WALL_BASE_CONSTRAINT", + "WALL_HEIGHT_TYPE", + "WALL_STRUCTURAL_SIGNIFICANT" + } + ); + + GetWallVoids(speckleWall, revitWall); + GetHostedElements(speckleWall, revitWall, out List hostedNotes); + if (hostedNotes.Any()) + { + notes.AddRange(hostedNotes); + } + + return speckleWall; + } + + private IEnumerable GetSubsetOfElementsInView(BuiltInCategory category, IEnumerable children) + { + if (ViewSpecificOptions == null) + { + return children; + } + + var allSubelementsInView = revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType>(out _) + .GetOrAdd( + category.ToString(), + () => + { + using var filter = new ElementCategoryFilter(category); + using var collector = new FilteredElementCollector(Doc, ViewSpecificOptions.View.Id); + + return new HashSet(collector.WhereElementIsNotElementType().WherePasses(filter).ToElementIds()); + }, + out _ + ); + + return children.Where(allSubelementsInView.Contains); + } + + //this is to prevent duplicated panels & mullions from being sent in curtain walls + //might need improvement in the future + //see https://github.com/specklesystems/speckle-sharp/issues/1197 + private List SubelementIds = new(); + + private void GetWallVoids(Base speckleElement, Wall wall) + { +#if !REVIT2020 && !REVIT2021 + var profile = ((Sketch)Doc.GetElement(wall.SketchId))?.Profile; + + if (profile == null) + { + return; + } + + var voidsList = new List(); + for (var i = 1; i < profile.Size; i++) + { + var segments = CurveListToSpeckle(profile.get_Item(i).Cast().ToList(), wall.Document); + if (segments.segments.Count() > 2) + { + voidsList.Add(segments); + } + } + if (voidsList.Count > 0) + { + speckleElement["voids"] = voidsList; + } +#endif + } + + private void SetWallVoids(Wall wall, Base speckleElement) + { +#if !REVIT2020 && !REVIT2021 + if (speckleElement["voids"] == null || !(speckleElement["voids"] is IList voidCurves)) + { + return; + } + + if (wall.SketchId.IntegerValue == -1) + { + Doc.Regenerate(); + wall.CreateProfileSketch(); + } + else + { + // TODO: actually update the profile in order to keep the user's dimensions + wall.RemoveProfileSketch(); + wall.CreateProfileSketch(); + } + + // need to regen doc in order for the sketch to have an id + Doc.Regenerate(); + var sketch = (Sketch)Doc.GetElement(wall.SketchId); + + transactionManager.Commit(); + var sketchEditScope = new SketchEditScope(Doc, "Add profile to the sketch"); + sketchEditScope.Start(sketch.Id); + transactionManager.StartSubtransaction(); + + foreach (var obj in voidCurves) + { + if (!(obj is ICurve @void)) + { + continue; + } + + var curveArray = CurveToNative(@void, true); + Doc.Create.NewModelCurveArray(curveArray, sketch.SketchPlane); + } + if (transactionManager.Commit() != TransactionStatus.Committed) + { + sketchEditScope.Cancel(); + } + + try + { + sketchEditScope.Commit(new ErrorEater()); + } + catch (Exception ex) + { + if (sketchEditScope.IsActive) + { + sketchEditScope.Cancel(); + } + } + finally + { + transactionManager.StartSubtransaction(); + } +#endif + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWire.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWire.cs new file mode 100644 index 0000000000..97938000d9 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWire.cs @@ -0,0 +1,167 @@ +using System.Collections.Generic; +using System.Linq; +using Autodesk.Revit.DB; +using ConverterRevitShared.Extensions; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using Curve = Objects.Geometry.Curve; +using DB = Autodesk.Revit.DB; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject WireToNative(BuiltElements.Wire speckleWire) + { + var speckleRevitWire = speckleWire as RevitWire; + + var docObj = GetExistingElementByApplicationId(speckleWire.applicationId); + var appObj = new ApplicationObject(speckleWire.id, speckleWire.speckle_type) + { + applicationId = speckleWire.applicationId + }; + + // skip if element already exists in doc & receive mode is set to ignore + if (IsIgnore(docObj, appObj)) + { + return appObj; + } + + var wiringType = + speckleRevitWire?.wiringType == "Chamfer" ? DB.Electrical.WiringType.Chamfer : DB.Electrical.WiringType.Arc; + var wireType = GetElementType(speckleWire, appObj, out bool _); + if (wireType == null) + { + appObj.Update(status: ApplicationObject.State.Failed); + return appObj; + } + + // get construction points (if wire is from Revit, these are not the same as the geometry points) + var points = new List(); + if (speckleRevitWire != null) + { + points = PointListToNative(speckleRevitWire.constructionPoints, speckleRevitWire.units); + } + else + { + foreach (var segment in speckleWire.segments) + { + switch (segment) + { + case Curve curve: + points.AddRange(PointListToNative(curve.points)); + break; + case Polyline line: + points.AddRange(PointListToNative(line.value)); + break; + default: // what other curves should be supported? currently just the ones you can create from revit + appObj.Update(logItem: $"Wire segment geometry of type {segment.GetType()} not currently supported"); + break; + } + } + } + + DB.Electrical.Wire wire = null; + if (docObj != null) + { + wire = (DB.Electrical.Wire)docObj; + // if the number of vertices doesn't match, we need to create a new wire + if (wire.NumberOfVertices != points.Count) + { + wire = null; + } + } + + // update points if we can + if (wire != null) + { + for (var i = 0; i < wire.NumberOfVertices; i++) + { + if (points[i].IsAlmostEqualTo(wire.GetVertex(i))) + { + continue; // borks if we set the same point + } + + wire.SetVertex(i, points[i]); + } + } + + var isUpdate = wire != null; + // create a new one if there isn't one to update + wire ??= DB.Electrical.Wire.Create(Doc, wireType.Id, Doc.ActiveView.Id, wiringType, points, null, null); + + if (speckleRevitWire != null) + { + SetInstanceParameters(wire, speckleRevitWire); + } + else + { + appObj.Update(status: ApplicationObject.State.Failed, logItem: "Creation returned null"); + return appObj; + } + + CreateSystemConnections(speckleRevitWire.Connectors, wire, receivedObjectsCache); + + var status = isUpdate ? ApplicationObject.State.Updated : ApplicationObject.State.Created; + appObj.Update(status: status, createdId: wire.UniqueId, convertedItem: wire); + return appObj; + } + + public BuiltElements.Wire WireToSpeckle(DB.Electrical.Wire revitWire) + { + var speckleWire = new RevitWire + { + family = revitWire.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM).AsValueString(), + type = revitWire.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString(), + wiringType = revitWire.get_Parameter(BuiltInParameter.RBS_ELEC_WIRE_TYPE).AsValueString(), + level = ConvertAndCacheLevel(revitWire.ReferenceLevel.Id, revitWire.Document) + }; + + // construction geometry for creating the wire on receive (doesn't match geometry points 🙃) + var points = new List(); + for (var i = 0; i < revitWire.NumberOfVertices; i++) + { + points.AddRange(PointToSpeckle(revitWire.GetVertex(i), revitWire.Document).ToList()); + } + + speckleWire.constructionPoints = points; + + // geometry + var start = ((LocationCurve)revitWire.Location).Curve.GetEndPoint(0); + speckleWire.segments = new List(); + var view = (View)revitWire.Document.GetElement(revitWire.OwnerViewId); + var segmentList = revitWire.get_Geometry(new Options { View = view }).ToList(); + foreach (var segment in segmentList) + { + // transform and convert the geometry segments + switch (segment) + { + case DB.PolyLine polyLine: + var revitLine = polyLine.GetTransformed(Transform.CreateTranslation(new XYZ(0, 0, start.Z))); + var line = PolylineToSpeckle(revitLine, revitWire.Document); + speckleWire.segments.Add(line); + break; + case DB.NurbSpline nurbSpline: + var revitCurve = nurbSpline.CreateTransformed(Transform.CreateTranslation(new XYZ(0, 0, start.Z))); + // add display value + var curve = (Curve)CurveToSpeckle(revitCurve, revitWire.Document); + var polyCoords = revitCurve + .Tessellate() + .SelectMany(pt => PointToSpeckle(pt, revitWire.Document).ToList()) + .ToList(); + curve.displayValue = new Polyline(polyCoords, ModelUnits); + speckleWire.segments.Add(curve); + break; + } + } + + GetAllRevitParamsAndIds(speckleWire, revitWire, new List()); + foreach (var connector in revitWire.GetConnectorSet()) + { + speckleWire.Connectors.Add(ConnectorToSpeckle(connector)); + } + return speckleWire; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertZone.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertZone.cs new file mode 100644 index 0000000000..252a5cf45c --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertZone.cs @@ -0,0 +1,191 @@ +using System; +using System.Linq; +using Autodesk.Revit.DB; +using Objects.BuiltElements; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; +using DB = Autodesk.Revit.DB.Mechanical; +using Level = Autodesk.Revit.DB.Level; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject ZoneToNative(RevitZone speckleZone) + { + var revitZone = ConvertZoneToRevit(speckleZone, out ApplicationObject.State state); + var appObj = new ApplicationObject(speckleZone.id, speckleZone.speckle_type) + { + applicationId = speckleZone.applicationId + }; + appObj.Update(status: state, createdId: revitZone.UniqueId, convertedItem: revitZone); + return appObj; + } + + public DB.Zone ConvertZoneToRevit(RevitZone speckleZone, out ApplicationObject.State state) + { + state = ApplicationObject.State.Unknown; + + if (speckleZone == null) + { + return null; + } + + var revitZone = GetExistingZone(speckleZone); + + var targetPhase = DetermineTargetPhase(speckleZone, revitZone); + + var revitZoneLevel = ConvertLevelToRevit(speckleZone.level, out _); + if (revitZone == null) + { + DB.Zone sameNameZone = GetZoneWithSameName(speckleZone); + + if (sameNameZone != null && sameNameZone.Phase.Name == speckleZone.phaseName) + { + revitZone = sameNameZone; + } + else + { + if (sameNameZone != null) + { + Doc.Delete(sameNameZone.Id); + Doc.Regenerate(); + } + + revitZone = CreateRevitZone(revitZoneLevel, targetPhase, speckleZone.name); + } + } + else + { + revitZone.Name = speckleZone.name; + } + + SetInstanceParameters(revitZone, speckleZone); + + var getSameNameZone = GetZoneWithSameName(speckleZone); + + state = ApplicationObject.State.Updated; + + return revitZone; + } + + private DB.Zone GetExistingZone(RevitZone speckleZone) + { + return GetExistingElementByApplicationId(speckleZone.applicationId) as DB.Zone; + } + + private DB.Zone GetZoneWithSameName(RevitZone speckleZone) + { + var docZones = new FilteredElementCollector(Doc).OfClass(typeof(DB.Zone)).ToElements().Cast(); + + return docZones.FirstOrDefault(x => x.Name == speckleZone.name); + } + + public DB.Zone CreateRevitZone(Level revitZoneLevel, Phase targetPhase, string zoneName = null) + { + var newZone = Doc.Create.NewZone(revitZoneLevel, targetPhase); + + if (zoneName != null) + { + newZone.Name = zoneName; + } + + Doc.Regenerate(); + return newZone; + } + + /// + /// Determines the target phase for a space based on available information. + /// + /// The Space object from the Speckle system. + /// The Space object from the Revit system. + /// The determined target Phase object. + /// + /// The method tries to determine the target phase based on the following priority: + /// 1. Phase from the Speckle space (if it exists). + /// 2. Phase from the existing Revit space (if it exists). + /// 3. Phase from the active view in Revit. + /// + private Phase DetermineTargetPhase(RevitZone speckleZone, DB.Zone revitZone) + { + // Get all phases + var phases = Doc.Phases.Cast(); + + // Determine existing space phase, if any + Phase existingZonePhase = null; + if (revitZone != null) + { + string existingZonePhaseName = revitZone.Phase.ToString(); + existingZonePhase = phases.FirstOrDefault(x => x.Name == existingZonePhaseName); + } + + // Determine active view phase + string activeViewPhaseName = Doc.ActiveView.get_Parameter(BuiltInParameter.VIEW_PHASE).AsValueString(); + var activeViewPhase = phases.FirstOrDefault(x => x.Name == activeViewPhaseName); + + // Determine target phase + // Priority: speckleSpace phase > existing space phase > active view phase + string targetPhaseName = speckleZone.phaseName; + var targetPhase = phases.FirstOrDefault(x => x.Name == targetPhaseName) ?? existingZonePhase ?? activeViewPhase; + + return targetPhase; + } + + /// + /// Handles the Revit Zone based on the provided Speckle Space and target phase. + /// + /// The Space object from the Speckle system. + /// The existing Revit Zone object. This may be modified by the method. + /// The target Phase object. + /// The Level object associated with the space. + /// The modified or newly created Revit Zone object. + private DB.Zone CreateRevitZoneIfNeeded(Space speckleSpace, DB.Zone revitZone, Phase targetPhase, Level level) + { + var zoneName = speckleSpace.zone != null ? speckleSpace.zone.name : speckleSpace.zoneName; // zoneName is the previous property retained here for backwards compatibility. + + if (revitZone == null && !string.IsNullOrEmpty(zoneName)) + { + revitZone = ConvertZoneToRevit(speckleSpace.zone, out _); + } + else if (revitZone != null && revitZone.Phase.Name != targetPhase.Name) + { + Doc.Delete(revitZone.Id); + + revitZone = string.IsNullOrEmpty(speckleSpace.zone.name) + ? ConvertZoneToRevit(speckleSpace.zone, out _) + : CreateRevitZone(level, targetPhase); + + revitZone.Name = speckleSpace.zone.name; + } + + return revitZone; + } + + public RevitZone ZoneToSpeckle(DB.Zone revitZone) + { + var speckleZone = new RevitZone + { + name = revitZone.Name, + area = GetParamValue(revitZone, BuiltInParameter.ROOM_AREA), + volume = GetParamValue(revitZone, BuiltInParameter.ROOM_VOLUME), + perimeter = GetParamValue(revitZone, BuiltInParameter.ZONE_PERIMETER), + serviceType = revitZone.ServiceType.ToString() + }; + + var level = revitZone.Spaces.Cast().Select(x => x.Level).First(); + + if (level != null) + { + speckleZone.level = LevelToSpeckle(level); + } + + GetAllRevitParamsAndIds(speckleZone, revitZone); + + // No implicit displayValue + // speckleZone.displayValue = GetElementDisplayValue(revitSpace); + + speckleZone["phaseName"] = revitZone.Phase.Name; + + return speckleZone; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/DirectShape.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/DirectShape.cs similarity index 52% rename from Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/DirectShape.cs rename to Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/DirectShape.cs index e2cd058f9f..98b1e56246 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Partial Classes/DirectShape.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/DirectShape.cs @@ -15,46 +15,51 @@ namespace Objects.Converter.Revit { public partial class ConverterRevit { - public ApplicationPlaceholderObject DirectShapeToNative(DirectShape speckleDs) { var docObj = GetExistingElementByApplicationId(speckleDs.applicationId); - //just create new one + //just create new one if (docObj != null) { Doc.Delete(docObj.Id); } - + var converted = new List(); - - speckleDs.baseGeometries.ToList().ForEach(b => - { - switch (b) + + speckleDs.baseGeometries + .ToList() + .ForEach(b => { - case Brep brep: - try - { - var solid = BrepToNative(brep); - converted.Add(solid); - } - catch (Exception e) - { - var mesh = MeshToNative(brep.displayValue); - converted.AddRange(mesh); - } - break; - case Mesh mesh: - var rMesh = MeshToNative(mesh); - converted.AddRange(rMesh); - break; - default: - ConversionErrors.Add(new Error("Incompatible geometry type", - $"Type ${b.GetType()} is not supported in DirectShape conversions.")); - break; - } - }); - + switch (b) + { + case Brep brep: + try + { + var solid = BrepToNative(brep); + converted.Add(solid); + } + catch (Exception e) + { + var mesh = MeshToNative(brep.displayValue); + converted.AddRange(mesh); + } + break; + case Mesh mesh: + var rMesh = MeshToNative(mesh); + converted.AddRange(rMesh); + break; + default: + ConversionErrors.Add( + new Error( + "Incompatible geometry type", + $"Type ${b.GetType()} is not supported in DirectShape conversions." + ) + ); + break; + } + }); + BuiltInCategory cat; var bic = RevitUtils.GetBuiltInCategory(speckleDs.category); BuiltInCategory.TryParse(bic, out cat); @@ -67,7 +72,12 @@ public ApplicationPlaceholderObject DirectShapeToNative(DirectShape speckleDs) revitDs.Name = speckleDs.name; SetInstanceParameters(revitDs, speckleDs); - return new ApplicationPlaceholderObject { applicationId = speckleDs.applicationId, ApplicationGeneratedId = revitDs.UniqueId, NativeObject = revitDs }; + return new ApplicationPlaceholderObject + { + applicationId = speckleDs.applicationId, + ApplicationGeneratedId = revitDs.UniqueId, + NativeObject = revitDs + }; } private DirectShape DirectShapeToSpeckle(DB.DirectShape revitAc) @@ -75,24 +85,20 @@ private DirectShape DirectShapeToSpeckle(DB.DirectShape revitAc) var cat = ((BuiltInCategory)revitAc.Category.Id.IntegerValue).ToString(); var category = RevitUtils.GetCategory(cat); var element = revitAc.get_Geometry(new Options()); - var geometries = element.ToList().Select(obj => - { - return obj switch + var geometries = element + .ToList() + .Select(obj => { - DB.Mesh mesh => MeshToSpeckle(mesh), - Solid solid => BrepToSpeckle(solid), - _ => null - }; - }); - var speckleAc = new DirectShape( - revitAc.Name, - category, - geometries.ToList(), - new List() - ); + return obj switch + { + DB.Mesh mesh => MeshToSpeckle(mesh), + Solid solid => BrepToSpeckle(solid), + _ => null + }; + }); + var speckleAc = new DirectShape(revitAc.Name, category, geometries.ToList(), new List()); GetRevitParameters(speckleAc, revitAc); return speckleAc; } - } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/Units.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/Units.cs new file mode 100644 index 0000000000..645d2f5e62 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/Units.cs @@ -0,0 +1,270 @@ +using Autodesk.Revit.DB; +using ConverterRevitShared.Extensions; +using RevitSharedResources.Interfaces; +using Speckle.Core.Logging; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + private string _modelUnits; + +#if REVIT2020 + public string ModelUnits + { + get + { + if (string.IsNullOrEmpty(_modelUnits)) + { + _modelUnits = UnitsToSpeckle(RevitLengthTypeId); + } + return _modelUnits; + } + } + + private DisplayUnitType _revitUnitsTypeId = DisplayUnitType.DUT_UNDEFINED; + public DisplayUnitType RevitLengthTypeId + { + get + { + if (_revitUnitsTypeId == DisplayUnitType.DUT_UNDEFINED) + { + var fo = Doc.GetUnits().GetFormatOptions(UnitType.UT_Length); + _revitUnitsTypeId = fo.DisplayUnits; + } + return _revitUnitsTypeId; + } + } + + /// + /// Converts Speckle length values to internal ones + /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToNative + /// as that takes into account the Project Base Location + /// + /// + /// + /// + public double ScaleToNative(double value, string units) + { + return UnitUtils.ConvertToInternalUnits(value, UnitsToNative(units)); + } + + /// + /// Converts Speckle length values to internal ones + /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToNative + /// as that takes into account the Project Base Location + /// + /// + /// + /// + public double ScaleToNative(double value, DisplayUnitType units) + { + return UnitUtils.ConvertToInternalUnits(value, units); + } + + /// + /// Converts internal length values to Speckle ones + /// NOTE: use only to convert double values, not point or vector coordinates. For those use Point/VectorToSpeckle + /// as that takes into account the Project Base Location + /// + /// + /// + /// + public double ScaleToSpeckle(double value) + { + return ScaleToSpeckle(value, RevitLengthTypeId); + } + + public static double ScaleToSpeckle(double value, DisplayUnitType unitType) + { + return UnitUtils.ConvertFromInternalUnits(value, unitType); + } + + public static double ScaleToSpeckle(double value, DisplayUnitType unitType, IRevitDocumentAggregateCache cache) + { + return ScaleToSpeckle(value, unitType); + } + + public static double ScaleToSpeckle(double value, string units) + { + return ScaleToSpeckle(value, UnitsToNative(units)); + } + + private string UnitsToSpeckle(DisplayUnitType type) + { + switch (type) + { + case DisplayUnitType.DUT_MILLIMETERS: + return Speckle.Core.Kits.Units.Millimeters; + case DisplayUnitType.DUT_CENTIMETERS: + return Speckle.Core.Kits.Units.Centimeters; + case DisplayUnitType.DUT_METERS: + return Speckle.Core.Kits.Units.Meters; + case DisplayUnitType.DUT_METERS_CENTIMETERS: + return Speckle.Core.Kits.Units.Meters; + case DisplayUnitType.DUT_DECIMAL_INCHES: + return Speckle.Core.Kits.Units.Inches; + case DisplayUnitType.DUT_DECIMAL_FEET: + return Speckle.Core.Kits.Units.Feet; + case DisplayUnitType.DUT_FEET_FRACTIONAL_INCHES: + return Speckle.Core.Kits.Units.Feet; + case DisplayUnitType.DUT_FRACTIONAL_INCHES: + return Speckle.Core.Kits.Units.Inches; + default: + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{type}\" is unsupported."); + } + + } + + public static DisplayUnitType UnitsToNative(string units) + { + switch (units) + { + case Speckle.Core.Kits.Units.Millimeters: + return DisplayUnitType.DUT_MILLIMETERS; + case Speckle.Core.Kits.Units.Centimeters: + return DisplayUnitType.DUT_CENTIMETERS; + case Speckle.Core.Kits.Units.Meters: + return DisplayUnitType.DUT_METERS; + case Speckle.Core.Kits.Units.Inches: + return DisplayUnitType.DUT_DECIMAL_INCHES; + case Speckle.Core.Kits.Units.Feet: + return DisplayUnitType.DUT_DECIMAL_FEET; + default: + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); + } + } + private static string UnitsToNativeString(DisplayUnitType unitType) + { + return unitType.ToString(); + } +#else + public string ModelUnits + { + get + { + if (string.IsNullOrEmpty(_modelUnits)) + { + _modelUnits = UnitsToSpeckle(RevitLengthTypeId.TypeId); + } + return _modelUnits; + } + } + + private ForgeTypeId _revitUnitsTypeId; + public ForgeTypeId RevitLengthTypeId + { + get + { + if (_revitUnitsTypeId == null) + { + var fo = Doc.GetUnits().GetFormatOptions(SpecTypeId.Length); + _revitUnitsTypeId = fo.GetUnitTypeId(); + } + return _revitUnitsTypeId; + } + } + + public static double ScaleToNative(double value, string units) + { + if (string.IsNullOrEmpty(units)) + { + return value; + } + + return UnitUtils.ConvertToInternalUnits(value, UnitsToNative(units)); + } + + private double? defaultConversionFactor; + + public double ScaleToSpeckle(double value) + { + defaultConversionFactor ??= ScaleToSpeckle(1, RevitLengthTypeId); + return value * defaultConversionFactor.Value; + } + + public static double ScaleToSpeckle(double value, string units) + { + return ScaleToSpeckle(value, UnitsToNative(units)); + } + + public static double ScaleToSpeckle(double value, ForgeTypeId forgeTypeId) + { + // our current profiling shows that the method "ConvertFromInternalUnits" is a huge bottleneck + // in the ScaleToSpeckle(double) method, but not here. This is because the former method is called + // roughly 12 times more often than this function + return UnitUtils.ConvertFromInternalUnits(value, forgeTypeId); + } + + //new units api introduced in 2021, bleah + public string UnitsToSpeckle(string typeId) + { + if (typeId == UnitTypeId.Millimeters.TypeId) + { + return Speckle.Core.Kits.Units.Millimeters; + } + else if (typeId == UnitTypeId.Centimeters.TypeId) + { + return Speckle.Core.Kits.Units.Centimeters; + } + else if (typeId == UnitTypeId.Meters.TypeId || typeId == UnitTypeId.MetersCentimeters.TypeId) + { + return Speckle.Core.Kits.Units.Meters; + } + else if (typeId == UnitTypeId.Inches.TypeId || typeId == UnitTypeId.FractionalInches.TypeId) + { + return Speckle.Core.Kits.Units.Inches; + } + else if (typeId == UnitTypeId.Feet.TypeId || typeId == UnitTypeId.FeetFractionalInches.TypeId) + { + return Speckle.Core.Kits.Units.Feet; + } + + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{typeId}\" is unsupported."); + } + + public static string UnitsToNativeString(string units) + { + return UnitsToNativeString(UnitsToNative(units)); + } + + public static string UnitsToNativeString(ForgeTypeId forgeTypeId) + { + return forgeTypeId.TypeId; + } + + public static ForgeTypeId UnitsToNative(string units) + { + var u = Speckle.Core.Kits.Units.GetUnitsFromString(units); + switch (u) + { + case Speckle.Core.Kits.Units.Millimeters: + return UnitTypeId.Millimeters; + case Speckle.Core.Kits.Units.Centimeters: + return UnitTypeId.Centimeters; + case Speckle.Core.Kits.Units.Meters: + return UnitTypeId.Meters; + case Speckle.Core.Kits.Units.Inches: + return UnitTypeId.Inches; + case Speckle.Core.Kits.Units.Feet: + return UnitTypeId.Feet; + default: + throw new Speckle.Core.Logging.SpeckleException($"The Unit System \"{units}\" is unsupported."); + } + } +#endif + + public static bool TryGetUnitsFromString(string units, out string? result) + { + try + { + result = Speckle.Core.Kits.Units.GetUnitsFromString(units); + return !string.IsNullOrEmpty(result); + } + catch (SpeckleException) + { + result = null; + return false; + } + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/UpdateParameter.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/UpdateParameter.cs new file mode 100644 index 0000000000..2dd2440020 --- /dev/null +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/UpdateParameter.cs @@ -0,0 +1,54 @@ +using Autodesk.Revit.DB; +using Objects.BuiltElements.Revit; +using Objects.Geometry; +using System.Collections.Generic; +using System.Linq; +using Speckle.Core.Helpers; +using Speckle.Core.Models; + +namespace Objects.Converter.Revit; + +public partial class ConverterRevit +{ + public ApplicationObject UpdateParameter(ParameterUpdater paramUpdater) + { + //the below does not work because ApplicationIds are stored within a stream + //try to get element using ApplicationId + //this will only work if the element has been successfully been received in Revit before + //var element = GetExistingElementByApplicationId(paramUpdater.revitId); + + var appObj = new ApplicationObject(paramUpdater.id, paramUpdater.speckle_type) + { + applicationId = paramUpdater.applicationId + }; + Element element = null; + + //try to get element using ElementId + if (int.TryParse(paramUpdater.elementId, out int intId)) + { + var elemId = new ElementId(intId); + element = Doc.GetElement(elemId); + } + + //try to get element using UniqueId + element ??= Doc.GetElement(paramUpdater.elementId); + + if (element != null) + { + SetInstanceParameters(element, paramUpdater); + appObj.Update( + status: ApplicationObject.State.Updated, + logItem: $"Successfully updated instance parameters for element {paramUpdater.elementId}" + ); + } + else + { + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Could not find element to update: Element Id = {paramUpdater.elementId}" + ); + } + + return appObj; + } +} diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/ConnectionPair.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/ConnectionPair.cs index d03fa2f4e5..2375212d41 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/ConnectionPair.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/ConnectionPair.cs @@ -1,107 +1,107 @@ -using Autodesk.Revit.DB; +using Autodesk.Revit.DB; using System; using System.Collections.Generic; -namespace ConverterRevitShared.Revit +namespace ConverterRevitShared.Revit; + +public class ConnectionPair : IComparable, IEquatable { - public class ConnectionPair : IComparable, IEquatable - { - public Element Owner { get; private set; } + public Element Owner { get; private set; } - public Connector Connector { get; private set; } + public Connector Connector { get; private set; } - public Connector RefConnector { get; private set; } + public Connector RefConnector { get; private set; } - public double Diameter { get; private set; } + public double Diameter { get; private set; } - public double Height { get; private set; } + public double Height { get; private set; } - public double Width { get; private set; } + public double Width { get; private set; } - public bool IsConnected { get; private set; } + public bool IsConnected { get; private set; } - public string Name => RefConnector != null + public string Name => + RefConnector != null ? $"{Owner.Category.Name}: {Connector.Owner.Name} --> {RefConnector.Owner.Category.Name}: {RefConnector.Owner.Name}" : $"{Owner.Category.Name}: {Connector.Owner.Name} --> NULL"; - private ConnectionPair(Element element, Connector connector, Connector refConnector = null) + private ConnectionPair(Element element, Connector connector, Connector refConnector = null) + { + Owner = element; + Connector = connector; + RefConnector = refConnector; + IsConnected = RefConnector != null; + var curve = element as MEPCurve; + switch (Connector.Shape) { - Owner = element; - Connector = connector; - RefConnector = refConnector; - IsConnected = RefConnector != null; - var curve = element as MEPCurve; - switch (Connector.Shape) - { - case ConnectorProfileType.Invalid: - break; - case ConnectorProfileType.Round: - Diameter = curve != null ? curve.Diameter : Connector.Radius * 2; - break; - default: - Height = curve != null ? curve.Height : Connector.Height; - Width = curve != null ? curve.Width : Connector.Width; - break; - } + case ConnectorProfileType.Invalid: + break; + case ConnectorProfileType.Round: + Diameter = curve != null ? curve.Diameter : Connector.Radius * 2; + break; + default: + Height = curve != null ? curve.Height : Connector.Height; + Width = curve != null ? curve.Width : Connector.Width; + break; } + } - public static ICollection GetConnectionPairs(Element element) + public static ICollection GetConnectionPairs(Element element) + { + var connectionPairs = new List(); + var connectors = GetConnectors(element); + var connectorsIterator = connectors.ForwardIterator(); + connectorsIterator.Reset(); + while (connectorsIterator.MoveNext()) { - var connectionPairs = new List(); - var connectors = GetConnectors(element); - var connectorsIterator = connectors.ForwardIterator(); - connectorsIterator.Reset(); - while (connectorsIterator.MoveNext()) + var connector = connectorsIterator.Current as Connector; + if (connector != null && connector.IsConnected) { - var connector = connectorsIterator.Current as Connector; - if (connector != null && connector.IsConnected) + var refs = connector.AllRefs; + var refsIterator = refs.ForwardIterator(); + refsIterator.Reset(); + while (refsIterator.MoveNext()) { - var refs = connector.AllRefs; - var refsIterator = refs.ForwardIterator(); - refsIterator.Reset(); - while (refsIterator.MoveNext()) + var refConnector = refsIterator.Current as Connector; + if (refConnector != null && !refConnector.Owner.Id.Equals(element.Id) && !(refConnector.Owner is MEPSystem)) { - var refConnector = refsIterator.Current as Connector; - if (refConnector != null && !refConnector.Owner.Id.Equals(element.Id) && !(refConnector.Owner is MEPSystem)) - connectionPairs.Add(new ConnectionPair(element, connector, refConnector)); + connectionPairs.Add(new ConnectionPair(element, connector, refConnector)); } } - else - { - connectionPairs.Add(new ConnectionPair(element, connector, null)); - } } - return connectionPairs; + else + { + connectionPairs.Add(new ConnectionPair(element, connector, null)); + } } + return connectionPairs; + } - public bool IsValid() - { - return Connector.Owner.Id.Equals(Owner.Id) && RefConnector != null ? - Connector.IsConnectedTo(RefConnector): - true; - } + public bool IsValid() + { + return Connector.Owner.Id.Equals(Owner.Id) && RefConnector != null ? Connector.IsConnectedTo(RefConnector) : true; + } - public int CompareTo(ConnectionPair other) - { - return Convert.ToInt32(Equals(other)); - } + public int CompareTo(ConnectionPair other) + { + return Convert.ToInt32(Equals(other)); + } - public bool Equals(ConnectionPair other) - { - return Owner.Id.Equals(other.Owner.Id) && RefConnector?.Owner?.Id == other.RefConnector?.Owner?.Id; - } + public bool Equals(ConnectionPair other) + { + return Owner.Id.Equals(other.Owner.Id) && RefConnector?.Owner?.Id == other.RefConnector?.Owner?.Id; + } - public bool ConnectedToCurve(out MEPCurve curve) - { - curve = RefConnector?.Owner as MEPCurve; - return curve != null; - } + public bool ConnectedToCurve(out MEPCurve curve) + { + curve = RefConnector?.Owner as MEPCurve; + return curve != null; + } - private static ConnectorSet GetConnectors(Element e) - { - return e is MEPCurve cure ? - cure.ConnectorManager.Connectors: - (e as FamilyInstance)?.MEPModel?.ConnectorManager?.Connectors ?? new ConnectorSet(); - } + private static ConnectorSet GetConnectors(Element e) + { + return e is MEPCurve cure + ? cure.ConnectorManager.Connectors + : (e as FamilyInstance)?.MEPModel?.ConnectorManager?.Connectors ?? new ConnectorSet(); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/FamilyLoadOptions.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/FamilyLoadOptions.cs index 3900662105..f69a0035f2 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/FamilyLoadOptions.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/Revit/FamilyLoadOptions.cs @@ -1,24 +1,27 @@ -using Autodesk.Revit.DB; +using Autodesk.Revit.DB; using System; using System.Collections.Generic; using System.Text; -namespace ConverterRevitShared.Revit +namespace ConverterRevitShared.Revit; + +public class FamilyLoadOption : IFamilyLoadOptions { - public class FamilyLoadOption : IFamilyLoadOptions + public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues) { - public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues) - { - overwriteParameterValues = true; - return true; - } - + overwriteParameterValues = true; + return true; + } - public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues) - { - source = FamilySource.Family; - overwriteParameterValues = true; - return true; - } + public bool OnSharedFamilyFound( + Family sharedFamily, + bool familyInUse, + out FamilySource source, + out bool overwriteParameterValues + ) + { + source = FamilySource.Family; + overwriteParameterValues = true; + return true; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitCommitObjectBuilder.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitCommitObjectBuilder.cs index ed2e240afe..179134568b 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitCommitObjectBuilder.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitCommitObjectBuilder.cs @@ -51,7 +51,10 @@ public override void BuildCommitObject(Base rootCommitObject) foreach (var col in _collections.Values) { if (!col.elements.Any()) + { continue; + } + rootElements.Add(col); } @@ -150,7 +153,9 @@ private void AddNestingInstructionsForMEPElement(Element nativeElement, List +/// Functionality related to retrieving, setting, and caching s. Implements and in order for the connector to be able to access object info through the converter during mapping on receive. +/// +public partial class ConverterRevit : IRevitElementTypeRetriever, IAllRevitCategoriesExposer { - /// - /// Functionality related to retrieving, setting, and caching s. Implements and in order for the connector to be able to access object info through the converter during mapping on receive. - /// - public partial class ConverterRevit : IRevitElementTypeRetriever, - IAllRevitCategoriesExposer + public IAllRevitCategories AllCategories => new AllRevitCategories(revitDocumentAggregateCache); + + #region IRevitElementTypeRetriever + public string? GetElementType(Base @base) { - public IAllRevitCategories AllCategories => new AllRevitCategories(revitDocumentAggregateCache); + string type = null; + switch (@base) + { + case OSG.Element1D el: + type = el.property?.name; + break; + case OSG.Element2D el: + type = el.property?.name; + break; + case Other.Revit.RevitInstance el: + type = el.typedDefinition?.type; + break; + case BuiltElements.TeklaStructures.TeklaBeam el: + type = el.profile?.name; + break; + } + ; - #region IRevitElementTypeRetriever - public string? GetElementType(Base @base) + if (!string.IsNullOrEmpty(type)) { - string type = null; - switch (@base) - { - case OSG.Element1D el: - type = el.property?.name; - break; - case OSG.Element2D el: - type = el.property?.name; - break; - case Other.Revit.RevitInstance el: - type = el.typedDefinition?.type; - break; - case BuiltElements.TeklaStructures.TeklaBeam el: - type = el.profile?.name; - break; - }; - - if (!string.IsNullOrEmpty(type)) return type; - return @base["type"] as string; + return type; } - - public void SetElementType(Base @base, string type) + + return @base["type"] as string; + } + + public void SetElementType(Base @base, string type) + { + switch (@base) { - switch (@base) - { - case OSG.Element1D el: - if (el.property == null) goto default; - el.property.name = type; - break; - case OSG.Element2D el: - if (el.property == null) goto default; - el.property.name = type; - break; - case Other.Revit.RevitInstance el: - if (el.typedDefinition == null) goto default; - el.typedDefinition.type = type; - break; - case BuiltElements.TeklaStructures.TeklaBeam el: - if (el.profile == null) goto default; - el.profile.name = type; - break; - default: - @base["type"] = type; - break; - }; + case OSG.Element1D el: + if (el.property == null) + { + goto default; + } + + el.property.name = type; + break; + case OSG.Element2D el: + if (el.property == null) + { + goto default; + } + + el.property.name = type; + break; + case Other.Revit.RevitInstance el: + if (el.typedDefinition == null) + { + goto default; + } + + el.typedDefinition.type = type; + break; + case BuiltElements.TeklaStructures.TeklaBeam el: + if (el.profile == null) + { + goto default; + } + + el.profile.name = type; + break; + default: + @base["type"] = type; + break; } - public string? GetElementFamily(Base @base) + ; + } + + public string? GetElementFamily(Base @base) + { + string family = null; + switch (@base) { - string family = null; - switch (@base) - { - case Other.Revit.RevitInstance el: - family = el.typedDefinition?.family; - break; - }; - return family ?? @base["family"] as string; + case Other.Revit.RevitInstance el: + family = el.typedDefinition?.family; + break; } - - public void SetElementFamily(Base @base, string family) + ; + return family ?? @base["family"] as string; + } + + public void SetElementFamily(Base @base, string family) + { + switch (@base) { - switch (@base) - { - case Other.Revit.RevitInstance el: - if (el.typedDefinition == null) goto default; - el.typedDefinition.family = family; - break; - default: - @base["family"] = family; - break; - }; + case Other.Revit.RevitInstance el: + if (el.typedDefinition == null) + { + goto default; + } + + el.typedDefinition.family = family; + break; + default: + @base["family"] = family; + break; } + ; + } + + #endregion - #endregion + private T? GetElementType(Base element, ApplicationObject appObj, out bool isExactMatch) + where T : ElementType + { + isExactMatch = false; - private T? GetElementType(Base element, ApplicationObject appObj, out bool isExactMatch) - where T : ElementType + var type = GetElementType(element); + if (type == null) { - isExactMatch = false; + SpeckleLog.Logger.Warning( + "Could not find valid incoming type for element of type {speckleType}", + element.speckle_type + ); + appObj.Update(logItem: $"Could not find valid incoming type for element of type \"{element.speckle_type}\""); + } + var typeInfo = AllCategories.GetRevitCategoryInfo(element); + var types = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory>() + .GetOrAddGroupOfTypes(typeInfo); - var type = GetElementType(element); - if (type == null) + if (!types.Any()) + { + var name = typeof(T).Name; + if (element["category"] is string category && !string.IsNullOrWhiteSpace(category)) { - SpeckleLog.Logger.Warning("Could not find valid incoming type for element of type {speckleType}", element.speckle_type); - appObj.Update(logItem: $"Could not find valid incoming type for element of type \"{element.speckle_type}\""); + name = category; } - var typeInfo = AllCategories.GetRevitCategoryInfo(element); - var types = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory>() - .GetOrAddGroupOfTypes(typeInfo); - if (!types.Any()) - { - var name = typeof(T).Name; - if (element["category"] is string category && !string.IsNullOrWhiteSpace(category)) - name = category; + appObj.Update( + status: ApplicationObject.State.Failed, + logItem: $"Could not find any loaded family to use for category {name}." + ); - appObj.Update(status: ApplicationObject.State.Failed, logItem: $"Could not find any loaded family to use for category {name}."); - - return default; - } + return default; + } - var family = GetElementFamily(element); + var family = GetElementFamily(element); - ElementType exactType = null; - if (!string.IsNullOrWhiteSpace(family)) - { - exactType = types - .Where(t => string.Equals(t.FamilyName, family, StringComparison.CurrentCultureIgnoreCase)) - .Where(t => string.Equals(t.Name, type, StringComparison.CurrentCultureIgnoreCase)) - .FirstOrDefault(); - } - exactType ??= revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .TryGet(typeInfo.GetCategorySpecificTypeName(type)); + ElementType exactType = null; + if (!string.IsNullOrWhiteSpace(family)) + { + exactType = types + .Where(t => string.Equals(t.FamilyName, family, StringComparison.CurrentCultureIgnoreCase)) + .Where(t => string.Equals(t.Name, type, StringComparison.CurrentCultureIgnoreCase)) + .FirstOrDefault(); + } + exactType ??= revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .TryGet(typeInfo.GetCategorySpecificTypeName(type)); - if (exactType != null) + if (exactType != null) + { + isExactMatch = true; + if (exactType is FamilySymbol fs && !fs.IsActive) { - isExactMatch = true; - if (exactType is FamilySymbol fs && !fs.IsActive) - fs.Activate(); - return (T)exactType; + fs.Activate(); } - return GetElementType(element, family, type, types, appObj, out isExactMatch); + return (T)exactType; } - private T GetElementType(Base element, string? family, string? type, List types, ApplicationObject appObj, out bool isExactMatch) + return GetElementType(element, family, type, types, appObj, out isExactMatch); + } + + private T GetElementType( + Base element, + string? family, + string? type, + List types, + ApplicationObject appObj, + out bool isExactMatch + ) + { + isExactMatch = false; + ElementType match = null; + + if (!string.IsNullOrEmpty(family)) // try and match the family only. { - isExactMatch = false; - ElementType match = null; + match = types.FirstOrDefault(x => x.FamilyName?.ToLower() == family.ToLower()); + } - if (!string.IsNullOrEmpty(family)) // try and match the family only. - { - match = types.FirstOrDefault(x => x.FamilyName?.ToLower() == family.ToLower()); - } - - if (match == null) + if (match == null) + { + if (element is Objects.BuiltElements.Wall) // specifies the basic wall sub type as default { - if (element is Objects.BuiltElements.Wall) // specifies the basic wall sub type as default - match = types.Cast().Where(o => o.Kind == WallKind.Basic).Cast().FirstOrDefault(); - match ??= types.First(); + match = types.Cast().Where(o => o.Kind == WallKind.Basic).Cast().FirstOrDefault(); } - if (!isExactMatch) - appObj.Update(logItem: $"Missing type. Family: {family ?? "Unknown"} Type: {type ?? "Unknown"}\nType was replaced with: {match.FamilyName}, {match.Name}"); + match ??= types.First(); + } - if (match is FamilySymbol fs && !fs.IsActive) - fs.Activate(); + if (!isExactMatch) + { + appObj.Update( + logItem: $"Missing type. Family: {family ?? "Unknown"} Type: {type ?? "Unknown"}\nType was replaced with: {match.FamilyName}, {match.Name}" + ); + } - return (T)(object)match; + if (match is FamilySymbol fs && !fs.IsActive) + { + fs.Activate(); } + + return (T)(object)match; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitVersionHelper.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitVersionHelper.cs index 6a471d5431..f7c7f1b9dd 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitVersionHelper.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitVersionHelper.cs @@ -1,163 +1,172 @@ using Autodesk.Revit.DB; using System; -namespace Objects.Converter.Revit +namespace Objects.Converter.Revit; + +public static class RevitVersionHelper { - public static class RevitVersionHelper + public static string Version { - public static string Version + get { - get - { #if REVIT2023 - return "2023"; + return "2023"; #elif REVIT2022 - return "2022"; + return "2022"; #elif REVIT2021 - return "2021"; + return "2021"; #elif REVIT2020 - return "2020"; + return "2020"; #else - return "2024"; + return "2024"; #endif - } } + } - /// - /// Converts to internal units by using the speckle parameter applicationUnit - /// - /// Speckle parameter - /// - public static double ConvertToInternalUnits(object value, string applicationUnit) - { + /// + /// Converts to internal units by using the speckle parameter applicationUnit + /// + /// Speckle parameter + /// + public static double ConvertToInternalUnits(object value, string applicationUnit) + { #if REVIT2020 - Enum.TryParse(applicationUnit, out DisplayUnitType sourceUnit); - return UnitUtils.ConvertToInternalUnits(Convert.ToDouble(value), sourceUnit); + Enum.TryParse(applicationUnit, out DisplayUnitType sourceUnit); + return UnitUtils.ConvertToInternalUnits(Convert.ToDouble(value), sourceUnit); #else - // if a commit is sent in <=2021 and received in 2022+, the application unit will be a different format - // therefore we need to check if the applicationUnit is in the wrong format - ForgeTypeId sourceUnit = null; - if (!string.IsNullOrEmpty(applicationUnit) && applicationUnit.Length >= 3 && - applicationUnit.Substring(0, 3) == "DUT") - sourceUnit = DUTToForgeTypeId(applicationUnit); - else - sourceUnit = new ForgeTypeId(applicationUnit); + // if a commit is sent in <=2021 and received in 2022+, the application unit will be a different format + // therefore we need to check if the applicationUnit is in the wrong format + ForgeTypeId sourceUnit = null; + if ( + !string.IsNullOrEmpty(applicationUnit) && applicationUnit.Length >= 3 && applicationUnit.Substring(0, 3) == "DUT" + ) + { + sourceUnit = DUTToForgeTypeId(applicationUnit); + } + else + { + sourceUnit = new ForgeTypeId(applicationUnit); + } - return UnitUtils.ConvertToInternalUnits(Convert.ToDouble(value), sourceUnit); + return UnitUtils.ConvertToInternalUnits(Convert.ToDouble(value), sourceUnit); #endif - } + } - /// - /// Converts to internal units by using the destination parameter Display Units - /// - /// Value to set - /// Destination parameter - /// - public static double ConvertToInternalUnits(double value, Parameter parameter) - { + /// + /// Converts to internal units by using the destination parameter Display Units + /// + /// Value to set + /// Destination parameter + /// + public static double ConvertToInternalUnits(double value, Parameter parameter) + { #if REVIT2020 - return UnitUtils.ConvertToInternalUnits(value, parameter.DisplayUnitType); + return UnitUtils.ConvertToInternalUnits(value, parameter.DisplayUnitType); #else - return UnitUtils.ConvertToInternalUnits(value, parameter.GetUnitTypeId()); + return UnitUtils.ConvertToInternalUnits(value, parameter.GetUnitTypeId()); #endif - } - - public static string GetUnityTypeString(this Definition definition) - { + } + + public static string GetUnityTypeString(this Definition definition) + { #if REVIT2020 || REVIT2021 - return definition.UnitType.ToString(); + return definition.UnitType.ToString(); #else - return definition.GetDataType().TypeId; + return definition.GetDataType().TypeId; +#endif + } + +#if REVIT2020 + public static DisplayUnitType GetUnitTypeId(this Parameter parameter) + { + return parameter.DisplayUnitType; + } +#else + public static ForgeTypeId GetUnitTypeId(this Parameter parameter) + { + return parameter.GetUnitTypeId(); + } #endif - } -#if REVIT2020 - public static DisplayUnitType GetUnitTypeId(this Parameter parameter) + public static bool IsCurveClosed(NurbSpline curve) + { +#if REVIT2020 + return curve.isClosed; +#else + try { - return parameter.DisplayUnitType; + return curve.IsClosed; } -#else - public static ForgeTypeId GetUnitTypeId(this Parameter parameter) + catch { - return parameter.GetUnitTypeId(); + return true; } #endif + } - public static bool IsCurveClosed(NurbSpline curve) - { + public static bool IsCurveClosed(Curve curve) + { #if REVIT2020 - return curve.isClosed; -#else - try - { - return curve.IsClosed; - } - catch - { - return true; - } -#endif + if (curve.IsBound && curve.GetEndPoint(0).IsAlmostEqualTo(curve.GetEndPoint(1))) + { + return true; } - - public static bool IsCurveClosed(Curve curve) + else if (!curve.IsBound && curve.IsCyclic) { -#if REVIT2020 - if (curve.IsBound && curve.GetEndPoint(0).IsAlmostEqualTo(curve.GetEndPoint(1))) - return true; - else if (!curve.IsBound && curve.IsCyclic) - return true; - return false; + return true; + } + + return false; #else - try - { - return curve.IsClosed; - } - catch - { - return true; - } -#endif + try + { + return curve.IsClosed; } + catch + { + return true; + } +#endif + } #if REVIT2020 #else - private static ForgeTypeId DUTToForgeTypeId(string s) + private static ForgeTypeId DUTToForgeTypeId(string s) + { + ForgeTypeId sourceUnit = null; + switch (s.ToLower()) { - ForgeTypeId sourceUnit = null; - switch (s.ToLower()) - { - case string a when a.Contains("millimeters"): - sourceUnit = UnitTypeId.Millimeters; - break; - case string a when a.Contains("centimeters"): - sourceUnit = UnitTypeId.Centimeters; - break; - case string a when a.Contains("meters"): - sourceUnit = UnitTypeId.Centimeters; - break; - case string a when a.Contains("centimeters"): - sourceUnit = UnitTypeId.Meters; - break; - case string a when a.Contains("feet") && a.Contains("inches"): - sourceUnit = UnitTypeId.FeetFractionalInches; - break; - case string a when a.Contains("feet"): - sourceUnit = UnitTypeId.Feet; - break; - case string a when a.Contains("inches"): - sourceUnit = UnitTypeId.Inches; - break; - case string a when a.Contains("degrees"): - sourceUnit = UnitTypeId.Degrees; - break; - case string a when a.Contains("radians"): - sourceUnit = UnitTypeId.Radians; - break; - } - - return sourceUnit; + case string a when a.Contains("millimeters"): + sourceUnit = UnitTypeId.Millimeters; + break; + case string a when a.Contains("centimeters"): + sourceUnit = UnitTypeId.Centimeters; + break; + case string a when a.Contains("meters"): + sourceUnit = UnitTypeId.Centimeters; + break; + case string a when a.Contains("centimeters"): + sourceUnit = UnitTypeId.Meters; + break; + case string a when a.Contains("feet") && a.Contains("inches"): + sourceUnit = UnitTypeId.FeetFractionalInches; + break; + case string a when a.Contains("feet"): + sourceUnit = UnitTypeId.Feet; + break; + case string a when a.Contains("inches"): + sourceUnit = UnitTypeId.Inches; + break; + case string a when a.Contains("degrees"): + sourceUnit = UnitTypeId.Degrees; + break; + case string a when a.Contains("radians"): + sourceUnit = UnitTypeId.Radians; + break; } -#endif + + return sourceUnit; } +#endif } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/AssertUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/AssertUtils.cs index ffc6f20b98..20e467543c 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/AssertUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/AssertUtils.cs @@ -9,320 +9,359 @@ using Xunit; using DB = Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +internal static class AssertUtils { - internal static class AssertUtils + internal static void AdaptiveComponentEqual(DB.FamilyInstance sourceElem, DB.FamilyInstance destElem) { - internal static void AdaptiveComponentEqual(DB.FamilyInstance sourceElem, DB.FamilyInstance destElem) - { - ElementEqual(sourceElem, destElem); - EqualParam(sourceElem, destElem, BuiltInParameter.FLEXIBLE_INSTANCE_FLIP); + ElementEqual(sourceElem, destElem); + EqualParam(sourceElem, destElem, BuiltInParameter.FLEXIBLE_INSTANCE_FLIP); - var dist = (sourceElem.Location as LocationPoint).Point.DistanceTo((destElem.Location as LocationPoint).Point); - - Assert.True(dist < 0.1); - } + var dist = (sourceElem.Location as LocationPoint).Point.DistanceTo((destElem.Location as LocationPoint).Point); - internal static void CurveEqual(DB.CurveElement sourceElem, DB.CurveElement destElem) - { - ElementEqual(sourceElem, destElem); - EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); - EqualParam(sourceElem, destElem, BuiltInParameter.BUILDING_CURVE_GSTYLE); - - if (((LocationCurve)sourceElem.Location).Curve.IsBound) - { - var sourceEnd = ((LocationCurve)sourceElem.Location).Curve.GetEndPoint(0); - var destEnd = ((LocationCurve)destElem.Location).Curve.GetEndPoint(0); + Assert.True(dist < 0.1); + } - Assert.Equal(sourceEnd.X, destEnd.X, 4); - Assert.Equal(sourceEnd.Y, destEnd.Y, 4); - Assert.Equal(sourceEnd.Z, destEnd.Z, 4); - } - } + internal static void CurveEqual(DB.CurveElement sourceElem, DB.CurveElement destElem) + { + ElementEqual(sourceElem, destElem); + EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); + EqualParam(sourceElem, destElem, BuiltInParameter.BUILDING_CURVE_GSTYLE); - internal static void DirectShapeEqual(DB.DirectShape sourceElem, DB.DirectShape destElem) + if (((LocationCurve)sourceElem.Location).Curve.IsBound) { - ElementEqual(sourceElem, destElem); - } + var sourceEnd = ((LocationCurve)sourceElem.Location).Curve.GetEndPoint(0); + var destEnd = ((LocationCurve)destElem.Location).Curve.GetEndPoint(0); - internal static void DuctEqual(DB.Mechanical.Duct sourceElem, DB.Mechanical.Duct destElem) - { - ElementEqual(sourceElem, destElem); - - EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_START_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_WIDTH_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_VELOCITY); - } - - internal static void ElementEqual(DB.Element sourceElem, DB.Element destElem) - { - Assert.NotNull(sourceElem); - Assert.NotNull(destElem); - Assert.Equal(sourceElem.Name, destElem.Name); - Assert.Equal(sourceElem.Document.GetElement(sourceElem.GetTypeId())?.Name, destElem.Document.GetElement(destElem.GetTypeId())?.Name); - Assert.Equal(sourceElem.Category.Name, destElem.Category.Name); + Assert.Equal(sourceEnd.X, destEnd.X, 4); + Assert.Equal(sourceEnd.Y, destEnd.Y, 4); + Assert.Equal(sourceEnd.Z, destEnd.Z, 4); } - - internal static void FamilyInstanceEqual(DB.FamilyInstance sourceElem, DB.FamilyInstance destElem) - { - ElementEqual(sourceElem, destElem); - - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); + } - EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); + internal static void DirectShapeEqual(DB.DirectShape sourceElem, DB.DirectShape destElem) + { + ElementEqual(sourceElem, destElem); + } - Assert.Equal(sourceElem.FacingFlipped, destElem.FacingFlipped); - Assert.Equal(sourceElem.HandFlipped, destElem.HandFlipped); - Assert.Equal(sourceElem.IsSlantedColumn, destElem.IsSlantedColumn); - Assert.Equal(sourceElem.StructuralType, destElem.StructuralType); + internal static void DuctEqual(DB.Mechanical.Duct sourceElem, DB.Mechanical.Duct destElem) + { + ElementEqual(sourceElem, destElem); + + EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_START_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_HEIGHT_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_WIDTH_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_CURVE_DIAMETER_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_VELOCITY); + } - //rotation - if (sourceElem.Location is LocationPoint) - Assert.Equal(((LocationPoint)sourceElem.Location).Rotation, ((LocationPoint)destElem.Location).Rotation); - } + internal static void ElementEqual(DB.Element sourceElem, DB.Element destElem) + { + Assert.NotNull(sourceElem); + Assert.NotNull(destElem); + Assert.Equal(sourceElem.Name, destElem.Name); + Assert.Equal( + sourceElem.Document.GetElement(sourceElem.GetTypeId())?.Name, + destElem.Document.GetElement(destElem.GetTypeId())?.Name + ); + Assert.Equal(sourceElem.Category.Name, destElem.Category.Name); + } - internal static async Task FloorEqual(DB.Floor sourceElem, DB.Floor destElem) - { - ElementEqual(sourceElem, destElem); + internal static void FamilyInstanceEqual(DB.FamilyInstance sourceElem, DB.FamilyInstance destElem) + { + ElementEqual(sourceElem, destElem); - var slopeArrow = await APIContext.Run(app => { - return ConverterRevit.GetSlopeArrow(sourceElem); - }).ConfigureAwait(false); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - if (slopeArrow == null) - { - EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM); - } - else - { - var tailOffset = ConverterRevit.GetSlopeArrowTailOffset(slopeArrow, sourceElem.Document); - _ = ConverterRevit.GetSlopeArrowHeadOffset(slopeArrow, sourceElem.Document, tailOffset, out var slope); + EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); - var newSlopeArrow = await APIContext.Run(app => { - return ConverterRevit.GetSlopeArrow(destElem); - }).ConfigureAwait(false); + Assert.Equal(sourceElem.FacingFlipped, destElem.FacingFlipped); + Assert.Equal(sourceElem.HandFlipped, destElem.HandFlipped); + Assert.Equal(sourceElem.IsSlantedColumn, destElem.IsSlantedColumn); + Assert.Equal(sourceElem.StructuralType, destElem.StructuralType); - Assert.NotNull(newSlopeArrow); + //rotation + if (sourceElem.Location is LocationPoint) + { + Assert.Equal(((LocationPoint)sourceElem.Location).Rotation, ((LocationPoint)destElem.Location).Rotation); + } + } - var newTailOffset = ConverterRevit.GetSlopeArrowTailOffset(slopeArrow, sourceElem.Document); - _ = ConverterRevit.GetSlopeArrowHeadOffset(slopeArrow, sourceElem.Document, tailOffset, out var newSlope); - Assert.Equal(slope, newSlope); + internal static async Task FloorEqual(DB.Floor sourceElem, DB.Floor destElem) + { + ElementEqual(sourceElem, destElem); - var sourceOffset = ConverterRevit.GetParamValue(sourceElem, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM); - Assert.Equal(sourceOffset + tailOffset, ConverterRevit.GetParamValue(destElem, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM)); - } + var slopeArrow = await APIContext + .Run(app => + { + return ConverterRevit.GetSlopeArrow(sourceElem); + }) + .ConfigureAwait(false); - EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL); - EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_ATTR_THICKNESS_PARAM); + if (slopeArrow == null) + { + EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM); } - - internal static void NestedEqual(DB.Element sourceElem, DB.Element destElem) + else { - ElementEqual(sourceElem, destElem); - - //family instance - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_ELEVATION_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM); + var tailOffset = ConverterRevit.GetSlopeArrowTailOffset(slopeArrow, sourceElem.Document); + _ = ConverterRevit.GetSlopeArrowHeadOffset(slopeArrow, sourceElem.Document, tailOffset, out var slope); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); + var newSlopeArrow = await APIContext + .Run(app => + { + return ConverterRevit.GetSlopeArrow(destElem); + }) + .ConfigureAwait(false); + + Assert.NotNull(newSlopeArrow); + + var newTailOffset = ConverterRevit.GetSlopeArrowTailOffset(slopeArrow, sourceElem.Document); + _ = ConverterRevit.GetSlopeArrowHeadOffset(slopeArrow, sourceElem.Document, tailOffset, out var newSlope); + Assert.Equal(slope, newSlope); + + var sourceOffset = ConverterRevit.GetParamValue( + sourceElem, + BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM + ); + Assert.Equal( + sourceOffset + tailOffset, + ConverterRevit.GetParamValue(destElem, BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM) + ); + } + EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_PARAM_IS_STRUCTURAL); + EqualParam(sourceElem, destElem, BuiltInParameter.FLOOR_ATTR_THICKNESS_PARAM); + } - if (sourceElem is FamilyInstance fi && fi.Host != null && destElem is FamilyInstance fi2) - { - Assert.Equal(fi.Host.Name, fi2.Host.Name); - } + internal static void NestedEqual(DB.Element sourceElem, DB.Element destElem) + { + ElementEqual(sourceElem, destElem); - //rotation - //for some reasons, rotation of hosted families stopped working in 2021.1 ...? - if (sourceElem.Location is LocationPoint && sourceElem is FamilyInstance fi3 && fi3.Host == null) - Assert.Equal(((LocationPoint)sourceElem.Location).Rotation, ((LocationPoint)destElem.Location).Rotation, 3); + //family instance + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_ELEVATION_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM); - //walls - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_OFFSET); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_TOP_OFFSET); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); + if (sourceElem is FamilyInstance fi && fi.Host != null && destElem is FamilyInstance fi2) + { + Assert.Equal(fi.Host.Name, fi2.Host.Name); } - internal static void OpeningEqual(DB.Element sourceElem, DB.Element destElem) + //rotation + //for some reasons, rotation of hosted families stopped working in 2021.1 ...? + if (sourceElem.Location is LocationPoint && sourceElem is FamilyInstance fi3 && fi3.Host == null) { - if (!(sourceElem is DB.Opening)) - return; + Assert.Equal(((LocationPoint)sourceElem.Location).Rotation, ((LocationPoint)destElem.Location).Rotation, 3); + } - ElementEqual(sourceElem, destElem); + //walls + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_OFFSET); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_TOP_OFFSET); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); + } - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + internal static void OpeningEqual(DB.Element sourceElem, DB.Element destElem) + { + if (!(sourceElem is DB.Opening)) + { + return; } - internal static void EqualParam(DB.Element expected, DB.Element actual, BuiltInParameter param) + ElementEqual(sourceElem, destElem); + + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + } + + internal static void EqualParam(DB.Element expected, DB.Element actual, BuiltInParameter param) + { + var expecedParam = expected.get_Parameter(param); + if (expecedParam == null) { - var expecedParam = expected.get_Parameter(param); - if (expecedParam == null) - return; + return; + } - switch (expecedParam.StorageType) + switch (expecedParam.StorageType) + { + case StorageType.Double: + Assert.Equal(expecedParam.AsDouble(), actual.get_Parameter(param).AsDouble(), 4); + break; + case StorageType.Integer: + Assert.Equal(expecedParam.AsInteger(), actual.get_Parameter(param).AsInteger()); + break; + case StorageType.String: + Assert.Equal(expecedParam.AsString(), actual.get_Parameter(param).AsString()); + break; + case StorageType.ElementId: { - case StorageType.Double: - Assert.Equal(expecedParam.AsDouble(), actual.get_Parameter(param).AsDouble(), 4); - break; - case StorageType.Integer: - Assert.Equal(expecedParam.AsInteger(), actual.get_Parameter(param).AsInteger()); - break; - case StorageType.String: - Assert.Equal(expecedParam.AsString(), actual.get_Parameter(param).AsString()); - break; - case StorageType.ElementId: - { - var e1 = expected.Document.GetElement(expecedParam.AsElementId()); - var e2 = actual.Document.GetElement(actual.get_Parameter(param).AsElementId()); - if (e1 is Level l1 && e2 is Level l2) - Assert.Equal(l1.Elevation, l2.Elevation, 3); - else if (e1 != null && e2 != null) - Assert.Equal(e1.Name, e2.Name); - break; - } - case StorageType.None: - break; - default: - throw new ArgumentOutOfRangeException(); + var e1 = expected.Document.GetElement(expecedParam.AsElementId()); + var e2 = actual.Document.GetElement(actual.get_Parameter(param).AsElementId()); + if (e1 is Level l1 && e2 is Level l2) + { + Assert.Equal(l1.Elevation, l2.Elevation, 3); + } + else if (e1 != null && e2 != null) + { + Assert.Equal(e1.Name, e2.Name); + } + + break; } + case StorageType.None: + break; + default: + throw new ArgumentOutOfRangeException(); } + } - internal static void PipeEqual(DB.Plumbing.Pipe sourceElem, DB.Plumbing.Pipe destElem) - { - ElementEqual(sourceElem, destElem); + internal static void PipeEqual(DB.Plumbing.Pipe sourceElem, DB.Plumbing.Pipe destElem) + { + ElementEqual(sourceElem, destElem); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_START_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM); - } + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_PIPE_DIAMETER_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.CURVE_ELEM_LENGTH); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_START_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM); + } - internal static void RoofEqual(DB.RoofBase sourceElem, DB.RoofBase destElem) - { - ElementEqual(sourceElem, destElem); + internal static void RoofEqual(DB.RoofBase sourceElem, DB.RoofBase destElem) + { + ElementEqual(sourceElem, destElem); - EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_SLOPE); - EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_BASE_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM); - } + EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_SLOPE); + EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_BASE_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.ROOF_UPTO_LEVEL_PARAM); + } - internal static async Task ScheduleEqual(DB.ViewSchedule sourceElem, DB.ViewSchedule destElem) - { - ElementEqual(sourceElem, destElem); + internal static async Task ScheduleEqual(DB.ViewSchedule sourceElem, DB.ViewSchedule destElem) + { + ElementEqual(sourceElem, destElem); - var sourceValueList = await APIContext.Run(app => + var sourceValueList = await APIContext + .Run(app => { return GetTextValuesFromSchedule(sourceElem); - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - var destValueList = await APIContext.Run(app => + var destValueList = await APIContext + .Run(app => { return GetTextValuesFromSchedule(destElem); - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - var index = 0; - for (var i = 0; i < sourceValueList.Count; i++) + var index = 0; + for (var i = 0; i < sourceValueList.Count; i++) + { + try { - try - { - // you can't unassign parameter values in Revit, so just ignore those - var emptyIndicies = Enumerable.Range(0, sourceValueList[i].Count) - .Where(j => string.IsNullOrWhiteSpace(sourceValueList[i][j])) - .ToList(); + // you can't unassign parameter values in Revit, so just ignore those + var emptyIndicies = Enumerable + .Range(0, sourceValueList[i].Count) + .Where(j => string.IsNullOrWhiteSpace(sourceValueList[i][j])) + .ToList(); - if (emptyIndicies.Any()) + if (emptyIndicies.Any()) + { + for (var j = emptyIndicies.Count - 1; j >= 0; j--) { - for (var j = emptyIndicies.Count - 1; j >= 0; j--) - { - sourceValueList[i].RemoveAt(emptyIndicies[j]); - destValueList[i].RemoveAt(emptyIndicies[j]); - } + sourceValueList[i].RemoveAt(emptyIndicies[j]); + destValueList[i].RemoveAt(emptyIndicies[j]); } - Assert.Equal(sourceValueList[i], destValueList[i]); } - catch (Exception ex) - { - throw; - } - index++; + Assert.Equal(sourceValueList[i], destValueList[i]); } + catch (Exception ex) + { + throw; + } + index++; } + } - private static List> GetTextValuesFromSchedule(ViewSchedule revitSchedule) + private static List> GetTextValuesFromSchedule(ViewSchedule revitSchedule) + { + var originalTableIds = new FilteredElementCollector(revitSchedule.Document, revitSchedule.Id).ToElementIds(); + var values = new List>(); + foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) { - var originalTableIds = new FilteredElementCollector(revitSchedule.Document, revitSchedule.Id) - .ToElementIds(); - var values = new List>(); - foreach (var rowInfo in RevitScheduleUtils.ScheduleRowIteration(revitSchedule)) + if (rowInfo.tableSection == SectionType.Header) { - if (rowInfo.tableSection == SectionType.Header) - { - continue; - } - if (!ConverterRevit.ElementApplicationIdsInRow(rowInfo.rowIndex, rowInfo.section, originalTableIds, revitSchedule, rowInfo.tableSection).Any()) - { - continue; - } - - var innerList = new List(); - for (var columnIndex = 0; columnIndex < rowInfo.columnCount; columnIndex++) - { - innerList.Add(revitSchedule.GetCellText(rowInfo.tableSection, rowInfo.rowIndex, columnIndex)); - } - values.Add(innerList); + continue; + } + if ( + !ConverterRevit + .ElementApplicationIdsInRow( + rowInfo.rowIndex, + rowInfo.section, + originalTableIds, + revitSchedule, + rowInfo.tableSection + ) + .Any() + ) + { + continue; } - return values; + var innerList = new List(); + for (var columnIndex = 0; columnIndex < rowInfo.columnCount; columnIndex++) + { + innerList.Add(revitSchedule.GetCellText(rowInfo.tableSection, rowInfo.rowIndex, columnIndex)); + } + values.Add(innerList); } - internal static void ValidSpeckleElement(DB.Element elem, Base spkElem) - { - Assert.NotNull(elem); - Assert.NotNull(spkElem); - Assert.NotNull(spkElem["speckle_type"]); - Assert.NotNull(spkElem["applicationId"]); + return values; + } - SpeckleUtils.CustomAssertions(elem, spkElem); - } + internal static void ValidSpeckleElement(DB.Element elem, Base spkElem) + { + Assert.NotNull(elem); + Assert.NotNull(spkElem); + Assert.NotNull(spkElem["speckle_type"]); + Assert.NotNull(spkElem["applicationId"]); - internal static void WallEqual(DB.Wall sourceElem, DB.Wall destElem) - { - ElementEqual(sourceElem, destElem); - - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_OFFSET); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_TOP_OFFSET); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); - EqualParam(sourceElem, destElem, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); - } + SpeckleUtils.CustomAssertions(elem, spkElem); + } - internal static void WireEqual(DB.Electrical.Wire sourceElem, DB.Electrical.Wire destElem) - { - ElementEqual(sourceElem, destElem); + internal static void WallEqual(DB.Wall sourceElem, DB.Wall destElem) + { + ElementEqual(sourceElem, destElem); + + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_USER_HEIGHT_PARAM); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_OFFSET); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_TOP_OFFSET); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_BASE_CONSTRAINT); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_HEIGHT_TYPE); + EqualParam(sourceElem, destElem, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); + } - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_ELEC_WIRE_TYPE); - EqualParam(sourceElem, destElem, BuiltInParameter.FABRIC_WIRE_LENGTH); - EqualParam(sourceElem, destElem, BuiltInParameter.RBS_ELEC_WIRE_ELEVATION); - } + internal static void WireEqual(DB.Electrical.Wire sourceElem, DB.Electrical.Wire destElem) + { + ElementEqual(sourceElem, destElem); + + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_ELEC_WIRE_TYPE); + EqualParam(sourceElem, destElem, BuiltInParameter.FABRIC_WIRE_LENGTH); + EqualParam(sourceElem, destElem, BuiltInParameter.RBS_ELEC_WIRE_ELEVATION); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/BrepTests.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/BrepTests.cs index d7010b1a7d..30a8993daa 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/BrepTests.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/BrepTests.cs @@ -9,84 +9,98 @@ using Xunit; using Xunit.Abstractions; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +public class BrepFixture : SpeckleConversionFixture { - public class BrepFixture : SpeckleConversionFixture + public override string TestName => "Brep"; + public override string Category => TestCategories.Brep; +} + +public class BrepTests : SpeckleConversionTest, IClassFixture +{ + private readonly ITestOutputHelper _testOutputHelper; + + public BrepTests(BrepFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) { - public override string TestName => "Brep"; - public override string Category => TestCategories.Brep; + _testOutputHelper = testOutputHelper; } - public class BrepTests : SpeckleConversionTest, IClassFixture + [Theory] + [Trait("Brep", "ToNative")] + [InlineData(@"Brep-Cube.json")] + [InlineData(@"Brep-CubeWithHole.json")] + [InlineData(@"Brep-TwoFaces.json")] + [InlineData(@"Brep-TrimmedFace.json")] + [InlineData(@"Brep-TrimmedFaceSingleLoop.json")] + [InlineData(@"Brep-FaceWithHole.json")] + [InlineData(@"Brep-NurbsWithHole.json")] + [InlineData(@"Brep-TwoFacesWithHole.json")] + [InlineData(@"Brep-Complex.json")] + [InlineData(@"Brep-QuadDome.json")] + [InlineData(@"Brep-SimpleHyparHole.json")] + [InlineData(@"Brep-FaceWithTrimmedEdge.json")] + public async Task BrepToNative(string fileName) { - private readonly ITestOutputHelper _testOutputHelper; + // Read and obtain `base` object. + var contents = System.IO.File.ReadAllText(Globals.GetTestModelOfCategory(fixture.Category, fileName)); + var converter = new ConverterRevit(); + var @base = Operations.Deserialize(contents); - public BrepTests(BrepFixture fixture, ITestOutputHelper testOutputHelper) : base(fixture) + // You read the wrong file, OOOPS!! + if (!(@base is Brep brep)) { - _testOutputHelper = testOutputHelper; + throw new Exception("Object was not a brep, did you choose the right file?"); } - [Theory] - [Trait("Brep", "ToNative")] - [InlineData(@"Brep-Cube.json")] - [InlineData(@"Brep-CubeWithHole.json")] - [InlineData(@"Brep-TwoFaces.json")] - [InlineData(@"Brep-TrimmedFace.json")] - [InlineData(@"Brep-TrimmedFaceSingleLoop.json")] - [InlineData(@"Brep-FaceWithHole.json")] - [InlineData(@"Brep-NurbsWithHole.json")] - [InlineData(@"Brep-TwoFacesWithHole.json")] - [InlineData(@"Brep-Complex.json")] - [InlineData(@"Brep-QuadDome.json")] - [InlineData(@"Brep-SimpleHyparHole.json")] - [InlineData(@"Brep-FaceWithTrimmedEdge.json")] - public async Task BrepToNative(string fileName) - { - - // Read and obtain `base` object. - var contents = System.IO.File.ReadAllText(Globals.GetTestModelOfCategory(fixture.Category, fileName)); - var converter = new ConverterRevit(); - var @base = Operations.Deserialize(contents); - - // You read the wrong file, OOOPS!! - if (!(@base is Brep brep)) throw new Exception("Object was not a brep, did you choose the right file?"); - DirectShape native = null; + DirectShape native = null; - await SpeckleUtils.RunInTransaction(() => + await SpeckleUtils.RunInTransaction( + () => { converter.SetContextDocument(fixture.NewDoc); native = converter.BrepToDirectShape(brep, out List notes); - }, fixture.NewDoc, converter); + }, + fixture.NewDoc, + converter + ); - Assert.True(native.get_Geometry(new Options()).First() is Solid); - } + Assert.True(native.get_Geometry(new Options()).First() is Solid); + } - [Fact] - [Trait("Brep", "ToSpeckle")] - public async Task BrepToSpeckle() + [Fact] + [Trait("Brep", "ToSpeckle")] + public async Task BrepToSpeckle() + { + await NativeToSpeckle(); + } + + [Fact] + [Trait("Brep", "Selection")] + public void BrepSelectionToNative() + { + var converter = new ConverterRevit(); + converter.SetContextDocument(fixture.NewDoc); + + if (fixture.Selection.Count == 0) { - await NativeToSpeckle(); + return; } - [Fact] - [Trait("Brep", "Selection")] - public void BrepSelectionToNative() + if (!(fixture.Selection[0] is DirectShape ds)) { - var converter = new ConverterRevit(); - converter.SetContextDocument(fixture.NewDoc); + throw new Exception("Selected object was not a direct shape."); + } - if (fixture.Selection.Count == 0) return; - if (!(fixture.Selection[0] is DirectShape ds)) - throw new Exception("Selected object was not a direct shape."); - var geo = ds.get_Geometry(new Options()); - if (!(geo.First() is Solid solid)) - throw new Exception("DS was not composed of a solid."); - var converted = converter.BrepToSpeckle(solid, fixture.NewDoc); - var nativeconverted = converter.BrepToNative(converted, out List notes); - Assert.NotNull(nativeconverted); + var geo = ds.get_Geometry(new Options()); + if (!(geo.First() is Solid solid)) + { + throw new Exception("DS was not composed of a solid."); } + var converted = converter.BrepToSpeckle(solid, fixture.NewDoc); + var nativeconverted = converter.BrepToNative(converted, out List notes); + Assert.NotNull(nativeconverted); } - } - diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/Globals.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/Globals.cs index de4ab2fd4b..335c7ad837 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/Globals.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/Globals.cs @@ -2,60 +2,61 @@ using System.Linq; using Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +public static class Globals { - public static class Globals + public static string GetTestModel(string filename) { - public static string GetTestModel(string filename) - { - var path = string.Empty; + var path = string.Empty; #if REVIT2021 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2021"), filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2021"), filename); #elif REVIT2022 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2022"), filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2022"), filename); #elif REVIT2023 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2023"), filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2023"), filename); #endif - return path; + return path; + } - } - public static string GetTestModelOfCategory(string category, string filename) - { - var path = string.Empty; + public static string GetTestModelOfCategory(string category, string filename) + { + var path = string.Empty; #if REVIT2021 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2021"), category, filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2021"), category, filename); #elif REVIT2022 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2022"), category, filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2022"), category, filename); #elif REVIT2023 - path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2023"), category, filename); + path = Path.Combine(GetTestModelFolderLocation(Directory.GetCurrentDirectory(), "2023"), category, filename); #endif - return path; + return path; + } - } + /// + /// This is the same method in TestGenerator.Globals. + /// TODO: Consolidate + /// + /// + /// + /// + public static string GetTestModelFolderLocation(string directoryStringInSpeckleSharp, string year) + { + var assemblyLocationList = directoryStringInSpeckleSharp.Split('\\').ToList(); - /// - /// This is the same method in TestGenerator.Globals. - /// TODO: Consolidate - /// - /// - /// - /// - public static string GetTestModelFolderLocation(string directoryStringInSpeckleSharp, string year) + for (var i = assemblyLocationList.Count - 1; i >= 0; i--) { - var assemblyLocationList = directoryStringInSpeckleSharp.Split('\\').ToList(); - - for (var i = assemblyLocationList.Count - 1; i >= 0; i--) + var folderName = assemblyLocationList[i]; + assemblyLocationList.RemoveAt(i); + if (folderName == "speckle-sharp") { - var folderName = assemblyLocationList[i]; - assemblyLocationList.RemoveAt(i); - if (folderName == "speckle-sharp") break; + break; } - assemblyLocationList.Add("speckle-sharp-test-models"); - assemblyLocationList.Add("Revit"); - - assemblyLocationList.Add(year); - var testFolderLocation = string.Join("\\", assemblyLocationList); - return testFolderLocation; } + assemblyLocationList.Add("speckle-sharp-test-models"); + assemblyLocationList.Add("Revit"); + + assemblyLocationList.Add(year); + var testFolderLocation = string.Join("\\", assemblyLocationList); + return testFolderLocation; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionFixture.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionFixture.cs index 77aaf2b5de..d08d467c7a 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionFixture.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionFixture.cs @@ -8,84 +8,88 @@ using xUnitRevitUtils; using DB = Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +public abstract class SpeckleConversionFixture : IAsyncLifetime { - public abstract class SpeckleConversionFixture : IAsyncLifetime + public Document SourceDoc { get; set; } + public Document UpdatedDoc { get; set; } + public Document NewDoc { get; set; } + public IList RevitElements { get; set; } + public IList UpdatedRevitElements { get; set; } + public List Selection { get; set; } + public string TemplateFile => Globals.GetTestModel("template.rte"); + public bool UpdateTestRunning { get; set; } + public string TestClassName { get; set; } + public virtual string TestName { get; } + public abstract string Category { get; } + public virtual string TestFile => Globals.GetTestModelOfCategory(Category, $"{TestName}.rvt"); + public virtual string UpdatedTestFile => Globals.GetTestModelOfCategory(Category, $"{TestName}Updated.rvt"); + public virtual string NewFile => Globals.GetTestModelOfCategory(Category, $"{TestName}ToNative.rvt"); + public virtual string ExpectedFailuresFile { get; } + + public SpeckleConversionFixture() { } + + public void Initialize() { - public Document SourceDoc { get; set; } - public Document UpdatedDoc { get; set; } - public Document NewDoc { get; set; } - public IList RevitElements { get; set; } - public IList UpdatedRevitElements { get; set; } - public List Selection { get; set; } - public string TemplateFile => Globals.GetTestModel("template.rte"); - public bool UpdateTestRunning { get; set; } - public string TestClassName { get; set; } - public virtual string TestName { get; } - public abstract string Category { get; } - public virtual string TestFile => Globals.GetTestModelOfCategory(Category, $"{TestName}.rvt"); - public virtual string UpdatedTestFile => Globals.GetTestModelOfCategory(Category, $"{TestName}Updated.rvt"); - public virtual string NewFile => Globals.GetTestModelOfCategory(Category, $"{TestName}ToNative.rvt"); - public virtual string ExpectedFailuresFile { get; } - public SpeckleConversionFixture() + if (!TestCategories.CategoriesDict.TryGetValue(Category.ToLower(), out var categories)) { + throw new System.Exception($"Category, {Category.ToLower()} is not a recognized category"); } + ElementMulticategoryFilter filter = new(categories); - public void Initialize() - { - if (!TestCategories.CategoriesDict.TryGetValue(Category.ToLower(), out var categories)) - { - throw new System.Exception($"Category, {Category.ToLower()} is not a recognized category"); - } - ElementMulticategoryFilter filter = new ElementMulticategoryFilter(categories); - - //get selection before opening docs, if any - Selection = xru.GetActiveSelection().ToList(); - SourceDoc = xru.OpenDoc(TestFile); - - if (File.Exists(UpdatedTestFile)) - { - UpdatedDoc = xru.OpenDoc(UpdatedTestFile); - UpdatedRevitElements = new FilteredElementCollector(UpdatedDoc).WhereElementIsNotElementType().WherePasses(filter).ToElements(); - } + //get selection before opening docs, if any + Selection = xru.GetActiveSelection().ToList(); + SourceDoc = xru.OpenDoc(TestFile); - if (File.Exists(NewFile)) - { - NewDoc = xru.OpenDoc(NewFile); - } - - RevitElements = new FilteredElementCollector(SourceDoc).WhereElementIsNotElementType().WherePasses(filter).ToElements(); + if (File.Exists(UpdatedTestFile)) + { + UpdatedDoc = xru.OpenDoc(UpdatedTestFile); + UpdatedRevitElements = new FilteredElementCollector(UpdatedDoc) + .WhereElementIsNotElementType() + .WherePasses(filter) + .ToElements(); } - public async Task InitializeAsync() + if (File.Exists(NewFile)) { - await SpeckleUtils.Throttler.WaitAsync(); - Initialize(); + NewDoc = xru.OpenDoc(NewFile); } - public Task DisposeAsync() + RevitElements = new FilteredElementCollector(SourceDoc) + .WhereElementIsNotElementType() + .WherePasses(filter) + .ToElements(); + } + + public async Task InitializeAsync() + { + await SpeckleUtils.Throttler.WaitAsync(); + Initialize(); + } + + public Task DisposeAsync() + { + try { - try - { - //var testsFailed = xru.MainViewModel.FilteredTestCases - // .Where(testCase => testCase.DisplayName.Contains(TestClassName)) - // .Any(testCase => testCase.State == Xunit.Runner.Wpf.TestState.Failed); + //var testsFailed = xru.MainViewModel.FilteredTestCases + // .Where(testCase => testCase.DisplayName.Contains(TestClassName)) + // .Any(testCase => testCase.State == Xunit.Runner.Wpf.TestState.Failed); - //// if none of the tests failed, close the documents - //if (!testsFailed) - //{ - xru.OpenDoc(Globals.GetTestModel("blank.rvt")); - xru.CloseDoc(SourceDoc); - xru.CloseDoc(UpdatedDoc); - xru.CloseDoc(NewDoc); - //} + //// if none of the tests failed, close the documents + //if (!testsFailed) + //{ + xru.OpenDoc(Globals.GetTestModel("blank.rvt")); + xru.CloseDoc(SourceDoc); + xru.CloseDoc(UpdatedDoc); + xru.CloseDoc(NewDoc); + //} - return Task.CompletedTask; - } - finally - { - SpeckleUtils.Throttler.Release(); - } + return Task.CompletedTask; + } + finally + { + SpeckleUtils.Throttler.Release(); } } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionTest.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionTest.cs index 6effe10411..f537be6472 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionTest.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleConversionTest.cs @@ -13,110 +13,119 @@ using xUnitRevitUtils; using DB = Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +public class SpeckleConversionTest { - public class SpeckleConversionTest + internal SpeckleConversionFixture fixture; + + public SpeckleConversionTest(SpeckleConversionFixture fixture) { - internal SpeckleConversionFixture fixture; + this.fixture = fixture; + this.fixture.TestClassName = GetType().Name; + } - public SpeckleConversionTest(SpeckleConversionFixture fixture) - { - this.fixture = fixture; - this.fixture.TestClassName = GetType().Name; - } + internal async Task NativeToSpeckle() + { + ConverterRevit converter = new(); + converter.SetContextDocument(fixture.SourceDoc); + converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - internal async Task NativeToSpeckle() + foreach (var elem in fixture.RevitElements) { - ConverterRevit converter = new ConverterRevit(); - converter.SetContextDocument(fixture.SourceDoc); - converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - - foreach (var elem in fixture.RevitElements) + await APIContext.Run(() => { - await APIContext.Run(() => - { - var spkElem = converter.ConvertToSpeckle(elem); + var spkElem = converter.ConvertToSpeckle(elem); - if (spkElem is Base re) - AssertUtils.ValidSpeckleElement(elem, re); - }); - } - Assert.Equal(0, converter.Report.ConversionErrorsCount); + if (spkElem is Base re) + { + AssertUtils.ValidSpeckleElement(elem, re); + } + }); } + Assert.Equal(0, converter.Report.ConversionErrorsCount); + } - /// - /// Gets elements from the fixture SourceDoc - /// Converts them to Speckle - /// Creates a new Doc (or uses the open one if open!) - /// Converts the speckle objects to Native - /// - /// - /// - internal async Task> SpeckleToNative( - Action assert, - Func assertAsync = null, - UpdateData ud = null - ) + /// + /// Gets elements from the fixture SourceDoc + /// Converts them to Speckle + /// Creates a new Doc (or uses the open one if open!) + /// Converts the speckle objects to Native + /// + /// + /// + internal async Task> SpeckleToNative( + Action assert, + Func assertAsync = null, + UpdateData ud = null + ) + { + Document doc = null; + IList elements = null; + List appPlaceholders = null; + + if (ud == null) + { + doc = fixture.SourceDoc; + elements = fixture.RevitElements; + } + else { - Document doc = null; - IList elements = null; - List appPlaceholders = null; + doc = ud.Doc; + elements = ud.Elements; + appPlaceholders = ud.AppPlaceholders; - if (ud == null) + var updateElementTestNumberMap = new Dictionary(); + foreach (var element in elements) { - doc = fixture.SourceDoc; - elements = fixture.RevitElements; - } - else - { - doc = ud.Doc; - elements = ud.Elements; - appPlaceholders = ud.AppPlaceholders; - - var updateElementTestNumberMap = new Dictionary(); - foreach (var element in elements) + var testNumber = SpeckleUtils.GetSpeckleObjectTestNumber(element); + if (testNumber > 0) { - var testNumber = SpeckleUtils.GetSpeckleObjectTestNumber(element); - if (testNumber > 0) + try { - try - { - updateElementTestNumberMap.Add(testNumber, element.UniqueId); - } - catch (ArgumentException e) - { - // there are duplicate SpeckleObjectTestNumber values in the update document - throw; - } + updateElementTestNumberMap.Add(testNumber, element.UniqueId); + } + catch (ArgumentException e) + { + // there are duplicate SpeckleObjectTestNumber values in the update document + throw; } } + } - foreach (var appObj in appPlaceholders) + foreach (var appObj in appPlaceholders) + { + if (!(appObj.Converted.FirstOrDefault() is DB.Element element)) { - if (!(appObj.Converted.FirstOrDefault() is DB.Element element)) - continue; + continue; + } - var testNumber = SpeckleUtils.GetSpeckleObjectTestNumber(element); - if (testNumber == 0) - continue; + var testNumber = SpeckleUtils.GetSpeckleObjectTestNumber(element); + if (testNumber == 0) + { + continue; + } - if (updateElementTestNumberMap.TryGetValue(testNumber, out var toNativeElementId)) - appObj.applicationId = toNativeElementId; + if (updateElementTestNumberMap.TryGetValue(testNumber, out var toNativeElementId)) + { + appObj.applicationId = toNativeElementId; } } + } - ConverterRevit converter = new ConverterRevit(); - converter.SetContextDocument(doc); - converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - //setting context objects for nested routine - var contextObjects = elements - .Select(obj => new ApplicationObject(obj.UniqueId, obj.GetType().ToString()) { applicationId = obj.UniqueId }) - .ToList(); - converter.SetContextObjects(contextObjects); - converter.SetContextDocument(new StreamStateCache(new StreamState())); - - var spkElems = new List(); - await APIContext.Run(() => + ConverterRevit converter = new(); + converter.SetContextDocument(doc); + converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); + //setting context objects for nested routine + var contextObjects = elements + .Select(obj => new ApplicationObject(obj.UniqueId, obj.GetType().ToString()) { applicationId = obj.UniqueId }) + .ToList(); + converter.SetContextObjects(contextObjects); + converter.SetContextDocument(new StreamStateCache(new StreamState())); + + var spkElems = new List(); + await APIContext + .Run(() => { foreach (var elem in elements) { @@ -126,7 +135,9 @@ await APIContext.Run(() => out ApplicationObject reportObj ); if (isAlreadyConverted) + { continue; + } var conversionResult = converter.ConvertToSpeckle(elem); if (conversionResult != null) @@ -137,186 +148,190 @@ out ApplicationObject reportObj }) .ConfigureAwait(false); - converter = new ConverterRevit(); - converter.ReceiveMode = Speckle.Core.Kits.ReceiveMode.Update; - - converter.SetContextDocument(fixture.NewDoc); - converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - //setting context objects for update routine - var state = new StreamState() - { - ReceivedObjects = appPlaceholders ?? new List() - }; - converter.SetContextDocument(new StreamStateCache(state)); - converter.SetContextDocument(new ConvertedObjectsCache()); - - var contextObjs = spkElems.Select(x => new ApplicationObject(x.id, x.speckle_type) { applicationId = x.applicationId }).ToList(); - var appObjs = new List(); - foreach (var contextObj in contextObjs) + converter = new ConverterRevit(); + converter.ReceiveMode = Speckle.Core.Kits.ReceiveMode.Update; + + converter.SetContextDocument(fixture.NewDoc); + converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); + //setting context objects for update routine + var state = new StreamState() { ReceivedObjects = appPlaceholders ?? new List() }; + converter.SetContextDocument(new StreamStateCache(state)); + converter.SetContextDocument(new ConvertedObjectsCache()); + + var contextObjs = spkElems + .Select(x => new ApplicationObject(x.id, x.speckle_type) { applicationId = x.applicationId }) + .ToList(); + var appObjs = new List(); + foreach (var contextObj in contextObjs) + { + if (string.IsNullOrEmpty(contextObj.applicationId) && string.IsNullOrEmpty(contextObj.OriginalId)) { - if (string.IsNullOrEmpty(contextObj.applicationId) - && string.IsNullOrEmpty(contextObj.OriginalId)) - { - continue; - } - - appObjs.Add(contextObj); + continue; } - converter.SetContextObjects(appObjs); + appObjs.Add(contextObj); + } + + converter.SetContextObjects(appObjs); - var resEls = new List(); - //used to associate th nested Base objects with eh flat revit ones - var flatSpkElems = new List(); + var resEls = new List(); + //used to associate th nested Base objects with eh flat revit ones + var flatSpkElems = new List(); - await SpeckleUtils.RunInTransaction( - () => + await SpeckleUtils.RunInTransaction( + () => + { + //xru.RunInTransaction(() => + //{ + foreach (var el in spkElems) { - //xru.RunInTransaction(() => - //{ - foreach (var el in spkElems) + object res = null; + try { - object res = null; - try - { - res = converter.ConvertToNative(el); - } - catch (Exception e) - { - converter.Report.LogConversionError(new Exception(e.Message, e)); - } + res = converter.ConvertToNative(el); + } + catch (Exception e) + { + converter.Report.LogConversionError(new Exception(e.Message, e)); + } - if (res is List apls) - { - resEls.AddRange(apls); - flatSpkElems.Add(el); - if (el["elements"] == null) - continue; - flatSpkElems.AddRange((el["elements"] as List).Where(b => converter.CanConvertToNative(b))); - } - else if (res is ApplicationObject appObj) - { - resEls.Add(appObj); - flatSpkElems.Add(el); - } - else if (res == null) - { - throw new Exception("Conversion returned null"); - } - else + if (res is List apls) + { + resEls.AddRange(apls); + flatSpkElems.Add(el); + if (el["elements"] == null) { - throw new Exception( - $"Conversion of Speckle object, of type {el.speckle_type}, to Revit returned unexpected type, {res.GetType().FullName}" - ); + continue; } - } - //}, fixture.NewDoc).Wait(); - }, - fixture.NewDoc, - converter - ); - Assert.Equal(0, converter.Report.ConversionErrorsCount); + flatSpkElems.AddRange((el["elements"] as List).Where(b => converter.CanConvertToNative(b))); + } + else if (res is ApplicationObject appObj) + { + resEls.Add(appObj); + flatSpkElems.Add(el); + } + else if (res == null) + { + throw new Exception("Conversion returned null"); + } + else + { + throw new Exception( + $"Conversion of Speckle object, of type {el.speckle_type}, to Revit returned unexpected type, {res.GetType().FullName}" + ); + } + } + //}, fixture.NewDoc).Wait(); + }, + fixture.NewDoc, + converter + ); - for (var i = 0; i < spkElems.Count; i++) - { - var sourceElem = (T)(object)elements.FirstOrDefault(x => x.UniqueId == flatSpkElems[i].applicationId); - var destElement = (T)((ApplicationObject)resEls[i]).Converted.FirstOrDefault(); + Assert.Equal(0, converter.Report.ConversionErrorsCount); - assert?.Invoke(sourceElem, destElement); - if (assertAsync != null) - { - await assertAsync.Invoke(sourceElem, destElement); - } - } + for (var i = 0; i < spkElems.Count; i++) + { + var sourceElem = (T)(object)elements.FirstOrDefault(x => x.UniqueId == flatSpkElems[i].applicationId); + var destElement = (T)((ApplicationObject)resEls[i]).Converted.FirstOrDefault(); - if (!fixture.UpdateTestRunning) + assert?.Invoke(sourceElem, destElement); + if (assertAsync != null) { - SpeckleUtils.DeleteElement(resEls); + await assertAsync.Invoke(sourceElem, destElement); } - - return resEls; } - /// - /// Runs SpeckleToNative with SourceDoc and UpdatedDoc - /// - /// - /// - internal async Task SpeckleToNativeUpdates(Action assert, Func assertAsync = null) + if (!fixture.UpdateTestRunning) { - fixture.UpdateTestRunning = true; - var initialObjs = await SpeckleToNative(assert, assertAsync); - var updatedObjs = await SpeckleToNative( - assert, - assertAsync, - new UpdateData - { - AppPlaceholders = initialObjs.Cast().ToList(), - Doc = fixture.UpdatedDoc, - Elements = fixture.UpdatedRevitElements - } - ); - fixture.UpdateTestRunning = false; - - // delete the elements that were not being deleted during the update test - SpeckleUtils.DeleteElement(initialObjs); - //DeleteElement(updatedObjs); + SpeckleUtils.DeleteElement(resEls); } - internal async Task SelectionToNative(Action assert, Func assertAsync = null) - { - ConverterRevit converter = new ConverterRevit(); - converter.SetContextDocument(fixture.SourceDoc); - converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - var spkElems = fixture.Selection.Select(x => converter.ConvertToSpeckle(x) as Base).ToList(); - - converter = new ConverterRevit(); - converter.SetContextDocument(fixture.NewDoc); - converter.SetContextDocument(new StreamStateCache(new StreamState())); - converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); - converter.SetContextDocument(new ConvertedObjectsCache()); - var revitEls = new List(); - - await SpeckleUtils.RunInTransaction( - () => + return resEls; + } + + /// + /// Runs SpeckleToNative with SourceDoc and UpdatedDoc + /// + /// + /// + internal async Task SpeckleToNativeUpdates(Action assert, Func assertAsync = null) + { + fixture.UpdateTestRunning = true; + var initialObjs = await SpeckleToNative(assert, assertAsync); + var updatedObjs = await SpeckleToNative( + assert, + assertAsync, + new UpdateData + { + AppPlaceholders = initialObjs.Cast().ToList(), + Doc = fixture.UpdatedDoc, + Elements = fixture.UpdatedRevitElements + } + ); + fixture.UpdateTestRunning = false; + + // delete the elements that were not being deleted during the update test + SpeckleUtils.DeleteElement(initialObjs); + //DeleteElement(updatedObjs); + } + + internal async Task SelectionToNative(Action assert, Func assertAsync = null) + { + ConverterRevit converter = new(); + converter.SetContextDocument(fixture.SourceDoc); + converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); + var spkElems = fixture.Selection.Select(x => converter.ConvertToSpeckle(x) as Base).ToList(); + + converter = new ConverterRevit(); + converter.SetContextDocument(fixture.NewDoc); + converter.SetContextDocument(new StreamStateCache(new StreamState())); + converter.SetContextDocument(new RevitDocumentAggregateCache(new UIDocumentProvider(xru.Uiapp))); + converter.SetContextDocument(new ConvertedObjectsCache()); + var revitEls = new List(); + + await SpeckleUtils.RunInTransaction( + () => + { + //xru.RunInTransaction(() => + //{ + foreach (var el in spkElems) { - //xru.RunInTransaction(() => - //{ - foreach (var el in spkElems) + var res = converter.ConvertToNative(el); + if (res is List apls) + { + revitEls.AddRange(apls); + } + else { - var res = converter.ConvertToNative(el); - if (res is List apls) - revitEls.AddRange(apls); - else - revitEls.Add(res); + revitEls.Add(res); } - //}, fixture.NewDoc).Wait(); - }, - fixture.NewDoc, - converter - ); + } + //}, fixture.NewDoc).Wait(); + }, + fixture.NewDoc, + converter + ); - Assert.Equal(0, converter.Report.ConversionErrorsCount); + Assert.Equal(0, converter.Report.ConversionErrorsCount); - for (var i = 0; i < revitEls.Count; i++) + for (var i = 0; i < revitEls.Count; i++) + { + var sourceElem = (T)(object)fixture.Selection[i]; + var destElement = (T)((ApplicationObject)revitEls[i]).Converted.FirstOrDefault(); + assert?.Invoke(sourceElem, destElement); + if (assertAsync != null) { - var sourceElem = (T)(object)fixture.Selection[i]; - var destElement = (T)((ApplicationObject)revitEls[i]).Converted.FirstOrDefault(); - assert?.Invoke(sourceElem, destElement); - if (assertAsync != null) - { - await assertAsync.Invoke(sourceElem, destElement); - } + await assertAsync.Invoke(sourceElem, destElement); } - SpeckleUtils.DeleteElement(revitEls); } + SpeckleUtils.DeleteElement(revitEls); } +} - public class UpdateData - { - public Document Doc { get; set; } - public IList Elements { get; set; } - public List AppPlaceholders { get; set; } - } +public class UpdateData +{ + public Document Doc { get; set; } + public IList Elements { get; set; } + public List AppPlaceholders { get; set; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleUtils.cs index e9aa16f043..22ee0360ba 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/SpeckleUtils.cs @@ -11,172 +11,179 @@ using xUnitRevitUtils; using DB = Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +internal static class SpeckleUtils { - internal static class SpeckleUtils + public static SemaphoreSlim Throttler = new(1, 1); + + internal async static Task RunInTransaction( + Action action, + DB.Document doc, + ConverterRevit converter = null, + string transactionName = "transaction", + bool ignoreWarnings = false + ) { - public static SemaphoreSlim Throttler = new SemaphoreSlim(1, 1); - - internal async static Task RunInTransaction( - Action action, - DB.Document doc, - ConverterRevit converter = null, - string transactionName = "transaction", - bool ignoreWarnings = false - ) + var tcs = new TaskCompletionSource(); + + await APIContext.Run(() => { - var tcs = new TaskCompletionSource(); + using var transactionManager = new TransactionManager("", doc); + transactionManager.Start(); - await APIContext.Run(() => + if (converter != null) { - using var transactionManager = new TransactionManager("", doc); - transactionManager.Start(); + converter.SetContextDocument(transactionManager); + } - if (converter != null) - { - converter.SetContextDocument(transactionManager); - } + try + { + action.Invoke(); + transactionManager.Finish(); + } + catch (Exception exception) + { + tcs.TrySetException(exception); + } - try - { - action.Invoke(); - transactionManager.Finish(); - } - catch (Exception exception) - { - tcs.TrySetException(exception); - } + tcs.TrySetResult(""); + }); - tcs.TrySetResult(""); - }); + return await tcs.Task; + } - return await tcs.Task; + internal class IgnoreAllWarnings : Autodesk.Revit.DB.IFailuresPreprocessor + { + public DB.FailureProcessingResult PreprocessFailures(Autodesk.Revit.DB.FailuresAccessor failuresAccessor) + { + IList failureMessages = failuresAccessor.GetFailureMessages(); + foreach (Autodesk.Revit.DB.FailureMessageAccessor item in failureMessages) + { + failuresAccessor.DeleteWarning(item); + } + + return DB.FailureProcessingResult.Continue; } + } - internal class IgnoreAllWarnings : Autodesk.Revit.DB.IFailuresPreprocessor + internal static void DeleteElement(object obj) + { + switch (obj) { - public DB.FailureProcessingResult PreprocessFailures(Autodesk.Revit.DB.FailuresAccessor failuresAccessor) - { - IList failureMessages = failuresAccessor.GetFailureMessages(); - foreach (Autodesk.Revit.DB.FailureMessageAccessor item in failureMessages) + case IList list: + foreach (var item in list) { - failuresAccessor.DeleteWarning(item); + DeleteElement(item); } - return DB.FailureProcessingResult.Continue; - } - } + break; + case ApplicationObject o: + foreach (var item in o.Converted) + { + DeleteElement(item); + } - internal static void DeleteElement(object obj) - { - switch (obj) - { - case IList list: - foreach (var item in list) - DeleteElement(item); - break; - case ApplicationObject o: - foreach (var item in o.Converted) - DeleteElement(item); - break; - case DB.ViewSchedule _: - // don't delete a view schedule since we didn't create it in the first place - break; - case DB.Element o: - try - { - xru.RunInTransaction( - () => - { - o.Document.Delete(o.Id); - }, - o.Document - ) - .Wait(); - } - // element already deleted, don't worry about it - catch { } - break; - default: - throw new Exception("It's not an element!?!?!"); - } + break; + case DB.ViewSchedule _: + // don't delete a view schedule since we didn't create it in the first place + break; + case DB.Element o: + try + { + xru.RunInTransaction( + () => + { + o.Document.Delete(o.Id); + }, + o.Document + ) + .Wait(); + } + // element already deleted, don't worry about it + catch { } + break; + default: + throw new Exception("It's not an element!?!?!"); } + } + + internal static int GetSpeckleObjectTestNumber(DB.Element element) + { + var param = element.Parameters + .Cast() + .Where(el => el.Definition.Name == "SpeckleObjectTestNumber") + .FirstOrDefault(); - internal static int GetSpeckleObjectTestNumber(DB.Element element) + if (param == null) { - var param = element.Parameters - .Cast() - .Where(el => el.Definition.Name == "SpeckleObjectTestNumber") - .FirstOrDefault(); + //throw new Exception($"Element of type {element.GetType()} with Id {element.Id.IntegerValue} does not have the parameter \"SpeckleObjectTestNumber\". If you are trying to create a new test document, then start from the \"blank.rvt\" file."); + return 0; + } - if (param == null) - { - //throw new Exception($"Element of type {element.GetType()} with Id {element.Id.IntegerValue} does not have the parameter \"SpeckleObjectTestNumber\". If you are trying to create a new test document, then start from the \"blank.rvt\" file."); - return 0; - } + return param.AsInteger(); + } - return param.AsInteger(); - } + internal static void CustomAssertions(DB.Element element, Base @base) + { + var parameters = element.Parameters.Cast().Where(el => el.Definition.Name.StartsWith("ToSpeckle")); - internal static void CustomAssertions(DB.Element element, Base @base) + foreach (var param in parameters) { - var parameters = element.Parameters.Cast().Where(el => el.Definition.Name.StartsWith("ToSpeckle")); - - foreach (var param in parameters) + var parts = param.Definition.Name.Split('-'); + if (parts.Length != 3) { - var parts = param.Definition.Name.Split('-'); - if (parts.Length != 3) - continue; + continue; + } - var assertionType = parts[1]; - var prop = parts[2]; + var assertionType = parts[1]; + var prop = parts[2]; - switch (param.StorageType) - { - case DB.StorageType.String: - var baseString = GetBaseValue(@base, prop); - var stringAssertionMethod = GetAssertionMethod(assertionType); - try - { - stringAssertionMethod(param.AsValueString(), baseString); - } - catch (Exception ex) - { - stringAssertionMethod(param.AsString(), baseString); - } - break; - case DB.StorageType.Integer: - var baseInt = GetBaseValue(@base, prop); - var intAssertionMethod = GetAssertionMethod(assertionType); - intAssertionMethod(param.AsInteger(), baseInt); - break; - case DB.StorageType.Double: - var baseDouble = GetBaseValue(@base, prop); - var doubleAssertionMethod = GetAssertionMethod(assertionType); - doubleAssertionMethod(param.AsDouble(), baseDouble); - break; - } + switch (param.StorageType) + { + case DB.StorageType.String: + var baseString = GetBaseValue(@base, prop); + var stringAssertionMethod = GetAssertionMethod(assertionType); + try + { + stringAssertionMethod(param.AsValueString(), baseString); + } + catch (Exception ex) + { + stringAssertionMethod(param.AsString(), baseString); + } + break; + case DB.StorageType.Integer: + var baseInt = GetBaseValue(@base, prop); + var intAssertionMethod = GetAssertionMethod(assertionType); + intAssertionMethod(param.AsInteger(), baseInt); + break; + case DB.StorageType.Double: + var baseDouble = GetBaseValue(@base, prop); + var doubleAssertionMethod = GetAssertionMethod(assertionType); + doubleAssertionMethod(param.AsDouble(), baseDouble); + break; } } + } - private static T GetBaseValue(Base @base, string prop) + private static T GetBaseValue(Base @base, string prop) + { + var path = prop.Split('.'); + dynamic value = @base; + foreach (var part in path) { - var path = prop.Split('.'); - dynamic value = @base; - foreach (var part in path) - { - value = value[part]; - } - return (T)value; + value = value[part]; } + return (T)value; + } - private static Action GetAssertionMethod(string assertionType) + private static Action GetAssertionMethod(string assertionType) + { + return assertionType switch { - return assertionType switch - { - "AE" => Assert.Equal, - _ => throw new Exception($"Assertion type of \"{assertionType}\" is not recognized") - }; - } + "AE" => Assert.Equal, + _ => throw new Exception($"Assertion type of \"{assertionType}\" is not recognized") + }; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/TestCategories.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/TestCategories.cs index 96d96593f6..df23aba5e0 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/TestCategories.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/TestCategories.cs @@ -1,65 +1,61 @@ using System.Collections.Generic; using Autodesk.Revit.DB; -namespace ConverterRevitTests +namespace ConverterRevitTests; + +internal static class TestCategories { - internal static class TestCategories - { - public const string AdaptiveComponent = "adaptivecomponent"; - public const string Beam = "beam"; - public const string Brep = "brep"; - public const string Column = "column"; - public const string Curve = "curve"; - public const string DirectShape = "directshape"; - public const string Duct = "duct"; - public const string FamilyInstance = "familyinstance"; - public const string Floor = "floor"; - public const string Opening = "opening"; - public const string Pipe = "pipe"; - public const string Roof = "roof"; - public const string Room = "room"; - public const string Schedule = "schedule"; - public const string Wall = "wall"; - public const string Wire = "wire"; + public const string AdaptiveComponent = "adaptivecomponent"; + public const string Beam = "beam"; + public const string Brep = "brep"; + public const string Column = "column"; + public const string Curve = "curve"; + public const string DirectShape = "directshape"; + public const string Duct = "duct"; + public const string FamilyInstance = "familyinstance"; + public const string Floor = "floor"; + public const string Opening = "opening"; + public const string Pipe = "pipe"; + public const string Roof = "roof"; + public const string Room = "room"; + public const string Schedule = "schedule"; + public const string Wall = "wall"; + public const string Wire = "wire"; - public static Dictionary> CategoriesDict = new() + public static Dictionary> CategoriesDict = + new() { - { AdaptiveComponent, new List() - { - BuiltInCategory.OST_GenericModel - } + { + AdaptiveComponent, + new List() { BuiltInCategory.OST_GenericModel } }, - { Beam, new List() - { - BuiltInCategory.OST_StructuralFraming - } + { + Beam, + new List() { BuiltInCategory.OST_StructuralFraming } }, - { Brep, new List() - { - BuiltInCategory.OST_Mass - } + { + Brep, + new List() { BuiltInCategory.OST_Mass } }, - { Column, new List() - { - BuiltInCategory.OST_Columns, BuiltInCategory.OST_StructuralColumns - } + { + Column, + new List() { BuiltInCategory.OST_Columns, BuiltInCategory.OST_StructuralColumns } }, - { Curve, new List() - { - BuiltInCategory.OST_Lines, BuiltInCategory.OST_RoomSeparationLines - } + { + Curve, + new List() { BuiltInCategory.OST_Lines, BuiltInCategory.OST_RoomSeparationLines } }, - { DirectShape, new List() - { - BuiltInCategory.OST_GenericModel - } + { + DirectShape, + new List() { BuiltInCategory.OST_GenericModel } }, - { Duct, new List() - { - BuiltInCategory.OST_DuctCurves - } + { + Duct, + new List() { BuiltInCategory.OST_DuctCurves } }, - { FamilyInstance, new List() + { + FamilyInstance, + new List() { BuiltInCategory.OST_Furniture, BuiltInCategory.OST_Doors, @@ -77,12 +73,13 @@ internal static class TestCategories BuiltInCategory.OST_Floors } }, - { Floor, new List() - { - BuiltInCategory.OST_Floors - } + { + Floor, + new List() { BuiltInCategory.OST_Floors } }, - { Opening, new List() + { + Opening, + new List() { BuiltInCategory.OST_CeilingOpening, BuiltInCategory.OST_ColumnOpening, @@ -98,36 +95,29 @@ internal static class TestCategories BuiltInCategory.OST_Roofs } }, - { Pipe, new List() - { - BuiltInCategory.OST_PipeCurves - } + { + Pipe, + new List() { BuiltInCategory.OST_PipeCurves } }, - { Roof, new List() - { - BuiltInCategory.OST_Roofs - } + { + Roof, + new List() { BuiltInCategory.OST_Roofs } }, - { Room, new List() - { - BuiltInCategory.OST_Rooms - } + { + Room, + new List() { BuiltInCategory.OST_Rooms } }, - { Schedule, new List() - { - BuiltInCategory.OST_Schedules - } + { + Schedule, + new List() { BuiltInCategory.OST_Schedules } }, - { Wall, new List() - { - BuiltInCategory.OST_Walls - } + { + Wall, + new List() { BuiltInCategory.OST_Walls } }, - { Wire, new List() - { - BuiltInCategory.OST_Wire - } + { + Wire, + new List() { BuiltInCategory.OST_Wire } }, }; - } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/xUnitRevitUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/xUnitRevitUtils.cs index 6191bd667b..adc1450adf 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/xUnitRevitUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/ConverterRevitTestsShared/xUnitRevitUtils.cs @@ -4,7 +4,5 @@ namespace ConverterRevitTestsShared { - internal class xUnitRevitUtils - { - } + internal class xUnitRevitUtils { } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Categories.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Categories.cs index 2cb63de3c3..24c346ed7b 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Categories.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Categories.cs @@ -2,70 +2,66 @@ using System.Collections.Generic; using System.Text; -namespace TestGenerator +namespace TestGenerator; + +internal struct CategoryProperties +{ + public string RevitType; + public string SyncAssertFunc; + public string AsyncAssertFunc; +} + +internal class Categories { - internal struct CategoryProperties - { - public string RevitType; - public string SyncAssertFunc; - public string AsyncAssertFunc; - } - internal class Categories - { - public const string AdaptiveComponent = "adaptivecomponent"; - public const string Beam = "beam"; - public const string Brep = "brep"; - public const string Column = "column"; - public const string Curve = "curve"; - public const string DirectShape = "directshape"; - public const string Duct = "duct"; - public const string FamilyInstance = "familyinstance"; - public const string Floor = "floor"; - public const string Opening = "opening"; - public const string Pipe = "pipe"; - public const string Roof = "roof"; - public const string Room = "room"; - public const string Schedule = "schedule"; - public const string Wall = "wall"; - public const string Wire = "wire"; + public const string AdaptiveComponent = "adaptivecomponent"; + public const string Beam = "beam"; + public const string Brep = "brep"; + public const string Column = "column"; + public const string Curve = "curve"; + public const string DirectShape = "directshape"; + public const string Duct = "duct"; + public const string FamilyInstance = "familyinstance"; + public const string Floor = "floor"; + public const string Opening = "opening"; + public const string Pipe = "pipe"; + public const string Roof = "roof"; + public const string Room = "room"; + public const string Schedule = "schedule"; + public const string Wall = "wall"; + public const string Wire = "wire"; - public static Dictionary CategoriesDict = new() + public static Dictionary CategoriesDict = + new() { - { AdaptiveComponent, new CategoryProperties() + { + AdaptiveComponent, + new CategoryProperties() { RevitType = "DB.FamilyInstance", SyncAssertFunc = "AssertUtils.AdaptiveComponentEqual" - } - }, - { Beam, new CategoryProperties() - { - RevitType = "DB.FamilyInstance", - SyncAssertFunc = "AssertUtils.FamilyInstanceEqual" } }, + { + Beam, + new CategoryProperties() { RevitType = "DB.FamilyInstance", SyncAssertFunc = "AssertUtils.FamilyInstanceEqual" } + }, //{ Brep, new CategoryProperties() // { // RevitType = "DB.FamilyInstance", // SyncAssertFunc = "AssertUtils.AdaptiveComponentEqual" // } //}, - { Column, new CategoryProperties() - { - RevitType = "DB.FamilyInstance", - SyncAssertFunc = "AssertUtils.FamilyInstanceEqual" - } + { + Column, + new CategoryProperties() { RevitType = "DB.FamilyInstance", SyncAssertFunc = "AssertUtils.FamilyInstanceEqual" } }, - { Curve, new CategoryProperties() - { - RevitType = "DB.CurveElement", - SyncAssertFunc = "AssertUtils.CurveEqual" - } + { + Curve, + new CategoryProperties() { RevitType = "DB.CurveElement", SyncAssertFunc = "AssertUtils.CurveEqual" } }, - { DirectShape, new CategoryProperties() - { - RevitType = "DB.DirectShape", - SyncAssertFunc = "AssertUtils.DirectShapeEqual" - } + { + DirectShape, + new CategoryProperties() { RevitType = "DB.DirectShape", SyncAssertFunc = "AssertUtils.DirectShapeEqual" } }, //{ Duct, new CategoryProperties() // { @@ -73,24 +69,22 @@ internal class Categories // SyncAssertFunc = "AssertUtils.DuctEqual" // } //}, - { FamilyInstance, new CategoryProperties() - { - RevitType = "DB.Element", - SyncAssertFunc = "AssertUtils.NestedEqual" - } + { + FamilyInstance, + new CategoryProperties() { RevitType = "DB.Element", SyncAssertFunc = "AssertUtils.NestedEqual" } }, - { Floor, new CategoryProperties() + { + Floor, + new CategoryProperties() { RevitType = "DB.Floor", SyncAssertFunc = "null", AsyncAssertFunc = "AssertUtils.FloorEqual" } }, - { Opening, new CategoryProperties() - { - RevitType = "DB.Element", - SyncAssertFunc = "AssertUtils.OpeningEqual" - } + { + Opening, + new CategoryProperties() { RevitType = "DB.Element", SyncAssertFunc = "AssertUtils.OpeningEqual" } }, //{ Pipe, new CategoryProperties() // { @@ -98,37 +92,30 @@ internal class Categories // SyncAssertFunc = "AssertUtils.PipeEqual" // } //}, - { Roof, new CategoryProperties() - { - RevitType = "DB.RoofBase", - SyncAssertFunc = "AssertUtils.RoofEqual" - } + { + Roof, + new CategoryProperties() { RevitType = "DB.RoofBase", SyncAssertFunc = "AssertUtils.RoofEqual" } }, - { Room, new CategoryProperties() - { - RevitType = "null", - SyncAssertFunc = "null" - } + { + Room, + new CategoryProperties() { RevitType = "null", SyncAssertFunc = "null" } }, - { Schedule, new CategoryProperties() + { + Schedule, + new CategoryProperties() { RevitType = "DB.ViewSchedule", //SyncAssertFunc = "null", AsyncAssertFunc = "AssertUtils.ScheduleEqual", } }, - { Wall, new CategoryProperties() - { - RevitType = "DB.Wall", - SyncAssertFunc = "AssertUtils.WallEqual" - } + { + Wall, + new CategoryProperties() { RevitType = "DB.Wall", SyncAssertFunc = "AssertUtils.WallEqual" } }, - { Wire, new CategoryProperties() - { - RevitType = "DB.Electrical.Wire", - SyncAssertFunc = "AssertUtils.WireEqual" - } + { + Wire, + new CategoryProperties() { RevitType = "DB.Electrical.Wire", SyncAssertFunc = "AssertUtils.WireEqual" } }, }; - } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Generator.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Generator.cs index f74eda99f4..97788bcc16 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Generator.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Generator.cs @@ -6,128 +6,168 @@ using Microsoft.CodeAnalysis; using System.Linq; -namespace TestGenerator +namespace TestGenerator; + +[Generator] +public class Generator : ISourceGenerator { - [Generator] - public class Generator : ISourceGenerator + public const string ToNative = "ToNative"; + public const string Updated = "Updated"; + + public void Execute(GeneratorExecutionContext context) { - public const string ToNative = "ToNative"; - public const string Updated = "Updated"; - public void Execute(GeneratorExecutionContext context) - { - //Debugger.Launch(); - var sb = new StringBuilder(); - sb.Append(TestTemplate.StartNamespace); + //Debugger.Launch(); + var sb = new StringBuilder(); + sb.Append(TestTemplate.StartNamespace); - // get any directory in the speckle sharp repo - var directoryInSharp = context.Compilation.Assembly.Locations.First().ToString(); - directoryInSharp = directoryInSharp.Replace("SourceFile(", ""); + // get any directory in the speckle sharp repo + var directoryInSharp = context.Compilation.Assembly.Locations.First().ToString(); + directoryInSharp = directoryInSharp.Replace("SourceFile(", ""); - // get the year for the test project as a string - var assemblyName = context.Compilation.AssemblyName; - var year = assemblyName.Substring(assemblyName.Length - 4); + // get the year for the test project as a string + var assemblyName = context.Compilation.AssemblyName; + var year = assemblyName.Substring(assemblyName.Length - 4); - string testFolderLocation = Globals.GetTestModelFolderLocation(directoryInSharp, year); - var subdirectories = Directory.GetDirectories(testFolderLocation); + string testFolderLocation = Globals.GetTestModelFolderLocation(directoryInSharp, year); + var subdirectories = Directory.GetDirectories(testFolderLocation); - foreach (var subdir in subdirectories) + foreach (var subdir in subdirectories) + { + string[] splitter = subdir.Split('\\'); + string category = splitter[splitter.Length - 1]; + + if (!Categories.CategoriesDict.TryGetValue(category.ToLower(), out var categoryProps)) { - string[] splitter = subdir.Split('\\'); - string category = splitter[splitter.Length - 1]; + continue; + //throw new Exception($"Category {category} is not in the CategoriesDict in the class {typeof(Categories).FullName}"); + } - if (!Categories.CategoriesDict.TryGetValue(category.ToLower(), out var categoryProps)) + var baseFiles = new List(); + var toNativeFiles = new List(); + var updatedFiles = new List(); + foreach (var file in Directory.GetFiles(subdir)) + { + var strippedFile = file.Split('\\').Last(); + if (!strippedFile.EndsWith(".rvt")) { continue; - //throw new Exception($"Category {category} is not in the CategoriesDict in the class {typeof(Categories).FullName}"); } - var baseFiles = new List(); - var toNativeFiles = new List(); - var updatedFiles = new List(); - foreach (var file in Directory.GetFiles(subdir)) - { - var strippedFile = file.Split('\\').Last(); - if (!strippedFile.EndsWith(".rvt")) continue; - strippedFile = strippedFile.Replace(".rvt", ""); - - // illegal character in revit file name - if (strippedFile.Contains('.')) continue; + strippedFile = strippedFile.Replace(".rvt", ""); - if (strippedFile.EndsWith(ToNative)) toNativeFiles.Add(strippedFile); - else if (strippedFile.EndsWith(Updated)) updatedFiles.Add(strippedFile); - else baseFiles.Add(strippedFile); + // illegal character in revit file name + if (strippedFile.Contains('.')) + { + continue; } - ValidateFilesInFolder(category, baseFiles, toNativeFiles, updatedFiles); - AddTestToStringBuilder(sb, category, categoryProps, baseFiles, toNativeFiles, updatedFiles); + if (strippedFile.EndsWith(ToNative)) + { + toNativeFiles.Add(strippedFile); + } + else if (strippedFile.EndsWith(Updated)) + { + updatedFiles.Add(strippedFile); + } + else + { + baseFiles.Add(strippedFile); + } } - sb.Append(TestTemplate.EndNamespace); - context.AddSource($"GeneratedTests.g.cs", sb.ToString()); + ValidateFilesInFolder(category, baseFiles, toNativeFiles, updatedFiles); + AddTestToStringBuilder(sb, category, categoryProps, baseFiles, toNativeFiles, updatedFiles); } - private static void AddTestToStringBuilder(StringBuilder sb, string category, CategoryProperties categoryProps, List baseFiles, List toNativeFiles, List updatedFiles) + sb.Append(TestTemplate.EndNamespace); + context.AddSource($"GeneratedTests.g.cs", sb.ToString()); + } + + private static void AddTestToStringBuilder( + StringBuilder sb, + string category, + CategoryProperties categoryProps, + List baseFiles, + List toNativeFiles, + List updatedFiles + ) + { + foreach (var file in baseFiles) { - foreach (var file in baseFiles) - { - sb.Append(TestTemplate.CreateFixture(category, file)); - var runToNativeTest = toNativeFiles.Contains(file + ToNative); - var runUpdateTest = updatedFiles.Contains(file + Updated); + sb.Append(TestTemplate.CreateFixture(category, file)); + var runToNativeTest = toNativeFiles.Contains(file + ToNative); + var runUpdateTest = updatedFiles.Contains(file + Updated); - sb.Append(TestTemplate.InitTest(category, file)); - sb.Append(TestTemplate.CreateToSpeckleTest(category, file)); + sb.Append(TestTemplate.InitTest(category, file)); + sb.Append(TestTemplate.CreateToSpeckleTest(category, file)); - if (runToNativeTest) - { - sb.Append(TestTemplate.CreateToNativeTest( + if (runToNativeTest) + { + sb.Append( + TestTemplate.CreateToNativeTest( category, file, categoryProps.RevitType, categoryProps.SyncAssertFunc ?? "null", categoryProps.AsyncAssertFunc ?? "null" - )); - sb.Append(TestTemplate.CreateSelectionTest(category, + ) + ); + sb.Append( + TestTemplate.CreateSelectionTest( + category, file, categoryProps.RevitType, categoryProps.SyncAssertFunc ?? "null", categoryProps.AsyncAssertFunc ?? "null" - )); - } - if (runUpdateTest) - { - sb.Append(TestTemplate.CreateUpdateTest(category, + ) + ); + } + if (runUpdateTest) + { + sb.Append( + TestTemplate.CreateUpdateTest( + category, file, categoryProps.RevitType, categoryProps.SyncAssertFunc ?? "null", categoryProps.AsyncAssertFunc ?? "null" - )); - } - sb.Append(TestTemplate.EndClass); + ) + ); } + sb.Append(TestTemplate.EndClass); } + } - private static void ValidateFilesInFolder(string category, List baseFiles, List toNativeFiles, List updatedFiles) + private static void ValidateFilesInFolder( + string category, + List baseFiles, + List toNativeFiles, + List updatedFiles + ) + { + foreach (var file in toNativeFiles) { - foreach (var file in toNativeFiles) + if (!baseFiles.Contains(file.Substring(0, file.Length - ToNative.Length))) { - if (!baseFiles.Contains(file.Substring(0, file.Length - ToNative.Length))) - { - throw new FileNotFoundException($"There is a file named {file} in folder {category}, but there is no corrosponding base file (without the {ToNative} extension)."); - } + throw new FileNotFoundException( + $"There is a file named {file} in folder {category}, but there is no corrosponding base file (without the {ToNative} extension)." + ); } - foreach (var file in updatedFiles) + } + foreach (var file in updatedFiles) + { + if (!baseFiles.Contains(file.Substring(0, file.Length - Updated.Length))) { - if (!baseFiles.Contains(file.Substring(0, file.Length - Updated.Length))) - { - throw new FileNotFoundException($"There is a file named {file} in folder {category}, but there is no corrosponding base file (without the {Updated} extension)."); - } + throw new FileNotFoundException( + $"There is a file named {file} in folder {category}, but there is no corrosponding base file (without the {Updated} extension)." + ); } } + } - public void Initialize(GeneratorInitializationContext context) - { - // No initialization required for this one - //Debugger.Launch(); - } + public void Initialize(GeneratorInitializationContext context) + { + // No initialization required for this one + //Debugger.Launch(); } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Globals.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Globals.cs index e7216e7630..e1ef0c3e57 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Globals.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/Globals.cs @@ -1,33 +1,35 @@ using System.IO; using System.Linq; -namespace TestGenerator +namespace TestGenerator; + +public static class Globals { - public static class Globals + /// + /// This is the same method in ConverterRevitTests.Globals + /// TODO: Consolidate + /// + /// + /// + /// + public static string GetTestModelFolderLocation(string directoryStringInSpeckleSharp, string year) { - /// - /// This is the same method in ConverterRevitTests.Globals - /// TODO: Consolidate - /// - /// - /// - /// - public static string GetTestModelFolderLocation(string directoryStringInSpeckleSharp, string year) - { - var assemblyLocationList = directoryStringInSpeckleSharp.Split('\\').ToList(); + var assemblyLocationList = directoryStringInSpeckleSharp.Split('\\').ToList(); - for (var i = assemblyLocationList.Count - 1; i >= 0; i--) + for (var i = assemblyLocationList.Count - 1; i >= 0; i--) + { + var folderName = assemblyLocationList[i]; + assemblyLocationList.RemoveAt(i); + if (folderName == "speckle-sharp") { - var folderName = assemblyLocationList[i]; - assemblyLocationList.RemoveAt(i); - if (folderName == "speckle-sharp") break; + break; } - assemblyLocationList.Add("speckle-sharp-test-models"); - assemblyLocationList.Add("Revit"); - - assemblyLocationList.Add(year); - var testFolderLocation = string.Join("\\", assemblyLocationList); - return testFolderLocation; } + assemblyLocationList.Add("speckle-sharp-test-models"); + assemblyLocationList.Add("Revit"); + + assemblyLocationList.Add(year); + var testFolderLocation = string.Join("\\", assemblyLocationList); + return testFolderLocation; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/TestTemplate.cs b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/TestTemplate.cs index 6ab853788b..1e57e3471b 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/TestTemplate.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitTests/TestGenerator/TestTemplate.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.Text; -namespace TestGenerator +namespace TestGenerator; + +internal static class TestTemplate { - internal static class TestTemplate - { - public const string StartNamespace = @" + public const string StartNamespace = + @" using System.Threading.Tasks; using Xunit; using DB = Autodesk.Revit.DB; @@ -14,10 +15,13 @@ internal static class TestTemplate namespace ConverterRevitTests { "; - public const string EndNamespace = @" + public const string EndNamespace = + @" } "; - public static string CreateFixture(string category, string fileName) => $@" + + public static string CreateFixture(string category, string fileName) => + $@" public class {category}{fileName}Fixture : SpeckleConversionFixture {{ public override string Category => ""{category}""; @@ -29,7 +33,8 @@ public class {category}{fileName}Fixture : SpeckleConversionFixture }} "; - public static string InitTest(string category, string fileName) => $@" + public static string InitTest(string category, string fileName) => + $@" public class {category}{fileName}Tests : SpeckleConversionTest, IClassFixture<{category}{fileName}Fixture> {{ public {category}{fileName}Tests({category}{fileName}Fixture fixture) : base(fixture) @@ -37,7 +42,8 @@ public class {category}{fileName}Tests : SpeckleConversionTest, IClassFixture<{c }} "; - public static string CreateToSpeckleTest(string category, string fileName) => $@" + public static string CreateToSpeckleTest(string category, string fileName) => + $@" [Fact] [Trait(""{category}"", ""{fileName}ToSpeckle"")] public async Task {category}{fileName}ToSpeckle() @@ -46,7 +52,14 @@ public static string CreateToSpeckleTest(string category, string fileName) => $@ }} "; - public static string CreateToNativeTest(string category, string fileName, string revitType, string syncAssertFunc, string asyncAssertFunc) => $@" + public static string CreateToNativeTest( + string category, + string fileName, + string revitType, + string syncAssertFunc, + string asyncAssertFunc + ) => + $@" [Fact] [Trait(""{category}"", ""{fileName}ToNative"")] public async Task {category}{fileName}ToNative() @@ -55,7 +68,14 @@ public static string CreateToNativeTest(string category, string fileName, string }} "; - public static string CreateUpdateTest(string category, string fileName, string revitType, string syncAssertFunc, string asyncAssertFunc) => $@" + public static string CreateUpdateTest( + string category, + string fileName, + string revitType, + string syncAssertFunc, + string asyncAssertFunc + ) => + $@" [Fact] [Trait(""{category}"", ""{fileName}ToNativeUpdates"")] public async Task {category}{fileName}ToNativeUpdates() @@ -64,7 +84,14 @@ public static string CreateUpdateTest(string category, string fileName, string r }} "; - public static string CreateSelectionTest(string category, string fileName, string revitType, string syncAssertFunc, string asyncAssertFunc) => $@" + public static string CreateSelectionTest( + string category, + string fileName, + string revitType, + string syncAssertFunc, + string asyncAssertFunc + ) => + $@" [Fact] [Trait(""{category}"", ""{fileName}Selection"")] public async Task {category}{fileName}SelectionToNative() @@ -73,8 +100,8 @@ public static string CreateSelectionTest(string category, string fileName, strin }} "; - public const string EndClass = @" + public const string EndClass = + @" } "; - } } diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/BrepEncoder.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/BrepEncoder.cs index 39bc320ead..b70e40b98e 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/BrepEncoder.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/BrepEncoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Rhino.Geometry; @@ -31,11 +31,15 @@ double modelRelativeTolerance ) { if (scaleFactor != 1.0 && !brep.Scale(scaleFactor)) + { return default; + } var bbox = brep.GetBoundingBox(false); if (!bbox.IsValid || bbox.Diagonal.Length < modelAngleToleranceRadians) + { return default; + } // Split and Shrink faces { @@ -64,8 +68,12 @@ private static BrepIssues AuditBrep(Brep brep, double modelRelativeTolerance) // Edges { foreach (var edge in brep.Edges) + { if (edge.Tolerance > modelRelativeTolerance) + { options |= BrepIssues.OutOfToleranceEdges; + } + } //GeometryEncoder.Context.Peek.RuntimeMessage(10, $"Geometry contains out of tolerance edges, it will be rebuilt.", edge); } @@ -104,7 +112,9 @@ double modelRelativeTolerance var edgesToUnjoin = brep.Edges.Select(x => x.EdgeIndex); var shells = brep.UnjoinEdges(edgesToUnjoin); if (shells.Length == 0) + { shells = new[] { brep }; + } var kinkyEdges = 0; var microEdges = 0; @@ -118,7 +128,9 @@ double modelRelativeTolerance int edgeCount = edges.Count; for (int ei = 0; ei < edgeCount; ++ei) + { edges.SplitKinkyEdge(ei, modelAngleToleranceRadians); + } kinkyEdges += edges.Count - edgeCount; #if RHINO7 @@ -138,12 +150,16 @@ double modelRelativeTolerance face.SetDomain(0, new Interval(0.0, width)); var deltaU = KnotListEncoder.MinDelta(face.GetSpanVector(0)); if (deltaU < 1e-6) + { face.SetDomain(0, new Interval(0.0, width * (1e-6 / deltaU))); + } face.SetDomain(1, new Interval(0.0, height)); var deltaV = KnotListEncoder.MinDelta(face.GetSpanVector(1)); if (deltaV < 1e-6) + { face.SetDomain(1, new Interval(0.0, height * (1e-6 / deltaV))); + } } face.RebuildEdges(1e-6, false, true); @@ -163,7 +179,9 @@ double modelRelativeTolerance { var merge = new Brep(); foreach (var shell in join) + { merge.Append(shell); + } brep = merge; } @@ -171,7 +189,9 @@ double modelRelativeTolerance var res = new List(); for (int i = 0; i < brep.Faces.Count; i++) + { res.Add(brep.Faces.ExtractFace(i)); + } brep = Brep.JoinBreps(res, 0.001)[0]; diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.BuiltElements.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.BuiltElements.cs index 664f30dd16..1df6117f49 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.BuiltElements.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.BuiltElements.cs @@ -98,7 +98,9 @@ public ApplicationObject ViewToNative(View3D view) SetViewParams(viewport, view); if (view.isOrthogonal) + { viewport.ChangeToParallelProjection(true); + } var commitInfo = GetCommitInfo(); bakedViewName = ReceiveMode == ReceiveMode.Create ? $"{commitInfo} - {view.name}" : $"{view.name}"; @@ -135,7 +137,9 @@ private void AttachViewParams(Base speckleView, ViewInfo view) out double far ) ) + { speckleView["frustrum"] = new List { left, right, bottom, top, near, far }; + } // crop speckleView["cropped"] = bool.FalseString; @@ -146,7 +150,9 @@ private RhinoViewport SetViewParams(RhinoViewport viewport, Base speckleView) // lens var lens = speckleView["lens"] as double?; if (lens != null) + { viewport.Camera35mmLensLength = (double)lens; + } return viewport; } @@ -194,11 +200,13 @@ public ApplicationObject GridlineToNative(GridLine gridline) { var linetypeIndex = Doc.Linetypes.Find("Dashed"); if (linetypeIndex >= 0) + { atts = new ObjectAttributes() { LinetypeIndex = linetypeIndex, LinetypeSource = ObjectLinetypeSource.LinetypeFromObject }; + } } // bake the curve @@ -216,10 +224,15 @@ public ApplicationObject GridlineToNative(GridLine gridline) { var labelStartId = Doc.Objects.AddTextDot(gridline.label, curve.PointAtStart); if (labelStartId != Guid.Empty) + { appObj.Update(convertedItem: Doc.Objects.FindId(labelStartId), createdId: labelStartId.ToString()); + } + var labelEndId = Doc.Objects.AddTextDot(gridline.label, curve.PointAtEnd); if (labelEndId != Guid.Empty) + { appObj.Update(convertedItem: Doc.Objects.FindId(labelEndId), createdId: labelEndId.ToString()); + } } return appObj; @@ -235,10 +248,14 @@ public RH.Curve AlignmentToNative(Alignment alignment) { var converted = CurveToNative(entity); if (converted != null) + { curves.Add(converted); + } } if (curves.Count == 0) + { return null; + } // try to join entity curves var joined = RH.Curve.JoinCurves(curves); diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Geometry.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Geometry.cs index 285e8fb09e..514362c7ce 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Geometry.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Geometry.cs @@ -32,13 +32,17 @@ public double[] PointToArray(RH.Point3d pt) public List PointListToNative(IList arr, string units) { if (arr.Count % 3 != 0) + { throw new SpeckleException("Array malformed: length%3 != 0."); + } var points = new List(arr.Count / 3); var sf = Units.GetConversionFactor(units, ModelUnits); for (int i = 2; i < arr.Count; i += 3) + { points.Add(new RH.Point3d(arr[i - 2] * sf, arr[i - 1] * sf, arr[i] * sf)); + } return points; } @@ -189,7 +193,9 @@ public RH.ArcCurve CircleToNative(Circle circ) var myCircle = new RH.ArcCurve(circle); if (circ.domain != null) + { myCircle.Domain = IntervalToNative(circ.domain); + } return myCircle; } @@ -243,7 +249,9 @@ public RH.ArcCurve ArcToNative(Arc arc) var arcCurve = new RH.ArcCurve(_arc); if (arc.domain != null) + { arcCurve.Domain = IntervalToNative(arc.domain); + } return arcCurve; } @@ -272,10 +280,14 @@ public RH.Curve EllipseToNative(Ellipse e) var myEllp = elp.ToNurbsCurve(); if (e.domain != null) + { myEllp.Domain = IntervalToNative(e.domain); + } if (e.trimDomain != null) + { myEllp = myEllp.Trim(IntervalToNative(e.trimDomain)).ToNurbsCurve(); + } return myEllp; } @@ -316,7 +328,10 @@ public ICurve PolylineToSpeckle(RH.Polyline poly, Interval domain, string units { var l = LineToSpeckle(new RH.Line(poly[0], poly[1]), u); if (domain != null) + { l.domain = domain; + } + return l; } @@ -324,7 +339,9 @@ public ICurve PolylineToSpeckle(RH.Polyline poly, Interval domain, string units myPoly.closed = poly.IsClosed; if (myPoly.closed) + { myPoly.value.RemoveRange(myPoly.value.Count - 3, 3); + } myPoly.domain = domain; myPoly.bbox = BoxToSpeckle(new RH.Box(poly.BoundingBox), u); @@ -356,7 +373,9 @@ public Base PolylineToSpeckle(RH.PolylineCurve poly, string units = null) myPoly.closed = polyline.IsClosed; if (myPoly.closed) + { myPoly.value.RemoveRange(myPoly.value.Count - 3, 3); + } myPoly.domain = intervalToSpeckle; myPoly.bbox = BoxToSpeckle(new RH.Box(poly.GetBoundingBox(true)), u); @@ -373,11 +392,15 @@ public RH.PolylineCurve PolylineToNative(Polyline poly) List points = PointListToNative(poly.value, poly.units); if (poly.closed) + { points.Add(points[0]); + } var myPoly = new RH.PolylineCurve(points); if (poly.domain != null) + { myPoly.Domain = IntervalToNative(poly.domain); + } return myPoly; } @@ -408,6 +431,7 @@ public RH.PolyCurve PolycurveToNative(Polycurve p) var notes = new List(); foreach (var segment in p.segments) + { try { //let the converter pick the best type of curve @@ -417,9 +441,12 @@ public RH.PolyCurve PolycurveToNative(Polycurve p) { notes.Add($"Could not append curve {segment.GetType()} to PolyCurve"); } + } if (p.domain != null) + { myPolyc.Domain = IntervalToNative(p.domain); + } return myPolyc; } @@ -466,7 +493,9 @@ public ICurve CurveToSpeckle(RH.Curve curve, string units = null) curve.TryGetPlane(out pln, tolerance); if (curve is RH.PolyCurve polyCurve) + { return PolycurveToSpeckle(polyCurve, u); + } if (curve.IsCircle(tolerance) && curve.IsClosed) { @@ -561,19 +590,29 @@ public RH.NurbsCurve NurbsToNative(Curve curve) var nurbsCurve = RH.NurbsCurve.Create(false, curve.degree, ptsList); if (nurbsCurve == null) + { return null; + } for (int j = 0; j < nurbsCurve.Points.Count; j++) + { nurbsCurve.Points.SetPoint(j, ptsList[j], curve.weights[j]); + } // check knot multiplicity to match Rhino's standard of (# control points + degree - 1) // skip extra knots at start & end if knot multiplicity is (# control points + degree + 1) int extraKnots = curve.knots.Count - nurbsCurve.Knots.Count; for (int j = 0; j < nurbsCurve.Knots.Count; j++) + { if (extraKnots == 2) + { nurbsCurve.Knots[j] = curve.knots[j + 1]; + } else + { nurbsCurve.Knots[j] = curve.knots[j]; + } + } nurbsCurve.Domain = IntervalToNative(curve.domain ?? new Interval(0, 1)); return nurbsCurve; @@ -660,7 +699,11 @@ public Mesh MeshToSpeckle(RH.SubD mesh, string units = null) var Faces = mesh.Faces.SelectMany(face => { - if (face.VertexCount == 4) return new[] { 4, subDVertices.IndexOf(face.VertexAt(0)), subDVertices.IndexOf(face.VertexAt(1)), subDVertices.IndexOf(face.VertexAt(2)), subDVertices.IndexOf(face.VertexAt(3)) }; + if (face.VertexCount == 4) + { + return new[] { 4, subDVertices.IndexOf(face.VertexAt(0)), subDVertices.IndexOf(face.VertexAt(1)), subDVertices.IndexOf(face.VertexAt(2)), subDVertices.IndexOf(face.VertexAt(3)) }; + } + return new[] { 3, subDVertices.IndexOf(face.VertexAt(0)), subDVertices.IndexOf(face.VertexAt(1)), subDVertices.IndexOf(face.VertexAt(2)) }; }).ToList(); @@ -692,7 +735,9 @@ public RH.Mesh MeshToNative(Mesh mesh) { int n = mesh.faces[i]; if (n < 3) + { n += 3; // 0 -> 3, 1 -> 4 + } if (n == 3) { @@ -763,17 +808,23 @@ public RH.PointCloud PointcloudToNative(Pointcloud pointcloud) double scaleFactor = ScaleToNative(1, pointcloud.units); for (int i = 0; i < numPoints; i++) + { rhPoints[i] = new RH.Point3d( sPoints[3 * i] * scaleFactor, sPoints[3 * i + 1] * scaleFactor, sPoints[3 * i + 2] * scaleFactor ); + } var _pointcloud = new RH.PointCloud(rhPoints); if (pointcloud.colors.Count == rhPoints.Length) + { for (int i = 0; i < rhPoints.Length; i++) + { _pointcloud[i].Color = Color.FromArgb(pointcloud.colors[i]); + } + } return _pointcloud; } @@ -793,8 +844,12 @@ private RH.PointCloud SetPointcloudParams(RH.PointCloud pointcloud, Base speckle // normals var normals = specklePointcloud["normals"] as List; if (normals != null && normals.Count == pointcloud.Count) + { for (int i = 0; i < pointcloud.Count; i++) + { pointcloud[i].Normal = VectorToNative(normals[i]); + } + } return pointcloud; } @@ -812,13 +867,17 @@ public Brep BrepToSpeckle(RH.Brep brep, string units = null, RH.Mesh previewMesh brep.Repair(tol); if (PreprocessGeometry) + { brep = BrepEncoder.ToRawBrep(brep, 1.0, Doc.ModelAngleToleranceRadians, Doc.ModelRelativeTolerance); + } // get display mesh and attach render material to it if it exists var displayMesh = previewMesh ?? GetBrepDisplayMesh(brep); var displayValue = MeshToSpeckle(displayMesh, u); if (displayValue != null && mat != null) + { displayValue["renderMaterial"] = mat; + } var spcklBrep = new Brep(displayValue: displayValue, provenance: RhinoAppName, units: u); @@ -961,9 +1020,13 @@ public RH.Brep BrepToNative(Brep brep, out List notes) edge.Domain == null || edge.Domain.start == edge.Curve.domain.start && edge.Domain.end == edge.Curve.domain.end ) + { newBrep.Edges.Add(edge.Curve3dIndex); + } else + { newBrep.Edges.Add(edge.StartIndex, edge.EndIndex, edge.Curve3dIndex, IntervalToNative(edge.Domain), tol); + } }); brep.Faces.ForEach(face => { @@ -981,21 +1044,27 @@ public RH.Brep BrepToNative(Brep brep, out List notes) { RH.BrepTrim rhTrim; if (trim.EdgeIndex != -1) + { rhTrim = newBrep.Trims.Add( newBrep.Edges[trim.EdgeIndex], trim.IsReversed, newBrep.Loops[trim.LoopIndex], trim.CurveIndex ); + } else if (trim.TrimType == BrepTrimType.Singular) + { rhTrim = newBrep.Trims.AddSingularTrim( newBrep.Vertices[trim.EndIndex], newBrep.Loops[trim.LoopIndex], (RH.IsoStatus)trim.IsoStatus, trim.CurveIndex ); + } else + { rhTrim = newBrep.Trims.Add(trim.IsReversed, newBrep.Loops[trim.LoopIndex], trim.CurveIndex); + } rhTrim.IsoStatus = (RH.IsoStatus)trim.IsoStatus; rhTrim.TrimType = (RH.BrepTrimType)trim.TrimType; @@ -1020,13 +1089,17 @@ public RH.Extrusion ExtrusionToNative(Extrusion extrusion) RH.Curve outerProfile = CurveToNative((Curve)extrusion.profile); RH.Curve innerProfile = null; if (extrusion.profiles.Count == 2) + { innerProfile = CurveToNative((Curve)extrusion.profiles[1]); + } try { var IsClosed = extrusion.profile.GetType().GetProperty("IsClosed").GetValue(extrusion.profile, null) as bool?; if (IsClosed != true) + { outerProfile.Reverse(); + } } catch { } @@ -1036,7 +1109,9 @@ public RH.Extrusion ExtrusionToNative(Extrusion extrusion) (bool)extrusion.capped ); if (innerProfile != null) + { myExtrusion.AddInnerProfile(innerProfile); + } return myExtrusion; } @@ -1046,29 +1121,45 @@ public RH.Extrusion ExtrusionToNative(Extrusion extrusion) public bool CurveSegments(List L, RH.Curve crv, bool recursive) { if (crv == null) + { return false; + } RH.PolyCurve polycurve = crv as RH.PolyCurve; if (polycurve != null) { if (recursive) + { polycurve.RemoveNesting(); + } RH.Curve[] segments = polycurve.Explode(); if (segments == null) + { return false; + } if (segments.Length == 0) + { return false; + } if (recursive) + { foreach (RH.Curve S in segments) + { CurveSegments(L, S, recursive); + } + } else + { foreach (RH.Curve S in segments) + { L.Add(S.DuplicateShallow() as RH.Curve); + } + } return true; } @@ -1076,7 +1167,9 @@ public bool CurveSegments(List L, RH.Curve crv, bool recursive) //Nothing else worked, lets assume it's a nurbs curve and go from there... var nurbs = crv.ToNurbsCurve(); if (nurbs == null) + { return false; + } double t0 = nurbs.Domain.Min; double t1 = nurbs.Domain.Max; @@ -1087,7 +1180,9 @@ public bool CurveSegments(List L, RH.Curve crv, bool recursive) do { if (!nurbs.GetNextDiscontinuity(RH.Continuity.C1_locus_continuous, t0, t1, out t)) + { break; + } var trim = new RH.Interval(t0, t); if (trim.Length < 1e-10) @@ -1099,13 +1194,17 @@ public bool CurveSegments(List L, RH.Curve crv, bool recursive) var M = nurbs.DuplicateCurve(); M = M.Trim(trim); if (M.IsValid) + { L.Add(M); + } t0 = t; } while (true); if (L.Count == LN) + { L.Add(nurbs); + } return true; } @@ -1143,10 +1242,15 @@ public RH.NurbsSurface SurfaceToNative(Surface surface) // Set knot vectors var correctUKnots = GetCorrectKnots(surface.knotsU, surface.countU, surface.degreeU); for (int i = 0; i < correctUKnots.Count; i++) + { result.KnotsU[i] = correctUKnots[i]; + } + var correctVKnots = GetCorrectKnots(surface.knotsV, surface.countV, surface.degreeV); for (int i = 0; i < correctVKnots.Count; i++) + { result.KnotsV[i] = correctVKnots[i]; + } // Set control points for (var i = 0; i < points.Count; i++) diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Mappings.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Mappings.cs index e23ef59ee1..c04c0451b7 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Mappings.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Mappings.cs @@ -134,18 +134,31 @@ private Base MappingToSpeckle(string mapping, RhinoObject @object, List case DirectShape o: if (string.IsNullOrEmpty(o.name)) + { o.name = "Speckle Mapper Shape"; + } + if (@object.Geometry as RH.Brep != null) + { o.baseGeometries = new List { BrepToSpeckle((RH.Brep)@object.Geometry) }; + } else if (@object.Geometry as RH.Mesh != null) + { o.baseGeometries = new List { MeshToSpeckle((RH.Mesh)@object.Geometry) }; + } + break; case FreeformElement o: if (@object.Geometry as RH.Brep != null) + { o.baseGeometries = new List { BrepToSpeckle((RH.Brep)@object.Geometry) }; + } else if (@object.Geometry as RH.Mesh != null) + { o.baseGeometries = new List { MeshToSpeckle((RH.Mesh)@object.Geometry) }; + } + break; case FamilyInstance o: @@ -197,9 +210,14 @@ private List GetSurfaceBrepEdges( RH.Curve[] brpCurves = null; if (getInterior) + { brpCurves = brep.DuplicateNakedEdgeCurves(false, true); + } else + { brpCurves = brep.DuplicateNakedEdgeCurves(true, false); + } + if (getBottom) { var bottomCrv = brpCurves @@ -214,15 +232,20 @@ private List GetSurfaceBrepEdges( ) ?.Aggregate((curMin, o) => curMin == null || o.PointAtStart.Z < curMin.PointAtStart.Z ? o : curMin); if (bottomCrv != null) + { brpCurves = new[] { bottomCrv }; + } } List outCurves = null; if (brpCurves != null && brpCurves.Count() > 0) + { outCurves = brpCurves.Count() == 1 ? new List { (ICurve)ConvertToSpeckle(brpCurves[0]) } : RH.Curve.JoinCurves(brpCurves, tol).Select(o => (ICurve)ConvertToSpeckle(o)).ToList(); + } + return outCurves; } } diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Organization.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Organization.cs index 82a9c63b94..2e188dfa70 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Organization.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Organization.cs @@ -27,7 +27,10 @@ Layer GetLayer(string path) { var index = Doc.Layers.FindByFullPath(path, RhinoMath.UnsetIntIndex); if (index != RhinoMath.UnsetIntIndex) + { return Doc.Layers[index]; + } + return null; } Layer MakeLayer(string name, Layer parentLayer = null) @@ -36,10 +39,16 @@ Layer MakeLayer(string name, Layer parentLayer = null) { Layer newLayer = new() { Name = name }; if (parentLayer != null) + { newLayer.ParentLayerId = parentLayer.Id; + } + int newIndex = Doc.Layers.Add(newLayer); if (newIndex < 0) + { return null; + } + return Doc.Layers.FindIndex(newIndex); } catch (Exception e) @@ -101,7 +110,10 @@ Layer MakeLayer(string name, Layer parentLayer = null) : null; layer.Color = displayStyle.ObjectColor; if (renderMaterial != null) + { layer.RenderMaterial = renderMaterial; + } + layer.PlotWeight = displayStyle.PlotWeight; layer.LinetypeIndex = displayStyle.LinetypeIndex; diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Other.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Other.cs index eb3df495a5..fff4047788 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Other.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Other.cs @@ -33,7 +33,10 @@ public RH.ObjectAttributes DisplayStyleToNative(DisplayStyle display) attributes.ObjectColor = Color.FromArgb(display.color); var colorSource = RH.ObjectColorSource.ColorFromObject; if (display["colorSource"] != null) + { Enum.TryParse(display["colorSource"] as string, out colorSource); + } + attributes.ColorSource = colorSource; // line type @@ -41,7 +44,10 @@ public RH.ObjectAttributes DisplayStyleToNative(DisplayStyle display) attributes.LinetypeIndex = lineStyle != null ? lineStyle.Index : 0; var lineSource = RH.ObjectLinetypeSource.LinetypeFromObject; if (display["lineSource"] != null) + { Enum.TryParse(display["lineSource"] as string, out lineSource); + } + attributes.LinetypeSource = lineSource; // plot weight @@ -50,7 +56,10 @@ public RH.ObjectAttributes DisplayStyleToNative(DisplayStyle display) attributes.PlotWeight = display.lineweight * conversionFactor; var weightSource = RH.ObjectPlotWeightSource.PlotWeightFromObject; if (display["weightSource"] != null) + { Enum.TryParse(display["weightSource"] as string, out weightSource); + } + attributes.PlotWeightSource = weightSource; return attributes; @@ -121,11 +130,19 @@ public DisplayStyle DisplayStyleToSpeckle(RH.ObjectAttributes attributes, RH.Lay // attach rhino specific props if (colorSource != null) + { style["colorSource"] = colorSource; + } + if (lineTypeSource != null) + { style["lineSource"] = lineTypeSource; + } + if (weightSource != null) + { style["weightSource"] = weightSource; + } return style; } @@ -140,7 +157,9 @@ public RenderMaterial RenderMaterialToNative(Other.RenderMaterial speckleMateria //NOTE: Looking up renderMaterials this way is slow, maybe we can create a dictionary? var existing = Doc.RenderMaterials.FirstOrDefault(x => x.Name == speckleName); if (existing != null) + { return existing; + } RenderMaterial rm; //#if RHINO6 @@ -178,7 +197,9 @@ public Other.RenderMaterial RenderMaterialToSpeckle(RH.Material material) { var renderMaterial = new Other.RenderMaterial(); if (material == null) + { return renderMaterial; + } renderMaterial.name = material.Name ?? "default"; // default rhino material has no name or id #if RHINO6 @@ -189,7 +210,9 @@ public Other.RenderMaterial RenderMaterialToSpeckle(RH.Material material) // for some reason some default material transparency props are 1 when they shouldn't be - use this hack for now if ((renderMaterial.name.ToLower().Contains("glass") || renderMaterial.name.ToLower().Contains("gem")) && renderMaterial.opacity == 0) + { renderMaterial.opacity = 0.3; + } #else RH.Material matToUse = material; if (!material.IsPhysicallyBased) @@ -216,7 +239,9 @@ public Other.RenderMaterial RenderMaterialToSpeckle(Rhino.Render.RenderMaterial { var renderMaterial = new Other.RenderMaterial(); if (material == null) + { return renderMaterial; + } renderMaterial.name = material.Name ?? "default"; // default rhino material has no name or id #if RHINO6 @@ -227,7 +252,9 @@ public Other.RenderMaterial RenderMaterialToSpeckle(Rhino.Render.RenderMaterial // for some reason some default material transparency props are 1 when they shouldn't be - use this hack for now if ((renderMaterial.name.ToLower().Contains("glass") || renderMaterial.name.ToLower().Contains("gem")) && renderMaterial.opacity == 0) + { renderMaterial.opacity = 0.3; + } #else RH.PhysicallyBasedMaterial pbrMaterial = material.ConvertToPhysicallyBased(RenderTexture.TextureGeneration.Allow); renderMaterial.diffuse = pbrMaterial.BaseColor.AsSystemColor().ToArgb(); @@ -274,9 +301,14 @@ public Other.Hatch HatchToSpeckle(Hatch hatch) // retrieve hatch loops var loops = new List(); foreach (var outer in hatch.Get3dCurves(true).ToList()) + { loops.Add(new HatchLoop(CurveToSpeckle(outer), HatchLoopType.Outer)); + } + foreach (var inner in hatch.Get3dCurves(false).ToList()) + { loops.Add(new HatchLoop(CurveToSpeckle(inner), HatchLoopType.Inner)); + } _hatch.loops = loops; _hatch.scale = hatch.PatternScale; @@ -294,7 +326,10 @@ private RH.HatchPattern FindDefaultPattern(string patternName) ?.ToList() .FirstOrDefault(); if (defaultPattern != null) + { return defaultPattern.GetValue(this, null) as RH.HatchPattern; + } + return RH.HatchPattern.Defaults.Solid; } @@ -321,10 +356,13 @@ public BlockDefinition BlockDefinitionToSpeckle(RH.InstanceDefinition definition { // check if this has been converted and cached already if (BlockDefinitions.ContainsKey(definition.Name)) + { return BlockDefinitions[definition.Name]; + } var geometry = new List(); foreach (var obj in definition.GetObjects()) + { if (CanConvertToSpeckle(obj)) { Base converted = ConvertToSpeckle(obj); @@ -334,6 +372,7 @@ public BlockDefinition BlockDefinitionToSpeckle(RH.InstanceDefinition definition geometry.Add(converted); } } + } // rhino by default sets selected block def base pt at world origin var _definition = new BlockDefinition(definition.Name, geometry, PointToSpeckle(Point3d.Origin)) @@ -358,11 +397,15 @@ public RH.InstanceDefinition DefinitionToNative(Base definition, out List).Cast().ToList(); break; default: @@ -397,8 +443,12 @@ public RH.InstanceDefinition DefinitionToNative(Base definition, out List notes); if (notes.Count > 0) + { appObj.Update(log: notes); + } + if (instanceDef == null) { appObj.Update(status: ApplicationObject.State.Failed, logItem: "Could not create block definition"); @@ -592,7 +659,10 @@ public ApplicationObject InstanceToNative(Instance instance, bool AppendToModelS // update appobj appObj.Update(convertedItem: _instance); if (AppendToModelSpace) + { appObj.CreatedIds.Add(instanceId.ToString()); + } + return appObj; } @@ -619,19 +689,25 @@ void StoreObject(Base current, string containerId) //Handle objects convertable using displayValues var fallbackMember = current["displayValue"] ?? current["@displayValue"]; if (fallbackMember != null) + { GraphTraversal.TraverseMember(fallbackMember).ToList().ForEach(o => StoreObject(o, containerId)); + } } string LayerId(TraversalContext context) => LayerIdRecurse(context, new StringBuilder()).ToString(); StringBuilder LayerIdRecurse(TraversalContext context, StringBuilder stringBuilder) { if (context.propName == null) + { return stringBuilder; + } // see if there's a layer property on this obj var layer = context.current["layer"] as string ?? context.current["Layer"] as string; if (!string.IsNullOrEmpty(layer)) + { return new StringBuilder(layer); + } var objectLayerName = context.propName[0] == '@' ? context.propName.Substring(1) : context.propName; @@ -681,14 +757,21 @@ public Text TextToSpeckle(TextEntity text) // display value as list of polylines var outlines = text.CreateCurves(text.DimensionStyle, false)?.ToList(); if (outlines != null) + { foreach (var outline in outlines) { Polyline poly = null; if (!outline.TryGetPolyline(out poly)) + { outline.ToPolyline(0, 1, 0, 0, 0, 0.1, 0, 0, true).TryGetPolyline(out poly); // this is from nurbs, should probably be refined for text + } + if (poly != null) + { _text.displayValue.Add(PolylineToSpeckle(poly) as Geometry.Polyline); + } } + } _text.plane = PlaneToSpeckle(text.Plane); _text.rotation = text.TextRotationRadians; @@ -702,7 +785,10 @@ public Text TextToSpeckle(TextEntity text) var props = Utilities.GetApplicationProps(text, typeof(TextEntity), true, ignore); var style = text.DimensionStyle.HasName ? text.DimensionStyle.Name : string.Empty; if (!string.IsNullOrEmpty(style)) + { props["DimensionStyleName"] = style; + } + _text[RhinoPropName] = props; return _text; @@ -713,9 +799,14 @@ public TextEntity TextToNative(Text text) var _text = new TextEntity(); _text.Plane = PlaneToNative(text.plane); if (!string.IsNullOrEmpty(text.richText)) + { _text.RichText = text.richText; + } else + { _text.PlainText = text.value; + } + _text.TextHeight = ScaleToNative(text.height, text.units); _text.TextRotationRadians = text.rotation; @@ -728,14 +819,18 @@ public TextEntity TextToNative(Text text) { var value = sourceAppProps[scaleProp] as double?; if (value.HasValue) + { sourceAppProps[scaleProp] = ScaleToNative(value.Value, text.units); + } } Utilities.SetApplicationProps(_text, typeof(TextEntity), sourceAppProps); RH.DimensionStyle dimensionStyle = Doc.DimStyles.FindName( sourceAppProps["DimensionStyleName"] as string ?? string.Empty ); if (dimensionStyle != null) + { _text.DimensionStyleId = dimensionStyle.Id; + } } return _text; } @@ -779,7 +874,9 @@ out textPoint linearDimension.position = PointToSpeckle(linearDimPoint); linearDimension.measured = new List { PointToSpeckle(linearStart), PointToSpeckle(linearEnd) }; if (o.GetDisplayLines(o.DimensionStyle, o.DimensionScale, out IEnumerable lines)) + { linearDimension.displayValue = lines.Select(l => LineToSpeckle(l) as ICurve).ToList(); + } props = Utilities.GetApplicationProps(o, typeof(LinearDimension), true, ignore); _dimension = linearDimension; @@ -842,7 +939,10 @@ out Point3d kink2Point ordinateDimension.position = PointToSpeckle(leader); ordinateDimension.measured = new List { PointToSpeckle(basePoint), PointToSpeckle(ordinateDefPoint) }; if (o.GetDisplayLines(o.DimensionStyle, o.DimensionScale, out IEnumerable lines)) + { ordinateDimension.displayValue = lines.Select(l => LineToSpeckle(l) as ICurve).ToList(); + } + textPoint = new Point3d( o.Plane.OriginX + o.TextPosition.X, o.Plane.OriginZ + o.TextPosition.Y, @@ -861,7 +961,9 @@ out Point3d kink2Point radialDimension.position = PointToSpeckle(radialDimPoint); radialDimension.measured = LineToSpeckle(new Line(radialCenter, radius)); if (o.GetDisplayLines(o.DimensionStyle, o.DimensionScale, out IEnumerable lines)) + { radialDimension.displayValue = lines.Select(l => LineToSpeckle(l) as ICurve).ToList(); + } textPoint = new Point3d( o.Plane.OriginX + o.TextPosition.X, @@ -884,7 +986,10 @@ out Point3d kink2Point // set rhino props var style = dimension.DimensionStyle.HasName ? dimension.DimensionStyle.Name : string.Empty; if (!string.IsNullOrEmpty(style)) + { props["DimensionStyleName"] = style; + } + props["plane"] = PlaneToSpeckle(dimension.Plane); _dimension[RhinoPropName] = props; } @@ -896,7 +1001,9 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) Rhino.Geometry.Dimension _dimension = null; Base sourceAppProps = dimension[RhinoPropName] as Base; if (sourceAppProps == null) + { return DimensionToNative(dimension); + } var position = PointToNative(dimension.position).Location; var plane = @@ -916,6 +1023,7 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) var end = PointToNative(linearDimension.measured[1]).Location; bool isRotated = sourceAppProps["AnnotationType"] as string == AnnotationType.Rotated.ToString() ? true : false; if (isRotated) + { _dimension = LinearDimension.Create( AnnotationType.Rotated, dimensionStyle, @@ -926,7 +1034,9 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) position, 0 ); + } else + { _dimension = LinearDimension.Create( AnnotationType.Aligned, dimensionStyle, @@ -937,12 +1047,17 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) position, 0 ); + } + Utilities.SetApplicationProps(_dimension, typeof(LinearDimension), sourceAppProps); break; case "AngularDimension": AngleDimension angleDimension = dimension as AngleDimension; if (angleDimension.measured.Count < 2) + { return null; + } + var angularCenter = PointToNative(angleDimension.measured[0].start).Location; var angularStart = PointToNative(angleDimension.measured[0].end).Location; var angularEnd = PointToNative(angleDimension.measured[1].end).Location; @@ -960,13 +1075,17 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) case "OrdinateDimension": var ordinateSpeckle = dimension as DistanceDimension; if (ordinateSpeckle == null || ordinateSpeckle.measured.Count < 2 || ordinateSpeckle.direction == null) + { return null; + } + var ordinateBase = PointToNative(ordinateSpeckle.measured[0]).Location; var ordinateDefining = PointToNative(ordinateSpeckle.measured[1]).Location; var kinkOffset1 = sourceAppProps["KinkOffset1"] as double? ?? 0; var kinkOffset2 = sourceAppProps["KinkOffset2"] as double? ?? 0; bool isXDirection = VectorToNative(ordinateSpeckle.direction).IsParallelTo(Vector3d.XAxis) == 0 ? false : true; if (isXDirection) + { _dimension = OrdinateDimension.Create( dimensionStyle, plane, @@ -977,7 +1096,9 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) kinkOffset1, kinkOffset2 ); + } else + { _dimension = OrdinateDimension.Create( dimensionStyle, plane, @@ -988,12 +1109,17 @@ public Rhino.Geometry.Dimension RhinoDimensionToNative(Dimension dimension) kinkOffset1, kinkOffset2 ); + } + Utilities.SetApplicationProps(_dimension, typeof(OrdinateDimension), sourceAppProps); break; case "RadialDimension": var radialSpeckle = dimension as LengthDimension; if (radialSpeckle == null || radialSpeckle.measured as Geometry.Line == null) + { return null; + } + var radialLine = LineToNative(radialSpeckle.measured as Geometry.Line); _dimension = RadialDimension.Create( dimensionStyle, @@ -1047,7 +1173,9 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) break; case AngleDimension o: if (o.measured.Count < 2) + { return null; + } var angularCenter = PointToNative(o.measured[0].start).Location; var angularStart = PointToNative(o.measured[0].end).Location; @@ -1064,7 +1192,10 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) break; case DistanceDimension o: if (o.measured.Count < 2) + { return null; + } + var start = PointToNative(o.measured[0]).Location; var end = PointToNative(o.measured[1]).Location; var normal = VectorToNative(o.direction); @@ -1072,6 +1203,7 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) { bool isXDirection = normal.IsParallelTo(Vector3d.XAxis) == 0 ? false : true; if (isXDirection) + { _dimension = OrdinateDimension.Create( style, plane, @@ -1082,7 +1214,9 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) 0, 0 ); + } else + { _dimension = OrdinateDimension.Create( style, plane, @@ -1093,6 +1227,7 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) 0, 0 ); + } } else { @@ -1133,7 +1268,10 @@ public Rhino.Geometry.Dimension DimensionToNative(Dimension dimension) // set text properties _dimension.PlainText = dimension.value; if (!string.IsNullOrEmpty(dimension.richText)) + { _dimension.RichText = dimension.richText; + } + var textPosition = PointToNative(dimension.textPosition).Location; _dimension.TextPosition = new Point2d( textPosition.X - _dimension.Plane.OriginX, diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Structural.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Structural.cs index 4012c083af..f5d7a80ca6 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Structural.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Structural.cs @@ -1,4 +1,4 @@ -#if GRASSHOPPER +#if GRASSHOPPER #endif using Objects.Structural.Geometry; using RH = Rhino.Geometry; diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Utils.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Utils.cs index 8efe3b26e2..cc17605e84 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Utils.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.Utils.cs @@ -39,13 +39,18 @@ public int GetMaterialIndex(string name) { var index = -1; if (string.IsNullOrEmpty(name)) + { return index; + } + for (int i = 0; i < Doc.Materials.Count; i++) + { if (Doc.Materials[i].Name == name) { index = i; break; } + } return index; } @@ -82,6 +87,7 @@ public void GetUserInfo( { var userStringsBase = new Base(); foreach (var key in userStrings.AllKeys) + { try { userStringsBase[key] = userStrings[key]; @@ -90,6 +96,7 @@ public void GetUserInfo( { notes.Add($"Could not attach user string: {e.Message}"); } + } obj[UserStrings] = userStringsBase; } @@ -104,7 +111,9 @@ public void GetUserInfo( // obj name if (!string.IsNullOrEmpty(name)) + { obj["name"] = name; + } } /// @@ -245,9 +254,15 @@ public static Layer GetLayer(RhinoDoc doc, string path, out int index, bool Make currentLayerPath = i == 0 ? layerNames[i] : $"{currentLayerPath}{Layer.PathSeparator}{layerNames[i]}"; currentLayer = GetLayer(doc, currentLayerPath, out index); if (currentLayer == null) + { currentLayer = MakeLayer(doc, layerNames[i], out index, parent); + } + if (currentLayer == null) + { break; + } + parent = currentLayer; } layer = currentLayer; @@ -260,10 +275,15 @@ private static Layer MakeLayer(RhinoDoc doc, string name, out int index, Layer p index = -1; Layer newLayer = new() { Color = Color.White, Name = name }; if (parentLayer != null) + { newLayer.ParentLayerId = parentLayer.Id; + } + int newIndex = doc.Layers.Add(newLayer); if (newIndex < 0) + { return null; + } index = newIndex; return doc.Layers.FindIndex(newIndex); diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.cs index 6911aba549..41c8ec39c3 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/ConverterRhinoGh.cs @@ -93,12 +93,19 @@ public void SetPreviousContextObjects(List objects) public void SetConverterSettings(object settings) { if (settings is Dictionary temp) + { Settings = temp; + } // TODO: Both settings bellow are here for backwards compatibility and should be removed after consolidating settings else if (settings is MeshSettings meshSettings) + { SelectedMeshSettings = meshSettings; + } + if (Settings.TryGetValue("preprocessGeometry", out string setting)) + { bool.TryParse(setting, out PreprocessGeometry); + } } public void SetContextDocument(object doc) @@ -114,16 +121,23 @@ public RH.Mesh GetRhinoRenderMesh(RhinoObject rhinoObj) { ObjRef[] meshObjRefs = RhinoObject.GetRenderMeshes(new List { rhinoObj }, false, false); if (meshObjRefs == null || meshObjRefs.Length == 0) + { return null; + } + if (meshObjRefs.Length == 1) + { return meshObjRefs[0]?.Mesh(); + } var joinedMesh = new RH.Mesh(); foreach (var t in meshObjRefs) { var mesh = t?.Mesh(); if (mesh != null) + { joinedMesh.Append(mesh); + } } return joinedMesh; @@ -163,22 +177,32 @@ public Base ConvertToSpeckle(object @object) // Fast way to get the displayMesh, try to get the mesh rhino shows on the viewport when available. // This will only return a mesh if the object has been displayed in any mode other than Wireframe. if (ro is BrepObject || ro is ExtrusionObject) + { displayMesh = GetRhinoRenderMesh(ro); + } //mapping tool var mappingString = ro.Attributes.GetUserString(SpeckleMappingKey); if (mappingString != null) + { schema = MappingToSpeckle(mappingString, ro, notes); + } if (!(@object is InstanceObject)) + { @object = ro.Geometry; // block instance check + } + break; case Layer l: var lId = l.GetUserString(ApplicationIdKey) ?? l.Id.ToString(); reportObj = new ApplicationObject(l.Id.ToString(), "Layer") { applicationId = lId }; if (l.RenderMaterial != null) + { material = RenderMaterialToSpeckle(l.RenderMaterial); + } + style = DisplayStyleToSpeckle(new ObjectAttributes(), l); userDictionary = l.UserDictionary; userStrings = l.GetUserStrings(); @@ -186,7 +210,9 @@ public Base ConvertToSpeckle(object @object) } if (schema != null) + { PreprocessGeometry = true; + } switch (@object) { @@ -270,9 +296,14 @@ public Base ConvertToSpeckle(object @object) #if RHINO7 case RH.SubD o: if (o.HasBrepForm) + { @base = BrepToSpeckle(o.ToBrep(new RH.SubDToBrepOptions()), null, displayMesh, material); + } else + { @base = MeshToSpeckle(o); + } + break; #endif case RH.Extrusion o: @@ -316,7 +347,9 @@ public Base ConvertToSpeckle(object @object) } if (@base is null) + { return @base; + } GetUserInfo(@base, out List attributeNotes, userDictionary, userStrings, objName); notes.AddRange(attributeNotes); @@ -324,10 +357,15 @@ public Base ConvertToSpeckle(object @object) { @base["renderMaterial"] = material; if (schema != null) + { schema["renderMaterial"] = material; + } } if (style != null) + { @base["displayStyle"] = style; + } + if (schema != null) { @base["@SpeckleSchema"] = schema; @@ -547,6 +585,7 @@ public object ConvertToNative(Base @object) case ApplicationObject o: // some to native methods return an application object (if object is baked to doc during conv) rhinoObj = o.Converted.Any() ? o.Converted : null; if (reportObj != null) + { reportObj.Update( status: o.Status, createdIds: o.CreatedIds, @@ -554,16 +593,24 @@ public object ConvertToNative(Base @object) container: o.Container, log: o.Log ); + } + break; default: if (reportObj != null) + { reportObj.Update(log: notes); + } + break; } if (reportObj != null) + { Report.UpdateReportObject(reportObj); + } + return rhinoObj; } @@ -580,7 +627,9 @@ public List ConvertToNative(List objects) public bool CanConvertToSpeckle(object @object) { if (@object is RhinoObject ro && !(@object is InstanceObject)) + { @object = ro.Geometry; + } switch (@object) { diff --git a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/KnotListEncoder.cs b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/KnotListEncoder.cs index 60f308deda..fbc3c42ba1 100644 --- a/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/KnotListEncoder.cs +++ b/Objects/Converters/ConverterRhinoGh/ConverterRhinoGhShared/KnotListEncoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using Rhino.Geometry; @@ -89,9 +89,13 @@ out bool strict var multiplicity = i - index; if (strict) + { average = knots[index]; + } else + { average /= multiplicity; + } return multiplicity; } @@ -128,9 +132,13 @@ out bool strict var multiplicity = i - index; if (strict) + { average = knots[index]; + } else + { average /= multiplicity; + } return multiplicity; } @@ -145,6 +153,7 @@ public static double MinDelta(IEnumerable knots) var delta = double.PositiveInfinity; using (var enumerator = knots.GetEnumerator()) + { if (enumerator.MoveNext()) { var previous = enumerator.Current; @@ -153,15 +162,20 @@ public static double MinDelta(IEnumerable knots) { var current = enumerator.Current; if (previous == current) + { continue; + } var d = current - previous; if (d < delta) + { delta = d; + } previous = current; } } + } return delta; } @@ -194,7 +208,10 @@ public static bool TryGetPolyCurveC2( if (multiplicity > degree - 2) { if (spans is null) + { spans = new List(); + } + spans.Add(knots[k]); } @@ -218,7 +235,9 @@ public static bool TryGetPolyCurveC2( // Remove old knots that do not overlap knots[k] if (excess > 0) + { knots.RemoveKnots(k + multiplicity, k + multiplicity + excess); + } } k += multiplicity; @@ -232,11 +251,15 @@ public static bool TryGetPolyCurveC2( polyCurve = new PolyCurve(); foreach (var span in curve.Split(spans)) + { polyCurve.AppendSegment(span); + } // Split may generate PolyCurves on seams. if (curve.IsClosed) + { polyCurve.RemoveNesting(); + } return true; } @@ -257,7 +280,10 @@ private static bool ToKinkedSpans( if (multiplicity > degree) { if (kinks is null) + { kinks = new List(); + } + kinks.Add(knots[k]); } @@ -273,7 +299,9 @@ private static bool ToKinkedSpans( // Remove old knots that do not overlap knots[k] if (excess > 0) + { knots.RemoveKnots(k + multiplicity, k + multiplicity + excess); + } } k += multiplicity; diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructureUtils.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructureUtils.cs index eacd1a81a3..cb1ee0bd8e 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructureUtils.cs +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructureUtils.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using Objects.Structural.Geometry; @@ -15,546 +15,632 @@ using Tekla.Structures.Datatype; using Objects.BuiltElements.TeklaStructures; -namespace Objects.Converter.TeklaStructures +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures { - public partial class ConverterTeklaStructures - { + public void SetUnits(string units) { } - public void SetUnits(string units) + public string GetUnitsFromModel() + { + var unit = Distance.CurrentUnitType; + switch (unit) { - + case Distance.UnitType.Millimeter: + return "mm"; + case Distance.UnitType.Centimeter: + return "cm"; + case Distance.UnitType.Meter: + return "m"; + case Distance.UnitType.Inch: + return "in"; + case Distance.UnitType.Foot: + return "ft"; + default: + return "mm"; } - public string GetUnitsFromModel() - { - var unit = Distance.CurrentUnitType; - switch (unit) - { - case Distance.UnitType.Millimeter: - return "mm"; - case Distance.UnitType.Centimeter: - return "cm"; - case Distance.UnitType.Meter: - return "m"; - case Distance.UnitType.Inch: - return "in"; - case Distance.UnitType.Foot: - return "ft"; - default: - return "mm"; + } - } + public Mesh GetMeshFromSolid(Solid solid) + { + List vertexList = new() { }; + ArrayList MyFaceNormalList = new(); + List facesList = new() { }; + FaceEnumerator MyFaceEnum = solid.GetFaceEnumerator(); - } - public Mesh GetMeshFromSolid(Solid solid) + var counter = 0; + while (MyFaceEnum.MoveNext()) { - List vertexList = new List { }; - ArrayList MyFaceNormalList = new ArrayList(); - List facesList = new List { }; + int faceIndexOffset = vertexList.Count / 3; - FaceEnumerator MyFaceEnum = solid.GetFaceEnumerator(); + var mesher = new PolygonMesher(); - var counter = 0; - while (MyFaceEnum.MoveNext()) + Face MyFace = MyFaceEnum.Current as Face; + if (MyFace != null) { - int faceIndexOffset = vertexList.Count / 3; - - var mesher = new PolygonMesher(); - - Face MyFace = MyFaceEnum.Current as Face; - if (MyFace != null) + List outerLoopList = new() { }; + List> innerLoopList = new(); + LoopEnumerator MyLoopEnum = MyFace.GetLoopEnumerator(); + var inner_loop = 0; + while (MyLoopEnum.MoveNext()) { - List outerLoopList = new List { }; - List> innerLoopList = new List>(); - LoopEnumerator MyLoopEnum = MyFace.GetLoopEnumerator(); - var inner_loop = 0; - while (MyLoopEnum.MoveNext()) + Loop MyLoop = MyLoopEnum.Current as Loop; + if (MyLoop != null) { - Loop MyLoop = MyLoopEnum.Current as Loop; - if (MyLoop != null) + VertexEnumerator MyVertexEnum = MyLoop.GetVertexEnumerator() as VertexEnumerator; + var innerLoopListOfList = new List { }; + while (MyVertexEnum.MoveNext()) { - - VertexEnumerator MyVertexEnum = MyLoop.GetVertexEnumerator() as VertexEnumerator; - var innerLoopListOfList = new List { }; - while (MyVertexEnum.MoveNext()) + Tekla.Structures.Geometry3d.Point MyVertex = MyVertexEnum.Current as Tekla.Structures.Geometry3d.Point; + if (MyVertex != null && inner_loop == 0) { - - Tekla.Structures.Geometry3d.Point MyVertex = MyVertexEnum.Current as Tekla.Structures.Geometry3d.Point; - if (MyVertex != null && inner_loop == 0) - { - outerLoopList.Add(MyVertex.X); - outerLoopList.Add(MyVertex.Y); - outerLoopList.Add(MyVertex.Z); - - } - else - { - innerLoopListOfList.Add(MyVertex.X); - innerLoopListOfList.Add(MyVertex.Y); - innerLoopListOfList.Add(MyVertex.Z); - } - - - //speckleBeam.displayMesh = beam.Profile. + outerLoopList.Add(MyVertex.X); + outerLoopList.Add(MyVertex.Y); + outerLoopList.Add(MyVertex.Z); } - inner_loop++; - if(innerLoopListOfList.Any()){ - innerLoopList.Add(innerLoopListOfList); + else + { + innerLoopListOfList.Add(MyVertex.X); + innerLoopListOfList.Add(MyVertex.Y); + innerLoopListOfList.Add(MyVertex.Z); } + + //speckleBeam.displayMesh = beam.Profile. + } + inner_loop++; + if (innerLoopListOfList.Any()) + { + innerLoopList.Add(innerLoopListOfList); } } - if (!innerLoopList.Any()) - { - mesher.Init(outerLoopList); - } - else - { - mesher.Init(outerLoopList, innerLoopList); - } - var faces = mesher.Faces(faceIndexOffset); - var vertices = mesher.Coordinates; - var verticesList = vertices.ToList(); - vertexList.AddRange(verticesList); - //var largestVertixCount = 0; - //if (facesList.Count == 0) - //{ - // largestVertixCount = 0; - //} - //else - //{ - // largestVertixCount = facesList.Max() + 1; - //} - //for (int i = 0; i < faces.Length; i++) - //{ - // if (i % 4 == 0) - // { - // continue; - // } - // else - // { - // faces[i] += largestVertixCount; - // } - //} - facesList.AddRange(faces.ToList()); } - } - return new Mesh(vertexList, facesList,units: GetUnitsFromModel()); - - } - /// - /// Get all user properties defined for this object in Tekla - /// - /// - /// - /// List of BuiltInParameters or GUIDs used to indicate what parameters NOT to get, - /// we exclude all params already defined on the top level object to avoid duplication and - /// potential conflicts when setting them back on the element - public void GetAllUserProperties(Base speckleElement, ModelObject teklaObject, List exclusions = null) - { - Hashtable propertyHashtable = new Hashtable(); - teklaObject.GetAllUserProperties(ref propertyHashtable); - - // sort by key - var sortedproperties = propertyHashtable.Cast().OrderBy(x => x.Key).ToDictionary(d => (string)d.Key, d => d.Value); - - Base paramBase = new Base(); - foreach (var kv in sortedproperties) - { - try + if (!innerLoopList.Any()) { - paramBase[kv.Key] = kv.Value; + mesher.Init(outerLoopList); } - catch + else { - //ignore + mesher.Init(outerLoopList, innerLoopList); } + var faces = mesher.Faces(faceIndexOffset); + var vertices = mesher.Coordinates; + var verticesList = vertices.ToList(); + vertexList.AddRange(verticesList); + //var largestVertixCount = 0; + //if (facesList.Count == 0) + //{ + // largestVertixCount = 0; + //} + //else + //{ + // largestVertixCount = facesList.Max() + 1; + //} + //for (int i = 0; i < faces.Length; i++) + //{ + // if (i % 4 == 0) + // { + // continue; + // } + // else + // { + // faces[i] += largestVertixCount; + // } + //} + facesList.AddRange(faces.ToList()); } - - if (paramBase.GetDynamicMembers().Any()) - speckleElement["parameters"] = paramBase; - //speckleElement["elementId"] = revitElement.Id.ToString(); - speckleElement.applicationId = teklaObject.Identifier.GUID.ToString(); - speckleElement["units"] = GetUnitsFromModel(); } + return new Mesh(vertexList, facesList, units: GetUnitsFromModel()); + } - public Structural.Properties.Profiles.SectionProfile GetBeamProfile(string teklaProfileString) - { - SectionProfile profile = null; - ProfileItem profileItem = null; + /// + /// Get all user properties defined for this object in Tekla + /// + /// + /// + /// List of BuiltInParameters or GUIDs used to indicate what parameters NOT to get, + /// we exclude all params already defined on the top level object to avoid duplication and + /// potential conflicts when setting them back on the element + public void GetAllUserProperties(Base speckleElement, ModelObject teklaObject, List exclusions = null) + { + Hashtable propertyHashtable = new(); + teklaObject.GetAllUserProperties(ref propertyHashtable); - LibraryProfileItem libItem = new LibraryProfileItem(); - ParametricProfileItem paramItem = new ParametricProfileItem(); - if (libItem.Select(teklaProfileString)) - { - profileItem = libItem; - } - else if (paramItem.Select(teklaProfileString)) + // sort by key + var sortedproperties = propertyHashtable + .Cast() + .OrderBy(x => x.Key) + .ToDictionary(d => (string)d.Key, d => d.Value); + + Base paramBase = new(); + foreach (var kv in sortedproperties) + { + try { - profileItem = paramItem; + paramBase[kv.Key] = kv.Value; } - - if (profileItem != null) + catch { - switch (profileItem.ProfileItemType) - { - case ProfileItem.ProfileItemTypeEnum.PROFILE_I: - profile = GetIProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_L: - profile = GetAngleProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_PL: - profile = GetRectangularProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_P: - profile = GetRectangularHollowProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_C: - case ProfileItem.ProfileItemTypeEnum.PROFILE_U: - profile = GetChannelProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_D: - profile = GetCircularProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_PD: - profile = GetCircularHollowProfile(profileItem); - break; - case ProfileItem.ProfileItemTypeEnum.PROFILE_T: - profile = GetTeeProfile(profileItem); - break; - default: - profile = new SectionProfile(); - profile.name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); - break; - } + //ignore } - return profile; } - public Structural.Properties.Profiles.SectionProfile GetContourPlateProfile(string teklaProfileString) + + if (paramBase.GetDynamicMembers().Any()) { - ParametricProfileItem paramItem = new ParametricProfileItem(); - SectionProfile profile = new SectionProfile() { name = teklaProfileString, shapeType = Structural.ShapeType.Perimeter }; - return profile; + speckleElement["parameters"] = paramBase; } + //speckleElement["elementId"] = revitElement.Id.ToString(); + speckleElement.applicationId = teklaObject.Identifier.GUID.ToString(); + speckleElement["units"] = GetUnitsFromModel(); + } + public Structural.Properties.Profiles.SectionProfile GetBeamProfile(string teklaProfileString) + { + SectionProfile profile = null; + ProfileItem profileItem = null; - - #region Profile type getters - private Structural.Properties.Profiles.ISection GetIProfile(ProfileItem profileItem) + LibraryProfileItem libItem = new(); + ParametricProfileItem paramItem = new(); + if (libItem.Select(teklaProfileString)) { - // Set profile name depending on type - var name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); - - // Get properties from catalog - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; - var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; - - var speckleProfile = new ISection(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), tw.GetValueOrDefault(), tf.GetValueOrDefault()); - return speckleProfile; + profileItem = libItem; } - private Structural.Properties.Profiles.Angle GetAngleProfile(ProfileItem profileItem) + else if (paramItem.Select(teklaProfileString)) { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); - - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var tf1 = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS_1")?.Value; - var tf2 = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS_2")?.Value; - - var speckleProfile = new Structural.Properties.Profiles.Angle(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), tf1.GetValueOrDefault(), tf2.GetValueOrDefault()); - - return speckleProfile; + profileItem = paramItem; } - private Structural.Properties.Profiles.Rectangular GetRectangularProfile(ProfileItem profileItem) + if (profileItem != null) { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); + switch (profileItem.ProfileItemType) + { + case ProfileItem.ProfileItemTypeEnum.PROFILE_I: + profile = GetIProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_L: + profile = GetAngleProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_PL: + profile = GetRectangularProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_P: + profile = GetRectangularHollowProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_C: + case ProfileItem.ProfileItemTypeEnum.PROFILE_U: + profile = GetChannelProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_D: + profile = GetCircularProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_PD: + profile = GetCircularHollowProfile(profileItem); + break; + case ProfileItem.ProfileItemTypeEnum.PROFILE_T: + profile = GetTeeProfile(profileItem); + break; + default: + profile = new SectionProfile(); + profile.name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + break; + } + } + return profile; + } - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var speckleProfile = new Structural.Properties.Profiles.Rectangular(name, depth.GetValueOrDefault(), width.GetValueOrDefault()); + public Structural.Properties.Profiles.SectionProfile GetContourPlateProfile(string teklaProfileString) + { + ParametricProfileItem paramItem = new(); + SectionProfile profile = new() { name = teklaProfileString, shapeType = Structural.ShapeType.Perimeter }; + return profile; + } - return speckleProfile; - } - private Structural.Properties.Profiles.Rectangular GetRectangularHollowProfile(ProfileItem profileItem) - { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); + #region Profile type getters + private Structural.Properties.Profiles.ISection GetIProfile(ProfileItem profileItem) + { + // Set profile name depending on type + var name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + // Get properties from catalog + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; + var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; + + var speckleProfile = new ISection( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + tw.GetValueOrDefault(), + tf.GetValueOrDefault() + ); + return speckleProfile; + } - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; - var speckleProfile = new Structural.Properties.Profiles.Rectangular(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), wallThk.GetValueOrDefault(), wallThk.GetValueOrDefault()); + private Structural.Properties.Profiles.Angle GetAngleProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var tf1 = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS_1")?.Value; + var tf2 = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS_2")?.Value; + + var speckleProfile = new Structural.Properties.Profiles.Angle( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + tf1.GetValueOrDefault(), + tf2.GetValueOrDefault() + ); + + return speckleProfile; + } - return speckleProfile; - } - private Structural.Properties.Profiles.Circular GetCircularProfile(ProfileItem profileItem) - { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); + private Structural.Properties.Profiles.Rectangular GetRectangularProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var speckleProfile = new Structural.Properties.Profiles.Rectangular( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault() + ); + + return speckleProfile; + } - var depth = properties.FirstOrDefault(p => p.Property == "DIAMETER")?.Value; - var speckleProfile = new Structural.Properties.Profiles.Circular(name, depth.GetValueOrDefault() * 0.5); + private Structural.Properties.Profiles.Rectangular GetRectangularHollowProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; + var speckleProfile = new Structural.Properties.Profiles.Rectangular( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + wallThk.GetValueOrDefault(), + wallThk.GetValueOrDefault() + ); + + return speckleProfile; + } - return speckleProfile; - } - private Structural.Properties.Profiles.Circular GetCircularHollowProfile(ProfileItem profileItem) - { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); + private Structural.Properties.Profiles.Circular GetCircularProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); - var depth = properties.FirstOrDefault(p => p.Property == "DIAMETER")?.Value; - var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; - var speckleProfile = new Structural.Properties.Profiles.Circular(name, depth.GetValueOrDefault() * 0.5, wallThk.GetValueOrDefault()); + var depth = properties.FirstOrDefault(p => p.Property == "DIAMETER")?.Value; + var speckleProfile = new Structural.Properties.Profiles.Circular(name, depth.GetValueOrDefault() * 0.5); - return speckleProfile; - } - private Structural.Properties.Profiles.Channel GetChannelProfile(ProfileItem profileItem) - { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); - - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; - var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; - var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; - - Channel speckleProfile; - if (tf.HasValue && tw.HasValue) - speckleProfile = new Channel(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), tw.GetValueOrDefault(), tf.GetValueOrDefault()); - else - speckleProfile = new Channel(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), wallThk.GetValueOrDefault(), wallThk.GetValueOrDefault()); + return speckleProfile; + } + + private Structural.Properties.Profiles.Circular GetCircularHollowProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "DIAMETER")?.Value; + var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; + var speckleProfile = new Structural.Properties.Profiles.Circular( + name, + depth.GetValueOrDefault() * 0.5, + wallThk.GetValueOrDefault() + ); + + return speckleProfile; + } - return speckleProfile; + private Structural.Properties.Profiles.Channel GetChannelProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; + var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; + var wallThk = properties.FirstOrDefault(p => p.Property == "PLATE_THICKNESS")?.Value; + + Channel speckleProfile; + if (tf.HasValue && tw.HasValue) + { + speckleProfile = new Channel( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + tw.GetValueOrDefault(), + tf.GetValueOrDefault() + ); } - private Structural.Properties.Profiles.Tee GetTeeProfile(ProfileItem profileItem) + else { - var properties = profileItem.aProfileItemParameters.Cast().ToList(); - string name = profileItem is LibraryProfileItem ? ((LibraryProfileItem)profileItem).ProfileName : ((ParametricProfileItem)profileItem).CreateProfileString(); - - var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; - var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; - var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; - var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; - - var speckleProfile = new Tee(name, depth.GetValueOrDefault(), width.GetValueOrDefault(), tw.GetValueOrDefault(), tf.GetValueOrDefault()); - return speckleProfile; + speckleProfile = new Channel( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + wallThk.GetValueOrDefault(), + wallThk.GetValueOrDefault() + ); } - #endregion + return speckleProfile; + } - public Structural.Materials.StructuralMaterial GetMaterial(string teklaMaterialString) - { - Structural.Materials.StructuralMaterial speckleMaterial = null; + private Structural.Properties.Profiles.Tee GetTeeProfile(ProfileItem profileItem) + { + var properties = profileItem.aProfileItemParameters.Cast().ToList(); + string name = + profileItem is LibraryProfileItem + ? ((LibraryProfileItem)profileItem).ProfileName + : ((ParametricProfileItem)profileItem).CreateProfileString(); + + var depth = properties.FirstOrDefault(p => p.Property == "HEIGHT")?.Value; + var width = properties.FirstOrDefault(p => p.Property == "WIDTH")?.Value; + var tf = properties.FirstOrDefault(p => p.Property == "FLANGE_THICKNESS")?.Value; + var tw = properties.FirstOrDefault(p => p.Property == "WEB_THICKNESS")?.Value; + + var speckleProfile = new Tee( + name, + depth.GetValueOrDefault(), + width.GetValueOrDefault(), + tw.GetValueOrDefault(), + tf.GetValueOrDefault() + ); + return speckleProfile; + } - MaterialItem materialItem = new MaterialItem(); - if (materialItem.Select(teklaMaterialString)) - { - switch (materialItem.Type) - { - case MaterialItem.MaterialItemTypeEnum.MATERIAL_STEEL: - speckleMaterial = new Structural.Materials.Steel(); - speckleMaterial.materialType = Structural.MaterialType.Steel; - break; - case MaterialItem.MaterialItemTypeEnum.MATERIAL_CONCRETE: - speckleMaterial = new Structural.Materials.Concrete(); - speckleMaterial.materialType = Structural.MaterialType.Concrete; - break; - default: - speckleMaterial = new Structural.Materials.StructuralMaterial(); - break; - } - speckleMaterial.name = materialItem.MaterialName; - speckleMaterial.density = materialItem.ProfileDensity; - speckleMaterial.elasticModulus = materialItem.ModulusOfElasticity; - speckleMaterial.poissonsRatio = materialItem.PoissonsRatio; - speckleMaterial.grade = materialItem.MaterialName; - speckleMaterial.thermalExpansivity = materialItem.ThermalDilatation; - } - return speckleMaterial; + #endregion - } + public Structural.Materials.StructuralMaterial GetMaterial(string teklaMaterialString) + { + Structural.Materials.StructuralMaterial speckleMaterial = null; - public ArrayList GetContourPointsFromPolyLine(Polyline polyline) + MaterialItem materialItem = new(); + if (materialItem.Select(teklaMaterialString)) { - var contourList = new ArrayList(); - var coordinates = polyline.value; - for (int j = 0; j < coordinates.Count; j++) + switch (materialItem.Type) { - if (j % 3 == 0) - { - var point = new TSG.Point(); - point.X = coordinates[j]; - point.Y = coordinates[j + 1]; - point.Z = coordinates[j + 2]; - contourList.Add(new ContourPoint(point, new Chamfer())); - } - + case MaterialItem.MaterialItemTypeEnum.MATERIAL_STEEL: + speckleMaterial = new Structural.Materials.Steel(); + speckleMaterial.materialType = Structural.MaterialType.Steel; + break; + case MaterialItem.MaterialItemTypeEnum.MATERIAL_CONCRETE: + speckleMaterial = new Structural.Materials.Concrete(); + speckleMaterial.materialType = Structural.MaterialType.Concrete; + break; + default: + speckleMaterial = new Structural.Materials.StructuralMaterial(); + break; } - return contourList; + speckleMaterial.name = materialItem.MaterialName; + speckleMaterial.density = materialItem.ProfileDensity; + speckleMaterial.elasticModulus = materialItem.ModulusOfElasticity; + speckleMaterial.poissonsRatio = materialItem.PoissonsRatio; + speckleMaterial.grade = materialItem.MaterialName; + speckleMaterial.thermalExpansivity = materialItem.ThermalDilatation; } - public void ToNativeContourPlate(Polyline polyline, Contour contour) + return speckleMaterial; + } + + public ArrayList GetContourPointsFromPolyLine(Polyline polyline) + { + var contourList = new ArrayList(); + var coordinates = polyline.value; + for (int j = 0; j < coordinates.Count; j++) { - var coordinates = polyline.value; - for (int j = 0; j < coordinates.Count; j++) + if (j % 3 == 0) { - if (j % 3 == 0) - { - var point = new TSG.Point(); - point.X = coordinates[j]; - point.Y = coordinates[j + 1]; - point.Z = coordinates[j + 2]; - contour.AddContourPoint(new ContourPoint(point, null)); - } + var point = new TSG.Point(); + point.X = coordinates[j]; + point.Y = coordinates[j + 1]; + point.Z = coordinates[j + 2]; + contourList.Add(new ContourPoint(point, new Chamfer())); } } - public Polyline ToSpecklePolyline(Tekla.Structures.Model.Polygon polygon) + return contourList; + } + + public void ToNativeContourPlate(Polyline polyline, Contour contour) + { + var coordinates = polyline.value; + for (int j = 0; j < coordinates.Count; j++) { - List coordinateList = new List(); - var units = GetUnitsFromModel(); - var polygonPointList = polygon.Points.Cast(); - foreach (var pt in polygonPointList) + if (j % 3 == 0) { - coordinateList.Add(pt.X); - coordinateList.Add(pt.Y); - coordinateList.Add(pt.Z); + var point = new TSG.Point(); + point.X = coordinates[j]; + point.Y = coordinates[j + 1]; + point.Z = coordinates[j + 2]; + contour.AddContourPoint(new ContourPoint(point, null)); } - - var specklePolyline = new Polyline(coordinateList, units); - return specklePolyline; } - public Polycurve ToSpecklePolycurve(Tekla.Structures.Geometry3d.Polycurve teklaPolycurve) + } + + public Polyline ToSpecklePolyline(Tekla.Structures.Model.Polygon polygon) + { + List coordinateList = new(); + var units = GetUnitsFromModel(); + var polygonPointList = polygon.Points.Cast(); + foreach (var pt in polygonPointList) { - var units = GetUnitsFromModel(); - var specklePolycurve = new Polycurve(units); + coordinateList.Add(pt.X); + coordinateList.Add(pt.Y); + coordinateList.Add(pt.Z); + } - foreach (var curveSegment in teklaPolycurve) - { - if (curveSegment is TSG.LineSegment) - { - var lineSeg = (TSG.LineSegment)curveSegment; + var specklePolyline = new Polyline(coordinateList, units); + return specklePolyline; + } - Point start = new Point(lineSeg.StartPoint.X, lineSeg.StartPoint.Y, lineSeg.StartPoint.Z, units); - Point end = new Point(lineSeg.EndPoint.X, lineSeg.EndPoint.Y, lineSeg.EndPoint.Z, units); + public Polycurve ToSpecklePolycurve(Tekla.Structures.Geometry3d.Polycurve teklaPolycurve) + { + var units = GetUnitsFromModel(); + var specklePolycurve = new Polycurve(units); - Line speckleLine = new Line(start, end, units); - specklePolycurve.segments.Add(speckleLine); - } - else if (curveSegment is TSG.Arc) - { - var arcSeg = (TSG.Arc)curveSegment; + foreach (var curveSegment in teklaPolycurve) + { + if (curveSegment is TSG.LineSegment) + { + var lineSeg = (TSG.LineSegment)curveSegment; - Point start = new Point(arcSeg.StartPoint.X, arcSeg.StartPoint.Y, arcSeg.StartPoint.Z, units); - Point end = new Point(arcSeg.EndPoint.X, arcSeg.EndPoint.Y, arcSeg.EndPoint.Z, units); - Point mid = new Point(arcSeg.ArcMiddlePoint.X, arcSeg.ArcMiddlePoint.Y, arcSeg.ArcMiddlePoint.Z, units); + Point start = new(lineSeg.StartPoint.X, lineSeg.StartPoint.Y, lineSeg.StartPoint.Z, units); + Point end = new(lineSeg.EndPoint.X, lineSeg.EndPoint.Y, lineSeg.EndPoint.Z, units); + Line speckleLine = new(start, end, units); + specklePolycurve.segments.Add(speckleLine); + } + else if (curveSegment is TSG.Arc) + { + var arcSeg = (TSG.Arc)curveSegment; - Arc speckleArc = new Arc(); - speckleArc.startPoint = start; - speckleArc.endPoint = end; - speckleArc.midPoint = mid; - speckleArc.radius = arcSeg.Radius; - speckleArc.angleRadians = arcSeg.Angle; + Point start = new(arcSeg.StartPoint.X, arcSeg.StartPoint.Y, arcSeg.StartPoint.Z, units); + Point end = new(arcSeg.EndPoint.X, arcSeg.EndPoint.Y, arcSeg.EndPoint.Z, units); + Point mid = new(arcSeg.ArcMiddlePoint.X, arcSeg.ArcMiddlePoint.Y, arcSeg.ArcMiddlePoint.Z, units); - specklePolycurve.segments.Add(speckleArc); - } + Arc speckleArc = new(); + speckleArc.startPoint = start; + speckleArc.endPoint = end; + speckleArc.midPoint = mid; + speckleArc.radius = arcSeg.Radius; + speckleArc.angleRadians = arcSeg.Angle; + + specklePolycurve.segments.Add(speckleArc); } - return specklePolycurve; } - public TeklaContourPoint ToSpeckleContourPoint(ContourPoint contourPoint) + return specklePolycurve; + } + + public TeklaContourPoint ToSpeckleContourPoint(ContourPoint contourPoint) + { + var speckleCP = new TeklaContourPoint(); + speckleCP.x = contourPoint.X; + speckleCP.y = contourPoint.Y; + speckleCP.z = contourPoint.Z; + + speckleCP.chamferType = (TeklaChamferType)contourPoint.Chamfer.Type; + speckleCP.xDim = contourPoint.Chamfer.X; + speckleCP.yDim = contourPoint.Chamfer.Y; + speckleCP.dz1 = contourPoint.Chamfer.DZ1; + speckleCP.dz2 = contourPoint.Chamfer.DZ2; + speckleCP.units = GetUnitsFromModel(); + return speckleCP; + } + + public ContourPoint ToTeklaContourPoint(TeklaContourPoint speckleCP) + { + var teklaCP = new ContourPoint(); + teklaCP.SetPoint(new TSG.Point(speckleCP.x, speckleCP.y, speckleCP.z)); + teklaCP.Chamfer.Type = (Chamfer.ChamferTypeEnum)speckleCP.chamferType; + teklaCP.Chamfer.X = speckleCP.xDim; + teklaCP.Chamfer.Y = speckleCP.yDim; + teklaCP.Chamfer.DZ1 = speckleCP.dz1; + teklaCP.Chamfer.DZ2 = speckleCP.dz2; + return teklaCP; + } + + public TeklaPosition GetPositioning(Position position) + { + var specklePosition = new TeklaPosition() { - var speckleCP = new TeklaContourPoint(); - speckleCP.x = contourPoint.X; - speckleCP.y = contourPoint.Y; - speckleCP.z = contourPoint.Z; - - speckleCP.chamferType = (TeklaChamferType)contourPoint.Chamfer.Type; - speckleCP.xDim = contourPoint.Chamfer.X; - speckleCP.yDim = contourPoint.Chamfer.Y; - speckleCP.dz1 = contourPoint.Chamfer.DZ1; - speckleCP.dz2 = contourPoint.Chamfer.DZ2; - speckleCP.units = GetUnitsFromModel(); - return speckleCP; - } - public ContourPoint ToTeklaContourPoint(TeklaContourPoint speckleCP) + Depth = (TeklaDepthEnum)position.Depth, + Plane = (TeklaPlaneEnum)position.Plane, + Rotation = (TeklaRotationEnum)position.Rotation, + depthOffset = position.DepthOffset, + planeOffset = position.PlaneOffset, + rotationOffset = position.RotationOffset + }; + + return specklePosition; + } + + public Position SetPositioning(TeklaPosition position) + { + var teklaPosition = new Position() { - var teklaCP = new ContourPoint(); - teklaCP.SetPoint(new TSG.Point(speckleCP.x, speckleCP.y, speckleCP.z)); - teklaCP.Chamfer.Type = (Chamfer.ChamferTypeEnum)speckleCP.chamferType; - teklaCP.Chamfer.X = speckleCP.xDim; - teklaCP.Chamfer.Y = speckleCP.yDim; - teklaCP.Chamfer.DZ1 = speckleCP.dz1; - teklaCP.Chamfer.DZ2 = speckleCP.dz2; - return teklaCP; - } + Depth = (Position.DepthEnum)position.Depth, + Plane = (Position.PlaneEnum)position.Plane, + Rotation = (Position.RotationEnum)position.Rotation, + DepthOffset = position.depthOffset, + PlaneOffset = position.planeOffset, + RotationOffset = position.rotationOffset + }; + + return teklaPosition; + } - public TeklaPosition GetPositioning(Position position) + public bool IsProfileValid(string profileName) + { + if (string.IsNullOrEmpty(profileName)) { - var specklePosition = new TeklaPosition() - { - Depth = (TeklaDepthEnum)position.Depth, - Plane = (TeklaPlaneEnum)position.Plane, - Rotation = (TeklaRotationEnum)position.Rotation, - depthOffset = position.DepthOffset, - planeOffset = position.PlaneOffset, - rotationOffset = position.RotationOffset - }; - - return specklePosition; + return false; } - public Position SetPositioning(TeklaPosition position) + + LibraryProfileItem lpi = new(); + if (lpi.Select(profileName)) { - var teklaPosition = new Position() - { - Depth = (Position.DepthEnum)position.Depth, - Plane = (Position.PlaneEnum)position.Plane, - Rotation = (Position.RotationEnum)position.Rotation, - DepthOffset = position.depthOffset, - PlaneOffset = position.planeOffset, - RotationOffset = position.rotationOffset - }; - - return teklaPosition; + return true; } - public bool IsProfileValid(string profileName) + else { - if (string.IsNullOrEmpty(profileName)) - return false; - - LibraryProfileItem lpi = new LibraryProfileItem(); - if (lpi.Select(profileName)) + ParametricProfileItem ppi = new(); + if (ppi.Select(profileName)) + { return true; + } else { - ParametricProfileItem ppi = new ParametricProfileItem(); - if (ppi.Select(profileName)) - return true; - else - return false; + return false; } } - //public static bool IsElementSupported(this ModelObject e) - //{ - - // if (SupportedBuiltInCategories.Contains(e) - // return true; - // return false; - //} - - ////list of currently supported Categories (for sending only) - ////exact copy of the one in the Speckle.ConnectorRevit.ConnectorRevitUtils - ////until issue https://github.com/specklesystems/speckle-sharp/issues/392 is resolved - //private static List SupportedBuiltInCategories = new List{ + } + //public static bool IsElementSupported(this ModelObject e) + //{ - //ModelObject.ModelObjectEnum.BEAM, + // if (SupportedBuiltInCategories.Contains(e) + // return true; + // return false; + //} + ////list of currently supported Categories (for sending only) + ////exact copy of the one in the Speckle.ConnectorRevit.ConnectorRevitUtils + ////until issue https://github.com/specklesystems/speckle-sharp/issues/392 is resolved + //private static List SupportedBuiltInCategories = new List{ - } + //ModelObject.ModelObjectEnum.BEAM, } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs index f6dd9fa66c..123fcf51d5 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs @@ -11,263 +11,264 @@ using BE = Objects.BuiltElements; using GE = Objects.Geometry; -namespace Objects.Converter.TeklaStructures +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures : ISpeckleConverter { - public partial class ConverterTeklaStructures : ISpeckleConverter - { #if TeklaStructures2020 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2020); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2020); #elif TeklaStructures2021 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2021); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2021); #elif TeklaStructures2022 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2022); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2022); #elif TeklaStructures2023 - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2023); + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.GetVersion(HostAppVersion.v2023); #else - public static string TeklaStructuresAppName = HostApplications.TeklaStructures.Name; + public static string TeklaStructuresAppName = HostApplications.TeklaStructures.Name; #endif - public string Description => "Default Speckle Kit for TeklaStructures"; + public string Description => "Default Speckle Kit for TeklaStructures"; - public string Name => nameof(ConverterTeklaStructures); + public string Name => nameof(ConverterTeklaStructures); - public Dictionary Settings { get; private set; } = new Dictionary(); + public Dictionary Settings { get; private set; } = new Dictionary(); - public string Author => "Speckle"; + public string Author => "Speckle"; - public string WebsiteOrEmail => "https://speckle.systems"; + public string WebsiteOrEmail => "https://speckle.systems"; - public Model Model { get; private set; } + public Model Model { get; private set; } - public ReceiveMode ReceiveMode { get; set; } + public ReceiveMode ReceiveMode { get; set; } - public void SetContextDocument(object doc) - { - Model = (Model)doc; - } + public void SetContextDocument(object doc) + { + Model = (Model)doc; + } - /// - /// To know which other objects are being converted, in order to sort relationships between them. - /// For example, elements that have children use this to determine whether they should send their children out or not. - /// - public List ContextObjects { get; set; } = new List(); + /// + /// To know which other objects are being converted, in order to sort relationships between them. + /// For example, elements that have children use this to determine whether they should send their children out or not. + /// + public List ContextObjects { get; set; } = new List(); - /// - /// To keep track of previously received objects from a given stream in here. If possible, conversions routines - /// will edit an existing object, otherwise they will delete the old one and create the new one. - /// - public List PreviousContextObjects { get; set; } = new List(); + /// + /// To keep track of previously received objects from a given stream in here. If possible, conversions routines + /// will edit an existing object, otherwise they will delete the old one and create the new one. + /// + public List PreviousContextObjects { get; set; } = new List(); - public HashSet ConversionErrors { get; private set; } = new HashSet(); + public HashSet ConversionErrors { get; private set; } = new HashSet(); - public ProgressReport Report { get; private set; } = new ProgressReport(); + public ProgressReport Report { get; private set; } = new ProgressReport(); - public bool CanConvertToNative(Base @object) + public bool CanConvertToNative(Base @object) + { + Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); + if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) { - Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); - if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) - { - if (DefaultTraversal.HasDefinition(@object) || DefaultTraversal.HasDisplayValue(@object)) - { - return true; - } - return false; - } - - switch (@object) + if (DefaultTraversal.HasDefinition(@object) || DefaultTraversal.HasDisplayValue(@object)) { - case BE.Beam b: - return true; - case BE.Column b: - return true; - case BE.Area a: - return true; - //recieving should first be ordered to place parts first before fittings, welds, booleans, bolts can be converted - //case BE.TeklaStructures.Bolts b: - // return true; - //case BE.TeklaStructures.Welds w: - // return true; - //case BE.Opening o: - // return true; - //case Geometry.Plane p: - // return true; - //case Geometry.Plane p: - // return true; - default: - return false; - //_ => (@object as ModelObject).IsElementSupported() + return true; } - ; + return false; } - public bool CanConvertToNativeDisplayable(Base @object) + switch (@object) { - return false; + case BE.Beam b: + return true; + case BE.Column b: + return true; + case BE.Area a: + return true; + //recieving should first be ordered to place parts first before fittings, welds, booleans, bolts can be converted + //case BE.TeklaStructures.Bolts b: + // return true; + //case BE.TeklaStructures.Welds w: + // return true; + //case BE.Opening o: + // return true; + //case Geometry.Plane p: + // return true; + //case Geometry.Plane p: + // return true; + default: + return false; + //_ => (@object as ModelObject).IsElementSupported() } + ; + } + + public bool CanConvertToNativeDisplayable(Base @object) + { + return false; + } - public bool CanConvertToSpeckle(object @object) + public bool CanConvertToSpeckle(object @object) + { + //return @object + switch (@object) { - //return @object - switch (@object) - { - case Beam b: - return true; - case PolyBeam pb: - return true; - case SpiralBeam sb: - return true; - case BoltGroup bg: - return true; - case ContourPlate cp: - return true; - case Weld w: - return true; - case PolygonWeld pw: - return true; - case BooleanPart bp: - return true; - case Fitting ft: - return true; - default: - return false; - //_ => (@object as ModelObject).IsElementSupported() - } - ; + case Beam b: + return true; + case PolyBeam pb: + return true; + case SpiralBeam sb: + return true; + case BoltGroup bg: + return true; + case ContourPlate cp: + return true; + case Weld w: + return true; + case PolygonWeld pw: + return true; + case BooleanPart bp: + return true; + case Fitting ft: + return true; + default: + return false; + //_ => (@object as ModelObject).IsElementSupported() } + ; + } - public object ConvertToNative(Base @object) + public object ConvertToNative(Base @object) + { + Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); + if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) { - Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); - if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) + if (@object is Instance instance) { - if (@object is Instance instance) - { - MeshToNative(instance, instance.GetTransformedGeometry().Where(t => t is Mesh).Cast().ToList()); - } - else + MeshToNative(instance, instance.GetTransformedGeometry().Where(t => t is Mesh).Cast().ToList()); + } + else + { + var bases = BaseExtensions.Flatten(@object); + foreach (var @base in bases) { - var bases = BaseExtensions.Flatten(@object); - foreach (var @base in bases) + foreach (var displayAlias in DefaultTraversal.displayValuePropAliases) { - foreach (var displayAlias in DefaultTraversal.displayValuePropAliases) + if (@base[displayAlias] is not List meshes) { - if (@base[displayAlias] is not List meshes) - continue; - - MeshToNative(@base, meshes); + continue; } + + MeshToNative(@base, meshes); } } } - - switch (@object) - { - case BE.Beam o: - BeamToNative(o); - return true; - case BE.Column o: - ColumnToNative(o); - return true; - case BE.Area o: - ContourPlateToNative(o); - return true; - case Geometry.Plane o: - FittingToNative(o); - return true; - case BE.Opening o: - BooleanPartToNative(o); - return true; - case BE.TeklaStructures.Bolts o: - BoltsToNative(o); - return true; - case BE.TeklaStructures.Welds o: - WeldsToNative(o); - return true; - default: - return false; - } } - public object ConvertToNativeDisplayable(Base @object) + switch (@object) { - throw new NotImplementedException(); + case BE.Beam o: + BeamToNative(o); + return true; + case BE.Column o: + ColumnToNative(o); + return true; + case BE.Area o: + ContourPlateToNative(o); + return true; + case Geometry.Plane o: + FittingToNative(o); + return true; + case BE.Opening o: + BooleanPartToNative(o); + return true; + case BE.TeklaStructures.Bolts o: + BoltsToNative(o); + return true; + case BE.TeklaStructures.Welds o: + WeldsToNative(o); + return true; + default: + return false; } + } - public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); + public object ConvertToNativeDisplayable(Base @object) + { + throw new NotImplementedException(); + } - public Base ConvertToSpeckle(object @object) + public List ConvertToNative(List objects) => objects.Select(ConvertToNative).ToList(); + + public Base ConvertToSpeckle(object @object) + { + Base returnObject = null; + switch (@object) { - Base returnObject = null; - switch (@object) - { - case Beam o: - returnObject = BeamToSpeckle(o); - Report.Log($"Created Beam"); - break; - case PolyBeam o: - returnObject = PolyBeamToSpeckle(o); - Report.Log($"Created PolyBeam"); - break; - case SpiralBeam o: - returnObject = SpiralBeamToSpeckle(o); - Report.Log($"Created SpiralBeam"); - break; - case BoltGroup o: - returnObject = BoltsToSpeckle(o); - Report.Log($"Created Bolts"); - break; - case RebarGroup o: - returnObject = RebarGroupToSpeckle(o); - Report.Log($"Created Rebars"); - break; - case ContourPlate o: - returnObject = ContourPlateToSpeckle(o); - Report.Log($"Created ContourPlate"); - break; - case Weld o: - returnObject = WeldsToSpeckle(o); - Report.Log($"Created Weld"); - break; - case PolygonWeld o: - returnObject = PoylgonWeldsToSpeckle(o); - Report.Log($"Created PolygonWeld"); - break; - case BooleanPart o: - returnObject = BooleanPartToSpeckle(o); - Report.Log($"Created BooleanPart"); - break; - case Fitting o: - returnObject = FittingsToSpeckle(o); - Report.Log($"Created Fitting"); - break; - default: - ConversionErrors.Add( - new Exception($"Skipping not supported type: {@object.GetType()}{GetElemInfo(@object)}") - ); - returnObject = null; - break; - } - return returnObject; + case Beam o: + returnObject = BeamToSpeckle(o); + Report.Log($"Created Beam"); + break; + case PolyBeam o: + returnObject = PolyBeamToSpeckle(o); + Report.Log($"Created PolyBeam"); + break; + case SpiralBeam o: + returnObject = SpiralBeamToSpeckle(o); + Report.Log($"Created SpiralBeam"); + break; + case BoltGroup o: + returnObject = BoltsToSpeckle(o); + Report.Log($"Created Bolts"); + break; + case RebarGroup o: + returnObject = RebarGroupToSpeckle(o); + Report.Log($"Created Rebars"); + break; + case ContourPlate o: + returnObject = ContourPlateToSpeckle(o); + Report.Log($"Created ContourPlate"); + break; + case Weld o: + returnObject = WeldsToSpeckle(o); + Report.Log($"Created Weld"); + break; + case PolygonWeld o: + returnObject = PoylgonWeldsToSpeckle(o); + Report.Log($"Created PolygonWeld"); + break; + case BooleanPart o: + returnObject = BooleanPartToSpeckle(o); + Report.Log($"Created BooleanPart"); + break; + case Fitting o: + returnObject = FittingsToSpeckle(o); + Report.Log($"Created Fitting"); + break; + default: + ConversionErrors.Add(new Exception($"Skipping not supported type: {@object.GetType()}{GetElemInfo(@object)}")); + returnObject = null; + break; } + return returnObject; + } - private string GetElemInfo(object o) + private string GetElemInfo(object o) + { + if (o is ModelObject e) { - if (o is ModelObject e) - return $", name: {e.Identifier.GetType().ToString()}, id: {e.Identifier.ToString()}"; - - return ""; + return $", name: {e.Identifier.GetType().ToString()}, id: {e.Identifier.ToString()}"; } - public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); + return ""; + } - public IEnumerable GetServicedApplications() => new string[] { TeklaStructuresAppName }; + public List ConvertToSpeckle(List objects) => objects.Select(ConvertToSpeckle).ToList(); - public void SetContextObjects(List objects) => ContextObjects = objects; + public IEnumerable GetServicedApplications() => new string[] { TeklaStructuresAppName }; - public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; + public void SetContextObjects(List objects) => ContextObjects = objects; - public void SetConverterSettings(object settings) - { - Settings = settings as Dictionary; - } + public void SetPreviousContextObjects(List objects) => PreviousContextObjects = objects; + + public void SetConverterSettings(object settings) + { + Settings = settings as Dictionary; } } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructuresShared.projitems b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructuresShared.projitems index 9624610c15..5e5907d0de 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructuresShared.projitems +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructuresShared.projitems @@ -11,19 +11,19 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBeam.cs deleted file mode 100644 index 4109fdb75e..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBeam.cs +++ /dev/null @@ -1,269 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using Objects.BuiltElements.TeklaStructures; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using TSG = Tekla.Structures.Geometry3d; -using System.Collections; -using StructuralUtilities.PolygonMesher; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void BeamToNative(BE.Beam beam) - { - - - if (beam is TeklaBeam) - { - - var teklaBeam = (TeklaBeam)beam; - switch (teklaBeam.TeklaBeamType) - { - case TeklaBeamType.Beam: - if (!(beam.baseLine is Line)) - { - } - Line line = (Line)beam.baseLine; - TSG.Point startPoint = new TSG.Point(line.start.x, line.start.y, line.start.z); - TSG.Point endPoint = new TSG.Point(line.end.x, line.end.y, line.end.z); - var myBeam = new Beam(startPoint, endPoint); - SetPartProperties(myBeam, teklaBeam); - if (!IsProfileValid(myBeam.Profile.ProfileString)) - { - Report.Log($"{myBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - return; - } - myBeam.Insert(); - //Model.CommitChanges(); - break; - case TeklaBeamType.PolyBeam: - Polyline polyline = (Polyline)beam.baseLine; - var polyBeam = new PolyBeam(); - ToNativeContourPlate(polyline, polyBeam.Contour); - SetPartProperties(polyBeam, teklaBeam); - if (!IsProfileValid(polyBeam.Profile.ProfileString)) - { - Report.Log($"{polyBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - return; - } - polyBeam.Insert(); - //Model.CommitChanges(); - break; - case TeklaBeamType.SpiralBeam: - Polyline polyline2 = (Polyline)beam.baseLine; - var teklaSpiralBeam = (Objects.BuiltElements.TeklaStructures.SpiralBeam)teklaBeam; - var startPt = new TSG.Point(teklaSpiralBeam.startPoint.x, teklaSpiralBeam.startPoint.y, teklaSpiralBeam.startPoint.z); - var rotatAxisPt1 = new TSG.Point(teklaSpiralBeam.rotationAxisPt1.x, teklaSpiralBeam.rotationAxisPt1.y, teklaSpiralBeam.rotationAxisPt1.z); - var rotatAxisPt2 = new TSG.Point(teklaSpiralBeam.rotationAxisPt2.x, teklaSpiralBeam.rotationAxisPt2.y, teklaSpiralBeam.rotationAxisPt2.z); - var totalRise = teklaSpiralBeam.totalRise; - var rotationAngle = teklaSpiralBeam.rotationAngle; - var twistAngleStart = teklaSpiralBeam.twistAngleStart; - var twistAngleEnd = teklaSpiralBeam.twistAngleEnd; - var spiralBeam = new Tekla.Structures.Model.SpiralBeam(startPt, rotatAxisPt1, rotatAxisPt2, totalRise, rotationAngle, twistAngleStart, twistAngleEnd); - SetPartProperties(spiralBeam, teklaBeam); - if (!IsProfileValid(spiralBeam.Profile.ProfileString)) - { - Report.Log($"{spiralBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - return; - } - spiralBeam.Insert(); - //Model.CommitChanges(); - break; - } - } - else - { - if (!(beam.baseLine is Line)) - { - } - Line line = (Line)beam.baseLine; - TSG.Point startPoint = new TSG.Point(line.start.x, line.start.y, line.start.z); - TSG.Point endPoint = new TSG.Point(line.end.x, line.end.y, line.end.z); - var myBeam = new Beam(startPoint, endPoint); - myBeam.Insert(); - //Model.CommitChanges(); - } - } - - - public void ColumnToNative(BE.Column column) - { - - - //if (beam is TeklaBeam) - //{ - - // var teklaBeam = (TeklaBeam)beam; - // switch (teklaBeam.TeklaBeamType) - // { - // case TeklaBeamType.Beam: - // if (!(beam.baseLine is Line)) - // { - // } - // Line line = (Line)beam.baseLine; - // TSG.Point startPoint = new TSG.Point(line.start.x, line.start.y, line.start.z); - // TSG.Point endPoint = new TSG.Point(line.end.x, line.end.y, line.end.z); - // var myBeam = new Beam(startPoint, endPoint); - // SetPartProperties(myBeam, teklaBeam); - // if (!IsProfileValid(myBeam.Profile.ProfileString)) - // { - // Report.Log($"{myBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - // return; - // } - // myBeam.Insert(); - // //Model.CommitChanges(); - // break; - // case TeklaBeamType.PolyBeam: - // Polyline polyline = (Polyline)beam.baseLine; - // var polyBeam = new PolyBeam(); - // ToNativeContourPlate(polyline, polyBeam.Contour); - // SetPartProperties(polyBeam, teklaBeam); - // if (!IsProfileValid(polyBeam.Profile.ProfileString)) - // { - // Report.Log($"{polyBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - // return; - // } - // polyBeam.Insert(); - // //Model.CommitChanges(); - // break; - // case TeklaBeamType.SpiralBeam: - // Polyline polyline2 = (Polyline)beam.baseLine; - // var teklaSpiralBeam = (Objects.BuiltElements.TeklaStructures.SpiralBeam)teklaBeam; - // var startPt = new TSG.Point(teklaSpiralBeam.startPoint.x, teklaSpiralBeam.startPoint.y, teklaSpiralBeam.startPoint.z); - // var rotatAxisPt1 = new TSG.Point(teklaSpiralBeam.rotationAxisPt1.x, teklaSpiralBeam.rotationAxisPt1.y, teklaSpiralBeam.rotationAxisPt1.z); - // var rotatAxisPt2 = new TSG.Point(teklaSpiralBeam.rotationAxisPt2.x, teklaSpiralBeam.rotationAxisPt2.y, teklaSpiralBeam.rotationAxisPt2.z); - // var totalRise = teklaSpiralBeam.totalRise; - // var rotationAngle = teklaSpiralBeam.rotationAngle; - // var twistAngleStart = teklaSpiralBeam.twistAngleStart; - // var twistAngleEnd = teklaSpiralBeam.twistAngleEnd; - // var spiralBeam = new Tekla.Structures.Model.SpiralBeam(startPt, rotatAxisPt1, rotatAxisPt2, totalRise, rotationAngle, twistAngleStart, twistAngleEnd); - // SetPartProperties(spiralBeam, teklaBeam); - // if (!IsProfileValid(spiralBeam.Profile.ProfileString)) - // { - // Report.Log($"{spiralBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); - // return; - // } - // spiralBeam.Insert(); - // //Model.CommitChanges(); - // break; - // } - //} - //else - //{ - if (!(column.baseLine is Line)) - { - } - Line line = (Line)column.baseLine; - TSG.Point startPoint = new TSG.Point(line.start.x, line.start.y, line.start.z); - TSG.Point endPoint = new TSG.Point(line.end.x, line.end.y, line.end.z); - var myBeam = new Beam(startPoint, endPoint); - myBeam.Insert(); - //Model.CommitChanges(); - //} - } - - - public void SetPartProperties(Part part, TeklaBeam teklaBeam) - { - part.Material.MaterialString = teklaBeam.material?.name; - part.Profile.ProfileString = teklaBeam.profile?.name; - part.Class = teklaBeam.classNumber; - part.Finish = teklaBeam.finish; - part.Name = teklaBeam.name; - part.Position = SetPositioning(teklaBeam.position); - } - - public TeklaBeam BeamToSpeckle(Tekla.Structures.Model.Beam beam) - { - var speckleBeam = new TeklaBeam(); - //TO DO: Support for curved beams goes in here as well + twin beams - - var endPoint = beam.EndPoint; - var startPoint = beam.StartPoint; - var units = GetUnitsFromModel(); - - Point speckleStartPoint = new Point(startPoint.X, startPoint.Y, startPoint.Z, units); - Point speckleEndPoint = new Point(endPoint.X, endPoint.Y, endPoint.Z, units); - speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); - speckleBeam.baseLine.length = Math.Sqrt(Math.Pow((startPoint.X - endPoint.X),2)+ Math.Pow((startPoint.Y - endPoint.Y), 2)+ Math.Pow((startPoint.Z - endPoint.Z), 2)); - speckleBeam.profile = GetBeamProfile(beam.Profile.ProfileString); - speckleBeam.material = GetMaterial(beam.Material.MaterialString); - var beamCS = beam.GetCoordinateSystem(); - speckleBeam.position = GetPositioning(beam.Position); - speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); - speckleBeam.finish = beam.Finish; - speckleBeam.classNumber = beam.Class; - speckleBeam.name = beam.Name; - speckleBeam.applicationId = beam.Identifier.GUID.ToString(); - speckleBeam.TeklaBeamType = TeklaBeamType.Beam; - var vol = new double(); - var area = new double(); - beam.GetReportProperty("VOLUME", ref vol); - speckleBeam.volume = vol; - beam.GetReportProperty("AREA", ref area); - speckleBeam.area = area; - - var rebars = beam.GetReinforcements(); - if (rebars != null) - { - foreach (var rebar in rebars) - { - if (rebar is RebarGroup) {speckleBeam.rebars = RebarGroupToSpeckle((RebarGroup)rebar); } - - } - } - - GetAllUserProperties(speckleBeam, beam); - - var solid = beam.GetSolid(); - speckleBeam.displayValue = new List{ GetMeshFromSolid(solid)}; - return speckleBeam; - } - /// - /// Create beam without display mesh for boolean parts - /// - /// - /// - public TeklaBeam AntiBeamToSpeckle(Tekla.Structures.Model.Beam beam) - { - var speckleBeam = new TeklaBeam(); - //TO DO: Support for curved beams goes in here as well + twin beams - - var endPoint = beam.EndPoint; - var startPoint = beam.StartPoint; - var units = GetUnitsFromModel(); - - Point speckleStartPoint = new Point(startPoint.X, startPoint.Y, startPoint.Z, units); - Point speckleEndPoint = new Point(endPoint.X, endPoint.Y, endPoint.Z, units); - speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); - - speckleBeam.profile = GetBeamProfile(beam.Profile.ProfileString); - speckleBeam.material = GetMaterial(beam.Material.MaterialString); - var beamCS = beam.GetCoordinateSystem(); - speckleBeam.position = GetPositioning(beam.Position); - speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); - speckleBeam.classNumber = beam.Class; - speckleBeam.name = beam.Name; - speckleBeam.TeklaBeamType = TeklaBeamType.Beam; - speckleBeam.applicationId = beam.Identifier.GUID.ToString(); - var vol = new double(); - var area = new double(); - beam.GetReportProperty("VOLUME", ref vol); - speckleBeam.volume = vol; - beam.GetReportProperty("AREA", ref area); - speckleBeam.area = area; - - speckleBeam["units"] = units; - - return speckleBeam; - } - } -} \ No newline at end of file diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBentPlate.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBentPlate.cs deleted file mode 100644 index 39de7cba4b..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBentPlate.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ConverterTeklaStructuresShared.Partial_Classes -{ - class ConvertBentPlate - { - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBolts.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBolts.cs deleted file mode 100644 index ad5e4d41f1..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBolts.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using TSG = Tekla.Structures.Geometry3d; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void BoltsToNative(BE.TeklaStructures.Bolts bolts) - { - switch (bolts) - { - case BE.TeklaStructures.BoltsArray ba: - { - BoltArray teklaBoltArray = new BoltArray(); - SetBoltGroupProperties(teklaBoltArray, ba); - for (int i = 0; i < ba.xDistance.Count; i++) - { - teklaBoltArray.AddBoltDistX(ba.xDistance[i]); - } - for (int i = 0; i < ba.yDistance.Count; i++) - { - teklaBoltArray.AddBoltDistY(ba.yDistance[i]); - } - teklaBoltArray.Insert(); - return; - } - case BE.TeklaStructures.BoltsXY bx: - { - BoltXYList teklaBoltXY = new BoltXYList(); - SetBoltGroupProperties(teklaBoltXY, bx); - for (int i = 0; i < bx.xPosition.Count; i++) - { - teklaBoltXY.AddBoltDistX(bx.xPosition[i]); - } - for (int i = 0; i < bx.yPosition.Count; i++) - { - teklaBoltXY.AddBoltDistY(bx.yPosition[i]); - } - teklaBoltXY.Insert(); - return; - } - case BE.TeklaStructures.BoltsCircle bc: - { - BoltCircle teklaBoltCircle = new BoltCircle(); - SetBoltGroupProperties(teklaBoltCircle, bc); - teklaBoltCircle.NumberOfBolts = bc.boltCount; - teklaBoltCircle.Diameter = bc.diameter; - teklaBoltCircle.Insert(); - return; - } - } - } - public BE.TeklaStructures.Bolts BoltsToSpeckle(BoltGroup Bolts) - { - BE.TeklaStructures.Bolts speckleTeklaBolt; - var units = GetUnitsFromModel(); - - // Add specific Tekla necessary properties for the different types of bolts possible - switch (Bolts) - { - case BoltArray ba: - var speckleBoltArray = new BE.TeklaStructures.BoltsArray(); - - speckleBoltArray.xDistance = new List(); - speckleBoltArray.yDistance = new List(); - for (int i = 0; i < ba.GetBoltDistXCount(); i++) - { - speckleBoltArray.xDistance.Add(ba.GetBoltDistX(i)); - } - for (int i = 0; i < ba.GetBoltDistYCount(); i++) - { - speckleBoltArray.yDistance.Add(ba.GetBoltDistY(i)); - } - speckleTeklaBolt = speckleBoltArray; - break; - case BoltXYList bxy: - var speckleBoltXY = new BE.TeklaStructures.BoltsXY(); - speckleBoltXY.xPosition = new List(); - speckleBoltXY.yPosition = new List(); - for (int i = 0; i < bxy.GetBoltDistXCount(); i++) - { - speckleBoltXY.xPosition.Add(bxy.GetBoltDistX(i)); - } - for (int i = 0; i < bxy.GetBoltDistYCount(); i++) - { - speckleBoltXY.yPosition.Add(bxy.GetBoltDistY(i)); - } - speckleTeklaBolt = speckleBoltXY; - break; - case BoltCircle bc: - var speckleBoltCircle = new BE.TeklaStructures.BoltsCircle(); - speckleBoltCircle.boltCount = (int)bc.NumberOfBolts; - speckleBoltCircle.diameter = bc.Diameter; - speckleTeklaBolt = speckleBoltCircle; - break; - default: - speckleTeklaBolt = new BE.TeklaStructures.Bolts(); - break; - } - - //Set common properties - speckleTeklaBolt.boltSize = Bolts.BoltSize; - speckleTeklaBolt.boltStandard = Bolts.BoltStandard; - speckleTeklaBolt.cutLength = Bolts.CutLength; - speckleTeklaBolt.length = Bolts.Length; - speckleTeklaBolt.position = GetPositioning(Bolts.Position); - - // global bolt coordinates - speckleTeklaBolt.coordinates = Bolts.BoltPositions - .Cast() - .Select(p => new Point(p.X, p.Y, p.Z, units)) - .ToList(); - - // Add bolted parts necessary for insertion into Tekla - speckleTeklaBolt.boltedPartsIds.Add(Bolts.PartToBeBolted.Identifier.GUID.ToString()); - speckleTeklaBolt.boltedPartsIds.Add(Bolts.PartToBoltTo.Identifier.GUID.ToString()); - if (Bolts.OtherPartsToBolt.Count > 0) - { - foreach (Part otherPart in Bolts.OtherPartsToBolt.Cast()) - { - speckleTeklaBolt.boltedPartsIds.Add(otherPart.Identifier.GUID.ToString()); - } - } - GetAllUserProperties(speckleTeklaBolt, Bolts); - - var solid = Bolts.GetSolid(); - speckleTeklaBolt.displayValue = new List { GetMeshFromSolid(solid) }; - - return speckleTeklaBolt; - } - - public void SetBoltGroupProperties(BoltGroup boltGroup, BE.TeklaStructures.Bolts bolts) - { - boltGroup.PartToBeBolted = Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[0])) as Part; - boltGroup.PartToBoltTo = Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[1])) as Part; - if (bolts.boltedPartsIds.Count > 2) - { - for (int i = 2; i < bolts.boltedPartsIds.Count; i++) - { - boltGroup.AddOtherPartToBolt(Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[i])) as Part); - } - } - boltGroup.FirstPosition = new TSG.Point(bolts.firstPosition.x, bolts.firstPosition.y, bolts.firstPosition.z); - boltGroup.SecondPosition = new TSG.Point(bolts.secondPosition.x, bolts.secondPosition.y, bolts.secondPosition.z); - boltGroup.BoltSize = bolts.boltSize; - boltGroup.Tolerance = bolts.tolerance; - boltGroup.BoltStandard = bolts.boltStandard; - boltGroup.CutLength = bolts.cutLength; - boltGroup.Position = SetPositioning(bolts.position); - } - } -} \ No newline at end of file diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBooleanPart.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBooleanPart.cs deleted file mode 100644 index ec1a96a7bd..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertBooleanPart.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using Objects.BuiltElements.TeklaStructures; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void BooleanPartToNative(BE.Opening opening) - { - BooleanPart booleanPart = new BooleanPart(); - switch (opening) - { - case TeklaContourOpening contourOpening: - { - var contourPlate = new ContourPlate(); - contourPlate.Profile.ProfileString = contourOpening.cuttingPlate.profile.name; - contourPlate.Material.MaterialString = contourOpening.cuttingPlate.material.name; - contourPlate.Class = BooleanPart.BooleanOperativeClassName; - contourPlate.Position = SetPositioning(contourOpening.cuttingPlate.position); - for (int i = 0; i < contourOpening.cuttingPlate.contour.Count; i++) - { - TeklaContourPoint cp = contourOpening.cuttingPlate.contour[i]; - contourPlate.AddContourPoint(ToTeklaContourPoint(cp)); - } - contourPlate.Insert(); - booleanPart.SetOperativePart(contourPlate); - booleanPart.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(contourOpening.openingHostId)); - booleanPart.Insert(); - contourPlate.Delete(); - } - break; - case TeklaBeamOpening beamOpening: - { - var beam = new Beam(); - var baseLine = beamOpening.cuttingBeam.baseLine as Line; - beam.StartPoint = new Tekla.Structures.Geometry3d.Point(baseLine.start.x, baseLine.start.y, baseLine.start.z); - beam.EndPoint = new Tekla.Structures.Geometry3d.Point(baseLine.start.x, baseLine.start.y, baseLine.start.z); - - beam.Profile.ProfileString = beamOpening.cuttingBeam.profile.name; - beam.Material.MaterialString = beamOpening.cuttingBeam.material.name; - beam.Class = BooleanPart.BooleanOperativeClassName; - beam.Position = SetPositioning(beamOpening.cuttingBeam.position); - beam.Insert(); - booleanPart.SetOperativePart(beam); - booleanPart.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(beamOpening.openingHostId)); - booleanPart.Insert(); - beam.Delete(); - } - break; - } - } - public TeklaOpening BooleanPartToSpeckle(Tekla.Structures.Model.BooleanPart booleanPart) - { - TeklaOpening teklaOpening; - if (booleanPart.OperativePart is ContourPlate) - { - var contourOpening = new TeklaContourOpening(); - contourOpening.applicationId = booleanPart.Identifier.GUID.ToString(); - contourOpening.openingHostId = booleanPart.Father.Identifier.GUID.ToString(); - contourOpening.cuttingPlate = AntiContourPlateToSpeckle(booleanPart.OperativePart as ContourPlate); - contourOpening.openingType = TeklaOpeningTypeEnum.contour; - contourOpening.outline = ToSpecklePolycurve((booleanPart.OperativePart as ContourPlate).GetContourPolycurve()); - contourOpening.thickness = double.Parse(new string((booleanPart.OperativePart as ContourPlate).Profile.ProfileString.Where(c => char.IsDigit(c)).ToArray())); - teklaOpening = contourOpening; - } - else - { - var beamOpening = new TeklaBeamOpening(); - beamOpening.applicationId = booleanPart.Identifier.GUID.ToString(); - beamOpening.openingHostId = booleanPart.Father.Identifier.GUID.ToString(); - beamOpening.openingType = TeklaOpeningTypeEnum.beam; - beamOpening.cuttingBeam = AntiBeamToSpeckle(booleanPart.OperativePart as Beam); - teklaOpening = beamOpening; - } - return teklaOpening; - } - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertContourPlate.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertContourPlate.cs deleted file mode 100644 index d87baf6b3e..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertContourPlate.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using Objects.BuiltElements.TeklaStructures; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void ContourPlateToNative(BE.Area area) - { - if (!(area.outline is Polyline)) { } - var ContourPlate = new ContourPlate(); - if (area is TeklaContourPlate) - { - //var countourPoints = GetContourPointsFromPolyLine((Polyline)area.outline); - var contour = (TeklaContourPlate)area; - - ContourPlate.Profile.ProfileString = contour.profile.name; - //ContourPlate.Contour.ContourPoints = countourPoints; - ContourPlate.Material.MaterialString = contour.material?.name; - foreach (var cp in contour.contour) - { - ContourPlate.AddContourPoint(ToTeklaContourPoint(cp)); - } - SetPartProperties(ContourPlate, contour); - } - ContourPlate.Insert(); - //Model.CommitChanges(); - - } - public TeklaContourPlate ContourPlateToSpeckle(Tekla.Structures.Model.ContourPlate plate) - { - var specklePlate = new TeklaContourPlate(); - specklePlate.name = plate.Name; - specklePlate.profile = GetContourPlateProfile(plate.Profile.ProfileString); - specklePlate.material = GetMaterial(plate.Material.MaterialString); - specklePlate.finish = plate.Finish; - specklePlate.classNumber = plate.Class; - specklePlate.position = GetPositioning(plate.Position); - - //Polygon teklaPolygon = null; - - // Get general outline for other programs - //plate.Contour.CalculatePolygon(out teklaPolygon); - //if (teklaPolygon != null) - // specklePlate.outline = ToSpecklePolyline(teklaPolygon); - - // Getting polycurve now works with new nuget packages - var teklaPolycurve = plate.GetContourPolycurve(); - specklePlate.outline = ToSpecklePolycurve(teklaPolycurve); - - // Get contour for ToNative Tekla conversion - specklePlate.contour = new List(); - var cPts = plate.Contour.ContourPoints.Cast(); - foreach (ContourPoint pt in cPts) - { - specklePlate.contour.Add(ToSpeckleContourPoint(pt)); - } - - GetAllUserProperties(specklePlate, plate); - - var solid = plate.GetSolid(); - specklePlate.displayValue = new List{ GetMeshFromSolid(solid)}; - var rebars = plate.GetReinforcements(); - if (rebars != null) - { - foreach (var rebar in rebars) - { - if (rebar is RebarGroup) { specklePlate.rebars = RebarGroupToSpeckle((RebarGroup)rebar); } - - } - } - return specklePlate; - - - } - /// - /// Create a contour plate without a display mesh for boolean parts - /// - /// - /// - public TeklaContourPlate AntiContourPlateToSpeckle(Tekla.Structures.Model.ContourPlate plate) - { - var specklePlate = new TeklaContourPlate(); - specklePlate.name = plate.Name; - specklePlate.profile = GetContourPlateProfile(plate.Profile.ProfileString); - specklePlate.material = GetMaterial(plate.Material.MaterialString); - - specklePlate.classNumber = plate.Class; - specklePlate.position = GetPositioning(plate.Position); - - Polygon teklaPolygon = null; - plate.Contour.CalculatePolygon(out teklaPolygon); - if (teklaPolygon != null) - specklePlate.outline = ToSpecklePolyline(teklaPolygon); - - // Get contour for ToNative Tekla conversion - specklePlate.contour = new List(); - var cPts = plate.Contour.ContourPoints.Cast(); - foreach (ContourPoint pt in cPts) - { - specklePlate.contour.Add(ToSpeckleContourPoint(pt)); - } - - var units = GetUnitsFromModel(); - specklePlate.applicationId = plate.Identifier.GUID.ToString(); - specklePlate["units"] = units; - return specklePlate; - } - public void SetPartProperties(Part part, TeklaContourPlate teklaPlate) - { - part.Material.MaterialString = teklaPlate.material?.name; - part.Profile.ProfileString = teklaPlate.profile.name; - part.Class = teklaPlate.classNumber; - part.Finish = teklaPlate.finish; - part.Name = teklaPlate.name; - part.Position = SetPositioning(teklaPlate.position); - } - } - -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertDirectShapeMesh.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertDirectShapeMesh.cs deleted file mode 100644 index cd8872f66f..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertDirectShapeMesh.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Collections.Generic; -using GE = Objects.Geometry; -using GES = Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using Objects.BuiltElements.TeklaStructures; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using Tekla.Structures.Model.UI; -using Tekla.Structures.Geometry3d; -using Tekla.Structures.Catalogs; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void MeshToNative(Base @object, List displayValues) - { - int incr = 0; - foreach (var mesh in displayValues) - { - FacetedBrep facetedBrep = CreateFacetedBrep(mesh); - - // Add shape to catalog - // Each shape in catalog needs to have a unique name - string objectName = GetShapeName(@object); - string shapeName = "Speckle_" + objectName + (incr > 0 ? "_" + incr.ToString() : ""); - var shapeItem = new ShapeItem - { - Name = shapeName, - ShapeFacetedBrep = facetedBrep, - UpAxis = ShapeUpAxis.Z_Axis - }; - // remove possibly pre-existing shape with same name and then insert a Speckle object shape - // with that name into the catalog - shapeItem.Delete(); - bool result = false; - try - { - result = shapeItem.Insert(); - // Fails if two shapes exist with different names but same geometry fingerprint - } - catch (Exception ex) { } - - if (!result) - { - // Find pre-existing shape in catalog with same fingerprint - var matchingShape = CheckFingerprint(shapeItem); - if (matchingShape != null) - { - shapeName = matchingShape.Name; - result = true; - } - } - - // Insert object in model - if (result) - { - var brep = new Brep(); - brep.StartPoint = new Tekla.Structures.Geometry3d.Point(0, 0, 0); - brep.EndPoint = new Tekla.Structures.Geometry3d.Point(1000, 0, 0); - brep.Profile.ProfileString = shapeName; - brep.Material.MaterialString = "TS_Undefined"; - brep.Position.Depth = Position.DepthEnum.MIDDLE; - brep.Position.Plane = Position.PlaneEnum.MIDDLE; - brep.Position.Rotation = Position.RotationEnum.TOP; - brep.Insert(); - } - - incr++; - } - - //var vertex = new[] - // { - // new Vector(0.0, 0.0, 0.0), // 0 - // new Vector(300.0, 0.0, 0.0), // 1 - // new Vector(300.0, 700.0, 0.0), // 2 - // new Vector(0.0, 700.0, 0.0), // 3 - // new Vector(300.0, 700.0, 0.0), // 4 - // new Vector(300.0, 700.0, 2000.0), // 5 - // new Vector(0.0, 700.0, 2000.0), // 6 - // new Vector(100.0, 100.0, 0.0), // 7 - // new Vector(200.0, 100.0, 0.0), // 8 - // new Vector(200.0, 200.0, 0.0), // 9 - // new Vector(100.0, 200.0, 0.0) // 10 - // }; - //var outerWires = new[] - //{ - //foreach - // }; - //var innerWires = new Dictionary - // { - - // }; - - //var brep = new FacetedBrep(vertex, outerWires, innerWires); - - //var shapeItem = new ShapeItem - //{ - // Name = "Test", - // ShapeFacetedBrep = brep, - // UpAxis = ShapeUpAxis.Z_Axis - //}; - //shapeItem.Insert(); - //Model.CommitChanges(); - } - - public FacetedBrep CreateFacetedBrep(GE.Mesh mesh) - { - var faces = mesh.faces; - List> faceList = new List> { }; - faceList = faces.Select((x, i) => new { Index = i, Value = x }) - .GroupBy(x => x.Index / 4) - .Select(x => x.Select(v => v.Value).ToList()) - .ToList(); - var vertices = mesh.vertices; - List> verticesList = new List> { }; - verticesList = vertices.Select((x, i) => new { Index = i, Value = x }) - .GroupBy(x => x.Index / 3) - .Select(x => x.Select(v => v.Value).ToList()) - .ToList(); - List vertexs = new List(); - List outerWires = new List(); - var innerLoop = new Dictionary { }; - foreach (var vertex in verticesList) - { - var teklaVectorVertex = new Vector(vertex[0], vertex[1], vertex[2]); - vertexs.Add(teklaVectorVertex); - } - foreach (var face in faceList) - { - // Tekla wants the face loops in reverse - var teklaFaceLoop = new[] { face[3], face[2], face[1] }; - outerWires.Add(teklaFaceLoop); - } - var brep = new FacetedBrep(vertexs.ToArray(), outerWires.ToArray(), innerLoop); - return brep; - } - public string GetShapeName(Base @object) - { - string name = ""; - - // Take application id - if (string.IsNullOrEmpty(name)) - name = @object.applicationId; - - // If still empty then do Speckle id but can cause failure since changes with every commit - if (string.IsNullOrEmpty(name)) - name = @object.id; - - return name; - } - public ShapeItem CheckFingerprint(ShapeItem si) - { - CatalogHandler catalogHandler = new CatalogHandler(); - ShapeItemEnumerator sie = catalogHandler.GetShapeItems(); - while(sie.MoveNext()) - { - ShapeItem siItem = sie.Current; - if (siItem.Fingerprint == Polymesh.Fingerprint(si.ShapeFacetedBrep)) - return siItem; - } - return null; - } - } - -} - diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertFitting.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertFitting.cs deleted file mode 100644 index f8b18a9554..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertFitting.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using TSG = Tekla.Structures.Geometry3d; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void FittingToNative(Objects.Geometry.Plane fitting) - { - if (fitting is BE.TeklaStructures.Fitting) - { - var fit = fitting as BE.TeklaStructures.Fitting; - Fitting teklaFitting = new Fitting(); - teklaFitting.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(fit.hostID)); - teklaFitting.Plane = new Tekla.Structures.Model.Plane(); - teklaFitting.Plane.Origin = new TSG.Point(fit.origin.x, fit.origin.y, fit.origin.z); - teklaFitting.Plane.AxisX = new TSG.Vector(fit.xdir.x, fit.xdir.y, fit.xdir.z); - teklaFitting.Plane.AxisY = new TSG.Vector(fit.ydir.x, fit.ydir.y, fit.ydir.z); - teklaFitting.Insert(); - } - } - public BE.TeklaStructures.Fitting FittingsToSpeckle(Fitting fitting) - { - var speckleFitting = new BE.TeklaStructures.Fitting(); - - var units = GetUnitsFromModel(); - speckleFitting.origin = new Point(fitting.Plane.Origin.X, fitting.Plane.Origin.Y, fitting.Plane.Origin.Z, units); - speckleFitting.xdir = new Vector(fitting.Plane.AxisX.X, fitting.Plane.AxisX.Y, fitting.Plane.AxisX.Z, units); - speckleFitting.ydir = new Vector(fitting.Plane.AxisY.X, fitting.Plane.AxisY.Y, fitting.Plane.AxisY.Z, units); - var normal = fitting.Plane.AxisX.Cross(fitting.Plane.AxisY).GetNormal(); - speckleFitting.normal = new Vector(normal.X, normal.Y, normal.Z, units); - speckleFitting.hostID = fitting.Father.Identifier.GUID.ToString(); - speckleFitting.units = units; - speckleFitting.applicationId = fitting.Identifier.GUID.ToString(); - - return speckleFitting; - } - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertLoftedPlates.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertLoftedPlates.cs deleted file mode 100644 index 0862d84196..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertLoftedPlates.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ConverterTeklaStructuresShared.Partial_Classes -{ - class ConvertLoftedPlates - { - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertModel.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertModel.cs deleted file mode 100644 index ca10c2d84c..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ConverterTeklaStructuresShared.Partial_Classes -{ - class ConvertModel - { - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolyBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolyBeam.cs deleted file mode 100644 index dfcf040e94..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolyBeam.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using Objects.BuiltElements.TeklaStructures; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - - public TeklaBeam PolyBeamToSpeckle(PolyBeam PolyBeam) - { - var speckleBeam = new TeklaBeam(); - var units = GetUnitsFromModel(); - var centerPolyCurve = PolyBeam.GetCenterLine(false); - //var centerPolycurve = PolyBeam.GetCenterLinePolycurve(); - var pointList = new List { }; - var polyLine = new Polycurve(); - foreach (Tekla.Structures.Geometry3d.Point point in centerPolyCurve) - { - pointList.Add(point.X); - pointList.Add(point.Y); - pointList.Add(point.Z); - } - speckleBeam.profile = GetBeamProfile(PolyBeam.Profile.ProfileString); - speckleBeam.material = GetMaterial(PolyBeam.Material.MaterialString); - speckleBeam.finish = PolyBeam.Finish; - speckleBeam.classNumber = PolyBeam.Class; - var beamCS = PolyBeam.GetCoordinateSystem(); - speckleBeam.position = GetPositioning(PolyBeam.Position); - speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); - speckleBeam.name = PolyBeam.Name; - speckleBeam.baseLine = new Polyline(pointList, units); - speckleBeam.TeklaBeamType = TeklaBeamType.PolyBeam; - GetAllUserProperties(speckleBeam, PolyBeam); - var solid = PolyBeam.GetSolid(); - speckleBeam.displayValue = new List { GetMeshFromSolid(solid) }; - var vol = new double(); - var area = new double(); - PolyBeam.GetReportProperty("VOLUME", ref vol); - speckleBeam.volume = vol; - PolyBeam.GetReportProperty("AREA", ref area); - speckleBeam.area = area; - - return speckleBeam; - } - } -} \ No newline at end of file diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolygonWelds.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolygonWelds.cs deleted file mode 100644 index a22039246a..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPolygonWelds.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using TSG = Tekla.Structures.Geometry3d; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public BE.TeklaStructures.PolygonWelds PoylgonWeldsToSpeckle(PolygonWeld welds) - { - var speckleTeklaPolygonWeld = new BE.TeklaStructures.PolygonWelds(); - - speckleTeklaPolygonWeld.sizeAbove = welds.SizeAbove; - speckleTeklaPolygonWeld.sizeBelow = welds.SizeBelow; - speckleTeklaPolygonWeld.lengthAbove = welds.LengthAbove; - speckleTeklaPolygonWeld.lengthBelow = welds.LengthBelow; - speckleTeklaPolygonWeld.pitchAbove = welds.PitchAbove; - speckleTeklaPolygonWeld.pitchBelow = welds.PitchBelow; - speckleTeklaPolygonWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)welds.TypeAbove; - speckleTeklaPolygonWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)welds.TypeBelow; - speckleTeklaPolygonWeld.intermittentType = (BE.TeklaStructures.TeklaWeldIntermittentType)welds.IntermittentType; - - speckleTeklaPolygonWeld.polyline = ToSpecklePolyline(welds.Polygon); - - GetAllUserProperties(speckleTeklaPolygonWeld, welds); - - var solid = welds.GetSolid(); - speckleTeklaPolygonWeld.displayValue = new List { GetMeshFromSolid(solid) }; - return speckleTeklaPolygonWeld; - } - } -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertRebar.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertRebar.cs deleted file mode 100644 index e920768ed4..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertRebar.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using Objects.BuiltElements.TeklaStructures; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using TSG = Tekla.Structures.Geometry3d; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using Objects.Structural.Materials; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public TeklaRebar RebarGroupToSpeckle(RebarGroup rebarGroup) - { - - var Rebar = new TeklaRebar(); - Rebar.displayValue = new List { GetMeshFromSolid(rebarGroup.GetSolid()) }; - foreach (Polygon polygon in rebarGroup.Polygons){ - var polyline = ToSpecklePolyline(polygon); - Rebar.curves.Add(polyline); - } - Rebar.units = GetUnitsFromModel(); - Rebar.name = rebarGroup.Name; - Rebar.material = new Structural.Materials.StructuralMaterial(); - Rebar.material.name = rebarGroup.Grade; - Rebar.material.grade = rebarGroup.Grade; - Rebar.size = rebarGroup.Size; - Rebar.classNumber = rebarGroup.Class; - Rebar.startHook = new Hook(); - Rebar.startHook.angle = rebarGroup.StartHook.Angle; - Rebar.startHook.length = rebarGroup.StartHook.Length; - Rebar.startHook.radius = rebarGroup.StartHook.Radius; - switch (rebarGroup.StartHook.Shape){ - case RebarHookData.RebarHookShapeEnum.NO_HOOK: - Rebar.startHook.shape = shape.NO_HOOK; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_90_DEGREES: - Rebar.startHook.shape = shape.HOOK_90_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_135_DEGREES: - Rebar.startHook.shape = shape.HOOK_135_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_180_DEGREES: - Rebar.startHook.shape = shape.HOOK_180_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.CUSTOM_HOOK: - Rebar.startHook.shape = shape.CUSTOM_HOOK; - break; - } - Rebar.endHook = new Hook(); - Rebar.endHook.angle = rebarGroup.EndHook.Angle; - Rebar.endHook.length = rebarGroup.EndHook.Length; - Rebar.endHook.radius = rebarGroup.EndHook.Radius; - switch (rebarGroup.EndHook.Shape) - { - case RebarHookData.RebarHookShapeEnum.NO_HOOK: - Rebar.endHook.shape = shape.NO_HOOK; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_90_DEGREES: - Rebar.endHook.shape = shape.HOOK_90_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_135_DEGREES: - Rebar.endHook.shape = shape.HOOK_135_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.HOOK_180_DEGREES: - Rebar.endHook.shape = shape.HOOK_180_DEGREES; - break; - case RebarHookData.RebarHookShapeEnum.CUSTOM_HOOK: - Rebar.endHook.shape = shape.CUSTOM_HOOK; - break; - } - return Rebar; - } - - } - - -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertSpiralBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertSpiralBeam.cs deleted file mode 100644 index d8ec3468fb..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertSpiralBeam.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using Tekla.Structures.Geometry3d; -using Objects.BuiltElements.TeklaStructures; -using SpiralBeam = Objects.BuiltElements.TeklaStructures.SpiralBeam; -using Point = Objects.Geometry.Point; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - - public SpiralBeam SpiralBeamToSpeckle(Tekla.Structures.Model.SpiralBeam SpiralBeam) - { - var units = GetUnitsFromModel(); - var speckleBeam = new SpiralBeam(); - var curveLine = SpiralBeam.GetCenterLine(false); - var pointList = new List { }; - foreach (Tekla.Structures.Geometry3d.Point point in curveLine) - { - pointList.Add(point.X); - pointList.Add(point.Y); - pointList.Add(point.Z); - } - - speckleBeam.baseLine = new Polyline(pointList,units); - - speckleBeam.profile = GetBeamProfile(SpiralBeam.Profile.ProfileString); - speckleBeam.material = GetMaterial(SpiralBeam.Material.MaterialString); - speckleBeam.finish = SpiralBeam.Finish; - speckleBeam.classNumber = SpiralBeam.Class; - speckleBeam.name = SpiralBeam.Name; - var beamCS = SpiralBeam.GetCoordinateSystem(); - speckleBeam.position = GetPositioning(SpiralBeam.Position); - speckleBeam.alignmentVector = new Objects.Geometry.Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); - GetAllUserProperties(speckleBeam, SpiralBeam); - speckleBeam.TeklaBeamType = TeklaBeamType.SpiralBeam; - //var refLine = SpiralBeam.GetReferenceLine(false); - var solid = SpiralBeam.GetSolid(); - speckleBeam.displayValue = new List { GetMeshFromSolid(solid) }; - - speckleBeam.startPoint = new Point(SpiralBeam.StartPoint.X, SpiralBeam.StartPoint.Y, SpiralBeam.StartPoint.Z); - speckleBeam.rotationAxisPt1 = new Point(SpiralBeam.RotationAxisBasePoint.X, SpiralBeam.RotationAxisBasePoint.Y, SpiralBeam.RotationAxisBasePoint.Z); - speckleBeam.rotationAxisPt2 = new Point(SpiralBeam.RotationAxisUpPoint.X, SpiralBeam.RotationAxisUpPoint.Y, SpiralBeam.RotationAxisUpPoint.Z); - speckleBeam.totalRise = SpiralBeam.TotalRise; - speckleBeam.rotationAngle = SpiralBeam.RotationAngle; - speckleBeam.twistAngleStart = SpiralBeam.TwistAngleStart; - speckleBeam.twistAngleEnd = SpiralBeam.TwistAngleEnd; - - var vol = new double(); - var area = new double(); - SpiralBeam.GetReportProperty("VOLUME", ref vol); - speckleBeam.volume = vol; - SpiralBeam.GetReportProperty("AREA", ref area); - speckleBeam.area = area; - - return speckleBeam; - } - } -} \ No newline at end of file diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertWelds.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertWelds.cs deleted file mode 100644 index 1001607049..0000000000 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertWelds.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; -using Objects.Geometry; -using Objects.Structural.Geometry; -using Objects.Structural.Analysis; -using Speckle.Core.Models; -using BE = Objects.BuiltElements; -using System.Linq; -using Tekla.Structures.Model; -using Tekla.Structures.Solid; -using System.Collections; -using StructuralUtilities.PolygonMesher; -using TSG = Tekla.Structures.Geometry3d; - -namespace Objects.Converter.TeklaStructures -{ - public partial class ConverterTeklaStructures - { - public void WeldsToNative(BE.TeklaStructures.Welds welds) - { - if (welds is BE.TeklaStructures.PolygonWelds) - { - var polygonWeld = welds as BE.TeklaStructures.PolygonWelds; - PolygonWeld teklaPolyWeld = new PolygonWeld(); - SetWeldProperties(teklaPolyWeld, polygonWeld); - teklaPolyWeld.MainObject = Model.SelectModelObject(new Tekla.Structures.Identifier(polygonWeld.mainObjectId)); - teklaPolyWeld.SecondaryObject = Model.SelectModelObject(new Tekla.Structures.Identifier(polygonWeld.secondaryObjectId)); - - var polyPoints = polygonWeld.polyline.GetPoints(); - for (int i = 0; i < polyPoints.Count; i++) - { - teklaPolyWeld.Polygon.Points.Add(polyPoints[i]); - } - teklaPolyWeld.Insert(); - } - else - { - Weld teklaWeld = new Weld(); - SetWeldProperties(teklaWeld, welds); - teklaWeld.MainObject = Model.SelectModelObject(new Tekla.Structures.Identifier(welds.mainObjectId)); - teklaWeld.SecondaryObject = Model.SelectModelObject(new Tekla.Structures.Identifier(welds.secondaryObjectId)); - teklaWeld.Insert(); - } - } - public BE.TeklaStructures.Welds WeldsToSpeckle(Weld welds) - { - var speckleTeklaWeld = new BE.TeklaStructures.Welds(); - - GetWeldProperties(welds, speckleTeklaWeld); - - speckleTeklaWeld.mainObjectId = welds.MainObject.Identifier.GUID.ToString(); - speckleTeklaWeld.secondaryObjectId = welds.SecondaryObject.Identifier.GUID.ToString(); - - GetAllUserProperties(speckleTeklaWeld, welds); - - var solid = welds.GetSolid(); - speckleTeklaWeld.displayValue = new List { GetMeshFromSolid(solid) }; - return speckleTeklaWeld; - } - - public void GetWeldProperties(BaseWeld baseWeld, BE.TeklaStructures.Welds speckleWeld) - { - speckleWeld.sizeAbove = baseWeld.SizeAbove; - speckleWeld.sizeBelow = baseWeld.SizeBelow; - speckleWeld.lengthAbove = baseWeld.LengthAbove; - speckleWeld.lengthBelow = baseWeld.LengthBelow; - speckleWeld.pitchAbove = baseWeld.PitchAbove; - speckleWeld.pitchBelow = baseWeld.PitchBelow; - speckleWeld.angleAbove = baseWeld.AngleAbove; - speckleWeld.angleBelow = baseWeld.AngleBelow; - speckleWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)baseWeld.TypeAbove; - speckleWeld.typeBelow = (BE.TeklaStructures.TeklaWeldType)baseWeld.TypeBelow; - speckleWeld.intermittentType = (BE.TeklaStructures.TeklaWeldIntermittentType)baseWeld.IntermittentType; - } - public void SetWeldProperties(BaseWeld baseWeld, BE.TeklaStructures.Welds speckleWeld) - { - baseWeld.SizeAbove = speckleWeld.sizeAbove; - baseWeld.SizeBelow = speckleWeld.sizeBelow; - baseWeld.LengthAbove = speckleWeld.lengthAbove; - baseWeld.LengthBelow = speckleWeld.lengthBelow; - baseWeld.PitchAbove = speckleWeld.pitchAbove; - baseWeld.PitchBelow = speckleWeld.pitchBelow; - baseWeld.AngleAbove = speckleWeld.angleAbove; - baseWeld.AngleBelow = speckleWeld.angleBelow; - baseWeld.TypeAbove = (BaseWeld.WeldTypeEnum)speckleWeld.typeAbove; - baseWeld.TypeBelow = (BaseWeld.WeldTypeEnum)speckleWeld.typeBelow; - baseWeld.IntermittentType = (BaseWeld.WeldIntermittentTypeEnum)speckleWeld.intermittentType; - } - } - - -} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs new file mode 100644 index 0000000000..4af262e24b --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using Objects.BuiltElements.TeklaStructures; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using TSG = Tekla.Structures.Geometry3d; +using System.Collections; +using StructuralUtilities.PolygonMesher; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void BeamToNative(BE.Beam beam) + { + if (beam is TeklaBeam) + { + var teklaBeam = (TeklaBeam)beam; + switch (teklaBeam.TeklaBeamType) + { + case TeklaBeamType.Beam: + if (!(beam.baseLine is Line)) { } + Line line = (Line)beam.baseLine; + TSG.Point startPoint = new(line.start.x, line.start.y, line.start.z); + TSG.Point endPoint = new(line.end.x, line.end.y, line.end.z); + var myBeam = new Beam(startPoint, endPoint); + SetPartProperties(myBeam, teklaBeam); + if (!IsProfileValid(myBeam.Profile.ProfileString)) + { + Report.Log($"{myBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + return; + } + myBeam.Insert(); + //Model.CommitChanges(); + break; + case TeklaBeamType.PolyBeam: + Polyline polyline = (Polyline)beam.baseLine; + var polyBeam = new PolyBeam(); + ToNativeContourPlate(polyline, polyBeam.Contour); + SetPartProperties(polyBeam, teklaBeam); + if (!IsProfileValid(polyBeam.Profile.ProfileString)) + { + Report.Log($"{polyBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + return; + } + polyBeam.Insert(); + //Model.CommitChanges(); + break; + case TeklaBeamType.SpiralBeam: + Polyline polyline2 = (Polyline)beam.baseLine; + var teklaSpiralBeam = (Objects.BuiltElements.TeklaStructures.SpiralBeam)teklaBeam; + var startPt = new TSG.Point( + teklaSpiralBeam.startPoint.x, + teklaSpiralBeam.startPoint.y, + teklaSpiralBeam.startPoint.z + ); + var rotatAxisPt1 = new TSG.Point( + teklaSpiralBeam.rotationAxisPt1.x, + teklaSpiralBeam.rotationAxisPt1.y, + teklaSpiralBeam.rotationAxisPt1.z + ); + var rotatAxisPt2 = new TSG.Point( + teklaSpiralBeam.rotationAxisPt2.x, + teklaSpiralBeam.rotationAxisPt2.y, + teklaSpiralBeam.rotationAxisPt2.z + ); + var totalRise = teklaSpiralBeam.totalRise; + var rotationAngle = teklaSpiralBeam.rotationAngle; + var twistAngleStart = teklaSpiralBeam.twistAngleStart; + var twistAngleEnd = teklaSpiralBeam.twistAngleEnd; + var spiralBeam = new Tekla.Structures.Model.SpiralBeam( + startPt, + rotatAxisPt1, + rotatAxisPt2, + totalRise, + rotationAngle, + twistAngleStart, + twistAngleEnd + ); + SetPartProperties(spiralBeam, teklaBeam); + if (!IsProfileValid(spiralBeam.Profile.ProfileString)) + { + Report.Log($"{spiralBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + return; + } + spiralBeam.Insert(); + //Model.CommitChanges(); + break; + } + } + else + { + if (!(beam.baseLine is Line)) { } + Line line = (Line)beam.baseLine; + TSG.Point startPoint = new(line.start.x, line.start.y, line.start.z); + TSG.Point endPoint = new(line.end.x, line.end.y, line.end.z); + var myBeam = new Beam(startPoint, endPoint); + myBeam.Insert(); + //Model.CommitChanges(); + } + } + + public void ColumnToNative(BE.Column column) + { + //if (beam is TeklaBeam) + //{ + + // var teklaBeam = (TeklaBeam)beam; + // switch (teklaBeam.TeklaBeamType) + // { + // case TeklaBeamType.Beam: + // if (!(beam.baseLine is Line)) + // { + // } + // Line line = (Line)beam.baseLine; + // TSG.Point startPoint = new TSG.Point(line.start.x, line.start.y, line.start.z); + // TSG.Point endPoint = new TSG.Point(line.end.x, line.end.y, line.end.z); + // var myBeam = new Beam(startPoint, endPoint); + // SetPartProperties(myBeam, teklaBeam); + // if (!IsProfileValid(myBeam.Profile.ProfileString)) + // { + // Report.Log($"{myBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + // return; + // } + // myBeam.Insert(); + // //Model.CommitChanges(); + // break; + // case TeklaBeamType.PolyBeam: + // Polyline polyline = (Polyline)beam.baseLine; + // var polyBeam = new PolyBeam(); + // ToNativeContourPlate(polyline, polyBeam.Contour); + // SetPartProperties(polyBeam, teklaBeam); + // if (!IsProfileValid(polyBeam.Profile.ProfileString)) + // { + // Report.Log($"{polyBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + // return; + // } + // polyBeam.Insert(); + // //Model.CommitChanges(); + // break; + // case TeklaBeamType.SpiralBeam: + // Polyline polyline2 = (Polyline)beam.baseLine; + // var teklaSpiralBeam = (Objects.BuiltElements.TeklaStructures.SpiralBeam)teklaBeam; + // var startPt = new TSG.Point(teklaSpiralBeam.startPoint.x, teklaSpiralBeam.startPoint.y, teklaSpiralBeam.startPoint.z); + // var rotatAxisPt1 = new TSG.Point(teklaSpiralBeam.rotationAxisPt1.x, teklaSpiralBeam.rotationAxisPt1.y, teklaSpiralBeam.rotationAxisPt1.z); + // var rotatAxisPt2 = new TSG.Point(teklaSpiralBeam.rotationAxisPt2.x, teklaSpiralBeam.rotationAxisPt2.y, teklaSpiralBeam.rotationAxisPt2.z); + // var totalRise = teklaSpiralBeam.totalRise; + // var rotationAngle = teklaSpiralBeam.rotationAngle; + // var twistAngleStart = teklaSpiralBeam.twistAngleStart; + // var twistAngleEnd = teklaSpiralBeam.twistAngleEnd; + // var spiralBeam = new Tekla.Structures.Model.SpiralBeam(startPt, rotatAxisPt1, rotatAxisPt2, totalRise, rotationAngle, twistAngleStart, twistAngleEnd); + // SetPartProperties(spiralBeam, teklaBeam); + // if (!IsProfileValid(spiralBeam.Profile.ProfileString)) + // { + // Report.Log($"{spiralBeam.Profile.ProfileString} not in model catalog. Cannot place object {beam.id}"); + // return; + // } + // spiralBeam.Insert(); + // //Model.CommitChanges(); + // break; + // } + //} + //else + //{ + if (!(column.baseLine is Line)) { } + Line line = (Line)column.baseLine; + TSG.Point startPoint = new(line.start.x, line.start.y, line.start.z); + TSG.Point endPoint = new(line.end.x, line.end.y, line.end.z); + var myBeam = new Beam(startPoint, endPoint); + myBeam.Insert(); + //Model.CommitChanges(); + //} + } + + public void SetPartProperties(Part part, TeklaBeam teklaBeam) + { + part.Material.MaterialString = teklaBeam.material?.name; + part.Profile.ProfileString = teklaBeam.profile?.name; + part.Class = teklaBeam.classNumber; + part.Finish = teklaBeam.finish; + part.Name = teklaBeam.name; + part.Position = SetPositioning(teklaBeam.position); + } + + public TeklaBeam BeamToSpeckle(Tekla.Structures.Model.Beam beam) + { + var speckleBeam = new TeklaBeam(); + //TO DO: Support for curved beams goes in here as well + twin beams + + var endPoint = beam.EndPoint; + var startPoint = beam.StartPoint; + var units = GetUnitsFromModel(); + + Point speckleStartPoint = new(startPoint.X, startPoint.Y, startPoint.Z, units); + Point speckleEndPoint = new(endPoint.X, endPoint.Y, endPoint.Z, units); + speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); + speckleBeam.baseLine.length = Math.Sqrt( + Math.Pow((startPoint.X - endPoint.X), 2) + + Math.Pow((startPoint.Y - endPoint.Y), 2) + + Math.Pow((startPoint.Z - endPoint.Z), 2) + ); + speckleBeam.profile = GetBeamProfile(beam.Profile.ProfileString); + speckleBeam.material = GetMaterial(beam.Material.MaterialString); + var beamCS = beam.GetCoordinateSystem(); + speckleBeam.position = GetPositioning(beam.Position); + speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); + speckleBeam.finish = beam.Finish; + speckleBeam.classNumber = beam.Class; + speckleBeam.name = beam.Name; + speckleBeam.applicationId = beam.Identifier.GUID.ToString(); + speckleBeam.TeklaBeamType = TeklaBeamType.Beam; + var vol = new double(); + var area = new double(); + beam.GetReportProperty("VOLUME", ref vol); + speckleBeam.volume = vol; + beam.GetReportProperty("AREA", ref area); + speckleBeam.area = area; + + var rebars = beam.GetReinforcements(); + if (rebars != null) + { + foreach (var rebar in rebars) + { + if (rebar is RebarGroup) + { + speckleBeam.rebars = RebarGroupToSpeckle((RebarGroup)rebar); + } + } + } + + GetAllUserProperties(speckleBeam, beam); + + var solid = beam.GetSolid(); + speckleBeam.displayValue = new List { GetMeshFromSolid(solid) }; + return speckleBeam; + } + + /// + /// Create beam without display mesh for boolean parts + /// + /// + /// + public TeklaBeam AntiBeamToSpeckle(Tekla.Structures.Model.Beam beam) + { + var speckleBeam = new TeklaBeam(); + //TO DO: Support for curved beams goes in here as well + twin beams + + var endPoint = beam.EndPoint; + var startPoint = beam.StartPoint; + var units = GetUnitsFromModel(); + + Point speckleStartPoint = new(startPoint.X, startPoint.Y, startPoint.Z, units); + Point speckleEndPoint = new(endPoint.X, endPoint.Y, endPoint.Z, units); + speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); + + speckleBeam.profile = GetBeamProfile(beam.Profile.ProfileString); + speckleBeam.material = GetMaterial(beam.Material.MaterialString); + var beamCS = beam.GetCoordinateSystem(); + speckleBeam.position = GetPositioning(beam.Position); + speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); + speckleBeam.classNumber = beam.Class; + speckleBeam.name = beam.Name; + speckleBeam.TeklaBeamType = TeklaBeamType.Beam; + speckleBeam.applicationId = beam.Identifier.GUID.ToString(); + var vol = new double(); + var area = new double(); + beam.GetReportProperty("VOLUME", ref vol); + speckleBeam.volume = vol; + beam.GetReportProperty("AREA", ref area); + speckleBeam.area = area; + + speckleBeam["units"] = units; + + return speckleBeam; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBentPlate.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBentPlate.cs new file mode 100644 index 0000000000..0f63ae8c20 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBentPlate.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ConverterTeklaStructuresShared.Partial_Classes; + +class ConvertBentPlate { } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBolts.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBolts.cs new file mode 100644 index 0000000000..19bc7d6106 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBolts.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using TSG = Tekla.Structures.Geometry3d; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void BoltsToNative(BE.TeklaStructures.Bolts bolts) + { + switch (bolts) + { + case BE.TeklaStructures.BoltsArray ba: + { + BoltArray teklaBoltArray = new(); + SetBoltGroupProperties(teklaBoltArray, ba); + for (int i = 0; i < ba.xDistance.Count; i++) + { + teklaBoltArray.AddBoltDistX(ba.xDistance[i]); + } + for (int i = 0; i < ba.yDistance.Count; i++) + { + teklaBoltArray.AddBoltDistY(ba.yDistance[i]); + } + teklaBoltArray.Insert(); + return; + } + case BE.TeklaStructures.BoltsXY bx: + { + BoltXYList teklaBoltXY = new(); + SetBoltGroupProperties(teklaBoltXY, bx); + for (int i = 0; i < bx.xPosition.Count; i++) + { + teklaBoltXY.AddBoltDistX(bx.xPosition[i]); + } + for (int i = 0; i < bx.yPosition.Count; i++) + { + teklaBoltXY.AddBoltDistY(bx.yPosition[i]); + } + teklaBoltXY.Insert(); + return; + } + case BE.TeklaStructures.BoltsCircle bc: + { + BoltCircle teklaBoltCircle = new(); + SetBoltGroupProperties(teklaBoltCircle, bc); + teklaBoltCircle.NumberOfBolts = bc.boltCount; + teklaBoltCircle.Diameter = bc.diameter; + teklaBoltCircle.Insert(); + return; + } + } + } + + public BE.TeklaStructures.Bolts BoltsToSpeckle(BoltGroup Bolts) + { + BE.TeklaStructures.Bolts speckleTeklaBolt; + var units = GetUnitsFromModel(); + + // Add specific Tekla necessary properties for the different types of bolts possible + switch (Bolts) + { + case BoltArray ba: + var speckleBoltArray = new BE.TeklaStructures.BoltsArray(); + + speckleBoltArray.xDistance = new List(); + speckleBoltArray.yDistance = new List(); + for (int i = 0; i < ba.GetBoltDistXCount(); i++) + { + speckleBoltArray.xDistance.Add(ba.GetBoltDistX(i)); + } + for (int i = 0; i < ba.GetBoltDistYCount(); i++) + { + speckleBoltArray.yDistance.Add(ba.GetBoltDistY(i)); + } + speckleTeklaBolt = speckleBoltArray; + break; + case BoltXYList bxy: + var speckleBoltXY = new BE.TeklaStructures.BoltsXY(); + speckleBoltXY.xPosition = new List(); + speckleBoltXY.yPosition = new List(); + for (int i = 0; i < bxy.GetBoltDistXCount(); i++) + { + speckleBoltXY.xPosition.Add(bxy.GetBoltDistX(i)); + } + for (int i = 0; i < bxy.GetBoltDistYCount(); i++) + { + speckleBoltXY.yPosition.Add(bxy.GetBoltDistY(i)); + } + speckleTeklaBolt = speckleBoltXY; + break; + case BoltCircle bc: + var speckleBoltCircle = new BE.TeklaStructures.BoltsCircle(); + speckleBoltCircle.boltCount = (int)bc.NumberOfBolts; + speckleBoltCircle.diameter = bc.Diameter; + speckleTeklaBolt = speckleBoltCircle; + break; + default: + speckleTeklaBolt = new BE.TeklaStructures.Bolts(); + break; + } + + //Set common properties + speckleTeklaBolt.boltSize = Bolts.BoltSize; + speckleTeklaBolt.boltStandard = Bolts.BoltStandard; + speckleTeklaBolt.cutLength = Bolts.CutLength; + speckleTeklaBolt.length = Bolts.Length; + speckleTeklaBolt.position = GetPositioning(Bolts.Position); + + // global bolt coordinates + speckleTeklaBolt.coordinates = Bolts.BoltPositions + .Cast() + .Select(p => new Point(p.X, p.Y, p.Z, units)) + .ToList(); + + // Add bolted parts necessary for insertion into Tekla + speckleTeklaBolt.boltedPartsIds.Add(Bolts.PartToBeBolted.Identifier.GUID.ToString()); + speckleTeklaBolt.boltedPartsIds.Add(Bolts.PartToBoltTo.Identifier.GUID.ToString()); + if (Bolts.OtherPartsToBolt.Count > 0) + { + foreach (Part otherPart in Bolts.OtherPartsToBolt.Cast()) + { + speckleTeklaBolt.boltedPartsIds.Add(otherPart.Identifier.GUID.ToString()); + } + } + GetAllUserProperties(speckleTeklaBolt, Bolts); + + var solid = Bolts.GetSolid(); + speckleTeklaBolt.displayValue = new List { GetMeshFromSolid(solid) }; + + return speckleTeklaBolt; + } + + public void SetBoltGroupProperties(BoltGroup boltGroup, BE.TeklaStructures.Bolts bolts) + { + boltGroup.PartToBeBolted = + Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[0])) as Part; + boltGroup.PartToBoltTo = Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[1])) as Part; + if (bolts.boltedPartsIds.Count > 2) + { + for (int i = 2; i < bolts.boltedPartsIds.Count; i++) + { + boltGroup.AddOtherPartToBolt( + Model.SelectModelObject(new Tekla.Structures.Identifier(bolts.boltedPartsIds[i])) as Part + ); + } + } + boltGroup.FirstPosition = new TSG.Point(bolts.firstPosition.x, bolts.firstPosition.y, bolts.firstPosition.z); + boltGroup.SecondPosition = new TSG.Point(bolts.secondPosition.x, bolts.secondPosition.y, bolts.secondPosition.z); + boltGroup.BoltSize = bolts.boltSize; + boltGroup.Tolerance = bolts.tolerance; + boltGroup.BoltStandard = bolts.boltStandard; + boltGroup.CutLength = bolts.cutLength; + boltGroup.Position = SetPositioning(bolts.position); + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBooleanPart.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBooleanPart.cs new file mode 100644 index 0000000000..0f90085ff5 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBooleanPart.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using Objects.BuiltElements.TeklaStructures; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void BooleanPartToNative(BE.Opening opening) + { + BooleanPart booleanPart = new(); + switch (opening) + { + case TeklaContourOpening contourOpening: + + { + var contourPlate = new ContourPlate(); + contourPlate.Profile.ProfileString = contourOpening.cuttingPlate.profile.name; + contourPlate.Material.MaterialString = contourOpening.cuttingPlate.material.name; + contourPlate.Class = BooleanPart.BooleanOperativeClassName; + contourPlate.Position = SetPositioning(contourOpening.cuttingPlate.position); + for (int i = 0; i < contourOpening.cuttingPlate.contour.Count; i++) + { + TeklaContourPoint cp = contourOpening.cuttingPlate.contour[i]; + contourPlate.AddContourPoint(ToTeklaContourPoint(cp)); + } + contourPlate.Insert(); + booleanPart.SetOperativePart(contourPlate); + booleanPart.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(contourOpening.openingHostId)); + booleanPart.Insert(); + contourPlate.Delete(); + } + break; + case TeklaBeamOpening beamOpening: + + { + var beam = new Beam(); + var baseLine = beamOpening.cuttingBeam.baseLine as Line; + beam.StartPoint = new Tekla.Structures.Geometry3d.Point(baseLine.start.x, baseLine.start.y, baseLine.start.z); + beam.EndPoint = new Tekla.Structures.Geometry3d.Point(baseLine.start.x, baseLine.start.y, baseLine.start.z); + + beam.Profile.ProfileString = beamOpening.cuttingBeam.profile.name; + beam.Material.MaterialString = beamOpening.cuttingBeam.material.name; + beam.Class = BooleanPart.BooleanOperativeClassName; + beam.Position = SetPositioning(beamOpening.cuttingBeam.position); + beam.Insert(); + booleanPart.SetOperativePart(beam); + booleanPart.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(beamOpening.openingHostId)); + booleanPart.Insert(); + beam.Delete(); + } + break; + } + } + + public TeklaOpening BooleanPartToSpeckle(Tekla.Structures.Model.BooleanPart booleanPart) + { + TeklaOpening teklaOpening; + if (booleanPart.OperativePart is ContourPlate) + { + var contourOpening = new TeklaContourOpening(); + contourOpening.applicationId = booleanPart.Identifier.GUID.ToString(); + contourOpening.openingHostId = booleanPart.Father.Identifier.GUID.ToString(); + contourOpening.cuttingPlate = AntiContourPlateToSpeckle(booleanPart.OperativePart as ContourPlate); + contourOpening.openingType = TeklaOpeningTypeEnum.contour; + contourOpening.outline = ToSpecklePolycurve((booleanPart.OperativePart as ContourPlate).GetContourPolycurve()); + contourOpening.thickness = double.Parse( + new string( + (booleanPart.OperativePart as ContourPlate).Profile.ProfileString.Where(c => char.IsDigit(c)).ToArray() + ) + ); + teklaOpening = contourOpening; + } + else + { + var beamOpening = new TeklaBeamOpening(); + beamOpening.applicationId = booleanPart.Identifier.GUID.ToString(); + beamOpening.openingHostId = booleanPart.Father.Identifier.GUID.ToString(); + beamOpening.openingType = TeklaOpeningTypeEnum.beam; + beamOpening.cuttingBeam = AntiBeamToSpeckle(booleanPart.OperativePart as Beam); + teklaOpening = beamOpening; + } + return teklaOpening; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertContourPlate.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertContourPlate.cs new file mode 100644 index 0000000000..854e5c3272 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertContourPlate.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using Objects.BuiltElements.TeklaStructures; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void ContourPlateToNative(BE.Area area) + { + if (!(area.outline is Polyline)) { } + var ContourPlate = new ContourPlate(); + if (area is TeklaContourPlate) + { + //var countourPoints = GetContourPointsFromPolyLine((Polyline)area.outline); + var contour = (TeklaContourPlate)area; + + ContourPlate.Profile.ProfileString = contour.profile.name; + //ContourPlate.Contour.ContourPoints = countourPoints; + ContourPlate.Material.MaterialString = contour.material?.name; + foreach (var cp in contour.contour) + { + ContourPlate.AddContourPoint(ToTeklaContourPoint(cp)); + } + SetPartProperties(ContourPlate, contour); + } + ContourPlate.Insert(); + //Model.CommitChanges(); + } + + public TeklaContourPlate ContourPlateToSpeckle(Tekla.Structures.Model.ContourPlate plate) + { + var specklePlate = new TeklaContourPlate(); + specklePlate.name = plate.Name; + specklePlate.profile = GetContourPlateProfile(plate.Profile.ProfileString); + specklePlate.material = GetMaterial(plate.Material.MaterialString); + specklePlate.finish = plate.Finish; + specklePlate.classNumber = plate.Class; + specklePlate.position = GetPositioning(plate.Position); + + //Polygon teklaPolygon = null; + + // Get general outline for other programs + //plate.Contour.CalculatePolygon(out teklaPolygon); + //if (teklaPolygon != null) + // specklePlate.outline = ToSpecklePolyline(teklaPolygon); + + // Getting polycurve now works with new nuget packages + var teklaPolycurve = plate.GetContourPolycurve(); + specklePlate.outline = ToSpecklePolycurve(teklaPolycurve); + + // Get contour for ToNative Tekla conversion + specklePlate.contour = new List(); + var cPts = plate.Contour.ContourPoints.Cast(); + foreach (ContourPoint pt in cPts) + { + specklePlate.contour.Add(ToSpeckleContourPoint(pt)); + } + + GetAllUserProperties(specklePlate, plate); + + var solid = plate.GetSolid(); + specklePlate.displayValue = new List { GetMeshFromSolid(solid) }; + var rebars = plate.GetReinforcements(); + if (rebars != null) + { + foreach (var rebar in rebars) + { + if (rebar is RebarGroup) + { + specklePlate.rebars = RebarGroupToSpeckle((RebarGroup)rebar); + } + } + } + return specklePlate; + } + + /// + /// Create a contour plate without a display mesh for boolean parts + /// + /// + /// + public TeklaContourPlate AntiContourPlateToSpeckle(Tekla.Structures.Model.ContourPlate plate) + { + var specklePlate = new TeklaContourPlate(); + specklePlate.name = plate.Name; + specklePlate.profile = GetContourPlateProfile(plate.Profile.ProfileString); + specklePlate.material = GetMaterial(plate.Material.MaterialString); + + specklePlate.classNumber = plate.Class; + specklePlate.position = GetPositioning(plate.Position); + + Polygon teklaPolygon = null; + plate.Contour.CalculatePolygon(out teklaPolygon); + if (teklaPolygon != null) + { + specklePlate.outline = ToSpecklePolyline(teklaPolygon); + } + + // Get contour for ToNative Tekla conversion + specklePlate.contour = new List(); + var cPts = plate.Contour.ContourPoints.Cast(); + foreach (ContourPoint pt in cPts) + { + specklePlate.contour.Add(ToSpeckleContourPoint(pt)); + } + + var units = GetUnitsFromModel(); + specklePlate.applicationId = plate.Identifier.GUID.ToString(); + specklePlate["units"] = units; + return specklePlate; + } + + public void SetPartProperties(Part part, TeklaContourPlate teklaPlate) + { + part.Material.MaterialString = teklaPlate.material?.name; + part.Profile.ProfileString = teklaPlate.profile.name; + part.Class = teklaPlate.classNumber; + part.Finish = teklaPlate.finish; + part.Name = teklaPlate.name; + part.Position = SetPositioning(teklaPlate.position); + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertDirectShapeMesh.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertDirectShapeMesh.cs new file mode 100644 index 0000000000..728edb183c --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertDirectShapeMesh.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using GE = Objects.Geometry; +using GES = Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using Objects.BuiltElements.TeklaStructures; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using Tekla.Structures.Model.UI; +using Tekla.Structures.Geometry3d; +using Tekla.Structures.Catalogs; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void MeshToNative(Base @object, List displayValues) + { + int incr = 0; + foreach (var mesh in displayValues) + { + FacetedBrep facetedBrep = CreateFacetedBrep(mesh); + + // Add shape to catalog + // Each shape in catalog needs to have a unique name + string objectName = GetShapeName(@object); + string shapeName = "Speckle_" + objectName + (incr > 0 ? "_" + incr.ToString() : ""); + var shapeItem = new ShapeItem + { + Name = shapeName, + ShapeFacetedBrep = facetedBrep, + UpAxis = ShapeUpAxis.Z_Axis + }; + // remove possibly pre-existing shape with same name and then insert a Speckle object shape + // with that name into the catalog + shapeItem.Delete(); + bool result = false; + try + { + result = shapeItem.Insert(); + // Fails if two shapes exist with different names but same geometry fingerprint + } + catch (Exception ex) { } + + if (!result) + { + // Find pre-existing shape in catalog with same fingerprint + var matchingShape = CheckFingerprint(shapeItem); + if (matchingShape != null) + { + shapeName = matchingShape.Name; + result = true; + } + } + + // Insert object in model + if (result) + { + var brep = new Brep(); + brep.StartPoint = new Tekla.Structures.Geometry3d.Point(0, 0, 0); + brep.EndPoint = new Tekla.Structures.Geometry3d.Point(1000, 0, 0); + brep.Profile.ProfileString = shapeName; + brep.Material.MaterialString = "TS_Undefined"; + brep.Position.Depth = Position.DepthEnum.MIDDLE; + brep.Position.Plane = Position.PlaneEnum.MIDDLE; + brep.Position.Rotation = Position.RotationEnum.TOP; + brep.Insert(); + } + + incr++; + } + + //var vertex = new[] + // { + // new Vector(0.0, 0.0, 0.0), // 0 + // new Vector(300.0, 0.0, 0.0), // 1 + // new Vector(300.0, 700.0, 0.0), // 2 + // new Vector(0.0, 700.0, 0.0), // 3 + // new Vector(300.0, 700.0, 0.0), // 4 + // new Vector(300.0, 700.0, 2000.0), // 5 + // new Vector(0.0, 700.0, 2000.0), // 6 + // new Vector(100.0, 100.0, 0.0), // 7 + // new Vector(200.0, 100.0, 0.0), // 8 + // new Vector(200.0, 200.0, 0.0), // 9 + // new Vector(100.0, 200.0, 0.0) // 10 + // }; + //var outerWires = new[] + //{ + //foreach + // }; + //var innerWires = new Dictionary + // { + + // }; + + //var brep = new FacetedBrep(vertex, outerWires, innerWires); + + //var shapeItem = new ShapeItem + //{ + // Name = "Test", + // ShapeFacetedBrep = brep, + // UpAxis = ShapeUpAxis.Z_Axis + //}; + //shapeItem.Insert(); + //Model.CommitChanges(); + } + + public FacetedBrep CreateFacetedBrep(GE.Mesh mesh) + { + var faces = mesh.faces; + List> faceList = new() { }; + faceList = faces + .Select((x, i) => new { Index = i, Value = x }) + .GroupBy(x => x.Index / 4) + .Select(x => x.Select(v => v.Value).ToList()) + .ToList(); + var vertices = mesh.vertices; + List> verticesList = new() { }; + verticesList = vertices + .Select((x, i) => new { Index = i, Value = x }) + .GroupBy(x => x.Index / 3) + .Select(x => x.Select(v => v.Value).ToList()) + .ToList(); + List vertexs = new(); + List outerWires = new(); + var innerLoop = new Dictionary { }; + foreach (var vertex in verticesList) + { + var teklaVectorVertex = new Vector(vertex[0], vertex[1], vertex[2]); + vertexs.Add(teklaVectorVertex); + } + foreach (var face in faceList) + { + // Tekla wants the face loops in reverse + var teklaFaceLoop = new[] { face[3], face[2], face[1] }; + outerWires.Add(teklaFaceLoop); + } + var brep = new FacetedBrep(vertexs.ToArray(), outerWires.ToArray(), innerLoop); + return brep; + } + + public string GetShapeName(Base @object) + { + string name = ""; + + // Take application id + if (string.IsNullOrEmpty(name)) + { + name = @object.applicationId; + } + + // If still empty then do Speckle id but can cause failure since changes with every commit + if (string.IsNullOrEmpty(name)) + { + name = @object.id; + } + + return name; + } + + public ShapeItem CheckFingerprint(ShapeItem si) + { + CatalogHandler catalogHandler = new(); + ShapeItemEnumerator sie = catalogHandler.GetShapeItems(); + while (sie.MoveNext()) + { + ShapeItem siItem = sie.Current; + if (siItem.Fingerprint == Polymesh.Fingerprint(si.ShapeFacetedBrep)) + { + return siItem; + } + } + return null; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertFitting.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertFitting.cs new file mode 100644 index 0000000000..da27c841f1 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertFitting.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using TSG = Tekla.Structures.Geometry3d; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void FittingToNative(Objects.Geometry.Plane fitting) + { + if (fitting is BE.TeklaStructures.Fitting) + { + var fit = fitting as BE.TeklaStructures.Fitting; + Fitting teklaFitting = new(); + teklaFitting.Father = Model.SelectModelObject(new Tekla.Structures.Identifier(fit.hostID)); + teklaFitting.Plane = new Tekla.Structures.Model.Plane(); + teklaFitting.Plane.Origin = new TSG.Point(fit.origin.x, fit.origin.y, fit.origin.z); + teklaFitting.Plane.AxisX = new TSG.Vector(fit.xdir.x, fit.xdir.y, fit.xdir.z); + teklaFitting.Plane.AxisY = new TSG.Vector(fit.ydir.x, fit.ydir.y, fit.ydir.z); + teklaFitting.Insert(); + } + } + + public BE.TeklaStructures.Fitting FittingsToSpeckle(Fitting fitting) + { + var speckleFitting = new BE.TeklaStructures.Fitting(); + + var units = GetUnitsFromModel(); + speckleFitting.origin = new Point(fitting.Plane.Origin.X, fitting.Plane.Origin.Y, fitting.Plane.Origin.Z, units); + speckleFitting.xdir = new Vector(fitting.Plane.AxisX.X, fitting.Plane.AxisX.Y, fitting.Plane.AxisX.Z, units); + speckleFitting.ydir = new Vector(fitting.Plane.AxisY.X, fitting.Plane.AxisY.Y, fitting.Plane.AxisY.Z, units); + var normal = fitting.Plane.AxisX.Cross(fitting.Plane.AxisY).GetNormal(); + speckleFitting.normal = new Vector(normal.X, normal.Y, normal.Z, units); + speckleFitting.hostID = fitting.Father.Identifier.GUID.ToString(); + speckleFitting.units = units; + speckleFitting.applicationId = fitting.Identifier.GUID.ToString(); + + return speckleFitting; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertLoftedPlates.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertLoftedPlates.cs new file mode 100644 index 0000000000..534f2abc60 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertLoftedPlates.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ConverterTeklaStructuresShared.Partial_Classes; + +class ConvertLoftedPlates { } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertModel.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertModel.cs new file mode 100644 index 0000000000..29cf557b77 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertModel.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ConverterTeklaStructuresShared.Partial_Classes; + +class ConvertModel { } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPoint.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPoint.cs similarity index 81% rename from Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPoint.cs rename to Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPoint.cs index 4533572686..553c9191ce 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/Partial Classes/ConvertPoint.cs +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPoint.cs @@ -4,7 +4,5 @@ namespace ConverterTeklaStructuresShared.Partial_Classes { - class ConvertPoint - { - } + class ConvertPoint { } } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolyBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolyBeam.cs new file mode 100644 index 0000000000..d77705e715 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolyBeam.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using Objects.BuiltElements.TeklaStructures; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public TeklaBeam PolyBeamToSpeckle(PolyBeam PolyBeam) + { + var speckleBeam = new TeklaBeam(); + var units = GetUnitsFromModel(); + var centerPolyCurve = PolyBeam.GetCenterLine(false); + //var centerPolycurve = PolyBeam.GetCenterLinePolycurve(); + var pointList = new List { }; + var polyLine = new Polycurve(); + foreach (Tekla.Structures.Geometry3d.Point point in centerPolyCurve) + { + pointList.Add(point.X); + pointList.Add(point.Y); + pointList.Add(point.Z); + } + speckleBeam.profile = GetBeamProfile(PolyBeam.Profile.ProfileString); + speckleBeam.material = GetMaterial(PolyBeam.Material.MaterialString); + speckleBeam.finish = PolyBeam.Finish; + speckleBeam.classNumber = PolyBeam.Class; + var beamCS = PolyBeam.GetCoordinateSystem(); + speckleBeam.position = GetPositioning(PolyBeam.Position); + speckleBeam.alignmentVector = new Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); + speckleBeam.name = PolyBeam.Name; + speckleBeam.baseLine = new Polyline(pointList, units); + speckleBeam.TeklaBeamType = TeklaBeamType.PolyBeam; + GetAllUserProperties(speckleBeam, PolyBeam); + var solid = PolyBeam.GetSolid(); + speckleBeam.displayValue = new List { GetMeshFromSolid(solid) }; + var vol = new double(); + var area = new double(); + PolyBeam.GetReportProperty("VOLUME", ref vol); + speckleBeam.volume = vol; + PolyBeam.GetReportProperty("AREA", ref area); + speckleBeam.area = area; + + return speckleBeam; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolygonWelds.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolygonWelds.cs new file mode 100644 index 0000000000..5bad15bf44 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertPolygonWelds.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using TSG = Tekla.Structures.Geometry3d; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public BE.TeklaStructures.PolygonWelds PoylgonWeldsToSpeckle(PolygonWeld welds) + { + var speckleTeklaPolygonWeld = new BE.TeklaStructures.PolygonWelds(); + + speckleTeklaPolygonWeld.sizeAbove = welds.SizeAbove; + speckleTeklaPolygonWeld.sizeBelow = welds.SizeBelow; + speckleTeklaPolygonWeld.lengthAbove = welds.LengthAbove; + speckleTeklaPolygonWeld.lengthBelow = welds.LengthBelow; + speckleTeklaPolygonWeld.pitchAbove = welds.PitchAbove; + speckleTeklaPolygonWeld.pitchBelow = welds.PitchBelow; + speckleTeklaPolygonWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)welds.TypeAbove; + speckleTeklaPolygonWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)welds.TypeBelow; + speckleTeklaPolygonWeld.intermittentType = (BE.TeklaStructures.TeklaWeldIntermittentType)welds.IntermittentType; + + speckleTeklaPolygonWeld.polyline = ToSpecklePolyline(welds.Polygon); + + GetAllUserProperties(speckleTeklaPolygonWeld, welds); + + var solid = welds.GetSolid(); + speckleTeklaPolygonWeld.displayValue = new List { GetMeshFromSolid(solid) }; + return speckleTeklaPolygonWeld; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertRebar.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertRebar.cs new file mode 100644 index 0000000000..276bfc118e --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertRebar.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using Objects.BuiltElements.TeklaStructures; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using TSG = Tekla.Structures.Geometry3d; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using Objects.Structural.Materials; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public TeklaRebar RebarGroupToSpeckle(RebarGroup rebarGroup) + { + var Rebar = new TeklaRebar(); + Rebar.displayValue = new List { GetMeshFromSolid(rebarGroup.GetSolid()) }; + foreach (Polygon polygon in rebarGroup.Polygons) + { + var polyline = ToSpecklePolyline(polygon); + Rebar.curves.Add(polyline); + } + Rebar.units = GetUnitsFromModel(); + Rebar.name = rebarGroup.Name; + Rebar.material = new Structural.Materials.StructuralMaterial(); + Rebar.material.name = rebarGroup.Grade; + Rebar.material.grade = rebarGroup.Grade; + Rebar.size = rebarGroup.Size; + Rebar.classNumber = rebarGroup.Class; + Rebar.startHook = new Hook(); + Rebar.startHook.angle = rebarGroup.StartHook.Angle; + Rebar.startHook.length = rebarGroup.StartHook.Length; + Rebar.startHook.radius = rebarGroup.StartHook.Radius; + switch (rebarGroup.StartHook.Shape) + { + case RebarHookData.RebarHookShapeEnum.NO_HOOK: + Rebar.startHook.shape = shape.NO_HOOK; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_90_DEGREES: + Rebar.startHook.shape = shape.HOOK_90_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_135_DEGREES: + Rebar.startHook.shape = shape.HOOK_135_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_180_DEGREES: + Rebar.startHook.shape = shape.HOOK_180_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.CUSTOM_HOOK: + Rebar.startHook.shape = shape.CUSTOM_HOOK; + break; + } + Rebar.endHook = new Hook(); + Rebar.endHook.angle = rebarGroup.EndHook.Angle; + Rebar.endHook.length = rebarGroup.EndHook.Length; + Rebar.endHook.radius = rebarGroup.EndHook.Radius; + switch (rebarGroup.EndHook.Shape) + { + case RebarHookData.RebarHookShapeEnum.NO_HOOK: + Rebar.endHook.shape = shape.NO_HOOK; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_90_DEGREES: + Rebar.endHook.shape = shape.HOOK_90_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_135_DEGREES: + Rebar.endHook.shape = shape.HOOK_135_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.HOOK_180_DEGREES: + Rebar.endHook.shape = shape.HOOK_180_DEGREES; + break; + case RebarHookData.RebarHookShapeEnum.CUSTOM_HOOK: + Rebar.endHook.shape = shape.CUSTOM_HOOK; + break; + } + return Rebar; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertSpiralBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertSpiralBeam.cs new file mode 100644 index 0000000000..10cc8a4933 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertSpiralBeam.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using Tekla.Structures.Geometry3d; +using Objects.BuiltElements.TeklaStructures; +using SpiralBeam = Objects.BuiltElements.TeklaStructures.SpiralBeam; +using Point = Objects.Geometry.Point; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public SpiralBeam SpiralBeamToSpeckle(Tekla.Structures.Model.SpiralBeam SpiralBeam) + { + var units = GetUnitsFromModel(); + var speckleBeam = new SpiralBeam(); + var curveLine = SpiralBeam.GetCenterLine(false); + var pointList = new List { }; + foreach (Tekla.Structures.Geometry3d.Point point in curveLine) + { + pointList.Add(point.X); + pointList.Add(point.Y); + pointList.Add(point.Z); + } + + speckleBeam.baseLine = new Polyline(pointList, units); + + speckleBeam.profile = GetBeamProfile(SpiralBeam.Profile.ProfileString); + speckleBeam.material = GetMaterial(SpiralBeam.Material.MaterialString); + speckleBeam.finish = SpiralBeam.Finish; + speckleBeam.classNumber = SpiralBeam.Class; + speckleBeam.name = SpiralBeam.Name; + var beamCS = SpiralBeam.GetCoordinateSystem(); + speckleBeam.position = GetPositioning(SpiralBeam.Position); + speckleBeam.alignmentVector = new Objects.Geometry.Vector(beamCS.AxisY.X, beamCS.AxisY.Y, beamCS.AxisY.Z, units); + GetAllUserProperties(speckleBeam, SpiralBeam); + speckleBeam.TeklaBeamType = TeklaBeamType.SpiralBeam; + //var refLine = SpiralBeam.GetReferenceLine(false); + var solid = SpiralBeam.GetSolid(); + speckleBeam.displayValue = new List { GetMeshFromSolid(solid) }; + + speckleBeam.startPoint = new Point(SpiralBeam.StartPoint.X, SpiralBeam.StartPoint.Y, SpiralBeam.StartPoint.Z); + speckleBeam.rotationAxisPt1 = new Point( + SpiralBeam.RotationAxisBasePoint.X, + SpiralBeam.RotationAxisBasePoint.Y, + SpiralBeam.RotationAxisBasePoint.Z + ); + speckleBeam.rotationAxisPt2 = new Point( + SpiralBeam.RotationAxisUpPoint.X, + SpiralBeam.RotationAxisUpPoint.Y, + SpiralBeam.RotationAxisUpPoint.Z + ); + speckleBeam.totalRise = SpiralBeam.TotalRise; + speckleBeam.rotationAngle = SpiralBeam.RotationAngle; + speckleBeam.twistAngleStart = SpiralBeam.TwistAngleStart; + speckleBeam.twistAngleEnd = SpiralBeam.TwistAngleEnd; + + var vol = new double(); + var area = new double(); + SpiralBeam.GetReportProperty("VOLUME", ref vol); + speckleBeam.volume = vol; + SpiralBeam.GetReportProperty("AREA", ref area); + speckleBeam.area = area; + + return speckleBeam; + } +} diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertWelds.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertWelds.cs new file mode 100644 index 0000000000..adbe3de4d9 --- /dev/null +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertWelds.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Structural.Geometry; +using Objects.Structural.Analysis; +using Speckle.Core.Models; +using BE = Objects.BuiltElements; +using System.Linq; +using Tekla.Structures.Model; +using Tekla.Structures.Solid; +using System.Collections; +using StructuralUtilities.PolygonMesher; +using TSG = Tekla.Structures.Geometry3d; + +namespace Objects.Converter.TeklaStructures; + +public partial class ConverterTeklaStructures +{ + public void WeldsToNative(BE.TeklaStructures.Welds welds) + { + if (welds is BE.TeklaStructures.PolygonWelds) + { + var polygonWeld = welds as BE.TeklaStructures.PolygonWelds; + PolygonWeld teklaPolyWeld = new(); + SetWeldProperties(teklaPolyWeld, polygonWeld); + teklaPolyWeld.MainObject = Model.SelectModelObject(new Tekla.Structures.Identifier(polygonWeld.mainObjectId)); + teklaPolyWeld.SecondaryObject = Model.SelectModelObject( + new Tekla.Structures.Identifier(polygonWeld.secondaryObjectId) + ); + + var polyPoints = polygonWeld.polyline.GetPoints(); + for (int i = 0; i < polyPoints.Count; i++) + { + teklaPolyWeld.Polygon.Points.Add(polyPoints[i]); + } + teklaPolyWeld.Insert(); + } + else + { + Weld teklaWeld = new(); + SetWeldProperties(teklaWeld, welds); + teklaWeld.MainObject = Model.SelectModelObject(new Tekla.Structures.Identifier(welds.mainObjectId)); + teklaWeld.SecondaryObject = Model.SelectModelObject(new Tekla.Structures.Identifier(welds.secondaryObjectId)); + teklaWeld.Insert(); + } + } + + public BE.TeklaStructures.Welds WeldsToSpeckle(Weld welds) + { + var speckleTeklaWeld = new BE.TeklaStructures.Welds(); + + GetWeldProperties(welds, speckleTeklaWeld); + + speckleTeklaWeld.mainObjectId = welds.MainObject.Identifier.GUID.ToString(); + speckleTeklaWeld.secondaryObjectId = welds.SecondaryObject.Identifier.GUID.ToString(); + + GetAllUserProperties(speckleTeklaWeld, welds); + + var solid = welds.GetSolid(); + speckleTeklaWeld.displayValue = new List { GetMeshFromSolid(solid) }; + return speckleTeklaWeld; + } + + public void GetWeldProperties(BaseWeld baseWeld, BE.TeklaStructures.Welds speckleWeld) + { + speckleWeld.sizeAbove = baseWeld.SizeAbove; + speckleWeld.sizeBelow = baseWeld.SizeBelow; + speckleWeld.lengthAbove = baseWeld.LengthAbove; + speckleWeld.lengthBelow = baseWeld.LengthBelow; + speckleWeld.pitchAbove = baseWeld.PitchAbove; + speckleWeld.pitchBelow = baseWeld.PitchBelow; + speckleWeld.angleAbove = baseWeld.AngleAbove; + speckleWeld.angleBelow = baseWeld.AngleBelow; + speckleWeld.typeAbove = (BE.TeklaStructures.TeklaWeldType)baseWeld.TypeAbove; + speckleWeld.typeBelow = (BE.TeklaStructures.TeklaWeldType)baseWeld.TypeBelow; + speckleWeld.intermittentType = (BE.TeklaStructures.TeklaWeldIntermittentType)baseWeld.IntermittentType; + } + + public void SetWeldProperties(BaseWeld baseWeld, BE.TeklaStructures.Welds speckleWeld) + { + baseWeld.SizeAbove = speckleWeld.sizeAbove; + baseWeld.SizeBelow = speckleWeld.sizeBelow; + baseWeld.LengthAbove = speckleWeld.lengthAbove; + baseWeld.LengthBelow = speckleWeld.lengthBelow; + baseWeld.PitchAbove = speckleWeld.pitchAbove; + baseWeld.PitchBelow = speckleWeld.pitchBelow; + baseWeld.AngleAbove = speckleWeld.angleAbove; + baseWeld.AngleBelow = speckleWeld.angleBelow; + baseWeld.TypeAbove = (BaseWeld.WeldTypeEnum)speckleWeld.typeAbove; + baseWeld.TypeBelow = (BaseWeld.WeldTypeEnum)speckleWeld.typeBelow; + baseWeld.IntermittentType = (BaseWeld.WeldIntermittentTypeEnum)speckleWeld.intermittentType; + } +} diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/ClosedLoop.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/ClosedLoop.cs index 3d7687da8c..1471345fa1 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/ClosedLoop.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/ClosedLoop.cs @@ -1,90 +1,100 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using MathNet.Spatial.Euclidean; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +internal class ClosedLoop { - internal class ClosedLoop + public List Vertices = new(); + public Dictionary IndexedLines = new(); + public int WindingDirection; + public CoordinateSystem CoordinateTranslation; + + public bool Init( + IEnumerable globalCoords, + ref CoordinateSystem CoordinateTranslation, + double tolerance, + int ptIndexOffset = 0 + ) { - public List Vertices = new List(); - public Dictionary IndexedLines = new Dictionary(); - public int WindingDirection; - public CoordinateSystem CoordinateTranslation; + var essential = globalCoords.Essential(); - public bool Init(IEnumerable globalCoords, ref CoordinateSystem CoordinateTranslation, double tolerance, int ptIndexOffset = 0) + var origPts = new List(); + for (var i = 0; i < essential.Length; i += 3) { - var essential = globalCoords.Essential(); + origPts.Add(new Point3D(essential[i], essential[i + 1], essential[i + 2])); + } - var origPts = new List(); - for (var i = 0; i < essential.Length; i += 3) - { - origPts.Add(new Point3D(essential[i], essential[i + 1], essential[i + 2])); - } + if (CoordinateTranslation == null) + { + //Create plane + var plane = Plane.FromPoints(origPts[0], origPts[1], origPts[2]); + var normal = plane.Normal; + var origin = origPts[0]; + var xDir = origPts[0].VectorTo(origPts[1]).Normalize(); + var yDir = normal.CrossProduct(xDir); - if (CoordinateTranslation == null) - { - //Create plane - var plane = Plane.FromPoints(origPts[0], origPts[1], origPts[2]); - var normal = plane.Normal; - var origin = origPts[0]; - var xDir = origPts[0].VectorTo(origPts[1]).Normalize(); - var yDir = normal.CrossProduct(xDir); - - //The CoordinateSystem class in MathNet.Spatial and its methods aren't not very intuitive as discussed in https://github.com/mathnet/mathnet-spatial/issues/53 - //Since I don't understand the offsets that seem to be applied by TransformFrom and TransformTo, I focussed on the Transform method, - //which transforms a local point to a global point. - //In order to transform a point from global into local, the coordinate system needs to be reversed so that the resulting coordinateSystem.Transform does the - //transformation from global to local. - CoordinateTranslation = new CoordinateSystem(new CoordinateSystem(origin, xDir, yDir, normal).Inverse()); - } - else - { - this.CoordinateTranslation = CoordinateTranslation; - } + //The CoordinateSystem class in MathNet.Spatial and its methods aren't not very intuitive as discussed in https://github.com/mathnet/mathnet-spatial/issues/53 + //Since I don't understand the offsets that seem to be applied by TransformFrom and TransformTo, I focussed on the Transform method, + //which transforms a local point to a global point. + //In order to transform a point from global into local, the coordinate system needs to be reversed so that the resulting coordinateSystem.Transform does the + //transformation from global to local. + CoordinateTranslation = new CoordinateSystem(new CoordinateSystem(origin, xDir, yDir, normal).Inverse()); + } + else + { + this.CoordinateTranslation = CoordinateTranslation; + } - //project points onto the plane - if the points are co-planar and translation is done correctly, all Z values should be zero - var nonCoPlanarPts = 0; - var n = origPts.Count(); - for (var i = 0; i < n; i++) + //project points onto the plane - if the points are co-planar and translation is done correctly, all Z values should be zero + var nonCoPlanarPts = 0; + var n = origPts.Count(); + for (var i = 0; i < n; i++) + { + var projectedPt = CoordinateTranslation.Transform(origPts[i]); + if (Math.Abs(projectedPt.Z) > tolerance) { - var projectedPt = CoordinateTranslation.Transform(origPts[i]); - if (Math.Abs(projectedPt.Z) > tolerance) - { - nonCoPlanarPts++; - } - var localPt = new Point2D(projectedPt.X, projectedPt.Y); - Vertices.Add(new Vertex(ptIndexOffset + i, localPt, origPts[i])); + nonCoPlanarPts++; } + var localPt = new Point2D(projectedPt.X, projectedPt.Y); + Vertices.Add(new Vertex(ptIndexOffset + i, localPt, origPts[i])); + } - WindingDirection = 0; - IndexedLines = new Dictionary(); - if (nonCoPlanarPts > 0) - { - return false; - } + WindingDirection = 0; + IndexedLines = new Dictionary(); + if (nonCoPlanarPts > 0) + { + return false; + } - for (var i = 0; i < n; i++) - { - var indexPair = new IndexPair(ptIndexOffset + i, ptIndexOffset + (i == n - 1 ? 0 : i + 1)); - IndexedLines.Add(indexPair, new Line2D(MeshPointByIndex(indexPair.Indices[0]).Local, MeshPointByIndex(indexPair.Indices[1]).Local)); - } + for (var i = 0; i < n; i++) + { + var indexPair = new IndexPair(ptIndexOffset + i, ptIndexOffset + (i == n - 1 ? 0 : i + 1)); + IndexedLines.Add( + indexPair, + new Line2D(MeshPointByIndex(indexPair.Indices[0]).Local, MeshPointByIndex(indexPair.Indices[1]).Local) + ); + } - WindingDirection = Vertices.Select(mp => mp.Local).GetWindingDirection(); + WindingDirection = Vertices.Select(mp => mp.Local).GetWindingDirection(); - return true; - } + return true; + } - public int NextIndex(int currIndex) => currIndex == Vertices.Last().Index ? Vertices.First().Index : currIndex + 1; - public int PrevIndex(int currIndex) => currIndex == Vertices.First().Index ? Vertices.Last().Index : currIndex - 1; - public int FirstIndex() => Vertices.First().Index; - public int LastIndex() => Vertices.Last().Index; + public int NextIndex(int currIndex) => currIndex == Vertices.Last().Index ? Vertices.First().Index : currIndex + 1; - public void ReverseDirection() - { - WindingDirection *= -1; - } + public int PrevIndex(int currIndex) => currIndex == Vertices.First().Index ? Vertices.Last().Index : currIndex - 1; + + public int FirstIndex() => Vertices.First().Index; - private Vertex MeshPointByIndex(int index) => Vertices.FirstOrDefault(mp => mp.Index == index); + public int LastIndex() => Vertices.Last().Index; + + public void ReverseDirection() + { + WindingDirection *= -1; } + + private Vertex MeshPointByIndex(int index) => Vertices.FirstOrDefault(mp => mp.Index == index); } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/Extensions.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/Extensions.cs index e1e1347189..93f9b78246 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/Extensions.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/Extensions.cs @@ -1,218 +1,223 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using MathNet.Numerics; using MathNet.Spatial.Euclidean; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +public static class Extensions { - public static class Extensions + public static bool IsInside(this IEnumerable pts, Point2D p) { - public static bool IsInside(this IEnumerable pts, Point2D p) - { - var ptsList = pts.ToList(); - ptsList.Add(ptsList[0]); // Add the end node again - return (Wn_PnPoly(p, ptsList) != 0); - } + var ptsList = pts.ToList(); + ptsList.Add(ptsList[0]); // Add the end node again + return (Wn_PnPoly(p, ptsList) != 0); + } - // wn_PnPoly(): winding number test for a point in a polygon - // Input: P = a point, - // V[] = vertex points of a polygon V[n+1] with V[n]=V[0] - // Return: wn = the winding number (=0 only when P is outside) - // Adapted from: http://geomalgorithms.com/a03-_inclusion.html - private static int Wn_PnPoly(Point2D P, List V) - { - int wn = 0; // the winding number counter - int n = V.Count() - 1; - - // loop through all edges of the polygon - for (int i = 0; i < n; i++) - { // edge from V[i] to V[i+1] - if (V[i].Y <= P.Y) - { // start y <= P.y - if (V[i + 1].Y > P.Y) // an upward crossing + // wn_PnPoly(): winding number test for a point in a polygon + // Input: P = a point, + // V[] = vertex points of a polygon V[n+1] with V[n]=V[0] + // Return: wn = the winding number (=0 only when P is outside) + // Adapted from: http://geomalgorithms.com/a03-_inclusion.html + private static int Wn_PnPoly(Point2D P, List V) + { + int wn = 0; // the winding number counter + int n = V.Count() - 1; + + // loop through all edges of the polygon + for (int i = 0; i < n; i++) + { // edge from V[i] to V[i+1] + if (V[i].Y <= P.Y) + { // start y <= P.y + if (V[i + 1].Y > P.Y) // an upward crossing + { + if (IsLeft(V[i], V[i + 1], P) > 0) // P left of edge { - if (IsLeft(V[i], V[i + 1], P) > 0) // P left of edge - { - ++wn; // have a valid up intersect - } + ++wn; // have a valid up intersect } } - else - { // start y > P.y (no test needed) - if (V[i + 1].Y <= P.Y) // a downward crossing + } + else + { // start y > P.y (no test needed) + if (V[i + 1].Y <= P.Y) // a downward crossing + { + if (IsLeft(V[i], V[i + 1], P) < 0) // P right of edge { - if (IsLeft(V[i], V[i + 1], P) < 0) // P right of edge - { - --wn; // have a valid down intersect - } + --wn; // have a valid down intersect } } } - return wn; } + return wn; + } - // isLeft(): tests if a point is Left|On|Right of an infinite line. - // Input: three points P0, P1, and P2 - // Return: >0 for P2 left of the line through P0 and P1 - // =0 for P2 on the line - // <0 for P2 right of the line - // See: Algorithm 1 "Area of Triangles and Polygons" - // Adapted from: http://geomalgorithms.com/a03-_inclusion.html - private static int IsLeft(Point2D P0, Point2D P1, Point2D P2) - { - var result = (((P1.X - P0.X) * (P2.Y - P0.Y) - - (P2.X - P0.X) * (P1.Y - P0.Y))); - return (result == 0) ? 0 : (result < 0) ? -1 : 1; - } + // isLeft(): tests if a point is Left|On|Right of an infinite line. + // Input: three points P0, P1, and P2 + // Return: >0 for P2 left of the line through P0 and P1 + // =0 for P2 on the line + // <0 for P2 right of the line + // See: Algorithm 1 "Area of Triangles and Polygons" + // Adapted from: http://geomalgorithms.com/a03-_inclusion.html + private static int IsLeft(Point2D P0, Point2D P1, Point2D P2) + { + var result = (((P1.X - P0.X) * (P2.Y - P0.Y) - (P2.X - P0.X) * (P1.Y - P0.Y))); + return (result == 0) + ? 0 + : (result < 0) + ? -1 + : 1; + } - //Using pseudocode found in https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order/1180256#1180256 - public static int GetWindingDirection(this IEnumerable loopPoints) + //Using pseudocode found in https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order/1180256#1180256 + public static int GetWindingDirection(this IEnumerable loopPoints) + { + var pts = loopPoints.ToArray(); + double signedArea = 0; + var n = pts.Count(); + for (var i = 0; i < n; i++) { - var pts = loopPoints.ToArray(); - double signedArea = 0; - var n = pts.Count(); - for (var i = 0; i < n; i++) - { - var nextPtIndex = (i < (n - 1)) ? (i + 1) : 0; - var x1 = pts[i].X; - var y1 = pts[i].Y; - var x2 = pts[nextPtIndex].X; - var y2 = pts[nextPtIndex].Y; + var nextPtIndex = (i < (n - 1)) ? (i + 1) : 0; + var x1 = pts[i].X; + var y1 = pts[i].Y; + var x2 = pts[nextPtIndex].X; + var y2 = pts[nextPtIndex].Y; - signedArea += (x1 * y2 - x2 * y1); - } - - if (signedArea > 0) - { - return 1; - } - else if (signedArea < 0) - { - return -1; - } - else - { - return 0; - } + signedArea += (x1 * y2 - x2 * y1); } - //Assumption: this method would never be called when the intersector's end points lie in the middle of an intersectee line - //This is the case for meshes defined by an ordered set of vertices - public static bool Intersects(this Line2D intersectee, Line2D intersector, double tolerance) + if (signedArea > 0) { - var intPtIntersection = intersectee.IntersectWith(intersector); - if (!intPtIntersection.HasValue) - { - return false; - } - var intPt = intPtIntersection.Value; - - //There is no intersection if it's at the end points of the line doing the suppposed intersection - if (intersector.StartPoint.EqualsWithinTolerance(intPt, tolerance) || intersector.EndPoint.EqualsWithinTolerance(intPt, tolerance)) - { - return false; - } - - //By default MathNet defines lines with infinite length so determine if the intersection point is actually within the original bounds of the line - var intersecteePt = intersectee.ClosestPointTo(intPt, true); - var intersectorPt = intersector.ClosestPointTo(intPt, true); - return intersecteePt.EqualsWithinTolerance(intersectorPt, tolerance); + return 1; } - - public static bool EqualsWithinTolerance(this Point2D pt1, Point2D pt2, double tolerance) + else if (signedArea < 0) { - return (pt1.DistanceTo(pt2) < tolerance); + return -1; } - - //Between does not include being parallel to either vectors - the value returned will be zer0 - public static bool IsBetweenVectors(this Vector2D candidate, Vector2D vFrom, Vector2D vTo) + else { - var candidateDia = candidate.DiamondAngle(); - var fromDia = vFrom.DiamondAngle(); - var toDia = vTo.DiamondAngle(); - - return (fromDia < toDia) - ? (candidateDia > fromDia && candidateDia < toDia) - : (candidateDia > fromDia || candidateDia < toDia); + return 0; } + } - public static double[] Essential(this IEnumerable coords) + //Assumption: this method would never be called when the intersector's end points lie in the middle of an intersectee line + //This is the case for meshes defined by an ordered set of vertices + public static bool Intersects(this Line2D intersectee, Line2D intersector, double tolerance) + { + var intPtIntersection = intersectee.IntersectWith(intersector); + if (!intPtIntersection.HasValue) { - var pts = coords.ToPoints(); - var reducedPts = pts.Essential(); - var retCoords = new double[reducedPts.Count() * 3]; - for (var i = 0; i < reducedPts.Count(); i++) - { - retCoords[i * 3] = reducedPts[i].X; - retCoords[(i * 3) + 1] = reducedPts[i].Y; - retCoords[(i * 3) + 2] = reducedPts[i].Z; - } - return retCoords; + return false; } + var intPt = intPtIntersection.Value; - public static List Essential(this List origPts) + //There is no intersection if it's at the end points of the line doing the suppposed intersection + if ( + intersector.StartPoint.EqualsWithinTolerance(intPt, tolerance) + || intersector.EndPoint.EqualsWithinTolerance(intPt, tolerance) + ) { - var origPtsExtended = new List() { origPts.Last() }; - origPtsExtended.AddRange(origPts); - origPtsExtended.Add(origPts.First()); - var numPtsExtended = origPtsExtended.Count(); - var retList = new List(); + return false; + } - for (var i = 1; i < (numPtsExtended - 1); i++) - { - var prev = origPtsExtended[i - 1]; - var next = origPtsExtended[i + 1]; + //By default MathNet defines lines with infinite length so determine if the intersection point is actually within the original bounds of the line + var intersecteePt = intersectee.ClosestPointTo(intPt, true); + var intersectorPt = intersector.ClosestPointTo(intPt, true); + return intersecteePt.EqualsWithinTolerance(intersectorPt, tolerance); + } - if (!origPtsExtended[i].IsOnLineBetween(prev, next)) - { - retList.Add(origPtsExtended[i]); - } - } + public static bool EqualsWithinTolerance(this Point2D pt1, Point2D pt2, double tolerance) + { + return (pt1.DistanceTo(pt2) < tolerance); + } - return retList; - } + //Between does not include being parallel to either vectors - the value returned will be zer0 + public static bool IsBetweenVectors(this Vector2D candidate, Vector2D vFrom, Vector2D vTo) + { + var candidateDia = candidate.DiamondAngle(); + var fromDia = vFrom.DiamondAngle(); + var toDia = vTo.DiamondAngle(); - public static bool IsOnLineBetween(this Point3D p, Point3D start, Point3D end) - { - var l = new Line3D(start, end); - return l.IsOnLine(p); - } + return (fromDia < toDia) + ? (candidateDia > fromDia && candidateDia < toDia) + : (candidateDia > fromDia || candidateDia < toDia); + } - public static bool IsOnLine(this Line3D l, Point3D p) + public static double[] Essential(this IEnumerable coords) + { + var pts = coords.ToPoints(); + var reducedPts = pts.Essential(); + var retCoords = new double[reducedPts.Count() * 3]; + for (var i = 0; i < reducedPts.Count(); i++) { - var closest = l.ClosestPointTo(p, true); - var ret = (closest.Equals(p, PolygonMesher.PointComparisonEpsilon)); - return ret; + retCoords[i * 3] = reducedPts[i].X; + retCoords[(i * 3) + 1] = reducedPts[i].Y; + retCoords[(i * 3) + 2] = reducedPts[i].Z; } + return retCoords; + } - public static List ToPoints(this IEnumerable coords) + public static List Essential(this List origPts) + { + var origPtsExtended = new List() { origPts.Last() }; + origPtsExtended.AddRange(origPts); + origPtsExtended.Add(origPts.First()); + var numPtsExtended = origPtsExtended.Count(); + var retList = new List(); + + for (var i = 1; i < (numPtsExtended - 1); i++) { - var numPts = (int)(coords.Count() / 3); - var pts = new List(); + var prev = origPtsExtended[i - 1]; + var next = origPtsExtended[i + 1]; - var coordsArray = coords.ToArray(); - for (var i = 0; i < numPts; i++) + if (!origPtsExtended[i].IsOnLineBetween(prev, next)) { - pts.Add(new Point3D(coordsArray[i * 3], coordsArray[(i * 3) + 1], coordsArray[(i * 3) + 2])); + retList.Add(origPtsExtended[i]); } - return pts; } - //Alternative to the expensive calculation of vector angles using trigonometry. - //Sourced from: https://stackoverflow.com/questions/1427422/cheap-algorithm-to-find-measure-of-angle-between-vectors - public static double DiamondAngle(this Vector2D v) + return retList; + } + + public static bool IsOnLineBetween(this Point3D p, Point3D start, Point3D end) + { + var l = new Line3D(start, end); + return l.IsOnLine(p); + } + + public static bool IsOnLine(this Line3D l, Point3D p) + { + var closest = l.ClosestPointTo(p, true); + var ret = (closest.Equals(p, PolygonMesher.PointComparisonEpsilon)); + return ret; + } + + public static List ToPoints(this IEnumerable coords) + { + var numPts = (int)(coords.Count() / 3); + var pts = new List(); + + var coordsArray = coords.ToArray(); + for (var i = 0; i < numPts; i++) + { + pts.Add(new Point3D(coordsArray[i * 3], coordsArray[(i * 3) + 1], coordsArray[(i * 3) + 2])); + } + return pts; + } + + //Alternative to the expensive calculation of vector angles using trigonometry. + //Sourced from: https://stackoverflow.com/questions/1427422/cheap-algorithm-to-find-measure-of-angle-between-vectors + public static double DiamondAngle(this Vector2D v) + { + var x = v.X; + var y = v.Y; + if (y >= 0) { - var x = v.X; - var y = v.Y; - if (y >= 0) - { - return (x >= 0 ? y / (x + y) : 1 - x / (-x + y)); - } - else - { - return (x < 0 ? 2 - y / (-x - y) : 3 + x / (x - y)); - } + return (x >= 0 ? y / (x + y) : 1 - x / (-x + y)); + } + else + { + return (x < 0 ? 2 - y / (-x - y) : 3 + x / (x - y)); } } } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/IndexPair.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/IndexPair.cs index 6227677f1c..f778c81a94 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/IndexPair.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/IndexPair.cs @@ -1,16 +1,18 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +internal class IndexPair : IndexSet { - internal class IndexPair : IndexSet - { - public IndexPair(int index1, int index2) : base(new List() { index1, index2 }) - { - } + public IndexPair(int index1, int index2) + : base(new List() { index1, index2 }) { } - public int? Other(int index) - { - return (Indices[0] == index) ? Indices[1] : (Indices[1] == index) ? (int?)Indices[0] : null; - } + public int? Other(int index) + { + return (Indices[0] == index) + ? Indices[1] + : (Indices[1] == index) + ? (int?)Indices[0] + : null; } } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/IndexSet.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/IndexSet.cs index 7207e106ae..8bbf72e286 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/IndexSet.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/IndexSet.cs @@ -1,25 +1,24 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +internal abstract class IndexSet { - internal abstract class IndexSet - { - public readonly int[] Indices; + public readonly int[] Indices; - public IndexSet(List values) - { - Indices = values.OrderBy(v => v).ToArray(); - } + public IndexSet(List values) + { + Indices = values.OrderBy(v => v).ToArray(); + } - public bool Contains(int index) - { - return Indices.Any(i => i == index); - } + public bool Contains(int index) + { + return Indices.Any(i => i == index); + } - public bool Matches(IndexSet other) - { - return Indices.SequenceEqual(other.Indices); - } + public bool Matches(IndexSet other) + { + return Indices.SequenceEqual(other.Indices); } } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/PolygonMesher.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/PolygonMesher.cs index 22ca9c533d..b97bd5d190 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/PolygonMesher.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/PolygonMesher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,391 +6,424 @@ using MathNet.Numerics.Interpolation; using MathNet.Spatial.Euclidean; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +public class PolygonMesher { - public class PolygonMesher - { - private CoordinateSystem CoordinateTranslation = null; + private CoordinateSystem CoordinateTranslation = null; - private readonly ClosedLoop ExternalLoop = new ClosedLoop(); - private readonly List Openings = new List(); + private readonly ClosedLoop ExternalLoop = new(); + private readonly List Openings = new(); - private readonly Dictionary Internals = new Dictionary(); - private readonly List Triangles = new List(); + private readonly Dictionary Internals = new(); + private readonly List Triangles = new(); - private readonly double tolerance = 0.001; + private readonly double tolerance = 0.001; - public static double PointComparisonEpsilon = 0.0001; + public static double PointComparisonEpsilon = 0.0001; - public double[] Coordinates + public double[] Coordinates + { + get { - get + var coord = new List(); + var vs = GetAllVertices(); + foreach (var v in vs) { - var coord = new List(); - var vs = GetAllVertices(); - foreach (var v in vs) - { - coord.AddRange(v.Coordinates); - } - return coord.ToArray(); + coord.AddRange(v.Coordinates); } + return coord.ToArray(); } + } - //Assumptions: - // - input coordinates are an ordered set of external vertices (i.e. not vertices of openings) - // - the lines defined by these vertices don't intersect each other - public bool Init(IEnumerable coords, IEnumerable> openingCoordsList = null) + //Assumptions: + // - input coordinates are an ordered set of external vertices (i.e. not vertices of openings) + // - the lines defined by these vertices don't intersect each other + public bool Init(IEnumerable coords, IEnumerable> openingCoordsList = null) + { + // if there are less than 3 coordinates, we cannot create a mesh + if (coords.Count() < 9) { - // if there are less than 3 coordinates, we cannot create a mesh - if (coords.Count() < 9) - return false; - - ExternalLoop.Init(coords, ref CoordinateTranslation, tolerance); - - if (openingCoordsList != null) - { - var indexOffset = ExternalLoop.Vertices.Count(); - foreach (var openingGlobalCoords in openingCoordsList) - { - var openingLoop = new ClosedLoop(); - openingLoop.Init(openingGlobalCoords, ref this.CoordinateTranslation, tolerance, indexOffset); - //openings are inverse loops - the inside should be considered the outside, to reverse the winding order - openingLoop.ReverseDirection(); - indexOffset += openingLoop.Vertices.Count(); - Openings.Add(openingLoop); - } - } + return false; + } - if (!GenerateInternals()) - { - return false; - } + ExternalLoop.Init(coords, ref CoordinateTranslation, tolerance); - if (!GenerateFaces()) + if (openingCoordsList != null) + { + var indexOffset = ExternalLoop.Vertices.Count(); + foreach (var openingGlobalCoords in openingCoordsList) { - return false; + var openingLoop = new ClosedLoop(); + openingLoop.Init(openingGlobalCoords, ref this.CoordinateTranslation, tolerance, indexOffset); + //openings are inverse loops - the inside should be considered the outside, to reverse the winding order + openingLoop.ReverseDirection(); + indexOffset += openingLoop.Vertices.Count(); + Openings.Add(openingLoop); } + } - return true; + if (!GenerateInternals()) + { + return false; } - private bool GenerateInternals() + if (!GenerateFaces()) { - var loops = GetLoops(); + return false; + } + + return true; + } + + private bool GenerateInternals() + { + var loops = GetLoops(); - //Go through each loop - foreach (var l in loops) + //Go through each loop + foreach (var l in loops) + { + for (var i = l.FirstIndex(); i <= l.LastIndex(); i++) { - for (var i = l.FirstIndex(); i <= l.LastIndex(); i++) + var nextPtIndex = l.NextIndex(i); + var prevPtIndex = l.PrevIndex(i); + var dictHalfSweep = PointIndicesSweep(i, nextPtIndex, prevPtIndex, l.WindingDirection); + + if (dictHalfSweep == null) { - var nextPtIndex = l.NextIndex(i); - var prevPtIndex = l.PrevIndex(i); - var dictHalfSweep = PointIndicesSweep(i, nextPtIndex, prevPtIndex, l.WindingDirection); + //This would only happen if winding direction hasn't been determined yet + return false; + } - if (dictHalfSweep == null) + if (dictHalfSweep.Keys.Count > 0) + { + //Go through each direction (ending in an external point) emanating from this candidate point + foreach (var vector in dictHalfSweep.Keys) { - //This would only happen if winding direction hasn't been determined yet - return false; - } + double? currShortestDistance = null; + int? shortestPtIndex = null; - if (dictHalfSweep.Keys.Count > 0) - { - //Go through each direction (ending in an external point) emanating from this candidate point - foreach (var vector in dictHalfSweep.Keys) + //Go through each point in the same direction from this candidate point (because multiple external points can be in alignment + //along the same direction) + foreach (var ptIndex in dictHalfSweep[vector]) { - double? currShortestDistance = null; - int? shortestPtIndex = null; - - //Go through each point in the same direction from this candidate point (because multiple external points can be in alignment - //along the same direction) - foreach (var ptIndex in dictHalfSweep[vector]) + var indexPair = new IndexPair(i, ptIndex); + var line = GetLine(indexPair); + if (!ValidNewInternalLine(indexPair, line)) { - var indexPair = new IndexPair(i, ptIndex); - var line = GetLine(indexPair); - if (!ValidNewInternalLine(indexPair, line)) continue; - - //Calculate distance - if currShortestDistance is either -1 or shorter than the shortest, replace the shortest - var distance = line.Length; - if (!currShortestDistance.HasValue || (distance < currShortestDistance)) - { - currShortestDistance = distance; - shortestPtIndex = ptIndex; - } + continue; } - //Now that the shortest valid line to another point has been found, add it to the list of lines - if (currShortestDistance > 0 && shortestPtIndex.HasValue && shortestPtIndex > 0) + //Calculate distance - if currShortestDistance is either -1 or shorter than the shortest, replace the shortest + var distance = line.Length; + if (!currShortestDistance.HasValue || (distance < currShortestDistance)) { - //Add line - which has already been checked to ensure it doesn't intersect others, etc - var shortestIndexPair = new IndexPair(i, shortestPtIndex.Value); - Internals.Add(shortestIndexPair, GetLine(shortestIndexPair)); - continue; + currShortestDistance = distance; + shortestPtIndex = ptIndex; } } + + //Now that the shortest valid line to another point has been found, add it to the list of lines + if (currShortestDistance > 0 && shortestPtIndex.HasValue && shortestPtIndex > 0) + { + //Add line - which has already been checked to ensure it doesn't intersect others, etc + var shortestIndexPair = new IndexPair(i, shortestPtIndex.Value); + Internals.Add(shortestIndexPair, GetLine(shortestIndexPair)); + continue; + } } } } - - return true; } - //This method might become useful when visualising these in Rhino, for example - public List GetInternalGlobalCoords() - { - var l = new List(); - var indexPoints = AllGlobalPoints; + return true; + } - foreach (var internalPair in Internals.Keys) - { - var startPt = indexPoints[internalPair.Indices[0]]; - var endPt = indexPoints[internalPair.Indices[1]]; - l.Add(new double[] { startPt.X, startPt.Y, startPt.Z, endPt.X, endPt.Y, endPt.Z }); - } + //This method might become useful when visualising these in Rhino, for example + public List GetInternalGlobalCoords() + { + var l = new List(); + var indexPoints = AllGlobalPoints; - return l; - } - - public List Faces(int faceIndexOffset = 0) + foreach (var internalPair in Internals.Keys) { - var faces = new List(); - foreach (var t in Triangles) - { - faces.Add(3); // signifying a triangle - faces.AddRange(t.Indices.Take(3).Select(x => x + faceIndexOffset)); - } - - return faces; + var startPt = indexPoints[internalPair.Indices[0]]; + var endPt = indexPoints[internalPair.Indices[1]]; + l.Add(new double[] { startPt.X, startPt.Y, startPt.Z, endPt.X, endPt.Y, endPt.Z }); } - private bool GenerateFaces() + return l; + } + + public List Faces(int faceIndexOffset = 0) + { + var faces = new List(); + foreach (var t in Triangles) { - //Now determine faces by cycling through each edge line and finding which other point is shared between all lines emanating from this point - Triangles.Clear(); + faces.Add(3); // signifying a triangle + faces.AddRange(t.Indices.Take(3).Select(x => x + faceIndexOffset)); + } - var indexPairs = GetAllIndexPairs(); - var vertices = GetAllVertices(); - var vertexSets = new List(); + return faces; + } - foreach (var vertex in vertices) - { - var linkedIndices = indexPairs.Where(v => v.Contains(vertex.Index)).Select(v => v.Other(vertex.Index).Value).ToList(); + private bool GenerateFaces() + { + //Now determine faces by cycling through each edge line and finding which other point is shared between all lines emanating from this point + Triangles.Clear(); + + var indexPairs = GetAllIndexPairs(); + var vertices = GetAllVertices(); + var vertexSets = new List(); - foreach (var l1i in linkedIndices) + foreach (var vertex in vertices) + { + var linkedIndices = indexPairs + .Where(v => v.Contains(vertex.Index)) + .Select(v => v.Other(vertex.Index).Value) + .ToList(); + + foreach (var l1i in linkedIndices) + { + var level2Indices = indexPairs + .Where(v => v.Contains(l1i) && !v.Contains(vertex.Index)) + .Select(v => v.Other(l1i).Value) + .ToList(); + foreach (var l2i in level2Indices) { - var level2Indices = indexPairs.Where(v => v.Contains(l1i) && !v.Contains(vertex.Index)).Select(v => v.Other(l1i).Value).ToList(); - foreach (var l2i in level2Indices) + if (indexPairs.Any(ip => ip.Matches(new IndexPair(l2i, vertex.Index)))) { - if (indexPairs.Any(ip => ip.Matches(new IndexPair(l2i, vertex.Index)))) + var triangle = new TriangleIndexSet(vertex.Index, l1i, l2i); + if (Triangles.All(t => !t.Matches(triangle))) { - var triangle = new TriangleIndexSet(vertex.Index, l1i, l2i); - if (Triangles.All(t => !t.Matches(triangle))) - { - Triangles.Add(triangle); - } + Triangles.Add(triangle); } } } } - - return true; } - private Dictionary AllIndexLocalLines + return true; + } + + private Dictionary AllIndexLocalLines + { + get { - get + var pairs = new Dictionary(); + foreach (var k in Internals.Keys) { - var pairs = new Dictionary(); - foreach (var k in Internals.Keys) - { - pairs.Add(k, Internals[k]); - } - foreach (var k in ExternalLoop.IndexedLines.Keys) - { - pairs.Add(k, ExternalLoop.IndexedLines[k]); - } + pairs.Add(k, Internals[k]); + } + foreach (var k in ExternalLoop.IndexedLines.Keys) + { + pairs.Add(k, ExternalLoop.IndexedLines[k]); + } - foreach (var l in Openings) + foreach (var l in Openings) + { + foreach (var k in l.IndexedLines.Keys) { - foreach (var k in l.IndexedLines.Keys) - { - pairs.Add(k, l.IndexedLines[k]); - } + pairs.Add(k, l.IndexedLines[k]); } - return pairs; } + return pairs; } + } - private Dictionary AllGlobalPoints + private Dictionary AllGlobalPoints + { + get { - get - { - var indexPoints = new Dictionary(); + var indexPoints = new Dictionary(); - foreach (var l in GetLoops()) + foreach (var l in GetLoops()) + { + foreach (var mp in l.Vertices) { - foreach (var mp in l.Vertices) - { - indexPoints.Add(mp.Index, mp.Global); - } + indexPoints.Add(mp.Index, mp.Global); } - return indexPoints; } + return indexPoints; } + } - private bool ExistingLinesContains(IndexPair indexPair) - { - var matching = AllIndexLocalLines.Keys.Where(i => i.Matches(indexPair)); - return (matching.Count() > 0); - } + private bool ExistingLinesContains(IndexPair indexPair) + { + var matching = AllIndexLocalLines.Keys.Where(i => i.Matches(indexPair)); + return (matching.Count() > 0); + } - private Line2D GetLine(IndexPair indexPair) - { - var allPts = GetAllPts(); - return new Line2D(allPts[indexPair.Indices[0]], allPts[indexPair.Indices[1]]); - } + private Line2D GetLine(IndexPair indexPair) + { + var allPts = GetAllPts(); + return new Line2D(allPts[indexPair.Indices[0]], allPts[indexPair.Indices[1]]); + } - private List GetLoops() + private List GetLoops() + { + var l = new List() { ExternalLoop }; + if (Openings != null && Openings.Count() > 0) { - var l = new List() { ExternalLoop }; - if (Openings != null && Openings.Count() > 0) - { - l.AddRange(Openings); - } - return l; + l.AddRange(Openings); } + return l; + } - private bool ValidNewInternalLine(IndexPair indexPair, Line2D line) + private bool ValidNewInternalLine(IndexPair indexPair, Line2D line) + { + if (indexPair == null) { - if (indexPair == null) return false; - - //Check if this line is already in the collection - if so, ignore it - if (ExistingLinesContains(indexPair)) return false; - - //Check if this line would intersect any external lines in this collection - if so, ignore it - if (IntersectsBoundaryLines(line)) return false; - - //Check if this line would intersect any already in this collection - if so, ignore it - if (IntersectsInternalLines(line)) return false; - - return true; + return false; } - private List GetPairedIndices(int index) + //Check if this line is already in the collection - if so, ignore it + if (ExistingLinesContains(indexPair)) { - return AllIndexLocalLines.Keys.Select(l => l.Other(index)).Where(l => l.HasValue).Cast().ToList(); + return false; } - private List GetAllPts() + //Check if this line would intersect any external lines in this collection - if so, ignore it + if (IntersectsBoundaryLines(line)) { - var allPts = new List(); - allPts.AddRange(ExternalLoop.Vertices.Select(mp => mp.Local)); - if (Openings != null) - { - foreach (var opening in Openings) - { - allPts.AddRange(opening.Vertices.Select(p => p.Local)); - } - } - return allPts; + return false; } - private List GetAllVertices() + //Check if this line would intersect any already in this collection - if so, ignore it + if (IntersectsInternalLines(line)) { - return GetLoops().SelectMany(l => l.Vertices).ToList(); + return false; } - private List GetAllBoundaryLines() + return true; + } + + private List GetPairedIndices(int index) + { + return AllIndexLocalLines.Keys.Select(l => l.Other(index)).Where(l => l.HasValue).Cast().ToList(); + } + + private List GetAllPts() + { + var allPts = new List(); + allPts.AddRange(ExternalLoop.Vertices.Select(mp => mp.Local)); + if (Openings != null) { - var allBoundaryLines = new List(); - allBoundaryLines.AddRange(ExternalLoop.IndexedLines.Select(p => p.Value)); foreach (var opening in Openings) { - allBoundaryLines.AddRange(opening.IndexedLines.Select(p => p.Value)); + allPts.AddRange(opening.Vertices.Select(p => p.Local)); } - return allBoundaryLines; } + return allPts; + } - private List GetAllBoundaryIndexPairs() + private List GetAllVertices() + { + return GetLoops().SelectMany(l => l.Vertices).ToList(); + } + + private List GetAllBoundaryLines() + { + var allBoundaryLines = new List(); + allBoundaryLines.AddRange(ExternalLoop.IndexedLines.Select(p => p.Value)); + foreach (var opening in Openings) { - var allBoundaryPairs = new List(); - allBoundaryPairs.AddRange(ExternalLoop.IndexedLines.Select(p => p.Key)); - foreach (var opening in Openings) - { - allBoundaryPairs.AddRange(opening.IndexedLines.Select(p => p.Key)); - } - return allBoundaryPairs; + allBoundaryLines.AddRange(opening.IndexedLines.Select(p => p.Value)); } + return allBoundaryLines; + } - private List GetAllIndexPairs() + private List GetAllBoundaryIndexPairs() + { + var allBoundaryPairs = new List(); + allBoundaryPairs.AddRange(ExternalLoop.IndexedLines.Select(p => p.Key)); + foreach (var opening in Openings) { - var allPairs = new List(); - allPairs.AddRange(GetAllBoundaryIndexPairs()); - allPairs.AddRange(Internals.Select(i => i.Key)); - return allPairs; + allBoundaryPairs.AddRange(opening.IndexedLines.Select(p => p.Key)); } + return allBoundaryPairs; + } - private bool IntersectsBoundaryLines(Line2D line) + private List GetAllIndexPairs() + { + var allPairs = new List(); + allPairs.AddRange(GetAllBoundaryIndexPairs()); + allPairs.AddRange(Internals.Select(i => i.Key)); + return allPairs; + } + + private bool IntersectsBoundaryLines(Line2D line) + { + var allBoundaryLines = GetAllBoundaryLines(); + foreach (var bl in allBoundaryLines) { - var allBoundaryLines = GetAllBoundaryLines(); - foreach (var bl in allBoundaryLines) + if (bl.Intersects(line, tolerance)) { - if (bl.Intersects(line, tolerance)) - { - return true; - } + return true; } - - return false; } - private bool IntersectsInternalLines(Line2D line) + return false; + } + + private bool IntersectsInternalLines(Line2D line) + { + foreach (var ik in Internals.Keys) { - foreach (var ik in Internals.Keys) + if (Internals[ik].Intersects(line, tolerance)) { - if (Internals[ik].Intersects(line, tolerance)) - { - return true; - } + return true; } - - return false; } - //Because multiple points can be aligned along the same direction from any given point, a dictionary is returned where - //the (unit) vectors towards the points are the keys, and all points in that exact direction listed as the values - private Dictionary> PointIndicesSweep(int ptIndex, int nextPtIndex, int prevPtIndex, int windingDirection) + return false; + } + + //Because multiple points can be aligned along the same direction from any given point, a dictionary is returned where + //the (unit) vectors towards the points are the keys, and all points in that exact direction listed as the values + private Dictionary> PointIndicesSweep( + int ptIndex, + int nextPtIndex, + int prevPtIndex, + int windingDirection + ) + { + if (windingDirection == 0) { - if (windingDirection == 0) - { - return null; - } + return null; + } - var allPts = GetAllPts(); + var allPts = GetAllPts(); - var vCurrToNext = allPts[ptIndex].VectorTo(allPts[nextPtIndex]).Normalize(); - var vCurrToPrev = allPts[ptIndex].VectorTo(allPts[prevPtIndex]).Normalize(); + var vCurrToNext = allPts[ptIndex].VectorTo(allPts[nextPtIndex]).Normalize(); + var vCurrToPrev = allPts[ptIndex].VectorTo(allPts[prevPtIndex]).Normalize(); - var dict = new Dictionary>(); + var dict = new Dictionary>(); - for (var i = 0; i < allPts.Count(); i++) + for (var i = 0; i < allPts.Count(); i++) + { + if (i == ptIndex || i == nextPtIndex || i == prevPtIndex) { - if (i == ptIndex || i == nextPtIndex || i == prevPtIndex) continue; + continue; + } - var vItem = allPts[ptIndex].VectorTo(allPts[i]).Normalize(); + var vItem = allPts[ptIndex].VectorTo(allPts[i]).Normalize(); - //The swapping of the vectors below is to align with the fact that the vector angle comparison is always done anti-clockwise - var isBetween = (windingDirection > 0) ? vItem.IsBetweenVectors(vCurrToNext, vCurrToPrev) : vItem.IsBetweenVectors(vCurrToPrev, vCurrToNext); + //The swapping of the vectors below is to align with the fact that the vector angle comparison is always done anti-clockwise + var isBetween = + (windingDirection > 0) + ? vItem.IsBetweenVectors(vCurrToNext, vCurrToPrev) + : vItem.IsBetweenVectors(vCurrToPrev, vCurrToNext); - if (isBetween) + if (isBetween) + { + if (!dict.ContainsKey(vItem)) { - if (!dict.ContainsKey(vItem)) - { - dict.Add(vItem, new List()); - } - dict[vItem].Add(i); + dict.Add(vItem, new List()); } + dict[vItem].Add(i); } - return dict; } + return dict; } } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/TriangleIndexSet.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/TriangleIndexSet.cs index 0af87b3fc8..e74f3ed8ab 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/TriangleIndexSet.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/TriangleIndexSet.cs @@ -1,11 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +internal class TriangleIndexSet : IndexSet { - internal class TriangleIndexSet : IndexSet - { - public TriangleIndexSet(int index1, int index2, int index3) : base(new List() { index1, index2, index3 }) - { - } - } + public TriangleIndexSet(int index1, int index2, int index3) + : base(new List() { index1, index2, index3 }) { } } diff --git a/Objects/Converters/StructuralUtilities/PolygonMesher/Vertex.cs b/Objects/Converters/StructuralUtilities/PolygonMesher/Vertex.cs index 231050e91b..9a0625fc56 100644 --- a/Objects/Converters/StructuralUtilities/PolygonMesher/Vertex.cs +++ b/Objects/Converters/StructuralUtilities/PolygonMesher/Vertex.cs @@ -1,25 +1,22 @@ -using MathNet.Spatial.Euclidean; +using MathNet.Spatial.Euclidean; -namespace StructuralUtilities.PolygonMesher +namespace StructuralUtilities.PolygonMesher; + +internal class Vertex { - internal class Vertex + public int Index; + public Point2D Local; + public Point3D Global; + + public Vertex(int index, Point2D local, Point3D global) { - public int Index; - public Point2D Local; - public Point3D Global; - public Vertex(int index, Point2D local, Point3D global) - { - this.Local = local; - this.Index = index; - this.Global = global; - } + this.Local = local; + this.Index = index; + this.Global = global; + } - public double[] Coordinates - { - get - { - return new double[] { Global.X, Global.Y, Global.Z }; - } - } + public double[] Coordinates + { + get { return new double[] { Global.X, Global.Y, Global.Z }; } } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBolt.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBolt.cs index 47cf8a9bc9..2d55320bed 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBolt.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBolt.cs @@ -13,26 +13,17 @@ public abstract class AsteelBolt : Base, IAsteelObject public Base asteelProperties { get; set; } - public AsteelBolt() - { - - } + public AsteelBolt() { } } public class AsteelCircularBolt : AsteelBolt { //[SchemaInfo("AsteelCircularBolt", "Creates a Advance Steel circular bolt.", "Advance Steel", "Structure")] - public AsteelCircularBolt() - { - - } + public AsteelCircularBolt() { } } public class AsteelRectangularBolt : AsteelBolt { //[SchemaInfo("AsteelRectangularBolt", "Creates a Advance Steel rectangular bolt.", "Advance Steel", "Structure")] - public AsteelRectangularBolt() - { - - } + public AsteelRectangularBolt() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelGrating.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelGrating.cs index 60c46fc8c6..fac263aa0b 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelGrating.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelGrating.cs @@ -15,8 +15,5 @@ public class AsteelGrating : Base, IAsteelObject public Base asteelProperties { get; set; } //[SchemaInfo("AsteelGrating", "Creates a Advance Steel grating.", "Advance Steel", "Structure")] - public AsteelGrating() - { - - } + public AsteelGrating() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPlate.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPlate.cs index a587b4b098..60138a0c01 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPlate.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPlate.cs @@ -24,8 +24,5 @@ public AsteelPlate(Polyline outline, string units, StructuralMaterial material = this.units = units; } - - public AsteelPlate() - { - } + public AsteelPlate() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPolyBeam.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPolyBeam.cs index 819a77317e..8ba194b04c 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPolyBeam.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelPolyBeam.cs @@ -3,8 +3,5 @@ namespace Objects.BuiltElements.AdvanceSteel; public class AsteelPolyBeam : AsteelBeam { //[SchemaInfo("AsteelPolyBeam", "Creates a Advance Steel polybeam.", "Advance Steel", "Structure")] - public AsteelPolyBeam() - { - - } + public AsteelPolyBeam() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSlab.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSlab.cs index 8c218ca866..b7b4642d1c 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSlab.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSlab.cs @@ -24,8 +24,5 @@ public AsteelSlab(Polyline outline, string units, StructuralMaterial material = this.units = units; } - - public AsteelSlab() - { - } + public AsteelSlab() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSpecialPart.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSpecialPart.cs index e1e6218e04..f05b8155fb 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSpecialPart.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelSpecialPart.cs @@ -14,8 +14,5 @@ public class AsteelSpecialPart : Base, IAsteelObject public Base asteelProperties { get; set; } //[SchemaInfo("AsteelSpecialPart", "Creates a Advance Steel special part.", "Advance Steel", "Structure")] - public AsteelSpecialPart() - { - - } + public AsteelSpecialPart() { } } diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelStraightBeam.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelStraightBeam.cs index 753d85557e..0e548aae3a 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelStraightBeam.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelStraightBeam.cs @@ -3,8 +3,5 @@ namespace Objects.BuiltElements.AdvanceSteel; public class AsteelStraightBeam : AsteelBeam { //[SchemaInfo("AsteelStraightBeam", "Creates a Advance Steel straightBeam.", "Advance Steel", "Structure")] - public AsteelStraightBeam() - { - - } + public AsteelStraightBeam() { } } diff --git a/Objects/Objects/BuiltElements/Archicad/Classification.cs b/Objects/Objects/BuiltElements/Archicad/Classification.cs index adb5091f3a..38beb85d2b 100644 --- a/Objects/Objects/BuiltElements/Archicad/Classification.cs +++ b/Objects/Objects/BuiltElements/Archicad/Classification.cs @@ -4,22 +4,21 @@ using Speckle.Core.Kits; using Speckle.Core.Models; -namespace Objects.BuiltElements.Archicad -{ - public class Classification : Base - { - public Classification() { } +namespace Objects.BuiltElements.Archicad; - [SchemaInfo("Classification", "A classification to set on an element", "BIM", "All")] - public Classification(string system, string code = null, string name = null) - { - this.system = system; - this.code = code; - this.name = name; - } +public class Classification : Base +{ + public Classification() { } - public string system { get; set; } - public string ?code { get; set; } - public string ?name { get; set; } + [SchemaInfo("Classification", "A classification to set on an element", "BIM", "All")] + public Classification(string system, string code = null, string name = null) + { + this.system = system; + this.code = code; + this.name = name; } + + public string system { get; set; } + public string? code { get; set; } + public string? name { get; set; } } diff --git a/Objects/Objects/BuiltElements/Level.cs b/Objects/Objects/BuiltElements/Level.cs index 011865a6ea..928d3abbde 100644 --- a/Objects/Objects/BuiltElements/Level.cs +++ b/Objects/Objects/BuiltElements/Level.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Objects.Utils; using Speckle.Core.Kits; using Speckle.Core.Models; diff --git a/Objects/Objects/BuiltElements/Network.cs b/Objects/Objects/BuiltElements/Network.cs index 8b4aa0ebfe..e8201e13d1 100644 --- a/Objects/Objects/BuiltElements/Network.cs +++ b/Objects/Objects/BuiltElements/Network.cs @@ -15,8 +15,11 @@ namespace Objects.BuiltElements /// public class Network : Base { - [Obsolete("The Network was previously used to assemble MEP systems, but now MEP systems are assembled by the RevitCommitObjectBuilder as MEP elements are converted.")] + [Obsolete( + "The Network was previously used to assemble MEP systems, but now MEP systems are assembled by the RevitCommitObjectBuilder as MEP elements are converted." + )] public Network() { } + public string name { get; set; } /// @@ -34,6 +37,7 @@ public class NetworkElement : Base { [Obsolete("The NetworkElement class is obsolete because the Network class is now obsolete")] public NetworkElement() { } + public string name { get; set; } [DetachProperty] @@ -64,6 +68,7 @@ public class NetworkLink : Base { [Obsolete("The NetworkLink class is obsolete because the Network class is now obsolete")] public NetworkLink() { } + public string name { get; set; } /// @@ -88,6 +93,7 @@ public class RevitNetworkElement : NetworkElement { [Obsolete("The RevitNetworkElement class is obsolete because the Network class is now obsolete")] public RevitNetworkElement() { } + /// /// Indicates if this element was constructed from an MEP curve /// diff --git a/Objects/Objects/BuiltElements/Opening.cs b/Objects/Objects/BuiltElements/Opening.cs index 244b2ffeab..597024a55b 100644 --- a/Objects/Objects/BuiltElements/Opening.cs +++ b/Objects/Objects/BuiltElements/Opening.cs @@ -48,7 +48,10 @@ public RevitWallOpening() { } public RevitWallOpening(ICurve outline, RevitWall? host = null) { if (outline is not Polyline) + { throw new SpeckleException("Outline should be a rectangular-shaped polyline", false); + } + this.outline = outline; this.host = host; } @@ -57,9 +60,15 @@ public RevitWallOpening(ICurve outline, RevitWall? host = null) public RevitWallOpening(Polyline outline, RevitWall? host = null) { if (outline == null) + { throw new SpeckleException("Outline cannot be null"); + } + if (outline.GetPoints().Count != 4) + { throw new SpeckleException("Outline should be a rectangular-shaped polyline"); + } + this.outline = outline; this.host = host; } diff --git a/Objects/Objects/BuiltElements/Revit/FreeformElement.cs b/Objects/Objects/BuiltElements/Revit/FreeformElement.cs index 04c8212746..662440169c 100644 --- a/Objects/Objects/BuiltElements/Revit/FreeformElement.cs +++ b/Objects/Objects/BuiltElements/Revit/FreeformElement.cs @@ -25,7 +25,10 @@ public FreeformElement(List baseGeometries, string subcategory = "", List< //this.category = category; this.subcategory = subcategory; if (!IsValid()) + { throw new Exception("Freeform elements can only be created from BREPs or Meshes"); + } + this.parameters = parameters.ToBase(); } @@ -47,11 +50,17 @@ public Base baseGeometry set { if (baseGeometries == null) + { baseGeometries = new List { value }; + } else if (baseGeometries.Count == 0) + { baseGeometries.Add(value); + } else + { baseGeometries[0] = value; + } } } @@ -87,7 +96,10 @@ public bool IsValidObject(Base @base) public FreeformElement(Base baseGeometry, List parameters = null) { if (!IsValidObject(baseGeometry)) + { throw new Exception("Freeform elements can only be created from BREPs or Meshes"); + } + baseGeometries = new List { baseGeometry }; this.parameters = parameters.ToBase(); } @@ -105,7 +117,10 @@ public FreeformElement(List baseGeometries, List parameters = n { this.baseGeometries = baseGeometries; if (!IsValid()) + { throw new Exception("Freeform elements can only be created from BREPs or Meshes"); + } + this.parameters = parameters.ToBase(); } diff --git a/Objects/Objects/BuiltElements/Revit/Interfaces/IHasMEPConnectors.cs b/Objects/Objects/BuiltElements/Revit/Interfaces/IHasMEPConnectors.cs index 4d1805588d..19a3620b27 100644 --- a/Objects/Objects/BuiltElements/Revit/Interfaces/IHasMEPConnectors.cs +++ b/Objects/Objects/BuiltElements/Revit/Interfaces/IHasMEPConnectors.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace Objects.BuiltElements.Revit.Interfaces +namespace Objects.BuiltElements.Revit.Interfaces; + +public interface IHasMEPConnectors { - public interface IHasMEPConnectors - { - List Connectors { get; set; } - } + List Connectors { get; set; } } diff --git a/Objects/Objects/BuiltElements/Revit/MEPFamilyInstance.cs b/Objects/Objects/BuiltElements/Revit/MEPFamilyInstance.cs index 98abed5191..f90538ec9a 100644 --- a/Objects/Objects/BuiltElements/Revit/MEPFamilyInstance.cs +++ b/Objects/Objects/BuiltElements/Revit/MEPFamilyInstance.cs @@ -3,14 +3,13 @@ using Objects.Other.Revit; using Speckle.Core.Models; -namespace Objects.BuiltElements.Revit +namespace Objects.BuiltElements.Revit; + +public class RevitMEPFamilyInstance : RevitInstance, IHasMEPConnectors { - public class RevitMEPFamilyInstance : RevitInstance, IHasMEPConnectors - { - public string RevitPartType { get; set; } + public string RevitPartType { get; set; } - [DetachProperty] - public List Connectors { get; set; } = new(); - public List Curves { get; set; } = new(); - } + [DetachProperty] + public List Connectors { get; set; } = new(); + public List Curves { get; set; } = new(); } diff --git a/Objects/Objects/BuiltElements/Revit/RevitCurtainWallPanel.cs b/Objects/Objects/BuiltElements/Revit/RevitCurtainWallPanel.cs index a1b065104f..e3b331eb2d 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitCurtainWallPanel.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitCurtainWallPanel.cs @@ -2,9 +2,6 @@ using System.Collections.Generic; using System.Text; -namespace Objects.BuiltElements.Revit -{ - public class RevitCurtainWallPanel : RevitElement - { - } -} +namespace Objects.BuiltElements.Revit; + +public class RevitCurtainWallPanel : RevitElement { } diff --git a/Objects/Objects/BuiltElements/Revit/RevitMEPConnector.cs b/Objects/Objects/BuiltElements/Revit/RevitMEPConnector.cs index e0494f9bac..9ce825778a 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitMEPConnector.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitMEPConnector.cs @@ -4,17 +4,16 @@ using Objects.Organization; using Speckle.Core.Models; -namespace Objects.BuiltElements.Revit +namespace Objects.BuiltElements.Revit; + +public class RevitMEPConnector : Base { - public class RevitMEPConnector : Base - { - public double angle { get; set; } - public List connectedConnectorIds { get; set; } = new(); - public double height { get; set; } - public Point origin { get; set; } - public double radius { get; set; } - public string shape { get; set; } - public string systemName { get; set; } - public double width { get; set; } - } + public double angle { get; set; } + public List connectedConnectorIds { get; set; } = new(); + public double height { get; set; } + public Point origin { get; set; } + public double radius { get; set; } + public string shape { get; set; } + public string systemName { get; set; } + public double width { get; set; } } diff --git a/Objects/Objects/BuiltElements/Revit/RevitToposolid.cs b/Objects/Objects/BuiltElements/Revit/RevitToposolid.cs index 749332141b..f5ad34dab7 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitToposolid.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitToposolid.cs @@ -4,40 +4,40 @@ using Speckle.Core.Kits; using Speckle.Core.Models; -namespace Objects.BuiltElements.Revit +namespace Objects.BuiltElements.Revit; + +public class RevitToposolid : Base, IDisplayValue> { - public class RevitToposolid : Base, IDisplayValue> + public RevitToposolid() { } + + [SchemaInfo("RevitToposolid", "Creates a Revit Toposolid", "Revit", "Architecture")] + public RevitToposolid( + Level level, + List profiles, + List topPlanePoints = null, + [SchemaParamInfo("Any nested elements that this floor might have")] List elements = null, + List parameters = null + ) { - public RevitToposolid() { } - - [SchemaInfo("RevitToposolid", "Creates a Revit Toposolid", "Revit", "Architecture")] - public RevitToposolid( - Level level, - List profiles, - List topPlanePoints = null, - [SchemaParamInfo("Any nested elements that this floor might have")] - List elements = null, - List parameters = null - ) - { - this.profiles = profiles; - this.level = level; - this.points = topPlanePoints; - this.elements = elements; - this.parameters = parameters.ToBase(); - } - - public List profiles { get; set; } = new(); - - public List points { get; set; } = new(); - - [DetachProperty] public List elements { get; set; } - - [DetachProperty] public List displayValue { get; set; } - - public string family { get; set; } - public string type { get; set; } - public Level level { get; set; } - public Base parameters { get; set; } + this.profiles = profiles; + this.level = level; + this.points = topPlanePoints; + this.elements = elements; + this.parameters = parameters.ToBase(); } + + public List profiles { get; set; } = new(); + + public List points { get; set; } = new(); + + [DetachProperty] + public List elements { get; set; } + + [DetachProperty] + public List displayValue { get; set; } + + public string family { get; set; } + public string type { get; set; } + public Level level { get; set; } + public Base parameters { get; set; } } diff --git a/Objects/Objects/BuiltElements/Wall.cs b/Objects/Objects/BuiltElements/Wall.cs index 4a22055703..496270a81a 100644 --- a/Objects/Objects/BuiltElements/Wall.cs +++ b/Objects/Objects/BuiltElements/Wall.cs @@ -178,11 +178,16 @@ public RevitFaceWall( ) { if (surface.Surfaces.Count == 0) + { throw new Exception("Cannot create a RevitWall with an empty BREP"); + } + if (surface.Surfaces.Count > 1) + { throw new Exception( "The provided brep has more than 1 surface. Please deconstruct/explode it to create multiple instances" ); + } this.family = family; this.type = type; diff --git a/Objects/Objects/BuiltElements/Zone.cs b/Objects/Objects/BuiltElements/Zone.cs index 64d6f8b297..7bbaa1dffc 100644 --- a/Objects/Objects/BuiltElements/Zone.cs +++ b/Objects/Objects/BuiltElements/Zone.cs @@ -8,7 +8,7 @@ namespace Objects.BuiltElements public class Zone : Base, IHasArea, IHasVolume { public Zone() { } - + public Zone(string name) { this.name = name; @@ -16,9 +16,9 @@ public Zone(string name) public string name { get; set; } public string units { get; set; } - + public List spaces { get; set; } - + // implicit measurements public double area { get; set; } public double volume { get; set; } diff --git a/Objects/Objects/GIS/GisTopography.cs b/Objects/Objects/GIS/GisTopography.cs index 0b05a4719c..502dd0c013 100644 --- a/Objects/Objects/GIS/GisTopography.cs +++ b/Objects/Objects/GIS/GisTopography.cs @@ -4,18 +4,17 @@ using Objects.Geometry; using Speckle.Core.Models; -namespace Objects.GIS +namespace Objects.GIS; + +public class GisTopography : Topography { - public class GisTopography : Topography - { - public int band_count { get; set; } - public List band_names { get; set; } - public float x_origin { get; set; } - public float y_origin { get; set; } - public int x_size { get; set; } - public int y_size { get; set; } - public float x_resolution { get; set; } - public float y_resolution { get; set; } - public List noDataValue { get; set; } - } + public int band_count { get; set; } + public List band_names { get; set; } + public float x_origin { get; set; } + public float y_origin { get; set; } + public int x_size { get; set; } + public int y_size { get; set; } + public float x_resolution { get; set; } + public float y_resolution { get; set; } + public List noDataValue { get; set; } } diff --git a/Objects/Objects/GIS/PolygonElement.cs b/Objects/Objects/GIS/PolygonElement.cs index 5f2092e95c..a1c35db2b8 100644 --- a/Objects/Objects/GIS/PolygonElement.cs +++ b/Objects/Objects/GIS/PolygonElement.cs @@ -2,12 +2,11 @@ using Objects.BuiltElements.Revit; using Speckle.Core.Models; -namespace Objects.GIS +namespace Objects.GIS; + +public class PolygonElement : Base { - public class PolygonElement : Base - { - [DetachProperty] - public List geometry { get; set; } - public Base attributes { get; set; } - } + [DetachProperty] + public List geometry { get; set; } + public Base attributes { get; set; } } diff --git a/Objects/Objects/Geometry/Arc.cs b/Objects/Objects/Geometry/Arc.cs index e9e32b1b44..630fd37012 100644 --- a/Objects/Objects/Geometry/Arc.cs +++ b/Objects/Objects/Geometry/Arc.cs @@ -92,9 +92,14 @@ public Arc( { // don't be annoying if (angleRadians > Math.PI * 2) + { throw new SpeckleException("Can't create an arc with an angle greater than 2pi"); + } + if (startPoint == endPoint) + { throw new SpeckleException("Can't create an arc where the start and end points are the same"); + } this.units = units; this.startPoint = startPoint; @@ -107,9 +112,13 @@ public Arc( var chordLength = Point.Distance(startPoint, endPoint); var chordAngle = angleRadians; if (chordAngle > Math.PI) + { chordAngle -= Math.PI * 2; + } else if (chordAngle < -Math.PI) + { chordAngle += Math.PI * 2; + } // use the law of cosines for an isosceles triangle to get the radius radius = chordLength / Math.Sqrt(2 - 2 * Math.Cos(chordAngle)); @@ -130,11 +139,18 @@ public Arc( // find the start angle using trig (correcting for quadrant position) and add the arc angle to get the end angle startAngle = Math.Tan((startPoint.y - circleCentre.y) / (startPoint.x - circleCentre.x)) % (2 * Math.PI); if (startPoint.x > circleCentre.x && startPoint.y < circleCentre.y) // Q4 + { startAngle *= -1; + } else if (startPoint.x < circleCentre.x && startPoint.y < circleCentre.y) // Q3 + { startAngle += Math.PI; + } else if (startPoint.x < circleCentre.x && startPoint.y > circleCentre.y) // Q2 + { startAngle = Math.PI - startAngle; + } + endAngle = startAngle + angleRadians; // Set the plane of this arc this.plane = plane; diff --git a/Objects/Objects/Geometry/Brep.cs b/Objects/Objects/Geometry/Brep.cs index cd511c3268..a19241d886 100644 --- a/Objects/Objects/Geometry/Brep.cs +++ b/Objects/Objects/Geometry/Brep.cs @@ -72,15 +72,22 @@ public List SurfacesValue { var list = new List(); if (Surfaces != null) + { foreach (var srf in Surfaces) + { list.AddRange(srf.ToList()); + } + } return list; } set { if (value == null) + { return; + } + var list = new List(); var done = false; var currentIndex = 0; @@ -115,7 +122,9 @@ public List Curve3DValues set { if (value != null) + { Curve3D = CurveArrayEncodingExtensions.FromArray(value); + } } } @@ -138,7 +147,9 @@ public List Curve2DValues set { if (value != null) + { Curve2D = CurveArrayEncodingExtensions.FromArray(value); + } } } @@ -162,7 +173,9 @@ public List VerticesValue var list = new List(); list.Add(Units.GetEncodingFromUnit(units)); foreach (var vertex in Vertices) + { list.AddRange(vertex.ToList()); + } return list; } @@ -172,7 +185,9 @@ public List VerticesValue { var units = value.Count % 3 == 0 ? Units.None : Units.GetUnitFromEncoding(value[0]); for (int i = value.Count % 3 == 0 ? 0 : 1; i < value.Count; i += 3) + { Vertices.Add(new Point(value[i], value[i + 1], value[i + 2], units)); + } } } } @@ -211,7 +226,10 @@ public List EdgesValue { Edges = new List(); if (value == null || value.Count == 0) + { return; + } + var i = 0; while (i < value.Count) { @@ -226,7 +244,10 @@ public List EdgesValue var domainEnd = loopValues[5]; Interval domain = null; if (domainStart.HasValue && domainEnd.HasValue) + { domain = new Interval(domainStart.Value, domainEnd.Value); + } + var trimIndices = loopValues.GetRange(6, loopValues.Count - 6).Select(d => Convert.ToInt32(d)).ToArray(); var edge = new BrepEdge(this, curve3dIndex, trimIndices, startIndex, endIndex, proxyReversed, domain); @@ -266,7 +287,10 @@ public List LoopsValue { Loops = new List(); if (value == null || value.Count == 0) + { return; + } + var i = 0; while (i < value.Count) { @@ -319,7 +343,10 @@ public List TrimsValue set { if (value == null) + { return; + } + var list = new List(); for (int i = 0; i < value.Count; i += 9) { @@ -373,7 +400,10 @@ public List FacesValue { Faces = new List(); if (value == null || value.Count == 0) + { return; + } + var i = 0; while (i < value.Count) { @@ -437,6 +467,7 @@ public bool TransformTo(Transform transform, out Brep brep) var success3D = true; var transformedCurve3D = new List(); foreach (var curve in Curve3D) + { if (curve is ITransformable c) { c.TransformTo(transform, out ITransformable tc); @@ -446,6 +477,7 @@ public bool TransformTo(Transform transform, out Brep brep) { success3D = false; } + } // transform vertices var transformedVertices = new List(); @@ -474,14 +506,19 @@ public bool TransformTo(Transform transform, out Brep brep) }; foreach (var e in Edges) + { brep.Edges.Add( new BrepEdge(brep, e.Curve3dIndex, e.TrimIndices, e.StartIndex, e.EndIndex, e.ProxyCurveIsReversed, e.Domain) ); + } foreach (var l in Loops) + { brep.Loops.Add(new BrepLoop(brep, l.FaceIndex, l.TrimIndices, l.Type)); + } foreach (var t in Trims) + { brep.Trims.Add( new BrepTrim( brep, @@ -496,9 +533,12 @@ public bool TransformTo(Transform transform, out Brep brep) t.EndIndex ) ); + } foreach (var f in Faces) + { brep.Faces.Add(new BrepFace(brep, f.SurfaceIndex, f.LoopIndices, f.OuterLoopIndex, f.OrientationReversed)); + } return success3D; } @@ -520,6 +560,7 @@ internal void OnDeserialized(StreamingContext context) { var e = Edges[i]; lock (e) + { if (e.Brep != null) { e = new BrepEdge( @@ -537,12 +578,14 @@ internal void OnDeserialized(StreamingContext context) { e.Brep = this; } + } } for (var i = 0; i < Loops.Count; i++) { var l = Loops[i]; lock (l) + { if (l.Brep != null) { l = new BrepLoop(this, l.FaceIndex, l.TrimIndices, l.Type); @@ -552,12 +595,14 @@ internal void OnDeserialized(StreamingContext context) { l.Brep = this; } + } } for (var i = 0; i < Trims.Count; i++) { var t = Trims[i]; lock (t) + { if (t.Brep != null) { t = new BrepTrim( @@ -578,12 +623,14 @@ internal void OnDeserialized(StreamingContext context) { t.Brep = this; } + } } for (var i = 0; i < Faces.Count; i++) { var f = Faces[i]; lock (f) + { if (f.Brep != null) { f = new BrepFace(this, f.SurfaceIndex, f.LoopIndices, f.OuterLoopIndex, f.OrientationReversed); @@ -593,6 +640,7 @@ internal void OnDeserialized(StreamingContext context) { f.Brep = this; } + } } } } diff --git a/Objects/Objects/Geometry/Curve.cs b/Objects/Objects/Geometry/Curve.cs index faca5821b2..50ef8a3207 100644 --- a/Objects/Objects/Geometry/Curve.cs +++ b/Objects/Objects/Geometry/Curve.cs @@ -119,13 +119,18 @@ public bool TransformTo(Transform transform, out ITransformable transformed) public List GetPoints() { if (points.Count % 3 != 0) + { throw new SpeckleException( $"{nameof(Curve)}.{nameof(points)} list is malformed: expected length to be multiple of 3" ); + } var pts = new List(points.Count / 3); for (int i = 2; i < points.Count; i += 3) + { pts.Add(new Point(points[i - 2], points[i - 1], points[i], units)); + } + return pts; } @@ -166,9 +171,14 @@ public List ToList() public static Curve FromList(List list) { if (list[0] != list.Count - 1) + { throw new Exception($"Incorrect length. Expected {list[0]}, got {list.Count}."); + } + if (list[1] != CurveTypeEncoding.Curve) + { throw new Exception($"Wrong curve type. Expected {CurveTypeEncoding.Curve}, got {list[1]}."); + } var curve = new Curve(); curve.degree = (int)list[2]; diff --git a/Objects/Objects/Geometry/Line.cs b/Objects/Objects/Geometry/Line.cs index de0eb089e7..ab20f49ed7 100644 --- a/Objects/Objects/Geometry/Line.cs +++ b/Objects/Objects/Geometry/Line.cs @@ -34,7 +34,10 @@ public Line(Point start, Point end, string units = Units.Meters, string applicat public Line(IList coordinates, string units = Units.Meters, string applicationId = null) { if (coordinates.Count < 6) + { throw new SpeckleException("Line from coordinate array requires 6 coordinates."); + } + start = new Point(coordinates[0], coordinates[1], coordinates[2], units, applicationId); end = new Point(coordinates[3], coordinates[4], coordinates[5], units, applicationId); length = Point.Distance(start, end); @@ -58,7 +61,10 @@ public List value set { if (value == null) + { return; + } + start = new Point(value[0], value[1], value[2]); end = new Point(value[3], value[4], value[5]); } diff --git a/Objects/Objects/Geometry/Mesh.cs b/Objects/Objects/Geometry/Mesh.cs index 17e823e4cb..39ed58cf76 100644 --- a/Objects/Objects/Geometry/Mesh.cs +++ b/Objects/Objects/Geometry/Mesh.cs @@ -150,13 +150,18 @@ public Point GetPoint(int index) public List GetPoints() { if (vertices.Count % 3 != 0) + { throw new SpeckleException( $"{nameof(Mesh)}.{nameof(vertices)} list is malformed: expected length to be multiple of 3" ); + } var pts = new List(vertices.Count / 3); for (int i = 2; i < vertices.Count; i += 3) + { pts.Add(new Point(vertices[i - 2], vertices[i - 1], vertices[i], units)); + } + return pts; } @@ -187,9 +192,14 @@ public List GetPoints() public void AlignVerticesWithTexCoordsByIndex() { if (textureCoordinates.Count == 0) + { return; + } + if (TextureCoordinatesCount == VerticesCount) + { return; //Tex-coords already aligned as expected + } var facesUnique = new List(faces.Count); var verticesUnique = new List(TextureCoordinatesCount * 3); @@ -201,10 +211,14 @@ public void AlignVerticesWithTexCoordsByIndex() { int n = faces[nIndex]; if (n < 3) + { n += 3; // 0 -> 3, 1 -> 4 + } if (nIndex + n >= faces.Count) + { break; //Malformed face list + } facesUnique.Add(n); for (int i = 1; i <= n; i++) diff --git a/Objects/Objects/Geometry/Point.cs b/Objects/Objects/Geometry/Point.cs index 3335c28134..cb294a817b 100644 --- a/Objects/Objects/Geometry/Point.cs +++ b/Objects/Objects/Geometry/Point.cs @@ -178,9 +178,14 @@ public void Deconstruct(out double x, out double y, out double z) public static bool operator ==(Point? point1, Point? point2) { if (point1 is null && point2 is null) + { return true; + } + if (point1 is null ^ point2 is null) + { return false; + } return point1.units == point2.units && point1.x == point2.x && point1.y == point2.y && point1.z == point2.z; } @@ -237,10 +242,14 @@ public static Point Add(Point left, Point right) public override bool Equals(object obj) { if (ReferenceEquals(this, obj)) + { return true; + } if (ReferenceEquals(obj, null)) + { return false; + } throw new NotImplementedException(); } diff --git a/Objects/Objects/Geometry/Pointcloud.cs b/Objects/Objects/Geometry/Pointcloud.cs index fed6da296d..57be11f182 100644 --- a/Objects/Objects/Geometry/Pointcloud.cs +++ b/Objects/Objects/Geometry/Pointcloud.cs @@ -91,13 +91,18 @@ public bool TransformTo(Transform transform, out ITransformable transformed) public List GetPoints() { if (points.Count % 3 != 0) + { throw new SpeckleException( $"{nameof(Pointcloud)}.{nameof(points)} list is malformed: expected length to be multiple of 3" ); + } var pts = new List(points.Count / 3); for (int i = 2; i < points.Count; i += 3) + { pts.Add(new Point(points[i - 2], points[i - 1], points[i], units)); + } + return pts; } } diff --git a/Objects/Objects/Geometry/Polycurve.cs b/Objects/Objects/Geometry/Polycurve.cs index 2d81d46253..6082eceedd 100644 --- a/Objects/Objects/Geometry/Polycurve.cs +++ b/Objects/Objects/Geometry/Polycurve.cs @@ -66,6 +66,7 @@ public bool TransformTo(Transform transform, out ITransformable polycurve) var success = true; var transformed = new List(); foreach (var curve in segments) + { if (curve is ITransformable c) { c.TransformTo(transform, out ITransformable tc); @@ -75,6 +76,7 @@ public bool TransformTo(Transform transform, out ITransformable polycurve) { success = false; } + } polycurve = new Polycurve { diff --git a/Objects/Objects/Geometry/Polyline.cs b/Objects/Objects/Geometry/Polyline.cs index 3d9e44f0a6..49b8bd3b83 100644 --- a/Objects/Objects/Geometry/Polyline.cs +++ b/Objects/Objects/Geometry/Polyline.cs @@ -70,7 +70,10 @@ public Polyline(List coordinates, string units = Units.Meters, string ap public object ToType(Type conversionType, IFormatProvider provider) { if (conversionType == typeof(Polycurve)) + { return (Polycurve)this; + } + throw new InvalidCastException(); } @@ -212,13 +215,18 @@ public bool TransformTo(Transform transform, out ITransformable polyline) public List GetPoints() { if (value.Count % 3 != 0) + { throw new SpeckleException( $"{nameof(Polyline)}.{nameof(value)} list is malformed: expected length to be multiple of 3" ); + } var pts = new List(value.Count / 3); for (int i = 2; i < value.Count; i += 3) + { pts.Add(new Point(value[i - 2], value[i - 1], value[i], units)); + } + return pts; } diff --git a/Objects/Objects/Geometry/PolylineExtensions.cs b/Objects/Objects/Geometry/PolylineExtensions.cs index 249fb9149b..d02cc07d84 100644 --- a/Objects/Objects/Geometry/PolylineExtensions.cs +++ b/Objects/Objects/Geometry/PolylineExtensions.cs @@ -2,24 +2,23 @@ using System.Collections.Generic; using System.Text; -namespace Objects.Geometry +namespace Objects.Geometry; + +public static class PolylineExtensions { - public static class PolylineExtensions + public static IEnumerable EnumerateAsLines(this Polyline polyline) { - public static IEnumerable EnumerateAsLines(this Polyline polyline) + List points = polyline.GetPoints(); + if (points.Count == 0) { - List points = polyline.GetPoints(); - if (points.Count == 0) - { - yield break; - } + yield break; + } - Point previousPoint = points[0]; - for (int i = 1; i < points.Count; i++) - { - yield return new Line(previousPoint, points[i], polyline.units); - previousPoint = points[i]; - } + Point previousPoint = points[0]; + for (int i = 1; i < points.Count; i++) + { + yield return new Line(previousPoint, points[i], polyline.units); + previousPoint = points[i]; } } } diff --git a/Objects/Objects/Geometry/Surface.cs b/Objects/Objects/Geometry/Surface.cs index a98e788997..a4b4c1597d 100644 --- a/Objects/Objects/Geometry/Surface.cs +++ b/Objects/Objects/Geometry/Surface.cs @@ -108,11 +108,13 @@ public bool TransformTo(Transform transform, out Surface surface) { var ptMatrix = GetControlPoints(); foreach (var ctrlPts in ptMatrix) + { for (int i = 0; i < ctrlPts.Count; i++) { ctrlPts[i].TransformTo(transform, out var tPt); ctrlPts[i] = tPt; } + } surface = new Surface { @@ -152,7 +154,9 @@ public List> GetControlPoints() { var matrix = new List>(); for (var i = 0; i < countU; i++) + { matrix.Add(new List()); + } for (var i = 0; i < pointData.Count; i += 4) { diff --git a/Objects/Objects/Geometry/Vector.cs b/Objects/Objects/Geometry/Vector.cs index 15fac44ba8..5c5a4aa4bf 100644 --- a/Objects/Objects/Geometry/Vector.cs +++ b/Objects/Objects/Geometry/Vector.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Objects.Other; using Speckle.Core.Kits; diff --git a/Objects/Objects/ObjectsKit.cs b/Objects/Objects/ObjectsKit.cs index ed1b16856c..a0cde7918b 100644 --- a/Objects/Objects/ObjectsKit.cs +++ b/Objects/Objects/ObjectsKit.cs @@ -59,7 +59,9 @@ public ISpeckleConverter LoadConverter(string app) { _converters = GetAvailableConverters(); if (_loadedConverters.TryGetValue(app, out Type t)) + { return (ISpeckleConverter)Activator.CreateInstance(t); + } var converterInstance = LoadConverterFromDisk(app); _loadedConverters[app] = converterInstance.GetType(); @@ -81,17 +83,25 @@ private static ISpeckleConverter LoadConverterFromDisk(string app) //fallback to the default folder, in case the Objects.dll was loaded in the app domain for other reasons if (!File.Exists(path)) + { path = Path.Combine(ObjectsFolder, $"Objects.Converter.{app}.dll"); + } if (!File.Exists(path)) + { throw new FileNotFoundException($"Converter for {app} was not found in kit {basePath}", path); + } AssemblyName assemblyToLoad = AssemblyName.GetAssemblyName(path); var objects = Assembly.GetExecutingAssembly().GetName(); //only get assemblies matching the Major and Minor version of Objects if (assemblyToLoad.Version.Major != objects.Version.Major || assemblyToLoad.Version.Minor != objects.Version.Minor) - throw new SpeckleException($"Mismatch between Objects library v{objects.Version} Converter v{assemblyToLoad.Version}.\nEnsure the same 2.x version of Speckle connectors is installed."); + { + throw new SpeckleException( + $"Mismatch between Objects library v{objects.Version} Converter v{assemblyToLoad.Version}.\nEnsure the same 2.x version of Speckle connectors is installed." + ); + } var assembly = Assembly.LoadFrom(path); @@ -102,7 +112,9 @@ private static ISpeckleConverter LoadConverterFromDisk(string app) .FirstOrDefault(converter => converter.GetServicedApplications().Contains(app)); if (converterInstance == null) + { throw new SpeckleException($"No suitable converter instance found for {app}"); + } SpeckleLog.Logger .ForContext() @@ -120,7 +132,9 @@ public List GetAvailableConverters() //fallback to the default folder, in case the Objects.dll was loaded in the app domain for other reasons if (!allConverters.Any()) + { allConverters = Directory.EnumerateFiles(ObjectsFolder, "Objects.Converter.*.dll"); + } //only get assemblies matching the Major and Minor version of Objects var objects = Assembly.GetExecutingAssembly().GetName(); @@ -129,7 +143,9 @@ public List GetAvailableConverters() { AssemblyName assemblyName = AssemblyName.GetAssemblyName(converter); if (assemblyName.Version.Major == objects.Version.Major && assemblyName.Version.Minor == objects.Version.Minor) + { availableConverters.Add(converter); + } } return availableConverters.Select(dllPath => dllPath.Split('.').Reverse().ElementAt(1)).ToList(); diff --git a/Objects/Objects/Organization/DataTable.cs b/Objects/Objects/Organization/DataTable.cs index bd9af02b0b..10d83f4b29 100644 --- a/Objects/Objects/Organization/DataTable.cs +++ b/Objects/Objects/Organization/DataTable.cs @@ -4,39 +4,43 @@ using Speckle.Core.Models; using Speckle.Newtonsoft.Json; -namespace Objects.Organization +namespace Objects.Organization; + +public class DataTable : Base { - public class DataTable : Base - { - public DataTable() { } - public int columnCount => columnMetadata.Count; - public int rowCount => rowMetadata.Count; - public int headerRowIndex { get; set; } - public string name { get; set; } - public List rowMetadata { get; set; } = new List(); - public List columnMetadata { get; set; } = new List(); - public List> data { get; set; } = new List>(); + public DataTable() { } - public void AddRow(Base metadata, int index = -1, params object[] objects) - { - if (objects.Length != columnCount) - throw new ArgumentException($"\"AddRow\" method was passed {objects.Length} objects, but the DataTable has {columnCount} columns. Partial and extended table rows are not accepted by the DataTable object."); + public int columnCount => columnMetadata.Count; + public int rowCount => rowMetadata.Count; + public int headerRowIndex { get; set; } + public string name { get; set; } + public List rowMetadata { get; set; } = new List(); + public List columnMetadata { get; set; } = new List(); + public List> data { get; set; } = new List>(); - if (index < 0 || index >= data.Count) - { - data.Add(objects.ToList()); - rowMetadata.Add(metadata); - } - else - { - data.Insert(index, objects.ToList()); - rowMetadata.Insert(index, metadata); - } + public void AddRow(Base metadata, int index = -1, params object[] objects) + { + if (objects.Length != columnCount) + { + throw new ArgumentException( + $"\"AddRow\" method was passed {objects.Length} objects, but the DataTable has {columnCount} columns. Partial and extended table rows are not accepted by the DataTable object." + ); } - public void DefineColumn(Base metadata) + if (index < 0 || index >= data.Count) { - columnMetadata.Add(metadata); + data.Add(objects.ToList()); + rowMetadata.Add(metadata); } + else + { + data.Insert(index, objects.ToList()); + rowMetadata.Insert(index, metadata); + } + } + + public void DefineColumn(Base metadata) + { + columnMetadata.Add(metadata); } } diff --git a/Objects/Objects/Organization/Deprecated/Collection.cs b/Objects/Objects/Organization/Deprecated/Collection.cs index 09654649e1..6c05f15ec1 100644 --- a/Objects/Objects/Organization/Deprecated/Collection.cs +++ b/Objects/Objects/Organization/Deprecated/Collection.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Objects.Organization.Deprecated; diff --git a/Objects/Objects/Other/Instance.cs b/Objects/Objects/Other/Instance.cs index 4022a9131a..436a5d06b1 100644 --- a/Objects/Objects/Other/Instance.cs +++ b/Objects/Objects/Other/Instance.cs @@ -43,7 +43,8 @@ protected virtual IEnumerable GetTransformableGeometry() .When(DefaultTraversal.HasDisplayValue) .ContinueTraversing(_ => DefaultTraversal.displayValueAndElementsPropAliases); - var instanceRule = TraversalRule.NewTraversalRule() + var instanceRule = TraversalRule + .NewTraversalRule() .When(b => b is Instance instance && instance != null) .ContinueTraversing(DefaultTraversal.None); @@ -66,7 +67,7 @@ public virtual IEnumerable GetTransformedGeometry() { case Instance i: return i.GetTransformedGeometry() - .Select(b => + .Select(b => { b.TransformTo(transform, out var tranformed); return tranformed; @@ -107,7 +108,9 @@ public override Base definition internal set { if (value is T type) + { typedDefinition = type; + } } } } @@ -178,7 +181,10 @@ protected override IEnumerable GetTransformableGeometry() { var allChildren = typedDefinition.elements ?? new List(); if (typedDefinition.displayValue.Any()) + { allChildren.AddRange(typedDefinition.displayValue); + } + return allChildren; } @@ -190,12 +196,16 @@ public override IEnumerable GetTransformedGeometry() // add any dynamically attached elements on this instance var elements = (this["elements"] ?? this["@elements"]) as List; if (elements != null) + { foreach (var element in elements) { var display = ((Base)element)["displayValue"] as List; if (display != null) + { transformed.AddRange(display.Cast()); + } } + } return transformed; } diff --git a/Objects/Objects/Other/MappedBlockWrapper.cs b/Objects/Objects/Other/MappedBlockWrapper.cs index 3609bfb8de..28daba64f8 100644 --- a/Objects/Objects/Other/MappedBlockWrapper.cs +++ b/Objects/Objects/Other/MappedBlockWrapper.cs @@ -1,4 +1,4 @@ -using Objects.BuiltElements.Revit; +using Objects.BuiltElements.Revit; using Speckle.Core.Models; namespace Objects.Other; diff --git a/Objects/Objects/Other/Transform.cs b/Objects/Objects/Other/Transform.cs index 2a1b130365..0d153a7902 100644 --- a/Objects/Objects/Other/Transform.cs +++ b/Objects/Objects/Other/Transform.cs @@ -26,10 +26,12 @@ public Transform() { } public Transform(double[] value, string units = null) { if (value.Length != 16) + { throw new ArgumentException( $"{nameof(Transform)}.{nameof(value)} array is malformed: expected length to be 16", nameof(value) ); + } matrix = CreateMatrix(value); this.units = units; @@ -44,7 +46,9 @@ public Transform(double[] value, string units = null) public Transform(float[] value, string units = null) { if (value.Length != 16) + { throw new SpeckleException($"{nameof(Transform)}.{nameof(value)} array is malformed: expected length to be 16"); + } matrix = CreateMatrix(value); this.units = units; @@ -189,7 +193,9 @@ private static Quaternion LookRotation(Vector3 forward, Vector3 up) public double[] ConvertToUnits(string newUnits) { if (newUnits == null || units == null) + { return ToArray(); + } var sf = Units.GetConversionFactor(units, newUnits); @@ -335,9 +341,11 @@ public double rotationZ public List ApplyToPoints(List points) { if (points.Count % 3 != 0) + { throw new SpeckleException( "Cannot apply transform as the points list is malformed: expected length to be multiple of 3" ); + } var transformed = new List(points.Count); for (var i = 0; i < points.Count; i += 3) @@ -371,7 +379,9 @@ public List ApplyToPoints(List points) public Point ApplyToPoint(Point point) { if (point == null) + { return null; + } point.TransformTo(this, out Point transformedPoint); return transformedPoint; @@ -408,7 +418,9 @@ public List ApplyToVector(List vector) var newPoint = new List(); for (var i = 0; i < 12; i += 4) + { newPoint.Add(vector[0] * value[i] + vector[1] * value[i + 1] + vector[2] * value[i + 2]); + } return newPoint; } @@ -424,6 +436,7 @@ public List ApplyToCurves(List curves, out bool success) success = true; var transformed = new List(); foreach (var curve in curves) + { if (curve is ITransformable c) { c.TransformTo(this, out ITransformable tc); @@ -433,6 +446,7 @@ public List ApplyToCurves(List curves, out bool success) { success = false; } + } return transformed; } diff --git a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement1D.cs b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement1D.cs index 9d2fbd04e8..1698bb0caa 100644 --- a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement1D.cs +++ b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement1D.cs @@ -118,6 +118,7 @@ public CSIElement1D() { } public string SpandrelAssignment { get; set; } public double[]? Modifiers { get; set; } public DesignProcedure DesignProcedure { get; set; } + [DetachProperty] public AnalyticalResults? AnalysisResults { get; set; } } diff --git a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement2D.cs b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement2D.cs index 8eb58fe426..0b13cf6cd9 100644 --- a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement2D.cs +++ b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSIElement2D.cs @@ -45,6 +45,7 @@ public CSIElement2D() { } public string? SpandrelAssignment { get; set; } public double[]? modifiers { get; set; } public bool Opening { get; set; } + [DetachProperty] public AnalyticalResults? AnalysisResults { get; set; } } diff --git a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSINode.cs b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSINode.cs index 3467442ff2..95bff5b539 100644 --- a/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSINode.cs +++ b/Objects/Objects/Structural/ApplicationSpecific/ETABS/Geometry/CSINode.cs @@ -56,6 +56,7 @@ public CSINode() { } public string? DiaphragmAssignment { get; set; } public DiaphragmOption DiaphragmOption { get; set; } + [DetachProperty] public AnalyticalResults? AnalysisResults { get; set; } } diff --git a/Objects/Objects/Structural/ApplicationSpecific/GSA/Analysis/GSAAnalysisCase.cs b/Objects/Objects/Structural/ApplicationSpecific/GSA/Analysis/GSAAnalysisCase.cs index 0e2dcf9371..09390a024c 100644 --- a/Objects/Objects/Structural/ApplicationSpecific/GSA/Analysis/GSAAnalysisCase.cs +++ b/Objects/Objects/Structural/ApplicationSpecific/GSA/Analysis/GSAAnalysisCase.cs @@ -20,7 +20,10 @@ public GSAAnalysisCase( ) { if (loadCases.Count != loadFactors.Count) + { throw new ArgumentException("Number of load cases provided does not match number of load factors provided"); + } + this.nativeId = nativeId; this.name = name; this.task = task; diff --git a/Objects/Objects/Structural/ApplicationSpecific/GSA/Loading/GSALoadCombination.cs b/Objects/Objects/Structural/ApplicationSpecific/GSA/Loading/GSALoadCombination.cs index 356528b5c2..7adedb0242 100644 --- a/Objects/Objects/Structural/ApplicationSpecific/GSA/Loading/GSALoadCombination.cs +++ b/Objects/Objects/Structural/ApplicationSpecific/GSA/Loading/GSALoadCombination.cs @@ -22,7 +22,9 @@ public GSALoadCombination( this.name = name; if (loadCases.Count != loadFactors.Count) + { throw new ArgumentException("Number of load cases provided does not match number of load factors provided"); + } this.loadFactors = loadFactors; this.loadCases = loadCases; diff --git a/Objects/Objects/Structural/Geometry/Restraint.cs b/Objects/Objects/Structural/Geometry/Restraint.cs index 237c186789..a803832491 100644 --- a/Objects/Objects/Structural/Geometry/Restraint.cs +++ b/Objects/Objects/Structural/Geometry/Restraint.cs @@ -57,13 +57,24 @@ public Restraint( public Restraint(RestraintType restraintType) { if (restraintType == RestraintType.Free) + { code = "RRRRRR"; + } + if (restraintType == RestraintType.Pinned) + { code = "FFFRRR"; + } + if (restraintType == RestraintType.Fixed) + { code = "FFFFFF"; + } + if (restraintType == RestraintType.Roller) + { code = "RRFRRR"; + } } public string code { get; set; } //a string to describe the restraint type for each degree of freedom - ex. FFFRRR (pin) / FFFFFF (fix) diff --git a/Objects/Objects/Structural/Loading/LoadCombination.cs b/Objects/Objects/Structural/Loading/LoadCombination.cs index 82cf7ce829..cd3e810884 100644 --- a/Objects/Objects/Structural/Loading/LoadCombination.cs +++ b/Objects/Objects/Structural/Loading/LoadCombination.cs @@ -25,7 +25,9 @@ CombinationType combinationType ) { if (loadCases.Count != loadFactors.Count) + { throw new ArgumentException("Number of load cases provided does not match number of load factors provided"); + } this.name = name; this.loadCases = loadCases; diff --git a/Objects/Objects/Structural/Results/AnalyticalResults.cs b/Objects/Objects/Structural/Results/AnalyticalResults.cs index aa1f910e8a..9c39b6fb91 100644 --- a/Objects/Objects/Structural/Results/AnalyticalResults.cs +++ b/Objects/Objects/Structural/Results/AnalyticalResults.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using Speckle.Core.Models; -namespace Objects.Structural.Results +namespace Objects.Structural.Results; + +public class AnalyticalResults : Base { - public class AnalyticalResults : Base - { - public string? lengthUnits { get; set; } - public string? forceUnits { get; set; } - [DetachProperty] - public List resultsByLoadCombination { get; set; } - } + public string? lengthUnits { get; set; } + public string? forceUnits { get; set; } + + [DetachProperty] + public List resultsByLoadCombination { get; set; } } diff --git a/Objects/Objects/Utils/EncodingOptimisations.cs b/Objects/Objects/Utils/EncodingOptimisations.cs index 69e5618c4f..1db99a56ce 100644 --- a/Objects/Objects/Utils/EncodingOptimisations.cs +++ b/Objects/Objects/Utils/EncodingOptimisations.cs @@ -21,6 +21,7 @@ public static List ToArray(List curves) { var list = new List(); foreach (var curve in curves) + { switch (curve) { case Arc a: @@ -47,6 +48,7 @@ public static List ToArray(List curves) default: throw new Exception($"Unkown curve type: {curve.GetType()}."); } + } return list; } @@ -55,7 +57,10 @@ public static List FromArray(List list) { var curves = new List(); if (list.Count == 0) + { return curves; + } + var done = false; var currentIndex = 0; diff --git a/Objects/Objects/Utils/MeshTriangulationHelper.cs b/Objects/Objects/Utils/MeshTriangulationHelper.cs index d7fa2f9c57..b95ad37e66 100644 --- a/Objects/Objects/Utils/MeshTriangulationHelper.cs +++ b/Objects/Objects/Utils/MeshTriangulationHelper.cs @@ -23,7 +23,9 @@ public static void TriangulateMesh(this Mesh mesh, bool preserveQuads = false) { int n = mesh.faces[i]; if (n < 3) + { n += 3; // 0 -> 3, 1 -> 4 + } if (n == 3) { @@ -81,7 +83,9 @@ public static List TriangulateFace( { int n = faces[faceIndex]; if (n < 3) + { n += 3; // 0 -> 3, 1 -> 4 + } #region Local Funcitions //Converts from relative to absolute index (returns index in mesh.vertices list) int AsIndex(int v) => faceIndex + v + 1; @@ -162,7 +166,10 @@ Vector3 V(int v) int c = faces[AsIndex(prev[i])]; if (includeIndicators) + { triangleFaces.Add(3); + } + triangleFaces.Add(a); triangleFaces.Add(b); triangleFaces.Add(c); diff --git a/Objects/Objects/Utils/Parameters.cs b/Objects/Objects/Utils/Parameters.cs index ad4c657483..048ed18ca8 100644 --- a/Objects/Objects/Utils/Parameters.cs +++ b/Objects/Objects/Utils/Parameters.cs @@ -14,7 +14,10 @@ public static class Parameters public static Base ToBase(this List parameters) { if (parameters == null) + { return null; + } + var @base = new Base(); foreach (Parameter p in parameters) @@ -22,7 +25,9 @@ public static Base ToBase(this List parameters) //if an applicationId is defined (BuiltInName) use that as key, otherwise use the display name var key = string.IsNullOrEmpty(p.applicationInternalName) ? p.name : p.applicationInternalName; if (string.IsNullOrEmpty(key) || @base[key] != null) + { continue; + } @base[key] = p; }