Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79a6c42cc7 | |||
| e2318df87a | |||
| 78d7814351 | |||
| 17a320ee53 | |||
| 396ef981ee | |||
| 763c413871 | |||
| 57a5b41ec1 | |||
| 8385532b96 | |||
| e109515852 | |||
| fdf2425ec6 | |||
| c067cf6f91 | |||
| 60e26d85c6 |
+14
-14
@@ -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
|
||||
|
||||
@@ -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') }}
|
||||
|
||||
@@ -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-*
|
||||
|
||||
@@ -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'">
|
||||
|
||||
@@ -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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -358,12 +336,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -358,12 +336,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -306,12 +288,33 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -306,12 +288,33 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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": {
|
||||
|
||||
+3
-71
@@ -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
|
||||
|
||||
+5
-5
@@ -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]);
|
||||
}
|
||||
|
||||
-12
@@ -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))
|
||||
|
||||
+8
-60
@@ -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,8 +7,6 @@ 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;
|
||||
@@ -22,7 +19,6 @@ 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;
|
||||
@@ -34,7 +30,6 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
|
||||
|
||||
protected AutocadRootObjectBaseBuilder(
|
||||
IRootToSpeckleConverter converter,
|
||||
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
|
||||
ISendConversionCache sendConversionCache,
|
||||
AutocadInstanceUnpacker instanceObjectManager,
|
||||
AutocadMaterialUnpacker materialUnpacker,
|
||||
@@ -45,7 +40,6 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_converterSettings = converterSettings;
|
||||
_sendConversionCache = sendConversionCache;
|
||||
_instanceUnpacker = instanceObjectManager;
|
||||
_materialUnpacker = materialUnpacker;
|
||||
@@ -87,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();
|
||||
@@ -128,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));
|
||||
}
|
||||
|
||||
@@ -158,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)
|
||||
@@ -186,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))
|
||||
|
||||
-3
@@ -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,
|
||||
|
||||
-79
@@ -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>
|
||||
-79
@@ -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>
|
||||
-8
@@ -53,12 +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>
|
||||
</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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -368,12 +346,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -368,12 +346,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -368,12 +346,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -316,12 +298,33 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
@@ -316,12 +298,33 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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": {
|
||||
|
||||
-3
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.etabs21": {
|
||||
@@ -357,12 +335,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.etabs22": {
|
||||
@@ -304,12 +286,33 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2020": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2021": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2022": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2023": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2024": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2025": {
|
||||
@@ -359,12 +337,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"Speckle.Objects": "[3.9.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.navisworks2026": {
|
||||
@@ -361,12 +339,35 @@
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.15.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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": {
|
||||
|
||||
+25
-15
@@ -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
-1
@@ -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;
|
||||
|
||||
|
||||
+12
-84
@@ -1,5 +1,3 @@
|
||||
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;
|
||||
@@ -14,7 +12,6 @@ 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;
|
||||
@@ -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))
|
||||
|
||||
+5
-8
@@ -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,6 +53,9 @@ 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
|
||||
@@ -61,9 +64,6 @@ public static class NavisworksConnectorServiceRegistration
|
||||
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>());
|
||||
@@ -73,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>();
|
||||
}
|
||||
}
|
||||
|
||||
+28
-9
@@ -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);
|
||||
}
|
||||
|
||||
+18
-47
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -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;
|
||||
|
||||
+37
-19
@@ -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,
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
+7
-5
@@ -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:
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -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)
|
||||
{
|
||||
|
||||
+5
-5
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
+89
-165
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -13,10 +14,7 @@ using Speckle.Sdk;
|
||||
using Speckle.Sdk.Logging;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
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,
|
||||
|
||||
+124
-71
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"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.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"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.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg==",
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"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.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"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.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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.1",
|
||||
"contentHash": "Gt1qAZrMflLMOjDy4cQzJX5pdq5WokphYdsry7pMBlRHRdx9imQhJUPCg528Y2iVSMUnRKvj3A3cHtBeUxysEQ==",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"Speckle.Sdk.Dependencies": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "OUOnt4Vnd1J838LTWEpP0ge8WIwjhx8O94kuTbC6AJRfOx9Lw78SG6XtVCE+WXb9zC5h3tzOV9YOng8Ke5yXMg=="
|
||||
},
|
||||
"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.1, )"
|
||||
"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.1, )"
|
||||
"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.1, )",
|
||||
"resolved": "3.15.1",
|
||||
"contentHash": "vFIf01jNVD69N6wE5iYVM7TKA6AbSTZxq1EedJCVZxhj5pkhHBw+23fyO+wz7Cd9ggqsiBUJMuKxUBHaDphGWQ==",
|
||||
"requested": "[3.9.0, )",
|
||||
"resolved": "3.9.0",
|
||||
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
|
||||
"dependencies": {
|
||||
"Speckle.Sdk": "3.15.1"
|
||||
"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
-15
@@ -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,215 +0,0 @@
|
||||
using Autodesk.Revit.DB;
|
||||
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;
|
||||
|
||||
public RevitParametersBinding(
|
||||
IBrowserBridge parent,
|
||||
RevitContext revitContext,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler,
|
||||
IRevitTask revitTask,
|
||||
ParameterUpdater parameterUpdater,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IBasicConnectorBinding baseBinding
|
||||
)
|
||||
{
|
||||
Parent = parent;
|
||||
_revitContext = revitContext;
|
||||
_topLevelExceptionHandler = topLevelExceptionHandler;
|
||||
_revitTask = revitTask;
|
||||
_parameterUpdater = parameterUpdater;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_baseBinding = baseBinding;
|
||||
}
|
||||
|
||||
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() > 1 ? $"{g.Count()} x {g.Key}" : g.Key);
|
||||
await _baseBinding.Commands.SetGlobalNotification(
|
||||
ToastNotificationType.WARNING,
|
||||
"Update Completed with Issues",
|
||||
$"Applied {successCount} updates. Encountered {errors.Count} errors: {string.Join(" | ", groupedErrors)}",
|
||||
autoClose: false
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _baseBinding.Commands.SetGlobalNotification(
|
||||
ToastNotificationType.SUCCESS,
|
||||
"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;
|
||||
}
|
||||
|
||||
var elementId = ElementIdHelper.GetElementIdFromUniqueId(doc, request.ApplicationId);
|
||||
if (elementId == null)
|
||||
{
|
||||
errorMessage = $"Element UniqueId not found: {request.ApplicationId}";
|
||||
return false;
|
||||
}
|
||||
|
||||
element = doc.GetElement(elementId);
|
||||
if (element == null)
|
||||
{
|
||||
errorMessage = $"Element is null for Id: {elementId}";
|
||||
return false;
|
||||
}
|
||||
|
||||
var rawPath = request.Path;
|
||||
if (string.IsNullOrEmpty(rawPath))
|
||||
{
|
||||
errorMessage = "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)
|
||||
{
|
||||
errorMessage = $"Path must have 3 parts. Got: '{rawPath}'";
|
||||
return false;
|
||||
}
|
||||
|
||||
parsedPath = new ParsedParameterPath(pathParts[0], pathParts[1], pathParts[2]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
+2
-15
@@ -48,46 +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.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; }
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Converters.RevitShared.Services;
|
||||
using Speckle.Sdk;
|
||||
using DB = Autodesk.Revit.DB;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// Updates parameter values on Revit elements. Mirrors the structure from ParameterExtractor.
|
||||
/// Path format: ["Instance Parameters" | "Type Parameters" | "System Type Parameters", "GroupName", "ParameterName"]
|
||||
/// </summary>
|
||||
public class ParameterUpdater
|
||||
{
|
||||
private readonly RevitContext _revitContext;
|
||||
private readonly ScalingServiceToHost _scalingServiceToHost;
|
||||
private readonly ILogger<ParameterUpdater> _logger;
|
||||
|
||||
public ParameterUpdater(
|
||||
RevitContext revitContext,
|
||||
ScalingServiceToHost scalingServiceToHost,
|
||||
ILogger<ParameterUpdater> logger
|
||||
)
|
||||
{
|
||||
_revitContext = revitContext;
|
||||
_scalingServiceToHost = scalingServiceToHost;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public UpdateResult Update(DB.Element element, string[] path, object? newValue, string? internalDefinitionName = null)
|
||||
{
|
||||
// path = ["Instance Parameters", "Identity Data", "Mark"]
|
||||
if (path.Length != 3)
|
||||
{
|
||||
return UpdateResult.Fail(
|
||||
$"Path must have exactly 3 segments: [scope, group, parameter]. Got: {string.Join(" → ", path)}"
|
||||
);
|
||||
}
|
||||
|
||||
var parameterScope = path[0]; // "Instance Parameters" | "Type Parameters" | "System Type Parameters"
|
||||
var groupName = path[1]; // "Identity Data", "Dimensions", etc.
|
||||
var parameterKey = path[2]; // human-readable name (or internalDefinitionName if collision)
|
||||
|
||||
// get target element based on scope
|
||||
var targetElement = GetTargetElement(element, parameterScope);
|
||||
if (targetElement == null)
|
||||
{
|
||||
return UpdateResult.Fail($"Could not resolve target for scope: {parameterScope}");
|
||||
}
|
||||
|
||||
// find the parameter (now using the robust lookup)
|
||||
var parameter = FindParameter(targetElement, groupName, parameterKey, internalDefinitionName);
|
||||
if (parameter == null)
|
||||
{
|
||||
return UpdateResult.Fail($"Parameter not found: {parameterKey} in group {groupName}");
|
||||
}
|
||||
|
||||
if (parameter.IsReadOnly)
|
||||
{
|
||||
return UpdateResult.Fail($"Parameter '{parameterKey}' is readonly in Revit");
|
||||
}
|
||||
|
||||
return SetParameterValue(parameter, newValue);
|
||||
}
|
||||
|
||||
private DB.Element? GetTargetElement(DB.Element element, string scope) =>
|
||||
scope switch
|
||||
{
|
||||
"Instance Parameters" => element,
|
||||
"Type Parameters" => GetTypeElement(element),
|
||||
"System Type Parameters" => GetSystemTypeElement(element),
|
||||
_ => null
|
||||
};
|
||||
|
||||
private DB.Element? GetTypeElement(DB.Element element)
|
||||
{
|
||||
var typeId = element.GetTypeId();
|
||||
if (typeId == DB.ElementId.InvalidElementId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _revitContext.UIApplication?.ActiveUIDocument.Document.GetElement(typeId);
|
||||
}
|
||||
|
||||
private DB.Element? GetSystemTypeElement(DB.Element element)
|
||||
{
|
||||
var system = GetMEPSystem(element);
|
||||
if (system == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _revitContext.UIApplication?.ActiveUIDocument.Document.GetElement(system.GetTypeId());
|
||||
}
|
||||
|
||||
private DB.MEPSystem? GetMEPSystem(DB.Element element)
|
||||
{
|
||||
if (element is DB.MEPCurve curve)
|
||||
{
|
||||
return curve.MEPSystem;
|
||||
}
|
||||
|
||||
if (element is DB.FamilyInstance fi)
|
||||
{
|
||||
var cm = fi.MEPModel?.ConnectorManager;
|
||||
if (cm != null)
|
||||
{
|
||||
foreach (DB.Connector conn in cm.Connectors)
|
||||
{
|
||||
if (conn.ConnectorType == DB.ConnectorType.Physical && conn.IsConnected && conn.MEPSystem != null)
|
||||
{
|
||||
return conn.MEPSystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private DB.Parameter? FindParameter(
|
||||
DB.Element element,
|
||||
string groupName,
|
||||
string parameterKey,
|
||||
string? internalDefinitionName
|
||||
)
|
||||
{
|
||||
// fast path: direct lookup using the internal definition name
|
||||
if (!string.IsNullOrEmpty(internalDefinitionName))
|
||||
{
|
||||
// try as BuiltInParameter enum
|
||||
if (Enum.TryParse(internalDefinitionName, out DB.BuiltInParameter bip) && bip != DB.BuiltInParameter.INVALID)
|
||||
{
|
||||
var param = element.get_Parameter(bip);
|
||||
if (param != null)
|
||||
{
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
// try as shared parameter Guid
|
||||
if (Guid.TryParse(internalDefinitionName, out Guid guid))
|
||||
{
|
||||
var param = element.get_Parameter(guid);
|
||||
if (param != null)
|
||||
{
|
||||
return param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fallback: iteration for project parameters or missing internal names
|
||||
DB.Parameter? fallbackParameter = null;
|
||||
|
||||
foreach (DB.Parameter parameter in element.Parameters)
|
||||
{
|
||||
var definition = parameter.Definition;
|
||||
if (definition == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var currentInternalName = GetInternalDefinitionName(parameter);
|
||||
var humanName = definition.Name;
|
||||
|
||||
// exact internal name match (covers project params that aren't BuiltIn/Shared)
|
||||
if (!string.IsNullOrEmpty(internalDefinitionName) && currentInternalName == internalDefinitionName)
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// fallback human-readable name matching
|
||||
if (humanName == parameterKey || currentInternalName == parameterKey)
|
||||
{
|
||||
var paramGroup = definition.GetGroupTypeId();
|
||||
var groupLabel = DB.LabelUtils.GetLabelForGroup(paramGroup);
|
||||
|
||||
if (groupLabel == groupName)
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
fallbackParameter ??= parameter;
|
||||
}
|
||||
}
|
||||
|
||||
return fallbackParameter;
|
||||
}
|
||||
|
||||
private string GetInternalDefinitionName(DB.Parameter parameter)
|
||||
{
|
||||
if (parameter.Definition is DB.InternalDefinition internalDef)
|
||||
{
|
||||
var bip = internalDef.BuiltInParameter;
|
||||
if (bip != DB.BuiltInParameter.INVALID)
|
||||
{
|
||||
return bip.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return parameter.Definition.Name;
|
||||
}
|
||||
|
||||
private UpdateResult SetParameterValue(DB.Parameter parameter, object? newValue)
|
||||
{
|
||||
var paramName = parameter.Definition.Name;
|
||||
if (newValue == null)
|
||||
{
|
||||
if (parameter.StorageType == DB.StorageType.String)
|
||||
{
|
||||
return parameter.Set(string.Empty)
|
||||
? UpdateResult.Success()
|
||||
: UpdateResult.Fail("Failed to clear string parameter");
|
||||
}
|
||||
return UpdateResult.Fail("Cannot set non-string parameter to null");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var success = parameter.StorageType switch
|
||||
{
|
||||
DB.StorageType.String => parameter.Set(newValue.ToString()),
|
||||
DB.StorageType.Integer => SetIntegerValue(parameter, newValue),
|
||||
DB.StorageType.Double => SetDoubleValue(parameter, newValue),
|
||||
DB.StorageType.ElementId => SetElementIdValue(parameter, newValue),
|
||||
_ => false
|
||||
};
|
||||
|
||||
return success ? UpdateResult.Success() : UpdateResult.Fail($"Failed to set parameter value to: {newValue}");
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to set parameter value");
|
||||
return UpdateResult.Fail($"Exception for '{paramName}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool SetIntegerValue(DB.Parameter parameter, object newValue)
|
||||
{
|
||||
if (newValue is int i)
|
||||
{
|
||||
return parameter.Set(i);
|
||||
}
|
||||
|
||||
if (newValue is bool b)
|
||||
{
|
||||
return parameter.Set(b ? 1 : 0);
|
||||
}
|
||||
|
||||
if (int.TryParse(newValue.ToString(), out var parsed))
|
||||
{
|
||||
return parameter.Set(parsed);
|
||||
}
|
||||
|
||||
var strValue = newValue.ToString();
|
||||
if (strValue == "Yes")
|
||||
{
|
||||
return parameter.Set(1);
|
||||
}
|
||||
if (strValue == "No")
|
||||
{
|
||||
return parameter.Set(0);
|
||||
}
|
||||
|
||||
return parameter.SetValueString(strValue);
|
||||
}
|
||||
|
||||
private bool SetDoubleValue(DB.Parameter parameter, object newValue)
|
||||
{
|
||||
double doubleValue;
|
||||
|
||||
if (newValue is double d)
|
||||
{
|
||||
doubleValue = d;
|
||||
}
|
||||
else if (newValue is int intVal)
|
||||
{
|
||||
doubleValue = intVal;
|
||||
}
|
||||
else if (double.TryParse(newValue.ToString(), out var parsed))
|
||||
{
|
||||
doubleValue = parsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var internalValue = _scalingServiceToHost.ScaleToNative(doubleValue, parameter.GetUnitTypeId());
|
||||
return parameter.Set(internalValue);
|
||||
}
|
||||
|
||||
private bool SetElementIdValue(DB.Parameter parameter, object newValue)
|
||||
{
|
||||
if (newValue is DB.ElementId eid)
|
||||
{
|
||||
return parameter.Set(eid);
|
||||
}
|
||||
|
||||
// TODO: check this fckr later
|
||||
|
||||
// if (newValue is long idInt)
|
||||
// {
|
||||
// #if REVIT2024_OR_GREATER
|
||||
// return parameter.Set(new DB.ElementId(idInt));
|
||||
// #else
|
||||
// return parameter.Set(new DB.ElementId((long)idInt));
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// if (long.TryParse(newValue.ToString(), out var parsedId))
|
||||
// {
|
||||
// #if REVIT2024_OR_GREATER
|
||||
// return parameter.Set(new DB.ElementId(parsedId));
|
||||
// #else
|
||||
// return parameter.Set(new DB.ElementId((long)parsedId));
|
||||
// #endif
|
||||
// }
|
||||
|
||||
var elementName = newValue.ToString();
|
||||
if (elementName != null)
|
||||
{
|
||||
var foundElement = FindElementByName(elementName);
|
||||
if (foundElement != null)
|
||||
{
|
||||
return parameter.Set(foundElement.Id);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private DB.Element? FindElementByName(string name)
|
||||
{
|
||||
var doc = _revitContext.UIApplication?.ActiveUIDocument.Document;
|
||||
|
||||
using var materialCollector = new DB.FilteredElementCollector(doc);
|
||||
var material = materialCollector.OfClass(typeof(DB.Material)).FirstOrDefault(e => e.Name == name);
|
||||
if (material != null)
|
||||
{
|
||||
return material;
|
||||
}
|
||||
|
||||
using var levelCollector = new DB.FilteredElementCollector(doc);
|
||||
var level = levelCollector.OfClass(typeof(DB.Level)).FirstOrDefault(e => e.Name == name);
|
||||
if (level != null)
|
||||
{
|
||||
return level;
|
||||
}
|
||||
using var phaseCollector = new DB.FilteredElementCollector(doc);
|
||||
var phase = phaseCollector.OfClass(typeof(DB.Phase)).FirstOrDefault(e => e.Name == name);
|
||||
if (phase != null)
|
||||
{
|
||||
return phase;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: we will see, extract this guy out
|
||||
public readonly struct UpdateResult
|
||||
{
|
||||
public bool IsSuccess { get; }
|
||||
public string? ErrorMessage { get; }
|
||||
|
||||
private UpdateResult(bool success, string? error)
|
||||
{
|
||||
IsSuccess = success;
|
||||
ErrorMessage = error;
|
||||
}
|
||||
|
||||
public static UpdateResult Success() => new(true, null);
|
||||
|
||||
public static UpdateResult Fail(string message) => new(false, message);
|
||||
}
|
||||
@@ -17,16 +17,13 @@ namespace Speckle.Connectors.Revit.HostApp;
|
||||
internal sealed class RevitDocumentStore : DocumentModelStore
|
||||
{
|
||||
private readonly ILogger<RevitDocumentStore> _logger;
|
||||
|
||||
//private readonly IAppIdleManager _idleManager;
|
||||
private readonly RevitIdleManager _idleManager;
|
||||
private readonly IAppIdleManager _idleManager;
|
||||
private readonly RevitContext _revitContext;
|
||||
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
|
||||
private readonly ISqLiteJsonCacheManager _jsonCacheManager;
|
||||
|
||||
public RevitDocumentStore(
|
||||
//IAppIdleManager idleManager,
|
||||
RevitIdleManager idleManager,
|
||||
IAppIdleManager idleManager,
|
||||
RevitContext revitContext,
|
||||
IJsonSerializer jsonSerializer,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler,
|
||||
@@ -37,7 +34,6 @@ internal sealed class RevitDocumentStore : DocumentModelStore
|
||||
: base(logger, jsonSerializer)
|
||||
{
|
||||
_jsonCacheManager = jsonCacheManagerFactory.CreateForUser("ConnectorsFileData");
|
||||
//_idleManager = idleManager;
|
||||
_idleManager = idleManager;
|
||||
_revitContext = revitContext;
|
||||
_topLevelExceptionHandler = topLevelExceptionHandler;
|
||||
|
||||
@@ -1,621 +0,0 @@
|
||||
using System.IO;
|
||||
using Autodesk.Revit.Creation;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.Structure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Speckle.Connectors.Common.Conversion;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common.Objects;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Converters.RevitShared.Settings;
|
||||
using Speckle.DoubleNumerics;
|
||||
using Speckle.Objects.Other;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.GraphTraversal;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
using DB = Autodesk.Revit.DB;
|
||||
using Document = Autodesk.Revit.DB.Document;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
public sealed class RevitFamilyBaker : IDisposable
|
||||
{
|
||||
private readonly IConverterSettingsStore<RevitConversionSettings> _converterSettings;
|
||||
private readonly RevitToHostCacheSingleton _cache;
|
||||
private readonly ILogger<RevitFamilyBaker> _logger;
|
||||
private readonly ITypedConverter<(Matrix4x4 matrix, string units), DB.Transform> _transformConverter;
|
||||
private readonly RevitMaterialBaker _materialBaker;
|
||||
private readonly FamilyGeometryBaker _familyGeometryBaker;
|
||||
private readonly FamilyCategoryUtils _familyCategoryUtils;
|
||||
private readonly FamilyTransformUtils _familyTransformUtils;
|
||||
|
||||
private string? _cachedTemplatePath;
|
||||
private readonly Dictionary<string, string> _bakedFamilyPaths = [];
|
||||
|
||||
private readonly string _tempDirectory;
|
||||
private static readonly char[] s_invalidChars = Path.GetInvalidFileNameChars();
|
||||
|
||||
public RevitFamilyBaker(
|
||||
IConverterSettingsStore<RevitConversionSettings> converterSettings,
|
||||
RevitToHostCacheSingleton cache,
|
||||
ILogger<RevitFamilyBaker> logger,
|
||||
ITypedConverter<(Matrix4x4 matrix, string units), DB.Transform> transformConverter,
|
||||
RevitMaterialBaker materialBaker,
|
||||
FamilyGeometryBaker familyGeometryBaker,
|
||||
FamilyCategoryUtils familyCategoryUtils,
|
||||
FamilyTransformUtils familyTransformUtils
|
||||
)
|
||||
{
|
||||
_converterSettings = converterSettings;
|
||||
_cache = cache;
|
||||
_logger = logger;
|
||||
_transformConverter = transformConverter;
|
||||
_materialBaker = materialBaker;
|
||||
_familyGeometryBaker = familyGeometryBaker;
|
||||
_familyCategoryUtils = familyCategoryUtils;
|
||||
_familyTransformUtils = familyTransformUtils;
|
||||
_tempDirectory = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString("N")[..8]}");
|
||||
Directory.CreateDirectory(_tempDirectory);
|
||||
}
|
||||
|
||||
public (List<ReceiveConversionResult> results, List<string> createdElementIds) BakeInstances(
|
||||
ICollection<(Collection[] collectionPath, IInstanceComponent component)> instanceComponents,
|
||||
IReadOnlyDictionary<string, TraversalContext> speckleObjectLookup,
|
||||
IReadOnlyCollection<RenderMaterialProxy> materialProxies,
|
||||
IProgress<CardProgress> onOperationProgressed
|
||||
)
|
||||
{
|
||||
var document = _converterSettings.Current.Document;
|
||||
var results = new List<ReceiveConversionResult>();
|
||||
var createdElementIds = new List<string>();
|
||||
|
||||
var (objectToMaterialMap, safeNameToProjectMatId) = BuildMaterialMaps(materialProxies);
|
||||
var consumedIds = BuildConsumedIdsSet(instanceComponents, speckleObjectLookup);
|
||||
var sortedComponents = SortComponentsForBaking(instanceComponents);
|
||||
|
||||
var count = 0;
|
||||
foreach (var (_, component) in sortedComponents)
|
||||
{
|
||||
onOperationProgressed.Report(new("Creating families", (double)++count / sortedComponents.Count));
|
||||
|
||||
try
|
||||
{
|
||||
if (component is InstanceDefinitionProxy definitionProxy)
|
||||
{
|
||||
var categoryString = _familyCategoryUtils.ExtractCategoryForDefinition(
|
||||
definitionProxy,
|
||||
instanceComponents,
|
||||
speckleObjectLookup
|
||||
);
|
||||
var result = CreateFamilyFromDefinition(
|
||||
document,
|
||||
definitionProxy,
|
||||
speckleObjectLookup,
|
||||
objectToMaterialMap,
|
||||
safeNameToProjectMatId,
|
||||
categoryString
|
||||
);
|
||||
|
||||
if (result.HasValue)
|
||||
{
|
||||
results.Add(
|
||||
new ReceiveConversionResult(Status.SUCCESS, definitionProxy, result.Value.family.Id.ToString(), "Family")
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (component is InstanceProxy instanceProxy)
|
||||
{
|
||||
bool isConsumed =
|
||||
(instanceProxy.id != null && consumedIds.Contains(instanceProxy.id))
|
||||
|| (instanceProxy.applicationId != null && consumedIds.Contains(instanceProxy.applicationId));
|
||||
|
||||
if (isConsumed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var instance = PlaceFamilyInstance(document, instanceProxy);
|
||||
|
||||
if (instance != null)
|
||||
{
|
||||
createdElementIds.Add(instance.UniqueId);
|
||||
|
||||
if (_familyTransformUtils.HasScaleOrSkew(instanceProxy.transform))
|
||||
{
|
||||
var warningEx = new SpeckleException(
|
||||
"Block instance placed with its original position and rotation, but the unsupported scale/skew was dropped"
|
||||
);
|
||||
results.Add(
|
||||
new ReceiveConversionResult(
|
||||
Status.WARNING,
|
||||
instanceProxy,
|
||||
instance.UniqueId,
|
||||
"FamilyInstance",
|
||||
warningEx
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(
|
||||
new ReceiveConversionResult(Status.SUCCESS, instanceProxy, instance.UniqueId, "FamilyInstance")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
string componentId = component switch
|
||||
{
|
||||
InstanceDefinitionProxy d => d.applicationId ?? d.id.NotNull(),
|
||||
InstanceProxy i => i.applicationId ?? i.id.NotNull(),
|
||||
_ => "unknown"
|
||||
};
|
||||
_logger.LogError(ex, "Failed to process instance component {ComponentId}", componentId);
|
||||
|
||||
if (component is Base b)
|
||||
{
|
||||
results.Add(new ReceiveConversionResult(Status.ERROR, b, null, null, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (results, createdElementIds);
|
||||
}
|
||||
|
||||
private (
|
||||
Dictionary<string, RenderMaterial> objectToMaterialMap,
|
||||
Dictionary<string, ElementId> safeNameToProjectMatId
|
||||
) BuildMaterialMaps(IReadOnlyCollection<RenderMaterialProxy> materialProxies)
|
||||
{
|
||||
Dictionary<string, RenderMaterial> objectToMaterialMap = new();
|
||||
Dictionary<string, ElementId> safeNameToProjectMatId = new();
|
||||
|
||||
foreach (var proxy in materialProxies)
|
||||
{
|
||||
string matId = proxy.value.id.NotNullOrWhiteSpace();
|
||||
string safeName = string.IsNullOrWhiteSpace(proxy.value.name) ? matId : proxy.value.name;
|
||||
|
||||
foreach (var objId in proxy.objects)
|
||||
{
|
||||
objectToMaterialMap[objId] = proxy.value;
|
||||
}
|
||||
|
||||
if (proxy.objects.Count > 0)
|
||||
{
|
||||
foreach (var objId in proxy.objects)
|
||||
{
|
||||
if (_cache.MaterialsByObjectId.TryGetValue(objId, out var projMatId))
|
||||
{
|
||||
safeNameToProjectMatId[safeName] = projMatId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (objectToMaterialMap, safeNameToProjectMatId);
|
||||
}
|
||||
|
||||
private static HashSet<string> BuildConsumedIdsSet(
|
||||
ICollection<(Collection[] collectionPath, IInstanceComponent component)> instanceComponents,
|
||||
IReadOnlyDictionary<string, TraversalContext> speckleObjectLookup
|
||||
)
|
||||
{
|
||||
var consumedIds = new HashSet<string>();
|
||||
|
||||
foreach (var (_, component) in instanceComponents)
|
||||
{
|
||||
if (component is InstanceDefinitionProxy definition)
|
||||
{
|
||||
foreach (var childId in definition.objects ?? Enumerable.Empty<string>())
|
||||
{
|
||||
consumedIds.Add(childId);
|
||||
if (speckleObjectLookup.TryGetValue(childId, out var childTc))
|
||||
{
|
||||
var childObj = childTc.Current;
|
||||
if (childObj.id != null)
|
||||
{
|
||||
consumedIds.Add(childObj.id);
|
||||
}
|
||||
|
||||
if (childObj.applicationId != null)
|
||||
{
|
||||
consumedIds.Add(childObj.applicationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumedIds;
|
||||
}
|
||||
|
||||
private static List<(Collection[] collectionPath, IInstanceComponent component)> SortComponentsForBaking(
|
||||
ICollection<(Collection[] collectionPath, IInstanceComponent component)> instanceComponents
|
||||
) =>
|
||||
instanceComponents
|
||||
.OrderByDescending(x => x.component.maxDepth)
|
||||
.ThenBy(x => x.component is InstanceDefinitionProxy ? 0 : 1)
|
||||
.ToList();
|
||||
|
||||
private (Family family, FamilySymbol symbol)? CreateFamilyFromDefinition(
|
||||
Document document,
|
||||
InstanceDefinitionProxy definitionProxy,
|
||||
IReadOnlyDictionary<string, TraversalContext> objectLookup,
|
||||
IReadOnlyDictionary<string, RenderMaterial> materialMap,
|
||||
IReadOnlyDictionary<string, ElementId> safeNameToProjectMatId,
|
||||
string? categoryString
|
||||
)
|
||||
{
|
||||
var definitionId = definitionProxy.applicationId ?? definitionProxy.id.NotNull();
|
||||
|
||||
if (_cache.FamiliesByDefinitionId.TryGetValue(definitionId, out var existingFamily))
|
||||
{
|
||||
var existingSymbol = _cache.SymbolsByDefinitionId[definitionId];
|
||||
return (existingFamily, existingSymbol);
|
||||
}
|
||||
|
||||
var familyName = GetFamilyName(definitionProxy);
|
||||
|
||||
bool isNewFamily = false;
|
||||
var family = FindFamilyByName(document, familyName);
|
||||
|
||||
if (family == null)
|
||||
{
|
||||
family = CreateFamily(document, familyName, definitionProxy, objectLookup, materialMap, categoryString);
|
||||
isNewFamily = true;
|
||||
}
|
||||
|
||||
if (family == null)
|
||||
{
|
||||
_logger.LogWarning("Failed to create family for definition {DefinitionId}", definitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
var symbolId = family.GetFamilySymbolIds().FirstOrDefault();
|
||||
if (symbolId == null || symbolId == ElementId.InvalidElementId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (document.GetElement(symbolId) is not FamilySymbol symbol)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!symbol.IsActive)
|
||||
{
|
||||
symbol.Activate();
|
||||
document.Regenerate();
|
||||
}
|
||||
|
||||
if (isNewFamily)
|
||||
{
|
||||
FamilyMaterialManager.AssignProjectMaterialsToFamily(document, symbol, safeNameToProjectMatId);
|
||||
}
|
||||
|
||||
_cache.FamiliesByDefinitionId[definitionId] = family;
|
||||
_cache.SymbolsByDefinitionId[definitionId] = symbol;
|
||||
|
||||
return (family, symbol);
|
||||
}
|
||||
|
||||
private Family? CreateFamily(
|
||||
Document document,
|
||||
string familyName,
|
||||
InstanceDefinitionProxy definition,
|
||||
IReadOnlyDictionary<string, TraversalContext> objectLookup,
|
||||
IReadOnlyDictionary<string, RenderMaterial> materialMap,
|
||||
string? categoryString
|
||||
)
|
||||
{
|
||||
var templatePath = GetFamilyTemplatePath(document);
|
||||
var famDoc = document.Application.NewFamilyDocument(templatePath);
|
||||
var tempPath = Path.Combine(_tempDirectory, $"{familyName}.rfa");
|
||||
|
||||
try
|
||||
{
|
||||
using (var t = new Transaction(famDoc, "Populate Family"))
|
||||
{
|
||||
t.Start();
|
||||
|
||||
var materialManager = new FamilyMaterialManager(_materialBaker, _logger);
|
||||
materialManager.SetupFamilyMaterials(famDoc, definition, objectLookup, materialMap);
|
||||
|
||||
_familyGeometryBaker.BakeFamilyGeometry(
|
||||
famDoc,
|
||||
definition,
|
||||
objectLookup,
|
||||
materialMap,
|
||||
materialManager,
|
||||
PlaceNestedInstance
|
||||
);
|
||||
|
||||
SetFamilyWorkPlaneBased(famDoc, true);
|
||||
_familyCategoryUtils.SetFamilyCategory(famDoc, categoryString);
|
||||
t.Commit();
|
||||
}
|
||||
|
||||
var saveOptions = new SaveAsOptions { OverwriteExistingFile = true };
|
||||
famDoc.SaveAs(tempPath, saveOptions);
|
||||
famDoc.Close(false);
|
||||
|
||||
var definitionId = definition.applicationId ?? definition.id.NotNull();
|
||||
_bakedFamilyPaths[definitionId] = tempPath;
|
||||
|
||||
document.LoadFamily(tempPath, new FamilyLoadOptions(), out var loadedFamily);
|
||||
return loadedFamily;
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.ApplicationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Revit API error creating family {FamilyName}", familyName);
|
||||
famDoc.Close(false);
|
||||
SafeDelete(tempPath);
|
||||
throw;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IO error creating family {FamilyName}", familyName);
|
||||
famDoc.Close(false);
|
||||
SafeDelete(tempPath);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlaceNestedInstance(Document famDoc, InstanceProxy instanceProxy, FamilyMaterialManager? materialManager)
|
||||
{
|
||||
var childDefinitionId = instanceProxy.definitionId;
|
||||
|
||||
if (!_bakedFamilyPaths.TryGetValue(childDefinitionId, out var rfaPath) || !File.Exists(rfaPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var familyName = Path.GetFileNameWithoutExtension(rfaPath);
|
||||
Family? childFamily = FindFamilyByName(famDoc, familyName) ?? LoadFamilyWrapper(famDoc, rfaPath);
|
||||
|
||||
using var _ = childFamily;
|
||||
if (childFamily == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var symbolId = childFamily.GetFamilySymbolIds().FirstOrDefault();
|
||||
if (symbolId == null || famDoc.GetElement(symbolId) is not FamilySymbol symbol)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!symbol.IsActive)
|
||||
{
|
||||
symbol.Activate();
|
||||
}
|
||||
|
||||
var instance = CreateAndPlaceFamilyInstance(famDoc, instanceProxy, symbol);
|
||||
|
||||
if (instance != null && materialManager != null)
|
||||
{
|
||||
foreach (Parameter childParam in symbol.Parameters)
|
||||
{
|
||||
if (childParam.Definition.Name.StartsWith("Material_") && childParam.StorageType == StorageType.ElementId)
|
||||
{
|
||||
string paramName = childParam.Definition.Name;
|
||||
|
||||
FamilyParameter? parentFamParam =
|
||||
famDoc.FamilyManager.get_Parameter(paramName)
|
||||
?? famDoc.FamilyManager.AddParameter(
|
||||
paramName,
|
||||
GroupTypeId.Materials,
|
||||
SpecTypeId.Reference.Material,
|
||||
false
|
||||
);
|
||||
|
||||
if (famDoc.FamilyManager.CanElementParameterBeAssociated(childParam))
|
||||
{
|
||||
try
|
||||
{
|
||||
famDoc.FamilyManager.AssociateElementParameterToFamilyParameter(childParam, parentFamParam);
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.ArgumentException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to associate material parameter {ParamName}", paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Family? LoadFamilyWrapper(Document doc, string path)
|
||||
{
|
||||
doc.LoadFamily(path, new FamilyLoadOptions(), out var family);
|
||||
return family;
|
||||
}
|
||||
|
||||
private FamilyInstance? CreateAndPlaceFamilyInstance(Document doc, InstanceProxy instanceProxy, FamilySymbol symbol)
|
||||
{
|
||||
var isMirrored = _familyTransformUtils.GetMirrorState(instanceProxy.transform).X;
|
||||
var hasScaleOrSkew = _familyTransformUtils.HasScaleOrSkew(instanceProxy.transform);
|
||||
|
||||
var cleanMatrix =
|
||||
(hasScaleOrSkew || isMirrored)
|
||||
? _familyTransformUtils.RemoveScaleAndSkew(instanceProxy.transform)
|
||||
: instanceProxy.transform;
|
||||
|
||||
var revitTransform = _transformConverter.Convert((cleanMatrix, instanceProxy.units));
|
||||
|
||||
XYZ origin = revitTransform.Origin;
|
||||
XYZ basisX = revitTransform.BasisX.Normalize();
|
||||
XYZ basisY = revitTransform.BasisY.Normalize();
|
||||
|
||||
var plane = DB.Plane.CreateByOriginAndBasis(origin, basisX, basisY);
|
||||
using var sketchPlane = SketchPlane.Create(doc, plane);
|
||||
|
||||
var creationData = new FamilyInstanceCreationData(
|
||||
location: origin,
|
||||
symbol: symbol,
|
||||
host: sketchPlane,
|
||||
level: null,
|
||||
structuralType: StructuralType.NonStructural
|
||||
);
|
||||
|
||||
ICollection<ElementId> ids = doc.IsFamilyDocument
|
||||
? doc.FamilyCreate.NewFamilyInstances2([creationData])
|
||||
: doc.Create.NewFamilyInstances2([creationData]);
|
||||
|
||||
if (ids.Count == 0 || doc.GetElement(ids.First()) is not FamilyInstance instance)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
doc.Regenerate();
|
||||
var mirrorState = _familyTransformUtils.GetMirrorState(instanceProxy.transform);
|
||||
_familyTransformUtils.ApplyMirroring(doc, instance.Id, plane, mirrorState);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private FamilyInstance? PlaceFamilyInstance(Document document, InstanceProxy instanceProxy)
|
||||
{
|
||||
var definitionId = instanceProxy.definitionId;
|
||||
|
||||
if (_cache.SymbolsByDefinitionId.TryGetValue(definitionId, out var symbol))
|
||||
{
|
||||
return CreateAndPlaceFamilyInstance(document, instanceProxy, symbol);
|
||||
}
|
||||
|
||||
_logger.LogWarning("No family symbol found for definition {DefinitionId}", definitionId);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetFamilyWorkPlaneBased(Document famDoc, bool enabled)
|
||||
{
|
||||
var workPlaneBasedParam = famDoc.OwnerFamily.get_Parameter(BuiltInParameter.FAMILY_WORK_PLANE_BASED);
|
||||
if (workPlaneBasedParam != null && !workPlaneBasedParam.IsReadOnly)
|
||||
{
|
||||
workPlaneBasedParam.Set(enabled ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFamilyTemplatePath(Document document)
|
||||
{
|
||||
if (_cachedTemplatePath != null)
|
||||
{
|
||||
return _cachedTemplatePath;
|
||||
}
|
||||
|
||||
var version = document.Application.VersionNumber;
|
||||
var isMetric = document.DisplayUnitSystem == DisplayUnit.METRIC;
|
||||
var templateName = isMetric ? "Metric Generic Model.rft" : "Generic Model.rft";
|
||||
var assemblyLocation = typeof(RevitFamilyBaker).Assembly.Location;
|
||||
var assemblyDir =
|
||||
Path.GetDirectoryName(assemblyLocation) ?? throw new ConversionException("Could not resolve assembly directory");
|
||||
|
||||
var templatePath = Path.Combine(assemblyDir, "Resources", "Templates", version, templateName);
|
||||
|
||||
if (!File.Exists(templatePath))
|
||||
{
|
||||
_logger.LogError("Revit Family Template missing. Searched path: {templatePath}", templatePath);
|
||||
throw new ConversionException($"Could not find required family template: {templateName}");
|
||||
}
|
||||
|
||||
_cachedTemplatePath = templatePath;
|
||||
return templatePath;
|
||||
}
|
||||
|
||||
private static string GetFamilyName(InstanceDefinitionProxy definitionProxy)
|
||||
{
|
||||
var baseName = definitionProxy.name;
|
||||
if (string.IsNullOrWhiteSpace(baseName))
|
||||
{
|
||||
return "Unnamed_Block";
|
||||
}
|
||||
|
||||
char[] buffer = baseName.ToCharArray();
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
if (Array.IndexOf(s_invalidChars, buffer[i]) >= 0)
|
||||
{
|
||||
buffer[i] = '_';
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
var safeName = changed ? new string(buffer) : baseName;
|
||||
|
||||
// truncate to avoid MAX_PATH exceptions. 100 chars should be very safe.
|
||||
if (safeName.Length > 100)
|
||||
{
|
||||
// Append a short hash of the definition ID to guarantee uniqueness after truncation
|
||||
var shortId = definitionProxy.id?[..8] ?? Guid.NewGuid().ToString("N")[..8];
|
||||
return $"{safeName[..90]}_{shortId}";
|
||||
}
|
||||
|
||||
return safeName;
|
||||
}
|
||||
|
||||
private static Family? FindFamilyByName(Document document, string familyName)
|
||||
{
|
||||
using var collector = new FilteredElementCollector(document);
|
||||
return collector.OfClass(typeof(Family)).OfType<Family>().FirstOrDefault(f => f.Name == familyName);
|
||||
}
|
||||
|
||||
private static void SafeDelete(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) { }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_bakedFamilyPaths.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(_tempDirectory))
|
||||
{
|
||||
Directory.Delete(_tempDirectory, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to clean up temporary family directory at {TempDir}", _tempDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FamilyLoadOptions : IFamilyLoadOptions
|
||||
{
|
||||
public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
|
||||
{
|
||||
overwriteParameterValues = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnSharedFamilyFound(
|
||||
Family sharedFamily,
|
||||
bool familyInUse,
|
||||
out FamilySource source,
|
||||
out bool overwriteParameterValues
|
||||
)
|
||||
{
|
||||
source = FamilySource.Family;
|
||||
overwriteParameterValues = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Speckle.Converters.Common;
|
||||
using Speckle.Converters.RevitShared.Settings;
|
||||
using Speckle.Objects.Other;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Extensions;
|
||||
using Speckle.Sdk.Models.GraphTraversal;
|
||||
@@ -31,24 +32,6 @@ public class RevitMaterialBaker
|
||||
_converterSettings = converterSettings;
|
||||
}
|
||||
|
||||
private ElementId? FindExistingMaterialByName(string? materialName, Document document)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(materialName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string sanitizedName = _revitUtils.RemoveInvalidChars(materialName!);
|
||||
|
||||
using var collector = new FilteredElementCollector(document);
|
||||
var existingMaterial = collector
|
||||
.OfClass(typeof(Material))
|
||||
.Cast<Material>()
|
||||
.FirstOrDefault(m => string.Equals(m.Name, sanitizedName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return existingMaterial?.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the every atomic object has render material or not, if not it tries to find it from its layer tree and mutates
|
||||
/// its render material proxy objects list with the traversal current. It will also map displayable objects' display values to their
|
||||
@@ -120,58 +103,44 @@ public class RevitMaterialBaker
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bakes a single Speckle RenderMaterial into the provided document.
|
||||
/// Used both for project-level baking and isolated family-level baking.
|
||||
/// </summary>
|
||||
public ElementId BakeMaterial(RenderMaterial speckleRenderMaterial, Document document)
|
||||
{
|
||||
ElementId? existingMaterialId = FindExistingMaterialByName(speckleRenderMaterial.name, document);
|
||||
|
||||
if (existingMaterialId != null)
|
||||
{
|
||||
return existingMaterialId;
|
||||
}
|
||||
|
||||
// create new material
|
||||
// all values assumed to be on the 0 - 1 scale need to pass through this validation and logging (if assumption wrong)
|
||||
double roughness = ClampToUnitRange(speckleRenderMaterial.roughness, "roughness", speckleRenderMaterial.name);
|
||||
double opacity = ClampToUnitRange(speckleRenderMaterial.opacity, "opacity", speckleRenderMaterial.name);
|
||||
double metalness = ClampToUnitRange(speckleRenderMaterial.metalness, "metalness", speckleRenderMaterial.name);
|
||||
|
||||
var diffuse = System.Drawing.Color.FromArgb(speckleRenderMaterial.diffuse);
|
||||
double transparency = 1 - opacity;
|
||||
double smoothness = 1 - roughness;
|
||||
string matName = _revitUtils.RemoveInvalidChars($"{speckleRenderMaterial.name}");
|
||||
|
||||
var newMaterialId = Material.Create(document, matName);
|
||||
var revitMaterial = (Material)document.GetElement(newMaterialId);
|
||||
revitMaterial.Color = new Color(diffuse.R, diffuse.G, diffuse.B);
|
||||
revitMaterial.Transparency = (int)(transparency * 100);
|
||||
revitMaterial.Shininess = (int)(metalness * 128);
|
||||
revitMaterial.Smoothness = (int)(smoothness * 100);
|
||||
|
||||
return revitMaterial.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will bake render materials in the project document.
|
||||
/// Will bake render materials in the revit document.
|
||||
/// </summary>
|
||||
/// <param name="speckleRenderMaterialProxies"></param>
|
||||
/// <param name="baseLayerName"></param>
|
||||
/// <returns></returns>
|
||||
public Dictionary<string, ElementId> BakeMaterials(
|
||||
IReadOnlyCollection<RenderMaterialProxy> speckleRenderMaterialProxies
|
||||
IReadOnlyCollection<RenderMaterialProxy> speckleRenderMaterialProxies,
|
||||
string baseLayerName
|
||||
)
|
||||
{
|
||||
Dictionary<string, ElementId> objectIdAndMaterialIndexMap = new();
|
||||
var document = _converterSettings.Current.Document;
|
||||
|
||||
foreach (var proxy in speckleRenderMaterialProxies)
|
||||
{
|
||||
var speckleRenderMaterial = proxy.value;
|
||||
|
||||
try
|
||||
{
|
||||
ElementId materialIdToUse = BakeMaterial(proxy.value, document);
|
||||
// all values assumed to be on the 0 - 1 scale need to pass through this validation and logging (if assumption wrong)
|
||||
double roughness = ClampToUnitRange(speckleRenderMaterial.roughness, "roughness", speckleRenderMaterial.name);
|
||||
double opacity = ClampToUnitRange(speckleRenderMaterial.opacity, "opacity", speckleRenderMaterial.name);
|
||||
double metalness = ClampToUnitRange(speckleRenderMaterial.metalness, "metalness", speckleRenderMaterial.name);
|
||||
|
||||
var diffuse = System.Drawing.Color.FromArgb(speckleRenderMaterial.diffuse);
|
||||
double transparency = 1 - opacity;
|
||||
double smoothness = 1 - roughness;
|
||||
string materialId = speckleRenderMaterial.applicationId ?? speckleRenderMaterial.id.NotNull();
|
||||
string matName = _revitUtils.RemoveInvalidChars($"{speckleRenderMaterial.name}-({materialId})-{baseLayerName}");
|
||||
|
||||
var newMaterialId = Material.Create(_converterSettings.Current.Document, matName);
|
||||
var revitMaterial = (Material)_converterSettings.Current.Document.GetElement(newMaterialId);
|
||||
revitMaterial.Color = new Color(diffuse.R, diffuse.G, diffuse.B);
|
||||
revitMaterial.Transparency = (int)(transparency * 100);
|
||||
revitMaterial.Shininess = (int)(metalness * 128);
|
||||
revitMaterial.Smoothness = (int)(smoothness * 128);
|
||||
|
||||
foreach (var objectId in proxy.objects)
|
||||
{
|
||||
objectIdAndMaterialIndexMap[objectId] = materialIdToUse;
|
||||
objectIdAndMaterialIndexMap[objectId] = revitMaterial.Id;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
@@ -188,20 +157,27 @@ public class RevitMaterialBaker
|
||||
var validBaseGroupName = _revitUtils.RemoveInvalidChars(baseGroupName);
|
||||
var document = _converterSettings.Current.Document;
|
||||
|
||||
using var collector = new FilteredElementCollector(document);
|
||||
var materialIds = collector
|
||||
.OfClass(typeof(Material))
|
||||
.Where(m => m.Name.Contains(validBaseGroupName))
|
||||
.Select(m => m.Id)
|
||||
.ToList();
|
||||
using (var collector = new FilteredElementCollector(document))
|
||||
{
|
||||
var materialIds = collector
|
||||
.OfClass(typeof(Material))
|
||||
.Where(m => m.Name.Contains(validBaseGroupName))
|
||||
.Select(m => m.Id)
|
||||
.ToList();
|
||||
|
||||
document.Delete(materialIds);
|
||||
document.Delete(materialIds);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// After CNX-2661, we've seen some edge cases contradicting the expected 0 - 1 range for PRB properties.
|
||||
/// Defensively, we'd rather clamp these values than throw.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Created a method so that we can extend the checks to any numerical value potentially leading to a negative value,
|
||||
/// which would throw an exception. Generalised method since Math.Clamp() only available since C# 8.0 and this method
|
||||
/// handles logging (in the hope that we can get a better feel for these "weird" models, e.g. 0 - 100 scale??)
|
||||
/// </remarks>
|
||||
private double ClampToUnitRange(double value, string propertyName, string materialName)
|
||||
{
|
||||
if (value is < 0 or > 1)
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common.Objects;
|
||||
using Speckle.Converters.RevitShared.Settings;
|
||||
using Speckle.Objects.Other;
|
||||
using Speckle.Sdk;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// Utility class that creates View3D elements from Camera objects during receive.
|
||||
/// </summary>
|
||||
public class RevitViewBaker
|
||||
{
|
||||
private readonly IConverterSettingsStore<RevitConversionSettings> _converterSettings;
|
||||
private readonly ILogger<RevitViewBaker> _logger;
|
||||
private readonly ITypedConverter<Speckle.Objects.Geometry.Point, XYZ> _pointConverter;
|
||||
private readonly ITypedConverter<Speckle.Objects.Geometry.Vector, XYZ> _vectorConverter;
|
||||
|
||||
public RevitViewBaker(
|
||||
IConverterSettingsStore<RevitConversionSettings> converterSettings,
|
||||
ILogger<RevitViewBaker> logger,
|
||||
ITypedConverter<Speckle.Objects.Geometry.Point, XYZ> pointConverter,
|
||||
ITypedConverter<Speckle.Objects.Geometry.Vector, XYZ> vectorConverter
|
||||
)
|
||||
{
|
||||
_converterSettings = converterSettings;
|
||||
_logger = logger;
|
||||
_pointConverter = pointConverter;
|
||||
_vectorConverter = vectorConverter;
|
||||
}
|
||||
|
||||
// Characters that are not allowed in Revit view names
|
||||
private readonly char[] _invalidViewNameChars = ['{', '}', '[', ']', '|', ';', '<', '>', '?', '`', '~', '\\', ':'];
|
||||
|
||||
/// <summary>
|
||||
/// Bakes Camera objects as View3D elements in Revit.
|
||||
/// </summary>
|
||||
public void BakeViews(IReadOnlyCollection<Camera> cameras)
|
||||
{
|
||||
if (cameras.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var camera in cameras)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(camera.name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var restoredName = RestoreViewName(camera.name);
|
||||
if (string.IsNullOrWhiteSpace(restoredName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingView = FindViewByName(restoredName);
|
||||
|
||||
try
|
||||
{
|
||||
if (existingView != null)
|
||||
{
|
||||
UpdatePerspectiveView(existingView, camera);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatePerspectiveView(camera, restoredName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create view '{ViewName}'", restoredName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitizes the view name by removing invalid characters.
|
||||
/// </summary>
|
||||
private string RestoreViewName(string name)
|
||||
{
|
||||
var restored = name;
|
||||
|
||||
foreach (var c in _invalidViewNameChars)
|
||||
{
|
||||
restored = restored.Replace(c.ToString(), string.Empty);
|
||||
}
|
||||
|
||||
return restored.Trim();
|
||||
}
|
||||
|
||||
private View3D? FindViewByName(string name)
|
||||
{
|
||||
using var collector = new FilteredElementCollector(_converterSettings.Current.Document);
|
||||
return collector
|
||||
.OfClass(typeof(View3D))
|
||||
.Cast<View3D>()
|
||||
.FirstOrDefault(v => !v.IsTemplate && string.Equals(v.Name, name, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private void UpdatePerspectiveView(View3D view3D, Camera camera)
|
||||
{
|
||||
var eyePosition = _pointConverter.Convert(camera.position);
|
||||
var forwardDirection = _vectorConverter.Convert(camera.forward).Normalize();
|
||||
var upDirection = _vectorConverter.Convert(camera.up).Normalize();
|
||||
|
||||
var orientation = new ViewOrientation3D(eyePosition, upDirection, forwardDirection);
|
||||
view3D.SetOrientation(orientation);
|
||||
}
|
||||
|
||||
private void CreatePerspectiveView(Camera camera, string viewName)
|
||||
{
|
||||
var document = _converterSettings.Current.Document;
|
||||
|
||||
// Get ViewFamilyType for 3D views
|
||||
using var collector = new FilteredElementCollector(document);
|
||||
var viewFamilyType = collector
|
||||
.OfClass(typeof(ViewFamilyType))
|
||||
.Cast<ViewFamilyType>()
|
||||
.FirstOrDefault(vft => vft.ViewFamily == ViewFamily.ThreeDimensional);
|
||||
|
||||
if (viewFamilyType == null)
|
||||
{
|
||||
_logger.LogError("Could not find a 3D ViewFamilyType to create view '{ViewName}'", viewName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create perspective view (View3D is a document element, not disposable) - low happiness level
|
||||
#pragma warning disable CA2000
|
||||
var view3D = View3D.CreatePerspective(document, viewFamilyType.Id);
|
||||
#pragma warning restore CA2000
|
||||
|
||||
// Convert camera position, forward, and up vectors
|
||||
var eyePosition = _pointConverter.Convert(camera.position);
|
||||
var forwardDirection = _vectorConverter.Convert(camera.forward).Normalize();
|
||||
var upDirection = _vectorConverter.Convert(camera.up).Normalize();
|
||||
|
||||
var orientation = new ViewOrientation3D(eyePosition, upDirection, forwardDirection);
|
||||
view3D.SetOrientation(orientation);
|
||||
|
||||
view3D.Name = viewName;
|
||||
|
||||
// Set display style to Shaded (looks better than default wireframe)
|
||||
view3D.DisplayStyle = DisplayStyle.Shading;
|
||||
|
||||
// Disable far clipping so depth is infinite
|
||||
var farClipParam = view3D.get_Parameter(BuiltInParameter.VIEWER_BOUND_ACTIVE_FAR);
|
||||
if (farClipParam != null && !farClipParam.IsReadOnly)
|
||||
{
|
||||
farClipParam.Set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,6 @@ public static class SupportedCategoriesUtils
|
||||
#else
|
||||
category.Name == "OST_Grids";
|
||||
#endif
|
||||
case CategoryType.AnalyticalModel:
|
||||
return true;
|
||||
|
||||
case CategoryType.Model:
|
||||
return
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Speckle.Objects.Other;
|
||||
using Speckle.Sdk;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks Revit Views for sending
|
||||
/// </summary>
|
||||
|
||||
public class ViewUnpacker
|
||||
{
|
||||
private readonly ILogger<ViewUnpacker> _logger;
|
||||
private readonly Converters.Common.IRootToSpeckleConverter _rootToSpeckleConverter;
|
||||
|
||||
public ViewUnpacker(Converters.Common.IRootToSpeckleConverter rootToSpeckleConverter, ILogger<ViewUnpacker> logger)
|
||||
{
|
||||
_rootToSpeckleConverter = rootToSpeckleConverter;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private Camera? ConvertViewToCamera(View3D view)
|
||||
{
|
||||
try
|
||||
{
|
||||
var converted = (Camera)_rootToSpeckleConverter.Convert(view);
|
||||
if (converted is null)
|
||||
{
|
||||
_logger.LogError("Failed to create a view from {view}", view.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create a view from {view}", view.Name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through the 3D views in the provided document to create cameras
|
||||
/// </summary>
|
||||
/// <param name="doc">Document to retrieve 3D views from</param>
|
||||
/// <returns></returns>
|
||||
public List<Camera> Unpack(Document doc)
|
||||
{
|
||||
List<Camera> cameras = new();
|
||||
using FilteredElementCollector collector = new(doc);
|
||||
List<View> views = collector
|
||||
.WhereElementIsNotElementType()
|
||||
.OfCategory(BuiltInCategory.OST_Views)
|
||||
.Cast<View>()
|
||||
.Where(x => x.ViewType == ViewType.ThreeD)
|
||||
.ToList();
|
||||
|
||||
foreach (View view in views)
|
||||
{
|
||||
if (view is not View3D view3D)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// not supporting parallel project yet, since it is too complex to match in the viewer for now
|
||||
try
|
||||
{
|
||||
if (!view3D.IsPerspective)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Autodesk.Revit.Exceptions.InvalidOperationException)
|
||||
{
|
||||
continue; // some threed views will throw an exception: returns true if view is not a view template
|
||||
}
|
||||
|
||||
if (ConvertViewToCamera(view3D) is Camera camera)
|
||||
{
|
||||
cameras.Add(camera);
|
||||
}
|
||||
}
|
||||
|
||||
return cameras;
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Objects.Data;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public class DirectShapeUnpackStrategy : RevitUnpackStrategyBase
|
||||
{
|
||||
private readonly ILocalToGlobalUnpacker _localToGlobalUnpacker;
|
||||
|
||||
public DirectShapeUnpackStrategy(ILocalToGlobalUnpacker localToGlobalUnpacker)
|
||||
{
|
||||
_localToGlobalUnpacker = localToGlobalUnpacker;
|
||||
}
|
||||
|
||||
public override UnpackStrategyResult Unpack(RootObjectUnpackerResult unpackedRoot)
|
||||
{
|
||||
// 1. Build the parent map so we don't lose metadata
|
||||
var parentDataObjectMap = new Dictionary<string, DataObject>();
|
||||
PopulateParentDataObjectMap(unpackedRoot, parentDataObjectMap);
|
||||
|
||||
// 2. Flatten everything, including instances
|
||||
var maps = _localToGlobalUnpacker.Unpack(unpackedRoot.DefinitionProxies, unpackedRoot.ObjectsToConvert.ToList());
|
||||
|
||||
// 3. Filter out DataObjects to avoid converter crashes
|
||||
var cleanedMaps = FilterUnpackedDataObjects(maps);
|
||||
|
||||
return new UnpackStrategyResult(cleanedMaps, null, parentDataObjectMap);
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public class FamilyUnpackStrategy : RevitUnpackStrategyBase
|
||||
{
|
||||
private readonly ILocalToGlobalUnpacker _localToGlobalUnpacker;
|
||||
private readonly RootObjectUnpacker _rootObjectUnpacker;
|
||||
|
||||
public FamilyUnpackStrategy(ILocalToGlobalUnpacker localToGlobalUnpacker, RootObjectUnpacker rootObjectUnpacker)
|
||||
{
|
||||
_localToGlobalUnpacker = localToGlobalUnpacker;
|
||||
_rootObjectUnpacker = rootObjectUnpacker;
|
||||
}
|
||||
|
||||
public override UnpackStrategyResult Unpack(RootObjectUnpackerResult unpackedRoot)
|
||||
{
|
||||
var parentDataObjectMap = new Dictionary<string, DataObject>();
|
||||
var displayValueDefinitionIds = new HashSet<string>();
|
||||
|
||||
// 1. Build parent maps and identify definitions used purely for DataObject display values
|
||||
PopulateParentDataObjectMap(unpackedRoot, parentDataObjectMap, displayValueDefinitionIds);
|
||||
|
||||
// 2. Split out standard atomic objects from instance components
|
||||
var (atomicObjects, instanceComponents) = _rootObjectUnpacker.SplitAtomicObjectsAndInstances(
|
||||
unpackedRoot.ObjectsToConvert
|
||||
);
|
||||
|
||||
// 3. Collect true definition geometries to filter out
|
||||
var consumedObjectIds = new HashSet<string>();
|
||||
if (unpackedRoot.DefinitionProxies != null)
|
||||
{
|
||||
foreach (var dp in unpackedRoot.DefinitionProxies)
|
||||
{
|
||||
var defId = dp.applicationId ?? dp.id.NotNull();
|
||||
if (!displayValueDefinitionIds.Contains(defId) && (dp.id == null || !displayValueDefinitionIds.Contains(dp.id)))
|
||||
{
|
||||
foreach (var objId in dp.objects)
|
||||
{
|
||||
consumedObjectIds.Add(objId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Filter out consumed objects
|
||||
var filteredAtomicObjects = atomicObjects
|
||||
.Where(tc =>
|
||||
{
|
||||
var appId = tc.Current.applicationId;
|
||||
var id = tc.Current.id;
|
||||
return (appId == null || !consumedObjectIds.Contains(appId)) && (id == null || !consumedObjectIds.Contains(id));
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 5. Prepare true Family instances (ignore the display value proxies)
|
||||
var instanceComponentsWithPath = instanceComponents
|
||||
.Where(tc => tc.Current is not InstanceProxy proxy || !displayValueDefinitionIds.Contains(proxy.definitionId))
|
||||
.Select(tc => (Array.Empty<Collection>(), tc.Current as IInstanceComponent))
|
||||
.Where(x => x.Item2 != null)
|
||||
.Select(x => (x.Item1, x.Item2!))
|
||||
.ToList();
|
||||
|
||||
// 6. Add true definition proxies
|
||||
if (unpackedRoot.DefinitionProxies != null)
|
||||
{
|
||||
var definitions = unpackedRoot
|
||||
.DefinitionProxies.Where(proxy =>
|
||||
{
|
||||
var defId = proxy.applicationId ?? proxy.id.NotNull();
|
||||
return !displayValueDefinitionIds.Contains(defId)
|
||||
&& (proxy.id == null || !displayValueDefinitionIds.Contains(proxy.id));
|
||||
})
|
||||
.Select(proxy => (Array.Empty<Collection>(), proxy as IInstanceComponent));
|
||||
|
||||
instanceComponentsWithPath.AddRange(definitions);
|
||||
}
|
||||
|
||||
// 7. Flatten surviving atomic objects
|
||||
var localToGlobalMaps = _localToGlobalUnpacker.Unpack(unpackedRoot.DefinitionProxies, filteredAtomicObjects);
|
||||
|
||||
// 8. Clean out DataObjects using the shared base logic!
|
||||
var cleanedMaps = FilterUnpackedDataObjects(localToGlobalMaps);
|
||||
|
||||
return new UnpackStrategyResult(cleanedMaps, instanceComponentsWithPath, parentDataObjectMap);
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public record UnpackStrategyResult(
|
||||
IReadOnlyCollection<LocalToGlobalMap> LocalToGlobalMaps,
|
||||
List<(Collection[] path, IInstanceComponent component)>? InstanceComponents,
|
||||
Dictionary<string, DataObject> ParentDataObjectMap
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the strategy for unpacking a commit into bakeable Revit objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Depending on the setting, we either blindly flatten everything into DirectShapes, or we carefully
|
||||
/// split out instance components to bake as native Revit Families.
|
||||
/// </remarks>
|
||||
public interface IRevitUnpackStrategy
|
||||
{
|
||||
UnpackStrategyResult Unpack(RootObjectUnpackerResult unpackedRoot);
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
using Speckle.Connectors.DUI.Settings;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public class ReceiveInstancesAsFamiliesSetting(bool value = ReceiveInstancesAsFamiliesSetting.DEFAULT_VALUE)
|
||||
: ICardSetting
|
||||
{
|
||||
public const string SETTING_ID = "receiveInstancesAsFamiliesSetting";
|
||||
public const bool DEFAULT_VALUE = false;
|
||||
|
||||
public string? Id { get; set; } = SETTING_ID;
|
||||
public string? Title { get; set; } = "Receive Blocks as Families";
|
||||
public string? Type { get; set; } = "boolean";
|
||||
public object? Value { get; set; } = value;
|
||||
public List<string>? Enum { get; set; }
|
||||
}
|
||||
+100
-124
@@ -13,17 +13,15 @@ using Speckle.Converters.RevitShared;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Converters.RevitShared.Settings;
|
||||
using Speckle.DoubleNumerics;
|
||||
using Speckle.Objects;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Objects.Geometry;
|
||||
using Speckle.Objects.Other;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Common.Exceptions;
|
||||
using Speckle.Sdk.Logging;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Speckle.Sdk.Models.GraphTraversal;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
using Transform = Speckle.Objects.Other.Transform;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
@@ -32,6 +30,7 @@ public sealed class RevitHostObjectBuilder(
|
||||
IConverterSettingsStore<RevitConversionSettings> converterSettings,
|
||||
ITransactionManager transactionManager,
|
||||
ISdkActivityFactory activityFactory,
|
||||
ILocalToGlobalUnpacker localToGlobalUnpacker,
|
||||
RevitGroupBaker groupManager,
|
||||
RevitMaterialBaker materialBaker,
|
||||
RootObjectUnpacker rootObjectUnpacker,
|
||||
@@ -39,14 +38,10 @@ public sealed class RevitHostObjectBuilder(
|
||||
IThreadContext threadContext,
|
||||
RevitToHostCacheSingleton revitToHostCacheSingleton,
|
||||
ITypedConverter<
|
||||
(Base atomicObject, IReadOnlyCollection<Matrix4x4> matrix, DataObject? parentDataObject),
|
||||
(Base atomicObject, IReadOnlyCollection<Matrix4x4> matrix),
|
||||
DirectShape
|
||||
> localToGlobalDirectShapeConverter,
|
||||
IReceiveConversionHandler conversionHandler,
|
||||
RevitFamilyBaker familyBaker,
|
||||
DirectShapeUnpackStrategy directShapeUnpackStrategy,
|
||||
FamilyUnpackStrategy familyUnpackStrategy,
|
||||
RevitPreBakeSetupService preBakeSetupService
|
||||
IReceiveConversionHandler conversionHandler
|
||||
) : IHostObjectBuilder, IDisposable
|
||||
{
|
||||
public Task<HostObjectBuilderResult> Build(
|
||||
@@ -102,18 +97,99 @@ public sealed class RevitHostObjectBuilder(
|
||||
|
||||
// 1 - Unpack objects and proxies from root commit object
|
||||
var unpackedRoot = rootObjectUnpacker.Unpack(rootObject);
|
||||
var localToGlobalMaps = localToGlobalUnpacker.Unpack(
|
||||
unpackedRoot.DefinitionProxies,
|
||||
unpackedRoot.ObjectsToConvert.ToList()
|
||||
);
|
||||
|
||||
// 2 - Determine conversion path based on setting
|
||||
var receiveInstancesAsFamilies = converterSettings.Current.ReceiveInstancesAsFamilies;
|
||||
IRevitUnpackStrategy unpackStrategy = receiveInstancesAsFamilies ? familyUnpackStrategy : directShapeUnpackStrategy;
|
||||
// NOTE: below is 💩... https://github.com/specklesystems/speckle-sharp-connectors/pull/813 broke sketchup to revit workflow
|
||||
// ids were modified to fix receiving instances [CNX-1707](https://linear.app/speckle/issue/CNX-1707/revit-curves-and-meshes-in-blocks-come-as-duplicated)
|
||||
// but we then broke sketchup to revit because applicationIds in proxies didn't match modified application ids which cam from #813 hack
|
||||
// given urgency to get sketchup to revit workflow back up and running, temp fix involves setting modified ids before material baking, mapping original app ids to modified ids and using those
|
||||
// this way, CNX-1707 fix stays in tact and we fix sketchup to revit
|
||||
// TODO: TransformTo and material baking needs to be fixed in Revit!!
|
||||
|
||||
// 3 - Split objects/Flatten objects based on strategy
|
||||
var unpackResult = unpackStrategy.Unpack(unpackedRoot);
|
||||
// create a mapping from original to modified IDs <- so that we can actually map ids in the proxies to the objects
|
||||
// as part of CNX-2677, we have a one-to-many problem. many instances share the same reference, so we use a list
|
||||
Dictionary<string, List<string>> originalToModifiedIds = new();
|
||||
|
||||
// 4 - Apply ID modifications and bake materials
|
||||
preBakeSetupService.ApplyIdModificationsAndBakeMaterials(unpackResult, unpackedRoot);
|
||||
// modify application IDs BEFORE material baking
|
||||
foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps)
|
||||
{
|
||||
if (
|
||||
localToGlobalMap.AtomicObject is ITransformable transformable
|
||||
&& localToGlobalMap.Matrix.Count > 0
|
||||
&& localToGlobalMap.AtomicObject["units"] is string units
|
||||
)
|
||||
{
|
||||
var id = localToGlobalMap.AtomicObject.id;
|
||||
var originalAppId = localToGlobalMap.AtomicObject.applicationId ?? id;
|
||||
|
||||
// 5 - Bake objects
|
||||
// Apply transformations...
|
||||
ITransformable? newTransformable = null;
|
||||
foreach (var mat in localToGlobalMap.Matrix)
|
||||
{
|
||||
transformable.TransformTo(new Transform() { matrix = mat, units = units }, out newTransformable);
|
||||
transformable = newTransformable;
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject = (newTransformable as Base)!;
|
||||
localToGlobalMap.AtomicObject.id = id;
|
||||
|
||||
// create modified ID and store mapping <- fixes CNX-1707 but causes us material mapping headache!!!
|
||||
string modifiedAppId = $"{originalAppId}_{Guid.NewGuid().ToString("N")[..8]}";
|
||||
if (originalAppId != null)
|
||||
{
|
||||
if (!originalToModifiedIds.TryGetValue(originalAppId, out List<string>? modifiedIds))
|
||||
{
|
||||
modifiedIds = new List<string>();
|
||||
originalToModifiedIds[originalAppId] = modifiedIds;
|
||||
}
|
||||
|
||||
modifiedIds.Add(modifiedAppId);
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject.applicationId = modifiedAppId;
|
||||
localToGlobalMap.Matrix = new HashSet<Matrix4x4>();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the RenderMaterialProxies with the "new" (aka hacked) application IDs
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
foreach (var proxy in unpackedRoot.RenderMaterialProxies)
|
||||
{
|
||||
var objectIdsToUse = new List<string>();
|
||||
foreach (var objectId in proxy.objects)
|
||||
{
|
||||
// Use the modified ID if it exists, otherwise keep the original <- this SUCKS and we need to change
|
||||
if (originalToModifiedIds.TryGetValue(objectId, out var modifiedIds))
|
||||
{
|
||||
objectIdsToUse.AddRange(modifiedIds);
|
||||
}
|
||||
else
|
||||
{
|
||||
objectIdsToUse.Add(objectId);
|
||||
}
|
||||
}
|
||||
proxy.objects = objectIdsToUse;
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - Bake materials (now with the updated IDs)
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
transactionManager.StartTransaction(true, "Baking materials");
|
||||
materialBaker.MapLayersRenderMaterials(unpackedRoot);
|
||||
var map = materialBaker.BakeMaterials(unpackedRoot.RenderMaterialProxies, baseGroupName);
|
||||
foreach (var kvp in map)
|
||||
{
|
||||
revitToHostCacheSingleton.MaterialsByObjectId.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
transactionManager.CommitTransaction();
|
||||
}
|
||||
|
||||
// 3 - Bake objects
|
||||
(
|
||||
HostObjectBuilderResult builderResult,
|
||||
List<(DirectShape res, string applicationId)> postBakePaintTargets
|
||||
@@ -134,52 +210,12 @@ public sealed class RevitHostObjectBuilder(
|
||||
)
|
||||
)
|
||||
{
|
||||
conversionResults = BakeObjects(
|
||||
unpackResult.LocalToGlobalMaps,
|
||||
unpackResult.ParentDataObjectMap,
|
||||
onOperationProgressed,
|
||||
cancellationToken
|
||||
);
|
||||
conversionResults = BakeObjects(localToGlobalMaps, onOperationProgressed, cancellationToken);
|
||||
}
|
||||
|
||||
transactionManager.CommitTransaction();
|
||||
}
|
||||
|
||||
// Bakes instances as families (if setting is enabled Count > 0)
|
||||
if (receiveInstancesAsFamilies && unpackResult.InstanceComponents is { Count: > 0 })
|
||||
{
|
||||
var speckleObjectLookup = new Dictionary<string, TraversalContext>();
|
||||
foreach (var tc in unpackedRoot.ObjectsToConvert)
|
||||
{
|
||||
var obj = tc.Current;
|
||||
|
||||
// 1. Primary Index: our Hash
|
||||
// TODO: investigate. this should never be null? but i (Björn) had some weird edge-cases
|
||||
if (!string.IsNullOrEmpty(obj.id))
|
||||
{
|
||||
speckleObjectLookup[obj.id.NotNullOrWhiteSpace()] = tc;
|
||||
}
|
||||
|
||||
// 2. Secondary Index: Application ID (kinda fallback)
|
||||
if (!string.IsNullOrEmpty(obj.applicationId))
|
||||
{
|
||||
speckleObjectLookup[obj.applicationId.NotNullOrWhiteSpace()] = tc;
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the unpacked material proxies down to the family baker, defaulting to empty if null
|
||||
var materialProxies = unpackedRoot.RenderMaterialProxies ?? [];
|
||||
|
||||
conversionResults = BakeInstancesAsFamilies(
|
||||
unpackResult.InstanceComponents,
|
||||
conversionResults,
|
||||
speckleObjectLookup,
|
||||
materialProxies,
|
||||
onOperationProgressed
|
||||
);
|
||||
}
|
||||
|
||||
// 6 - Paint solids
|
||||
// 4 - Paint solids
|
||||
{
|
||||
using var _ = activityFactory.Start("Painting solids");
|
||||
transactionManager.StartTransaction(true, "Painting solids");
|
||||
@@ -187,7 +223,7 @@ public sealed class RevitHostObjectBuilder(
|
||||
transactionManager.CommitTransaction();
|
||||
}
|
||||
|
||||
// 7 - Create group
|
||||
// 5 - Create group
|
||||
{
|
||||
using var _ = activityFactory.Start("Grouping");
|
||||
transactionManager.StartTransaction(true, "Grouping");
|
||||
@@ -198,55 +234,6 @@ public sealed class RevitHostObjectBuilder(
|
||||
return conversionResults.builderResult;
|
||||
}
|
||||
|
||||
private (
|
||||
HostObjectBuilderResult builderResult,
|
||||
List<(DirectShape res, string applicationId)> postBakePaintTargets
|
||||
) BakeInstancesAsFamilies(
|
||||
List<(Collection[] path, IInstanceComponent component)> instanceComponents,
|
||||
(
|
||||
HostObjectBuilderResult builderResult,
|
||||
List<(DirectShape res, string applicationId)> postBakePaintTargets
|
||||
) currentResults,
|
||||
Dictionary<string, TraversalContext> speckleObjectLookup,
|
||||
IReadOnlyCollection<RenderMaterialProxy> materialProxies,
|
||||
IProgress<CardProgress> onOperationProgressed
|
||||
)
|
||||
{
|
||||
using var _ = activityFactory.Start("Creating families");
|
||||
transactionManager.StartTransaction(true, "Creating families");
|
||||
|
||||
(List<ReceiveConversionResult> familyResults, List<string> familyElementIds) = familyBaker.BakeInstances(
|
||||
instanceComponents,
|
||||
speckleObjectLookup,
|
||||
materialProxies,
|
||||
onOperationProgressed
|
||||
);
|
||||
|
||||
// Merge results
|
||||
var mergedConversionResults = currentResults.builderResult.ConversionResults.ToList();
|
||||
mergedConversionResults.AddRange(familyResults);
|
||||
|
||||
var mergedBakedObjectIds = currentResults.builderResult.BakedObjectIds.ToList();
|
||||
mergedBakedObjectIds.AddRange(familyElementIds);
|
||||
|
||||
// Add created elements to group
|
||||
foreach (var elementId in familyElementIds)
|
||||
{
|
||||
var element = converterSettings.Current.Document.GetElement(elementId);
|
||||
if (element != null)
|
||||
{
|
||||
groupManager.AddToTopLevelGroup(element);
|
||||
}
|
||||
}
|
||||
|
||||
transactionManager.CommitTransaction();
|
||||
|
||||
return (
|
||||
new HostObjectBuilderResult(mergedBakedObjectIds, mergedConversionResults),
|
||||
currentResults.postBakePaintTargets
|
||||
);
|
||||
}
|
||||
|
||||
private Autodesk.Revit.DB.Transform? CalculateNewTransform(
|
||||
Autodesk.Revit.DB.Transform? receiveTransform,
|
||||
Autodesk.Revit.DB.Transform? rootTransform
|
||||
@@ -270,7 +257,6 @@ public sealed class RevitHostObjectBuilder(
|
||||
List<(DirectShape res, string applicationId)> postBakePaintTargets
|
||||
) BakeObjects(
|
||||
IReadOnlyCollection<LocalToGlobalMap> localToGlobalMaps,
|
||||
Dictionary<string, DataObject> parentDataObjectMap,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
@@ -292,17 +278,9 @@ public sealed class RevitHostObjectBuilder(
|
||||
onOperationProgressed.Report(new("Converting", (double)++count / localToGlobalMaps.Count));
|
||||
if (result is DirectShapeDefinitionWrapper)
|
||||
{
|
||||
// Look up parent DataObject for this atomic object (handles InstanceProxy displayValue)
|
||||
var atomicId = localToGlobalMap.AtomicObject.applicationId;
|
||||
DataObject? parentDataObject = null;
|
||||
if (atomicId is not null)
|
||||
{
|
||||
parentDataObjectMap.TryGetValue(atomicId, out parentDataObject);
|
||||
}
|
||||
|
||||
// direct shape creation happens here
|
||||
DirectShape directShapes = localToGlobalDirectShapeConverter.Convert(
|
||||
(localToGlobalMap.AtomicObject, localToGlobalMap.Matrix, parentDataObject)
|
||||
(localToGlobalMap.AtomicObject, localToGlobalMap.Matrix)
|
||||
);
|
||||
|
||||
bakedObjectIds.Add(directShapes.UniqueId);
|
||||
@@ -331,7 +309,6 @@ public sealed class RevitHostObjectBuilder(
|
||||
conversionResults.Add(new(Status.ERROR, localToGlobalMap.AtomicObject, null, null, ex));
|
||||
}
|
||||
}
|
||||
|
||||
return (new(bakedObjectIds, conversionResults), postBakePaintTargets);
|
||||
}
|
||||
|
||||
@@ -373,12 +350,12 @@ public sealed class RevitHostObjectBuilder(
|
||||
{
|
||||
DirectShapeLibrary.GetDirectShapeLibrary(converterSettings.Current.Document).Reset(); // Note: this needs to be cleared, as it is being used in the converter
|
||||
|
||||
revitToHostCacheSingleton.Clear(); // "Massive hack!" - Anonymous. Ogu and Björn: it looks legit
|
||||
revitToHostCacheSingleton.MaterialsByObjectId.Clear(); // Massive hack!
|
||||
groupManager.PurgeGroups(baseGroupName);
|
||||
materialBaker.PurgeMaterials(baseGroupName);
|
||||
}
|
||||
|
||||
public void Dispose() => transactionManager.Dispose();
|
||||
public void Dispose() => transactionManager?.Dispose();
|
||||
|
||||
// NOTE: temp poc HACK!
|
||||
// this hack only works if we are only assuming one material applied to the solids inside DataObject displayValue. as soon as we have multiple solids with multiple materials it will break again.
|
||||
@@ -396,7 +373,6 @@ public sealed class RevitHostObjectBuilder(
|
||||
{
|
||||
SetSolidPostBakePaintTargets(item, directShapes, targets);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Connectors.Revit.HostApp;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.DoubleNumerics;
|
||||
using Speckle.Objects;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Sdk.Models;
|
||||
using Transform = Speckle.Objects.Other.Transform;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public class RevitPreBakeSetupService
|
||||
{
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
private readonly RevitMaterialBaker _materialBaker;
|
||||
private readonly RevitViewBaker _viewBaker;
|
||||
private readonly RevitToHostCacheSingleton _revitToHostCacheSingleton;
|
||||
|
||||
public RevitPreBakeSetupService(
|
||||
ITransactionManager transactionManager,
|
||||
RevitMaterialBaker materialBaker,
|
||||
RevitViewBaker viewBaker,
|
||||
RevitToHostCacheSingleton revitToHostCacheSingleton
|
||||
)
|
||||
{
|
||||
_transactionManager = transactionManager;
|
||||
_materialBaker = materialBaker;
|
||||
_viewBaker = viewBaker;
|
||||
_revitToHostCacheSingleton = revitToHostCacheSingleton;
|
||||
}
|
||||
|
||||
public void ApplyIdModificationsAndBakeMaterials(
|
||||
UnpackStrategyResult unpackResult,
|
||||
RootObjectUnpackerResult unpackedRoot
|
||||
)
|
||||
{
|
||||
Dictionary<string, List<string>> originalToModifiedIds = new();
|
||||
|
||||
foreach (LocalToGlobalMap localToGlobalMap in unpackResult.LocalToGlobalMaps)
|
||||
{
|
||||
if (
|
||||
localToGlobalMap.AtomicObject is ITransformable transformable
|
||||
&& localToGlobalMap.Matrix.Count > 0
|
||||
&& localToGlobalMap.AtomicObject["units"] is string units
|
||||
)
|
||||
{
|
||||
var id = localToGlobalMap.AtomicObject.id;
|
||||
var originalAppId = localToGlobalMap.AtomicObject.applicationId ?? id;
|
||||
|
||||
ITransformable? newTransformable = null;
|
||||
foreach (var mat in localToGlobalMap.Matrix)
|
||||
{
|
||||
transformable.TransformTo(new Transform() { matrix = mat, units = units }, out newTransformable);
|
||||
transformable = newTransformable;
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject = (newTransformable as Base)!;
|
||||
localToGlobalMap.AtomicObject.id = id;
|
||||
|
||||
string modifiedAppId = $"{originalAppId}_{Guid.NewGuid().ToString("N")[..8]}";
|
||||
if (originalAppId != null)
|
||||
{
|
||||
if (!originalToModifiedIds.TryGetValue(originalAppId, out List<string>? modifiedIds))
|
||||
{
|
||||
modifiedIds = new List<string>();
|
||||
originalToModifiedIds[originalAppId] = modifiedIds;
|
||||
}
|
||||
modifiedIds.Add(modifiedAppId);
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject.applicationId = modifiedAppId;
|
||||
localToGlobalMap.Matrix = new HashSet<Matrix4x4>();
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
foreach (var proxy in unpackedRoot.RenderMaterialProxies)
|
||||
{
|
||||
var objectIdsToUse = new List<string>();
|
||||
foreach (var objectId in proxy.objects)
|
||||
{
|
||||
if (originalToModifiedIds.TryGetValue(objectId, out var modifiedIds))
|
||||
{
|
||||
objectIdsToUse.AddRange(modifiedIds);
|
||||
}
|
||||
else
|
||||
{
|
||||
objectIdsToUse.Add(objectId);
|
||||
}
|
||||
}
|
||||
proxy.objects = objectIdsToUse;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAtomicObjectLookupWithModifiedIds(unpackResult.ParentDataObjectMap, originalToModifiedIds);
|
||||
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
_transactionManager.StartTransaction(true, "Baking materials");
|
||||
_materialBaker.MapLayersRenderMaterials(unpackedRoot);
|
||||
var map = _materialBaker.BakeMaterials(unpackedRoot.RenderMaterialProxies);
|
||||
foreach (var kvp in map)
|
||||
{
|
||||
_revitToHostCacheSingleton.MaterialsByObjectId.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
_transactionManager.CommitTransaction();
|
||||
}
|
||||
|
||||
if (unpackedRoot.Cameras is not null)
|
||||
{
|
||||
_transactionManager.StartTransaction(true, "Baking views");
|
||||
_viewBaker.BakeViews(unpackedRoot.Cameras);
|
||||
_transactionManager.CommitTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAtomicObjectLookupWithModifiedIds(
|
||||
Dictionary<string, DataObject> map,
|
||||
Dictionary<string, List<string>> originalToModifiedIds
|
||||
)
|
||||
{
|
||||
var entriesToAdd = new List<KeyValuePair<string, DataObject>>();
|
||||
var keysToRemove = new List<string>();
|
||||
|
||||
foreach (var kvp in map)
|
||||
{
|
||||
if (originalToModifiedIds.TryGetValue(kvp.Key, out var modifiedIds))
|
||||
{
|
||||
keysToRemove.Add(kvp.Key);
|
||||
foreach (var modifiedId in modifiedIds)
|
||||
{
|
||||
entriesToAdd.Add(new KeyValuePair<string, DataObject>(modifiedId, kvp.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var key in keysToRemove)
|
||||
{
|
||||
map.Remove(key);
|
||||
}
|
||||
|
||||
foreach (var entry in entriesToAdd)
|
||||
{
|
||||
map[entry.Key] = entry.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
using Speckle.Connectors.Common.Instances;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Sdk.Common;
|
||||
using Speckle.Sdk.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public abstract class RevitUnpackStrategyBase : IRevitUnpackStrategy
|
||||
{
|
||||
public abstract UnpackStrategyResult Unpack(RootObjectUnpackerResult unpackedRoot);
|
||||
|
||||
/// <summary>
|
||||
/// Builds a map of definition IDs and geometry IDs to their parent DataObject to preserve metadata.
|
||||
/// </summary>
|
||||
protected void PopulateParentDataObjectMap(
|
||||
RootObjectUnpackerResult unpackedRoot,
|
||||
Dictionary<string, DataObject> map,
|
||||
HashSet<string>? displayValueDefinitionIds = null
|
||||
)
|
||||
{
|
||||
var definitionToDataObject = new Dictionary<string, DataObject>();
|
||||
|
||||
foreach (var tc in unpackedRoot.ObjectsToConvert)
|
||||
{
|
||||
if (tc.Current is DataObject dataObject)
|
||||
{
|
||||
var instanceProxies = dataObject.displayValue.OfType<InstanceProxy>().ToList();
|
||||
if (instanceProxies.Count > 0)
|
||||
{
|
||||
foreach (var ip in instanceProxies)
|
||||
{
|
||||
definitionToDataObject[ip.definitionId] = dataObject;
|
||||
displayValueDefinitionIds?.Add(ip.definitionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackedRoot.DefinitionProxies is not null)
|
||||
{
|
||||
foreach (var defProxy in unpackedRoot.DefinitionProxies)
|
||||
{
|
||||
var defId = defProxy.applicationId ?? defProxy.id.NotNull();
|
||||
if (
|
||||
definitionToDataObject.TryGetValue(defId, out var parentDataObject)
|
||||
|| (defProxy.id != null && definitionToDataObject.TryGetValue(defProxy.id, out parentDataObject))
|
||||
)
|
||||
{
|
||||
foreach (var objectId in defProxy.objects)
|
||||
{
|
||||
map[objectId] = parentDataObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes DataObjects that use InstanceProxies as display values from the map list.
|
||||
/// Their geometries are already flattened, and this prevents the geometry converter from crashing.
|
||||
/// </summary>
|
||||
protected IReadOnlyCollection<LocalToGlobalMap> FilterUnpackedDataObjects(
|
||||
IReadOnlyCollection<LocalToGlobalMap> maps
|
||||
) =>
|
||||
maps.Where(map =>
|
||||
{
|
||||
if (map.AtomicObject is DataObject dataObject && dataObject.displayValue.Any(dv => dv is InstanceProxy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
-19
@@ -50,25 +50,6 @@ public class ToHostSettingsManager : IToHostSettingsManager
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool GetReceiveInstancesAsFamiliesSetting(ModelCard modelCard)
|
||||
{
|
||||
var settingValue =
|
||||
modelCard.Settings?.FirstOrDefault(s => s.Id == ReceiveInstancesAsFamiliesSetting.SETTING_ID)?.Value as bool?;
|
||||
|
||||
if (settingValue is not null)
|
||||
{
|
||||
return settingValue.Value;
|
||||
}
|
||||
|
||||
_logger.LogWarning(
|
||||
"Receive instances as families setting was null for model {ModelCardId}, using default: {DefaultValue}",
|
||||
modelCard.ModelCardId,
|
||||
ReceiveInstancesAsFamiliesSetting.DEFAULT_VALUE
|
||||
);
|
||||
|
||||
return ReceiveInstancesAsFamiliesSetting.DEFAULT_VALUE;
|
||||
}
|
||||
|
||||
private Transform? GetTransform(ReceiveReferencePointType referencePointType)
|
||||
{
|
||||
Transform? referencePointTransform = null;
|
||||
|
||||
+1
-5
@@ -81,11 +81,7 @@ public class RevitCategoriesFilter : DiscriminatedObject, ISendFilter, IRevitSen
|
||||
|
||||
foreach (Category category in _doc.Settings.Categories)
|
||||
{
|
||||
if (SupportedCategoriesUtils.IsSupportedCategory(category)
|
||||
#if REVIT2023_OR_GREATER
|
||||
&& category.BuiltInCategory != BuiltInCategory.INVALID
|
||||
#endif
|
||||
)
|
||||
if (SupportedCategoriesUtils.IsSupportedCategory(category))
|
||||
{
|
||||
categories.Add(new CategoryData(category.Name, category.Id.ToString()));
|
||||
}
|
||||
|
||||
+5
-21
@@ -82,10 +82,11 @@ public class RevitViewsFilter : DiscriminatedObject, ISendFilter, IRevitSendFilt
|
||||
|
||||
IEnumerable<Element> elementsInView = GetFilteredElementsForView(document, view);
|
||||
|
||||
// Filter out wall sweep/reveal sub-elements with empty names to avoid duplicates (CNX-1482).
|
||||
// Only these specific categories are excluded — other unnamed elements like steel connections
|
||||
// must be kept (CNX-3130).
|
||||
var objectIds = elementsInView.Where(e => !IsEmptyNameWallSubElement(e)).Select(e => e.UniqueId).ToList();
|
||||
// NOTE: FilteredElementCollector() includes sweeps and reveals from a wall family's definition and includes them as additional objects
|
||||
// on this return. displayValue for Wall already includes these, therefore we end up with duplicate elements on wall sweeps
|
||||
// related to [CNX-1482](https://linear.app/speckle/issue/CNX-1482/wall-sweeps-published-duplicated)
|
||||
// i (björn) noticed that all these elements have an empty string as Name parameter, hence below exclusion. tested as much as possible, seems like legit fix
|
||||
var objectIds = elementsInView.Where(e => !string.IsNullOrEmpty(e.Name)).Select(e => e.UniqueId).ToList();
|
||||
// we need the view uniqueId among the objectIds
|
||||
// to expire the modelCards with viewFilters when the user changes category visibility
|
||||
// a change in category visibility will trigger DocChangeHandler in RevitSendBinding
|
||||
@@ -175,21 +176,4 @@ public class RevitViewsFilter : DiscriminatedObject, ISendFilter, IRevitSendFilt
|
||||
|
||||
return allElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detects wall sweep/reveal sub-elements that have empty names when returned by the
|
||||
/// view-scoped FilteredElementCollector. These are duplicates of geometry already included
|
||||
/// in the parent wall's displayValue.
|
||||
/// See <a href="https://linear.app/speckle/issue/CNX-1482">CNX-1482</a>.
|
||||
/// </summary>
|
||||
private static bool IsEmptyNameWallSubElement(Element e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var bic = e.Category?.GetBuiltInCategory();
|
||||
return bic is BuiltInCategory.OST_Cornices or BuiltInCategory.OST_Reveals;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-22
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Autodesk.Revit.DB;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Speckle.Connectors.Common.Builders;
|
||||
@@ -8,7 +7,6 @@ using Speckle.Connectors.Common.Extensions;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Threading;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Connectors.DUI.Settings;
|
||||
using Speckle.Connectors.Revit.HostApp;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
@@ -26,13 +24,11 @@ public class RevitRootObjectBuilder(
|
||||
ISendConversionCache sendConversionCache,
|
||||
ElementUnpacker elementUnpacker,
|
||||
LevelUnpacker levelUnpacker,
|
||||
ViewUnpacker viewUnpacker,
|
||||
IThreadContext threadContext,
|
||||
SendCollectionManager sendCollectionManager,
|
||||
ILogger<RevitRootObjectBuilder> logger,
|
||||
RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton,
|
||||
LinkedModelHandler linkedModelHandler,
|
||||
IConfigStore configStore
|
||||
LinkedModelHandler linkedModelHandler
|
||||
) : IRootObjectBuilder<DocumentToConvert>
|
||||
{
|
||||
public Task<RootObjectBuilderResult> Build(
|
||||
@@ -45,7 +41,6 @@ public class RevitRootObjectBuilder(
|
||||
() => Task.FromResult(BuildSync(documentElementContexts, projectId, onOperationProgressed, ct))
|
||||
);
|
||||
|
||||
[SuppressMessage("Maintainability", "CA1506:Avoid excessive class coupling")]
|
||||
private RootObjectBuilderResult BuildSync(
|
||||
IReadOnlyList<DocumentToConvert> documentElementContexts,
|
||||
string projectId,
|
||||
@@ -138,8 +133,6 @@ public class RevitRootObjectBuilder(
|
||||
var cacheHitCount = 0;
|
||||
var skippedObjectCount = 0;
|
||||
|
||||
var config = configStore.GetConnectorConfig();
|
||||
|
||||
foreach (var atomicObjectByDocumentAndTransform in atomicObjectsByDocumentAndTransform)
|
||||
{
|
||||
string? modelDisplayName = null;
|
||||
@@ -191,11 +184,7 @@ public class RevitRootObjectBuilder(
|
||||
// TODO: Potential here to transform cached objects and NOT reconvert,
|
||||
// TODO: we wont do !hasTransform here, and re-set application id before this
|
||||
|
||||
if (
|
||||
!hasTransform
|
||||
&& !config.DocumentChangeListeningDisabled //This is experimental
|
||||
&& sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value)
|
||||
)
|
||||
if (!hasTransform && sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
|
||||
{
|
||||
converted = value;
|
||||
cacheHitCount++;
|
||||
@@ -251,7 +240,6 @@ public class RevitRootObjectBuilder(
|
||||
throw new SpeckleException("Failed to convert all objects.");
|
||||
}
|
||||
|
||||
// STEP 5: Unpack proxies to attach to root collection
|
||||
var flatElements = atomicObjectsByDocumentAndTransform.SelectMany(t => t.Elements).ToList();
|
||||
var idsAndSubElementIds = elementUnpacker.GetElementsAndSubelementIdsFromAtomicObjects(flatElements);
|
||||
|
||||
@@ -268,17 +256,10 @@ public class RevitRootObjectBuilder(
|
||||
new Collection()
|
||||
{
|
||||
elements = revitToSpeckleCacheSingleton.GetBaseObjectsForObjects(idsAndSubElementIds),
|
||||
name = "definitionGeometry"
|
||||
name = "revitInstancedObjects"
|
||||
}
|
||||
);
|
||||
|
||||
// STEP 6: Unpack all other objects to attach to root collection
|
||||
List<Objects.Other.Camera> views = viewUnpacker.Unpack(converterSettings.Current.Document);
|
||||
if (views.Count > 0)
|
||||
{
|
||||
rootObject[RootKeys.VIEW] = views;
|
||||
}
|
||||
|
||||
// NOTE: these are currently not used anywhere, we'll skip them until someone calls for it back
|
||||
// rootObject[ProxyKeys.PARAMETER_DEFINITIONS] = _parameterDefinitionHandler.Definitions;
|
||||
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
using Speckle.Connectors.DUI.Settings;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Send.Settings;
|
||||
|
||||
public class SendAreasAsMeshSetting(bool value = SendAreasAsMeshSetting.DEFAULT_VALUE) : ICardSetting
|
||||
{
|
||||
public const string SETTING_ID = "sendAreasAsMesh";
|
||||
public const bool DEFAULT_VALUE = false;
|
||||
|
||||
public string? Id { get; set; } = SETTING_ID;
|
||||
public string? Title { get; set; } = "Send Areas As Mesh";
|
||||
public string? Type { get; set; } = "boolean";
|
||||
public object? Value { get; set; } = value;
|
||||
public List<string>? Enum { get; set; }
|
||||
}
|
||||
-11
@@ -22,7 +22,6 @@ public class ToSpeckleSettingsManager(
|
||||
private readonly Dictionary<string, bool?> _sendNullParamsCache = [];
|
||||
private readonly Dictionary<string, bool?> _sendLinkedModelsCache = [];
|
||||
private readonly Dictionary<string, bool?> _sendRebarsAsVolumetricCache = [];
|
||||
private readonly Dictionary<string, bool?> _sendAreasAsMeshCache = [];
|
||||
|
||||
public DetailLevelType GetDetailLevelSetting(Document document, SenderModelCard modelCard)
|
||||
{
|
||||
@@ -132,16 +131,6 @@ public class ToSpeckleSettingsManager(
|
||||
"Send rebars as volumetric"
|
||||
);
|
||||
|
||||
public bool GetSendAreasAsMesh(Document document, SenderModelCard modelCard) =>
|
||||
GetBooleanSettingWithCache(
|
||||
document,
|
||||
SendAreasAsMeshSetting.SETTING_ID,
|
||||
SendAreasAsMeshSetting.DEFAULT_VALUE,
|
||||
modelCard,
|
||||
_sendAreasAsMeshCache,
|
||||
"Send areas as mesh"
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to handle boolean settings with caching and logging
|
||||
/// </summary>
|
||||
|
||||
@@ -6,106 +6,38 @@ using Speckle.Sdk.Common;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
/// <remarks>
|
||||
/// Please do NOT try and refactor this class.
|
||||
/// Whether it's to try and generalize with the <see cref="IdleCallManager"/> class
|
||||
/// or to unnecessary try and make this class thread safe.
|
||||
/// This class is a simple singleton, targeted to a Revit's host app requirements
|
||||
/// where everything happens on the main thread, and we can avoid overly complex threading/thread-safety.
|
||||
///
|
||||
/// Previous refactors with good intention have lead to poor debugging experiences, over-engineered threading,
|
||||
/// and low confidence in the reliability.
|
||||
/// </remarks>
|
||||
/// should be registered as singleton
|
||||
public class RevitIdleManager(RevitContext revitContext, ITopLevelExceptionHandler topLevelExceptionHandler)
|
||||
public sealed class RevitIdleManager : AppIdleManager
|
||||
{
|
||||
private readonly UIApplication _uiApplication = revitContext.UIApplication.NotNull();
|
||||
private readonly UIApplication _uiApplication;
|
||||
private readonly IIdleCallManager _idleCallManager;
|
||||
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
|
||||
|
||||
private readonly Dictionary<string, Func<Task>> _calls = new();
|
||||
private bool _hasSubscribed;
|
||||
private event EventHandler<IdlingEventArgs>? OnIdle;
|
||||
|
||||
private bool _isExecutingIdle;
|
||||
|
||||
/// <summary>
|
||||
/// Defers the invocation of an <paramref name="action"/> until next Revit idle tick (deduped by name).
|
||||
/// The <paramref name="action"/> will be called only once.
|
||||
/// </summary>
|
||||
/// <param name="name">A key that prevents enqueuing duplicate events</param>
|
||||
/// <param name="action">The action to be invoked</param>
|
||||
/// <example>
|
||||
/// Some events in host app are triggered many times, we might get 10x per object
|
||||
/// Making this more like a deferred action, so we don't update the UI many times
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// This function must be called on the main thread
|
||||
/// </remarks>
|
||||
public void SubscribeToIdle(string name, Action action)
|
||||
public RevitIdleManager(
|
||||
RevitContext revitContext,
|
||||
IIdleCallManager idleCallManager,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler,
|
||||
IRevitTask revitTask
|
||||
)
|
||||
: base(idleCallManager)
|
||||
{
|
||||
SubscribeToIdle(
|
||||
name,
|
||||
() =>
|
||||
{
|
||||
action.Invoke();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
_topLevelExceptionHandler = topLevelExceptionHandler;
|
||||
_uiApplication = revitContext.UIApplication.NotNull();
|
||||
_idleCallManager = idleCallManager;
|
||||
revitTask.Run(
|
||||
() => _uiApplication.Idling += (s, e) => OnIdle?.Invoke(s, e) // will be called on the main thread always and fixing the Revit exceptions on subscribing/unsubscribing Idle events
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="SubscribeToIdle(string, Action)"/>
|
||||
public void SubscribeToIdle(string name, Func<Task> action)
|
||||
protected override void AddEvent()
|
||||
{
|
||||
if (_isExecutingIdle)
|
||||
_topLevelExceptionHandler.CatchUnhandled(() =>
|
||||
{
|
||||
//Either, you're trying to SubscribeToIdle from not the main thread (don't do this)
|
||||
//OR, an OnIdle event handler is calling SubscribeToIdle (re-entry), check the call stack
|
||||
throw new InvalidOperationException("SubscribeToIdle called while already executing idle events");
|
||||
}
|
||||
|
||||
_calls[name] = action;
|
||||
|
||||
if (_hasSubscribed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_hasSubscribed = true;
|
||||
|
||||
_uiApplication.Idling += RevitAppOnIdle;
|
||||
}
|
||||
|
||||
private void RevitAppOnIdle(object? sender, IdlingEventArgs e)
|
||||
{
|
||||
topLevelExceptionHandler.CatchUnhandled(() =>
|
||||
{
|
||||
if (_isExecutingIdle)
|
||||
{
|
||||
//Either, you're trying to SubscribeToIdle from not the main thread (don't do this)
|
||||
//OR, an OnIdle event handler is calling SubscribeToIdle (re-entry), check the call stack... avoid this
|
||||
throw new InvalidOperationException("SubscribeToIdle called while already executing idle events");
|
||||
}
|
||||
|
||||
_isExecutingIdle = true;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (KeyValuePair<string, Func<Task>> kvp in _calls)
|
||||
{
|
||||
topLevelExceptionHandler.FireAndForget(kvp.Value.Invoke);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_calls.Clear();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_uiApplication.Idling -= RevitAppOnIdle;
|
||||
|
||||
_isExecutingIdle = false;
|
||||
// setting last will delay entering re-subscription
|
||||
_hasSubscribed = false;
|
||||
}
|
||||
OnIdle += RevitAppOnIdle;
|
||||
});
|
||||
}
|
||||
|
||||
private void RevitAppOnIdle(object? sender, IdlingEventArgs e) =>
|
||||
_idleCallManager.AppOnIdle(() => OnIdle -= RevitAppOnIdle);
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user