Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b485a4ff6f | |||
| 5697afc292 | |||
| 4ec45d3cd5 | |||
| ac1345bbaf |
+1
-4
@@ -66,10 +66,7 @@ public static class Affected
|
||||
Console.WriteLine("Affected project group being built: " + group.HostAppSlug);
|
||||
}
|
||||
|
||||
if (groups.Count > 0)
|
||||
{
|
||||
return groups.ToArray();
|
||||
}
|
||||
return groups.ToArray();
|
||||
}
|
||||
|
||||
Console.WriteLine("Using all project groups: " + string.Join(',', Consts.ProjectGroups));
|
||||
|
||||
@@ -3,8 +3,6 @@ using Autodesk.Revit.DB;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.RevitShared;
|
||||
using Speckle.Connectors.RevitShared.Operations.Send.Filters;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Sdk.Common;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
@@ -16,14 +14,9 @@ namespace Speckle.Connectors.Revit.HostApp;
|
||||
/// </summary>
|
||||
public class LinkedModelHandler
|
||||
{
|
||||
private readonly RevitContext _revitContext;
|
||||
// Dictionary to track linked model display names
|
||||
public Dictionary<string, string> LinkedModelDisplayNames { get; } = new();
|
||||
|
||||
public LinkedModelHandler(RevitContext revitContext)
|
||||
{
|
||||
_revitContext = revitContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets elements from a linked document based on the provided send filter.
|
||||
/// This method handles the specifics of element collection but doesn't make decisions
|
||||
@@ -45,36 +38,6 @@ public class LinkedModelHandler
|
||||
}
|
||||
return new List<Element>();
|
||||
}
|
||||
|
||||
// send mode → Views (taken from the legacy code)
|
||||
if (sendFilter is RevitViewsFilter viewFilter && viewFilter.GetView() != null)
|
||||
{
|
||||
RevitLinkInstance linkInstance = FindLinkInstanceForDocument(
|
||||
linkedDocument.PathName,
|
||||
_revitContext.UIApplication.NotNull().ActiveUIDocument.Document
|
||||
);
|
||||
|
||||
#if REVIT2024_OR_GREATER
|
||||
// revit 2024 and 2025 we can use the three-parameter constructor to get only visible elements
|
||||
using var viewCollector = new FilteredElementCollector(
|
||||
_revitContext.UIApplication.ActiveUIDocument.Document,
|
||||
viewFilter.GetView().NotNull().Id,
|
||||
linkInstance.Id
|
||||
);
|
||||
return viewCollector.WhereElementIsNotElementType().ToElements().ToList();
|
||||
#else
|
||||
// 🚨 LIMITATION: in Revit 2023 and below, we can only check if the entire linked model is visible,
|
||||
// not individual elements within it. If the linked model is visible, all its elements will be included.
|
||||
// constructor overload pertaining to searching and filtering visible elements from a revit link only added 2024.
|
||||
if (linkInstance.IsHidden(viewFilter.GetView().NotNull()))
|
||||
{
|
||||
return new List<Element>(); // if the linked model is hidden, return no elements
|
||||
}
|
||||
// 💩 fallback to getting all elements if the linked model is visible
|
||||
return GetAllElementsForLinkedModelSelection(linkedDocument);
|
||||
#endif
|
||||
}
|
||||
|
||||
// send mode → Selection
|
||||
return GetAllElementsForLinkedModelSelection(linkedDocument);
|
||||
}
|
||||
@@ -165,14 +128,4 @@ public class LinkedModelHandler
|
||||
using var collector = new FilteredElementCollector(linkedDoc);
|
||||
return collector.WhereElementIsNotElementType().WhereElementIsViewIndependent().ToList();
|
||||
}
|
||||
|
||||
private RevitLinkInstance FindLinkInstanceForDocument(string linkedDocumentPath, Document mainDocument)
|
||||
{
|
||||
using var collector = new FilteredElementCollector(mainDocument);
|
||||
return collector
|
||||
.OfClass(typeof(RevitLinkInstance))
|
||||
.Cast<RevitLinkInstance>()
|
||||
.FirstOrDefault(link => link.GetLinkDocument()?.PathName == linkedDocumentPath)
|
||||
.NotNull();
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -5,6 +5,7 @@ using Speckle.Connectors.Common.Caching;
|
||||
using Speckle.Connectors.Common.Conversion;
|
||||
using Speckle.Connectors.Common.Extensions;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Threading;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Connectors.Revit.HostApp;
|
||||
using Speckle.Converters.Common;
|
||||
@@ -22,6 +23,7 @@ public class RevitRootObjectBuilder(
|
||||
IConverterSettingsStore<RevitConversionSettings> converterSettings,
|
||||
ISendConversionCache sendConversionCache,
|
||||
ElementUnpacker elementUnpacker,
|
||||
IThreadContext threadContext,
|
||||
SendCollectionManager sendCollectionManager,
|
||||
ILogger<RevitRootObjectBuilder> logger,
|
||||
RevitToSpeckleCacheSingleton revitToSpeckleCacheSingleton,
|
||||
@@ -33,6 +35,16 @@ public class RevitRootObjectBuilder(
|
||||
SendInfo sendInfo,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken ct = default
|
||||
) =>
|
||||
threadContext.RunOnMainAsync(
|
||||
() => Task.FromResult(BuildSync(documentElementContexts, sendInfo, onOperationProgressed, ct))
|
||||
);
|
||||
|
||||
private RootObjectBuilderResult BuildSync(
|
||||
IReadOnlyList<DocumentToConvert> documentElementContexts,
|
||||
SendInfo sendInfo,
|
||||
IProgress<CardProgress> onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var doc = converterSettings.Current.Document;
|
||||
@@ -143,7 +155,7 @@ public class RevitRootObjectBuilder(
|
||||
var atomicObjects = atomicObjectByDocumentAndTransform.Elements;
|
||||
foreach (Element revitElement in atomicObjects)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
string applicationId = revitElement.UniqueId;
|
||||
string sourceType = revitElement.GetType().Name;
|
||||
try
|
||||
@@ -229,6 +241,6 @@ public class RevitRootObjectBuilder(
|
||||
// NOTE: these are currently not used anywhere, we'll skip them until someone calls for it back
|
||||
// rootObject[ProxyKeys.PARAMETER_DEFINITIONS] = _parameterDefinitionHandler.Definitions;
|
||||
|
||||
return Task.FromResult(new RootObjectBuilderResult(rootObject, results));
|
||||
return new RootObjectBuilderResult(rootObject, results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public abstract class DocumentModelStore(IJsonSerializer serializer)
|
||||
}
|
||||
}
|
||||
|
||||
protected string Serialize() => serializer.Serialize(Models.ToList());
|
||||
protected string Serialize() => serializer.Serialize(Models);
|
||||
|
||||
// POC: this seemms more like a IModelsDeserializer?, seems disconnected from this class
|
||||
protected List<ModelCard> Deserialize(string models) => serializer.Deserialize<List<ModelCard>>(models).NotNull();
|
||||
|
||||
@@ -15,18 +15,32 @@ namespace Speckle.Importers.Ifc.Tester2;
|
||||
public sealed class IfcTester(IClientFactory clientFactory, Importer importer, IAccountManager accountManager)
|
||||
{
|
||||
// Settings, Change these to suit!
|
||||
private readonly FilePath _filePath =
|
||||
//new(@"C:\Users\Jedd\Desktop\GRAPHISOFT_Archicad_Sample_Project-S-Office_v1.0_AC25.ifc");
|
||||
new(@"C:\Users\Jedd\Desktop\EST-BRE-AF-3D-BT1-30-SD-00001-A-P.ifc");
|
||||
// private readonly ICollection<FilePath> _filePath = [new(@"C:\Users\Jedd\Desktop\GRAPHISOFT_Archicad_Sample_Project-S-Office_v1.0_AC25.ifc")]
|
||||
private readonly IEnumerable<string> _filePaths = Directory.EnumerateFiles(@"C:\Users\Jedd\Desktop\", "*.ifc");
|
||||
|
||||
private readonly Uri _serverUrl = new("https://app.speckle.systems");
|
||||
private const string PROJECT_ID = "f3a42bdf24";
|
||||
|
||||
public async Task Run()
|
||||
public async Task Run(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var account = accountManager.GetAccounts(_serverUrl).First();
|
||||
using var speckleClient = clientFactory.Create(account);
|
||||
string modelName = _filePath.GetFileName();
|
||||
var existing = await speckleClient.Project.GetWithModels(PROJECT_ID, 1, modelsFilter: new(search: modelName));
|
||||
|
||||
foreach (var path in _filePaths)
|
||||
{
|
||||
await ImportFile(speckleClient, path, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportFile(Client speckleClient, FilePath filePath, CancellationToken cancellationToken)
|
||||
{
|
||||
string modelName = filePath.GetFileName();
|
||||
var existing = await speckleClient.Project.GetWithModels(
|
||||
PROJECT_ID,
|
||||
1,
|
||||
modelsFilter: new(search: modelName),
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
string? existingModel = existing.models.items.Count >= 1 ? existing.models.items.First().id : null;
|
||||
|
||||
// Convert IFC to Speckle Objects
|
||||
@@ -35,14 +49,14 @@ public sealed class IfcTester(IClientFactory clientFactory, Importer importer, I
|
||||
new()
|
||||
{
|
||||
ServerUrl = _serverUrl,
|
||||
FilePath = _filePath.ToString(),
|
||||
FilePath = filePath.ToString(),
|
||||
ProjectId = PROJECT_ID,
|
||||
ModelId = existingModel,
|
||||
ModelName = _filePath.GetFileName(),
|
||||
ModelName = filePath.GetFileName(),
|
||||
VersionMessage = "",
|
||||
Token = account.token
|
||||
Token = speckleClient.Account.token
|
||||
};
|
||||
var version = await importer.ImportIfc(args, null, default);
|
||||
var version = await importer.ImportIfc(args, null, cancellationToken);
|
||||
Console.WriteLine($"File was successfully sent {version.id}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Speckle.Importers.Ifc.Ara3D.IfcParser.Schema;
|
||||
using Speckle.Importers.Ifc.Ara3D.IfcParser.Schema;
|
||||
using Speckle.Importers.Ifc.Ara3D.StepParser;
|
||||
|
||||
namespace Speckle.Importers.Ifc.Ara3D.IfcParser;
|
||||
@@ -34,20 +33,19 @@ public class IfcEntity
|
||||
|
||||
public override string ToString() => $"{Type}#{Id}";
|
||||
|
||||
[MemberNotNullWhen(true, nameof(Guid))]
|
||||
public bool IsIfcRoot => Count >= 4 && this[0] is StepString && (this[1] is StepId) || (this[1] is StepUnassigned);
|
||||
|
||||
// Modern IFC files conform to this, but older ones have been observed to have different length IDs.
|
||||
// Leaving as a comment for now.
|
||||
//&& str.Value.Length == 22;
|
||||
|
||||
public string? Guid => IsIfcRoot ? ((StepString)this[0]).Value.ToString() : null;
|
||||
public string Guid => ((StepString)this[0]).Value.ToString();
|
||||
|
||||
public uint OwnerId => IsIfcRoot ? (this[1] as StepId)?.Id ?? 0 : 0;
|
||||
public uint OwnerId => (this[1] as StepId)?.Id ?? 0;
|
||||
|
||||
public string? Name => IsIfcRoot ? (this[2] as StepString)?.AsString() : null;
|
||||
public string? Name => (this[2] as StepString)?.AsString();
|
||||
|
||||
public string? Description => IsIfcRoot ? (this[3] as StepString)?.AsString() : null;
|
||||
public string? Description => (this[3] as StepString)?.AsString();
|
||||
|
||||
public int Count => LineData.Count;
|
||||
|
||||
|
||||
@@ -11,9 +11,6 @@ public sealed class DataObjectConverter(IGeometryConverter geometryConverter) :
|
||||
{
|
||||
public DataObject Convert(IfcModel model, IfcNode node, INodeConverter childrenConverter)
|
||||
{
|
||||
if (!node.IsIfcRoot)
|
||||
throw new ArgumentException("Expected to be an IfcRoot", paramName: nameof(node));
|
||||
|
||||
// Even if there is no geometry, this will return an empty collection.
|
||||
var geo = model.GetGeometry(node.Id);
|
||||
List<Base> displayValue = geo != null ? geometryConverter.Convert(geo) : new();
|
||||
@@ -24,7 +21,7 @@ public sealed class DataObjectConverter(IGeometryConverter geometryConverter) :
|
||||
properties = node.ConvertPropertySets(),
|
||||
name = node.Name ?? node.Guid,
|
||||
displayValue = displayValue,
|
||||
["@elements"] = childrenConverter.ConvertChildren(model, node),
|
||||
["@elements"] = childrenConverter.ConvertChildren(model, node).ToList(),
|
||||
["ifcType"] = node.Type,
|
||||
["expressID"] = node.Id,
|
||||
["ownerId"] = node.OwnerId,
|
||||
|
||||
@@ -37,8 +37,8 @@ public sealed class NodeConverter(
|
||||
};
|
||||
}
|
||||
|
||||
public List<Base> ConvertChildren(IfcModel model, IfcNode node)
|
||||
public IEnumerable<Base> ConvertChildren(IfcModel model, IfcNode node)
|
||||
{
|
||||
return node.GetChildren().Where(x => x.IsIfcRoot).Select(x => Convert(model, x)).ToList();
|
||||
return node.GetChildren().Where(x => x.IsIfcRoot).Select(x => Convert(model, x));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,11 @@ public sealed class ProjectConverter : IProjectConverter
|
||||
{
|
||||
public Collection Convert(IfcModel model, IfcProject node, INodeConverter childrenConverter)
|
||||
{
|
||||
if (!node.IsIfcRoot) //I'd really rather have a class for this (IfcRoot : IfcNode)
|
||||
throw new ArgumentException("Expected to be an IfcRoot", paramName: nameof(node));
|
||||
|
||||
return new Collection
|
||||
{
|
||||
name = node.Name ?? node.Guid,
|
||||
applicationId = node.Guid,
|
||||
elements = childrenConverter.ConvertChildren(model, node),
|
||||
elements = childrenConverter.ConvertChildren(model, node).ToList(),
|
||||
["expressID"] = node.Id,
|
||||
["ownerId"] = node.OwnerId,
|
||||
["ifcType"] = node.Type,
|
||||
|
||||
@@ -1,23 +1,41 @@
|
||||
using Speckle.Importers.Ifc.Ara3D.IfcParser.Schema;
|
||||
using Speckle.Importers.Ifc.Types;
|
||||
using Speckle.InterfaceGenerator;
|
||||
using Speckle.Objects.Data;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
|
||||
namespace Speckle.Importers.Ifc.Converters;
|
||||
|
||||
[GenerateAutoInterface]
|
||||
public sealed class IfcSpatialStructureElementConverter : IIfcSpatialStructureElementConverter
|
||||
public sealed class IfcSpatialStructureElementConverter(IGeometryConverter geometryConverter)
|
||||
: IIfcSpatialStructureElementConverter
|
||||
{
|
||||
public Collection Convert(IfcModel model, IfcSpatialStructureElement node, INodeConverter childrenConverter)
|
||||
{
|
||||
if (!node.IsIfcRoot) //I'd really rather have a class for this (IfcRoot : IfcNode)
|
||||
throw new ArgumentException("Expected to be an IfcRoot", paramName: nameof(node));
|
||||
var directGeometry = ConvertAsDataObject(model, node);
|
||||
|
||||
var relationalChildren = childrenConverter.ConvertChildren(model, node);
|
||||
var allChildren = relationalChildren.Prepend(directGeometry).ToList();
|
||||
|
||||
//We're preferring to keep IFC collections lightweight, and adding a DataObject with the properties
|
||||
// 1. Spatial elements can can have direct geometry (mostly only common with IFC Site)
|
||||
// 2. Keeps property access simpler
|
||||
return new Collection
|
||||
{
|
||||
name = node.Name ?? node.Guid,
|
||||
applicationId = node.Guid,
|
||||
elements = childrenConverter.ConvertChildren(model, node),
|
||||
name = node.Name ?? node.LongName ?? node.Guid,
|
||||
elements = allChildren,
|
||||
["expressID"] = node.Id,
|
||||
};
|
||||
}
|
||||
|
||||
private DataObject ConvertAsDataObject(IfcModel model, IfcSpatialStructureElement node)
|
||||
{
|
||||
var geo = model.GetGeometry(node.Id);
|
||||
List<Base> displayValue = geo != null ? geometryConverter.Convert(geo) : new();
|
||||
|
||||
return new DataObject
|
||||
{
|
||||
["expressID"] = node.Id,
|
||||
["ownerId"] = node.OwnerId,
|
||||
["ifcType"] = node.Type,
|
||||
@@ -25,7 +43,10 @@ public sealed class IfcSpatialStructureElementConverter : IIfcSpatialStructureEl
|
||||
["objectType"] = node.ObjectType,
|
||||
["compositionType"] = node.CompositionType,
|
||||
["longName"] = node.LongName,
|
||||
["properties"] = node.ConvertPropertySets(),
|
||||
name = node.Name ?? node.LongName ?? node.Guid,
|
||||
applicationId = node.Guid,
|
||||
properties = node.ConvertPropertySets(),
|
||||
displayValue = displayValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user