Compare commits

..

12 Commits

Author SHA1 Message Date
Jonathon Broughton 79a6c42cc7 Improves geometry conversion performance
Introduces caching mechanisms for fragment IDs and geometry to avoid redundant processing, significantly enhancing geometry conversion speed.

Adds methods to clear caches and retrieve statistics for performance monitoring and memory usage estimation.

Handles COM exceptions and invalid operations more gracefully, preventing crashes and improving stability.
2025-11-15 18:03:36 +00:00
Jonathon Broughton e2318df87a Adds COM object lifetime management utility
Introduces a `ComScope` struct to automatically manage the
lifecycle of Navisworks COM objects using RAII principles.

This prevents memory leaks caused by unreleased COM objects,
addressing a common issue with Navisworks interop.
2025-11-15 18:03:17 +00:00
Jonathon Broughton 78d7814351 Fixes RenderMaterials 2025-11-14 19:11:16 +03:00
Jonathon Broughton 17a320ee53 LFG!!!
Matrix4x4 Transposed
Adds an application ID to instance references.
2025-11-14 18:33:32 +03:00
Jonathon Broughton 396ef981ee Fixes geometry processing for instance handling
Refactors geometry processing logic to handle instances more efficiently.
It now correctly applies transformations for single objects, ensuring accurate placement in the scene.
Simplifies processing of transforms where necessary for single objects.
Removes redundant logging.
2025-11-14 16:41:58 +03:00
Jonathon Broughton 763c413871 Adds instance geometry support to Navisworks connector
Introduces instance geometry handling for more efficient and accurate Navisworks data streams.

This includes:
- Scoping the `InstanceStoreManager` to each conversion session.
- Creating a "Geometry Definitions" collection to store shared geometry.
- Adding instance definition proxies to the root collection.

Addresses issues with duplicate geometry and improves stream performance.
2025-11-14 14:48:31 +03:00
Jonathon Broughton 57a5b41ec1 Refactors display value extraction
Streamlines display value extraction by injecting the geometry converter.

This change simplifies the DisplayValueExtractor by removing its dependencies on settings and logging.
It now directly uses a GeometryToSpeckleConverter instance, which is passed in, for converting model item geometry.
2025-11-14 14:47:47 +03:00
Jonathon Broughton 8385532b96 Introduces instance store management
Adds a service to manage shared geometry and instance definition proxies.

This system uses two stores for geometry definitions and their instance proxies,
facilitating efficient handling of shared geometry. It provides methods for
adding, retrieving, and clearing geometries, ensuring deduplication and
optimized memory usage.
2025-11-14 14:47:14 +03:00
Jonathon Broughton e109515852 Implements geometry instancing for Navisworks
Adds geometry instancing to improve performance and reduce data size when converting Navisworks models with shared geometry.

It identifies shared geometries based on fragment paths, extracts the base geometry once, and creates instance references with transforms. This reduces data duplication and improves loading times in Speckle.

Improves handling of COM array data for fragment ID generation and includes comprehensive logging for debugging instancing issues.
2025-11-14 14:46:54 +03:00
Jonathon Broughton fdf2425ec6 Adds shared project file for Navisworks converter
Introduces a shared project file for the Navisworks converter, promoting code reuse and consistency across different Navisworks converter implementations.

This file includes common data extractors, data handlers, helpers, services, and settings, reducing duplication and improving maintainability.
2025-11-14 14:46:28 +03:00
Jonathon Broughton c067cf6f91 Adds instance store manager for geometry
Introduces an instance store manager to handle shared geometry, which includes separate stores for geometry definitions and instance proxies.

This change prepares for the implementation of an instancing pattern compatible with .NET Framework.
It also registers settings from a factory to resolve conversion settings.
2025-11-14 14:45:49 +03:00
Jonathon Broughton 60e26d85c6 Introduces shared geometry store service
Creates a singleton service for deduplicating geometry during conversion.

This service stores mesh objects, preventing redundant processing of identical geometries by leveraging application IDs.

