Compare commits

...

15 Commits

Author SHA1 Message Date
Dogukan Karatas a4345a28f8 supress the check
.NET Build and Publish / build-connectors (push) Has been cancelled
.NET Build and Publish / deploy-installers (push) Has been cancelled
2025-11-27 18:14:33 +01:00
Dogukan Karatas 95ca68c393 version bump 2025-11-27 17:57:30 +01:00
Dogukan Karatas 0f81216ba1 some formatting 2025-11-27 17:34:11 +01:00
Dogukan Karatas 7aa375039d solidx converter added 2025-11-26 14:07:41 +01:00
Björn Steinhagen 93ede98135 fix(grasshopper): CastFrom with long (#1197)
* fix: cast from with long

* chore: be loud about future casting fails
2025-11-26 12:43:13 +02:00
Jedd Morgan 03cffcdf4c Merge pull request #1196 from specklesystems/dependabot/github_actions/actions/checkout-6
chore(deps): bump actions/checkout from 5 to 6
2025-11-24 22:40:43 +03:00
dependabot[bot] c533d0922a chore(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 14:54:29 +00:00
Björn Steinhagen c24fb7eaa0 fix(rhino): remove control characters from revit families for rhino layer names (#1195) 2025-11-19 09:44:22 +00:00
Jonathon Broughton 003e310089 Adds room ID properties for family instances (#1192)
Introduces extraction of 'toRoomId' and 'fromRoomId' for family instance elements, enhancing the representation of relationships between doors and associated rooms.

Improves data completeness for elements with room associations.
2025-11-18 12:44:40 +00:00
Oğuzhan Koral 5917530761 Add account via binding (#1191) 2025-11-18 13:26:19 +03:00
Claire Kuang 349009314b feat(rhino/revit): publishes views (#1160)
* adds view proxies and converter

* adds rhino views

* updates with new proxy field

* adds views to revit send

* updates views to not include parallel projections

also adds rootkeys to connectors common

* updates to 3.8.0 sdk

* only add views if any
2025-11-17 17:50:41 +00:00
Jonathon Broughton 659a29a294 Improves property value conversion and extraction (#1183)
* Refactors property extraction to use model units

Uses the model's units when extracting properties to
ensure consistency and accuracy of converted values.

Extracts property sets as a static function to provide
re-usability without the class instance.

* Refactors Revit category extraction

Improves Revit category extraction by utilizing UI units for property conversion, ensuring consistent unit handling.

Additionally, refactors the extractor to a static class.

* Improves property conversion and handling

Introduces robust property conversion and handling logic.

Leverages user interface units for length, area, and volume property conversions,
ensuring consistency with the Navisworks UI.

Enhances property data handling by using dictionaries to represent
numerical properties with associated units, providing more context
for downstream applications.

Adds property name sanitization to ensure compatibility with
Speckle's object model.

* Removes the unused `Speckle.Converter.Navisworks.Helpers` import from the PropertySetsExtractor class to reduce clutter and improve code maintainability.

Relates to CNX-2784

* Standardizes numerical property dictionary creation.

Simplifies the creation of numerical property dictionaries
by removing the `internalDefinitionName` parameter from the
`NumObj` method. This ensures a consistent format for numerical
properties across the connector.

Relates to CNX-2784

* Refactors property conversion to service

Moves property conversion logic into a dedicated service.

This improves code organization and testability and allows
to reuse logic and manage UI units consistently.

* Refactors property conversion for consistency

Standardizes property conversion by introducing a dedicated `IPropertyConverter` service.

This change ensures consistent handling of property values across different extractors,
improving data accuracy and reducing inconsistencies in quantity extraction.
It also adds resets of the property converter to ensure clean conversions for each item.

Relates to CNX-2784

* Update Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/PropertyHelpers.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/PropertyHelpers.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/PropertyHelpers.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Moves UI Units cache to service

Moves the UI Units cache logic from the helpers to a dedicated service.

This improves the separation of concerns and makes the code more maintainable and testable.

Relates to CNX-2784

* Fixes unit label typos.

Corrects minor spelling errors in the unit labels for
centimeters, millimeters, micrometers, and kilometers.

Relates to CNX-2784

* Ensures correct units are used on send

Uses the UI Units Cache service to ensure the correct
units are being applied to objects when sending them to Speckle.

Relates to CNX-2784

* Enhances the property helper functionality to support additional features. Adjusts the constructor parameters to accommodate new requirements.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-17 20:42:52 +03:00
Jonathon Broughton 1ffeddbc2c Implements geometry instancing and optimization in Navisworks connector (#1188)
* Introduces shared geometry store service

Creates a singleton service for deduplicating geometry during conversion.

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

It uses a dictionary and a hash set to optimize lookup and storage, and includes thread safety mechanisms.

* Adds instance store manager for geometry

Introduces an instance store manager to handle shared geometry, which includes separate stores for geometry definitions and instance proxies.

This change prepares for the implementation of an instancing pattern compatible with .NET Framework.
It also registers settings from a factory to resolve conversion settings.

* Adds shared project file for Navisworks converter

Introduces a shared project file for the Navisworks converter, promoting code reuse and consistency across different Navisworks converter implementations.

This file includes common data extractors, data handlers, helpers, services, and settings, reducing duplication and improving maintainability.

* Implements geometry instancing for Navisworks

Adds geometry instancing to improve performance and reduce data size when converting Navisworks models with shared geometry.

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

Improves handling of COM array data for fragment ID generation and includes comprehensive logging for debugging instancing issues.

* Introduces instance store management

Adds a service to manage shared geometry and instance definition proxies.

This system uses two stores for geometry definitions and their instance proxies,
facilitating efficient handling of shared geometry. It provides methods for
adding, retrieving, and clearing geometries, ensuring deduplication and
optimized memory usage.

* Refactors display value extraction

Streamlines display value extraction by injecting the geometry converter.

This change simplifies the DisplayValueExtractor by removing its dependencies on settings and logging.
It now directly uses a GeometryToSpeckleConverter instance, which is passed in, for converting model item geometry.

* Adds instance geometry support to Navisworks connector

Introduces instance geometry handling for more efficient and accurate Navisworks data streams.

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

Addresses issues with duplicate geometry and improves stream performance.

* Fixes geometry processing for instance handling

Refactors geometry processing logic to handle instances more efficiently.
It now correctly applies transformations for single objects, ensuring accurate placement in the scene.
Simplifies processing of transforms where necessary for single objects.
Removes redundant logging.

* LFG!!!

Matrix4x4 Transposed
Adds an application ID to instance references.

* Fixes RenderMaterials

* Refactors dependency injection for settings

* Reduces comment clutter in Navisworks converters

Removes unnecessary comments to enhance code readability
and maintainability.

Simplifies the logic flow by eliminating obsolete comments
that do not provide value, promoting a cleaner codebase
moving forward.

Relates to issue jonathon/cnx-2817-adopt-displayvalue-proxification-pattern-in-navisworks.

* Renames methods for clarity and updates logic

Refactors method names to improve readability and understanding of functionality.

Consolidates selection logic related to representation modes and enhances the cohesiveness of the code.

Also updates the property extraction method for better clarity on its purpose.

Relates to the adoption of the display-value proxification pattern.

* Refines COM object management and method naming

Improves memory safety by ensuring all COM objects are explicitly released in try-finally blocks.

* Refactors constants usage for geometry identification

Introduces new constant definitions to standardise fragment ID prefixing.

* Refactors Navisworks build process for resilience

Adds error checking to ensure the Navisworks version is set before build occurs, and improves error handling to avoid empty output directories.

Updates file copy logic to handle resource and ribbon files correctly.
Ensures that the Navisworks plugin is correctly packaged and deployed.

Addresses CNX-2788

* Improves geometry retrieval and checks

Refactors geometry definition retrieval for better readability.

* Refactors property name sanitisation logic

Consolidates the logic for sanitising property names into a more concise format.

* Refactors method signature for clarity

* Update Converters/Navisworks/Speckle.Converters.NavisworksShared/Services/InstanceStoreManager.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Enhances fragment processing logic and error handling

Improves null handling for selection paths to prevent crashes.

* Changes fragment ID method visibility to public

Updates the visibility of the fragment ID generation method to public, allowing it to be accessed from outside the class.

* implementing more robust error handling during COM
interop operations.

* Updates method signatures to replace base geometry types with shared models, ensuring consistent handling of geometry data.

* Refactors parameter list for clarity

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
2025-11-17 19:37:02 +03:00
Björn Steinhagen 9d9a27d9cb fix: bake transforms into curves/polylines/points for family instances (#1190)
Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
2025-11-17 16:02:58 +00:00
Björn Steinhagen b2a885c193 fix(grasshopper): dispayValue proxies broke grasshopper load (#1187)
* fix: poc

* refactor: consolidating poc

* fix: tweaking through testing

* fix: async component

* fix: ci

* chore: is null and is not null form

* refactor: using NotNull()

* chore: csharpier

* refactor: ogu bey
2025-11-17 17:52:56 +02:00
130 changed files with 3554 additions and 1670 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
file_version: ${{ steps.set-version.outputs.file_version }}
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -293,7 +293,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -337,18 +337,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -358,14 +358,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -293,7 +293,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -337,18 +337,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -358,14 +358,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -294,7 +294,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -211,9 +211,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -245,7 +245,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -289,18 +289,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -211,9 +211,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -245,7 +245,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -289,18 +289,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -269,9 +269,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -303,7 +303,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -347,18 +347,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -368,14 +368,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -269,9 +269,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -303,7 +303,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -347,18 +347,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -368,14 +368,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -269,9 +269,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -303,7 +303,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -347,18 +347,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -368,14 +368,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -220,9 +220,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -255,7 +255,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -299,18 +299,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -318,14 +318,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -220,9 +220,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -255,7 +255,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -299,18 +299,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -318,14 +318,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.etabs21": {
@@ -336,18 +336,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -357,14 +357,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -211,9 +211,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -237,7 +237,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.etabs22": {
@@ -287,18 +287,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -306,14 +306,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
+47 -17
View File
@@ -2,33 +2,63 @@
<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>$(AppData)\Autodesk\ApplicationPlugins\Speckle.Connectors.Navisworks.bundle\Contents\$(NavisworksVersion)</PluginVersionContentTarget>
<PluginVersionContentTarget>$(PluginBundleTarget)\Contents\$(NavisworksVersion)</PluginVersionContentTarget>
<RootNamespace>Speckle.Connector.Navisworks</RootNamespace>
</PropertyGroup>
<!-- 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="'$(OS)' == 'Windows_NT' and '$(NavisworksVersion)' != ''">
<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)')"/>
<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)\" />
<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."/>
</Target>
</Project>
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2020": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2021": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2022": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2023": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2024": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -266,9 +266,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -292,7 +292,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2025": {
@@ -338,18 +338,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -359,14 +359,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -267,9 +267,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -293,7 +293,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.navisworks2026": {
@@ -340,18 +340,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -361,14 +361,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
".NETFramework,Version=v4.8/win-x64": {
@@ -15,6 +15,7 @@ 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.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Sdk.Models.GraphTraversal;
@@ -52,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
@@ -16,7 +16,13 @@ public class NavisworksColorUnpacker(
IElementSelectionService selectionService
)
{
private static T Select<T>(RepresentationMode mode, T active, T permanent, T original, T defaultValue) =>
private static T SelectByRepresentationMode<T>(
RepresentationMode mode,
T active,
T permanent,
T original,
T defaultValue
) =>
mode switch
{
RepresentationMode.Active => active,
@@ -71,14 +77,14 @@ public class NavisworksColorUnpacker(
using var defaultColor = new NAV.Color(1.0, 1.0, 1.0);
var representationColor = Select(
var representationColor = SelectByRepresentationMode(
mode,
geometry.ActiveColor,
geometry.PermanentColor,
geometry.OriginalColor,
defaultColor
);
var colorId = Select(
var colorId = SelectByRepresentationMode(
mode,
$"{geometry.ActiveColor.GetHashCode()}_{geometry.ActiveTransparency}".GetHashCode(),
$"{geometry.PermanentColor.GetHashCode()}_{geometry.PermanentTransparency}".GetHashCode(),
@@ -124,30 +130,49 @@ public class NavisworksColorUnpacker(
var comSelection = ComBridge.ToInwOpSelection([modelItem]);
try
{
foreach (ComApi.InwOaPath path in comSelection.Paths())
var pathsCollection = comSelection.Paths();
try
{
GC.KeepAlive(path);
foreach (ComApi.InwOaFragment3 fragment in path.Fragments())
foreach (ComApi.InwOaPath path in pathsCollection)
{
GC.KeepAlive(fragment);
fragment.GenerateSimplePrimitives(ComApi.nwEVertexProperty.eNORMAL, primitiveChecker);
// Exit early if triangles are found
if (primitiveChecker.HasTriangles)
var fragmentsCollection = path.Fragments();
try
{
return false;
foreach (ComApi.InwOaFragment3 fragment in fragmentsCollection.OfType<ComApi.InwOaFragment3>())
{
fragment.GenerateSimplePrimitives(ComApi.nwEVertexProperty.eNORMAL, primitiveChecker);
if (primitiveChecker.HasTriangles)
{
return false;
}
}
}
finally
{
if (fragmentsCollection != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(fragmentsCollection);
}
}
}
}
// Return true if any 2D primitives are found
return primitiveChecker.HasLines || primitiveChecker.HasPoints || primitiveChecker.HasSnapPoints;
return primitiveChecker.HasLines || primitiveChecker.HasPoints || primitiveChecker.HasSnapPoints;
}
finally
{
if (pathsCollection != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(pathsCollection);
}
}
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
if (comSelection != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
}
}
}
}
@@ -1,7 +1,11 @@
using Autodesk.Navisworks.Api.ComApi;
using Autodesk.Navisworks.Api.Interop.ComApi;
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.Services;
using Speckle.Converter.Navisworks.Constants;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.Objects.Other;
using Speckle.Sdk;
@@ -11,12 +15,17 @@ namespace Speckle.Connector.Navisworks.HostApp;
public class NavisworksMaterialUnpacker(
ILogger<NavisworksMaterialUnpacker> logger,
IConverterSettingsStore<NavisworksConversionSettings> converterSettings,
IElementSelectionService selectionService
IElementSelectionService selectionService,
GeometryToSpeckleConverter converter
)
{
// 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) =>
private static T SelectByRepresentationMode<T>(
RepresentationMode mode,
T active,
T permanent,
T original,
T defaultValue
) =>
mode switch
{
RepresentationMode.Active => active,
@@ -64,26 +73,87 @@ public class NavisworksMaterialUnpacker(
var navisworksObjectId = selectionService.GetModelItemPath(navisworksObject);
var finalId = mergedIds.TryGetValue(navisworksObjectId, out var mergedId) ? mergedId : navisworksObjectId;
string hashId = "";
try
{
var item = selectionService.GetModelItemFromPath(finalId);
var comSelection = ComApiBridge.ToInwOpSelection([item]);
try
{
var paths = comSelection.Paths();
try
{
if (paths.Count > 0)
{
var firstPath = paths.OfType<InwOaPath>().FirstOrDefault();
if (firstPath != null)
{
var fragments = firstPath.Fragments();
try
{
if (fragments.Count > 1)
{
var fragmentId = converter.GenerateFragmentId(paths);
hashId = $"{InstanceConstants.GEOMETRY_ID_PREFIX}{fragmentId}";
}
}
finally
{
if (fragments != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(fragments);
}
}
}
}
}
finally
{
if (paths != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(paths);
}
}
}
finally
{
if (comSelection != null)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(comSelection);
}
}
}
catch (Exception ex) when (!ex.IsFatal())
{ // If COM interop fails during hash generation, fall back to using finalId
logger.LogWarning(
ex,
"Failed to generate fragment hash ID for item {ItemId}, using finalId as fallback",
finalId
);
hashId = "";
}
var geometry = navisworksObject.Geometry;
var mode = converterSettings.Current.User.VisualRepresentationMode;
using var defaultColor = new NAV.Color(1.0, 1.0, 1.0);
var renderColor = Select(
var renderColor = SelectByRepresentationMode(
mode,
geometry.ActiveColor,
geometry.PermanentColor,
geometry.OriginalColor,
defaultColor
);
var renderTransparency = Select(
var renderTransparency = SelectByRepresentationMode(
mode,
geometry.ActiveTransparency,
geometry.PermanentTransparency,
geometry.OriginalTransparency,
0.0
);
var renderMaterialId = Select(
var renderMaterialId = SelectByRepresentationMode(
mode,
$"{geometry.ActiveColor.GetHashCode()}_{geometry.ActiveTransparency}".GetHashCode(),
$"{geometry.PermanentColor.GetHashCode()}_{geometry.PermanentTransparency}".GetHashCode(),
@@ -92,9 +162,8 @@ public class NavisworksMaterialUnpacker(
);
var materialName =
$"NavisworksMaterial_{Math.Abs(ColorConverter.NavisworksColorToColor(renderColor).ToArgb())}";
$"{MaterialConstants.DEFAULT_MATERIAL_NAME_PREFIX}{Math.Abs(ColorConverter.NavisworksColorToColor(renderColor).ToArgb())}";
// Check Item category for material name
var itemCategory = navisworksObject.PropertyCategories.FindCategoryByDisplayName("Item");
if (itemCategory != null)
{
@@ -106,7 +175,6 @@ public class NavisworksMaterialUnpacker(
}
}
// Check Material category for material name
var materialPropertyCategory = navisworksObject.PropertyCategories.FindCategoryByDisplayName("Material");
if (materialPropertyCategory != null)
{
@@ -120,19 +188,14 @@ 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 = ConvertRenderColorAndTransparencyToSpeckle(
materialName,
renderTransparency,
renderColor,
renderMaterialId
),
objects = [finalId]
value = CreateRenderMaterial(materialName, renderTransparency, renderColor, renderMaterialId),
objects = [!string.IsNullOrEmpty(hashId) ? hashId : finalId]
};
}
}
@@ -145,7 +208,7 @@ public class NavisworksMaterialUnpacker(
return renderMaterialProxies.Values.ToList();
}
private static RenderMaterial ConvertRenderColorAndTransparencyToSpeckle(
private static RenderMaterial CreateRenderMaterial(
string name,
double transparency,
NAV.Color navisworksColor,
@@ -156,7 +219,9 @@ public class NavisworksMaterialUnpacker(
var speckleRenderMaterial = new RenderMaterial()
{
name = !string.IsNullOrEmpty(name) ? name : $"NavisworksMaterial_{Math.Abs(color.ToArgb())}",
name = !string.IsNullOrEmpty(name)
? name
: $"{MaterialConstants.DEFAULT_MATERIAL_NAME_PREFIX}{Math.Abs(color.ToArgb())}",
opacity = 1 - transparency,
metalness = 0,
roughness = 1,
@@ -6,6 +6,7 @@ using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Objects.Data;
@@ -25,7 +26,9 @@ public class NavisworksRootObjectBuilder(
ISdkActivityFactory activityFactory,
NavisworksMaterialUnpacker materialUnpacker,
NavisworksColorUnpacker colorUnpacker,
IElementSelectionService elementSelectionService
IElementSelectionService elementSelectionService,
IUiUnitsCache uiUnitsCache,
InstanceStoreManager instanceStoreManager
) : IRootObjectBuilder<NAV.ModelItem>
{
private bool SkipNodeMerging { get; set; }
@@ -40,32 +43,45 @@ public class NavisworksRootObjectBuilder(
)
{
#if DEBUG
// This is a temporary workaround to disable node merging for debugging purposes - false is default, true is for debugging
SkipNodeMerging = false;
SkipNodeMerging = true;
#endif
using var activity = activityFactory.Start("Build");
ValidateInputs(navisworksModelItems, projectId, onOperationProgressed);
// 2. Initialize root collection
var rootCollection = InitializeRootCollection();
// 3. Convert all model items and store results
var (convertedElements, conversionResults) = await ConvertModelItemsAsync(
navisworksModelItems,
projectId,
onOperationProgressed,
cancellationToken
);
(Dictionary<string, Base?> convertedElements, List<SendConversionResult> conversionResults) =
await ConvertModelItemsAsync(navisworksModelItems, projectId, onOperationProgressed, cancellationToken);
ValidateConversionResults(conversionResults);
var groupedNodes = SkipNodeMerging ? [] : GroupSiblingGeometryNodes(navisworksModelItems);
var finalElements = BuildFinalElements(convertedElements, groupedNodes);
List<Base> geometryDefinitions = instanceStoreManager.GetGeometryDefinitions();
await AddProxiesToCollection(rootCollection, navisworksModelItems, groupedNodes);
rootCollection.elements = finalElements;
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);
}
return new RootObjectBuilderResult(rootCollection, conversionResults);
}
@@ -137,12 +153,10 @@ 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 hierarchy mode is enabled, reorganize into proper nested structure
if (converterSettings.Current.User.PreserveModelHierarchy)
{
var hierarchyBuilder = new NavisworksHierarchyBuilder(
@@ -151,12 +165,9 @@ public class NavisworksRootObjectBuilder(
elementSelectionService
);
var hierarchy = hierarchyBuilder.BuildHierarchy();
return hierarchy;
return hierarchyBuilder.BuildHierarchy();
}
// Otherwise continue with flat mode
AddRemainingElements(finalElements, convertedBases, processedPaths);
return finalElements;
}
@@ -213,24 +224,17 @@ public class NavisworksRootObjectBuilder(
}
}
private (string name, string path) GetContext(string applicationId)
private (string name, string path) GetElementNameAndPath(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) = GetContext(cleanParentPath);
(string name, string path) = GetElementNameAndPath(cleanParentPath);
return new NavisworksObject
{
@@ -238,16 +242,11 @@ public class NavisworksRootObjectBuilder(
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, // Use the full composite key as applicationId to preserve uniqueness
applicationId = groupKey,
["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)
@@ -255,14 +254,16 @@ public class NavisworksRootObjectBuilder(
return null;
}
(string name, string path) = GetContext(convertedBase.applicationId);
(string name, string path) = GetElementNameAndPath(convertedBase.applicationId);
var units = uiUnitsCache.Ensure();
return new NavisworksObject
{
name = name,
displayValue = convertedBase["displayValue"] as List<Base> ?? [],
properties = convertedBase["properties"] as Dictionary<string, object?> ?? [],
units = converterSettings.Current.Derived.SpeckleUnits,
units = units.ToString(),
applicationId = convertedBase.applicationId,
["path"] = path
};
@@ -288,18 +289,16 @@ public class NavisworksRootObjectBuilder(
rootCollection[ProxyKeys.COLOR] = colors;
}
var instanceDefinitionProxies = instanceStoreManager.GetInstanceDefinitionProxies();
if (instanceDefinitionProxies.Count > 0)
{
rootCollection[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies.ToList();
}
return Task.CompletedTask;
}
/// <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,
@@ -282,9 +282,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +307,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.revit2022": {
@@ -352,11 +352,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Revit.API": {
@@ -367,9 +367,9 @@
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -379,14 +379,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -282,9 +282,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +307,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.revit2023": {
@@ -352,11 +352,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Revit.API": {
@@ -367,9 +367,9 @@
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -379,14 +379,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -282,9 +282,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -307,7 +307,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.revit2024": {
@@ -352,11 +352,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Revit.API": {
@@ -367,9 +367,9 @@
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -379,14 +379,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -227,9 +227,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -252,7 +252,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.revit2025": {
@@ -297,11 +297,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Revit.API": {
@@ -312,9 +312,9 @@
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -322,14 +322,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -220,9 +220,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -245,7 +245,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.revit2026": {
@@ -281,11 +281,11 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Revit.API": {
@@ -296,9 +296,9 @@
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -306,14 +306,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -58,6 +58,7 @@ public static class ServiceRegistration
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>();
@@ -0,0 +1,87 @@
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;
}
}
@@ -24,6 +24,7 @@ public class RevitRootObjectBuilder(
ISendConversionCache sendConversionCache,
ElementUnpacker elementUnpacker,
LevelUnpacker levelUnpacker,
ViewUnpacker viewUnpacker,
IThreadContext threadContext,
SendCollectionManager sendCollectionManager,
ILogger<RevitRootObjectBuilder> logger,
@@ -240,6 +241,7 @@ 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);
@@ -260,6 +262,13 @@ public class RevitRootObjectBuilder(
}
);
// 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;
@@ -24,6 +24,7 @@
<Compile Include="$(MSBuildThisFileDirectory)HostApp\LevelUnpacker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\LinkedModelHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RevitMaterialBaker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\ViewUnpacker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\SupportedCategoriesUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RevitViewManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\HideWarningsFailuresPreprocessor.cs" />
@@ -60,4 +61,4 @@
<Compile Include="$(MSBuildThisFileDirectory)Plugin\RevitCefPlugin.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Plugin\SpeckleRevitTaskException.cs" />
</ItemGroup>
</Project>
</Project>
@@ -326,9 +326,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.logging": {
@@ -338,7 +338,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.rhino7": {
@@ -383,18 +383,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -404,14 +404,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -326,9 +326,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.logging": {
@@ -338,7 +338,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.rhino8": {
@@ -382,18 +382,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -403,14 +403,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -27,8 +27,7 @@ public class ExpandSpeckleProperties : GH_Component, IGH_VariableParameterCompon
protected override Bitmap Icon => Resources.speckle_properties_expand;
public override GH_Exposure Exposure => GH_Exposure.secondary;
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
protected override void RegisterInputParams(GH_InputParamManager pManager) =>
pManager.AddParameter(
new SpecklePropertyGroupParam(),
"Properties",
@@ -36,7 +35,6 @@ public class ExpandSpeckleProperties : GH_Component, IGH_VariableParameterCompon
"Speckle Properties to expand",
GH_ParamAccess.item
);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager) { }
@@ -447,73 +447,89 @@ public sealed class ReceiveComponentWorker : WorkerInstance<ReceiveAsyncComponen
}
using var scope = PriorityLoader.CreateScopeForActiveDocument();
Root = await scope
.Get<GrasshopperReceiveOperation>()
.ReceiveCommitObject(receiveInfo, progress, CancellationToken)
.ConfigureAwait(false);
CancellationToken.ThrowIfCancellationRequested();
SpecklePropertyGroupGoo? rootPropertiesGoo = null;
if (Root is RootCollection rootCollection && rootCollection.properties.Count > 0)
try
{
rootPropertiesGoo = new SpecklePropertyGroupGoo(rootCollection.properties);
Root = await scope
.Get<GrasshopperReceiveOperation>()
.ReceiveCommitObject(receiveInfo, progress, CancellationToken)
.ConfigureAwait(false);
CancellationToken.ThrowIfCancellationRequested();
SpecklePropertyGroupGoo? rootPropertiesGoo = null;
if (Root is RootCollection rootCollection && rootCollection.properties.Count > 0)
{
rootPropertiesGoo = new SpecklePropertyGroupGoo(rootCollection.properties);
}
// Step 2 - CONVERT
//receiveComponent.Message = $"Unpacking...";
SpeckleConversionContext.SetupCurrent(scope);
var unpackedRoot = scope.Get<RootObjectUnpacker>().Unpack(Root);
// separate atomic objects from block instances
var (atomicObjects, blockInstances) = scope
.Get<RootObjectUnpacker>()
.SplitAtomicObjectsAndInstances(unpackedRoot.ObjectsToConvert);
// initialize unpackers and collection builder (data holders - created with new)
var colorUnpacker = new GrasshopperColorUnpacker(unpackedRoot);
var materialUnpacker = new GrasshopperMaterialUnpacker(unpackedRoot);
var collectionRebuilder = new GrasshopperCollectionRebuilder(
(Root as Collection) ?? new Collection { name = "unnamed" }
);
// get handler from DI and initialize with per-operation data
var mapHandler = scope
.Get<LocalToGlobalMapHandler>()
.Initialize(
scope.Get<TraversalContextUnpacker>(),
colorUnpacker,
materialUnpacker,
collectionRebuilder,
unpackedRoot.DefinitionProxies
);
// handler deals with two-pass conversion: normal objects first, then DataObjects with InstanceProxies
mapHandler.ConvertAtomicObjects(atomicObjects);
// process block instances using converted atomic objects
// internally filters out InstanceProxies that belong to registered DataObjects
// block processing needs converted objects, but object filtering needs block definitions.
mapHandler.ConvertBlockInstances(blockInstances);
Result = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
RootProperties = rootPropertiesGoo;
// TODO: If we have NodeRun events later, better to have `ComponentTracker` to use across components
var customProperties = new Dictionary<string, object>()
{
{ "isAsync", true },
{ "sourceHostApp", HostApplications.GetSlugFromHostAppNameAndVersion(receiveInfo.SourceApplication) },
{ "auto", Parent.AutoReceive }
};
if (receiveInfo.WorkspaceId != null)
{
customProperties.Add("workspace_id", receiveInfo.WorkspaceId);
}
if (receiveInfo.SelectedVersionUserId != null)
{
customProperties.Add(
"isMultiplayer",
receiveInfo.SelectedVersionUserId != Parent.ApiClient.Account.userInfo.id
);
}
await scope
.Get<IMixPanelManager>()
.TrackEvent(MixPanelEvents.Receive, Parent.ApiClient.Account, customProperties);
}
// Step 2 - CONVERT
//receiveComponent.Message = $"Unpacking...";
TraversalContextUnpacker traversalContextUnpacker = new();
var unpackedRoot = scope.Get<RootObjectUnpacker>().Unpack(Root);
// separate atomic objects from block instances
var (atomicObjects, blockInstances) = scope
.Get<RootObjectUnpacker>()
.SplitAtomicObjectsAndInstances(unpackedRoot.ObjectsToConvert);
// initialize unpackers and collection builder
var colorUnpacker = new GrasshopperColorUnpacker(unpackedRoot);
var materialUnpacker = new GrasshopperMaterialUnpacker(unpackedRoot);
var collectionRebuilder = new GrasshopperCollectionRebuilder(
(Root as Collection) ?? new Collection { name = "unnamed" }
);
// convert atomic objects directly
var mapHandler = new LocalToGlobalMapHandler(
traversalContextUnpacker,
collectionRebuilder,
colorUnpacker,
materialUnpacker
);
foreach (var atomicContext in atomicObjects)
finally
{
mapHandler.ConvertAtomicObject(atomicContext);
SpeckleConversionContext.EndCurrent();
}
// process block instances using converted atomic objects
// block processing needs converted objects, but object filtering needs block definitions.
mapHandler.ConvertBlockInstances(blockInstances, unpackedRoot.DefinitionProxies);
Result = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
RootProperties = rootPropertiesGoo;
// TODO: If we have NodeRun events later, better to have `ComponentTracker` to use across components
var customProperties = new Dictionary<string, object>()
{
{ "isAsync", true },
{ "sourceHostApp", HostApplications.GetSlugFromHostAppNameAndVersion(receiveInfo.SourceApplication) },
{ "auto", Parent.AutoReceive }
};
if (receiveInfo.WorkspaceId != null)
{
customProperties.Add("workspace_id", receiveInfo.WorkspaceId);
}
if (receiveInfo.SelectedVersionUserId != null)
{
customProperties.Add("isMultiplayer", receiveInfo.SelectedVersionUserId != Parent.ApiClient.Account.userInfo.id);
}
await scope.Get<IMixPanelManager>().TrackEvent(MixPanelEvents.Receive, Parent.ApiClient.Account, customProperties);
}
}
@@ -143,95 +143,102 @@ public class ReceiveComponent : SpeckleTaskCapableComponent<ReceiveComponentInpu
}
using var scope = PriorityLoader.CreateScopeForActiveDocument();
var clientFactory = scope.ServiceProvider.GetRequiredService<IClientFactory>();
var receiveOperation = scope.ServiceProvider.GetRequiredService<GrasshopperReceiveOperation>();
// Do the thing 👇🏼
Account? account = input.Resource.Account.GetAccount(scope);
if (account is null)
try
{
throw new SpeckleAccountManagerException("No default account was found");
var clientFactory = scope.ServiceProvider.GetRequiredService<IClientFactory>();
var receiveOperation = scope.ServiceProvider.GetRequiredService<GrasshopperReceiveOperation>();
// Do the thing 👇🏼
Account? account = input.Resource.Account.GetAccount(scope);
if (account is null)
{
throw new SpeckleAccountManagerException("No default account was found");
}
using var client = clientFactory.Create(account);
var receiveInfo = await input.Resource.GetReceiveInfo(client, cancellationToken).ConfigureAwait(false);
// store version id for tracking
_lastVersionId = receiveInfo.SelectedVersionId;
var progress = new Progress<CardProgress>(_ =>
{
// TODO: Progress only makes sense in non-blocking async receive, which is not supported yet.
// Message = $"{progress.Status}: {progress.Progress}";
});
var root = await receiveOperation
.ReceiveCommitObject(receiveInfo, progress, cancellationToken)
.ConfigureAwait(false);
// extract model-wide root properties (see cnx-2722)
SpecklePropertyGroupGoo? rootPropertiesGoo = null;
if (root is RootCollection rootCollection && rootCollection.properties.Count > 0)
{
rootPropertiesGoo = new SpecklePropertyGroupGoo(rootCollection.properties);
}
// TODO: If we have NodeRun events later, better to have `ComponentTracker` to use across components
var customProperties = new Dictionary<string, object>
{
{ "isAsync", false },
{ "sourceHostApp", HostApplications.GetSlugFromHostAppNameAndVersion(receiveInfo.SourceApplication) }
};
if (receiveInfo.WorkspaceId != null)
{
customProperties.Add("workspace_id", receiveInfo.WorkspaceId);
}
if (receiveInfo.SelectedVersionUserId != null)
{
customProperties.Add("isMultiplayer", receiveInfo.SelectedVersionUserId != client.Account.userInfo.id);
}
var mixpanel = PriorityLoader.Container.GetRequiredService<IMixPanelManager>();
await mixpanel.TrackEvent(MixPanelEvents.Receive, account, customProperties);
// Setup conversion context BEFORE unpacking (which triggers DataObjectConverter)
SpeckleConversionContext.SetupCurrent(scope);
var rootObjectUnpacker = scope.ServiceProvider.GetService<RootObjectUnpacker>();
var unpackedRoot = rootObjectUnpacker.Unpack(root);
// split atomic objects from block components before conversion
var (atomicObjects, blockInstances) = rootObjectUnpacker.SplitAtomicObjectsAndInstances(
unpackedRoot.ObjectsToConvert
);
// Initialize unpackers and collection builder (data holders - created with new)
var colorUnpacker = new GrasshopperColorUnpacker(unpackedRoot);
var materialUnpacker = new GrasshopperMaterialUnpacker(unpackedRoot);
var collectionRebuilder = new GrasshopperCollectionRebuilder(
(root as Collection) ?? new Collection { name = "unnamed" }
);
// get handler from DI and initialize with per-operation data
var mapHandler = scope
.ServiceProvider.GetRequiredService<LocalToGlobalMapHandler>()
.Initialize(
scope.ServiceProvider.GetRequiredService<TraversalContextUnpacker>(),
colorUnpacker,
materialUnpacker,
collectionRebuilder,
unpackedRoot.DefinitionProxies
);
// two-pass conversion: normal objects first, then DataObjects with InstanceProxies
mapHandler.ConvertAtomicObjects(atomicObjects);
// process block instances (internally filters InstanceProxies belonging to registered DataObjects)
mapHandler.ConvertBlockInstances(blockInstances);
var goo = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
return new ReceiveComponentOutput { RootObject = goo, RootProperties = rootPropertiesGoo };
}
using var client = clientFactory.Create(account);
var receiveInfo = await input.Resource.GetReceiveInfo(client, cancellationToken).ConfigureAwait(false);
// store version id for tracking
_lastVersionId = receiveInfo.SelectedVersionId;
var progress = new Progress<CardProgress>(_ =>
finally
{
// TODO: Progress only makes sense in non-blocking async receive, which is not supported yet.
// Message = $"{progress.Status}: {progress.Progress}";
});
var root = await receiveOperation
.ReceiveCommitObject(receiveInfo, progress, cancellationToken)
.ConfigureAwait(false);
// extract model-wide root properties (see cnx-2722)
SpecklePropertyGroupGoo? rootPropertiesGoo = null;
if (root is RootCollection rootCollection && rootCollection.properties.Count > 0)
{
rootPropertiesGoo = new SpecklePropertyGroupGoo(rootCollection.properties);
SpeckleConversionContext.EndCurrent();
}
// TODO: If we have NodeRun events later, better to have `ComponentTracker` to use across components
var customProperties = new Dictionary<string, object>
{
{ "isAsync", false },
{ "sourceHostApp", HostApplications.GetSlugFromHostAppNameAndVersion(receiveInfo.SourceApplication) }
};
if (receiveInfo.WorkspaceId != null)
{
customProperties.Add("workspace_id", receiveInfo.WorkspaceId);
}
if (receiveInfo.SelectedVersionUserId != null)
{
customProperties.Add("isMultiplayer", receiveInfo.SelectedVersionUserId != client.Account.userInfo.id);
}
var mixpanel = PriorityLoader.Container.GetRequiredService<IMixPanelManager>();
await mixpanel.TrackEvent(MixPanelEvents.Receive, account, customProperties);
// We need to rethink these lovely unpackers, there's a bit too many of 'em
var rootObjectUnpacker = scope.ServiceProvider.GetService<RootObjectUnpacker>();
var traversalContextUnpacker = new TraversalContextUnpacker();
var unpackedRoot = rootObjectUnpacker.Unpack(root);
// split atomic objects from block components before conversion
var (atomicObjects, blockInstances) = rootObjectUnpacker.SplitAtomicObjectsAndInstances(
unpackedRoot.ObjectsToConvert
);
// Initialize unpackers and collection builder
var colorUnpacker = new GrasshopperColorUnpacker(unpackedRoot);
var materialUnpacker = new GrasshopperMaterialUnpacker(unpackedRoot);
var collectionRebuilder = new GrasshopperCollectionRebuilder(
(root as Collection) ?? new Collection { name = "unnamed" }
);
// convert atomic objects directly
var mapHandler = new LocalToGlobalMapHandler(
traversalContextUnpacker,
collectionRebuilder,
colorUnpacker,
materialUnpacker
);
foreach (var atomicContext in atomicObjects)
{
mapHandler.ConvertAtomicObject(atomicContext);
}
// process block instances using converted atomic objects
// block processing needs converted objects, but object filtering needs block definitions.
mapHandler.ConvertBlockInstances(blockInstances, unpackedRoot.DefinitionProxies);
// var x = new SpeckleCollectionGoo { Value = collGen.RootCollection };
var goo = new SpeckleCollectionWrapperGoo(collectionRebuilder.RootCollectionWrapper);
return new ReceiveComponentOutput { RootObject = goo, RootProperties = rootPropertiesGoo };
}
private void SetupSubscription(SpeckleUrlModelResource resource)
@@ -29,13 +29,13 @@ public class SpeckleConversionContext(IRootToSpeckleConverter speckleConverter,
}
}
public static void SetupCurrent()
public static void SetupCurrent(IServiceScope? scope = null)
{
if (s_currentContext != null)
{
return;
}
s_scope = PriorityLoader.CreateScopeForActiveDocument();
s_scope = scope ?? PriorityLoader.CreateScopeForActiveDocument();
s_currentContext = s_scope.Get<SpeckleConversionContext>();
}
@@ -60,6 +60,7 @@ public class SpeckleConversionContext(IRootToSpeckleConverter speckleConverter,
{
GeometryBase geometry => [(geometry, input)],
List<GeometryBase> geometryList => geometryList.Select(o => ((object)o, input)).ToList(),
List<(GeometryBase, Base)> pairList when pairList.Count == 0 => [],
IEnumerable<(GeometryBase, Base)> fallbackConversionResult
=> fallbackConversionResult.Select(o => ((object)o.Item1, o.Item2)).ToList(),
object obj => [(obj, input)],
@@ -1,12 +1,18 @@
using Microsoft.Extensions.Logging;
using Rhino.Geometry;
using Speckle.Connectors.Common.Operations.Receive;
using Speckle.Connectors.GrasshopperShared.HostApp;
using Speckle.Connectors.GrasshopperShared.Operations.Receive;
using Speckle.Connectors.GrasshopperShared.Parameters;
using Speckle.Converters.Common.ToHost;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
using Speckle.Sdk.Models.GraphTraversal;
using Speckle.Sdk.Models.Instances;
using DataObject = Speckle.Objects.Data.DataObject;
namespace Speckle.Connectors.GrasshopperShared.Operations.Receive;
/// <summary>
/// Handles conversion of atomic objects from TraversalContexts into Grasshopper wrapper objects.
@@ -19,184 +25,388 @@ using Speckle.Sdk.Models.Instances;
internal sealed class LocalToGlobalMapHandler
{
public Dictionary<string, SpeckleGeometryWrapper> ConvertedObjectsMap { get; } = new();
public readonly GrasshopperCollectionRebuilder CollectionRebuilder;
private readonly TraversalContextUnpacker _traversalContextUnpacker;
private readonly GrasshopperColorUnpacker _colorUnpacker;
private readonly GrasshopperMaterialUnpacker _materialUnpacker;
// injected via constructor (DI-managed)
private readonly IDataObjectInstanceRegistry _dataObjectInstanceRegistry;
private readonly ILogger<LocalToGlobalMapHandler> _logger;
// set via Initialize() method (per-operation data)
private TraversalContextUnpacker _traversalContextUnpacker = null!;
private GrasshopperColorUnpacker _colorUnpacker = null!;
private GrasshopperMaterialUnpacker _materialUnpacker = null!;
private IReadOnlyCollection<InstanceDefinitionProxy>? _definitionProxies;
// auto property (fixes IDE0032)
public GrasshopperCollectionRebuilder CollectionRebuilder { get; private set; } = null!;
public LocalToGlobalMapHandler(
IDataObjectInstanceRegistry dataObjectInstanceRegistry,
ILogger<LocalToGlobalMapHandler> logger
)
{
_dataObjectInstanceRegistry = dataObjectInstanceRegistry;
_logger = logger;
}
/// <summary>
/// Initializes the handler with per-operation data.
/// Must be called before using ConvertAtomicObjects or ConvertBlockInstances.
/// </summary>
public LocalToGlobalMapHandler Initialize(
TraversalContextUnpacker traversalContextUnpacker,
GrasshopperCollectionRebuilder collectionRebuilder,
GrasshopperColorUnpacker colorUnpacker,
GrasshopperMaterialUnpacker materialUnpacker
GrasshopperMaterialUnpacker materialUnpacker,
GrasshopperCollectionRebuilder collectionRebuilder,
IReadOnlyCollection<InstanceDefinitionProxy>? definitionProxies
)
{
_traversalContextUnpacker = traversalContextUnpacker;
_colorUnpacker = colorUnpacker;
_materialUnpacker = materialUnpacker;
CollectionRebuilder = collectionRebuilder;
_definitionProxies = definitionProxies;
return this;
}
/// <summary>
/// Converts atomic object from TraversalContext to SpeckleObjectWrapper.
/// Converts all atomic objects in two passes:
/// Pass 1 - Convert normal objects and populate ConvertedObjectsMap
/// Pass 2 - Resolve registered DataObjects with InstanceProxies using the populated map
/// </summary>
public void ConvertAtomicObject(TraversalContext atomicContext)
public void ConvertAtomicObjects(IEnumerable<TraversalContext> atomicContexts)
{
// Cache to avoid re-iterating for registered check
var atomicList = atomicContexts as IList<TraversalContext> ?? atomicContexts.ToList();
// Pass 1: Convert all non-registered DataObjects to populate ConvertedObjectsMap
foreach (var atomicContext in atomicList)
{
ConvertObjectToCache(atomicContext);
}
// Pass 2: Process registered DataObjects (definitions now available in ConvertedObjectsMap)
foreach (var atomicContext in atomicList)
{
if (atomicContext.Current is DataObject dataObject)
{
var dataObjectId = dataObject.applicationId ?? dataObject.id;
if (dataObjectId is not null && _dataObjectInstanceRegistry.IsRegistered(dataObjectId))
{
ResolveDataObjectInstanceProxies(atomicContext);
}
}
}
}
/// <summary>
/// Converts and caches an atomic object for later lookup.
/// Skips registered DataObjects (displayValue is InstanceProxy) - they are resolved in ResolveDataObjectInstanceProxies.
/// </summary>
private void ConvertObjectToCache(TraversalContext atomicContext)
{
var obj = atomicContext.Current;
var objId = obj.applicationId ?? obj.id;
if (objId == null || ConvertedObjectsMap.ContainsKey(objId))
if (objId is null || ConvertedObjectsMap.ContainsKey(objId))
{
return;
}
// skip registered DataObjects - they'll be processed in second pass
if (obj is DataObject dataObject)
{
var id = dataObject.applicationId ?? dataObject.id.NotNull();
if (_dataObjectInstanceRegistry.IsRegistered(id))
{
return;
}
}
try
{
List<(object, Base)> converted = SpeckleConversionContext.Current.ConvertToHost(obj);
if (converted.Count == 0)
{
return;
}
// get path and collection
var path = _traversalContextUnpacker.GetCollectionPath(atomicContext).ToList();
// Always create collection - consumed objects will be cleaned up later
var objectCollection = CollectionRebuilder.GetOrCreateSpeckleCollectionFromPath(
path,
_colorUnpacker,
_materialUnpacker
);
if (obj is Speckle.Objects.Data.DataObject dataObject)
// nothing converted - nothing to do
if (converted.Count == 0)
{
// get color and mat on dataobject first
Color? dataObjColor = _colorUnpacker.Cache.TryGetValue(
dataObject.applicationId ?? "",
out var cachedDataObjColor
)
? cachedDataObjColor
: null;
SpeckleMaterialWrapper? dataObjMat = _materialUnpacker.Cache.TryGetValue(
dataObject.applicationId ?? "",
out var cachedDataObjMaterial
)
? cachedDataObjMaterial
: null;
// get geometries
List<SpeckleGeometryWrapper> geometries = new();
foreach ((object convertedObj, Base original) in converted)
{
if (convertedObj is GeometryBase geometryBase)
{
SpeckleGeometryWrapper wrapper =
new()
{
Base = original,
GeometryBase = geometryBase,
Color = _colorUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjColor)
? cachedObjColor
: dataObjColor,
Material = _materialUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjMaterial)
? cachedObjMaterial
: dataObjMat,
};
geometries.Add(wrapper);
}
}
SpecklePropertyGroupGoo propertyGroup = new();
propertyGroup.CastFrom(dataObject.properties);
// remove the displayvalue of the original dataobject since these are now processed and stored on the wrapper
// to prevent storing of duplicate Base
dataObject.displayValue.Clear();
var dataObjectWrapper = new SpeckleDataObjectWrapper()
{
Base = dataObject,
Geometries = geometries,
Path = path.Select(p => p.name).ToList(),
Parent = objectCollection,
Name = dataObject.name,
Properties = propertyGroup,
ApplicationId = dataObject.applicationId,
};
// Add to collections (not to map since these won't be definition objects)
CollectionRebuilder.AppendSpeckleGrasshopperObject(dataObjectWrapper, path, _colorUnpacker, _materialUnpacker);
return;
}
else
// handle normal DataObject (has converted geometry)
if (obj is DataObject normalDataObject)
{
SpecklePropertyGroupGoo propertyGroup = new();
if (obj[Constants.PROPERTIES_PROP] is Dictionary<string, object?> props)
{
propertyGroup.CastFrom(props);
}
var geometries = ConvertToGeometryWrappers(converted);
var dataObjectWrapper = CreateDataObjectWrapper(normalDataObject, geometries, path, objectCollection);
foreach ((object convertedObj, Base original) in converted)
CollectionRebuilder.AppendSpeckleGrasshopperObject(dataObjectWrapper, path, _colorUnpacker, _materialUnpacker);
return;
}
// handle normal geometry (not DataObject)
SpecklePropertyGroupGoo propertyGroup = new();
if (obj[Constants.PROPERTIES_PROP] is Dictionary<string, object?> props)
{
propertyGroup.CastFrom(props);
}
foreach ((object convertedObj, Base original) in converted)
{
if (convertedObj is GeometryBase geometryBase)
{
if (convertedObj is GeometryBase geometryBase)
var wrapper = new SpeckleGeometryWrapper()
{
var wrapper = new SpeckleGeometryWrapper()
{
Base = original,
Path = path.Select(p => p.name).ToList(),
Parent = objectCollection,
GeometryBase = geometryBase,
Properties = propertyGroup,
Name = obj[Constants.NAME_PROP] as string ?? "",
Color = _colorUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjColor)
? cachedObjColor
: null,
Material = _materialUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjMaterial)
? cachedObjMaterial
: null,
ApplicationId = objId
};
Base = original,
Path = path.Select(p => p.name).ToList(),
Parent = objectCollection,
GeometryBase = geometryBase,
Properties = propertyGroup,
Name = obj[Constants.NAME_PROP] as string ?? "",
Color = _colorUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjColor)
? cachedObjColor
: null,
Material = _materialUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjMaterial)
? cachedObjMaterial
: null,
ApplicationId = objId
};
// Always add to both map and collections
ConvertedObjectsMap[objId] = wrapper;
CollectionRebuilder.AppendSpeckleGrasshopperObject(wrapper, path, _colorUnpacker, _materialUnpacker);
}
ConvertedObjectsMap[objId] = wrapper;
CollectionRebuilder.AppendSpeckleGrasshopperObject(wrapper, path, _colorUnpacker, _materialUnpacker);
}
}
}
catch (Exception ex) when (!ex.IsFatal())
{
// TODO: throw?
// don't throw - continue processing other objects
_logger.LogError(ex, "Failed to convert object {objectId} of type {objectType}", objId, obj.speckle_type);
}
}
/// <summary>
/// Resolves a registered DataObject by transforming its InstanceProxy definition objects.
/// Requires definition objects to exist in ConvertedObjectsMap (populated by ConvertObjectToCache).
/// </summary>
private void ResolveDataObjectInstanceProxies(TraversalContext atomicContext)
{
var obj = atomicContext.Current;
if (obj is not DataObject dataObject)
{
return;
}
var dataObjectId = dataObject.applicationId ?? dataObject.id.NotNull();
if (!_dataObjectInstanceRegistry.IsRegistered(dataObjectId))
{
return;
}
try
{
var path = _traversalContextUnpacker.GetCollectionPath(atomicContext).ToList();
var objectCollection = CollectionRebuilder.GetOrCreateSpeckleCollectionFromPath(
path,
_colorUnpacker,
_materialUnpacker
);
var entry = _dataObjectInstanceRegistry.GetEntries()[dataObjectId];
var resolvedGeometries = ResolveInstanceProxiesToGeometries(entry.InstanceProxies);
var dataObjectWrapper = CreateDataObjectWrapper(dataObject, resolvedGeometries, path, objectCollection);
CollectionRebuilder.AppendSpeckleGrasshopperObject(dataObjectWrapper, path, _colorUnpacker, _materialUnpacker);
}
catch (Exception ex) when (!ex.IsFatal())
{
// don't throw - continue processing other DataObjects
_logger.LogError(ex, "Failed to resolve DataObject {dataObjectId} with InstanceProxies", dataObjectId);
}
}
/// <summary>
/// Converts block instances and definitions from traversal contexts into Grasshopper wrapper objects.
/// Automatically filters out InstanceProxies belonging to registered DataObjects.
/// Automatically handles cleanup of consumed objects from the collection hierarchy.
/// </summary>
/// <remarks>
/// Deliberately handles both block conversion AND consumed object cleanup in a single operation.
/// Too much, I know, BUT it ensures the cleanup always occurs immediately after block processing without
/// requiring receive components to call a separate cleanup method in the correct order.
/// </remarks>
public void ConvertBlockInstances(
IReadOnlyCollection<TraversalContext> blocks,
IReadOnlyCollection<InstanceDefinitionProxy>? definitionProxies
)
public void ConvertBlockInstances(IReadOnlyCollection<TraversalContext> blockInstances)
{
// build set of registered InstanceProxy IDs for fast lookup
var registeredProxyIds = new HashSet<string>();
foreach (var entry in _dataObjectInstanceRegistry.GetEntries().Values)
{
foreach (var proxy in entry.InstanceProxies)
{
var proxyId = proxy.applicationId ?? proxy.id;
if (proxyId is not null)
{
registeredProxyIds.Add(proxyId);
}
}
}
// filter out InstanceProxies that belong to registered DataObjects
var filteredBlockInstances = blockInstances
.Where(tc =>
{
if (tc.Current is InstanceProxy proxy)
{
var proxyId = proxy.applicationId ?? proxy.id;
return proxyId is null || !registeredProxyIds.Contains(proxyId);
}
return true;
})
.ToList();
var blockUnpacker = new GrasshopperBlockUnpacker(_traversalContextUnpacker, _colorUnpacker, _materialUnpacker);
// Get consumed object IDs from unpacker
// get consumed object IDs from unpacker
var consumedObjectIds = blockUnpacker.UnpackBlocks(
blocks,
definitionProxies,
filteredBlockInstances,
_definitionProxies,
ConvertedObjectsMap,
CollectionRebuilder
);
// Clean up consumed objects from collections
// clean up consumed objects from collections
CollectionRebuilder.RemoveConsumedObjects(consumedObjectIds);
}
/// <summary>
/// Creates a DataObjectWrapper from a DataObject and its geometries.
/// Handles color/material inheritance and property extraction.
/// </summary>
private SpeckleDataObjectWrapper CreateDataObjectWrapper(
DataObject dataObject,
List<SpeckleGeometryWrapper> geometries,
List<Collection> path,
SpeckleCollectionWrapper objectCollection
)
{
// Get color and material on DataObject
Color? dataObjColor = _colorUnpacker.Cache.TryGetValue(dataObject.applicationId ?? "", out var cachedDataObjColor)
? cachedDataObjColor
: null;
SpeckleMaterialWrapper? dataObjMat = _materialUnpacker.Cache.TryGetValue(
dataObject.applicationId ?? "",
out var cachedDataObjMaterial
)
? cachedDataObjMaterial
: null;
// Apply DataObject color/material to geometries that don't have their own
foreach (var geometry in geometries)
{
geometry.Color ??= dataObjColor;
geometry.Material ??= dataObjMat;
}
// Create property group
SpecklePropertyGroupGoo propertyGroup = new();
propertyGroup.CastFrom(dataObject.properties);
// Clear the displayValue to prevent storing duplicate Base
dataObject.displayValue.Clear();
return new SpeckleDataObjectWrapper()
{
Base = dataObject,
Geometries = geometries,
Path = path.Select(p => p.name).ToList(),
Parent = objectCollection,
Name = dataObject.name,
Properties = propertyGroup,
ApplicationId = dataObject.applicationId,
};
}
/// <summary>
/// Resolves InstanceProxy displayValues to transformed geometries.
/// Returns the list of resolved geometries that can be used as DataObject displayValue replacements.
/// </summary>
private List<SpeckleGeometryWrapper> ResolveInstanceProxiesToGeometries(List<InstanceProxy> instanceProxies)
{
var resolvedGeometries = new List<SpeckleGeometryWrapper>();
// build a lookup of definitionId -> definition objects for quick access
var definitionObjectsMap = new Dictionary<string, List<string>>();
if (_definitionProxies is not null)
{
foreach (var defProxy in _definitionProxies)
{
var defId = defProxy.applicationId ?? defProxy.id;
if (defId is not null)
{
definitionObjectsMap[defId] = defProxy.objects;
}
}
}
foreach (var instanceProxy in instanceProxies)
{
// get the definition objects for this instance
if (!definitionObjectsMap.TryGetValue(instanceProxy.definitionId, out var definitionObjectIds))
{
continue; // definition not found, skip this proxy
}
// get transform from the instance proxy
var transform = GrasshopperHelpers.MatrixToTransform(instanceProxy.transform, instanceProxy.units);
// apply transform to each definition object
foreach (var objectId in definitionObjectIds)
{
if (ConvertedObjectsMap.TryGetValue(objectId, out var definitionObject))
{
// deep copy and transform the geometry
var transformedWrapper = definitionObject.DeepCopy();
transformedWrapper.GeometryBase.NotNull().Transform(transform);
resolvedGeometries.Add(transformedWrapper);
}
}
}
return resolvedGeometries;
}
/// <summary>
/// Converts the raw converted objects to SpeckleGeometryWrappers for DataObject display values.
/// Does NOT apply DataObject-level colors/materials - that's handled by CreateDataObjectWrapper.
/// </summary>
private List<SpeckleGeometryWrapper> ConvertToGeometryWrappers(List<(object, Base)> converted)
{
var geometries = new List<SpeckleGeometryWrapper>();
foreach ((object convertedObj, Base original) in converted)
{
if (convertedObj is GeometryBase geometryBase)
{
SpeckleGeometryWrapper wrapper =
new()
{
Base = original,
GeometryBase = geometryBase,
// try to get color/material from the individual geometry first
Color = _colorUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjColor)
? cachedObjColor
: null,
Material = _materialUnpacker.Cache.TryGetValue(original.applicationId ?? "", out var cachedObjMaterial)
? cachedObjMaterial
: null,
};
geometries.Add(wrapper);
}
}
return geometries;
}
}
@@ -79,6 +79,9 @@ public class SpecklePropertyGoo : GH_Goo<object>, ISpecklePropertyGoo
case int i:
Value = i;
return true;
case long l:
Value = l;
return true;
case string s:
Value = s;
return true;
@@ -161,7 +161,12 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, ISpeckl
else
{
SpecklePropertyGoo entry = new();
entry.CastFrom(kvp.Value);
if (!entry.CastFrom(kvp.Value))
{
throw new ArgumentException(
$"Property '{kvp.Key}' has unsupported type '{kvp.Value?.GetType().Name ?? "null"}'"
);
}
val = entry;
}
@@ -15,6 +15,7 @@ using Speckle.Connectors.GrasshopperShared.Operations.Send;
using Speckle.Connectors.GrasshopperShared.Parameters;
using Speckle.Connectors.GrasshopperShared.Properties;
using Speckle.Converters.Common;
using Speckle.Converters.Common.ToHost;
using Speckle.Converters.Rhino;
using Speckle.Sdk;
using Speckle.Sdk.Models.GraphTraversal;
@@ -58,6 +59,8 @@ public class PriorityLoader : GH_AssemblyPriority
services.AddTransient<GrasshopperReceiveOperation>();
services.AddSingleton(DefaultTraversal.CreateTraversalFunc());
services.AddTransient<TraversalContextUnpacker>();
services.AddScoped<IDataObjectInstanceRegistry, DataObjectInstanceRegistry>();
services.AddTransient<LocalToGlobalMapHandler>();
// send
services.AddTransient<IRootObjectBuilder<SpeckleCollectionWrapperGoo>, GrasshopperRootObjectBuilder>();
@@ -307,9 +307,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -342,7 +342,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.rhino7": {
@@ -402,18 +402,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -423,14 +423,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
},
"System.Resources.Extensions": {
"type": "CentralTransitive",
@@ -307,9 +307,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -342,7 +342,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.rhino8": {
@@ -401,18 +401,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -422,14 +422,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
},
"System.Resources.Extensions": {
"type": "CentralTransitive",
@@ -236,9 +236,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -262,7 +262,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"speckle.converters.rhino8": {
@@ -312,18 +312,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -331,14 +331,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
},
"net8.0-windows7.0/win-x64": {
@@ -123,6 +123,12 @@ public class RhinoLayerBaker : TraversalContextUnpacker
}
var cleanNewLayerName = RhinoUtils.CleanLayerName(collection.name);
if (!ModelComponent.IsValidComponentName(cleanNewLayerName))
{
throw new SpeckleException($"Layer name '{currentLayerName}' is not valid");
}
Layer newLayer = new() { Name = cleanNewLayerName, ParentLayerId = previousLayer?.Id ?? Guid.Empty };
// set material
@@ -150,7 +156,7 @@ public class RhinoLayerBaker : TraversalContextUnpacker
int index = currentDocument.Layers.Add(newLayer);
if (index == -1)
{
throw new SpeckleException($"Could not create layer '{currentLayerName}'.");
throw new SpeckleException($"Could not create layer '{currentLayerName}'");
}
_hostLayerCache.Add(currentLayerName, index);
@@ -1,27 +1,41 @@
using System.Text;
namespace Speckle.Connectors.Rhino.HostApp;
public static class RhinoUtils
{
public static string CleanBlockDefinitionName(string str)
{
return ReplaceChars(str, @"\/", "_");
}
private static readonly HashSet<char> s_skipChars = ['[', ']', '(', ')', '{', '}'];
private static readonly HashSet<char> s_replaceWithHyphen = [':', ';'];
public static string CleanBlockDefinitionName(string str) => str.Replace('/', '_').Replace('\\', '_');
// Cleans up layer names to be "rhino" proof. Note this can be improved, as "()[] and {}" are illegal only at the start.
// https://docs.mcneel.com/rhino/6/help/en-us/index.htm#information/namingconventions.htm?Highlight=naming
public static string CleanLayerName(string str)
{
str = ReplaceChars(str, @"[](){}", "");
return ReplaceChars(str, @":;", "-");
}
var sb = new StringBuilder(str.Length);
private static string ReplaceChars(string str, string invalidChars, string replaceString)
{
foreach (char c in invalidChars)
foreach (char c in str)
{
str = str.Replace(c.ToString(), replaceString);
if (char.IsControl(c))
{
continue; // skip control characters (shoutout cnx-2809)
}
if (s_skipChars.Contains(c))
{
continue; // skip brackets
}
if (s_replaceWithHyphen.Contains(c))
{
sb.Append('-');
continue;
}
sb.Append(c);
}
return str;
return sb.ToString();
}
}
@@ -0,0 +1,65 @@
using Microsoft.Extensions.Logging;
using Rhino.DocObjects;
using Rhino.DocObjects.Tables;
using Speckle.Converters.Common;
using Speckle.Objects.Other;
using Speckle.Sdk;
namespace Speckle.Connectors.Rhino.HostApp;
public class RhinoViewUnpacker
{
private readonly IRootToSpeckleConverter _rootToSpeckleConverter;
private readonly ILogger<RhinoViewUnpacker> _logger;
public RhinoViewUnpacker(IRootToSpeckleConverter rootToSpeckleConverter, ILogger<RhinoViewUnpacker> logger)
{
_rootToSpeckleConverter = rootToSpeckleConverter;
_logger = logger;
}
private Camera? ConvertViewToCamera(ViewInfo view)
{
try
{
var converted = (Speckle.Objects.Other.Camera)_rootToSpeckleConverter.Convert(view);
if (converted is null)
{
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 a given set of rhino named views to create proxies
/// </summary>
/// <param name="views">current document named views</param>
/// <returns></returns>
public List<Camera> UnpackViews(NamedViewTable views)
{
List<Camera> cameras = new();
foreach (ViewInfo view in views)
{
// skip isometric views for now.
// getting the orthographic match between host apps and the viewer requires too much effort atm.
if (view.Viewport.IsParallelProjection)
{
continue;
}
if (ConvertViewToCamera(view) is Camera camera)
{
cameras.Add(camera);
}
}
return cameras;
}
}
@@ -33,6 +33,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
private readonly RhinoGroupUnpacker _groupUnpacker;
private readonly RhinoMaterialUnpacker _materialUnpacker;
private readonly RhinoColorUnpacker _colorUnpacker;
private readonly RhinoViewUnpacker _viewUnpacker;
private readonly PropertiesExtractor _propertiesExtractor;
private readonly ILogger<RhinoRootObjectBuilder> _logger;
private readonly ISdkActivityFactory _activityFactory;
@@ -46,6 +47,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
RhinoGroupUnpacker groupUnpacker,
RhinoMaterialUnpacker materialUnpacker,
RhinoColorUnpacker colorUnpacker,
RhinoViewUnpacker viewUnpacker,
PropertiesExtractor propertiesExtractor,
ILogger<RhinoRootObjectBuilder> logger,
ISdkActivityFactory activityFactory
@@ -59,6 +61,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
_rootToSpeckleConverter = rootToSpeckleConverter;
_materialUnpacker = materialUnpacker;
_colorUnpacker = colorUnpacker;
_viewUnpacker = viewUnpacker;
_propertiesExtractor = propertiesExtractor;
_logger = logger;
_activityFactory = activityFactory;
@@ -122,20 +125,30 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
throw new SpeckleException("Failed to convert all objects."); // fail fast instead creating empty commit! It will appear as model card error with red color.
}
// 4 - Unpack all proxies for the root
// Get all layers from the created collections on the root object commit for proxy processing
List<Layer> layers = _layerUnpacker.GetUsedLayers().ToList();
using (var _ = _activityFactory.Start("UnpackRenderMaterials"))
{
// 4 - Unpack the render material proxies
rootObjectCollection[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackRenderMaterials(atomicObjects, layers);
}
using (var _ = _activityFactory.Start("UnpackColors"))
{
// 5 - Unpack the color proxies
rootObjectCollection[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, layers);
}
// 5 - Unpack all other objects for the root
using (var _ = _activityFactory.Start("UnpackViews"))
{
List<Objects.Other.Camera> views = _viewUnpacker.UnpackViews(_converterSettings.Current.Document.NamedViews);
if (views.Count > 0)
{
rootObjectCollection[RootKeys.VIEW] = views;
}
}
return new RootObjectBuilderResult(rootObjectCollection, results);
}
@@ -92,6 +92,8 @@ public static class ServiceRegistration
serviceCollection.AddScoped<RhinoColorBaker>();
serviceCollection.AddScoped<RhinoColorUnpacker>();
serviceCollection.AddScoped<RhinoViewUnpacker>();
serviceCollection.AddScoped<PropertiesExtractor>();
serviceCollection.AddScoped<RevitMappingResolver>();
@@ -25,6 +25,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Extensions\AttributeExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\DataObjectInstanceGrouper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Properties\PropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RhinoViewUnpacker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RhinoIdleManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RhinoLayerHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RhinoObjectHelper.cs" />
@@ -63,4 +64,4 @@
<Compile Include="$(MSBuildThisFileDirectory)Plugin\Speckle.Connectors.RhinoCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Plugin\Speckle.Connectors.RhinoPlugin.cs" />
</ItemGroup>
</Project>
</Project>
@@ -326,9 +326,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -361,7 +361,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"LibTessDotNet": {
@@ -411,18 +411,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -432,14 +432,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -407,9 +407,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -442,7 +442,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"LibTessDotNet": {
@@ -492,18 +492,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -513,14 +513,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -407,9 +407,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -442,7 +442,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"LibTessDotNet": {
@@ -492,18 +492,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -513,14 +513,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -258,7 +258,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -287,18 +287,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -258,7 +258,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -287,18 +287,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -286,7 +286,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -330,18 +330,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -351,14 +351,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -211,9 +211,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -237,7 +237,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -281,18 +281,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -300,14 +300,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -211,9 +211,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -237,7 +237,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -281,18 +281,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -300,14 +300,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -22,8 +22,10 @@
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\ExtrusionXToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\SubDXToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\BrepXToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\SolidXToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\MeshToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\DataObjectConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Helpers\RawEncodingToHost.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Raw\AutocadPolycurveToHostPolyline2dRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Raw\AutocadPolycurveToHostPolyline3dRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Raw\AutocadPolycurveToHostPolylineRawConverter.cs" />
@@ -58,6 +60,8 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Properties\ExtensionDictionaryExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Properties\IPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Properties\PropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Encoding\RawEncodingCreator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Encoding\DisplayMeshExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\BrepToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\CircularArc2dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBArcToSpeckleRawConverter.cs" />
@@ -66,6 +70,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBLineToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBBodyToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBSolid3dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\Solid3dToSolidXRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBCurveToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\CircleToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\EllipseToSpeckleConverter.cs" />
@@ -0,0 +1,70 @@
using Speckle.Converters.Autocad.ToHost.Helpers;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Objects.Other;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
namespace Speckle.Converters.Autocad.Geometry;
/// <summary>
/// Converts a SolidX to AutoCAD Solid3d entities with lossless round-tripping via DWG encoding.
/// </summary>
[NameAndRankValue(typeof(SOG.SolidX), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
public class SolidXToHostConverter : IToHostTopLevelConverter, ITypedConverter<SOG.SolidX, List<(ADB.Entity a, Base b)>>
{
private readonly ITypedConverter<SOG.Mesh, ADB.PolyFaceMesh> _meshConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
private readonly ISdkActivityFactory _activityFactory;
public SolidXToHostConverter(
ITypedConverter<SOG.Mesh, ADB.PolyFaceMesh> meshConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore,
ISdkActivityFactory activityFactory
)
{
_meshConverter = meshConverter;
_settingsStore = settingsStore;
_activityFactory = activityFactory;
}
public object Convert(Base target) => Convert((SOG.SolidX)target);
public List<(ADB.Entity a, Base b)> Convert(SOG.SolidX target)
{
// Try to decode raw encoding first for lossless conversion
if (target.encodedValue?.format == RawEncodingFormats.ACAD_DWG)
{
try
{
var database = _settingsStore.Current.Document.Database;
List<ADB.Entity> entities = RawEncodingToHost.Convert(target, database);
if (entities.Count > 0)
{
// Successfully decoded - return the native entities
// Map all entities to the same source SolidX for tracking
return entities.Select(entity => ((ADB.Entity)entity, (Base)target)).ToList();
}
}
catch (ConversionException ex)
{
// Log the failure and fall through to displayValue fallback
using var activity = _activityFactory.Start("SolidX Raw Encoding Fallback");
activity?.SetStatus(SdkActivityStatusCode.Error);
activity?.RecordException(ex);
}
}
// Fallback: Convert displayValue meshes to PolyFaceMesh
var result = new List<ADB.PolyFaceMesh>();
foreach (SOG.Mesh mesh in target.displayValue)
{
ADB.PolyFaceMesh convertedMesh = _meshConverter.Convert(mesh);
result.Add(convertedMesh);
}
return result.Zip(target.displayValue, (a, b) => ((ADB.Entity)a, (Base)b)).ToList();
}
}
@@ -0,0 +1,104 @@
using Speckle.Objects.Other;
using Speckle.Sdk.Common.Exceptions;
namespace Speckle.Converters.Autocad.ToHost.Helpers;
/// <summary>
/// Handler for decoding raw-encoded objects (SolidX) back to ACAD/Civil entities.
/// </summary>
public static class RawEncodingToHost
{
#pragma warning disable IDE0060 // Remove unused parameter - kept for API consistency and future use
public static List<ADB.Entity> Convert(SOG.IRawEncodedObject target, ADB.Database targetDb)
#pragma warning restore IDE0060
{
if (target?.encodedValue == null)
{
throw new ArgumentNullException(nameof(target), "Raw encoded object or its encodedValue cannot be null.");
}
// Route to appropriate handler based on format
switch (target.encodedValue.format)
{
case RawEncodingFormats.ACAD_DWG:
return HandleDwg(target);
default:
throw new ConversionException(
$"Unsupported raw encoding format: {target.encodedValue.format}. Expected '{RawEncodingFormats.ACAD_DWG}'."
);
}
}
/// <summary>
/// Handles decoding of DWG binary format.
/// </summary>
private static List<ADB.Entity> HandleDwg(SOG.IRawEncodedObject target)
{
try
{
// Decode base64 to bytes
var dwgBytes = System.Convert.FromBase64String(target.encodedValue.contents);
// Create a temporary file for the DWG data
// (AutoCAD API requires a file path for reading DWG databases)
string tempFile = System.IO.Path.GetTempFileName();
string tempDwgFile = System.IO.Path.ChangeExtension(tempFile, ".dwg");
try
{
// Write DWG bytes to temp file
System.IO.File.WriteAllBytes(tempDwgFile, dwgBytes);
// Read the DWG database
using var sourceDb = new ADB.Database(false, true);
sourceDb.ReadDwgFile(tempDwgFile, System.IO.FileShare.Read, true, null);
// Extract entities from ModelSpace
var entities = new List<ADB.Entity>();
using var tr = sourceDb.TransactionManager.StartTransaction();
var bt = (ADB.BlockTable)tr.GetObject(sourceDb.BlockTableId, ADB.OpenMode.ForRead);
var btr = (ADB.BlockTableRecord)tr.GetObject(bt[ADB.BlockTableRecord.ModelSpace], ADB.OpenMode.ForRead);
foreach (ADB.ObjectId objId in btr)
{
if (tr.GetObject(objId, ADB.OpenMode.ForRead) is ADB.Entity entity)
{
// Clone the entity to ensure it's not tied to the source database
var clonedEntity = (ADB.Entity)entity.Clone();
entities.Add(clonedEntity);
}
}
tr.Commit();
return entities;
}
finally
{
// Clean up temporary files
try
{
if (System.IO.File.Exists(tempDwgFile))
{
System.IO.File.Delete(tempDwgFile);
}
if (System.IO.File.Exists(tempFile))
{
System.IO.File.Delete(tempFile);
}
}
#pragma warning disable CA1031 // Catching general exception for cleanup - failures are intentionally ignored
catch
{
// Ignore cleanup errors
}
#pragma warning restore CA1031
}
}
catch (System.Exception ex)
{
throw new ConversionException($"Failed to decode DWG format: {ex.Message}", ex);
}
}
}
@@ -0,0 +1,36 @@
using Speckle.Converters.Common.Objects;
using Speckle.Sdk.Common.Exceptions;
namespace Speckle.Converters.Autocad.ToSpeckle.Encoding;
/// <summary>
/// Extracts display meshes from AutoCAD geometry for visualization in the Speckle viewer.
/// Follows the BrepX pattern/
/// </summary>
internal static class DisplayMeshExtractor
{
public static List<SOG.Mesh> GetSpeckleMeshes(ADB.Solid3d solid, ITypedConverter<ABR.Brep, SOG.Mesh> meshConverter)
{
if (solid == null)
{
throw new ArgumentNullException(nameof(solid));
}
if (meshConverter == null)
{
throw new ArgumentNullException(nameof(meshConverter));
}
// Extract Brep from Solid3d
using ABR.Brep brep = new(solid);
if (brep.IsNull)
{
throw new ValidationException("Could not extract Brep from Solid3d for display mesh generation.");
}
// Convert Brep to Speckle mesh
SOG.Mesh displayMesh = meshConverter.Convert(brep);
return new List<SOG.Mesh> { displayMesh };
}
}
@@ -0,0 +1,84 @@
using System.Diagnostics.CodeAnalysis;
using Speckle.Objects.Other;
using Speckle.Sdk.Common;
using Speckle.Sdk.Common.Exceptions;
namespace Speckle.Converters.Autocad.ToSpeckle.Encoding;
/// <summary>
/// Creates raw encoded representations of AutoCAD geometry using DWG binary format.
/// </summary>
internal static class RawEncodingCreator
{
/// <summary>
/// Encodes an AutoCAD Solid3d to DWG binary format.
/// </summary>
public static RawEncoding Encode(ADB.Solid3d target, ADB.Database sourceDb) => Encode((ADB.Entity)target, sourceDb);
/// <summary>
/// Encodes any AutoCAD/Civil3D Entity to DWG binary format.
/// </summary>
public static RawEncoding Encode([NotNull] ADB.Entity? target, [NotNull] ADB.Database? sourceDb)
{
target.NotNull();
sourceDb.NotNull();
string tempFile = System.IO.Path.GetTempFileName();
string tempDwgFile = System.IO.Path.ChangeExtension(tempFile, ".dwg");
try
{
// Create a new in-memory database
using var tempDb = new ADB.Database(true, false);
// Copy unit settings from source database to preserve scale
tempDb.Insunits = sourceDb.Insunits;
// Open ModelSpace for write
using var tr = tempDb.TransactionManager.StartTransaction();
var bt = (ADB.BlockTable)tr.GetObject(tempDb.BlockTableId, ADB.OpenMode.ForRead);
var btr = (ADB.BlockTableRecord)tr.GetObject(bt[ADB.BlockTableRecord.ModelSpace], ADB.OpenMode.ForWrite);
// Clone the solid to the new database
var idMapping = new ADB.IdMapping();
var objectIds = new ADB.ObjectIdCollection { target.ObjectId };
sourceDb.WblockCloneObjects(objectIds, btr.ObjectId, idMapping, ADB.DuplicateRecordCloning.Replace, false);
tr.Commit();
// Save database to temp file as DWG
tempDb.SaveAs(tempDwgFile, ADB.DwgVersion.Current);
// Read file bytes and convert to base64
var dwgBytes = System.IO.File.ReadAllBytes(tempDwgFile);
var dwgString = System.Convert.ToBase64String(dwgBytes);
return new RawEncoding { contents = dwgString, format = RawEncodingFormats.ACAD_DWG };
}
catch (System.Exception ex)
{
throw new ConversionException($"Failed to encode Entity to DWG format: {ex.Message}", ex);
}
finally
{
// Clean up temporary files
try
{
if (System.IO.File.Exists(tempDwgFile))
{
System.IO.File.Delete(tempDwgFile);
}
if (System.IO.File.Exists(tempFile))
{
System.IO.File.Delete(tempFile);
}
}
#pragma warning disable CA1031 // Catching general exception for cleanup - failures are intentionally ignored
catch
{
// Ignore cleanup errors
}
#pragma warning restore CA1031
}
}
}
@@ -4,19 +4,22 @@ using Speckle.Sdk.Models;
namespace Speckle.Converters.Autocad.Geometry;
[NameAndRankValue(typeof(ADB.Solid3d), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
/// <summary>
/// Converts AutoCAD Solid3d entities to SolidX with DWG encoding.
/// </summary>
[NameAndRankValue(typeof(ADB.Solid3d), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK + 1)]
public class Solid3dToSpeckleConverter : IToSpeckleTopLevelConverter
{
private readonly ITypedConverter<ADB.Solid3d, SOG.Mesh> _solidConverter;
private readonly ITypedConverter<ADB.Solid3d, SOG.SolidX> _solidConverter;
public Solid3dToSpeckleConverter(ITypedConverter<ADB.Solid3d, SOG.Mesh> solidConverter)
public Solid3dToSpeckleConverter(ITypedConverter<ADB.Solid3d, SOG.SolidX> solidConverter)
{
_solidConverter = solidConverter;
}
public Base Convert(object target) => RawConvert((ADB.Solid3d)target);
public SOG.Mesh RawConvert(ADB.Solid3d target)
public SOG.SolidX RawConvert(ADB.Solid3d target)
{
return _solidConverter.Convert(target);
}
@@ -0,0 +1,77 @@
using Speckle.Converters.Autocad.ToSpeckle.Encoding;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk.Common.Exceptions;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
/// <summary>
/// Converts AutoCAD Solid3d entities to SolidX with DWG encoding.
/// </summary>
public class Solid3dToSolidXRawConverter : ITypedConverter<ADB.Solid3d, SOG.SolidX>
{
private readonly ITypedConverter<ABR.Brep, SOG.Mesh> _meshConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public Solid3dToSolidXRawConverter(
ITypedConverter<ABR.Brep, SOG.Mesh> meshConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_meshConverter = meshConverter;
_settingsStore = settingsStore;
}
public SOG.SolidX Convert(ADB.Solid3d target)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
var database = target.Database ?? throw new ConversionException("Solid3d entity must belong to a database.");
// Create raw encoding for round-tripping
var solidEncoding = RawEncodingCreator.Encode(target, database);
// Generate display meshes for viewer
List<SOG.Mesh> displayValue = DisplayMeshExtractor.GetSpeckleMeshes(target, _meshConverter);
// Calculate geometric properties
double volume = 0;
double area = 0;
try
{
using ABR.Brep brep = new(target);
if (!brep.IsNull)
{
area = brep.GetSurfaceArea();
try
{
volume = brep.GetVolume();
}
catch (ABR.Exception)
{
// Volume calculation can fail for non-volumetric solids
}
}
}
catch (System.Exception ex)
{
throw new ConversionException($"Failed to calculate geometric properties: {ex.Message}", ex);
}
// Create SolidX with all data
var solidX = new SOG.SolidX
{
displayValue = displayValue,
encodedValue = solidEncoding,
volume = volume,
area = area,
units = _settingsStore.Current.SpeckleUnits
};
return solidX;
}
}
@@ -258,7 +258,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -287,18 +287,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -209,7 +209,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -238,18 +238,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -257,14 +257,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -17,4 +17,4 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\EtabsShellSectionResolver.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\TopLevel\EtabsObjectToSpeckleConverter.cs" />
</ItemGroup>
</Project>
</Project>
@@ -267,7 +267,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -296,18 +296,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -317,14 +317,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -267,7 +267,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -296,18 +296,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -317,14 +317,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -267,7 +267,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -296,18 +296,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -317,14 +317,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -220,9 +220,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -246,7 +246,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -290,18 +290,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -309,14 +309,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -220,9 +220,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -246,7 +246,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -290,18 +290,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Data.Sqlite": "7.0.5",
@@ -309,14 +309,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -260,9 +260,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -279,7 +279,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -317,18 +317,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -338,14 +338,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -261,9 +261,9 @@
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Converters.Common": "[1.0.0, )",
"Speckle.Objects": "[3.9.0, )",
"Speckle.Sdk": "[3.9.0, )",
"Speckle.Sdk.Dependencies": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )",
"Speckle.Sdk": "[3.11.0-alpha, )",
"Speckle.Sdk.Dependencies": "[3.11.0-alpha, )"
}
},
"speckle.connectors.dui": {
@@ -280,7 +280,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.DependencyInjection": {
@@ -318,18 +318,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -339,14 +339,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}
@@ -1,38 +1,19 @@
using Microsoft.Extensions.Logging;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models;
using static Speckle.Converter.Navisworks.Helpers.ElementSelectionHelper;
namespace Speckle.Converter.Navisworks.ToSpeckle;
public class DisplayValueExtractor
public class DisplayValueExtractor(GeometryToSpeckleConverter geometryConverter)
{
private readonly IConverterSettingsStore<NavisworksConversionSettings> _converterSettings;
private readonly ILogger<DisplayValueExtractor> _logger;
private readonly GeometryToSpeckleConverter _geometryConverter;
public DisplayValueExtractor(
IConverterSettingsStore<NavisworksConversionSettings> converterSettings,
ILogger<DisplayValueExtractor> logger
)
{
_converterSettings = converterSettings;
_logger = logger;
_geometryConverter = new GeometryToSpeckleConverter(_converterSettings.Current);
}
internal List<Base> GetDisplayValue(NAV.ModelItem modelItem)
{
if (modelItem == null)
{
throw new ArgumentNullException(nameof(modelItem));
}
if (!modelItem.HasGeometry)
{
return [];
}
return !IsElementVisible(modelItem) ? [] : _geometryConverter.Convert(modelItem);
}
internal List<Base> GetDisplayValue(NAV.ModelItem modelItem) =>
modelItem == null
? throw new ArgumentNullException(nameof(modelItem))
: !modelItem.HasGeometry
? ([])
: !IsElementVisible(modelItem)
? []
:
// this can be meshes or the instance reference objects
// the un transformed objects stored in a separate collection
geometryConverter.Convert(modelItem);
}
@@ -1,10 +1,14 @@
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using static Speckle.Converter.Navisworks.Helpers.PropertyHelpers;
namespace Speckle.Converter.Navisworks.ToSpeckle;
public class PropertySetsExtractor(IConverterSettingsStore<NavisworksConversionSettings> settingsStore)
public class PropertySetsExtractor(
IConverterSettingsStore<NavisworksConversionSettings> settingsStore,
IPropertyConverter propertyConverter
)
{
internal Dictionary<string, object?>? GetPropertySets(NAV.ModelItem modelItem)
{
@@ -18,6 +22,17 @@ public class PropertySetsExtractor(IConverterSettingsStore<NavisworksConversionS
return propertyDictionary;
}
private static NAV.Units GetModelUnits(NAV.ModelItem modelItem)
{
NAV.ModelItem? ancestor = modelItem;
while (ancestor != null && !ancestor.HasModel)
{
ancestor = ancestor.Parent;
}
return ancestor != null ? ancestor.Model.Units : NAV.Units.Meters;
}
/// <summary>
/// Extracts property sets from a NAV.ModelItem and adds them to a dictionary,
/// PropertySets are specific to the host application source appended to Navisworks and therefore
@@ -28,10 +43,13 @@ public class PropertySetsExtractor(IConverterSettingsStore<NavisworksConversionS
private Dictionary<string, object?> ExtractPropertySets(NAV.ModelItem modelItem)
{
var propertySetDictionary = new Dictionary<string, object?>();
var modelUnits = GetModelUnits(modelItem);
propertyConverter.Reset();
foreach (var propertyCategory in modelItem.PropertyCategories)
{
if (IsCategoryToBeSkipped(propertyCategory))
if (ShouldSkipCategory(propertyCategory))
{
continue;
}
@@ -40,23 +58,18 @@ public class PropertySetsExtractor(IConverterSettingsStore<NavisworksConversionS
foreach (var property in propertyCategory.Properties)
{
string sanitizedName = SanitizePropertyName(property.DisplayName);
var propertyValue = ConvertPropertyValue(property.Value, settingsStore.Current.Derived.SpeckleUnits);
var sanitizedName = SanitizePropertyName(property.DisplayName);
var propertyValue = propertyConverter.ConvertPropertyValue(property.Value, modelUnits, property.DisplayName);
if (propertyValue != null)
{
propertySet[sanitizedName] = propertyValue;
}
}
if (propertySet.Count <= 0)
if (propertySet.Count > 0)
{
continue;
propertySetDictionary[SanitizePropertyName(propertyCategory.DisplayName)] = propertySet;
}
string categoryName = SanitizePropertyName(propertyCategory.DisplayName);
propertySetDictionary[categoryName] = propertySet;
}
return propertySetDictionary;
@@ -1,8 +1,10 @@
using static Speckle.Converter.Navisworks.Helpers.PropertyHelpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.InterfaceGenerator;
namespace Speckle.Converter.Navisworks.ToSpeckle;
public sealed class RevitBuiltInCategoryExtractor
[GenerateAutoInterface]
public class RevitBuiltInCategoryExtractor(IPropertyConverter converter) : IRevitBuiltInCategoryExtractor
{
private const int ANCESTOR_AND_SELF_COUNT = 4; // It seems like this is the maximum depth found needed in practice
private const string REVIT_CAT_GROUP = "LcRevitData_Element";
@@ -13,28 +15,28 @@ public sealed class RevitBuiltInCategoryExtractor
/// Attempts to map a Navisworks/Revit display category from the given model item or its ancestors
/// to a known Revit built-in category constant (e.g., "OST_Walls").
/// </summary>
internal static bool TryGetBuiltInCategory(
NAV.ModelItem item,
out string mapped,
int maxDepth = ANCESTOR_AND_SELF_COUNT
)
public bool TryGetBuiltInCategory(NAV.ModelItem item, out string mapped, int maxDepth = ANCESTOR_AND_SELF_COUNT)
{
mapped = string.Empty;
// Look up the category value, starting at this item and walking up to maxDepth ancestors
// Find the category VariantData up the hierarchy
var v = FindRevitCategoryInHierarchy(item, maxDepth);
if (v == null)
if (v is null)
{
return false;
}
var name = ConvertPropertyValue(v, "")?.ToString();
converter.Reset();
// Convert using per-object model units and current UI units
var nameObj = converter.ConvertPropertyValue(v, item.Model.Units, item.DisplayName);
var name = nameObj?.ToString();
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
name = name?.Trim();
name = name!.Trim();
// Map display name to OST_* built-in category constant
var builtInCategory = DisplayNameToRevitBuiltInCategory(name);
@@ -11,7 +11,8 @@ public class HierarchicalPropertyHandler(
PropertySetsExtractor propertySetsExtractor,
ModelPropertiesExtractor modelPropertiesExtractor,
ClassPropertiesExtractor classPropertiesExtractor,
IConverterSettingsStore<NavisworksConversionSettings> settingsStore
IConverterSettingsStore<NavisworksConversionSettings> settingsStore,
IRevitBuiltInCategoryExtractor revitCategoryExtractor
) : BasePropertyHandler(propertySetsExtractor, modelPropertiesExtractor)
{
private static string PseudoClassPropertiesKey => "_pseudoClassProperties";
@@ -22,7 +23,7 @@ public class HierarchicalPropertyHandler(
var propertyDict = classPropertiesExtractor.GetClassProperties(modelItem) ?? [];
// Interop-lite mapping for Revit built-in categories
if (_mapRevit && RevitBuiltInCategoryExtractor.TryGetBuiltInCategory(modelItem, out var builtInCategory))
if (_mapRevit && revitCategoryExtractor.TryGetBuiltInCategory(modelItem, out var builtInCategory))
{
PropertyHelpers.AddPropertyIfNotNullOrEmpty(
propertyDict,
@@ -46,6 +46,20 @@ public static class NavisworksConverterServiceRegistration
serviceCollection.AddScoped<DisplayValueExtractor>();
serviceCollection.AddScoped<GeometryToSpeckleConverter>();
// Register dual shared geometry stores for instancing pattern (.NET Framework compatible)
// Store 1: For geometry definitions (Mesh, Curve, etc.) - Store 2: For InstanceDefinitionProxy objects
serviceCollection.AddScoped<InstanceStoreManager>();
// Register ISharedGeometryStore interface using the geometry definitions store for backward compatibility
serviceCollection.AddScoped<ISharedGeometryStore>(provider =>
provider.GetRequiredService<InstanceStoreManager>().GeometryDefinitionsStore
);
// Register settings resolved from factory
serviceCollection.AddScoped<NavisworksConversionSettings>(sp =>
sp.GetRequiredService<INavisworksConversionSettingsFactory>().Current
);
return serviceCollection;
}
}
@@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
using System.Text.RegularExpressions;
using Speckle.Objects.Geometry;
@@ -8,6 +8,9 @@ public static class PropertyHelpers
{
private static readonly HashSet<string> s_excludedCategories = ["Geometry", "Metadata"];
/// <summary>
/// Adds a property to an object (either a Base object or a Dictionary) if the value is not null or empty.
/// </summary>
private static readonly Dictionary<NAV.VariantDataType, Func<NAV.VariantData, string, dynamic?>> s_typeHandlers =
new()
{
@@ -47,24 +50,15 @@ public static class PropertyHelpers
return handler(value, units);
}
// Default case for unsupported types
return value.DataType == NAV.VariantDataType.None || value.DataType == NAV.VariantDataType.Point2D
? null
: value.ToString();
return value.DataType is NAV.VariantDataType.None or NAV.VariantDataType.Point2D ? null : value.ToString();
}
/// <summary>
/// Adds a property to an object (either a Base object or a Dictionary) if the value is not null or empty.
/// </summary>
/// <param name="baseObject">The object to which the property is to be added. Can be either a Base object or a Dictionary.</param>
/// <param name="propertyName">The name of the property to add.</param>
/// <param name="value">The value of the property.</param>
internal static void AddPropertyIfNotNullOrEmpty(object baseObject, string propertyName, object? value)
{
switch (value)
{
case null:
break; // Do not add null values
break;
case string stringValue:
{
if (!string.IsNullOrEmpty(stringValue))
@@ -80,9 +74,6 @@ public static class PropertyHelpers
}
}
/// <summary>
/// Helper method to assign the property to the base object or dictionary.
/// </summary>
private static void AssignProperty(object baseObject, string propertyName, object value)
{
switch (baseObject)
@@ -98,16 +89,33 @@ public static class PropertyHelpers
}
}
/// <summary>
/// Sanitizes property names by replacing invalid characters with underscores.
/// </summary>
internal static string SanitizePropertyName(string name) =>
// Regex pattern from speckle-sharp/Core/Core/Models/DynamicBase.cs IsPropNameValid
name == "Item"
// Item is a reserved term for Indexed Properties: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/using-indexers
? "Item"
: Regex.Replace(name, @"[\.\/\s]", "_");
name == "Item" ? "Item" : Regex.Replace(name, @"[\.\/\s]", "_");
internal static bool IsCategoryToBeSkipped(NAV.PropertyCategory propertyCategory) =>
internal static bool ShouldSkipCategory(NAV.PropertyCategory propertyCategory) =>
s_excludedCategories.Contains(propertyCategory.DisplayName);
}
internal static class UnitLabels
{
internal static string Linear(NAV.Units u) =>
u switch
{
NAV.Units.Kilometers => "Kilometers",
NAV.Units.Meters => "Metres",
NAV.Units.Centimeters => "Centimeters",
NAV.Units.Millimeters => "Millimeters",
NAV.Units.Micrometers => "Micrometers",
NAV.Units.Miles => "Miles",
NAV.Units.Yards => "Yards",
NAV.Units.Feet => "Feet",
NAV.Units.Inches => "Inches",
NAV.Units.Mils => "Mils",
NAV.Units.Microinches => "Microinches",
_ => "Metres"
};
internal static string Area(NAV.Units u) => $"Square {Linear(u).ToLower()}";
public static string Volume(NAV.Units u) => $"Cubic {Linear(u).ToLower()}";
}
@@ -1,4 +1,4 @@
namespace Speckle.Converter.Navisworks.Constants;
namespace Speckle.Converter.Navisworks.Constants;
public static class PathConstants
{
@@ -6,3 +6,14 @@ public static class PathConstants
public const string MATERIAL_SEPARATOR = "::";
public const string SET_SEPARATOR = ">";
}
public static class InstanceConstants
{
public const string GEOMETRY_ID_PREFIX = "geom_";
public const string DEFINITION_ID_PREFIX = "def_";
}
public static class MaterialConstants
{
public const string DEFAULT_MATERIAL_NAME_PREFIX = "NavisworksMaterial_";
}
@@ -0,0 +1,141 @@
using Microsoft.Extensions.Logging;
using Speckle.Converter.Navisworks.Constants;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Converter.Navisworks.Services;
/// <summary>
/// Simple wrapper class that manages two SharedGeometryStores instances for dual instancing pattern.
/// Provides easy access to both mesh definitions store and instance definition proxies store.
/// </summary>
public class InstanceStoreManager(ILogger<InstanceStoreManager> logger)
{
private readonly ILogger<InstanceStoreManager> _logger = logger ?? throw new ArgumentNullException(nameof(logger));
/// <summary>
/// Store for geometry definitions (geometry data) - untransformed base geometries.
/// </summary>
internal SharedGeometryStore GeometryDefinitionsStore { get; } = new();
/// <summary>
/// Store for InstanceDefinitionProxy objects that reference geometry definitions.
/// </summary>
internal SharedGeometryStore InstanceDefinitionProxiesStore { get; } = new();
/// <summary>
/// Clears both stores for a new conversion session.
/// Should be called at the start of each conversion.
/// </summary>
public void ClearAll()
{
GeometryDefinitionsStore.Clear();
InstanceDefinitionProxiesStore.Clear();
}
/// <summary>
/// Gets all instance definition proxies from the store, cast to their specific type.
/// Useful for adding to root collection at end of conversion.
/// </summary>
public IReadOnlyCollection<InstanceDefinitionProxy> GetInstanceDefinitionProxies()
{
var proxies = InstanceDefinitionProxiesStore.Geometries.OfType<InstanceDefinitionProxy>().ToList().AsReadOnly();
_logger.LogDebug("GetInstanceDefinitionProxies returning {Count} proxies", proxies.Count);
return proxies;
}
/// <summary>
/// Gets all geometry definitions from the geometry definitions store.
/// </summary>
/// <returns></returns>
public List<Base> GetGeometryDefinitions() => [.. GeometryDefinitionsStore.Geometries.ToList().AsReadOnly()];
/// <summary>
/// Gets a geometry definition by its application ID from the geometry definitions store.
/// </summary>
/// <returns>The geometry if found, null otherwise.</returns>
public Base? GetGeometryDefinition(string fragmentId) =>
GeometryDefinitionsStore.Geometries.FirstOrDefault(g =>
g.applicationId == $"{InstanceConstants.GEOMETRY_ID_PREFIX}{fragmentId}"
);
/// <summary>
/// Gets an instance definition proxy by its application ID.
/// </summary>
/// <returns>The instance definition proxy if found, null otherwise.</returns>
public InstanceDefinitionProxy? GetInstanceDefinitionProxy(string fragmentId) =>
InstanceDefinitionProxiesStore
.Geometries.OfType<InstanceDefinitionProxy>()
.FirstOrDefault(p => p.applicationId == $"{InstanceConstants.DEFINITION_ID_PREFIX}{fragmentId}");
/// <summary>
/// Adds a geometry definition and corresponding instance definition proxy for shared geometry.
/// This is a convenience method that handles both stores in one call.
/// </summary>
/// <param name="fragmentId">The fragment-based application ID.</param>
/// <param name="geometry">The untransformed base geometry.</param>
/// <returns>True if both were added (new geometry), false if they already existed.</returns>
public bool AddSharedGeometry(string fragmentId, Base geometry)
{
_logger.LogDebug("AddSharedGeometry called for FragmentId={FragmentId}", fragmentId);
bool geometryAdded = false;
bool proxyAdded = false;
// Create prefixed IDs for 1:1:1 relationship using base fragment hash
var geometryId = $"{InstanceConstants.GEOMETRY_ID_PREFIX}{fragmentId}";
var definitionId = $"{InstanceConstants.DEFINITION_ID_PREFIX}{fragmentId}";
_logger.LogDebug("Using GeometryId={GeometryId}, DefinitionId={DefinitionId}", geometryId, definitionId);
// Add geometry definition if not exists
if (!GeometryDefinitionsStore.Contains(geometryId))
{
geometry.applicationId = geometryId;
geometryAdded = GeometryDefinitionsStore.Add(geometry);
_logger.LogDebug("Added geometry definition: {GeometryId}, Success={Success}", geometryId, geometryAdded);
}
else
{
_logger.LogDebug("Geometry definition already exists: {GeometryId}", geometryId);
}
// Add instance definition proxy if not exists
if (!InstanceDefinitionProxiesStore.Contains(definitionId))
{
var definitionProxy = new InstanceDefinitionProxy
{
applicationId = definitionId,
name = $"Shared Geometry {fragmentId[..8]}...", // Show first 8 chars for readability
objects = [geometry.applicationId],
maxDepth = 0
};
proxyAdded = InstanceDefinitionProxiesStore.Add(definitionProxy);
_logger.LogDebug("Added instance definition proxy: {DefinitionId}, Success={Success}", definitionId, proxyAdded);
}
else
{
_logger.LogDebug("Instance definition proxy already exists: {DefinitionId}", definitionId);
}
var conversionSucceededResult = geometryAdded || proxyAdded;
_logger.LogDebug(
"AddSharedGeometry completed: FragmentId={FragmentId}, Result={Result}, GeometryAdded={GeometryAdded}, ProxyAdded={ProxyAdded}",
fragmentId,
conversionSucceededResult,
geometryAdded,
proxyAdded
);
return conversionSucceededResult;
}
/// <summary>
/// Checks if shared geometry already exists in both stores.
/// </summary>
/// <param name="fragmentId">The fragment-based application ID.</param>
/// <returns>True if geometry definition exists in both stores.</returns>
public bool ContainsSharedGeometry(string fragmentId) =>
GeometryDefinitionsStore.Contains($"{InstanceConstants.GEOMETRY_ID_PREFIX}{fragmentId}")
// && InstanceDefinitionProxiesStore.Contains($"{InstanceConstants.DEFINITION_ID_PREFIX}{fragmentId}")
;
}
@@ -0,0 +1,91 @@
using System.Globalization;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.InterfaceGenerator;
namespace Speckle.Converter.Navisworks.Services;
[GenerateAutoInterface]
public class PropertyConverter(IUiUnitsCache uiUnitsCache) : IPropertyConverter
{
public void Reset() => uiUnitsCache.Reset();
public object? ConvertPropertyValue(NAV.VariantData? value, NAV.Units modelUnits, string propDisplayName) =>
value == null
? null
: _handlers.TryGetValue(value.DataType, out var f)
? f(value, (modelUnits, propDisplayName))
: value.DataType is NAV.VariantDataType.None or NAV.VariantDataType.Point2D
? null
: value.ToString();
private readonly Dictionary<
NAV.VariantDataType,
Func<NAV.VariantData, (NAV.Units model, string name), object?>
> _handlers =
new()
{
{ NAV.VariantDataType.Boolean, (v, _) => v.ToBoolean() },
{ NAV.VariantDataType.DisplayString, (v, _) => v.ToDisplayString() },
{ NAV.VariantDataType.IdentifierString, (v, _) => v.ToIdentifierString() },
{ NAV.VariantDataType.Int32, (v, _) => v.ToInt32() },
{ NAV.VariantDataType.Double, (v, _) => v.ToDouble() },
// Angle as dictionary with units
{ NAV.VariantDataType.DoubleAngle, (v, t) => NumObj(t.name, v.ToDoubleAngle(), "Degrees") },
// Length → dictionary in UI units
{
NAV.VariantDataType.DoubleLength,
(v, t) =>
{
var uiUnits = uiUnitsCache.Ensure();
var k = NAV.UnitConversion.ScaleFactor(t.model, uiUnits);
return NumObj(t.name, v.ToDoubleLength() * k, UnitLabels.Linear(uiUnits));
}
},
// Area → dictionary in UI units^2
{
NAV.VariantDataType.DoubleArea,
(v, t) =>
{
var uiUnits = uiUnitsCache.Ensure();
var k = NAV.UnitConversion.ScaleFactor(t.model, uiUnits);
k *= k;
return NumObj(t.name, v.ToDoubleArea() * k, UnitLabels.Area(uiUnits));
}
},
// Volume → dictionary in UI units^3
{
NAV.VariantDataType.DoubleVolume,
(v, t) =>
{
var uiUnits = uiUnitsCache.Ensure();
var k = NAV.UnitConversion.ScaleFactor(t.model, uiUnits);
k = k * k * k;
return NumObj(t.name, v.ToDoubleVolume() * k, UnitLabels.Volume(uiUnits));
}
},
{ NAV.VariantDataType.DateTime, (v, _) => v.ToDateTime().ToString(CultureInfo.InvariantCulture) },
{ NAV.VariantDataType.NamedConstant, (v, _) => v.ToNamedConstant().DisplayName },
{ NAV.VariantDataType.None, (_, _) => null },
{ NAV.VariantDataType.Point2D, (_, _) => null },
{
NAV.VariantDataType.Point3D,
(v, t) =>
{
var uiUnits = uiUnitsCache.Ensure();
var k = NAV.UnitConversion.ScaleFactor(t.model, uiUnits);
var p = v.ToPoint3D();
return new Speckle.Objects.Geometry.Point(p.X * k, p.Y * k, p.Z * k, UnitLabels.Linear(uiUnits));
}
}
};
private static Dictionary<string, object> NumObj(string name, double value, string units) =>
new()
{
["name"] = name,
["value"] = value,
["units"] = units
};
}
@@ -0,0 +1,92 @@
using Speckle.InterfaceGenerator;
using Speckle.Sdk.Models;
namespace Speckle.Converter.Navisworks.Services;
[GenerateAutoInterface]
public class SharedGeometryStore : ISharedGeometryStore
{
private readonly HashSet<Base> _geometries = new();
private readonly Dictionary<string, Base> _geometriesByApplicationId = new();
private readonly object _lock = new();
/// <summary>
/// Gets a read-only collection of all stored geometries.
/// </summary>
public IReadOnlyCollection<Base> Geometries
{
get
{
lock (_lock)
{
return _geometries.ToList().AsReadOnly();
}
}
}
/// <summary>
/// Adds a geometry to the store if it doesn't already exist.
/// </summary>
/// <param name="geometry">The geometry to add.</param>
/// <returns>True if the geometry was added, false if it already existed.</returns>
public bool Add(Base geometry)
{
if (geometry == null)
{
throw new ArgumentNullException(nameof(geometry));
}
if (string.IsNullOrEmpty(geometry.applicationId))
{
throw new ArgumentException("Geometry must have an applicationId for deduplication", nameof(geometry));
}
lock (_lock)
{
if (geometry.applicationId != null && _geometriesByApplicationId.ContainsKey(geometry.applicationId))
{
return false; // Already exists
}
_geometries.Add(geometry);
if (geometry.applicationId != null)
{
_geometriesByApplicationId[geometry.applicationId] = geometry;
}
return true; // Added successfully
}
}
/// <summary>
/// Checks if a geometry with the specified application ID already exists in the store.
/// </summary>
/// <param name="applicationId">The application ID to check for.</param>
/// <returns>True if a geometry with the application ID exists, false otherwise.</returns>
public bool Contains(string applicationId)
{
if (string.IsNullOrEmpty(applicationId))
{
return false;
}
lock (_lock)
{
var contains = _geometriesByApplicationId.ContainsKey(applicationId);
return contains;
}
}
/// <summary>
/// Clears all stored geometries for a new conversion session.
/// </summary>
public void Clear()
{
lock (_lock)
{
_geometries.Clear();
_geometriesByApplicationId.Clear();
}
}
}
@@ -0,0 +1,71 @@
using Autodesk.Navisworks.Api.Interop;
using Speckle.InterfaceGenerator;
using static Autodesk.Navisworks.Api.Interop.LcUOption;
namespace Speckle.Converter.Navisworks.Services;
[GenerateAutoInterface]
public class UiUnitsCache : IUiUnitsCache
{
private NAV.Units? _ui;
public NAV.Units Ensure()
{
if (_ui.HasValue)
{
return _ui.Value;
}
UiUnitsUtil.TryGetUiLinearUnits(out var ui);
_ui = ui;
return _ui.Value;
}
public void Reset() => _ui = null;
}
public static class UiUnitsUtil
{
// disp_units: 0=linear_format
public static bool TryGetUiLinearUnits(out NAV.Units uiUnits)
{
using var opt = new LcUOptionLock();
var root = GetRoot(opt);
var disp = root.GetSubOptions("interface").GetSubOptions("disp_units");
int code = -1;
using var v = new NAV.VariantData();
disp.GetValue(0, v);
var s = v.ToString();
var colon = s.LastIndexOf(':');
var open = s.IndexOf('(', colon + 1);
if (colon >= 0 && open > colon && !int.TryParse(s.Substring(colon + 1, open - colon - 1), out code))
{
code = -1;
}
uiUnits = code switch
{
0 => NAV.Units.Kilometers,
1 => NAV.Units.Meters,
2 => NAV.Units.Centimeters,
3 => NAV.Units.Millimeters,
4 => NAV.Units.Micrometers,
5 => NAV.Units.Miles,
6 => NAV.Units.Miles,
7 => NAV.Units.Yards,
8 => NAV.Units.Yards,
9 => NAV.Units.Feet,
10 => NAV.Units.Feet,
11 => NAV.Units.Feet,
12 => NAV.Units.Inches,
13 => NAV.Units.Inches,
14 => NAV.Units.Mils,
15 => NAV.Units.Microinches,
_ => NAV.Units.Meters
};
return code >= 0;
}
}
@@ -9,35 +9,39 @@
<Import_RootNamespace>Speckle.Converters.NavisworksShared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\ClassPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\DisplayValueExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\ModelPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\PropertySetsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\RevitBuiltInCategoryExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\BasePropertyHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\HierarchicalPropertyHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\IPropertyHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\StandardPropertyHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\NavisworksConverterServiceRegistration.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ArrayExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geometries\Primitives.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geometries\TransformMatrix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\ColorConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\HierarchyHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\ElementSelectionHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\PrimitiveProcessor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\PropertyHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GlobalUsing.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\GeometryHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PathConstants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\GeometryToSpeckleConverter.cs" />
<Folder Include="$(MSBuildThisFileDirectory)Models\" />
<Compile Include="$(MSBuildThisFileDirectory)Services\NavisworksToSpeckleUnitConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Settings\ConversionModes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Settings\NavisworksConversionSettings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Settings\NavisworksConversionSettingsFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\NavisworksRootToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\BoundingBoxToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\TopLevel\ModelItemTopLevelConverterToSpeckle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\ClassPropertiesExtractor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\DisplayValueExtractor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\ModelPropertiesExtractor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\PropertySetsExtractor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataExtractors\RevitBuiltInCategoryExtractor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\BasePropertyHandler.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\HierarchicalPropertyHandler.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\IPropertyHandler.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DataHandlers\StandardPropertyHandler.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\NavisworksConverterServiceRegistration.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ArrayExtensions.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Geometries\Primitives.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Geometries\TransformMatrix.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\ColorConverter.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\HierarchyHelper.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\ElementSelectionHelper.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\PrimitiveProcessor.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\PropertyHelpers.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)GlobalUsing.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Helpers\GeometryHelpers.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)PathConstants.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Services\PropertyConversion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\UIUnits.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Services\SharedGeometryStores.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Services\InstanceStoreManager.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\GeometryToSpeckleConverter.cs"/>
<Folder Include="$(MSBuildThisFileDirectory)Models\"/>
<Compile Include="$(MSBuildThisFileDirectory)Services\NavisworksToSpeckleUnitConverter.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Settings\ConversionModes.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Settings\NavisworksConversionSettings.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Settings\NavisworksConversionSettingsFactory.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\NavisworksRootToSpeckleConverter.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\BoundingBoxToSpeckleRawConverter.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\TopLevel\ModelItemTopLevelConverterToSpeckle.cs"/>
</ItemGroup>
</Project>
</Project>
@@ -1,4 +1,4 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
@@ -8,9 +8,6 @@ using Speckle.Sdk.Models;
namespace Speckle.Converter.Navisworks.ToSpeckle;
/// <summary>
/// Converts Navisworks ModelItem objects to Speckle Base objects.
/// </summary>
public class NavisworksRootToSpeckleConverter : IRootToSpeckleConverter
{
private readonly IConverterManager<IToSpeckleTopLevelConverter> _toSpeckle;
@@ -41,11 +38,8 @@ public class NavisworksRootToSpeckleConverter : IRootToSpeckleConverter
}
Type type = target.GetType();
var objectConverter = _toSpeckle.ResolveConverter(type, true);
Base result = objectConverter.Convert(modelItem);
result.applicationId = ElementSelectionHelper.ResolveModelItemToIndexPath(modelItem);
return result;
@@ -1,45 +1,47 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Autodesk.Navisworks.Api.Interop.ComApi;
using Speckle.Converter.Navisworks.Extensions;
using Microsoft.Extensions.Logging;
using Speckle.Converter.Navisworks.Constants;
using Speckle.Converter.Navisworks.Geometry;
using Speckle.Converter.Navisworks.Helpers;
using Speckle.Converter.Navisworks.Services;
using Speckle.Converter.Navisworks.Settings;
using Speckle.DoubleNumerics;
using Speckle.Objects.Geometry;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Instances;
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
namespace Speckle.Converter.Navisworks.ToSpeckle;
/// <summary>
/// Converts Navisworks geometry to Speckle displayable geometry.
///
/// Note: This class does not implement ITypedConverter{ModelGeometry, Base} because Navisworks geometry
/// conversion requires COM interop access that isn't available through the public ModelGeometry class.
/// The conversion process requires:
/// 1. Convert ModelItem to InwOaPath3 via ComApiBridge
/// 2. Use that to get InwOaFragmentList
/// 3. Process each InwOaFragment3 to generate primitives
/// 4. Convert those primitives to Speckle geometry with appropriate transforms
/// </summary>
public class GeometryToSpeckleConverter
/// <remarks>
/// Memory Safety: All COM objects (InwSelectionPathsColl, InwOaPath, InwOaFragmentList) are explicitly
/// released using Marshal.ReleaseComObject in try-finally blocks to prevent memory leaks.
/// NAV.Color objects are disposed using 'using' statements as they implement IDisposable.
/// </remarks>
public class GeometryToSpeckleConverter(
NavisworksConversionSettings settings,
InstanceStoreManager instanceStoreManager,
ILogger<GeometryToSpeckleConverter> logger
)
{
private readonly NavisworksConversionSettings _settings;
private readonly bool _isUpright;
private readonly SafeVector _transformVector;
private const double SCALE = 1.0; // Default scale factor
private readonly NavisworksConversionSettings _settings =
settings ?? throw new ArgumentNullException(nameof(settings));
public GeometryToSpeckleConverter(NavisworksConversionSettings settings)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
_isUpright = settings.Derived.IsUpright;
_transformVector = settings.Derived.TransformVector;
}
private readonly bool _isUpright = settings.Derived.IsUpright;
private readonly SafeVector _transformVector = settings.Derived.TransformVector;
private const double SCALE = 1.0;
private static readonly Matrix4x4 s_identityMatrix = new(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
private static readonly double[] s_identityTransform = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
/// <summary>
/// Converts a ModelItem's geometry to Speckle display geometry by accessing the underlying COM objects.
/// Applies necessary transformations and unit scaling.
/// </summary>
internal List<Base> Convert(NAV.ModelItem modelItem)
private readonly InstanceStoreManager _instanceStoreManager =
instanceStoreManager ?? throw new ArgumentNullException(nameof(instanceStoreManager));
private readonly ILogger<GeometryToSpeckleConverter> _logger =
logger ?? throw new ArgumentNullException(nameof(logger));
internal List<SSM.Base> Convert(NAV.ModelItem modelItem)
{
if (modelItem == null)
{
@@ -56,22 +58,42 @@ public class GeometryToSpeckleConverter
{
var fragmentStack = new Stack<InwOaFragment3>();
var paths = comSelection.Paths();
if (paths == null)
{
return [];
}
try
{
// Populate fragment stack with all fragments
if (paths.Count > 0)
{
var firstPath = paths.Cast<InwOaPath>().First();
var fragmentsCollection = firstPath.Fragments();
try
{
if (fragmentsCollection.Count > 1)
{
return ProcessSharedGeometry(paths, fragmentStack);
}
}
finally
{
if (fragmentsCollection != null)
{
Marshal.ReleaseComObject(fragmentsCollection);
}
}
}
foreach (InwOaPath path in paths)
{
CollectFragments(path, fragmentStack);
}
return ProcessFragments(fragmentStack, paths);
return ProcessFragments(fragmentStack, paths, true);
}
finally
{
if (paths != null)
{
Marshal.ReleaseComObject(paths);
}
Marshal.ReleaseComObject(paths);
}
}
finally
@@ -86,24 +108,61 @@ public class GeometryToSpeckleConverter
private static void CollectFragments(InwOaPath path, Stack<InwOaFragment3> fragmentStack)
{
var fragments = path.Fragments();
foreach (var fragment in fragments.OfType<InwOaFragment3>())
try
{
if (fragment.path?.ArrayData is not Array pathData1 || path.ArrayData is not Array pathData2)
foreach (var fragment in fragments.OfType<InwOaFragment3>())
{
continue;
if (AreFragmentPathsEqual(fragment, path))
{
fragmentStack.Push(fragment);
}
}
var pathArray1 = pathData1.ToArray<int>();
var pathArray2 = pathData2.ToArray<int>();
if (pathArray1.Length == pathArray2.Length && pathArray1.SequenceEqual(pathArray2))
}
finally
{
if (fragments != null)
{
fragmentStack.Push(fragment);
Marshal.ReleaseComObject(fragments);
}
}
}
private List<Base> ProcessFragments(Stack<InwOaFragment3> fragmentStack, InwSelectionPathsColl paths)
private List<SSM.Base> ProcessSharedGeometry(InwSelectionPathsColl paths, Stack<InwOaFragment3> fragmentStack)
{
var fragmentId = GenerateFragmentId(paths);
if (string.IsNullOrEmpty(fragmentId))
{
foreach (InwOaPath path in paths)
{
CollectFragments(path, fragmentStack);
}
return ProcessFragments(fragmentStack, paths, true);
}
if (_instanceStoreManager.ContainsSharedGeometry(fragmentId))
{
return CreateInstanceReference(fragmentId, paths);
}
foreach (InwOaPath path in paths)
{
CollectFragments(path, fragmentStack);
}
var baseGeometry = ExtractUntransformedGeometry(fragmentStack);
return baseGeometry == null || !_instanceStoreManager.AddSharedGeometry(fragmentId, baseGeometry)
? ProcessFragments(fragmentStack, paths) // default false flag for isSingleObject
: CreateInstanceReference(fragmentId, paths);
}
private List<SSM.Base> ProcessFragments(
Stack<InwOaFragment3> fragmentStack,
InwSelectionPathsColl paths,
bool isSingleObject = false
)
{
var callbackListeners = new List<PrimitiveProcessor>();
@@ -113,11 +172,6 @@ public class GeometryToSpeckleConverter
foreach (var fragment in fragmentStack)
{
if (!ValidateFragmentPath(fragment, path))
{
continue;
}
var matrix = fragment.GetLocalToWorldMatrix();
var transform = matrix as InwLTransform3f3;
if (transform?.Matrix is not Array matrixArray)
@@ -125,31 +179,43 @@ public class GeometryToSpeckleConverter
continue;
}
processor.LocalToWorldTransformation = ConvertArrayToDouble(matrixArray);
var fragmentsForCount = path.Fragments();
int fragmentCount;
try
{
fragmentCount = fragmentsForCount?.Count ?? 0;
}
finally
{
if (fragmentsForCount != null)
{
Marshal.ReleaseComObject(fragmentsForCount);
}
}
double[] makeNoChange = s_identityTransform;
double[] transformMatrix = ConvertArrayToDouble(matrixArray);
processor.LocalToWorldTransformation =
isSingleObject || fragmentCount == 1 ? transformMatrix : (IEnumerable<double>)makeNoChange;
fragment.GenerateSimplePrimitives(nwEVertexProperty.eNORMAL, processor);
}
callbackListeners.Add(processor);
}
var baseGeometries = ProcessGeometries(callbackListeners);
return baseGeometries;
return ProcessGeometries(callbackListeners);
}
private static bool ValidateFragmentPath(InwOaFragment3 fragment, InwOaPath path)
{
if (fragment.path?.ArrayData is not Array fragmentPathData || path.ArrayData is not Array pathData)
{
return false;
}
private static bool AreFragmentPathsEqual(InwOaFragment3 fragment, InwOaPath path) =>
fragment.path?.ArrayData is Array fragmentPathData
&& path.ArrayData is Array pathData
&& AreFragmentPathsEqual(fragmentPathData, pathData);
return IsSameFragmentPath(fragmentPathData, pathData);
}
private List<Base> ProcessGeometries(List<PrimitiveProcessor> processors)
private List<SSM.Base> ProcessGeometries(List<PrimitiveProcessor> processors)
{
var baseGeometries = new List<Base>();
var baseGeometries = new List<SSM.Base>();
foreach (var processor in processors)
{
@@ -178,7 +244,6 @@ public class GeometryToSpeckleConverter
{
var triangle = triangles[t];
// No need to worry about disposal of COM across boundaries - we're working with our safe structs
vertices.AddRange(
[
(triangle.Vertex1.X + _transformVector.X) * SCALE,
@@ -204,9 +269,8 @@ public class GeometryToSpeckleConverter
}
private List<Line> CreateLines(IReadOnlyList<SafeLine> lines) =>
(
from line in lines
select new Line
lines
.Select(line => new Line
{
start = new Point(
(line.Start.X + _transformVector.X) * SCALE,
@@ -221,10 +285,312 @@ public class GeometryToSpeckleConverter
_settings.Derived.SpeckleUnits
),
units = _settings.Derived.SpeckleUnits
}
).ToList();
})
.ToList();
private static double[]? ConvertArrayToDouble(Array arr)
public string GenerateFragmentId(InwSelectionPathsColl paths)
{
try
{
if (paths.Count == 0)
{
return string.Empty;
}
var fragmentHashes = new List<string>();
foreach (var fragments in from InwOaPath path in paths select path.Fragments())
{
try
{
var fragmentIndex = 0;
foreach (InwOaFragment3 fragment in fragments.OfType<InwOaFragment3>())
{
if (fragment.path?.ArrayData is not Array pathData || pathData.Length == 0)
{
fragmentIndex++;
continue;
}
try
{
if (pathData.Rank != 1)
{
var fragmentHashFallback = TrySimpleArrayEnumeration(pathData, fragmentIndex);
if (!string.IsNullOrEmpty(fragmentHashFallback))
{
fragmentHashes.Add(fragmentHashFallback);
}
fragmentIndex++;
continue;
}
var lowerBound = pathData.GetLowerBound(0);
var upperBound = pathData.GetUpperBound(0);
var arrayLength = upperBound - lowerBound + 1;
var pathInts = new int[arrayLength];
for (int i = lowerBound; i <= upperBound; i++)
{
try
{
var value = pathData.GetValue(i);
var arrayIndex = i - lowerBound;
pathInts[arrayIndex] = System.Convert.ToInt32(value);
}
catch (Exception ex) when (ex is COMException or InvalidCastException)
{
var errorType = ex is COMException ? "COM array access failed" : "Type conversion failed";
_logger.LogDebug(ex, "{ErrorType} at index {Index}", errorType, i);
}
}
var fragmentHash = string.Join("_", pathInts);
fragmentHashes.Add(fragmentHash);
}
catch (Exception ex) when (ex is COMException or IndexOutOfRangeException or RankException)
{
var errorType = ex switch
{
COMException => "COM access failed",
IndexOutOfRangeException => "Array bounds exceeded",
RankException => "Array rank mismatch",
_ => "Error"
};
_logger.LogDebug(
ex,
"{ErrorType} processing fragment {FragmentIndex}, trying simple enumeration",
errorType,
fragmentIndex
);
var fragmentHash = TrySimpleArrayEnumeration(pathData, fragmentIndex);
if (!string.IsNullOrEmpty(fragmentHash))
{
fragmentHashes.Add(fragmentHash);
}
fragmentIndex++;
continue;
}
fragmentIndex++;
}
}
finally
{
if (fragments != null)
{
Marshal.ReleaseComObject(fragments);
}
}
}
if (fragmentHashes.Count > 0)
{
fragmentHashes.Sort();
var rawData = string.Join("__", fragmentHashes);
var fragmentId = HashRawData(rawData);
return fragmentId;
}
return string.Empty;
}
catch (Exception ex) when (ex is COMException or InvalidCastException or IndexOutOfRangeException)
{
var errorType = ex switch
{
COMException => "COM access failed",
InvalidCastException => "Type conversion failed",
IndexOutOfRangeException => "Array bounds exceeded",
_ => "Error"
};
_logger.LogWarning(ex, "{ErrorType} generating fragment ID", errorType);
return string.Empty;
}
}
private string TrySimpleArrayEnumeration(Array pathData, int fragmentIndex)
{
try
{
var values = new List<string>();
var maxAttempts = Math.Min(pathData.Length, 20);
for (int i = 0; i < maxAttempts; i++)
{
try
{
var value = pathData.GetValue(i);
var convertedValue = System.Convert.ToInt32(value);
values.Add(convertedValue.ToString());
}
catch (IndexOutOfRangeException)
{
break;
}
catch (InvalidCastException ex)
{
_logger.LogDebug(ex, "Type conversion failed at index {Index}", i);
}
}
if (values.Count <= 0)
{
return string.Empty;
}
return string.Join("_", values);
}
catch (COMException ex)
{
_logger.LogDebug(ex, "COM enumeration failed for fragment {FragmentIndex}", fragmentIndex);
return string.Empty;
}
}
private static string HashRawData(string rawData)
{
using var sha256 = SHA256.Create();
var inputBytes = Encoding.UTF8.GetBytes(rawData);
var hashBytes = sha256.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
private SSM.Base? ExtractUntransformedGeometry(Stack<InwOaFragment3> fragmentStack)
{
var processor = new PrimitiveProcessor(_isUpright);
foreach (var fragment in fragmentStack)
{
processor.LocalToWorldTransformation = s_identityTransform;
fragment.GenerateSimplePrimitives(nwEVertexProperty.eNORMAL, processor);
}
return processor.Triangles.Count > 0 ? CreateMesh(processor.Triangles) : null;
}
private List<SSM.Base> CreateInstanceReference(string fragmentId, InwSelectionPathsColl paths)
{
var transform = ExtractInstanceTransform(paths);
var instanceReference = new InstanceProxy
{
definitionId = $"{InstanceConstants.DEFINITION_ID_PREFIX}{fragmentId}",
transform = transform,
units = _settings.Derived.SpeckleUnits,
maxDepth = 0,
applicationId = Guid.NewGuid().ToString()
};
return [instanceReference];
}
private Matrix4x4 ExtractInstanceTransform(InwSelectionPathsColl paths)
{
try
{
if (paths.Count == 0)
{
return s_identityMatrix;
}
var firstPath = paths.Cast<InwOaPath>().First();
var fragments = firstPath.Fragments();
try
{
if (fragments.Count == 0)
{
return s_identityMatrix;
}
var fragmentStack = new Stack<InwOaFragment3>();
foreach (var frag in fragments.OfType<InwOaFragment3>())
{
if (frag.path?.ArrayData is not Array pathData1 || firstPath.ArrayData is not Array pathData2)
{
continue;
}
var pathArray1 = pathData1.Cast<int>().ToArray();
var pathArray2 = pathData2.Cast<int>().ToArray();
if (pathArray1.Length == pathArray2.Length && pathArray1.SequenceEqual(pathArray2))
{
fragmentStack.Push(frag);
}
}
var fragment = fragmentStack.First();
var matrix = fragment.GetLocalToWorldMatrix();
if (matrix is InwLTransform3f3 { Matrix: Array matrixArray })
{
var transformArray = ConvertArrayToDouble(matrixArray);
var transformedMatrix = ApplyCoordinateTransform(transformArray);
var newMatrix = new Matrix4x4(
transformedMatrix[0],
transformedMatrix[1],
transformedMatrix[2],
transformedMatrix[3],
transformedMatrix[4],
transformedMatrix[5],
transformedMatrix[6],
transformedMatrix[7],
transformedMatrix[8],
transformedMatrix[9],
transformedMatrix[10],
transformedMatrix[11],
transformedMatrix[12],
transformedMatrix[13],
transformedMatrix[14],
transformedMatrix[15]
);
return Matrix4x4.Transpose(newMatrix);
}
}
finally
{
if (fragments != null)
{
Marshal.ReleaseComObject(fragments);
}
}
}
catch (Exception ex) when (ex is COMException or InvalidCastException or NullReferenceException)
{
var errorType = ex switch
{
COMException => "COM access failed",
InvalidCastException => "Transform matrix type conversion failed",
NullReferenceException => "Null reference",
_ => "Error"
};
_logger.LogWarning(ex, "{ErrorType} extracting instance transform", errorType);
}
return s_identityMatrix;
}
private double[] ApplyCoordinateTransform(double[] matrixArray)
{
var result = new double[16];
Array.Copy(matrixArray, result, 16);
result[12] = (result[12] + _transformVector.X) * SCALE;
result[13] = (result[13] + _transformVector.Y) * SCALE;
result[14] = (result[14] + _transformVector.Z) * SCALE;
return result;
}
private static double[] ConvertArrayToDouble(Array arr)
{
if (arr.Rank != 1)
{
@@ -240,6 +606,6 @@ public class GeometryToSpeckleConverter
return doubleArray;
}
private static bool IsSameFragmentPath(Array a1, Array a2) =>
private static bool AreFragmentPathsEqual(Array a1, Array a2) =>
a1.Length == a2.Length && a1.Cast<int>().SequenceEqual(a2.Cast<int>());
}
@@ -1,4 +1,4 @@
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.Settings;
using Speckle.Converter.Navisworks.ToSpeckle.PropertyHandlers;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
@@ -258,7 +258,7 @@
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Objects": "[3.9.0, )"
"Speckle.Objects": "[3.11.0-alpha, )"
}
},
"Microsoft.Extensions.Logging": {
@@ -287,18 +287,18 @@
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "fAOUhScCfDFVVynvipczjyw9RZlOgPOo8aH5A7EDAwZiDuDdd4EsnrqBCSPlmuoPYzY7hsN+5mfRkfw2rB36Ig==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "SY/kQ7VaydugVxlqqjQXXsMWdNkS5GntAVytIonQp7OaOKWrnUZeN165ADbGkWneY8Fb6vB2fVyiz3yfSm3EhA==",
"dependencies": {
"Speckle.Sdk": "3.9.0"
"Speckle.Sdk": "3.11.0-alpha"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "GtbvnySinrE6Canm6fVjyUOxs4G1bw0aRLs9oPVMdodOKc9TxIQjp1lzVBtr6Jli+nzIxtC86xP5J6r9tufnrQ==",
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "pzdfq9bDiRRAjr44c8xROCZ+lROhrW400ZPFaZsSnpkTfp57DvJlXEW/hfwpzeeLnA4kj9AviHZtyJOiDBWFhg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
@@ -308,14 +308,14 @@
"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": "3.11.0-alpha"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.9.0, )",
"resolved": "3.9.0",
"contentHash": "m/3i+DX/1McN8ig0CcjmHM1BcNmNxgmny/735sKntzzDw23wdo868eOOTrogzmDoYHTyc7J4IjK+GE7iAyWn/g=="
"requested": "[3.11.0-alpha, )",
"resolved": "3.11.0-alpha",
"contentHash": "//0uk6ELZ4aoEpg9p8pwtxcqfcjETt4ACCn9HIfiLhfhwCDWYCBYD1x2+bODAC5tmZRwyISQBE1hAHFHnzAjBg=="
}
}
}

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