It uses a dictionary and a hash set to optimize lookup and storage, and includes thread safety mechanisms.
2025-11-13 14:17:50 +03:00
485 changed files with 7033 additions and 18898 deletions
+14 -14
View File
@@ -6,34 +6,34 @@
# Connectors
/Connectors/Autocad/* @oguzhankoral @JR-Morgan @dogukankaratas
/Connectors/Civil3d/* @oguzhankoral @JR-Morgan @dogukankaratas
/Connectors/ArcGIS/* @KatKatKateryna
/Connectors/Autocad/* @clairekuang @oguzhankoral @didimitrie
/Connectors/Civil3d/* @clairekuang @oguzhankoral @didimitrie
/Connectors/CSi/* @bjoernsteinhagen @dogukankaratas
/Connectors/Navisworks/* @jsdbroughton
/Connectors/Revit/* @oguzhankoral
/Connectors/Rhino/* @oguzhankoral @JR-Morgan
/Connectors/Revit/* @clairekuang @oguzhankoral @didimitrie
/Connectors/Rhino/* @clairekuang @oguzhankoral @didimitrie
/Connectors/Tekla/* @bjoernsteinhagen @dogukankaratas
# Converters
/Convertors/Autocad/* @oguzhankoral @JR-Morgan @dogukankaratas
/Convertors/Civil3d/* @oguzhankoral @JR-Morgan @dogukankaratas
/Convertors/ArcGIS/* @KatKatKateryna
/Convertors/Autocad/* @clairekuang @oguzhankoral @didimitrie
/Convertors/Civil3d/* @clairekuang @oguzhankoral @didimitrie
/Convertors/CSi/* @bjoernsteinhagen @dogukankaratas
/Convertors/Navisworks/* @jsdbroughton
/Convertors/Revit/* @oguzhankoral
/Convertors/Rhino/* @oguzhankoral @JR-Morgan
/Convertors/Revit/* @clairekuang @oguzhankoral @didimitrie
/Convertors/Rhino/* @clairekuang @oguzhankoral @didimitrie
/Convertors/Tekla/* @bjoernsteinhagen @dogukankaratas
# DUI
/DUI3/* @oguzhankoral
/DUI3/* @clairekuang @oguzhankoral @didimitrie
# Importers
/Importers/* @JR-Morgan @oguzhankoral
/Importers/* @JR-Morgan @didimitrie @oguzhankoral @adamhathcock
# SDK
/SDK/* @JR-Morgan @oguzhankoral
/SDK/* @JR-Morgan @clairekuang @didimitrie @oguzhankoral @adamhathcock
# Build
/Build/* @JR-Morgan @oguzhankoral
/.github/* @JR-Morgan @oguzhankoral
/.config/* @JR-Morgan @oguzhankoral
/Build/* @JR-Morgan @oguzhankoral @adamhathcock
+3 -3
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -20,7 +20,7 @@ jobs:
dotnet-version: 8.0.4xx # Align with global.json (including roll forward rules)
- name: Cache Nuget
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@@ -29,7 +29,7 @@ jobs:
run: ./build.sh test-and-pack
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v5
with:
files: Converters/**/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
+11 -9
View File
@@ -16,7 +16,7 @@ jobs:
file_version: ${{ steps.set-version.outputs.file_version }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -26,7 +26,7 @@ jobs:
dotnet-version: 8.0.4xx # Align with global.json (including roll forward rules)
- name: Cache Nuget
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@@ -35,7 +35,7 @@ jobs:
run: ./build.ps1 zip
- name: ⬆️ Upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v5
with:
name: output-${{ env.SEMVER }}
path: output/*.*
@@ -48,7 +48,7 @@ jobs:
run: |
echo "semver=${{ env.SEMVER }}" >> "$Env:GITHUB_OUTPUT"
echo "file_version=${{ env.FILE_VERSION }}" >> "$Env:GITHUB_OUTPUT"
deploy-installers:
runs-on: ubuntu-latest
needs: build-connectors
@@ -56,7 +56,7 @@ jobs:
IS_PUBLIC_RELEASE: ${{ github.ref_type == 'tag' }}
steps:
- name: 🔫 Trigger Build Installers
uses: benc-uk/workflow-dispatch@v1
uses: the-actions-org/workflow-dispatch@v4.0.0
with:
workflow: Build Installers
repo: specklesystems/connector-installers
@@ -70,10 +70,12 @@ jobs:
}'
ref: main
wait-for-completion: true
sync-status: true
timeout-minutes: 15
wait-for-completion-interval: 10s
wait-for-completion-timeout: 10m
display-workflow-run-url: true
display-workflow-run-url-interval: 10s
# Allows us to inspect the artifacts of failed builds, since this below step will be skipped if the above step fails
- uses: geekyeggo/delete-artifact@v6
- uses: geekyeggo/delete-artifact@v5
with:
name: output-*
-2
View File
@@ -21,5 +21,3 @@ tools
coverage.xml
output/
Images/Thumbs.db
.claude/
-1
View File
@@ -43,7 +43,6 @@ public static class Consts
new("Connectors/Autocad/Speckle.Connectors.Civil3d2026", "net8.0-windows")
]
),
new("plant3d", [new("Connectors/Autocad/Speckle.Connectors.Plant3d2026", "net8.0-windows")]),
new(
"navisworks",
[
+1 -1
View File
@@ -1,4 +1,4 @@
CA1502: 25
CA1501: 5
CA1506(Method): 60
CA1506(Method): 50
CA1506(Type): 95
+4 -25
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Target AfterTargets="Clean" Name="CleanAddinAutocad" Condition="'$(AutoCADVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<RemoveDir Directories="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Autocad.bundle\Contents\Windows\Speckle.Connectors.Autocad$(AutoCADVersion);" />
<RemoveDir Directories="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Autocad$(AutoCADVersion);" />
</Target>
<Target AfterTargets="Build" Name="AfterBuildAutoCAD" Condition="'$(AutoCADVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
@@ -9,12 +9,11 @@
<AutoCADDLLs Include="$(TargetDir)\**\*.*" />
</ItemGroup>
<Message Text="AutoCAD Version $(AutoCADVersion)" Importance="high"/>
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Autocad.bundle\Contents\Windows\Speckle.Connectors.Autocad$(AutoCADVersion)\%(RecursiveDir)" SourceFiles="@(AutoCADDLLs)" />
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Autocad.bundle\" SourceFiles="$(TargetDir)\Plugin\BundleAutoCAD\PackageContents.xml" />
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Autocad$(AutoCADVersion)\%(RecursiveDir)" SourceFiles="@(AutoCADDLLs)" />
</Target>
<Target AfterTargets="Clean" Name="CleanAddinCivil3D" Condition="'$(Civil3DVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<RemoveDir Directories="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Civil3d.bundle\Contents\Windows\Speckle.Connectors.Civil3d$(Civil3DVersion);" />
<RemoveDir Directories="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Civil3d$(Civil3DVersion);" />
</Target>
<Target AfterTargets="Build" Name="AfterBuildCivil3D" Condition="'$(Civil3DVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
@@ -22,8 +21,7 @@
<Civil3DDLLs Include="$(TargetDir)\**\*.*" />
</ItemGroup>
<Message Text="Civil3D Version $(Civil3DVersion)" Importance="high"/>
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Civil3d.bundle\Contents\Windows\Speckle.Connectors.Civil3d$(Civil3DVersion)\%(RecursiveDir)" SourceFiles="@(Civil3DDLLs)" />
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Civil3d.bundle\" SourceFiles="$(TargetDir)\Plugin\BundleCivil3D\PackageContents.xml" />
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Civil3d$(Civil3DVersion)\%(RecursiveDir)" SourceFiles="@(Civil3DDLLs)" />
</Target>
<PropertyGroup Condition="'$(AutoCADVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
@@ -35,23 +33,4 @@
<StartProgram>$(ProgramW6432)\Autodesk\AutoCAD $(Civil3DVersion)\acad.exe</StartProgram>
<StartArguments>/product C3D</StartArguments>
</PropertyGroup>
<Target AfterTargets="Clean" Name="CleanAddinPlant3D" Condition="'$(Plant3DVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<RemoveDir Directories="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Plant3d.bundle\Contents\Windows\Speckle.Connectors.Plant3d$(Plant3DVersion);" />
</Target>
<Target AfterTargets="Build" Name="AfterBuildPlant3D" Condition="'$(Plant3DVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<ItemGroup>
<Plant3DDLLs Include="$(TargetDir)\**\*.*" />
</ItemGroup>
<Message Text="Plant3D Version $(Plant3DVersion)" Importance="high"/>
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Plant3d.bundle\Contents\Windows\Speckle.Connectors.Plant3d$(Plant3DVersion)\%(RecursiveDir)" SourceFiles="@(Plant3DDLLs)" />
<Copy DestinationFolder="$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Plant3d.bundle\" SourceFiles="$(TargetDir)\Plugin\BundlePlant3D\PackageContents.xml" />
</Target>
<PropertyGroup Condition="'$(Plant3DVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<StartAction>Program</StartAction>
<StartProgram>$(ProgramW6432)\Autodesk\AutoCAD $(Plant3DVersion)\acad.exe</StartProgram>
<StartArguments>/product PLNT3D</StartArguments>
</PropertyGroup>
</Project>
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -314,7 +292,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -358,12 +336,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -314,7 +292,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -358,12 +336,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -315,7 +293,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -155,25 +155,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -229,8 +210,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -262,7 +244,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -306,12 +288,33 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -155,25 +155,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -229,8 +210,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -262,7 +244,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -306,12 +288,33 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -1,7 +1,6 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
@@ -41,9 +40,6 @@ public abstract class AutocadSendBaseBinding : ISendBinding
/// </summary>
private ConcurrentBag<string> ChangedObjectIds { get; set; } = new();
private readonly List<string> _docSubsTracker = new();
private readonly Dictionary<string, Matrix3d> _docUcsTracker = new();
protected AutocadSendBaseBinding(
DocumentModelStore store,
IBrowserBridge parent,
@@ -75,10 +71,6 @@ public abstract class AutocadSendBaseBinding : ISendBinding
// catches the case when autocad just opens up with a blank new doc
SubscribeToObjectChanges(Application.DocumentManager.CurrentDocument);
}
Application.SystemVariableChanged += (_, e) =>
_topLevelExceptionHandler.CatchUnhandled(() => OnSystemVariableChanged(e));
// Since ids of the objects generates from same seed, we should clear the cache always whenever doc swapped.
_store.DocumentChanged += (_, _) =>
{
@@ -86,6 +78,8 @@ public abstract class AutocadSendBaseBinding : ISendBinding
};
}
private readonly List<string> _docSubsTracker = new();
private void SubscribeToObjectChanges(Document doc)
{
if (doc == null || doc.Database == null || _docSubsTracker.Contains(doc.Name))
@@ -94,58 +88,11 @@ public abstract class AutocadSendBaseBinding : ISendBinding
}
_docSubsTracker.Add(doc.Name);
_docUcsTracker[doc.Name] = doc.Editor.CurrentUserCoordinateSystem;
doc.Database.ObjectAppended += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectErased += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectModified += (_, e) => OnObjectChanged(e.DBObject);
}
/// <summary>
/// Handles system variable changes to detect UCS modifications.
/// When UCS changes, clears the conversion cache and expires all sender model cards.
/// </summary>
private void OnSystemVariableChanged(Autodesk.AutoCAD.ApplicationServices.SystemVariableChangedEventArgs e)
{
// check if this is a UCS-defining system variable
string varName = e.Name.ToUpperInvariant();
bool isUcsChange = varName == "UCSNAME" || varName == "UCSORG" || varName == "UCSXDIR" || varName == "UCSYDIR";
if (!isUcsChange)
{
return;
}
// get the currently active document
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null)
{
return;
}
var currentUcs = doc.Editor.CurrentUserCoordinateSystem;
// first time tracking this document's UCS
if (!_docUcsTracker.TryGetValue(doc.Name, out Matrix3d storedUcs))
{
_docUcsTracker[doc.Name] = currentUcs;
return;
}
// ucs hasn't actually changed (multiple variables fire for single UCS change)
if (currentUcs.IsEqualTo(storedUcs))
{
return;
}
// ucs has changed - all cached conversions invalid
_sendConversionCache.ClearCache();
_docUcsTracker[doc.Name] = currentUcs;
// expire all sender model cards
_idleManager.SubscribeToIdle(nameof(ExpireAllSenders), async () => await ExpireAllSenders());
}
private void OnObjectChanged(DBObject dbObject) =>
_topLevelExceptionHandler.CatchUnhandled(() => OnChangeChangedObjectIds(dbObject));
@@ -176,19 +123,6 @@ public abstract class AutocadSendBaseBinding : ISendBinding
ChangedObjectIds = new();
}
/// <summary>
/// Expires all sender model cards when a global change occurs (like UCS change).
/// </summary>
private async Task ExpireAllSenders()
{
var senders = _store.GetSenders();
var expiredSenderIds = senders.Select(s => s.ModelCardId.NotNull()).ToList();
if (expiredSenderIds.Count > 0)
{
await Commands.SetModelsExpired(expiredSenderIds);
}
}
public List<ISendFilter> GetSendFilters() => _sendFilters;
public List<ICardSetting> GetSendSettings() => [];
@@ -211,9 +145,7 @@ public abstract class AutocadSendBaseBinding : ISendBinding
Commands,
modelCardId,
(sp, card) => InitializeSettings(sp),
card => Application.DocumentManager.CurrentDocument.GetObjects(card.SendFilter.NotNull().RefreshObjectIds()),
Application.DocumentManager.CurrentDocument.Name,
null
card => Application.DocumentManager.CurrentDocument.GetObjects(card.SendFilter.NotNull().RefreshObjectIds())
);
}
finally
@@ -18,10 +18,6 @@ public static class AutocadConnectorModule
// Send
serviceCollection.LoadSend();
serviceCollection.AddScoped<IRootObjectBuilder<AutocadRootObject>, AutocadRootObjectBuilder>();
serviceCollection.AddScoped<
IRootContinuousTraversalBuilder<AutocadRootObject>,
AutocadContinuousTraversalBuilder
>();
// Receive
serviceCollection.LoadReceive();
@@ -1,9 +1,9 @@
using Autodesk.AutoCAD.Colors;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Operations;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Models.Proxies;
using Speckle.Sdk.Pipelines.Progress;
using AutocadColor = Autodesk.AutoCAD.Colors.Color;
namespace Speckle.Connectors.Autocad.HostApp;
@@ -5,6 +5,7 @@ using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Instances;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.DoubleNumerics;
@@ -15,7 +16,6 @@ using Speckle.Sdk.Dependencies;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
using AutocadColor = Autodesk.AutoCAD.Colors.Color;
namespace Speckle.Connectors.Autocad.HostApp;
@@ -3,9 +3,9 @@ using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Instances;
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.AutocadShared.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.DoubleNumerics;
using Speckle.Sdk;
using Speckle.Sdk.Models.Instances;
@@ -46,7 +46,6 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
{
UnpackInstance(blockReference, 0, transaction);
}
_instanceObjectsManager.AddAtomicObject(obj.ApplicationId, obj);
}
return _instanceObjectsManager.GetUnpackResult();
@@ -67,14 +66,13 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
? instance.AnonymousBlockTableRecord
: instance.BlockTableRecord;
// transforms on instances are always stored in WCS
InstanceProxy instanceProxy =
new()
{
applicationId = instanceId,
definitionId = definitionId.ToString(),
maxDepth = depth,
transform = TransformHelper.ConvertToInstanceMatrix4x4(instance.BlockTransform),
transform = GetMatrix(instance.BlockTransform.ToArray()),
units = _unitsConverter.ConvertOrThrow(Application.DocumentManager.CurrentDocument.Database.Insunits)
};
@@ -175,7 +173,6 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
UnpackInstance(blockReference, depth + 1, transaction);
}
_instanceObjectsManager.AddAtomicDefinitionObjectId(appId);
_instanceObjectsManager.AddAtomicObject(appId, new(obj, appId));
}
@@ -186,4 +183,7 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
_logger.LogError(ex, "Failed unpacking Autocad instance");
}
}
private Matrix4x4 GetMatrix(double[] t) =>
new(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
}
@@ -3,12 +3,12 @@ using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.GraphicsInterface;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.InterfaceGenerator;
using Speckle.Objects.Other;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models;
using Speckle.Sdk.Pipelines.Progress;
using Material = Autodesk.AutoCAD.DatabaseServices.Material;
using RenderMaterial = Speckle.Objects.Other.RenderMaterial;
@@ -51,12 +51,6 @@ public class AutocadMaterialUnpacker
if (transaction.GetObject(entity.MaterialId, OpenMode.ForRead) is Material material)
{
// skip default material
if (material.Name == "Global")
{
continue;
}
string materialId = material.GetSpeckleApplicationId();
if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value))
{
@@ -83,12 +77,6 @@ public class AutocadMaterialUnpacker
{
if (transaction.GetObject(layer.MaterialId, OpenMode.ForRead) is Material material)
{
// skip default material
if (material.Name == "Global")
{
continue;
}
string materialId = material.GetSpeckleApplicationId();
string layerId = layer.GetSpeckleApplicationId(); // Do not use handle directly, see note in the 'GetSpeckleApplicationId' method
if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value))
@@ -12,7 +12,6 @@ using Speckle.Sdk.Dependencies;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
using AutocadColor = Autodesk.AutoCAD.Colors.Color;
namespace Speckle.Connectors.Autocad.Operations.Receive;
@@ -1,197 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Extensions;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Common;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
using Speckle.Sdk.Pipelines.Send;
namespace Speckle.Connectors.Autocad.Operations.Send;
/// <summary>
/// Abstract base class for AutoCAD continuous traversal builders that stream objects through a
/// <see cref="SendPipeline"/> for packfile-based uploads. Same conversion logic as
/// <see cref="AutocadRootObjectBaseBuilder"/>, but processes elements through the pipeline.
/// </summary>
public abstract class AutocadContinuousTraversalBaseBuilder : IRootContinuousTraversalBuilder<AutocadRootObject>
{
private readonly IRootToSpeckleConverter _converter;
private readonly string[] _documentPathSeparator = ["\\"];
private readonly ISendConversionCache _sendConversionCache;
private readonly AutocadInstanceUnpacker _instanceUnpacker;
private readonly AutocadMaterialUnpacker _materialUnpacker;
private readonly AutocadColorUnpacker _colorUnpacker;
private readonly AutocadGroupUnpacker _groupUnpacker;
private readonly ILogger<AutocadRootObjectBuilder> _logger;
private readonly ISdkActivityFactory _activityFactory;
protected AutocadContinuousTraversalBaseBuilder(
IRootToSpeckleConverter converter,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
AutocadColorUnpacker colorUnpacker,
AutocadGroupUnpacker groupUnpacker,
ILogger<AutocadRootObjectBuilder> logger,
ISdkActivityFactory activityFactory
)
{
_converter = converter;
_sendConversionCache = sendConversionCache;
_instanceUnpacker = instanceObjectManager;
_materialUnpacker = materialUnpacker;
_colorUnpacker = colorUnpacker;
_groupUnpacker = groupUnpacker;
_logger = logger;
_activityFactory = activityFactory;
}
[SuppressMessage(
"Maintainability",
"CA1506:Avoid excessive class coupling",
Justification = """
It is already simplified but has many different references since it is a builder. Do not know can we simplify it now.
Later we might consider to refactor proxies from one proxy manager? but we do not know the shape of it all potential
proxy classes yet. So I'm supressing this one now!!!
"""
)]
public async Task<RootObjectBuilderResult> Build(
IReadOnlyList<AutocadRootObject> objects,
string projectId,
SendPipeline sendPipeline,
IProgress<CardProgress> onOperationProgressed,
CancellationToken cancellationToken
)
{
// 0 - Init the root
Collection root =
new()
{
name = Application
.DocumentManager.CurrentDocument.Name.Split(_documentPathSeparator, StringSplitOptions.None)
.Reverse()
.First()
};
Document doc = Application.DocumentManager.CurrentDocument;
using Transaction tr = doc.Database.TransactionManager.StartTransaction();
// 1 - Unpack the instances
var (atomicObjects, _, instanceProxies, instanceDefinitionProxies) = _instanceUnpacker.UnpackSelection(objects);
root[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies;
// 2 - Unpack the groups
root[ProxyKeys.GROUP] = _groupUnpacker.UnpackGroups(atomicObjects);
using (var _ = _activityFactory.Start("Converting objects"))
{
// 3 - Convert atomic objects and process through pipeline
List<LayerTableRecord> usedAcadLayers = new();
List<SendConversionResult> results = new();
int count = 0;
foreach (var (entity, applicationId) in atomicObjects)
{
cancellationToken.ThrowIfCancellationRequested();
(Collection objectCollection, LayerTableRecord? autocadLayer) = CreateObjectCollection(entity, tr);
if (autocadLayer is not null)
{
usedAcadLayers.Add(autocadLayer);
root.elements.Add(objectCollection);
}
var result = await ConvertAutocadEntity(
entity,
applicationId,
objectCollection,
instanceProxies,
projectId,
sendPipeline
);
results.Add(result);
onOperationProgressed.Report(
new($"Converting objects... ({count:N0} / {atomicObjects.Count:N0})", (double)++count / atomicObjects.Count)
);
}
if (results.All(x => x.Status == Status.ERROR))
{
throw new SpeckleException("Failed to convert all objects.");
}
// 4 - Unpack the render material proxies
root[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackMaterials(atomicObjects, usedAcadLayers);
// 5 - Unpack the color proxies
root[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, usedAcadLayers);
// add any additional properties (most likely from verticals)
AddAdditionalProxiesToRoot(root);
// Process root collection and wait for all uploads
await sendPipeline.Process(root);
await sendPipeline.WaitForUpload();
return new RootObjectBuilderResult(root, results);
}
}
public virtual (Collection, LayerTableRecord?) CreateObjectCollection(Entity entity, Transaction tr)
{
return (new(), null);
}
public virtual void AddAdditionalProxiesToRoot(Collection rootCollection)
{
return;
}
private async Task<SendConversionResult> ConvertAutocadEntity(
Entity entity,
string applicationId,
Collection collectionHost,
IReadOnlyDictionary<string, InstanceProxy> instanceProxies,
string projectId,
SendPipeline sendPipeline
)
{
string sourceType = entity.GetType().ToString();
try
{
Base converted;
if (entity is BlockReference && instanceProxies.TryGetValue(applicationId, out InstanceProxy? instanceProxy))
{
converted = instanceProxy;
}
else if (_sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
{
converted = value;
}
else
{
converted = _converter.Convert(entity);
converted.applicationId = applicationId;
}
// NOTE: this is the main part that differentiate from the main root object builder
var reference = await sendPipeline.Process(converted).ConfigureAwait(false);
collectionHost.elements.Add(reference);
return new(Status.SUCCESS, applicationId, sourceType, reference);
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogSendConversionError(ex, sourceType);
return new(Status.ERROR, applicationId, sourceType, null, ex);
}
}
}
@@ -1,46 +0,0 @@
using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Caching;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Autocad.Operations.Send;
public sealed class AutocadContinuousTraversalBuilder : AutocadContinuousTraversalBaseBuilder
{
private readonly AutocadLayerUnpacker _layerUnpacker;
public AutocadContinuousTraversalBuilder(
AutocadLayerUnpacker layerUnpacker,
IRootToSpeckleConverter converter,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
AutocadColorUnpacker colorUnpacker,
AutocadGroupUnpacker groupUnpacker,
ILogger<AutocadRootObjectBuilder> logger,
ISdkActivityFactory activityFactory
)
: base(
converter,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
colorUnpacker,
groupUnpacker,
logger,
activityFactory
)
{
_layerUnpacker = layerUnpacker;
}
public override (Collection, LayerTableRecord?) CreateObjectCollection(Entity entity, Transaction tr)
{
Layer layer = _layerUnpacker.GetOrCreateSpeckleLayer(entity, tr, out LayerTableRecord? autocadLayer);
return (layer, autocadLayer);
}
}
@@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Builders;
@@ -8,22 +7,18 @@ using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Extensions;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Autocad;
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.Common;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
namespace Speckle.Connectors.Autocad.Operations.Send;
public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadRootObject>
{
private readonly IRootToSpeckleConverter _converter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _converterSettings;
private readonly string[] _documentPathSeparator = ["\\"];
private readonly ISendConversionCache _sendConversionCache;
private readonly AutocadInstanceUnpacker _instanceUnpacker;
@@ -35,7 +30,6 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
protected AutocadRootObjectBaseBuilder(
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -46,7 +40,6 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
)
{
_converter = converter;
_converterSettings = converterSettings;
_sendConversionCache = sendConversionCache;
_instanceUnpacker = instanceObjectManager;
_materialUnpacker = materialUnpacker;
@@ -88,35 +81,17 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
using Transaction tr = doc.Database.TransactionManager.StartTransaction();
// 1 - Unpack the instances
var (atomicObjects, atomicDefinitionObjectIds, instanceProxies, instanceDefinitionProxies) =
_instanceUnpacker.UnpackSelection(objects);
var (atomicObjects, instanceProxies, instanceDefinitionProxies) = _instanceUnpacker.UnpackSelection(objects);
root[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies;
// 2 - Unpack the groups
root[ProxyKeys.GROUP] = _groupUnpacker.UnpackGroups(atomicObjects);
// 3 - Add the Reference Point
Matrix3d? referenceTransform = null;
if (
Application.DocumentManager.CurrentDocument.Editor.CurrentUserCoordinateSystem is Matrix3d matrix
&& matrix != Matrix3d.Identity
)
{
referenceTransform = matrix.Inverse();
/* POC: Do not attach transform to root for now! we are not consuming this in autocad/civil on receive and in revit it will undo all baked transforms :(
var transformMatrix = ReferencePointHelper.CreateTransformDataForRootObject(matrix);
root[ReferencePointHelper.REFERENCE_POINT_TRANSFORM_KEY] = transformMatrix;
*/
}
using (var _ = _activityFactory.Start("Converting objects"))
{
// 3 - Convert atomic objects
List<LayerTableRecord> usedAcadLayers = new(); // Keeps track of autocad layers used, so we can pass them on later to the material and color unpacker.
List<SendConversionResult> results = new();
int count = 0;
// 4 - Convert atomic objects
foreach (var (entity, applicationId) in atomicObjects)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -129,28 +104,9 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
root.elements.Add(objectCollection);
}
SendConversionResult? result = null;
// If this is a atomic definition object, we *do not* want to bake in the reference point transform to the object
if (atomicDefinitionObjectIds.Contains(applicationId))
{
using (_converterSettings.Push(currentSettings => currentSettings with { ReferencePointTransform = null }))
{
result = ConvertAutocadEntity(entity, applicationId, objectCollection, instanceProxies, projectId);
}
}
else // this is a selected atomic object (not part of definition)
{
result = ConvertAutocadEntity(
entity,
applicationId,
objectCollection,
instanceProxies,
projectId,
referenceTransform // set this for top level instance proxies to use if needed
);
}
var result = ConvertAutocadEntity(entity, applicationId, objectCollection, instanceProxies, projectId);
results.Add(result);
onOperationProgressed.Report(new("Converting", (double)++count / atomicObjects.Count));
}
@@ -159,10 +115,10 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
throw new SpeckleException("Failed to convert all objects."); // fail fast instead creating empty commit! It will appear as model card error with red color.
}
// 5 - Unpack the render material proxies
// 4 - Unpack the render material proxies
root[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackMaterials(atomicObjects, usedAcadLayers);
// 6 - Unpack the color proxies
// 5 - Unpack the color proxies
root[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, usedAcadLayers);
// add any additional properties (most likely from verticals)
@@ -187,24 +143,15 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
string applicationId,
Collection collectionHost,
IReadOnlyDictionary<string, InstanceProxy> instanceProxies,
string projectId,
Matrix3d? transform = null
string projectId
)
{
string sourceType = entity.GetType().ToString();
try
{
Base converted;
if (entity is BlockReference br && instanceProxies.TryGetValue(applicationId, out InstanceProxy? instanceProxy))
if (entity is BlockReference && instanceProxies.TryGetValue(applicationId, out InstanceProxy? instanceProxy))
{
// modify transform by reference point this if it is top level
if (instanceProxy.maxDepth == 0 && transform is Matrix3d validTransform)
{
instanceProxy.transform = TransformHelper.ConvertToInstanceMatrix4x4(
br.BlockTransform.PreMultiplyBy(validTransform)
);
}
converted = instanceProxy;
}
else if (_sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
@@ -2,7 +2,6 @@ using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Caching;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models.Collections;
@@ -16,7 +15,6 @@ public sealed class AutocadRootObjectBuilder : AutocadRootObjectBaseBuilder
public AutocadRootObjectBuilder(
AutocadLayerUnpacker layerUnpacker,
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -27,7 +25,6 @@ public sealed class AutocadRootObjectBuilder : AutocadRootObjectBaseBuilder
)
: base(
converter,
converterSettings,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
@@ -7,8 +7,6 @@ public static class AppUtils
public static Speckle.Sdk.Application App =>
#if CIVIL3D
HostApplications.Civil3D;
#elif PLANT3D
HostApplications.Plant3D;
#elif AUTOCAD
HostApplications.AutoCAD;
#else
@@ -16,11 +14,11 @@ public static class AppUtils
#endif
public static HostAppVersion Version =>
#if AUTOCAD2026 || CIVIL3D2026 || PLANT3D2026
#if AUTOCAD2026 || CIVIL3D2026
HostAppVersion.v2026;
#elif AUTOCAD2025 || CIVIL3D2025 || PLANT3D2025
#elif AUTOCAD2025 || CIVIL3D2025
HostAppVersion.v2025;
#elif AUTOCAD2024 || CIVIL3D2024 || PLANT3D2024
#elif AUTOCAD2024 || CIVIL3D2024
HostAppVersion.v2024;
#elif AUTOCAD2023|| CIVIL3D2023
HostAppVersion.v2023;
@@ -11,9 +11,6 @@ using Speckle.Converters.Autocad;
#elif CIVIL3D
using Speckle.Converters.Civil3dShared;
using Speckle.Connectors.Civil3dShared.DependencyInjection;
#elif PLANT3D
using Speckle.Connectors.Plant3dShared.DependencyInjection;
using Speckle.Converters.Plant3dShared;
#endif
namespace Speckle.Connectors.Autocad.Plugin;
@@ -42,18 +39,13 @@ public class AutocadCommand
// init DI
var services = new ServiceCollection();
_disposableLogger = services.Initialize(AppUtils.App, AppUtils.Version);
#if AUTOCAD
services.AddAutocad();
services.AddAutocadConverters();
#elif CIVIL3D
services.AddCivil3d();
services.AddCivil3dConverters();
#elif PLANT3D
services.AddPlant3d();
services.AddPlant3dConverters();
#endif
Container = services.BuildServiceProvider();
Container.UseDUI();
@@ -3,7 +3,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using Autodesk.Windows;
using Speckle.Sdk;
#if !AUTOCAD2025_OR_GREATER && !CIVIL3D2025_OR_GREATER && !PLANT3D2025_OR_GREATER
#if !AUTOCAD2025_OR_GREATER && !CIVIL3D2025_OR_GREATER
using System.IO;
#endif
@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage
SchemaVersion="1.0"
AppVersion="1.0"
Author="AEC SYSTEMS LTD"
Name="Speckle for AutoCAD"
Description="Speckle for AutoCAD"
Icon="./Contents/Resources/Logo.ico"
ProductCode="{958850b9-3782-4e6f-b9b3-1b570e0fcae1}"
UpgradeCode="{274de351-80aa-4972-9b45-6a93f8ce968f}"> <!-- For now, we're not updating the AppVersion & ProductCodes with each version -->
<CompanyDetails
Name="Speckle"
Url="https://speckle.systems"
Email="support@speckle.systems" />
<Components>
<!-- AutoCAD 2022 -->
<ComponentEntry
AppName="Speckle.Connectors.Autocad2022"
ModuleName="./Contents/Windows/Speckle.Connectors.Autocad2022/Speckle.Connectors.Autocad2022.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD"
SeriesMin="R24.1"
SeriesMax="R24.1" />
</ComponentEntry>
<!-- AutoCAD 2023 -->
<ComponentEntry
AppName="Speckle.Connectors.Autocad2023"
ModuleName="./Contents/Windows/Speckle.Connectors.Autocad2023/Speckle.Connectors.Autocad2023.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD"
SeriesMin="R24.2"
SeriesMax="R24.2" />
</ComponentEntry>
<!-- AutoCAD 2024 -->
<ComponentEntry
AppName="Speckle.Connectors.Autocad2024"
ModuleName="./Contents/Windows/Speckle.Connectors.Autocad2024/Speckle.Connectors.Autocad2024.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD"
SeriesMin="R24.3"
SeriesMax="R24.3" />
</ComponentEntry>
<!-- AutoCAD 2025 -->
<ComponentEntry
AppName="Speckle.Connectors.Autocad2025"
ModuleName="./Contents/Windows/Speckle.Connectors.Autocad2025/Speckle.Connectors.Autocad2025.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD"
SeriesMin="R25.0"
SeriesMax="R25.0" />
</ComponentEntry>
<!-- AutoCAD 2026 -->
<ComponentEntry
AppName="Speckle.Connectors.Autocad2026"
ModuleName="./Contents/Windows/Speckle.Connectors.Autocad2026/Speckle.Connectors.Autocad2026.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD"
SeriesMin="R25.1"
SeriesMax="R25.1" />
</ComponentEntry>
</Components>
</ApplicationPackage>
@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage
SchemaVersion="1.0"
AppVersion="1.0"
Author="AEC SYSTEMS LTD"
Name="Speckle for Civil 3D"
Description="Speckle for Civil 3D"
Icon="./Contents/Resources/Logo.ico"
ProductCode="{cecad7b2-daa9-4a9d-941d-737619ffd999}"
UpgradeCode="{ccf4134d-0e24-4e91-8bf4-781ec7313bef}"> <!-- For now, we're not updating the AppVersion & ProductCodes with each version -->
<CompanyDetails
Name="Speckle"
Url="https://speckle.systems"
Email="support@speckle.systems" />
<Components>
<!-- AutoCAD 2022 -->
<ComponentEntry
AppName="Speckle.Connectors.Civil3d2022"
ModuleName="./Contents/Windows/Speckle.Connectors.Civil3d2022/Speckle.Connectors.Civil3d2022.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Civil3D"
SeriesMin="R24.1"
SeriesMax="R24.1" />
</ComponentEntry>
<!-- AutoCAD 2023 -->
<ComponentEntry
AppName="Speckle.Connectors.Civil3d2023"
ModuleName="./Contents/Windows/Speckle.Connectors.Civil3d2023/Speckle.Connectors.Civil3d2023.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Civil3D"
SeriesMin="R24.2"
SeriesMax="R24.2" />
</ComponentEntry>
<!-- AutoCAD 2024 -->
<ComponentEntry
AppName="Speckle.Connectors.Civil3d2024"
ModuleName="./Contents/Windows/Speckle.Connectors.Civil3d2024/Speckle.Connectors.Civil3d2024.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Civil3D"
SeriesMin="R24.3"
SeriesMax="R24.3" />
</ComponentEntry>
<!-- AutoCAD 2025 -->
<ComponentEntry
AppName="Speckle.Connectors.Civil3d2025"
ModuleName="./Contents/Windows/Speckle.Connectors.Civil3d2025/Speckle.Connectors.Civil3d2025.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Civil3D"
SeriesMin="R25.0"
SeriesMax="R25.0" />
</ComponentEntry>
<!-- AutoCAD 2026 -->
<ComponentEntry
AppName="Speckle.Connectors.Civil3d2026"
ModuleName="./Contents/Windows/Speckle.Connectors.Civil3d2026/Speckle.Connectors.Civil3d2026.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Civil3D"
SeriesMin="R25.1"
SeriesMax="R25.1" />
</ComponentEntry>
</Components>
</ApplicationPackage>
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage
SchemaVersion="1.0"
AppVersion="1.0"
Author="AEC SYSTEMS LTD"
Name="Speckle for Plant 3D"
Description="Speckle for Plant 3D"
Icon="./Contents/Resources/Logo.ico"
ProductCode="{b91352b6-01db-4084-93c8-684bb231947e}"
UpgradeCode="{91c7e43f-e962-40e9-85bd-d6bd733b6964}">
<CompanyDetails
Name="Speckle"
Url="https://speckle.systems"
Email="support@speckle.systems" />
<Components>
<!-- Plant 3D 2026 -->
<ComponentEntry
AppName="Speckle.Connectors.Plant3d2026"
ModuleName="./Contents/Windows/Speckle.Connectors.Plant3d2026/Speckle.Connectors.Plant3d2026.dll"
LoadOnAutoCADStartup="True">
<RuntimeRequirements
OS="Win64"
Platform="Plant3D"
SeriesMin="R25.1"
SeriesMax="R25.1" />
</ComponentEntry>
</Components>
</ApplicationPackage>
@@ -41,8 +41,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\AutocadHostObjectBaseBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\AutocadHostObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadRootObject.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadContinuousTraversalBaseBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadContinuousTraversalBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadRootObjectBaseBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadRootObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Plugin\AutocadRibbon.cs" />
@@ -55,15 +53,4 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Resources\s2logo16.png" />
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Resources\s2logo32.png" />
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)Plugin\BundleCivil3D\PackageContents.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Plugin\BundleAutoCAD\PackageContents.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Plugin\BundlePlant3D\PackageContents.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
@@ -82,8 +82,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -178,29 +178,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -291,8 +268,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -324,7 +302,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -368,12 +346,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -82,8 +82,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -178,29 +178,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -291,8 +268,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -324,7 +302,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -368,12 +346,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -82,8 +82,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -178,29 +178,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -291,8 +268,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -324,7 +302,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -368,12 +346,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -164,25 +164,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -238,8 +219,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -272,7 +254,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -316,12 +298,33 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -164,25 +164,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -238,8 +219,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -272,7 +254,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -316,12 +298,33 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -22,10 +22,6 @@ public static class Civil3dConnectorModule
// add send
serviceCollection.LoadSend();
serviceCollection.AddScoped<IRootObjectBuilder<AutocadRootObject>, Civil3dRootObjectBuilder>();
serviceCollection.AddScoped<
IRootContinuousTraversalBuilder<AutocadRootObject>,
Civil3dContinuousTraversalBuilder
>();
serviceCollection.AddSingleton<IBinding, Civil3dSendBinding>();
// add receive
@@ -1,57 +0,0 @@
using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Civil3dShared.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Civil3dShared.Operations.Send;
public sealed class Civil3dContinuousTraversalBuilder : AutocadContinuousTraversalBaseBuilder
{
private readonly AutocadLayerUnpacker _layerUnpacker;
private readonly PropertySetDefinitionHandler _propertySetDefinitionHandler;
public Civil3dContinuousTraversalBuilder(
AutocadLayerUnpacker layerUnpacker,
PropertySetDefinitionHandler propertySetDefinitionHandler,
IRootToSpeckleConverter converter,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
AutocadColorUnpacker colorUnpacker,
AutocadGroupUnpacker groupUnpacker,
ILogger<AutocadRootObjectBuilder> logger,
ISdkActivityFactory activityFactory
)
: base(
converter,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
colorUnpacker,
groupUnpacker,
logger,
activityFactory
)
{
_layerUnpacker = layerUnpacker;
_propertySetDefinitionHandler = propertySetDefinitionHandler;
}
public override (Collection, LayerTableRecord?) CreateObjectCollection(Entity entity, Transaction tr)
{
Layer layer = _layerUnpacker.GetOrCreateSpeckleLayer(entity, tr, out LayerTableRecord? autocadLayer);
return (layer, autocadLayer);
}
public override void AddAdditionalProxiesToRoot(Collection rootObject)
{
rootObject[ProxyKeys.PROPERTYSET_DEFINITIONS] = _propertySetDefinitionHandler.Definitions;
}
}
@@ -4,7 +4,6 @@ using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Autocad;
using Speckle.Converters.Civil3dShared.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
@@ -21,7 +20,6 @@ public sealed class Civil3dRootObjectBuilder : AutocadRootObjectBaseBuilder
AutocadLayerUnpacker layerUnpacker,
PropertySetDefinitionHandler propertySetDefinitionHandler,
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -32,7 +30,6 @@ public sealed class Civil3dRootObjectBuilder : AutocadRootObjectBaseBuilder
)
: base(
converter,
converterSettings,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
@@ -13,7 +13,6 @@
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\Civil3dConnectorModule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\PropertySetBaker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\Civil3dHostObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Civil3dContinuousTraversalBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Civil3dRootObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bindings\Civil3dSendBinding.cs" />
</ItemGroup>
@@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Plant3DVersion>2026</Plant3DVersion>
<DefineConstants>$(DefineConstants);PLANT3D2026;PLANT3D;PLANT3D2024_OR_GREATER;PLANT3D2025_OR_GREATER;PLANT3D2026_OR_GREATER</DefineConstants>
<Configurations>Debug;Release;Local</Configurations>
</PropertyGroup>
<PropertyGroup>
<!-- .NET Core uses this to move native dependencies into a root for runtime selection and usage for non-windows development https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#enablewindowstargeting -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <!--This is needed for managed dependencies-->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <!--This is needed for the rest-->
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> <!--This is needed just to keep folder paths the same as the netframework versions-->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Speckle.AutoCAD.API" VersionOverride="2026.0.0" ExcludeAssets="runtime"/>
<PackageReference Include="Speckle.Plant3D.API" VersionOverride="2026.0.0" ExcludeAssets="runtime"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Converters\Plant3d\Speckle.Converters.Plant3d2026\Speckle.Converters.Plant3d2026.csproj" />
<ProjectReference Include="..\..\..\DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj" />
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj" />
</ItemGroup>
<Import Project="..\Speckle.Connectors.Plant3dShared\Speckle.Connectors.Plant3dShared.projitems" Label="Shared" />
<Import Project="..\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems" Label="Shared" />
</Project>
@@ -1,341 +0,0 @@
{
"version": 2,
"dependencies": {
"net8.0-windows7.0": {
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.AutoCAD.API": {
"type": "Direct",
"requested": "[2026.0.0, )",
"resolved": "2026.0.0",
"contentHash": "WlkV81PmbK/ftoM7aGpU6LGosKbePBQej9MO/m63rFMozX89tsitEhE12o58wu7K/4FmRUdAMolYtdK20EDBnw=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"Speckle.Plant3D.API": {
"type": "Direct",
"requested": "[2026.0.0, )",
"resolved": "2026.0.0",
"contentHash": "VT8M6CGQl1mk3/5Ro3AEAOVrOs/cX58YRwYZnu+6xeHvsazK07Et/6kMJsde4Y7Xrpox7eBLKgYeOspiRVvX5g==",
"dependencies": {
"Speckle.AutoCAD.API": "2026.0.0"
}
},
"GraphQL.Client": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0",
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
"System.Reactive": "5.0.0"
}
},
"GraphQL.Client.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
"dependencies": {
"GraphQL.Primitives": "6.0.0"
}
},
"GraphQL.Client.Abstractions.Websocket": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0"
}
},
"GraphQL.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.Data.Sqlite": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "7.0.5",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "2.2.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Primitives": "2.2.0",
"System.ComponentModel.Annotations": "4.5.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Speckle.Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Reactive": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
}
},
"speckle.connectors.dui": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Connectors.Common": "[1.0.0, )"
}
},
"speckle.connectors.dui.webview": {
"type": "Project",
"dependencies": {
"Microsoft.Web.WebView2": "[1.0.1938.49, )",
"Speckle.Connectors.DUI": "[1.0.0, )"
}
},
"speckle.connectors.logging": {
"type": "Project"
},
"speckle.converters.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
}
},
"speckle.converters.plant3d2026": {
"type": "Project",
"dependencies": {
"Speckle.AutoCAD.API": "[2026.0.0, )",
"Speckle.Connectors.DUI.WebView": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Plant3D.API": "[2026.0.0, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Microsoft.Web.WebView2": {
"type": "CentralTransitive",
"requested": "[1.0.1938.49, )",
"resolved": "1.0.1938.49",
"contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw=="
},
"Speckle.DoubleNumerics": {
"type": "CentralTransitive",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
}
}
},
"net8.0-windows7.0/win-x64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"Microsoft.Web.WebView2": {
"type": "CentralTransitive",
"requested": "[1.0.1938.49, )",
"resolved": "1.0.1938.49",
"contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw=="
}
}
}
}
@@ -1,61 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Autocad.Bindings;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Converters.Plant3dShared;
namespace Speckle.Connectors.Plant3dShared.Bindings;
public sealed class Plant3dSendBinding : AutocadSendBaseBinding
{
private readonly IPlant3dConversionSettingsFactory _plant3dConversionSettingsFactory;
private readonly IAutocadConversionSettingsFactory _autocadConversionSettingsFactory;
public Plant3dSendBinding(
DocumentModelStore store,
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
ICancellationManager cancellationManager,
ISendConversionCache sendConversionCache,
IPlant3dConversionSettingsFactory plant3dConversionSettingsFactory,
IAutocadConversionSettingsFactory autocadConversionSettingsFactory,
IThreadContext threadContext,
ITopLevelExceptionHandler topLevelExceptionHandler,
IAppIdleManager appIdleManager,
ISendOperationManagerFactory sendOperationManagerFactory
)
: base(
store,
parent,
sendFilters,
cancellationManager,
sendConversionCache,
threadContext,
topLevelExceptionHandler,
appIdleManager,
sendOperationManagerFactory
)
{
_plant3dConversionSettingsFactory = plant3dConversionSettingsFactory;
_autocadConversionSettingsFactory = autocadConversionSettingsFactory;
}
// We need a separate send binding for Plant 3D due to using a different unit converter (needed for conversion settings construction)
protected override void InitializeSettings(IServiceProvider serviceProvider)
{
serviceProvider
.GetRequiredService<IConverterSettingsStore<Plant3dConversionSettings>>()
.Initialize(_plant3dConversionSettingsFactory.Create(Application.DocumentManager.CurrentDocument));
serviceProvider
.GetRequiredService<IConverterSettingsStore<AutocadConversionSettings>>()
.Initialize(_autocadConversionSettingsFactory.Create(Application.DocumentManager.CurrentDocument));
}
}
@@ -1,27 +0,0 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Autocad.DependencyInjection;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.Plant3dShared.Bindings;
using Speckle.Connectors.Plant3dShared.Operations.Send;
using Speckle.Sdk;
namespace Speckle.Connectors.Plant3dShared.DependencyInjection;
public static class Plant3dConnectorModule
{
public static void AddPlant3d(this IServiceCollection serviceCollection)
{
serviceCollection.AddAutocadBase();
// add send
serviceCollection.LoadSend();
serviceCollection.AddScoped<IRootObjectBuilder<AutocadRootObject>, Plant3dRootObjectBuilder>();
serviceCollection.AddSingleton<IBinding, Plant3dSendBinding>();
// automatically detects the Class:IClass interface pattern to register all generated interfaces
serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetExecutingAssembly());
}
}
@@ -1,50 +0,0 @@
using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Caching;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Plant3dShared.Operations.Send;
public sealed class Plant3dRootObjectBuilder : AutocadRootObjectBaseBuilder
{
private readonly AutocadLayerUnpacker _layerUnpacker;
public Plant3dRootObjectBuilder(
AutocadLayerUnpacker layerUnpacker,
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
AutocadColorUnpacker colorUnpacker,
AutocadGroupUnpacker groupUnpacker,
ILogger<AutocadRootObjectBuilder> logger,
ISdkActivityFactory activityFactory
)
: base(
converter,
converterSettings,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
colorUnpacker,
groupUnpacker,
logger,
activityFactory
)
{
_layerUnpacker = layerUnpacker;
}
public override (Collection, LayerTableRecord?) CreateObjectCollection(Entity entity, Transaction tr)
{
Layer layer = _layerUnpacker.GetOrCreateSpeckleLayer(entity, tr, out LayerTableRecord? autocadLayer);
return (layer, autocadLayer);
}
}
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>B1C4A14C-2F4E-4C3D-9B71-A3F5D8E6C912</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Speckle.Connectors.Plant3dShared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\Plant3dConnectorModule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Plant3dRootObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bindings\Plant3dSendBinding.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)DependencyInjection\" />
<Folder Include="$(MSBuildThisFileDirectory)Operations\Send\" />
</ItemGroup>
</Project>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{B1C4A14C-2F4E-4C3D-9B71-A3F5D8E6C912}</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="Speckle.Connectors.Plant3dShared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
@@ -1,5 +1,4 @@
using System.IO;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.CSiShared.HostApp;
using Speckle.Connectors.CSiShared.Operations.Send.Settings;
@@ -56,7 +55,6 @@ public sealed class CsiSharedSendBinding : ISendBinding
public async Task Send(string modelCardId)
{
using var manager = _sendOperationManagerFactory.Create();
var (fileName, fileSizeBytes) = GetFileInfo();
await manager.Process(
Commands,
modelCardId,
@@ -71,24 +69,10 @@ public sealed class CsiSharedSendBinding : ISendBinding
)
);
},
card => card.SendFilter.NotNull().RefreshObjectIds().Select(DecodeObjectIdentifier).ToList(),
fileName,
fileSizeBytes
card => card.SendFilter.NotNull().RefreshObjectIds().Select(DecodeObjectIdentifier).ToList()
);
}
private (string? fileName, long? fileBytes) GetFileInfo()
{
string fullPath = _csiApplicationService.SapModel.GetModelFilename(true);
if (!File.Exists(fullPath))
{
return (null, null);
}
var fileInfo = new FileInfo(fullPath);
return (fileInfo.Name, fileInfo.Length);
}
private ICsiWrapper DecodeObjectIdentifier(string encodedId)
{
var (type, name) = ObjectIdentifier.Decode(encodedId);
@@ -1,211 +0,0 @@
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.CSiShared.HostApp;
using Speckle.Connectors.CSiShared.HostApp.Helpers;
using Speckle.Connectors.CSiShared.Utils;
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared;
using Speckle.Converters.CSiShared.Extensions;
using Speckle.Converters.CSiShared.Utils;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Pipelines.Progress;
using Speckle.Sdk.Pipelines.Send;
namespace Speckle.Connectors.CSiShared.Builders;
/// <summary>
/// Continuous traversal builder for CSi that streams objects through a <see cref="SendPipeline"/>
/// for packfile-based uploads. Same conversion logic as <see cref="CsiRootObjectBuilder"/>.
/// </summary>
public class CsiContinuousTraversalBuilder : IRootContinuousTraversalBuilder<ICsiWrapper>
{
private readonly IRootToSpeckleConverter _rootToSpeckleConverter;
private readonly IConverterSettingsStore<CsiConversionSettings> _converterSettings;
private readonly CsiSendCollectionManager _sendCollectionManager;
private readonly IMaterialUnpacker _materialUnpacker;
private readonly ISectionUnpacker _sectionUnpacker;
private readonly ILogger<CsiRootObjectBuilder> _logger;
private readonly ISdkActivityFactory _activityFactory;
private readonly ICsiApplicationService _csiApplicationService;
private readonly AnalysisResultsExtractor _analysisResultsExtractor;
public CsiContinuousTraversalBuilder(
IRootToSpeckleConverter rootToSpeckleConverter,
IConverterSettingsStore<CsiConversionSettings> converterSettings,
CsiSendCollectionManager sendCollectionManager,
IMaterialUnpacker materialUnpacker,
ISectionUnpacker sectionUnpacker,
ILogger<CsiRootObjectBuilder> logger,
ISdkActivityFactory activityFactory,
ICsiApplicationService csiApplicationService,
AnalysisResultsExtractor analysisResultsExtractor
)
{
_converterSettings = converterSettings;
_sendCollectionManager = sendCollectionManager;
_materialUnpacker = materialUnpacker;
_sectionUnpacker = sectionUnpacker;
_rootToSpeckleConverter = rootToSpeckleConverter;
_logger = logger;
_activityFactory = activityFactory;
_csiApplicationService = csiApplicationService;
_analysisResultsExtractor = analysisResultsExtractor;
}
public async Task<RootObjectBuilderResult> Build(
IReadOnlyList<ICsiWrapper> csiObjects,
string projectId,
SendPipeline sendPipeline,
IProgress<CardProgress> onOperationProgressed,
CancellationToken cancellationToken
)
{
using var activity = _activityFactory.Start("Build");
string modelFileName = _csiApplicationService.SapModel.GetModelFilename(false) ?? "Unnamed model";
(string forceUnit, string tempUnit) = GetForceAndTemperatureUnits();
Collection rootObjectCollection =
new()
{
name = modelFileName,
["units"] = _converterSettings.Current.SpeckleUnits,
["forceUnits"] = forceUnit,
["temperatureUnits"] = tempUnit
};
List<SendConversionResult> results = new(csiObjects.Count);
int count = 0;
using (var _ = _activityFactory.Start("Convert all"))
{
foreach (ICsiWrapper csiObject in csiObjects)
{
cancellationToken.ThrowIfCancellationRequested();
var result = await ConvertCsiObject(csiObject, rootObjectCollection, sendPipeline);
results.Add(result);
count++;
onOperationProgressed.Report(
new($"Converting objects... ({count:N0} / {csiObjects.Count:N0})", (double)count / csiObjects.Count)
);
await Task.Yield();
}
}
if (results.All(x => x.Status == Status.ERROR))
{
throw new SpeckleException("Failed to convert all objects");
}
using (var _ = _activityFactory.Start("Process Proxies"))
{
rootObjectCollection[ProxyKeys.MATERIAL] = _materialUnpacker.UnpackMaterials().ToList();
rootObjectCollection[ProxyKeys.SECTION] = _sectionUnpacker.UnpackSections().ToList();
}
// Extract analysis results (if applicable)
var objectSelectionSummary = GetObjectSummary(csiObjects);
var selectedCasesAndCombinations = _converterSettings.Current.SelectedLoadCasesAndCombinations;
var requestedResultTypes = _converterSettings.Current.SelectedResultTypes;
if (selectedCasesAndCombinations?.Count > 0)
{
if (requestedResultTypes == null || requestedResultTypes.Count == 0)
{
throw new SpeckleException(
"Adjust publish settings - no result type input for the requested load cases and combinations"
);
}
if (!_csiApplicationService.SapModel.GetModelIsLocked())
{
throw new SpeckleException("Model unlocked, no access to analysis results");
}
try
{
var analysisResults = _analysisResultsExtractor.ExtractAnalysisResults(
selectedCasesAndCombinations,
requestedResultTypes,
objectSelectionSummary
);
rootObjectCollection[RootKeys.ANALYSIS_RESULTS] = analysisResults;
}
catch (Exception ex)
{
throw new SpeckleException("Analysis result extraction failed", ex);
}
}
// Process root collection and wait for all uploads
await sendPipeline.Process(rootObjectCollection);
await sendPipeline.WaitForUpload();
return new RootObjectBuilderResult(rootObjectCollection, results);
}
private async Task<SendConversionResult> ConvertCsiObject(
ICsiWrapper csiObject,
Collection typeCollection,
SendPipeline sendPipeline
)
{
string sourceType = csiObject.ObjectName;
string applicationId = csiObject switch
{
CsiJointWrapper jointWrapper => jointWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
CsiFrameWrapper frameWrapper => frameWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
CsiCableWrapper cableWrapper => cableWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
CsiTendonWrapper tendonWrapper => tendonWrapper.ObjectName,
CsiShellWrapper shellWrapper => shellWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
CsiSolidWrapper solidWrapper => solidWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
CsiLinkWrapper linkWrapper => linkWrapper.GetSpeckleApplicationId(_csiApplicationService.SapModel),
_ => throw new ArgumentException($"Unsupported wrapper type: {csiObject.GetType()}", nameof(csiObject))
};
try
{
Base converted = _rootToSpeckleConverter.Convert(csiObject);
var collection = _sendCollectionManager.AddObjectCollectionToRoot(converted, typeCollection);
// NOTE: this is the main part that differentiate from the main root object builder
var reference = await sendPipeline.Process(converted).ConfigureAwait(false);
collection.elements.Add(reference);
return new(Status.SUCCESS, applicationId, sourceType, reference);
}
catch (NotImplementedException ex)
{
_logger.LogError(ex, "Failed to convert object {sourceType}", sourceType);
return new(Status.WARNING, applicationId, sourceType, null, ex);
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogError(ex, "Failed to convert object {sourceType}", sourceType);
return new(Status.ERROR, applicationId, sourceType, null, ex);
}
}
private Dictionary<ModelObjectType, List<string>> GetObjectSummary(IReadOnlyList<ICsiWrapper> csiObjects) =>
csiObjects
.GroupBy(csiObject => csiObject.ObjectType)
.ToDictionary(group => group.Key, group => group.Select(obj => obj.Name).ToList());
private (string, string) GetForceAndTemperatureUnits()
{
var forceUnit = eForce.NotApplicable;
var lengthUnit = eLength.NotApplicable;
var temperatureUnit = eTemperature.NotApplicable;
_converterSettings.Current.SapModel.GetDatabaseUnits_2(ref forceUnit, ref lengthUnit, ref temperatureUnit);
return (forceUnit.ToString(), temperatureUnit.ToString());
}
}
@@ -13,7 +13,6 @@ using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Pipelines.Progress;
namespace Speckle.Connectors.CSiShared.Builders;
@@ -43,7 +43,6 @@ public static class ServiceRegistration
services.AddScoped<ISendFilter, CsiSharedSelectionFilter>();
services.AddScoped<CsiSendCollectionManager>();
services.AddScoped<IRootObjectBuilder<ICsiWrapper>, CsiRootObjectBuilder>();
services.AddScoped<IRootContinuousTraversalBuilder<ICsiWrapper>, CsiContinuousTraversalBuilder>();
services.AddScoped<SendOperation<ICsiWrapper>>();
services.AddScoped<CsiMaterialPropertyExtractor>();
@@ -29,7 +29,6 @@
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Helpers\IApplicationSectionPropertyExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Helpers\ISectionPropertyExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Helpers\ISectionUnpacker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\CsiContinuousTraversalBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\CsiRootObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Settings\ToSpeckleSettingsManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Plugin\CsiPluginBase.cs" />
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.etabs21": {
@@ -357,12 +335,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -155,25 +155,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -229,8 +210,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -254,7 +236,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.etabs22": {
@@ -304,12 +286,33 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
+17 -47
View File
@@ -2,63 +2,33 @@
<Project>
<PropertyGroup>
<UseWpf>true</UseWpf>
<Description>NextGen Speckle Connector for Autodesk Navisworks Manage</Description>
<Authors>$(Authors) jonathon@speckle.systems</Authors>
<PackageTags>$(PackageTags) connector nwd nwc nwf navisworks manage</PackageTags>
<PluginBundleTarget>$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Navisworks.bundle</PluginBundleTarget>
<PluginVersionContentTarget>$(PluginBundleTarget)\Contents\$(NavisworksVersion)</PluginVersionContentTarget>
<PluginVersionContentTarget>$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Navisworks.bundle\Contents\$(NavisworksVersion)</PluginVersionContentTarget>
<RootNamespace>Speckle.Connector.Navisworks</RootNamespace>
</PropertyGroup>
<Target Name="PostBuild"
AfterTargets="Build"
Condition="'$(OS)' == 'Windows_NT' and '$(NavisworksVersion)' != ''">
<!-- Post Builds -->
<ItemGroup>
<RibbonFiles Include="$(OutDir)Plugin\NavisworksRibbon.*"/>
<ResourceFiles Include="$(OutDir)Resources\**\*.png"/>
<ResourceFiles Include="$(OutDir)Resources\**\*.ico"/>
<AllFiles Include="$(OutDir)*"/>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="Build" Condition="'$(NavisworksVersion)' != '' And '$(ContinuousIntegrationBuild)' != 'true' And '$(OS)' == 'Windows_NT'">
<Message Text="Navisworks Version $(NavisworksVersion)" Importance="high"/>
<RemoveDir Directories="$(PluginVersionContentTarget)" Condition="Exists('$(PluginVersionContentTarget)')"/>
<MakeDir Directories="
$(PluginBundleTarget);
$(PluginBundleTarget)\Contents;
$(PluginVersionContentTarget);
$(PluginVersionContentTarget)\en-US;
$(PluginVersionContentTarget)\Resources"/>
<!-- Re-evaluate outputs at execution time -->
<ItemGroup>
<PackageXml Include="$(OutDir)Plugin\PackageContents.xml"/>
<RibbonFiles Include="$(OutDir)Plugin\NavisworksRibbon.*"/>
<ResourceFiles Include="$(OutDir)Resources\**\*.png;$(OutDir)Resources\**\*.ico"/>
<AllFiles Include="$(OutDir)**\*.*"/>
<Message Text="AllFiles count: @(AllFiles->Count())" Importance="high"/>
<Warning Condition="'@(AllFiles)' == ''" Text="No files in $(OutDir) at PostBuild time."/>
</ItemGroup>
<Copy SourceFiles="@(PackageXml)"
DestinationFolder="$(PluginBundleTarget)\"
SkipUnchangedFiles="true"/>
<Copy SourceFiles="@(RibbonFiles)"
DestinationFolder="$(PluginVersionContentTarget)\en-US\"
SkipUnchangedFiles="true"/>
<Copy SourceFiles="@(ResourceFiles)"
DestinationFiles="@(ResourceFiles->'$(PluginVersionContentTarget)\Resources\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"/>
<Copy SourceFiles="@(AllFiles)"
DestinationFiles="@(AllFiles->'$(PluginVersionContentTarget)\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"/>
<Message Text="Copied build to $(PluginVersionContentTarget)" Importance="high"/>
</Target>
<Target Name="ValidateNavisworksVersion" BeforeTargets="PostBuild"
Condition="'$(NavisworksVersion)' == '' and '$(OS)' == 'Windows_NT'">
<Error Text="NavisworksVersion property is required for PostBuild packaging."/>
<Copy SourceFiles="$(OutDir)Plugin\PackageContents.xml" DestinationFolder="$(PluginBundleTarget)\"/>
<Copy SourceFiles="@(RibbonFiles)" DestinationFolder="$(PluginVersionContentTarget)\en-US\"/>
<Copy SourceFiles="@(ResourceFiles)" DestinationFolder="$(PluginVersionContentTarget)\Resources\"/>
<Copy SourceFiles="@(AllFiles)" DestinationFolder="$(PluginVersionContentTarget)\" />
</Target>
</Project>
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2020": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2021": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2022": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2023": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -73,8 +73,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -169,29 +169,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -282,8 +259,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +285,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2024": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -79,8 +79,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -175,29 +175,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -288,8 +265,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -313,7 +291,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2025": {
@@ -359,12 +337,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -88,8 +88,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -184,29 +184,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -289,8 +266,9 @@
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -314,7 +292,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.navisworks2026": {
@@ -361,12 +339,35 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -6,22 +6,32 @@ using Speckle.Sdk;
namespace Speckle.Connector.Navisworks.Bindings;
public class NavisworksBasicConnectorBinding(
IBrowserBridge parent,
DocumentModelStore store,
ISpeckleApplication speckleApplication
) : IBasicConnectorBinding
public class NavisworksBasicConnectorBinding : IBasicConnectorBinding
{
public string Name => "baseBinding";
public IBrowserBridge Parent { get; } = parent;
public IBrowserBridge Parent { get; }
public BasicConnectorBindingCommands Commands { get; }
public BasicConnectorBindingCommands Commands { get; } = new(parent);
private readonly DocumentModelStore _store;
private readonly ISpeckleApplication _speckleApplication;
public string GetSourceApplicationName() => speckleApplication.Slug;
public NavisworksBasicConnectorBinding(
IBrowserBridge parent,
DocumentModelStore store,
ISpeckleApplication speckleApplication
)
{
Parent = parent;
_store = store;
_speckleApplication = speckleApplication;
Commands = new BasicConnectorBindingCommands(parent);
}
public string GetSourceApplicationVersion() => speckleApplication.HostApplicationVersion;
public string GetSourceApplicationName() => _speckleApplication.Slug;
public string GetConnectorVersion() => speckleApplication.SpeckleVersion;
public string GetSourceApplicationVersion() => _speckleApplication.HostApplicationVersion;
public string GetConnectorVersion() => _speckleApplication.SpeckleVersion;
public DocumentInfo? GetDocumentInfo() =>
NavisworksApp.ActiveDocument is null || NavisworksApp.ActiveDocument.Models.Count == 0
@@ -32,15 +42,15 @@ public class NavisworksBasicConnectorBinding(
NavisworksApp.ActiveDocument.GetHashCode().ToString()
);
public DocumentModelStore GetDocumentState() => store;
public DocumentModelStore GetDocumentState() => _store;
public void AddModel(ModelCard model) => store.AddModel(model);
public void AddModel(ModelCard model) => _store.AddModel(model);
public void UpdateModel(ModelCard model) => store.UpdateModel(model);
public void UpdateModel(ModelCard model) => _store.UpdateModel(model);
public void RemoveModel(ModelCard model) => store.RemoveModel(model);
public void RemoveModel(ModelCard model) => _store.RemoveModel(model);
public void RemoveModels(List<ModelCard> models) => store.RemoveModels(models);
public void RemoveModels(List<ModelCard> models) => _store.RemoveModels(models);
public Task HighlightModel(string modelCardId) => Task.CompletedTask;
@@ -1,6 +1,6 @@
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Converter.Navisworks.Services;
namespace Speckle.Connector.Navisworks.Bindings;
@@ -1,10 +1,9 @@
using System.IO;
using Autodesk.Navisworks.Api;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connector.Navisworks.Operations.Send.Filters;
using Speckle.Connector.Navisworks.Operations.Send.Settings;
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
@@ -13,11 +12,9 @@ using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Settings;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Sdk.Common;
using Speckle.Sdk.Pipelines.Progress;
namespace Speckle.Connector.Navisworks.Bindings;
@@ -61,12 +58,12 @@ public class NavisworksSendBinding : ISendBinding
private static void SubscribeToNavisworksEvents() { }
// WARNING: Changes to filter behavior here must match everywhere filters are used, or saved sets won't update correctly
// Do not change the behavior/scope of this class on send binding unless make sure the behavior is same. Otherwise, we might not be able to update list of saved sets.
public List<ISendFilter> GetSendFilters() =>
[
new NavisworksSelectionFilter() { IsDefault = true },
new NavisworksSavedSetsFilter(new ConnectorElementSelectionService()),
new NavisworksSavedViewsFilter(new ConnectorElementSelectionService())
new NavisworksSavedSetsFilter(new ElementSelectionService()),
new NavisworksSavedViewsFilter(new ElementSelectionService())
];
public List<ICardSetting> GetSendSettings() =>
@@ -85,27 +82,7 @@ public class NavisworksSendBinding : ISendBinding
private async Task SendInternal(string modelCardId)
{
using var manager = _sendOperationManagerFactory.Create();
var (fileName, fileSizeBytes) = GetFileInfo();
await manager.Process(
Commands,
modelCardId,
InitializeConverterSettings,
GetNavisworksModelItems,
fileName,
fileSizeBytes
);
}
private (string? fileName, long? fileSizeBytes) GetFileInfo()
{
Document? activeDoc = NavisworksApp.ActiveDocument;
if (activeDoc is null || !File.Exists(activeDoc.FileName))
{
return (null, null);
}
FileInfo fileInfo = new(activeDoc.FileName);
return (fileInfo.Name, fileInfo.Length);
await manager.Process(Commands, modelCardId, InitializeConverterSettings, GetNavisworksModelItems);
}
private void InitializeConverterSettings(IServiceProvider serviceProvider, SenderModelCard modelCard) =>
@@ -128,7 +105,6 @@ public class NavisworksSendBinding : ISendBinding
)
{
var selectedPaths = modelCard.SendFilter.NotNull().RefreshObjectIds();
var convertHiddenElementsSetting =
modelCard.Settings!.FirstOrDefault(s => s.Id == "convertHiddenElements")?.Value as bool? ?? false;
var message = convertHiddenElementsSetting
@@ -139,78 +115,30 @@ public class NavisworksSendBinding : ISendBinding
{
throw new SpeckleSendFilterException(message);
}
onOperationProgressed.Report(new CardProgress("Getting selection...", null));
await Task.CompletedTask;
int estimatedCapacity = selectedPaths.Count * 10;
var modelItems = new List<NAV.ModelItem>(estimatedCapacity);
var modelItems = new List<NAV.ModelItem>();
double count = 0;
foreach (var path in selectedPaths)
{
onOperationProgressed.Report(new CardProgress("Getting selection...", count / selectedPaths.Count));
await Task.CompletedTask;
var modelItem = _selectionService.GetModelItemFromPath(path);
var hasChildren = modelItem.Children.Any();
if (hasChildren)
{
int nodesVisited = 0;
int hiddenBranchesPruned = 0;
const int REPORT_INTERVAL = 1000;
void TraverseWithProgress(NAV.ModelItem node)
{
nodesVisited++;
if (nodesVisited % REPORT_INTERVAL == 0)
{
onOperationProgressed.Report(
new CardProgress(
$"Expanding tree: {nodesVisited} visited, {modelItems.Count} with geometry, {hiddenBranchesPruned} hidden",
null
)
);
Task.Delay(1).Wait();
}
if (!_selectionService.IsVisible(node))
{
hiddenBranchesPruned++;
return;
}
if (node.HasGeometry)
{
modelItems.Add(node);
}
foreach (var child in node.Children)
{
TraverseWithProgress(child);
}
}
TraverseWithProgress(modelItem);
}
else
{
if (modelItem.HasGeometry && _selectionService.IsVisible(modelItem))
{
modelItems.Add(modelItem);
}
}
modelItems.AddRange(_selectionService.GetGeometryNodes(modelItem).Where(_selectionService.IsVisible));
count++;
}
return modelItems.Count == 0 ? throw new SpeckleSendFilterException(message) : modelItems;
}
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
/// <summary>
/// Cancels all outstanding send operations for the current document.
/// This method is called when the active document changes, to ensure
/// that any in-progress send operations are properly canceled before
/// the new document is loaded.
/// </summary>
public void CancelAllSendOperations()
{
foreach (var modelCardId in _store.GetSenders().Select(m => m.ModelCardId))
@@ -15,8 +15,8 @@ using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.WebView;
using Speckle.Converter.Navisworks.Constants.Registers;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converters.Common;
using Speckle.Sdk.Models.GraphTraversal;
@@ -53,18 +53,17 @@ public static class NavisworksConnectorServiceRegistration
serviceCollection.AddScoped<NavisworksMaterialUnpacker>();
serviceCollection.AddScoped<NavisworksColorUnpacker>();
// Register dual shared geometry stores for instancing pattern
serviceCollection.AddScoped<InstanceStoreManager>();
serviceCollection.AddSingleton<IAppIdleManager, NavisworksIdleManager>();
// Sending operations
serviceCollection.AddScoped<IRootObjectBuilder<NAV.ModelItem>, NavisworksRootObjectBuilder>();
serviceCollection.AddScoped<IRootContinuousTraversalBuilder<NAV.ModelItem>, NavisworksContinuousTraversalBuilder>();
serviceCollection.AddScoped<SendOperation<NAV.ModelItem>>();
serviceCollection.AddSingleton(DefaultTraversal.CreateTraversalFunc());
serviceCollection.AddSingleton<IOperationProgressManager, OperationProgressManager>();
// Registers and caches
serviceCollection.AddScoped<IInstanceFragmentRegistry, InstanceFragmentRegistry>();
// Register Intercom/interop
serviceCollection.AddSingleton<NavisworksDocumentModelStore>();
serviceCollection.AddSingleton<DocumentModelStore>(sp => sp.GetRequiredService<NavisworksDocumentModelStore>());
@@ -74,9 +73,6 @@ public static class NavisworksConnectorServiceRegistration
serviceCollection.AddScoped<ISendFilter, NavisworksSelectionFilter>();
serviceCollection.AddScoped<ISendFilter, NavisworksSavedSetsFilter>();
serviceCollection.AddScoped<ISendFilter, NavisworksSavedViewsFilter>();
serviceCollection.AddScoped<
Converter.Navisworks.Services.IElementSelectionService,
ConnectorElementSelectionService
>();
serviceCollection.AddScoped<IElementSelectionService, ElementSelectionService>();
}
}
@@ -1,12 +1,31 @@
namespace Speckle.Connector.Navisworks.Services;
using Speckle.InterfaceGenerator;
using static Speckle.Converter.Navisworks.Helpers.ElementSelectionHelper;
/// <summary>
/// Connector-specific element selection service that extends the converter's base implementation.
/// Inherits the cached visibility checking and path resolution from the converter layer.
/// </summary>
public class ConnectorElementSelectionService : Converter.Navisworks.Services.ElementSelectionService
namespace Speckle.Connector.Navisworks.Services;
[GenerateAutoInterface]
public class ElementSelectionService : IElementSelectionService
{
// This inherits all functionality from the converter's ElementSelectionService
// including cached IsVisible, GetModelItemPath, GetModelItemFromPath, and GetGeometryNodes
// Connector-specific extensions can be added here if needed in the future
private readonly Dictionary<Guid, bool> _visibleCache = new();
public string GetModelItemPath(NAV.ModelItem modelItem) => ResolveModelItemToIndexPath(modelItem);
public NAV.ModelItem GetModelItemFromPath(string path) => ResolveIndexPathToModelItem(path);
public bool IsVisible(NAV.ModelItem modelItem)
{
var key = modelItem.InstanceGuid;
if (_visibleCache.TryGetValue(key, out var isVisible))
{
return isVisible;
}
//same as ElementSelectionHelper.IsElementVisible
foreach (var item in modelItem.AncestorsAndSelf)
{
_visibleCache[item.InstanceGuid] = !item.IsHidden;
}
return _visibleCache[key];
}
public IEnumerable<NAV.ModelItem> GetGeometryNodes(NAV.ModelItem modelItem) => ResolveGeometryLeafNodes(modelItem);
}
@@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.Services;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Sdk;
@@ -16,13 +16,7 @@ public class NavisworksColorUnpacker(
IElementSelectionService selectionService
)
{
private static T SelectByRepresentationMode<T>(
RepresentationMode mode,
T active,
T permanent,
T original,
T defaultValue
) =>
private static T Select<T>(RepresentationMode mode, T active, T permanent, T original, T defaultValue) =>
mode switch
{
RepresentationMode.Active => active,
@@ -77,14 +71,14 @@ public class NavisworksColorUnpacker(
using var defaultColor = new NAV.Color(1.0, 1.0, 1.0);
var representationColor = SelectByRepresentationMode(
var representationColor = Select(
mode,
geometry.ActiveColor,
geometry.PermanentColor,
geometry.OriginalColor,
defaultColor
);
var colorId = SelectByRepresentationMode(
var colorId = Select(
mode,
$"{geometry.ActiveColor.GetHashCode()}_{geometry.ActiveTransparency}".GetHashCode(),
$"{geometry.PermanentColor.GetHashCode()}_{geometry.PermanentTransparency}".GetHashCode(),
@@ -130,53 +124,30 @@ public class NavisworksColorUnpacker(
var comSelection = ComBridge.ToInwOpSelection([modelItem]);
try
{
var paths = comSelection.Paths();
try
foreach (ComApi.InwOaPath path in comSelection.Paths())
{
foreach (ComApi.InwOaPath path in paths)
GC.KeepAlive(path);
foreach (ComApi.InwOaFragment3 fragment in path.Fragments())
{
GC.KeepAlive(path);
GC.KeepAlive(fragment);
var fragments = path.Fragments();
try
fragment.GenerateSimplePrimitives(ComApi.nwEVertexProperty.eNORMAL, primitiveChecker);
// Exit early if triangles are found
if (primitiveChecker.HasTriangles)
{
foreach (ComApi.InwOaFragment3 fragment in fragments)
{
GC.KeepAlive(fragment);
fragment.GenerateSimplePrimitives(ComApi.nwEVertexProperty.eNORMAL, primitiveChecker);
if (primitiveChecker.HasTriangles)
{
return false;
}
}
}
finally
{
if (fragments != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(fragments);
}
return false;
}
}
}
return primitiveChecker.HasLines || primitiveChecker.HasPoints || primitiveChecker.HasSnapPoints;
}
finally
{
if (paths != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(paths);
}
}
// Return true if any 2D primitives are found
return primitiveChecker.HasLines || primitiveChecker.HasPoints || primitiveChecker.HasSnapPoints;
}
finally
{
if (comSelection != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
}
}
}
@@ -120,6 +120,17 @@ public sealed class NavisworksDocumentEvents
}
}
private void UnsubscribeFromDocumentModelEvents(object _)
{
var activeDocument = NavisworksApp.ActiveDocument;
if (activeDocument != null)
{
UnsubscribeFromModelEvents(activeDocument);
}
_isSubscribed = false;
}
private void UnsubscribeFromModelEvents(NAV.Document document)
{
document.Models.CollectionChanged -= HandleDocumentModelCountChanged;
@@ -1,27 +1,26 @@
using Autodesk.Navisworks.Api.ComApi;
using Autodesk.Navisworks.Api.Interop.ComApi;
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.Services;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.Objects.Other;
using Speckle.Sdk;
using static Speckle.Converter.Navisworks.Constants.MaterialConstants;
namespace Speckle.Connector.Navisworks.HostApp;
public class NavisworksMaterialUnpacker(
ILogger<NavisworksMaterialUnpacker> logger,
IConverterSettingsStore<NavisworksConversionSettings> converterSettings,
IElementSelectionService selectionService
IElementSelectionService selectionService,
GeometryToSpeckleConverter converter
)
{
private static T SelectByRepresentationMode<T>(
RepresentationMode mode,
T active,
T permanent,
T original,
T defaultValue
) =>
// Helper function to select a property based on the representation mode
// Selector method for individual properties
private static T Select<T>(RepresentationMode mode, T active, T permanent, T original, T defaultValue) =>
mode switch
{
RepresentationMode.Active => active,
@@ -70,26 +69,38 @@ public class NavisworksMaterialUnpacker(
var navisworksObjectId = selectionService.GetModelItemPath(navisworksObject);
var finalId = mergedIds.TryGetValue(navisworksObjectId, out var mergedId) ? mergedId : navisworksObjectId;
var item = selectionService.GetModelItemFromPath(finalId);
string hashId = "";
var comSelection = ComApiBridge.ToInwOpSelection([item]);
var paths = comSelection.Paths();
var path = paths.OfType<InwOaPath>().First();
var fragments = path.Fragments();
if (fragments.Count > 1)
{
var fragmentId = converter.GenerateFragmentId(paths);
hashId = $"geom_{fragmentId}";
}
var geometry = navisworksObject.Geometry;
var mode = converterSettings.Current.User.VisualRepresentationMode;
using var defaultColor = new NAV.Color(1.0, 1.0, 1.0);
var renderColor = SelectByRepresentationMode(
var renderColor = Select(
mode,
geometry.ActiveColor,
geometry.PermanentColor,
geometry.OriginalColor,
defaultColor
);
var renderTransparency = SelectByRepresentationMode(
var renderTransparency = Select(
mode,
geometry.ActiveTransparency,
geometry.PermanentTransparency,
geometry.OriginalTransparency,
0.0
);
var renderMaterialId = SelectByRepresentationMode(
var renderMaterialId = Select(
mode,
$"{geometry.ActiveColor.GetHashCode()}_{geometry.ActiveTransparency}".GetHashCode(),
$"{geometry.PermanentColor.GetHashCode()}_{geometry.PermanentTransparency}".GetHashCode(),
@@ -98,8 +109,9 @@ public class NavisworksMaterialUnpacker(
);
var materialName =
$"{DEFAULT_MATERIAL_NAME_PREFIX}{Math.Abs(ColorConverter.NavisworksColorToColor(renderColor).ToArgb())}";
$"NavisworksMaterial_{Math.Abs(ColorConverter.NavisworksColorToColor(renderColor).ToArgb())}";
// Check Item category for material name
var itemCategory = navisworksObject.PropertyCategories.FindCategoryByDisplayName("Item");
if (itemCategory != null)
{
@@ -111,6 +123,7 @@ public class NavisworksMaterialUnpacker(
}
}
// Check Material category for material name
var materialPropertyCategory = navisworksObject.PropertyCategories.FindCategoryByDisplayName("Material");
if (materialPropertyCategory != null)
{
@@ -124,14 +137,19 @@ public class NavisworksMaterialUnpacker(
if (renderMaterialProxies.TryGetValue(renderMaterialId.ToString(), out RenderMaterialProxy? value))
{
value.objects.Add(finalId);
value.objects.Add(!string.IsNullOrEmpty(hashId) ? hashId : finalId);
}
else
{
renderMaterialProxies[renderMaterialId.ToString()] = new RenderMaterialProxy()
{
value = CreateRenderMaterial(materialName, renderTransparency, renderColor, renderMaterialId),
objects = [finalId]
value = ConvertRenderColorAndTransparencyToSpeckle(
materialName,
renderTransparency,
renderColor,
renderMaterialId
),
objects = [!string.IsNullOrEmpty(hashId) ? hashId : finalId]
};
}
}
@@ -144,7 +162,7 @@ public class NavisworksMaterialUnpacker(
return renderMaterialProxies.Values.ToList();
}
private static RenderMaterial CreateRenderMaterial(
private static RenderMaterial ConvertRenderColorAndTransparencyToSpeckle(
string name,
double transparency,
NAV.Color navisworksColor,
@@ -155,7 +173,7 @@ public class NavisworksMaterialUnpacker(
var speckleRenderMaterial = new RenderMaterial()
{
name = !string.IsNullOrEmpty(name) ? name : $"{DEFAULT_MATERIAL_NAME_PREFIX}{Math.Abs(color.ToArgb())}",
name = !string.IsNullOrEmpty(name) ? name : $"NavisworksMaterial_{Math.Abs(color.ToArgb())}",
opacity = 1 - transparency,
metalness = 0,
roughness = 1,
@@ -1,7 +1,7 @@
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Utils;
using Speckle.Converter.Navisworks.Services;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
@@ -1,7 +1,7 @@
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Utils;
using Speckle.Converter.Navisworks.Services;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
@@ -48,6 +48,8 @@ public class NavisworksSavedViewsFilter : DiscriminatedObject, ISendFilterSelect
return objectIds;
}
var savedViews = NavisworksApp.ActiveDocument.SavedViewpoints;
foreach (var savedViewItem in SelectedItems.Select(item => ResolveSavedView(item.Id)))
{
// Get the visible elements in the saved view.
@@ -80,12 +82,12 @@ public class NavisworksSavedViewsFilter : DiscriminatedObject, ISendFilterSelect
{
var objectIds = new List<string>();
// THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOR - DISCUSSION REQUIRED
// THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOUR - DISCUSSION REQUIRED
// if (!savedView.ContainsVisibilityOverrides)
// {
// // We check this again as the view settings may have changed in the saved card.
// // If the saved view does not contain visibility overrides, this is effectively everything in the model.
// // This will need to be the documented behavior.
// // This will need to be the documented behaviour.
// throw new SpeckleSendFilterException(
// "Saved view does not contain visibility overrides. This would effectively publish everything in the model."
// );
@@ -152,7 +154,7 @@ public class NavisworksSavedViewsFilter : DiscriminatedObject, ISendFilterSelect
switch (item)
{
// case NAV.SavedViewpoint { ContainsVisibilityOverrides: false }:
// Legacy defensive behavior: skip viewpoints without visibility overrides.
// Legacy defensive behaviour: skip viewpoints without visibility overrides.
// Essentially, send everything, or whatever the current view state for hidden elements is.
// break;
case NAV.SavedViewpointAnimationCut:
@@ -1,4 +1,4 @@
using static Speckle.Converter.Navisworks.Constants.PathConstants;
using Speckle.Converter.Navisworks.Constants;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
@@ -15,6 +15,6 @@ public static class SavedItemHelpers
current = current.Parent;
}
return string.Join(SET_SEPARATOR, pathParts);
return string.Join(PathConstants.SET_SEPARATOR, pathParts);
}
}
@@ -1,5 +1,5 @@
using Speckle.Connector.Navisworks.Services;
using static Speckle.Converter.Navisworks.Constants.PathConstants;
using Speckle.Converter.Navisworks.Constants;
namespace Speckle.Connector.Navisworks.Operations.Send;
@@ -10,29 +10,29 @@ public static class GeometryNodeMerger
{
/// <summary>
/// Groups sibling geometry nodes based on material properties for merging.
/// This only merges nodes that share the same parent and have identical material properties.
/// Only merges nodes that share the same parent and have identical material properties.
/// </summary>
/// <param name="nodes">The collection of ModelItems to process</param>
/// <returns>Dictionary mapping parent paths (with material signature suffix) to their mergeable child nodes</returns>
public static Dictionary<string, List<NAV.ModelItem>> GroupSiblingGeometryNodes(IReadOnlyList<NAV.ModelItem> nodes)
{
var selectionService = new ConnectorElementSelectionService();
var selectionService = new ElementSelectionService();
// Group nameless geometry nodes by parent path and material signature
var mergeableGroups = nodes
.Where(node => node.HasGeometry && string.IsNullOrEmpty(node.DisplayName)) // Only anonymous geometry nodes
.GroupBy(node =>
{
// Get the parent path
// Get parent path
var path = selectionService.GetModelItemPath(node);
var lastSeparatorIndex = path.LastIndexOf(SEPARATOR);
var lastSeparatorIndex = path.LastIndexOf(PathConstants.SEPARATOR);
var parentPath = lastSeparatorIndex == -1 ? path : path[..lastSeparatorIndex];
// Generate material signature
string signature = GenerateSignature(node);
// Combine parent path with signature
return $"{parentPath}{MATERIAL_SEPARATOR}{signature}";
return $"{parentPath}{PathConstants.MATERIAL_SEPARATOR}{signature}";
})
.Where(group => group.Count() > 1) // Only include groups with multiple children
.ToDictionary(group => group.Key, group => group.ToList());
@@ -95,7 +95,7 @@ public static class GeometryNodeMerger
// Build a consistent string representation of all properties
var hashInput = new System.Text.StringBuilder();
// Sort keys to ensure a consistent order
// Sort keys to ensure consistent order
var sortedKeys = properties.Keys.OrderBy(k => k).ToList();
foreach (var key in sortedKeys)
@@ -139,7 +139,7 @@ public static class GeometryNodeMerger
/// </summary>
private static string GetMaterialName(NAV.ModelItem node)
{
// Check the Item category for material name
// Check Item category for material name
var itemCategory = node.PropertyCategories.FindCategoryByDisplayName("Item");
if (itemCategory != null)
{
@@ -1,400 +0,0 @@
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.HostApp;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Conversion;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Objects.Data;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
using Speckle.Sdk.Pipelines.Send;
using static Speckle.Connector.Navisworks.Operations.Send.GeometryNodeMerger;
using static Speckle.Connectors.Common.Operations.ProxyKeys;
using static Speckle.Converter.Navisworks.Constants.InstanceConstants;
namespace Speckle.Connector.Navisworks.Operations.Send;
/// <summary>
/// Continuous traversal builder for Navisworks that streams objects through a <see cref="SendPipeline"/>
/// for packfile-based uploads. Same conversion/grouping logic as <see cref="NavisworksRootObjectBuilder"/>,
/// but processes final elements through the pipeline after all post-processing is complete.
/// </summary>
public class NavisworksContinuousTraversalBuilder(
IRootToSpeckleConverter rootToSpeckleConverter,
IConverterSettingsStore<NavisworksConversionSettings> converterSettings,
ILogger<NavisworksContinuousTraversalBuilder> logger,
ISdkActivityFactory activityFactory,
NavisworksMaterialUnpacker materialUnpacker,
NavisworksColorUnpacker colorUnpacker,
Speckle.Converter.Navisworks.Constants.Registers.IInstanceFragmentRegistry instanceRegistry,
IElementSelectionService elementSelectionService,
IUiUnitsCache uiUnitsCache
) : IRootContinuousTraversalBuilder<NAV.ModelItem>
{
private bool SkipNodeMerging { get; set; }
private bool DisableGroupingForInstanceTesting { get; set; }
public async Task<RootObjectBuilderResult> Build(
IReadOnlyList<NAV.ModelItem> navisworksModelItems,
string projectId,
SendPipeline sendPipeline,
IProgress<CardProgress> onOperationProgressed,
CancellationToken cancellationToken
)
{
#if DEBUG
SkipNodeMerging = false;
DisableGroupingForInstanceTesting = false;
#endif
using var activity = activityFactory.Start("Build");
ValidateInputs(navisworksModelItems, projectId, onOperationProgressed);
var rootCollection = InitializeRootCollection();
(Dictionary<string, Base?> convertedElements, List<SendConversionResult> conversionResults) =
await ConvertModelItemsAsync(navisworksModelItems, onOperationProgressed, cancellationToken);
ValidateConversionResults(conversionResults);
var groupedNodes = SkipNodeMerging ? [] : GroupSiblingGeometryNodes(navisworksModelItems);
var finalElements = BuildFinalElements(convertedElements, groupedNodes);
await AddProxiesToCollection(rootCollection, navisworksModelItems, groupedNodes);
AddInstanceDefinitionsToCollection(rootCollection, ref finalElements);
// Process each final element through the send pipeline
var processedElements = new List<Base>(finalElements.Count);
foreach (var element in finalElements)
{
cancellationToken.ThrowIfCancellationRequested();
// NOTE: this is the main part that differentiate from the main root object builder
var reference = await sendPipeline.Process(element).ConfigureAwait(false);
processedElements.Add(reference);
}
rootCollection.elements = processedElements;
// Process the root collection and wait for all uploads to complete
await sendPipeline.Process(rootCollection);
await sendPipeline.WaitForUpload();
return new RootObjectBuilderResult(rootCollection, conversionResults);
}
private static void ValidateInputs(
IReadOnlyList<NAV.ModelItem> navisworksModelItems,
string projectId,
IProgress<CardProgress> onOperationProgressed
)
{
if (!navisworksModelItems.Any())
{
throw new SpeckleException("No objects to convert");
}
if (navisworksModelItems == null)
{
throw new ArgumentNullException(nameof(navisworksModelItems));
}
if (onOperationProgressed == null || projectId == null)
{
throw new ArgumentNullException(
onOperationProgressed == null ? nameof(onOperationProgressed) : nameof(projectId)
);
}
}
private Collection InitializeRootCollection() =>
new()
{
name = NavisworksApp.ActiveDocument.Title ?? "Unnamed model",
["units"] = converterSettings.Current.Derived.SpeckleUnits
};
private Task<(Dictionary<string, Base?> converted, List<SendConversionResult> results)> ConvertModelItemsAsync(
IReadOnlyList<NAV.ModelItem> navisworksModelItems,
IProgress<CardProgress> onOperationProgressed,
CancellationToken cancellationToken
)
{
var results = new List<SendConversionResult>(navisworksModelItems.Count);
var convertedBases = new Dictionary<string, Base?>();
int processedCount = 0;
int totalCount = navisworksModelItems.Count;
foreach (var item in navisworksModelItems)
{
cancellationToken.ThrowIfCancellationRequested();
var converted = ConvertNavisworksItem(item, convertedBases);
results.Add(converted);
processedCount++;
onOperationProgressed.Report(new CardProgress("Converting", (double)processedCount / totalCount));
}
return Task.FromResult((convertedBases, results));
}
private static void ValidateConversionResults(List<SendConversionResult> results)
{
if (results.All(x => x.Status == Status.ERROR))
{
throw new SpeckleException("Failed to convert all objects.");
}
}
private List<Base> BuildFinalElements(
Dictionary<string, Base?> convertedBases,
Dictionary<string, List<NAV.ModelItem>> groupedNodes
)
{
var finalElements = new List<Base>();
var processedPaths = new HashSet<string>();
if (!DisableGroupingForInstanceTesting)
{
AddGroupedElements(finalElements, convertedBases, groupedNodes, processedPaths);
logger.LogInformation(
"After grouping: {grouped} paths processed, {elements} elements in collection",
processedPaths.Count,
finalElements.Count
);
}
else
{
logger.LogInformation("Grouping disabled for instance testing");
}
if (converterSettings.Current.User.PreserveModelHierarchy)
{
logger.LogInformation("Building hierarchy (PreserveModelHierarchy=true)");
var hierarchyBuilder = new NavisworksHierarchyBuilder(
convertedBases,
rootToSpeckleConverter,
elementSelectionService
);
return hierarchyBuilder.BuildHierarchy();
}
logger.LogInformation("Adding remaining elements (flat mode)");
AddRemainingElements(finalElements, convertedBases, processedPaths);
logger.LogInformation("Final elements count: {count}", finalElements.Count);
return finalElements;
}
private void AddGroupedElements(
List<Base> finalElements,
Dictionary<string, Base?> convertedBases,
Dictionary<string, List<NAV.ModelItem>> groupedNodes,
HashSet<string> processedPaths
)
{
foreach (var group in groupedNodes)
{
var siblingBases = new List<Base>(group.Value.Count);
foreach (var itemPath in group.Value.Select(elementSelectionService.GetModelItemPath))
{
processedPaths.Add(itemPath);
if (convertedBases.TryGetValue(itemPath, out var convertedBase) && convertedBase != null)
{
siblingBases.Add(convertedBase);
}
}
if (siblingBases.Count > 0)
{
finalElements.Add(CreateNavisworksObject(group.Key, siblingBases));
}
}
}
private void AddRemainingElements(
List<Base> finalElements,
Dictionary<string, Base?> convertedBases,
HashSet<string> processedPaths
)
{
foreach (var kvp in convertedBases.Where(kvp => !processedPaths.Contains(kvp.Key)))
{
switch (kvp.Value)
{
case null:
continue;
case Collection collection:
finalElements.Add(collection);
break;
default:
if (CreateNavisworksObject(kvp.Value) is { } navisworksObject)
{
finalElements.Add(navisworksObject);
}
break;
}
}
}
private (string name, string path) GetElementNameAndPath(string applicationId)
{
var modelItem = elementSelectionService.GetModelItemFromPath(applicationId);
var context = HierarchyHelper.ExtractContext(modelItem);
return (context.Name, context.Path);
}
private NavisworksObject CreateNavisworksObject(string groupKey, List<Base> siblingBases)
{
string cleanParentPath = ElementSelectionHelper.GetCleanPath(groupKey);
(string name, string path) = GetElementNameAndPath(cleanParentPath);
int estimatedCapacity = siblingBases.Sum(b => (b["displayValue"] as List<Base>)?.Count ?? 0);
var displayValues = new List<Base>(estimatedCapacity);
displayValues.AddRange(
siblingBases
.Where(sibling => sibling["displayValue"] is List<Base>)
.SelectMany(sibling => (List<Base>)sibling["displayValue"]!)
);
return new NavisworksObject
{
name = name,
displayValue = displayValues,
properties = siblingBases.First()["properties"] as Dictionary<string, object?> ?? [],
units = converterSettings.Current.Derived.SpeckleUnits,
applicationId = groupKey,
["path"] = path
};
}
private NavisworksObject? CreateNavisworksObject(Base convertedBase)
{
if (convertedBase.applicationId == null)
{
return null;
}
(string name, string path) = GetElementNameAndPath(convertedBase.applicationId);
var units = uiUnitsCache.Ensure();
return new NavisworksObject
{
name = name,
displayValue = convertedBase["displayValue"] as List<Base> ?? [],
properties = convertedBase["properties"] as Dictionary<string, object?> ?? [],
units = units.ToString(),
applicationId = convertedBase.applicationId,
["path"] = path
};
}
private Task AddProxiesToCollection(
Collection rootCollection,
IReadOnlyList<NAV.ModelItem> navisworksModelItems,
Dictionary<string, List<NAV.ModelItem>> groupedNodes
)
{
using var _ = activityFactory.Start("UnpackProxies");
var renderMaterials = materialUnpacker.UnpackRenderMaterial(navisworksModelItems, groupedNodes);
if (renderMaterials.Count > 0)
{
rootCollection[RENDER_MATERIAL] = renderMaterials;
}
var colors = colorUnpacker.UnpackColor(navisworksModelItems, groupedNodes);
if (colors.Count > 0)
{
rootCollection[COLOR] = colors;
}
return Task.CompletedTask;
}
private void AddInstanceDefinitionsToCollection(Collection rootCollection, ref List<Base> finalElements)
{
using var _ = activityFactory.Start("BuildInstanceDefinitions");
var allDefinitions = instanceRegistry.GetAllDefinitionGeometries();
if (allDefinitions.Count == 0)
{
logger.LogInformation("No instance definitions found - instancing may be disabled");
return;
}
logger.LogInformation("Building instance structure for {count} definition groups", allDefinitions.Count);
var instanceDefinitionProxies = new List<InstanceDefinitionProxy>(allDefinitions.Count);
int estimatedGeometryCount = allDefinitions.Sum(kvp => kvp.Value.Count);
var allDefinitionGeometries = new List<Base>(estimatedGeometryCount);
foreach (var kvp in allDefinitions)
{
var groupKey = kvp.Key;
var geometries = kvp.Value;
var groupKeyPath = groupKey.ToPathString();
var defProxy = new InstanceDefinitionProxy
{
name = $"Shared Geometry {groupKeyPath}",
objects = geometries.Select(g => g.applicationId ?? "").Where(id => !string.IsNullOrEmpty(id)).ToList(),
applicationId = $"{DEFINITION_ID_PREFIX}{groupKeyPath}",
maxDepth = 0
};
instanceDefinitionProxies.Add(defProxy);
allDefinitionGeometries.AddRange(geometries);
}
rootCollection[INSTANCE_DEFINITION] = instanceDefinitionProxies;
var geometryDefinitionsCollection = new Collection
{
name = "Geometry Definitions",
elements = allDefinitionGeometries
};
var objectCollection = new Collection { name = "", elements = finalElements };
finalElements = [geometryDefinitionsCollection, objectCollection];
logger.LogInformation(
"Added {proxyCount} instance definition proxies and {geomCount} definition geometries",
instanceDefinitionProxies.Count,
allDefinitionGeometries.Count
);
}
private SendConversionResult ConvertNavisworksItem(
NAV.ModelItem navisworksItem,
Dictionary<string, Base?> convertedBases
)
{
string applicationId = elementSelectionService.GetModelItemPath(navisworksItem);
string sourceType = navisworksItem.GetType().Name;
try
{
Base converted = rootToSpeckleConverter.Convert(navisworksItem);
convertedBases[applicationId] = converted;
return new SendConversionResult(Status.SUCCESS, applicationId, sourceType, converted);
}
catch (Exception ex) when (!ex.IsFatal())
{
logger.LogError(ex, "Failed to convert model item {id}", applicationId);
return new SendConversionResult(Status.ERROR, applicationId, "ModelItem", null, ex);
}
}
}
@@ -1,8 +1,8 @@
using Speckle.Converter.Navisworks.Services;
using Speckle.Connector.Navisworks.Services;
using Speckle.Converter.Navisworks.Constants;
using Speckle.Converters.Common;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using static Speckle.Converter.Navisworks.Constants.PathConstants;
namespace Speckle.Connector.Navisworks.Operations.Send;
@@ -59,8 +59,8 @@ public class NavisworksHierarchyBuilder
allPaths.Sort(
(a, b) =>
{
var depthA = a.Count(c => c == SEPARATOR);
var depthB = b.Count(c => c == SEPARATOR);
var depthA = a.Count(c => c == PathConstants.SEPARATOR);
var depthB = b.Count(c => c == PathConstants.SEPARATOR);
return depthB.CompareTo(depthA); // <- Sort in ascending order of path length
}
);
@@ -126,7 +126,7 @@ public class NavisworksHierarchyBuilder
private static string GetParentPath(string path)
{
var idx = path.LastIndexOf(SEPARATOR);
var idx = path.LastIndexOf(PathConstants.SEPARATOR);
return idx == -1 ? string.Empty : path[..idx];
}
@@ -1,8 +1,10 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.HostApp;
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
@@ -12,11 +14,7 @@ using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Instances;
using Speckle.Sdk.Pipelines.Progress;
using static Speckle.Connector.Navisworks.Operations.Send.GeometryNodeMerger;
using static Speckle.Connectors.Common.Operations.ProxyKeys;
using static Speckle.Converter.Navisworks.Constants.InstanceConstants;
namespace Speckle.Connector.Navisworks.Operations.Send;
@@ -28,15 +26,13 @@ public class NavisworksRootObjectBuilder(
ISdkActivityFactory activityFactory,
NavisworksMaterialUnpacker materialUnpacker,
NavisworksColorUnpacker colorUnpacker,
Speckle.Converter.Navisworks.Constants.Registers.IInstanceFragmentRegistry instanceRegistry,
IElementSelectionService elementSelectionService,
IUiUnitsCache uiUnitsCache
InstanceStoreManager instanceStoreManager
) : IRootObjectBuilder<NAV.ModelItem>
{
#pragma warning disable CA1823
#pragma warning restore CA1823
private bool SkipNodeMerging { get; set; }
private bool DisableGroupingForInstanceTesting { get; set; }
internal NavisworksConversionSettings GetCurrentSettings() => converterSettings.Current;
public async Task<RootObjectBuilderResult> Build(
IReadOnlyList<NAV.ModelItem> navisworksModelItems,
@@ -46,14 +42,19 @@ public class NavisworksRootObjectBuilder(
)
{
#if DEBUG
SkipNodeMerging = false;
DisableGroupingForInstanceTesting = false;
// This is a temporary workaround to disable node merging for debugging purposes - false is default, true is for debugging
SkipNodeMerging = true;
#endif
using var activity = activityFactory.Start("Build");
ValidateInputs(navisworksModelItems, projectId, onOperationProgressed);
// 2. Initialize root collection
var rootCollection = InitializeRootCollection();
// InstanceStoreManager is scoped - starts fresh for each conversion session
// 3. Convert all model items and store results
(Dictionary<string, Base?> convertedElements, List<SendConversionResult> conversionResults) =
await ConvertModelItemsAsync(navisworksModelItems, projectId, onOperationProgressed, cancellationToken);
@@ -61,17 +62,32 @@ public class NavisworksRootObjectBuilder(
var groupedNodes = SkipNodeMerging ? [] : GroupSiblingGeometryNodes(navisworksModelItems);
var finalElements = BuildFinalElements(convertedElements, groupedNodes);
List<Base> geometryDefinitions = instanceStoreManager.GetGeometryDefinitions();
await AddProxiesToCollection(rootCollection, navisworksModelItems, groupedNodes);
AddInstanceDefinitionsToCollection(rootCollection, ref finalElements);
int finalInstanceProxyCount = CountInstanceProxiesRecursive(finalElements);
logger.LogInformation(
"Final output contains {count} InstanceProxy objects in displayValues",
finalInstanceProxyCount
);
// rootCollection.elements will contain two Collections: one for geometry definitions and one for the main elements
var geometryDefinitionsCollection = new Collection
{
name = "Geometry Definitions",
["units"] = converterSettings.Current.Derived.SpeckleUnits,
elements = geometryDefinitions
};
var mainElementsCollection = new Collection
{
name = rootCollection.name,
["units"] = converterSettings.Current.Derived.SpeckleUnits,
elements = finalElements
};
rootCollection.elements = [mainElementsCollection];
if (geometryDefinitions.Count > 0)
{
rootCollection.elements.Add(geometryDefinitionsCollection);
}
rootCollection.elements = finalElements;
return new RootObjectBuilderResult(rootCollection, conversionResults);
}
@@ -117,32 +133,16 @@ public class NavisworksRootObjectBuilder(
var convertedBases = new Dictionary<string, Base?>();
int processedCount = 0;
int totalCount = navisworksModelItems.Count;
int instanceProxyCount = 0;
foreach (var item in navisworksModelItems)
{
cancellationToken.ThrowIfCancellationRequested();
var converted = ConvertNavisworksItem(item, convertedBases, projectId);
results.Add(converted);
if (
converted.Status == Status.SUCCESS
&& convertedBases.TryGetValue(elementSelectionService.GetModelItemPath(item), out var convertedBase)
&& convertedBase?["displayValue"] is List<Base> displayValues
)
{
instanceProxyCount += displayValues.Count(dv => dv.GetType().Name == "InstanceProxy");
}
processedCount++;
onOperationProgressed.Report(new CardProgress("Converting", (double)processedCount / totalCount));
}
logger.LogInformation(
"Converted {total} items, found {instanceProxies} InstanceProxy objects",
totalCount,
instanceProxyCount
);
return Task.FromResult((convertedBases, results));
}
@@ -159,39 +159,27 @@ public class NavisworksRootObjectBuilder(
Dictionary<string, List<NAV.ModelItem>> groupedNodes
)
{
// First build the grouped nodes as before
var finalElements = new List<Base>();
var processedPaths = new HashSet<string>();
AddGroupedElements(finalElements, convertedBases, groupedNodes, processedPaths);
if (!DisableGroupingForInstanceTesting)
{
AddGroupedElements(finalElements, convertedBases, groupedNodes, processedPaths);
logger.LogInformation(
"After grouping: {grouped} paths processed, {elements} elements in collection",
processedPaths.Count,
finalElements.Count
);
}
else
{
logger.LogInformation("Grouping disabled for instance testing");
}
// If hierarchy mode is enabled, reorganize into proper nested structure
if (converterSettings.Current.User.PreserveModelHierarchy)
{
logger.LogInformation("Building hierarchy (PreserveModelHierarchy=true)");
var hierarchyBuilder = new NavisworksHierarchyBuilder(
convertedBases,
rootToSpeckleConverter,
elementSelectionService
);
return hierarchyBuilder.BuildHierarchy();
var hierarchy = hierarchyBuilder.BuildHierarchy();
return hierarchy;
}
logger.LogInformation("Adding remaining elements (flat mode)");
// Otherwise continue with flat mode
AddRemainingElements(finalElements, convertedBases, processedPaths);
logger.LogInformation("Final elements count: {count}", finalElements.Count);
return finalElements;
}
@@ -204,7 +192,7 @@ public class NavisworksRootObjectBuilder(
{
foreach (var group in groupedNodes)
{
var siblingBases = new List<Base>(group.Value.Count);
var siblingBases = new List<Base>();
foreach (var itemPath in group.Value.Select(elementSelectionService.GetModelItemPath))
{
processedPaths.Add(itemPath);
@@ -247,48 +235,41 @@ public class NavisworksRootObjectBuilder(
}
}
private (string name, string path) GetElementNameAndPath(string applicationId)
private (string name, string path) GetContext(string applicationId)
{
var modelItem = elementSelectionService.GetModelItemFromPath(applicationId);
var context = HierarchyHelper.ExtractContext(modelItem);
return (context.Name, context.Path);
}
/// <summary>
/// Processes and adds any remaining non-grouped elements.
/// </summary>
/// <remarks>
/// Handles both Collection and Base type elements differently.
/// Only processes elements that weren't handled in grouped processing.
/// </remarks>
private NavisworksObject CreateNavisworksObject(string groupKey, List<Base> siblingBases)
{
string cleanParentPath = ElementSelectionHelper.GetCleanPath(groupKey);
(string name, string path) = GetElementNameAndPath(cleanParentPath);
int estimatedCapacity = siblingBases.Sum(b => (b["displayValue"] as List<Base>)?.Count ?? 0);
var displayValues = new List<Base>(estimatedCapacity);
displayValues.AddRange(
siblingBases
.Where(sibling => sibling["displayValue"] is List<Base>)
.SelectMany(sibling => (List<Base>)sibling["displayValue"]!)
);
var instanceProxyCount = displayValues.Count(dv => dv.GetType().Name == "InstanceProxy");
if (instanceProxyCount > 0)
{
logger.LogDebug(
"Group {groupKey} merging {siblings} siblings with {proxies} InstanceProxy objects",
groupKey,
siblingBases.Count,
instanceProxyCount
);
}
(string name, string path) = GetContext(cleanParentPath);
return new NavisworksObject
{
name = name,
displayValue = displayValues,
displayValue = siblingBases.SelectMany(b => b["displayValue"] as List<Base> ?? []).ToList(),
properties = siblingBases.First()["properties"] as Dictionary<string, object?> ?? [],
units = converterSettings.Current.Derived.SpeckleUnits,
applicationId = groupKey,
applicationId = groupKey, // Use the full composite key as applicationId to preserve uniqueness
["path"] = path
};
}
/// <summary>
/// Creates a NavisworksObject from a single converted base.
/// </summary>
/// <param name="convertedBase">The converted Speckle Base object.</param>
/// <returns>A new NavisworksObject containing the converted data.</returns>
private NavisworksObject? CreateNavisworksObject(Base convertedBase)
{
if (convertedBase.applicationId == null)
@@ -296,16 +277,14 @@ public class NavisworksRootObjectBuilder(
return null;
}
(string name, string path) = GetElementNameAndPath(convertedBase.applicationId);
var units = uiUnitsCache.Ensure();
(string name, string path) = GetContext(convertedBase.applicationId);
return new NavisworksObject
{
name = name,
displayValue = convertedBase["displayValue"] as List<Base> ?? [],
properties = convertedBase["properties"] as Dictionary<string, object?> ?? [],
units = units.ToString(),
units = converterSettings.Current.Derived.SpeckleUnits,
applicationId = convertedBase.applicationId,
["path"] = path
};
@@ -322,100 +301,45 @@ public class NavisworksRootObjectBuilder(
var renderMaterials = materialUnpacker.UnpackRenderMaterial(navisworksModelItems, groupedNodes);
if (renderMaterials.Count > 0)
{
rootCollection[RENDER_MATERIAL] = renderMaterials;
rootCollection[ProxyKeys.RENDER_MATERIAL] = renderMaterials;
}
var colors = colorUnpacker.UnpackColor(navisworksModelItems, groupedNodes);
if (colors.Count > 0)
{
rootCollection[COLOR] = colors;
rootCollection[ProxyKeys.COLOR] = colors;
}
// Add instance definition proxies from dual store
var instanceDefinitionProxies = instanceStoreManager.GetInstanceDefinitionProxies();
logger.LogDebug("Retrieved {Count} instance definition proxies from store", instanceDefinitionProxies.Count);
if (instanceDefinitionProxies.Count > 0)
{
rootCollection[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies.ToList();
logger.LogDebug(
"Added {Count} instance definition proxies to root collection under key '{Key}'",
instanceDefinitionProxies.Count,
ProxyKeys.INSTANCE_DEFINITION
);
}
else
{
logger.LogDebug("No instance definition proxies to add to root collection");
}
return Task.CompletedTask;
}
private void AddInstanceDefinitionsToCollection(Collection rootCollection, ref List<Base> finalElements)
{
using var _ = activityFactory.Start("BuildInstanceDefinitions");
// Get all definition geometries from the registry
var allDefinitions = instanceRegistry.GetAllDefinitionGeometries();
if (allDefinitions.Count == 0)
{
logger.LogInformation("No instance definitions found - instancing may be disabled");
return;
}
logger.LogInformation("Building instance structure for {count} definition groups", allDefinitions.Count);
if (allDefinitions.Count > 100)
{
logger.LogWarning(
"Large number of definition groups ({count}) detected - this may indicate instance grouping is not working effectively",
allDefinitions.Count
);
}
var instanceDefinitionProxies = new List<InstanceDefinitionProxy>(allDefinitions.Count);
int estimatedGeometryCount = allDefinitions.Sum(kvp => kvp.Value.Count);
var allDefinitionGeometries = new List<Base>(estimatedGeometryCount);
foreach (var kvp in allDefinitions)
{
var groupKey = kvp.Key;
var geometries = kvp.Value;
var groupKeyPath = groupKey.ToPathString();
var defProxy = new InstanceDefinitionProxy
{
name = $"Shared Geometry {groupKeyPath}",
objects = geometries.Select(g => g.applicationId ?? "").Where(id => !string.IsNullOrEmpty(id)).ToList(),
applicationId = $"{DEFINITION_ID_PREFIX}{groupKeyPath}",
maxDepth = 0
};
instanceDefinitionProxies.Add(defProxy);
allDefinitionGeometries.AddRange(geometries);
}
rootCollection[INSTANCE_DEFINITION] = instanceDefinitionProxies;
var geometryDefinitionsCollection = new Collection
{
name = "Geometry Definitions",
elements = allDefinitionGeometries
};
var objectCollection = new Collection { name = "", elements = finalElements };
finalElements = [geometryDefinitionsCollection, objectCollection];
logger.LogInformation(
"Added {proxyCount} instance definition proxies and {geomCount} definition geometries",
instanceDefinitionProxies.Count,
allDefinitionGeometries.Count
);
}
private int CountInstanceProxiesRecursive(List<Base> elements)
{
int count = 0;
foreach (var element in elements)
{
if (element["displayValue"] is List<Base> displayValues)
{
count += displayValues.Count(dv => dv.GetType().Name == "InstanceProxy");
}
if (element is Collection { elements: not null } collection)
{
count += CountInstanceProxiesRecursive(collection.elements);
}
}
return count;
}
/// <summary>
/// Converts a single Navisworks item to a Speckle object.
/// </summary>
/// <remarks>
/// Attempts to retrieve from cache first.
/// Falls back to fresh conversion if not cached.
/// Logs errors but doesn't throw exceptions.
/// </remarks>
/// <returns>A SendConversionResult indicating success or failure.</returns>
private SendConversionResult ConvertNavisworksItem(
NAV.ModelItem navisworksItem,
Dictionary<string, Base?> convertedBases,
@@ -1,4 +1,5 @@
using Speckle.Connectors.Common.Caching;
using System.Diagnostics.CodeAnalysis;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Converter.Navisworks.Settings;
using Speckle.InterfaceGenerator;
@@ -7,106 +8,158 @@ using Speckle.Sdk.Common;
namespace Speckle.Connector.Navisworks.Operations.Send.Settings;
[GenerateAutoInterface]
public class ToSpeckleSettingsManagerNavisworks(ISendConversionCache sendConversionCache)
: IToSpeckleSettingsManagerNavisworks
public class ToSpeckleSettingsManagerNavisworks : IToSpeckleSettingsManagerNavisworks
{
// cache invalidation process run with ModelCardId since the settings are model-specific
private readonly ISendConversionCache _sendConversionCache;
// cache invalidation process run with ModelCardId since the settings are model specific
private readonly Dictionary<string, RepresentationMode> _visualRepresentationCache = [];
private readonly Dictionary<string, OriginMode> _originModeCache = [];
private readonly Dictionary<string, bool> _convertHiddenElementsCache = [];
private readonly Dictionary<string, bool> _includeInternalPropertiesCache = [];
private readonly Dictionary<string, bool> _preserveModelHierarchyCache = [];
private readonly Dictionary<string, bool> _revitCategoryMappingCache = [];
private readonly Dictionary<string, bool?> _convertHiddenElementsCache = [];
private readonly Dictionary<string, bool?> _includeInternalPropertiesCache = [];
private readonly Dictionary<string, bool?> _preserveModelHierarchyCache = [];
private readonly Dictionary<string, bool?> _revitCategoryMappingCache = [];
/// <summary>
/// Generic helper to get a setting value with caching and cache invalidation.
/// </summary>
private T GetCachedSetting<T>(
SenderModelCard modelCard,
string settingId,
Dictionary<string, T> cache,
Func<object?, T> valueExtractor,
T defaultValue
)
public ToSpeckleSettingsManagerNavisworks(ISendConversionCache sendConversionCache)
{
_sendConversionCache = sendConversionCache;
}
public RepresentationMode GetVisualRepresentationMode(SenderModelCard modelCard)
{
if (modelCard == null)
{
throw new ArgumentNullException(nameof(modelCard));
}
var settingValue = modelCard.Settings?.FirstOrDefault(s => s.Id == settingId)?.Value;
var returnValue = settingValue != null ? valueExtractor(settingValue) : defaultValue;
var representationString = modelCard.Settings?.First(s => s.Id == "visualRepresentation").Value as string;
if (
cache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousValue)
&& !EqualityComparer<T>.Default.Equals(previousValue, returnValue)
representationString is not null
&& VisualRepresentationSetting.VisualRepresentationMap.TryGetValue(
representationString,
out RepresentationMode representation
)
)
{
if (_visualRepresentationCache.TryGetValue(modelCard.ModelCardId.NotNull(), out RepresentationMode previousType))
{
if (previousType != representation)
{
EvictCacheForModelCard(modelCard);
}
}
_visualRepresentationCache[modelCard.ModelCardId.NotNull()] = representation;
return representation;
}
throw new ArgumentException($"Invalid visual representation value: {representationString}");
}
public OriginMode GetOriginMode(SenderModelCard modelCard)
{
if (modelCard == null)
{
throw new ArgumentNullException(nameof(modelCard));
}
var originString = modelCard.Settings?.FirstOrDefault(s => s.Id == "originMode")?.Value as string;
if (!OriginModeSetting.OriginModeMap.TryGetValue(originString ?? string.Empty, out var origin))
{
return OriginMode.ModelOrigin; // Default to ModelOrigin if not specified or invalid
}
if (_originModeCache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousType) && previousType != origin)
{
EvictCacheForModelCard(modelCard);
}
cache[modelCard.ModelCardId.NotNull()] = returnValue;
_originModeCache[modelCard.ModelCardId.NotNull()] = origin;
return origin;
}
public bool GetMappingToRevitCategories(SenderModelCard modelCard)
{
if (modelCard == null)
{
throw new ArgumentNullException(nameof(modelCard));
}
var value = modelCard.Settings?.FirstOrDefault(s => s.Id == "mappingToRevitCategories")?.Value as bool?;
var returnValue = value != null && value.NotNull();
if (_revitCategoryMappingCache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousValue))
{
if (previousValue != returnValue)
{
EvictCacheForModelCard(modelCard);
}
}
_revitCategoryMappingCache[modelCard.ModelCardId] = returnValue;
return returnValue;
}
public RepresentationMode GetVisualRepresentationMode(SenderModelCard modelCard) =>
GetCachedSetting(
modelCard,
"visualRepresentation",
_visualRepresentationCache,
value =>
public bool GetConvertHiddenElements(SenderModelCard modelCard)
{
if (modelCard == null)
{
throw new ArgumentNullException(nameof(modelCard));
}
var value = modelCard.Settings?.FirstOrDefault(s => s.Id == "convertHiddenElements")?.Value as bool?;
var returnValue = value != null && value.NotNull();
if (_convertHiddenElementsCache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousValue))
{
if (previousValue != returnValue)
{
var representationString = value as string;
return
representationString is not null
&& VisualRepresentationSetting.VisualRepresentationMap.TryGetValue(
representationString,
out RepresentationMode representation
)
? representation
: throw new ArgumentException($"Invalid visual representation value: {representationString}");
},
RepresentationMode.Active // default value if setting not found
);
EvictCacheForModelCard(modelCard);
}
}
public OriginMode GetOriginMode(SenderModelCard modelCard) =>
GetCachedSetting(
modelCard,
"originMode",
_originModeCache,
value =>
_convertHiddenElementsCache[modelCard.ModelCardId] = returnValue;
return returnValue;
}
public bool GetIncludeInternalProperties([NotNull] SenderModelCard modelCard)
{
var value = modelCard.Settings?.FirstOrDefault(s => s.Id == "includeInternalProperties")?.Value as bool?;
var returnValue = value != null && value.NotNull();
if (_includeInternalPropertiesCache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousValue))
{
if (previousValue != returnValue)
{
var originString = value as string;
if (OriginModeSetting.OriginModeMap.TryGetValue(originString ?? string.Empty, out var origin))
{
return origin;
}
return OriginMode.ModelOrigin;
},
OriginMode.ModelOrigin
);
EvictCacheForModelCard(modelCard);
}
}
public bool GetMappingToRevitCategories(SenderModelCard modelCard) =>
GetCachedSetting(modelCard, "mappingToRevitCategories", _revitCategoryMappingCache, value => value is true, false);
_includeInternalPropertiesCache[modelCard.ModelCardId] = returnValue;
return returnValue;
}
public bool GetConvertHiddenElements(SenderModelCard modelCard) =>
GetCachedSetting(modelCard, "convertHiddenElements", _convertHiddenElementsCache, value => value is true, false);
public bool GetPreserveModelHierarchy([NotNull] SenderModelCard modelCard)
{
var value = modelCard.Settings?.FirstOrDefault(s => s.Id == "preserveModelHierarchy")?.Value as bool?;
public bool GetIncludeInternalProperties(SenderModelCard modelCard) =>
GetCachedSetting(
modelCard,
"includeInternalProperties",
_includeInternalPropertiesCache,
value => value is true,
false
);
var returnValue = value != null && value.NotNull();
if (_preserveModelHierarchyCache.TryGetValue(modelCard.ModelCardId.NotNull(), out var previousValue))
{
if (previousValue != returnValue)
{
EvictCacheForModelCard(modelCard);
}
}
public bool GetPreserveModelHierarchy(SenderModelCard modelCard) =>
GetCachedSetting(modelCard, "preserveModelHierarchy", _preserveModelHierarchyCache, value => value is true, false);
_preserveModelHierarchyCache[modelCard.ModelCardId] = returnValue;
return returnValue;
}
private void EvictCacheForModelCard(SenderModelCard modelCard)
{
var objectIds = modelCard.SendFilter != null ? modelCard.SendFilter.NotNull().SelectedObjectIds : [];
sendConversionCache.EvictObjects(objectIds);
_sendConversionCache.EvictObjects(objectIds);
}
}
@@ -14,7 +14,7 @@ public static class SpeckleV3Tool
public const string RIBBON_STRINGS = "NavisworksRibbon.name";
public const string PLUGIN_SUFFIX = ".Speckle";
public static Sdk.Application App =>
public static Speckle.Sdk.Application App =>
#if NAVIS
HostApplications.Navisworks;
#else
@@ -24,7 +24,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Filters\SavedItemHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\GeometryNodeMerger.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\NavisworksHierarchyBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\NavisworksContinuousTraversalBuilder.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\NavisworksRootObjectBuilder.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Settings\ConvertHiddenElementsSetting.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Settings\IncludeInternalPropertiesSetting.cs"/>
@@ -95,8 +95,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -191,29 +191,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -299,20 +276,14 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
"speckle.common.meshtriangulation": {
"type": "Project",
"dependencies": {
"LibTessDotNet": "[1.1.15, )",
"Speckle.DoubleNumerics": "[4.1.0, )"
}
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -335,23 +306,16 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.revit2022": {
"type": "Project",
"dependencies": {
"Speckle.Common.MeshTriangulation": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Revit.API": "[2022.0.2.1, )"
}
},
"LibTessDotNet": {
"type": "CentralTransitive",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
@@ -387,11 +351,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Revit.API": {
@@ -399,6 +363,29 @@
"requested": "[2023.0.0, )",
"resolved": "2022.0.2.1",
"contentHash": "IrLN4WyI2ix+g3zCpo7sX8zNB3FrtrdQ3E2RpceGVPNG00v8OfD+Kei7o1bn1u/ML46iBYRAr/JcsLbwfUQsBw=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -95,8 +95,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -191,29 +191,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -299,20 +276,14 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
"speckle.common.meshtriangulation": {
"type": "Project",
"dependencies": {
"LibTessDotNet": "[1.1.15, )",
"Speckle.DoubleNumerics": "[4.1.0, )"
}
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -335,23 +306,16 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.revit2023": {
"type": "Project",
"dependencies": {
"Speckle.Common.MeshTriangulation": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Revit.API": "[2023.0.0, )"
}
},
"LibTessDotNet": {
"type": "CentralTransitive",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
@@ -387,11 +351,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Revit.API": {
@@ -399,6 +363,29 @@
"requested": "[2023.0.0, )",
"resolved": "2023.0.0",
"contentHash": "tq40eD7psgTbV+epNouYyqfo6+hEi7FmXZqcxEOsAV7zfYyWhL6Rt3vmojkWGNuerGbH6oRI6KIIxrnlCNb8Hw=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -95,8 +95,8 @@
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "9.0.4",
"contentHash": "9VGI5kxIvrNG2mqLQZnUR6y/3fcnygD8eNpHR+CqfbnIXvea6nehnYknDKQTxZVPMpzpNca+7DxLBmpdB3q0Bw==",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -191,29 +191,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "9.0.4"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -299,20 +276,14 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
"speckle.common.meshtriangulation": {
"type": "Project",
"dependencies": {
"LibTessDotNet": "[1.1.15, )",
"Speckle.DoubleNumerics": "[4.1.0, )"
}
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -335,23 +306,16 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.revit2024": {
"type": "Project",
"dependencies": {
"Speckle.Common.MeshTriangulation": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Revit.API": "[2024.0.0, )"
}
},
"LibTessDotNet": {
"type": "CentralTransitive",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
@@ -387,11 +351,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Revit.API": {
@@ -399,6 +363,29 @@
"requested": "[2023.0.0, )",
"resolved": "2024.0.0",
"contentHash": "a4dsvZ00ocvzTgCD6dUdydf0jIZDVcDhs6dUX9cv+y3aTDbU8rmzhYXWt8sThedIG+IPSVa0vHmAH9pKiJL3SQ=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
}
}
@@ -171,25 +171,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -240,20 +221,14 @@
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.common.meshtriangulation": {
"type": "Project",
"dependencies": {
"LibTessDotNet": "[1.1.15, )",
"Speckle.DoubleNumerics": "[4.1.0, )"
}
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -276,23 +251,16 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.revit2025": {
"type": "Project",
"dependencies": {
"Speckle.Common.MeshTriangulation": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Revit.API": "[2025.0.0, )"
}
},
"LibTessDotNet": {
"type": "CentralTransitive",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
@@ -328,11 +296,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Revit.API": {
@@ -340,6 +308,27 @@
"requested": "[2023.0.0, )",
"resolved": "2025.0.0",
"contentHash": "Hwf/3Ydc7KxvjgD9pSZKLSJRsFTsxYg95YyTm6f43hcsGjmk49GsLFQt921Z9OcvUVewOggQHcmBgti+P2EPHw=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -3,15 +3,17 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:dui="clr-namespace:Speckle.Connectors.DUI;assembly=Speckle.Connectors.DUI"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<!-- WebView2 is created lazily -->
<Border Name="BrowserContainer" Background="White">
<TextBlock Name="LoadingText"
Text="Loading Speckle..."
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Foreground="Gray" />
</Border>
<UserControl.Resources>
<wv2:CoreWebView2CreationProperties x:Key="EvergreenWebView2CreationProperties" UserDataFolder="C:\temp" />
</UserControl.Resources>
<DockPanel>
<wv2:WebView2
CreationProperties="{StaticResource EvergreenWebView2CreationProperties}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Name="Browser" Grid.Row="0" Source="{x:Static dui:Url.Netlify}" />
</DockPanel>
</UserControl>
@@ -2,8 +2,6 @@ using System.Windows.Controls;
using System.Windows.Threading;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using Speckle.Connectors.DUI;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.Revit.Plugin;
@@ -14,10 +12,6 @@ public sealed partial class RevitControlWebView : UserControl, IBrowserScriptExe
{
private readonly IServiceProvider _serviceProvider;
private readonly IRevitTask _revitTask;
#pragma warning disable CA2213
private WebView2? _browser;
#pragma warning restore CA2213
private bool _isInitializing;
public RevitControlWebView(IServiceProvider serviceProvider, IRevitTask revitTask)
{
@@ -25,73 +19,36 @@ public sealed partial class RevitControlWebView : UserControl, IBrowserScriptExe
_revitTask = revitTask;
InitializeComponent();
// Delay WebView2 creation until the panel is actually visible
// This avoids conflicts with other plugins (like pyRevit) during startup
IsVisibleChanged += OnIsVisibleChanged;
}
private void OnIsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is true && _browser == null && !_isInitializing)
{
_isInitializing = true;
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, CreateWebView2);
}
}
private void CreateWebView2()
{
_browser = new WebView2
{
CreationProperties = new CoreWebView2CreationProperties { UserDataFolder = "C:\\temp" },
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
Source = Url.Netlify
};
_browser.CoreWebView2InitializationCompleted += (sender, args) =>
Browser.CoreWebView2InitializationCompleted += (sender, args) =>
_serviceProvider
.GetRequiredService<ITopLevelExceptionHandler>()
.CatchUnhandled(() => OnInitialized(sender, args));
BrowserContainer.Child = _browser;
}
public bool IsBrowserInitialized => _browser?.IsInitialized ?? false;
public bool IsBrowserInitialized => Browser.IsInitialized;
public object BrowserElement => _browser!;
public object BrowserElement => Browser;
/// <inheritdoc/>
public void ExecuteScript(string script, CancellationToken cancellationToken)
public void ExecuteScript(string script)
{
if (_browser == null || !_browser.IsInitialized)
if (!Browser.IsInitialized)
{
throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet");
throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet.");
}
if (!_browser.CheckAccess())
{
ExecuteScriptDispatched(script, cancellationToken);
return;
}
_browser.ExecuteScriptAsync(script);
_revitTask.Run(() => Browser.ExecuteScriptAsync(script));
}
/// <inheritdoc/>
public void ExecuteScriptDispatched(string script, CancellationToken cancellationToken)
public void SendProgress(string script)
{
if (_browser == null || !_browser.IsInitialized)
if (!Browser.IsInitialized)
{
throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet");
throw new InvalidOperationException("Failed to execute script, Webview2 is not initialized yet.");
}
//Intentionally using the dispatcher even from the main thread
//As it allows the UI to pump messages, and stay responsive
_browser.Dispatcher.Invoke(
() => _browser.ExecuteScriptAsync(script),
DispatcherPriority.Background,
cancellationToken
//always invoke even on the main thread because it's better somehow
Browser.Dispatcher.Invoke(
//fire and forget
() => Browser.ExecuteScriptAsync(script),
DispatcherPriority.Background
);
}
@@ -117,18 +74,11 @@ public sealed partial class RevitControlWebView : UserControl, IBrowserScriptExe
private void SetupBinding(IBinding binding)
{
binding.Parent.AssociateWithBinding(binding);
_browser!.CoreWebView2.AddHostObjectToScript(binding.Name, binding.Parent);
Browser.CoreWebView2.AddHostObjectToScript(binding.Name, binding.Parent);
}
public void ShowDevTools() => _browser?.CoreWebView2?.OpenDevToolsWindow();
public void ShowDevTools() => Browser.CoreWebView2.OpenDevToolsWindow();
//https://github.com/MicrosoftEdge/WebView2Feedback/issues/2161
public void Dispose()
{
if (_browser != null)
{
_browser.Dispatcher.Invoke(() => _browser.Dispose(), DispatcherPriority.Send);
_browser = null;
}
}
public void Dispose() => Browser.Dispatcher.Invoke(() => Browser.Dispose(), DispatcherPriority.Send);
}
@@ -164,25 +164,6 @@
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"Speckle.Sdk": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "6gmPoWTv7DwqvUae57wCLF93upE9RIjaCZFue9UMY4I6FB8vLbMGfcyiUwnUY551WlGOual15ISS3G15/kMmnw==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.15.3"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Transitive",
"resolved": "3.15.3",
"contentHash": "VLgyGi1kQNWe0fzRO0U3qnZZUQGDeFacnpn25Yy3esE0qeo4tqa1BrvXPv2ivEZbbhBkkg6+Gd+CztDIyw3Y/w=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
@@ -233,20 +214,14 @@
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.common.meshtriangulation": {
"type": "Project",
"dependencies": {
"LibTessDotNet": "[1.1.15, )",
"Speckle.DoubleNumerics": "[4.1.0, )"
}
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
}
},
"speckle.connectors.dui": {
@@ -269,23 +244,16 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.15.3, )"
"Speckle.Objects": "[3.9.0, )"
}
},
"speckle.converters.revit2026": {
"type": "Project",
"dependencies": {
"Speckle.Common.MeshTriangulation": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Revit.API": "[2026.0.0, )"
}
},
"LibTessDotNet": {
"type": "CentralTransitive",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
@@ -312,11 +280,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.15.3, )",
"resolved": "3.15.3",
"contentHash": "zmHnLKR46in0xH5ashD+ENlYUPDktUMZhXYYOb8aWHAG3Zxai2WvmDJtdf7pV9GTafkpR6fCo2EQTeCoY+XXxQ==",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"dependencies": {
"Speckle.Sdk": "3.15.3"
"Speckle.Sdk": "3.9.0"
}
},
"Speckle.Revit.API": {
@@ -324,6 +292,27 @@
"requested": "[2023.0.0, )",
"resolved": "2026.0.0",
"contentHash": "SiqqKbF1pXyZWXZhAl2JhjYhTt7RiYO5JaQrAjq+OlleAjT4zatwAp/DnTwQspFbP7UZr3b2Ed2kuWNN0ZFelw=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.9.0"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows.Threading;
using Autodesk.Revit.UI;
@@ -13,50 +14,36 @@ public partial class CefSharpPanel : Page, Autodesk.Revit.UI.IDockablePaneProvid
InitializeComponent();
}
/// <inheritdoc/>
public void ExecuteScript(string script, CancellationToken cancellationToken)
public void ExecuteScript(string script)
{
if (!Browser.CheckAccess())
try
{
ExecuteScriptDispatched(script, cancellationToken);
return;
}
//avoid exceptions by checking if IBrowser is there
if (!Browser.IsBrowserInitialized || Browser.GetBrowser() is null)
{
return;
}
Browser.ExecuteScriptAsync(script);
}
/// <inheritdoc/>
public void ExecuteScriptDispatched(string script, CancellationToken cancellationToken)
{
if (Browser == null || !Browser.IsInitialized)
{
throw new InvalidOperationException("Failed to execute script, ChromiumWebBrowser is not initialized yet");
}
//Intentionally using the dispatcher even from the main thread
//As it allows the UI to pump messages, and stay responsive
Browser.Dispatcher.Invoke(
() =>
{
//avoid exceptions by checking if IBrowser is there
if (!Browser.IsBrowserInitialized || Browser.GetBrowser() is null)
Browser.Dispatcher.Invoke(
() =>
{
return;
}
//avoid exceptions by checking if IBrowser is there
if (!Browser.IsBrowserInitialized || Browser.GetBrowser() is null)
{
return;
}
Browser.ExecuteScriptAsync(script);
},
DispatcherPriority.Background,
cancellationToken
);
Browser.ExecuteScriptAsync(script);
},
DispatcherPriority.Background
);
}
catch (SEHException)
{
//do nothing as we can't control external components
}
catch (OperationCanceledException)
{
//do nothing, happens when closing Revit while a script is being executed
}
}
public void SendProgress(string script) => ExecuteScript(script);
public bool IsBrowserInitialized => Browser.IsBrowserInitialized;
public object BrowserElement => Browser;
@@ -2,8 +2,6 @@ using Autodesk.Revit.DB;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Utils;
using Speckle.Connectors.Revit.HostApp;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Connectors.RevitShared;
using Speckle.Connectors.RevitShared.Operations.Send.Filters;
@@ -26,8 +24,6 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
private readonly ISpeckleApplication _speckleApplication;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly IRevitTask _revitTask;
private readonly ParameterUpdater _parameterUpdater;
private readonly IJsonSerializer _jsonSerializer;
public BasicConnectorBindingRevit(
DocumentModelStore store,
@@ -35,9 +31,7 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
RevitContext revitContext,
ISpeckleApplication speckleApplication,
ITopLevelExceptionHandler topLevelExceptionHandler,
IRevitTask revitTask,
ParameterUpdater parameterUpdater,
IJsonSerializer jsonSerializer
IRevitTask revitTask
)
{
Name = "baseBinding";
@@ -47,8 +41,6 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
_speckleApplication = speckleApplication;
_topLevelExceptionHandler = topLevelExceptionHandler;
_revitTask = revitTask;
_parameterUpdater = parameterUpdater;
_jsonSerializer = jsonSerializer;
Commands = new BasicConnectorBindingCommands(parent);
_store.DocumentChanged += (_, _) =>
@@ -81,12 +73,7 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
}
//should this use the Hashcode of the document instead of something like CreationGUID?
var info = new DocumentInfo(
doc.PathName,
doc.Title,
doc.GetHashCode().ToString(),
doc.IsModelInCloud ? doc.GetCloudModelUrn() : null
);
var info = new DocumentInfo(doc.PathName, doc.Title, doc.GetHashCode().ToString());
return info;
}
@@ -1,251 +0,0 @@
using Autodesk.Revit.DB;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Utils;
using Speckle.Connectors.Revit.HostApp;
using Speckle.Connectors.Revit.Operations.Receive;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Connectors.RevitShared;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Sdk;
namespace Speckle.Connectors.Revit.Bindings;
public static class ParameterScopes
{
public const string INSTANCE = "Instance Parameters";
public const string TYPE = "Type Parameters";
public const string SYSTEM_TYPE = "System Type Parameters";
}
public record ParsedParameterPath(string Scope, string Category, string Name)
{
public string[] ToArray() => [Scope, Category, Name];
}
internal sealed class RevitParametersBinding : IParametersBinding
{
public string Name => "parametersBinding";
public IBrowserBridge Parent { get; }
private readonly RevitContext _revitContext;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly IRevitTask _revitTask;
private readonly ParameterUpdater _parameterUpdater;
private readonly IJsonSerializer _jsonSerializer;
private readonly IBasicConnectorBinding _baseBinding;
private readonly ILogger<RevitParametersBinding> _logger;
public RevitParametersBinding(
IBrowserBridge parent,
RevitContext revitContext,
ITopLevelExceptionHandler topLevelExceptionHandler,
IRevitTask revitTask,
ParameterUpdater parameterUpdater,
IJsonSerializer jsonSerializer,
IBasicConnectorBinding baseBinding,
ILogger<RevitParametersBinding> logger
)
{
Parent = parent;
_revitContext = revitContext;
_topLevelExceptionHandler = topLevelExceptionHandler;
_revitTask = revitTask;
_parameterUpdater = parameterUpdater;
_jsonSerializer = jsonSerializer;
_baseBinding = baseBinding;
_logger = logger;
}
public async Task Update(string payload)
{
try
{
var wrapper = _jsonSerializer.Deserialize<ParameterChangesWrapper>(payload);
var requests = wrapper?.Changes;
if (requests == null || requests.Count == 0)
{
return;
}
var activeUIDoc =
_revitContext.UIApplication?.ActiveUIDocument
?? throw new SpeckleException("Unable to retrieve active UI document");
var doc = activeUIDoc.Document;
int successCount = 0;
List<string> errors = [];
await _revitTask
.RunAsync(() =>
{
using var t = new Transaction(doc, "Speckle: Apply Parameter Changes");
// silence pop-ups like "duplicate mark values" etc. which blocks our param updates
var failureOptions = t.GetFailureHandlingOptions();
failureOptions.SetFailuresPreprocessor(new HideWarningsFailuresPreprocessor());
t.SetFailureHandlingOptions(failureOptions);
t.Start();
foreach (var request in requests)
{
if (!TryValidateAndParseRequest(doc, request, out var element, out var parsedPath, out var errorMessage))
{
errors.Add(errorMessage!);
continue;
}
object? rawValue = request.To;
if (rawValue is Newtonsoft.Json.Linq.JValue jValue)
{
rawValue = jValue.Value;
}
var result = _parameterUpdater.Update(
element!,
parsedPath!.ToArray(),
rawValue,
request.InternalDefinitionName
);
if (result.IsSuccess)
{
successCount++;
}
else
{
errors.Add(result.ErrorMessage ?? "Unknown error");
}
}
t.Commit();
})
.ConfigureAwait(false);
if (errors.Count > 0)
{
var groupedErrors = errors.GroupBy(e => e).Select(g => $"{g.Count()} x {g.Key}");
var errorString = string.Join(", ", groupedErrors);
if (successCount > 0)
{
// Partial Success (Some worked, some failed)
await _baseBinding.Commands.SetGlobalNotification(
ToastNotificationType.WARNING,
"Parameters updated with errors",
$"Applied {successCount} updates. Encountered {errors.Count} errors: {errorString}",
autoClose: false
);
}
else
{
// Total Failure (None worked)
await _baseBinding.Commands.SetGlobalNotification(
ToastNotificationType.DANGER,
"No parameters updated",
$"All {errors.Count} updates failed: {errorString}",
autoClose: false
);
}
}
else if (successCount > 0)
{
// Total Success
await _baseBinding.Commands.SetGlobalNotification(
ToastNotificationType.SUCCESS,
"All parameters updated",
$"Successfully applied {successCount} updates."
);
}
}
catch (Exception ex)
{
_topLevelExceptionHandler.CatchUnhandled(
() => throw new SpeckleException("Failed to apply parameter updates", ex)
);
}
}
private bool TryValidateAndParseRequest(
Document doc,
ParameterChangeRequest request,
out Element? element,
out ParsedParameterPath? parsedPath,
out string? errorMessage
)
{
element = null;
parsedPath = null;
errorMessage = null;
if (string.IsNullOrEmpty(request.ApplicationId))
{
errorMessage = "Missing ApplicationId";
return false;
}
if (ContainsLinkedModelTransformHash(request.ApplicationId))
{
errorMessage = "Cannot modify elements from a linked model";
return false;
}
var elementId = ElementIdHelper.GetElementIdFromUniqueId(doc, request.ApplicationId);
if (elementId == null)
{
errorMessage = "Element(s) not found in document";
return false;
}
element = doc.GetElement(elementId);
if (element == null)
{
errorMessage = "Element(s) not found in document";
return false;
}
var rawPath = request.Path;
if (string.IsNullOrEmpty(rawPath))
{
_logger.LogError("Widget / DUI payload error: parameter path missing");
errorMessage = "Parameter path is missing";
return false;
}
if (rawPath.StartsWith("properties.", StringComparison.InvariantCultureIgnoreCase))
{
rawPath = rawPath[11..];
}
if (rawPath.StartsWith("parameters.", StringComparison.InvariantCultureIgnoreCase))
{
rawPath = rawPath[11..];
}
var pathParts = rawPath.Split(['.'], 3);
if (pathParts.Length != 3)
{
_logger.LogError(
"Path format error: Expected exactly 3 parts (Scope.Category.Name) but received '{RawPath}' for element",
rawPath
);
errorMessage = "Parameter path is incorrectly formatted";
return false;
}
parsedPath = new ParsedParameterPath(pathParts[0], pathParts[1], pathParts[2]);
return true;
}
private static bool ContainsLinkedModelTransformHash(string applicationId) =>
// Evaluates if the ID contains the standard transform hash for linked elements
System.Text.RegularExpressions.Regex.IsMatch(applicationId, @"_t[a-f0-9]+$");
}
public class ParameterChangesWrapper
{
public List<ParameterChangeRequest>? Changes { get; set; }
}
@@ -4,7 +4,6 @@ using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Settings;
using Speckle.Connectors.Revit.Operations.Receive;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Converters.Common;
using Speckle.Converters.RevitShared.Settings;
@@ -25,8 +24,7 @@ public sealed class RevitReceiveBinding(
private IReceiveBindingUICommands Commands { get; } = new ReceiveBindingUICommands(parent);
#pragma warning disable CA1024
public List<ICardSetting> GetReceiveSettings() =>
[new Operations.Receive.Settings.ReceiveReferencePointSetting(), new ReceiveInstancesAsFamiliesSetting()];
public List<ICardSetting> GetReceiveSettings() => [new Operations.Receive.Settings.ReceiveReferencePointSetting()];
#pragma warning restore CA1024
public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId);
@@ -46,9 +44,7 @@ public sealed class RevitReceiveBinding(
toHostSettingsManager.GetReferencePointSetting(card),
false,
true,
false,
false,
toHostSettingsManager.GetReceiveInstancesAsFamiliesSetting(card)
false
)
);
},
@@ -1,4 +1,3 @@
using System.IO;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Microsoft.Extensions.DependencyInjection;
@@ -25,7 +24,7 @@ namespace Speckle.Connectors.Revit.Bindings;
internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
{
private readonly RevitIdleManager _revitIdleManager;
private readonly IAppIdleManager _idleManager;
private readonly RevitContext _revitContext;
private readonly DocumentModelStore _store;
private readonly ICancellationManager _cancellationManager;
@@ -39,10 +38,6 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
private readonly LinkedModelHandler _linkedModelHandler;
private readonly IThreadContext _threadContext;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
private readonly ParameterUpdater _parameterUpdater;
private bool _isDocChangedSubscribed;
private EventHandler<Autodesk.Revit.DB.Events.DocumentChangedEventArgs>? _documentChangedHandler;
private readonly ConnectorConfig _config;
/// <summary>
/// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See:
@@ -53,7 +48,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
private ConcurrentHashSet<ElementId> ChangedObjectIds { get; set; } = new();
public RevitSendBinding(
RevitIdleManager revitIdleManager,
IAppIdleManager idleManager,
RevitContext revitContext,
DocumentModelStore store,
ICancellationManager cancellationManager,
@@ -67,13 +62,11 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
LinkedModelHandler linkedModelHandler,
IThreadContext threadContext,
IRevitTask revitTask,
ISendOperationManagerFactory sendOperationManagerFactory,
ParameterUpdater parameterUpdater,
IConfigStore configStore
ISendOperationManagerFactory sendOperationManagerFactory
)
: base("sendBinding", bridge)
{
_revitIdleManager = revitIdleManager;
_idleManager = idleManager;
_revitContext = revitContext;
_store = store;
_cancellationManager = cancellationManager;
@@ -86,8 +79,6 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
_linkedModelHandler = linkedModelHandler;
_threadContext = threadContext;
_sendOperationManagerFactory = sendOperationManagerFactory;
_parameterUpdater = parameterUpdater;
_config = configStore.GetConnectorConfig();
Commands = new SendBindingUICommands(bridge);
// TODO expiry events
@@ -95,61 +86,15 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
revitTask.Run(() =>
{
// revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) =>
// _topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e));
_documentChangedHandler = (_, e) => _topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e));
_store.ModelCardsChanged += (_, e) => OnModelCardsChanged(e);
revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) =>
_topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e));
_store.DocumentChanged += (_, _) => topLevelExceptionHandler.FireAndForget(async () => await OnDocumentChanged());
});
}
private void OnModelCardsChanged(ModelCardsChangedEventArgs e)
{
if (
!_config.DocumentChangeListeningDisabled
&& e.ModelCards.Count > 0
&& e.ModelCards.Any(m => m.TypeDiscriminator == nameof(SenderModelCard))
)
{
SubscribeDocChanged();
}
else
{
UnsubscribeDocChanged();
}
}
private void SubscribeDocChanged()
{
if (_documentChangedHandler == null || _isDocChangedSubscribed)
{
return;
}
_threadContext.RunOnMain(() =>
{
_revitContext.UIApplication.NotNull().Application.DocumentChanged += _documentChangedHandler;
});
_isDocChangedSubscribed = true;
}
private void UnsubscribeDocChanged()
{
if (_documentChangedHandler == null || !_isDocChangedSubscribed)
{
return;
}
_threadContext.RunOnMain(() =>
{
_revitContext.UIApplication.NotNull().Application.DocumentChanged -= _documentChangedHandler;
});
_isDocChangedSubscribed = false;
}
public List<ISendFilter> GetSendFilters() =>
[
new RevitSelectionFilter { IsDefault = true },
new RevitSelectionFilter() { IsDefault = true },
new RevitViewsFilter(_revitContext),
new RevitCategoriesFilter(_revitContext)
];
@@ -160,8 +105,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
new SendReferencePointSetting(),
new SendParameterNullOrEmptyStringsSetting(),
new LinkedModelsSetting(),
new SendRebarsAsVolumetricSetting(),
new SendAreasAsMeshSetting()
new SendRebarsAsVolumetricSetting()
];
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
@@ -176,7 +120,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
throw new SpeckleException("No document is active for sending.");
}
using var manager = _sendOperationManagerFactory.Create();
var (fileName, fileBytes) = GetFileInfo(document);
await manager.Process<DocumentToConvert>(
Commands,
modelCardId,
@@ -189,70 +133,14 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
_toSpeckleSettingsManager.GetReferencePointSetting(document, card),
_toSpeckleSettingsManager.GetSendParameterNullOrEmptyStringsSetting(document, card),
_toSpeckleSettingsManager.GetLinkedModelsSetting(document, card),
_toSpeckleSettingsManager.GetSendRebarsAsVolumetric(document, card),
_toSpeckleSettingsManager.GetSendAreasAsMesh(document, card),
_toSpeckleSettingsManager.GetSendRebarsAsVolumetric(document, card)
)
);
},
async x => await RefreshElementsIdsOnSender(document, x.NotNull()),
fileName: fileName,
fileSizeBytes: fileBytes
async x => await RefreshElementsIdsOnSender(document, x.NotNull())
);
}
public async Task UpdateParameters(List<ParameterChangeRequest> changes)
{
var document = _revitContext.UIApplication?.ActiveUIDocument?.Document;
if (document == null)
{
throw new SpeckleException("No document is active.");
}
await _threadContext.RunOnMainAsync(() =>
{
using var transaction = new Transaction(document, "Speckle Parameter Updates");
transaction.Start();
foreach (var change in changes)
{
var element = document.GetElement(change.ApplicationId);
if (element == null)
{
continue;
}
var path = ParsePath(change.Path);
var result = _parameterUpdater.Update(element, path, change.To);
}
transaction.Commit();
return Task.FromResult(true);
});
}
private string[] ParsePath(string concatenatedPath)
{
// "properties.Parameters.Type Parameters.Other.Family Name"
// → ["Type Parameters", "Other", "Family Name"]
var segments = concatenatedPath.Split('.');
return segments.Skip(2).ToArray();
}
private static (string? fileName, long? fileBytes) GetFileInfo(Document document)
{
string fullPath = document.PathName;
if (File.Exists(document.PathName))
{
var fileInfo = new FileInfo(document.PathName);
return (fileInfo.Name, fileInfo.Length);
}
else
{
return (fullPath.Split('/').LastOrDefault(), null);
}
}
private async Task<List<DocumentToConvert>> RefreshElementsIdsOnSender(Document document, SenderModelCard modelCard)
{
if (modelCard.SendFilter.NotNull() is IRevitSendFilter viewFilter)
@@ -388,7 +276,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
if (addedElementIds.Count > 0)
{
_revitIdleManager.SubscribeToIdle(nameof(PostSetObjectIds), PostSetObjectIds);
_idleManager.SubscribeToIdle(nameof(PostSetObjectIds), PostSetObjectIds);
}
if (HaveUnitsChanged(doc))
@@ -408,8 +296,8 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
_sendConversionCache.EvictObjects(unpackedObjectIds);
}
_revitIdleManager.SubscribeToIdle(nameof(CheckFilterExpiration), CheckFilterExpiration);
_revitIdleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks);
_idleManager.SubscribeToIdle(nameof(CheckFilterExpiration), CheckFilterExpiration);
_idleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks);
}
// Keeps track of doc and current units
@@ -1,6 +1,5 @@
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Settings;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Sdk.Common;
@@ -18,32 +17,27 @@ internal sealed class SelectionBinding : RevitBaseBinding, ISelectionBinding, ID
public SelectionBinding(
RevitContext revitContext,
IBrowserBridge parent,
RevitIdleManager idleManager,
#if REVIT2022
IAppIdleManager idleManager,
ITopLevelExceptionHandler topLevelExceptionHandler,
#endif
IRevitTask revitTask,
IConfigStore configStore
IRevitTask revitTask
)
: base("selectionBinding", parent)
{
_revitContext = revitContext;
if (!configStore.GetConnectorConfig().SelectionChangeListeningDisabled)
{
#if REVIT2022
// NOTE: getting the selection data should be a fast function all, even for '000s of elements - and having a timer hitting it every 1s is ok.
_selectionTimer = new System.Timers.Timer(1000);
_selectionTimer.Elapsed += (_, _) => topLevelExceptionHandler.CatchUnhandled(OnSelectionChanged);
_selectionTimer.Start();
// NOTE: getting the selection data should be a fast function all, even for '000s of elements - and having a timer hitting it every 1s is ok.
_selectionTimer = new System.Timers.Timer(1000);
_selectionTimer.Elapsed += (_, _) => topLevelExceptionHandler.CatchUnhandled(OnSelectionChanged);
_selectionTimer.Start();
#else
revitTask.Run(
() =>
_revitContext.UIApplication.NotNull().SelectionChanged += (_, _) =>
idleManager.SubscribeToIdle(nameof(OnSelectionChanged), OnSelectionChanged)
);
revitTask.Run(
() =>
_revitContext.UIApplication.NotNull().SelectionChanged += (_, _) =>
idleManager.SubscribeToIdle(nameof(OnSelectionChanged), OnSelectionChanged)
);
#endif
}
}
private void OnSelectionChanged()
@@ -48,47 +48,33 @@ public static class ServiceRegistration
serviceCollection.AddSingleton<IBinding, SelectionBinding>();
serviceCollection.AddSingleton<IBinding, RevitSendBinding>();
serviceCollection.AddSingleton<IBinding, RevitReceiveBinding>();
serviceCollection.AddSingleton<RevitIdleManager>();
serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IBasicConnectorBinding>());
serviceCollection.AddSingleton<IBasicConnectorBinding, BasicConnectorBindingRevit>();
serviceCollection.AddSingleton<IBinding>(sp => sp.GetRequiredService<IParametersBinding>());
serviceCollection.AddSingleton<IParametersBinding, RevitParametersBinding>();
// serviceCollection.AddSingleton<IAppIdleManager, RevitIdleManager>();
serviceCollection.AddSingleton<IAppIdleManager, RevitIdleManager>();
// send operation and dependencies
serviceCollection.AddScoped<SendOperation<DocumentToConvert>>();
serviceCollection.AddScoped<ElementUnpacker>();
serviceCollection.AddScoped<LevelUnpacker>();
serviceCollection.AddScoped<ViewUnpacker>();
serviceCollection.AddScoped<SendCollectionManager>();
serviceCollection.AddScoped<IRootObjectBuilder<DocumentToConvert>, RevitRootObjectBuilder>();
serviceCollection.AddScoped<IRootContinuousTraversalBuilder<DocumentToConvert>, RevitContinuousTraversalBuilder>();
serviceCollection.AddSingleton<ISendConversionCache, SendConversionCache>();
serviceCollection.AddSingleton<ToSpeckleSettingsManager>();
serviceCollection.AddSingleton<ToHostSettingsManager>();
serviceCollection.AddSingleton<LinkedModelHandler>();
serviceCollection.AddSingleton<ParameterUpdater>();
// receive operation and dependencies
serviceCollection.AddScoped<IHostObjectBuilder, RevitHostObjectBuilder>();
serviceCollection.AddScoped<ITransactionManager, TransactionManager>();
serviceCollection.AddScoped<RevitFamilyBaker>();
serviceCollection.AddScoped<FamilyGeometryBaker>();
serviceCollection.AddScoped<RevitGroupBaker>();
serviceCollection.AddScoped<RevitMaterialBaker>();
serviceCollection.AddScoped<RevitViewBaker>();
serviceCollection.AddScoped<RevitViewManager>();
serviceCollection.AddScoped<DirectShapeUnpackStrategy>();
serviceCollection.AddScoped<FamilyUnpackStrategy>();
serviceCollection.AddScoped<RevitPreBakeSetupService>();
serviceCollection.AddSingleton<RevitUtils>();
serviceCollection.AddSingleton<FamilyCategoryUtils>();
serviceCollection.AddSingleton<FamilyTransformUtils>();
serviceCollection.AddSingleton<IFailuresPreprocessor, HideWarningsFailuresPreprocessor>();
serviceCollection.AddSingleton(DefaultTraversal.CreateTraversalFunc());
serviceCollection.AddScoped<LocalToGlobalConverterUtils>();
// operation progress manager
@@ -1,6 +1,5 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Speckle.Converters.RevitShared.Extensions;
namespace Speckle.Connectors.Revit.HostApp;
@@ -9,19 +8,8 @@ namespace Speckle.Connectors.Revit.HostApp;
/// </summary>
public class ElementUnpacker
{
private static readonly List<BuiltInCategory> s_skippedCategories =
[
BuiltInCategory.OST_SketchLines,
BuiltInCategory.OST_MassForm,
BuiltInCategory.OST_StairsSketchBoundaryLines,
BuiltInCategory.OST_StairsSketchLandingCenterLines,
BuiltInCategory.OST_StairsSketchRiserLines,
BuiltInCategory.OST_RebarSketchLines,
BuiltInCategory.OST_StairsSketchRunLines
];
/// <summary>
/// Unpacks a random set of revit objects into atomic objects. It currently unpacks groups recursively, nested families into atomic family instances.
/// Unpacks a random set of revit objects into atomic objects. It currently unpacks groups recurisvely, nested families into atomic family instances.
/// This method will also "pack" curtain walls if necessary (ie, if mullions or panels are selected without their parent curtain wall, they are sent independently; if the parent curtain wall is selected, they will be removed out as the curtain wall will include all its children).
/// </summary>
/// <param name="selectionElements"></param>
@@ -35,15 +23,15 @@ public class ElementUnpacker
// Step 1: unpack groups
var atomicObjects = UnpackElements(selectionElements, doc);
// Step 2: Deduplicate parent-child elements in selection
// Removes child elements (mullions, panels, top rails, stacked wall members) when
// their parent element is also selected, since parents include children in their conversion.
// Children are only converted independently when their parent is NOT in the selection.
return RemoveKnownChildElementsWhenParentPresent(atomicObjects, doc);
// Step 2: pack curtain wall elements, once we know the full extent of our flattened item list.
// The behaviour we're looking for:
// If parent wall is part of selection, does not select individual elements out. Otherwise, selects individual elements (Panels, Mullions) as atomic objects.
// NOTE: this also conditionally "packs" stacked wall elements if their parent is present. See detailed note inside the function.
return PackCurtainWallElementsAndStackedWalls(atomicObjects, doc);
}
/// <summary>
/// Unpacks input element ids into their sub-elements, eg groups and nested family instances
/// Unpacks input element ids into their subelements, eg groups and nested family instances
/// </summary>
/// <param name="objectIds"></param>
/// <returns></returns>
@@ -68,21 +56,11 @@ public class ElementUnpacker
// UNPACK: Groups
if (element is Group g)
{
var memberIds = g.GetMemberIds();
if (memberIds.Count <= 0)
{
continue;
}
// using a collector more efficient
using var collector = new FilteredElementCollector(doc, memberIds);
collector.WhereElementIsNotElementType(); // exclude "Type" elements (FamilySymbols)
var filter = new ElementMulticategoryFilter(s_skippedCategories, inverted: true); // exclude "Sketch/Form" categories
collector.WherePasses(filter);
// recursively unpack the valid results
unpackedElements.AddRange(UnpackElements(collector, doc));
// When a group is from a linked model, GetMemberIds may behave differently
// We add null checks to handle cases where elements can't be properly resolved
// POC: this might screw up generating hosting rel generation here, because nested families in groups get flattened out by GetMemberIds().
var groupElements = g.GetMemberIds().Select(doc.GetElement).Where(el => el != null);
unpackedElements.AddRange(UnpackElements(groupElements, doc));
}
else if (element is BaseArray baseArray)
{
@@ -130,7 +108,7 @@ public class ElementUnpacker
// We use the nullable document (happiness level 5/10) for the sake of linked models - bc we use this function in 2 different places
// 1- RootObjectBuilder with linked model document - otherwise we cannot unpack elements from correct document.
// 2- Evicting the cache while introducing the settings
private List<Element> RemoveKnownChildElementsWhenParentPresent(List<Element> elements, Document doc)
private List<Element> PackCurtainWallElementsAndStackedWalls(List<Element> elements, Document doc)
{
//just used for contains so use ToHashSet
var ids = elements.Select(el => el.Id).ToHashSet();
@@ -153,37 +131,64 @@ public class ElementUnpacker
// If you wonder why revit is driving people to insanity, this is one of those moments.
// See [CNX-851: Stacked Wall Duplicate Geometry or Materials not applied](https://linear.app/speckle/issue/CNX-851/stacked-wall-duplicate-geometry-or-materials-not-applied)
|| (element is Wall { IsStackedWallMember: true } wall && ids.Contains(wall.StackedWallOwnerId))
// Railings: Remove TopRail when parent railing is selected
// Prevents duplication since railing converter includes TopRail as a child element
// TODO: Consider adding HandRail support (also inherits from ContinuousRail)
|| (
element is TopRail topRail
&& doc.GetElement(topRail.HostRailingId) is Railing railing
&& ids.Contains(railing.Id)
)
);
return elements;
}
/// <summary>
/// Returns element IDs and their known child element IDs for cache tracking.
/// Uses <see cref="ElementExtensions.GetKnownChildrenElements"/> to determine which children to include.
/// Given a set of atomic elements, it will return a list of all their ids as well as their subelements. This currently handles <b>curtain walls</b> and <b>stacked walls</b>.
/// This might not be an exhaustive list of valid objects with "subelements" in revit, and will need revisiting.
/// </summary>
/// <param name="elements">Elements to process</param>
/// <returns>Flattened list of parent and child element IDs</returns>
/// <param name="elements"></param>
/// <returns></returns>
public List<string> GetElementsAndSubelementIdsFromAtomicObjects(List<Element> elements)
{
var ids = new HashSet<string>();
foreach (var element in elements)
{
// add the element's own ID
ids.Add(element.Id.ToString());
// add all known children IDs using the extension method. trying to consolidate duplication here with converter
foreach (var childId in element.GetKnownChildrenElements())
switch (element)
{
ids.Add(childId.ToString());
case Wall wall:
if (wall.CurtainGrid is { } grid)
{
foreach (var mullionId in grid.GetMullionIds())
{
ids.Add(mullionId.ToString());
}
foreach (var panelId in grid.GetPanelIds())
{
ids.Add(panelId.ToString());
}
}
else if (wall.IsStackedWall)
{
foreach (var stackedWallId in wall.GetStackedWallMemberIds())
{
ids.Add(stackedWallId.ToString());
}
}
break;
case FootPrintRoof footPrintRoof:
if (footPrintRoof.CurtainGrids is { } gs)
{
foreach (CurtainGrid roofGrid in gs)
{
foreach (var mullionId in roofGrid.GetMullionIds())
{
ids.Add(mullionId.ToString());
}
foreach (var panelId in roofGrid.GetPanelIds())
{
ids.Add(panelId.ToString());
}
}
}
break;
default:
break;
}
ids.Add(element.Id.ToString());
}
return ids.ToList();
@@ -1,77 +0,0 @@
using Autodesk.Revit.DB;
using Microsoft.Extensions.Logging;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Objects.Data;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.GraphTraversal;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Revit.HostApp;
public class FamilyCategoryUtils
{
private readonly CategoryExtractor _categoryExtractor;
private readonly ILogger<FamilyCategoryUtils> _logger;
public FamilyCategoryUtils(CategoryExtractor categoryExtractor, ILogger<FamilyCategoryUtils> logger)
{
_categoryExtractor = categoryExtractor;
_logger = logger;
}
public string? ExtractCategoryForDefinition(
InstanceDefinitionProxy definition,
ICollection<(Collection[] collectionPath, IInstanceComponent component)> instanceComponents,
IReadOnlyDictionary<string, TraversalContext> speckleObjectLookup
)
{
var definitionId = definition.applicationId ?? definition.id;
var firstInstance = instanceComponents
.Select(x => x.component)
.OfType<InstanceProxy>()
.FirstOrDefault(i => i.definitionId == definitionId);
if (firstInstance == null)
{
return null;
}
var instanceObjectId = firstInstance.applicationId ?? firstInstance.id;
if (instanceObjectId != null && speckleObjectLookup.TryGetValue(instanceObjectId, out var tc))
{
var parentDataObject = tc.Parent?.Current as DataObject;
return _categoryExtractor.ExtractBuiltInCategory(parentDataObject, tc.Current);
}
return null;
}
public void SetFamilyCategory(Document familyDoc, string? builtInCategoryString)
{
if (!familyDoc.IsFamilyDocument || string.IsNullOrEmpty(builtInCategoryString))
{
return;
}
if (Enum.TryParse(builtInCategoryString, out BuiltInCategory bic))
{
try
{
Category targetCategory = familyDoc.Settings.Categories.get_Item(bic);
if (targetCategory != null)
{
familyDoc.OwnerFamily.FamilyCategory = targetCategory;
}
}
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
_logger.LogInformation("Category {Category} cannot be assigned to a Family. Falling back to default.", bic);
}
catch (Autodesk.Revit.Exceptions.InvalidOperationException ex)
{
_logger.LogWarning(ex, "Invalid operation when setting category {Category}. Falling back to default.", bic);
}
}
}
}
@@ -1,336 +0,0 @@
using Autodesk.Revit.DB;
using Microsoft.Extensions.Logging;
using Speckle.Converters.Common.Objects;
using Speckle.Objects.Other;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.Extensions;
using Speckle.Sdk.Models.GraphTraversal;
using Speckle.Sdk.Models.Instances;
using SMesh = Speckle.Objects.Geometry.Mesh;
namespace Speckle.Connectors.Revit.HostApp;
/// <summary>
/// Handles the low-level conversion and baking of Speckle geometries into a Revit Family Document.
/// Extracted from RevitFamilyBaker to separate geometry generation from high-level orchestration, reducing class coupling.
/// </summary>
public class FamilyGeometryBaker
{
private readonly ILogger<FamilyGeometryBaker> _logger;
private readonly ITypedConverter<Base, List<GeometryObject>> _geometryConverter;
private readonly ITypedConverter<SMesh, GeometryObject> _freeformMeshConverter;
public FamilyGeometryBaker(
ILogger<FamilyGeometryBaker> logger,
ITypedConverter<Base, List<GeometryObject>> geometryConverter,
ITypedConverter<SMesh, GeometryObject> freeformMeshConverter
)
{
_logger = logger;
_geometryConverter = geometryConverter;
_freeformMeshConverter = freeformMeshConverter;
}
public void BakeFamilyGeometry(
Document famDoc,
InstanceDefinitionProxy definition,
IReadOnlyDictionary<string, TraversalContext> objectLookup,
IReadOnlyDictionary<string, RenderMaterial> materialMap,
FamilyMaterialManager materialManager,
Action<Document, InstanceProxy, FamilyMaterialManager?> placeNestedInstanceAction
)
{
if (definition.objects.Count == 0)
{
return;
}
foreach (var id in definition.objects)
{
if (!objectLookup.TryGetValue(id, out var tc))
{
continue;
}
string? extractedSubcategoryName = null;
var parentTc = tc.Parent;
while (parentTc != null)
{
if (parentTc.Current is Collection col && !string.IsNullOrWhiteSpace(col.name))
{
extractedSubcategoryName = col.name;
break;
}
parentTc = parentTc.Parent;
}
ProcessObjectForFamily(
famDoc,
tc.Current,
null,
definition.name,
extractedSubcategoryName,
materialManager,
materialMap,
placeNestedInstanceAction
);
}
}
private void ProcessObjectForFamily(
Document famDoc,
Base obj,
Category? currentSubcategory,
string familyName,
string? extractedSubcategoryName,
FamilyMaterialManager? materialManager,
IReadOnlyDictionary<string, RenderMaterial>? materialMap,
Action<Document, InstanceProxy, FamilyMaterialManager?> placeNestedInstanceAction
)
{
try
{
Category? newSubcategory = currentSubcategory;
string? subcategoryName = extractedSubcategoryName ?? (obj as Collection)?.name;
if (!string.IsNullOrWhiteSpace(subcategoryName))
{
var familyCategory = famDoc.OwnerFamily.FamilyCategory;
if (familyCategory != null)
{
if (familyCategory.SubCategories.Contains(subcategoryName))
{
newSubcategory = familyCategory.SubCategories.get_Item(subcategoryName);
}
else
{
try
{
newSubcategory = famDoc.Settings.Categories.NewSubcategory(familyCategory, subcategoryName);
}
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
_logger.LogWarning("Failed to create Revit subcategory with name: {SubcategoryName}", subcategoryName);
newSubcategory = currentSubcategory;
}
}
}
}
if (obj is Collection col)
{
foreach (var element in col.elements)
{
ProcessObjectForFamily(
famDoc,
element,
newSubcategory,
familyName,
null,
materialManager,
materialMap,
placeNestedInstanceAction
);
}
}
else if (obj is InstanceProxy instanceProxy)
{
placeNestedInstanceAction(famDoc, instanceProxy, materialManager);
}
else
{
BakeGeometry(famDoc, obj, newSubcategory, materialManager, materialMap, placeNestedInstanceAction);
}
}
catch (Autodesk.Revit.Exceptions.ApplicationException ex)
{
_logger.LogWarning(ex, "Revit API error baking object {ObjectId} into family {Family}", obj.id, familyName);
}
catch (SpeckleException ex)
{
_logger.LogWarning(ex, "Speckle error baking object {ObjectId} into family {Family}", obj.id, familyName);
}
}
private void BakeGeometry(
Document famDoc,
Base obj,
Category? subcategory,
FamilyMaterialManager? materialManager,
IReadOnlyDictionary<string, RenderMaterial>? materialMap,
Action<Document, InstanceProxy, FamilyMaterialManager?> placeNestedInstanceAction
)
{
string objectId = obj.applicationId ?? obj.id.NotNull();
string? speckleMatId = null;
if (materialMap != null && materialMap.TryGetValue(objectId, out var mat))
{
speckleMatId = mat.id;
}
if (obj is SMesh mesh)
{
BakeMesh(famDoc, mesh, subcategory, speckleMatId, materialManager);
return;
}
try
{
var geometries = _geometryConverter.Convert(obj);
if (geometries.Count > 0)
{
var solids = new List<Solid>(geometries.Count);
var nonSolids = new List<GeometryObject>(geometries.Count);
foreach (var geom in geometries)
{
if (geom is Solid s && !s.Faces.IsEmpty)
{
solids.Add(s);
}
else
{
nonSolids.Add(geom);
}
}
foreach (var solid in solids)
{
using var freeFormElement = FreeFormElement.Create(famDoc, solid);
if (subcategory != null)
{
freeFormElement.Subcategory = subcategory;
}
if (
materialManager != null
&& speckleMatId != null
&& materialManager.FamilyParameters.TryGetValue(speckleMatId, out var famParam)
)
{
Parameter ffeMatParam = freeFormElement.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM);
if (ffeMatParam != null && famDoc.FamilyManager.CanElementParameterBeAssociated(ffeMatParam))
{
famDoc.FamilyManager.AssociateElementParameterToFamilyParameter(ffeMatParam, famParam);
}
}
}
if (nonSolids.Count > 0)
{
// try to use the Family's actual Category, otherwise default to Generic Model
ElementId categoryId =
famDoc.OwnerFamily.FamilyCategory?.Id ?? new ElementId(BuiltInCategory.OST_GenericModel);
if (!DirectShape.IsValidCategoryId(categoryId, famDoc))
{
categoryId = new ElementId(BuiltInCategory.OST_GenericModel);
}
try
{
using var ds = DirectShape.CreateElement(famDoc, categoryId);
ds.SetShape(nonSolids);
}
catch (Autodesk.Revit.Exceptions.ArgumentException ex)
{
_logger.LogWarning(
ex,
"DirectShape rejected Category ID {CategoryId}, falling back to Generic Model",
categoryId
);
using var fallbackDs = DirectShape.CreateElement(famDoc, new ElementId(BuiltInCategory.OST_GenericModel));
fallbackDs.SetShape(nonSolids);
}
}
return;
}
}
catch (SpeckleException) { }
var displayValues = obj.TryGetDisplayValue();
if (displayValues != null)
{
foreach (var item in displayValues)
{
BakeGeometry(famDoc, item, subcategory, materialManager, materialMap, placeNestedInstanceAction);
}
}
}
private void BakeMesh(
Document famDoc,
SMesh mesh,
Category? subcategory,
string? speckleMatId,
FamilyMaterialManager? materialManager
)
{
GeometryObject geomObject;
try
{
geomObject = _freeformMeshConverter.Convert(mesh);
}
catch (SpeckleException ex)
{
_logger.LogWarning(ex, "Failed to convert Speckle Mesh into Revit freeform geometry.");
return;
}
if (geomObject is Solid solid)
{
using var freeFormElement = FreeFormElement.Create(famDoc, solid);
if (subcategory != null)
{
freeFormElement.Subcategory = subcategory;
}
if (
materialManager != null
&& speckleMatId != null
&& materialManager.FamilyParameters.TryGetValue(speckleMatId, out var famParam)
)
{
Parameter ffeMatParam = freeFormElement.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM);
if (ffeMatParam != null && famDoc.FamilyManager.CanElementParameterBeAssociated(ffeMatParam))
{
famDoc.FamilyManager.AssociateElementParameterToFamilyParameter(ffeMatParam, famParam);
}
}
}
else if (geomObject is Mesh revitMesh)
{
// try to use the Family's actual Category, otherwise default to Generic Model
ElementId categoryId = famDoc.OwnerFamily.FamilyCategory?.Id ?? new ElementId(BuiltInCategory.OST_GenericModel);
if (!DirectShape.IsValidCategoryId(categoryId, famDoc))
{
categoryId = new ElementId(BuiltInCategory.OST_GenericModel);
}
try
{
using var ds = DirectShape.CreateElement(famDoc, categoryId);
ds.SetShape([revitMesh]);
}
catch (Autodesk.Revit.Exceptions.ArgumentException ex)
{
_logger.LogWarning(
ex,
"DirectShape rejected Category ID {CategoryId}, falling back to Generic Model",
categoryId
);
using var fallbackDs = DirectShape.CreateElement(famDoc, new ElementId(BuiltInCategory.OST_GenericModel));
fallbackDs.SetShape([revitMesh]);
}
}
}
}
@@ -1,199 +0,0 @@
using Autodesk.Revit.DB;
using Microsoft.Extensions.Logging;
using Speckle.Objects.Other;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models.GraphTraversal;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Revit.HostApp;
/// <summary>
/// Manages the resolution and assignment of materials, subcategories, and parameters
/// strictly within the context of a temporary Family Document.
/// </summary>
public class FamilyMaterialManager
{
private readonly RevitMaterialBaker _materialBaker;
private readonly ILogger _logger;
private static readonly char[] s_invalidRevitChars =
[
'\\',
':',
'{',
'}',
'[',
']',
'|',
';',
'<',
'>',
'?',
'`',
'~'
];
public Dictionary<string, FamilyParameter> FamilyParameters { get; } = [];
public Dictionary<string, ElementId> SubCategories { get; } = [];
private Dictionary<string, ElementId> BakedMaterials { get; } = [];
public FamilyMaterialManager(RevitMaterialBaker materialBaker, ILogger logger)
{
_materialBaker = materialBaker;
_logger = logger;
}
/// <summary>
/// Sanitizes string to ensure it is valid for Revit Parameters and SubCategories.
/// </summary>
public static string GetSafeName(string rawName)
{
if (string.IsNullOrWhiteSpace(rawName))
{
return "Unnamed";
}
char[] buffer = rawName.ToCharArray();
bool changed = false;
for (int i = 0; i < buffer.Length; i++)
{
if (Array.IndexOf(s_invalidRevitChars, buffer[i]) >= 0)
{
buffer[i] = '_';
changed = true;
}
}
return changed ? new string(buffer) : rawName;
}
public void SetupFamilyMaterials(
Document famDoc,
InstanceDefinitionProxy definition,
IReadOnlyDictionary<string, TraversalContext> objectLookup,
IReadOnlyDictionary<string, RenderMaterial> materialMap
)
{
Category baseCategory = famDoc.OwnerFamily.FamilyCategory;
foreach (var id in definition.objects)
{
if (!objectLookup.TryGetValue(id, out var tc))
{
continue;
}
var obj = tc.Current;
string objectId = obj.applicationId ?? obj.id.NotNull();
if (materialMap.TryGetValue(objectId, out var renderMat))
{
if (BakedMaterials.ContainsKey(renderMat.id.NotNullOrWhiteSpace()))
{
continue;
}
try
{
// 1. Bake the material locally
ElementId famMatId = _materialBaker.BakeMaterial(renderMat, famDoc);
BakedMaterials[renderMat.id] = famMatId;
// 2. Setup Subcategory (for DirectShapes)
string rawName = string.IsNullOrWhiteSpace(renderMat.name) ? renderMat.id : renderMat.name;
string safeName = GetSafeName(rawName);
string subCatName = $"Mat_{safeName}";
subCatName = subCatName.Length > 50 ? subCatName[..50] : subCatName;
if (baseCategory != null)
{
if (!baseCategory.SubCategories.Contains(subCatName))
{
Category subCat = famDoc.Settings.Categories.NewSubcategory(baseCategory, subCatName);
subCat.Material = famDoc.GetElement(famMatId) as Material;
SubCategories[renderMat.id] = subCat.Id;
}
else
{
SubCategories[renderMat.id] = baseCategory.SubCategories.get_Item(subCatName).Id;
}
}
// 3. Setup Family Parameter (for FreeFormElements)
string paramName = $"Material_{safeName}";
FamilyParameter? existingParam = famDoc.FamilyManager.get_Parameter(paramName);
if (existingParam == null)
{
FamilyParameter famParam = famDoc.FamilyManager.AddParameter(
paramName,
GroupTypeId.Materials,
SpecTypeId.Reference.Material,
false
);
FamilyParameters[renderMat.id] = famParam;
}
else
{
FamilyParameters[renderMat.id] = existingParam;
}
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogWarning(ex, "Failed to setup family material {MatName}", renderMat.name);
}
}
}
}
public static void AssignProjectMaterialsToFamily(
Document document,
FamilySymbol symbol,
IReadOnlyDictionary<string, ElementId> originalNameToProjectMatId
)
{
Category? baseCategory = document.Settings.Categories.get_Item(BuiltInCategory.OST_GenericModel);
// Create a local map with sanitized keys so it perfectly matches the safeNames applied in the Family
var sanitizedMatMap = new Dictionary<string, ElementId>();
foreach (var kvp in originalNameToProjectMatId)
{
sanitizedMatMap[GetSafeName(kvp.Key)] = kvp.Value;
}
foreach (Parameter p in symbol.Parameters)
{
if (p.Definition.Name.StartsWith("Material_") && p.StorageType == StorageType.ElementId)
{
string safeName = p.Definition.Name["Material_".Length..];
if (sanitizedMatMap.TryGetValue(safeName, out var projMatId) && !p.IsReadOnly)
{
p.Set(projMatId);
}
}
}
if (baseCategory != null)
{
foreach (var kvp in sanitizedMatMap)
{
string safeName = kvp.Key;
ElementId projMatId = kvp.Value;
string subCatName = $"Mat_{safeName}";
subCatName = subCatName.Length > 50 ? subCatName[..50] : subCatName;
if (baseCategory.SubCategories.Contains(subCatName))
{
Category projSubCat = baseCategory.SubCategories.get_Item(subCatName);
if (projSubCat != null && document.GetElement(projMatId) is Material projMat)
{
projSubCat.Material = projMat;
}
}
}
}
}
}
@@ -1,184 +0,0 @@
using Autodesk.Revit.DB;
using Microsoft.Extensions.Logging;
using Speckle.DoubleNumerics;
namespace Speckle.Connectors.Revit.HostApp;
/// <summary>
/// Pure math and transform utilities for Revit Family Instance placement.
/// </summary>
/// <remarks>
/// Architecturally, these methods live in the Connector rather than the Converters project
/// because stripping scale/skew and applying API mirroring are Host App-specific workarounds
/// for Revit's shitty Family Instance rules, not general stateless conversion logic.
/// </remarks>
public class FamilyTransformUtils
{
private readonly ILogger<FamilyTransformUtils> _logger;
public FamilyTransformUtils(ILogger<FamilyTransformUtils> logger)
{
_logger = logger;
}
/// <summary>
/// Checks if a transform matrix contains non-uniform scaling or shear/skew.
/// </summary>
/// <remarks>
/// Revit family instances natively reject matrices with scale or skew.
/// We flag these matrices so we can sanitize them before placement.
/// </remarks>
public bool HasScaleOrSkew(Matrix4x4 matrix)
{
// Extract lengths of basis vectors
var lenX = Math.Sqrt(matrix.M11 * matrix.M11 + matrix.M21 * matrix.M21 + matrix.M31 * matrix.M31);
var lenY = Math.Sqrt(matrix.M12 * matrix.M12 + matrix.M22 * matrix.M22 + matrix.M32 * matrix.M32);
var lenZ = Math.Sqrt(matrix.M13 * matrix.M13 + matrix.M23 * matrix.M23 + matrix.M33 * matrix.M33);
// Calculate dot products to check for orthogonality
var dotXy = matrix.M11 * matrix.M12 + matrix.M21 * matrix.M22 + matrix.M31 * matrix.M32;
var dotXz = matrix.M11 * matrix.M13 + matrix.M21 * matrix.M23 + matrix.M31 * matrix.M33;
var dotYz = matrix.M12 * matrix.M13 + matrix.M22 * matrix.M23 + matrix.M32 * matrix.M33;
double tol = 1e-4;
bool isOrthogonal = Math.Abs(dotXy) < tol && Math.Abs(dotXz) < tol && Math.Abs(dotYz) < tol;
bool isUnitScale = Math.Abs(lenX - 1.0) < tol && Math.Abs(lenY - 1.0) < tol && Math.Abs(lenZ - 1.0) < tol;
return !isOrthogonal || !isUnitScale;
}
/// <summary>
/// Sanitizes a transform matrix by stripping out any scale or skew, returning a rigid transform.
/// </summary>
public Matrix4x4 RemoveScaleAndSkew(Matrix4x4 matrix)
{
// 1. Extract Z column and normalize
double zX = matrix.M13,
zY = matrix.M23,
zZ = matrix.M33;
double lenZ = Math.Sqrt(zX * zX + zY * zY + zZ * zZ);
if (lenZ > 1e-6)
{
zX /= lenZ;
zY /= lenZ;
zZ /= lenZ;
}
else
{
zX = 0;
zY = 0;
zZ = 1;
}
// 2. Extract Y column
double yX = matrix.M12,
yY = matrix.M22,
yZ = matrix.M32;
// 3. Cross product Y and Z to get orthogonal X
double xX = yY * zZ - yZ * zY;
double xY = yZ * zX - yX * zZ;
double xZ = yX * zY - yY * zX;
double lenX = Math.Sqrt(xX * xX + xY * xY + xZ * xZ);
if (lenX > 1e-6)
{
xX /= lenX;
xY /= lenX;
xZ /= lenX;
}
else
{
xX = 1;
xY = 0;
xZ = 0;
}
// 4. Cross product Z and X to get orthogonal unit Y
yX = zY * xZ - zZ * xY;
yY = zZ * xX - zX * xZ;
yZ = zX * xY - zY * xX;
double lenY = Math.Sqrt(yX * yX + yY * yY + yZ * yZ);
if (lenY > 1e-6)
{
yX /= lenY;
yY /= lenY;
yZ /= lenY;
}
return new Matrix4x4(
xX,
yX,
zX,
matrix.M14,
xY,
yY,
zY,
matrix.M24,
xZ,
yZ,
zZ,
matrix.M34,
matrix.M41,
matrix.M42,
matrix.M43,
matrix.M44
);
}
/// <summary>
/// Evaluates the determinant of a matrix to check if it encodes a mirrored state.
/// </summary>
/// <remarks>
/// A negative determinant implies a left-handed coordinate system (mirroring).
/// We extract this so we can apply the mirror via Revit's native API instead.
/// </remarks>
public (bool X, bool Y, bool Z) GetMirrorState(Matrix4x4 matrix)
{
var det =
matrix.M11 * (matrix.M22 * matrix.M33 - matrix.M23 * matrix.M32)
- matrix.M12 * (matrix.M21 * matrix.M33 - matrix.M23 * matrix.M31)
+ matrix.M13 * (matrix.M21 * matrix.M32 - matrix.M22 * matrix.M31);
return det < 0 ? (true, false, false) : (false, false, false);
}
/// <summary>
/// Applies native Revit mirror operations to an element based on the evaluated mirror state.
/// </summary>
/// <remarks>
/// Because we strip the mirrored (left-handed) state from the initial transform to keep Revit happy,
/// we must restore the mirrored geometry as a post-placement operation.
/// </remarks>
public void ApplyMirroring(
Document document,
ElementId elementId,
Autodesk.Revit.DB.Plane plane,
(bool X, bool Y, bool Z) mirrorState
)
{
var mirrorOperations = new List<(string name, bool shouldMirror, Autodesk.Revit.DB.Plane mirrorPlane)>
{
("YZ", mirrorState.X, Autodesk.Revit.DB.Plane.CreateByOriginAndBasis(plane.Origin, plane.YVec, plane.Normal)),
("XZ", mirrorState.Y, Autodesk.Revit.DB.Plane.CreateByOriginAndBasis(plane.Origin, plane.XVec, plane.Normal)),
("XY", mirrorState.Z, Autodesk.Revit.DB.Plane.CreateByOriginAndBasis(plane.Origin, plane.XVec, plane.YVec))
};
foreach (var (name, _, mirrorPlane) in mirrorOperations.Where(op => op.shouldMirror))
{
try
{
document.Regenerate();
ElementTransformUtils.MirrorElements(document, [elementId], mirrorPlane, false);
}
catch (Autodesk.Revit.Exceptions.ApplicationException e)
{
_logger.LogWarning(e, "Failed to mirror element on {PlaneName} plane", name);
}
finally
{
mirrorPlane.Dispose();
}
}
}
}
@@ -1,9 +0,0 @@
namespace Speckle.Connectors.Revit.HostApp;
public class ParameterChangeRequest
{
public required string ApplicationId { get; init; }
public required string Path { get; init; }
public object? To { get; init; }
public string? InternalDefinitionName { get; set; }
}

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