From e28f84e62b3582a135fbd292207ebdc6a9f4088e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= <57442769+gjedlicska@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:11:57 +0200 Subject: [PATCH 01/12] Gergo/automate sdk exit code hotfix (#3492) * fix(automate): if function runs to completion we always need to exit with 0 * chore(automate): reformat * fix: exit code of function runs, fix trigger deserialization * chore(automate): reformat * fix(automate): fix tests for automate --- .../Speckle.Automate.Sdk/AutomationContext.cs | 2 ++ Automate/Speckle.Automate.Sdk/Runner.cs | 25 +++++++++++++------ .../Schema/AutomationRunData.cs | 2 +- .../Schema/AutomationStatus.cs | 3 ++- .../Schema/AutomationStatusMapping.cs | 2 ++ .../Schema/Triggers/VersionCreationTrigger.cs | 2 +- .../Test/TestAutomateUtils.cs | 5 +--- .../SpeckleAutomate.cs | 4 +-- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Automate/Speckle.Automate.Sdk/AutomationContext.cs b/Automate/Speckle.Automate.Sdk/AutomationContext.cs index fef232187b..5844df540a 100644 --- a/Automate/Speckle.Automate.Sdk/AutomationContext.cs +++ b/Automate/Speckle.Automate.Sdk/AutomationContext.cs @@ -317,6 +317,8 @@ private void MarkRun(AutomationStatus status, string? statusMessage) public void MarkRunFailed(string statusMessage) => MarkRun(AutomationStatus.Failed, statusMessage); + public void MarkRunException(string? statusMessage) => MarkRun(AutomationStatus.Exception, statusMessage); + public void MarkRunSuccess(string? statusMessage) => MarkRun(AutomationStatus.Succeeded, statusMessage); /// diff --git a/Automate/Speckle.Automate.Sdk/Runner.cs b/Automate/Speckle.Automate.Sdk/Runner.cs index 62b9297c72..43f50c0cc6 100644 --- a/Automate/Speckle.Automate.Sdk/Runner.cs +++ b/Automate/Speckle.Automate.Sdk/Runner.cs @@ -41,7 +41,7 @@ TInput inputs catch (Exception ex) when (!ex.IsFatal()) { Console.WriteLine(ex.ToString()); - automationContext.MarkRunFailed("Function error. Check the automation run logs for details."); + automationContext.MarkRunException("Function error. Check the automation run logs for details."); } finally { @@ -59,16 +59,14 @@ public static async Task RunFunction( Func automateFunction, AutomationRunData automationRunData, string speckleToken - ) - { - return await RunFunction( + ) => + await RunFunction( async (context, _) => await automateFunction(context).ConfigureAwait(false), automationRunData, speckleToken, new Fake() ) .ConfigureAwait(false); - } private struct Fake { } @@ -100,14 +98,25 @@ public static async Task Main(string[] args, Func pathArg = new(name: "Input Path", description: "A file path to retrieve function inputs"); RootCommand rootCommand = new(); + // a stupid hack to be able to exit with a specific integer exit code + // read more at https://github.com/dotnet/command-line-api/issues/1570 + var exitCode = 0; + rootCommand.AddArgument(pathArg); rootCommand.SetHandler( async inputPath => { FunctionRunData data = FunctionRunDataParser.FromPath(inputPath); - await RunFunction(automateFunction, data.AutomationRunData, data.SpeckleToken, data.FunctionInputs) + var context = await RunFunction( + automateFunction, + data.AutomationRunData, + data.SpeckleToken, + data.FunctionInputs + ) .ConfigureAwait(false); + + exitCode = context.RunStatus == "EXCEPTION" ? 1 : 0; }, pathArg ); @@ -118,7 +127,7 @@ await RunFunction(automateFunction, data.AutomationRunData, data.SpeckleToken, d Command generateSchemaCommand = new("generate-schema", "Generate JSON schema for the function inputs"); generateSchemaCommand.AddArgument(schemaFilePathArg); generateSchemaCommand.SetHandler( - (schemaFilePath) => + schemaFilePath => { JSchemaGenerator generator = new() { ContractResolver = new CamelCasePropertyNamesContractResolver() }; generator.GenerationProviders.Add(new SpeckleSecretProvider()); @@ -134,7 +143,7 @@ await RunFunction(automateFunction, data.AutomationRunData, data.SpeckleToken, d // if we've gotten this far, the execution should technically be completed as expected // thus exiting with 0 is the semantically correct thing to do - return 0; + return exitCode; } } diff --git a/Automate/Speckle.Automate.Sdk/Schema/AutomationRunData.cs b/Automate/Speckle.Automate.Sdk/Schema/AutomationRunData.cs index 755d833003..08997f7a73 100644 --- a/Automate/Speckle.Automate.Sdk/Schema/AutomationRunData.cs +++ b/Automate/Speckle.Automate.Sdk/Schema/AutomationRunData.cs @@ -12,5 +12,5 @@ public struct AutomationRunData public string AutomationId { get; set; } public string AutomationRunId { get; set; } public string FunctionRunId { get; set; } - public List Triggers { get; set; } + public List Triggers { get; set; } } diff --git a/Automate/Speckle.Automate.Sdk/Schema/AutomationStatus.cs b/Automate/Speckle.Automate.Sdk/Schema/AutomationStatus.cs index b23ba0feaf..b7b34b66f1 100644 --- a/Automate/Speckle.Automate.Sdk/Schema/AutomationStatus.cs +++ b/Automate/Speckle.Automate.Sdk/Schema/AutomationStatus.cs @@ -8,5 +8,6 @@ public enum AutomationStatus Initializing, Running, Failed, - Succeeded + Succeeded, + Exception } diff --git a/Automate/Speckle.Automate.Sdk/Schema/AutomationStatusMapping.cs b/Automate/Speckle.Automate.Sdk/Schema/AutomationStatusMapping.cs index fe3f6d9f33..a7996bbeee 100644 --- a/Automate/Speckle.Automate.Sdk/Schema/AutomationStatusMapping.cs +++ b/Automate/Speckle.Automate.Sdk/Schema/AutomationStatusMapping.cs @@ -6,6 +6,7 @@ public abstract class AutomationStatusMapping private const string RUNNING = "RUNNING"; private const string FAILED = "FAILED"; private const string SUCCEEDED = "SUCCEEDED"; + private const string EXCEPTION = "EXCEPTION"; public static string Get(AutomationStatus status) => status switch @@ -14,6 +15,7 @@ public static string Get(AutomationStatus status) => AutomationStatus.Failed => FAILED, AutomationStatus.Succeeded => SUCCEEDED, AutomationStatus.Initializing => INITIALIZING, + AutomationStatus.Exception => EXCEPTION, _ => throw new ArgumentOutOfRangeException($"Not valid value for enum {status}") }; } diff --git a/Automate/Speckle.Automate.Sdk/Schema/Triggers/VersionCreationTrigger.cs b/Automate/Speckle.Automate.Sdk/Schema/Triggers/VersionCreationTrigger.cs index dd5f649bf1..477df4b10b 100644 --- a/Automate/Speckle.Automate.Sdk/Schema/Triggers/VersionCreationTrigger.cs +++ b/Automate/Speckle.Automate.Sdk/Schema/Triggers/VersionCreationTrigger.cs @@ -10,7 +10,7 @@ public class VersionCreationTrigger : AutomationRunTriggerBase public VersionCreationTrigger(string modelId, string versionId) { TriggerType = "versionCreation"; - Payload = new VersionCreationTriggerPayload() { ModelId = modelId, VersionId = versionId }; + Payload = new VersionCreationTriggerPayload { ModelId = modelId, VersionId = versionId }; } } diff --git a/Automate/Speckle.Automate.Sdk/Test/TestAutomateUtils.cs b/Automate/Speckle.Automate.Sdk/Test/TestAutomateUtils.cs index f28596bc88..21e6f83d2a 100644 --- a/Automate/Speckle.Automate.Sdk/Test/TestAutomateUtils.cs +++ b/Automate/Speckle.Automate.Sdk/Test/TestAutomateUtils.cs @@ -52,10 +52,7 @@ mutation Mutation($projectId: ID!, $automationId: ID!) { AutomationId = TestAutomateEnvironment.GetSpeckleAutomationId(), AutomationRunId = runData["automationRunId"], FunctionRunId = runData["functionRunId"], - Triggers = new List() - { - new VersionCreationTrigger(modelId: modelId, versionId: versionId) - } + Triggers = new List { new(modelId: modelId, versionId: versionId) } }; return data; diff --git a/Automate/Tests/Speckle.Automate.Sdk.Tests.Integration/SpeckleAutomate.cs b/Automate/Tests/Speckle.Automate.Sdk.Tests.Integration/SpeckleAutomate.cs index 90987fa8fb..1c663e6ecb 100644 --- a/Automate/Tests/Speckle.Automate.Sdk.Tests.Integration/SpeckleAutomate.cs +++ b/Automate/Tests/Speckle.Automate.Sdk.Tests.Integration/SpeckleAutomate.cs @@ -46,7 +46,7 @@ private async Task AutomationRunData(Base testObject) string functionRelease = Utils.RandomString(10); string functionRunId = Utils.RandomString(10); - var triggers = new List() { new VersionCreationTrigger(modelId, versionId) }; + var triggers = new List { new(modelId, versionId) }; return new AutomationRunData { @@ -59,7 +59,7 @@ private async Task AutomationRunData(Base testObject) }; } - private VersionCreationTrigger GetVersionCreationTrigger(List triggers) + private VersionCreationTrigger GetVersionCreationTrigger(List triggers) { if (triggers.FirstOrDefault() is not VersionCreationTrigger trigger) { From 460e9acb8a8b780f8cab091c275ec24be1c569d1 Mon Sep 17 00:00:00 2001 From: Claire Kuang Date: Fri, 7 Jun 2024 06:52:44 -0700 Subject: [PATCH 02/12] CNX-9753: Add assembly and subassembly objects to Corridors (#3475) * adds additional corridor classes * updates with subassembly info and featureline based baselines * warnings fix * adds additional props to corridor sub elements --- .../ConverterAutocadCivil.Civil.cs | 192 ++++++++++++++---- .../ConverterAutocadCivil.cs | 2 +- Objects/Objects/BuiltElements/Baseline.cs | 88 ++++++++ .../Civil/CivilAppliedAssembly.cs | 26 +++ .../Civil/CivilAppliedSubassembly.cs | 37 ++++ .../BuiltElements/Civil/CivilBaseline.cs | 54 +++++ .../Civil/CivilBaselineRegion.cs | 45 ++++ .../Civil/CivilCalculatedLink.cs | 20 ++ .../Civil/CivilCalculatedPoint.cs | 35 ++++ .../Civil/CivilCalculatedShape.cs | 26 +++ Objects/Objects/Interfaces.cs | 11 + Objects/Objects/Other/Civil/CivilDataField.cs | 16 +- Objects/Objects/Other/DataField.cs | 6 +- 13 files changed, 509 insertions(+), 49 deletions(-) create mode 100644 Objects/Objects/BuiltElements/Baseline.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilAppliedAssembly.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilAppliedSubassembly.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilBaseline.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilBaselineRegion.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilCalculatedLink.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilCalculatedPoint.cs create mode 100644 Objects/Objects/BuiltElements/Civil/CivilCalculatedShape.cs diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs index a5d50b5efc..fce119ee81 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs @@ -30,6 +30,7 @@ using SpiralType = Objects.Geometry.SpiralType; using Station = Objects.BuiltElements.Station; using Structure = Objects.BuiltElements.Structure; +using Vector = Objects.Geometry.Vector; using Speckle.Core.Logging; namespace Objects.Converter.AutocadCivil; @@ -640,7 +641,7 @@ private Line ProfileGenericToSpeckle(double startStation, double startElevation, } // featurelines - public Featureline FeatureLineToSpeckle(CivilDB.FeatureLine featureline) + public Featureline FeaturelineToSpeckle(CivilDB.FeatureLine featureline) { // get all points var points = new List(); @@ -666,25 +667,18 @@ public Featureline FeatureLineToSpeckle(CivilDB.FeatureLine featureline) piPoints.Add(allPoints.IndexOf(piPoint)); } - /* - // get bulges at pi point indices - int count = (featureline.Closed) ? featureline.PointsCount : featureline.PointsCount - 1; - List bulges = new List(); - for (int i = 0; i < count; i++) bulges.Add(featureline.GetBulge(i)); - var piBulges = new List(); - foreach (var index in indices) piBulges.Add(bulges[index]); - */ - // get displayvalue var polyline = PolylineToSpeckle(new Polyline3d(Poly3dType.SimplePoly, intersectionPoints, false)); // featureline Featureline speckleFeatureline = new() { + points = points, curve = CurveToSpeckle(featureline.BaseCurve, ModelUnits), units = ModelUnits, displayValue = new List() { polyline } }; + AddNameAndDescriptionProperty(featureline.Name, featureline.Description, speckleFeatureline); speckleFeatureline["@piPoints"] = piPoints; speckleFeatureline["@elevationPoints"] = ePoints; @@ -1035,7 +1029,7 @@ private List PartDataRecordToSpeckle(PartDataRecord partData) foreach (PartDataField partField in partData.GetAllDataFields()) { - CivilDataField field = new(partField.Name, partField.DataType.ToString(), partField.Units.ToString(), partField.Context.ToString(), partField.Value); + CivilDataField field = new(partField.Name, partField.DataType.ToString(), partField.Value, partField.Units.ToString(),partField.Context.ToString(), null); fields.Add(field); } @@ -1128,13 +1122,154 @@ public Pipe PipeToSpeckle(PressurePipe pipe) // corridors // this is composed of assemblies, alignments, and profiles, use point codes to generate featurelines (which will have the 3d curve) + + private CivilDataField AppliedSubassemblyParamToSpeckle(IAppliedSubassemblyParam param) + { + CivilDataField baseParam = new(param.KeyName, param.ValueType.Name, param.ValueAsObject, null, null, param.DisplayName); + return baseParam; + } + + private CivilAppliedSubassembly AppliedSubassemblyToSpeckle(AppliedSubassembly appliedSubassembly) + { + // retrieve subassembly name + Subassembly subassembly = Trans.GetObject(appliedSubassembly.SubassemblyId, OpenMode.ForRead) as Subassembly; + + // get the calculated shapes + List speckleShapes = new(); + foreach (CalculatedShape shape in appliedSubassembly.Shapes) + { + CivilCalculatedShape speckleShape = CalculatedShapeToSpeckle(shape); + speckleShapes.Add(speckleShape); + } + + Point soePoint = PointToSpeckle(appliedSubassembly.OriginStationOffsetElevationToBaseline); + List speckleParameters = appliedSubassembly.Parameters.Select(p => AppliedSubassemblyParamToSpeckle(p)).ToList(); + + CivilAppliedSubassembly speckleAppliedSubassembly = new(appliedSubassembly.SubassemblyId.ToString(), subassembly.Name, speckleShapes, soePoint, speckleParameters); + return speckleAppliedSubassembly; + } + + private CivilAppliedAssembly AppliedAssemblyToSpeckle(AppliedAssembly appliedAssembly) + { + // get the applied subassemblies + List speckleSubassemblies = new(); + foreach (AppliedSubassembly appliedSubassembly in appliedAssembly.GetAppliedSubassemblies()) + { + CivilAppliedSubassembly speckleSubassembly = AppliedSubassemblyToSpeckle(appliedSubassembly); + speckleSubassemblies.Add(speckleSubassembly); + } + + CivilAppliedAssembly speckleAppliedAssembly = new(speckleSubassemblies, appliedAssembly.AdjustedElevation, ModelUnits); + return speckleAppliedAssembly; + } + + private CivilBaselineRegion BaselineRegionToSpeckle(BaselineRegion region) + { + // get the region assembly + Assembly assembly = Trans.GetObject(region.AssemblyId, OpenMode.ForRead) as Assembly; + + // get the applied assemblies by station + List speckleAppliedAssemblies = new(); + double[] sortedStations = region.SortedStations(); + for (int i = 0; i < sortedStations.Length; i++) + { + double station = sortedStations[i]; + CivilAppliedAssembly speckleAssembly = AppliedAssemblyToSpeckle(region.AppliedAssemblies[i]); + speckleAssembly["station"] = station; + speckleAppliedAssemblies.Add(speckleAssembly); + } + + // create the speckle region + CivilBaselineRegion speckleRegion = new(region.Name, region.StartStation, region.EndStation, assembly.Id.ToString(), assembly.Name, speckleAppliedAssemblies); + return speckleRegion; + } + + private CivilCalculatedShape CalculatedShapeToSpeckle(CalculatedShape shape) + { + List codes = shape.CorridorCodes.ToList(); + List speckleLinks = new(); + foreach (CalculatedLink link in shape.CalculatedLinks) + { + CivilCalculatedLink speckleLink = CalculatedLinkToSpeckle(link); + speckleLinks.Add(speckleLink); + } + + CivilCalculatedShape speckleCalculatedShape = new(codes, speckleLinks, shape.Area, ModelUnits); + return speckleCalculatedShape; + } + + private CivilCalculatedLink CalculatedLinkToSpeckle(CalculatedLink link) + { + List codes = link.CorridorCodes.ToList(); + List specklePoints = new(); + foreach (CalculatedPoint point in link.CalculatedPoints) + { + CivilCalculatedPoint specklePoint = CalculatedPointToSpeckle(point); + specklePoints.Add(specklePoint); + } + + CivilCalculatedLink speckleLink = new(codes, specklePoints); + return speckleLink; + } + + private CivilCalculatedPoint CalculatedPointToSpeckle(CalculatedPoint point) + { + Point specklePoint = PointToSpeckle(point.XYZ); + List codes = point.CorridorCodes.ToList(); + Vector normalBaseline = VectorToSpeckle(point.NormalToBaseline); + Vector normalSubAssembly = VectorToSpeckle(point.NormalToSubassembly); + Point soePoint = PointToSpeckle(point.StationOffsetElevationToBaseline); + CivilCalculatedPoint speckleCalculatedPoint = new(specklePoint, codes, normalBaseline, normalSubAssembly, soePoint); + return speckleCalculatedPoint; + } + + private CivilBaseline BaselineToSpeckle(CivilDB.Baseline baseline) + { + CivilBaseline speckleBaseline = null; + + // get the speckle regions + List speckleRegions = new(); + foreach (BaselineRegion region in baseline.BaselineRegions) + { + CivilBaselineRegion speckleRegion = BaselineRegionToSpeckle(region); + speckleRegions.Add(speckleRegion); + } + + // get profile and alignment if nonfeaturelinebased + // for featureline based corridors, accessing AlignmentId and ProfileId will return NULL + // and throw an exception ""This operation on feature line based baseline is invalid". + if (!baseline.IsFeatureLineBased()) + { + // get the speckle alignment + var alignment = Trans.GetObject(baseline.AlignmentId, OpenMode.ForRead) as CivilDB.Alignment; + CivilAlignment speckleAlignment = AlignmentToSpeckle(alignment); + + // get the speckle profile + var profile = Trans.GetObject(baseline.ProfileId, OpenMode.ForRead) as CivilDB.Profile; + CivilProfile speckleProfile = ProfileToSpeckle(profile); + + speckleBaseline = new(baseline.Name, speckleRegions, baseline.SortedStations().ToList(), baseline.StartStation, baseline.EndStation, speckleAlignment, speckleProfile); + } + else + { + // get the baseline featureline + var featureline = Trans.GetObject(baseline.FeatureLineId, OpenMode.ForRead) as CivilDB.FeatureLine; + Featureline speckleFeatureline = FeaturelineToSpeckle(featureline); + + speckleBaseline = new(baseline.Name, speckleRegions, baseline.SortedStations().ToList(), baseline.StartStation, baseline.EndStation, speckleFeatureline); + } + + return speckleBaseline; + } + public Base CorridorToSpeckle(Corridor corridor) { - List alignments = new(); - List profiles = new(); List featurelines = new(); - foreach (Baseline baseline in corridor.Baselines) + List baselines = new(); + foreach (CivilDB.Baseline baseline in corridor.Baselines) { + CivilBaseline speckleBaseline = BaselineToSpeckle(baseline); + baselines.Add(speckleBaseline); // get the collection of featurelines for this baseline foreach (FeatureLineCollection mainFeaturelineCollection in baseline.MainBaselineFeatureLines.FeatureLineCollectionMap) // main featurelines @@ -1155,32 +1290,6 @@ public Base CorridorToSpeckle(Corridor corridor) } } } - - // get alignment and profile if relevant - // for featureline based corridors, accessing AlignmentId and ProfileId will return NULL - // and throw an exception ""This operation on feature line based baseline is invalid". - if (!baseline.IsFeatureLineBased()) - { - if (baseline.AlignmentId is ObjectId alignmentId) - { - var alignment = Trans.GetObject(alignmentId, OpenMode.ForRead) as CivilDB.Alignment; - var convertedAlignment = AlignmentToSpeckle(alignment); - if (convertedAlignment != null) - { - alignments.Add(convertedAlignment); - } - } - - if (baseline.ProfileId is ObjectId profileId) - { - var profile = Trans.GetObject(profileId, OpenMode.ForRead) as CivilDB.Profile; - var convertedProfile = ProfileToSpeckle(profile); - if (convertedProfile != null) - { - profiles.Add(convertedProfile); - } - } - } } // get corridor surfaces @@ -1202,9 +1311,8 @@ public Base CorridorToSpeckle(Corridor corridor) } var corridorBase = new Base(); - corridorBase["@alignments"] = alignments; - corridorBase["@profiles"] = profiles; corridorBase["@featurelines"] = featurelines; + corridorBase["@baselines"] = baselines; AddNameAndDescriptionProperty(corridor.Name, corridor.Description, corridorBase); corridorBase["units"] = ModelUnits; if (surfaces.Count > 0) diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs index 957fff734b..96bd06d9f1 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.cs @@ -206,7 +206,7 @@ public Base ConvertToSpeckle(object @object) @base = CorridorToSpeckle(o); break; case CivilDB.FeatureLine o: - @base = FeatureLineToSpeckle(o); + @base = FeaturelineToSpeckle(o); break; case CivilDB.Structure o: @base = StructureToSpeckle(o); diff --git a/Objects/Objects/BuiltElements/Baseline.cs b/Objects/Objects/BuiltElements/Baseline.cs new file mode 100644 index 0000000000..a78fc9b069 --- /dev/null +++ b/Objects/Objects/BuiltElements/Baseline.cs @@ -0,0 +1,88 @@ +using Speckle.Core.Models; +using Speckle.Newtonsoft.Json; + +namespace Objects.BuiltElements; + +public abstract class Baseline : Base +{ + protected Baseline() { } + + protected Baseline(string name, bool isFeaturelineBased) + { + this.name = name; + this.isFeaturelineBased = isFeaturelineBased; + } + + /// + /// The name of this baseline + /// + public string name { get; set; } + + /// + /// The horizontal component of this baseline + /// + public abstract Alignment? alignment { get; internal set; } + + /// + /// The vertical component of this baseline + /// + public abstract Profile? profile { get; internal set; } + + [DetachProperty] + public Featureline? featureline { get; internal set; } + + public bool isFeaturelineBased { get; set; } +} + +/// +/// Generic instance class +/// +public abstract class Baseline : Baseline + where TA : Alignment + where TP : Profile +{ + protected Baseline(string name, TA alignment, TP profile, Featureline? featureline, bool isFeaturelineBased) + : base(name, isFeaturelineBased) + { + this.name = name; + typedAlignment = alignment; + typedProfile = profile; + this.featureline = featureline; + this.isFeaturelineBased = isFeaturelineBased; + } + + protected Baseline() + : base(string.Empty, false) { } + + [JsonIgnore] + public TA typedAlignment { get; set; } + + [JsonIgnore] + public TP typedProfile { get; set; } + + [DetachProperty] + public override Alignment? alignment + { + get => typedAlignment; + internal set + { + if (value is TA typeA) + { + typedAlignment = typeA; + } + } + } + + [DetachProperty] + public override Profile? profile + { + get => typedProfile; + internal set + { + if (value is TP typeP) + { + typedProfile = typeP; + } + } + } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilAppliedAssembly.cs b/Objects/Objects/BuiltElements/Civil/CivilAppliedAssembly.cs new file mode 100644 index 0000000000..f490c643de --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilAppliedAssembly.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilAppliedAssembly : Base +{ + public CivilAppliedAssembly() { } + + public CivilAppliedAssembly( + List appliedSubassemblies, + double adjustedElevation, + string units + ) + { + this.appliedSubassemblies = appliedSubassemblies; + this.adjustedElevation = adjustedElevation; + this.units = units; + } + + public List appliedSubassemblies { get; set; } + + public double adjustedElevation { get; set; } + + public string units { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilAppliedSubassembly.cs b/Objects/Objects/BuiltElements/Civil/CivilAppliedSubassembly.cs new file mode 100644 index 0000000000..f4beb7a3d0 --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilAppliedSubassembly.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Objects.Geometry; +using Objects.Other.Civil; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilAppliedSubassembly : Base +{ + public CivilAppliedSubassembly() { } + + public CivilAppliedSubassembly( + string subassemblyId, + string subassemblyName, + List shapes, + Point stationOffsetElevationToBaseline, + List parameters + ) + { + this.subassemblyId = subassemblyId; + this.subassemblyName = subassemblyName; + this.shapes = shapes; + this.stationOffsetElevationToBaseline = stationOffsetElevationToBaseline; + this.parameters = parameters; + } + + public string subassemblyId { get; set; } + + public string subassemblyName { get; set; } + + public List shapes { get; set; } + + public Point stationOffsetElevationToBaseline { get; set; } + + [DetachProperty] + public List parameters { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilBaseline.cs b/Objects/Objects/BuiltElements/Civil/CivilBaseline.cs new file mode 100644 index 0000000000..826ef8df2b --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilBaseline.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +namespace Objects.BuiltElements.Civil; + +public class CivilBaseline : Baseline +{ + public CivilBaseline() { } + + public CivilBaseline( + string name, + List regions, + List stations, + double startStation, + double endStation, + CivilAlignment alignment, + CivilProfile profile + ) + { + this.name = name; + this.regions = regions; + this.stations = stations; + this.startStation = startStation; + this.endStation = endStation; + this.alignment = alignment; + this.profile = profile; + isFeaturelineBased = false; + } + + public CivilBaseline( + string name, + List regions, + List stations, + double startStation, + double endStation, + Featureline featureline + ) + { + this.name = name; + this.regions = regions; + this.stations = stations; + this.startStation = startStation; + this.endStation = endStation; + this.featureline = featureline; + isFeaturelineBased = true; + } + + public List regions { get; set; } + + public List stations { get; set; } + + public double startStation { get; set; } + + public double endStation { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilBaselineRegion.cs b/Objects/Objects/BuiltElements/Civil/CivilBaselineRegion.cs new file mode 100644 index 0000000000..5aabffd3f7 --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilBaselineRegion.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilBaselineRegion : Base +{ + public CivilBaselineRegion() { } + + public CivilBaselineRegion( + string name, + double startStation, + double endStation, + string assemblyId, + string? assemblyName, + List appliedAssemblies + ) + { + this.name = name; + this.startStation = startStation; + this.endStation = endStation; + this.assemblyId = assemblyId; + this.assemblyName = assemblyName; + this.appliedAssemblies = appliedAssemblies; + } + + /// + /// The name of the region + /// + public string name { get; set; } + + /// + /// The id of the assembly of the region + /// + public string assemblyId { get; set; } + + public string? assemblyName { get; set; } + + public double startStation { get; set; } + + public double endStation { get; set; } + + [DetachProperty] + public List appliedAssemblies { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilCalculatedLink.cs b/Objects/Objects/BuiltElements/Civil/CivilCalculatedLink.cs new file mode 100644 index 0000000000..aa0bc94979 --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilCalculatedLink.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilCalculatedLink : Base, ICivilCalculatedObject +{ + public CivilCalculatedLink() { } + + public CivilCalculatedLink(List codes, List points) + { + this.codes = codes; + this.points = points; + } + + public List codes { get; set; } + + [DetachProperty] + public List points { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilCalculatedPoint.cs b/Objects/Objects/BuiltElements/Civil/CivilCalculatedPoint.cs new file mode 100644 index 0000000000..c6ed147b4f --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilCalculatedPoint.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Objects.Geometry; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilCalculatedPoint : Base, ICivilCalculatedObject +{ + public CivilCalculatedPoint() { } + + public CivilCalculatedPoint( + Point point, + List codes, + Vector normalToBaseline, + Vector normalToSubassembly, + Point stationOffsetElevationToBaseline + ) + { + this.point = point; + this.codes = codes; + this.normalToBaseline = normalToBaseline; + this.normalToSubassembly = normalToSubassembly; + this.stationOffsetElevationToBaseline = stationOffsetElevationToBaseline; + } + + public Point point { get; set; } + + public List codes { get; set; } + + public Vector normalToBaseline { get; set; } + + public Vector normalToSubassembly { get; set; } + + public Point stationOffsetElevationToBaseline { get; set; } +} diff --git a/Objects/Objects/BuiltElements/Civil/CivilCalculatedShape.cs b/Objects/Objects/BuiltElements/Civil/CivilCalculatedShape.cs new file mode 100644 index 0000000000..1e6a3fb7b6 --- /dev/null +++ b/Objects/Objects/BuiltElements/Civil/CivilCalculatedShape.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Speckle.Core.Models; + +namespace Objects.BuiltElements.Civil; + +public class CivilCalculatedShape : Base, ICivilCalculatedObject +{ + public CivilCalculatedShape() { } + + public CivilCalculatedShape(List codes, List links, double area, string units) + { + this.codes = codes; + this.links = links; + this.area = area; + this.units = units; + } + + public List codes { get; set; } + + [DetachProperty] + public List links { get; set; } + + public double area { get; set; } + + public string units { get; set; } +} diff --git a/Objects/Objects/Interfaces.cs b/Objects/Objects/Interfaces.cs index f732d0d64f..4a4ff2d789 100644 --- a/Objects/Objects/Interfaces.cs +++ b/Objects/Objects/Interfaces.cs @@ -110,5 +110,16 @@ public interface IDisplayValue T displayValue { get; set; } } +/// +/// Represents a calculated object for civil disciplines +/// +public interface ICivilCalculatedObject +{ + /// + /// for this calculated object. + /// + List codes { get; set; } +} + #endregion diff --git a/Objects/Objects/Other/Civil/CivilDataField.cs b/Objects/Objects/Other/Civil/CivilDataField.cs index 48e1a2ad83..6919669d85 100644 --- a/Objects/Objects/Other/Civil/CivilDataField.cs +++ b/Objects/Objects/Other/Civil/CivilDataField.cs @@ -4,17 +4,27 @@ public class CivilDataField : DataField { public CivilDataField() { } - public CivilDataField(string name, string type, string units, string context, object? value = null) + public CivilDataField( + string name, + string type, + object? value, + string? units = null, + string? context = null, + string? displayName = null + ) { this.name = name; this.type = type; + this.value = value; this.units = units; this.context = context; - this.value = value; + this.displayName = displayName; } /// /// The context type of the Civil3D part /// - public string context { get; set; } + public string? context { get; set; } + + public string? displayName { get; set; } } diff --git a/Objects/Objects/Other/DataField.cs b/Objects/Objects/Other/DataField.cs index 6770b3a8ef..4d3fd5a1ea 100644 --- a/Objects/Objects/Other/DataField.cs +++ b/Objects/Objects/Other/DataField.cs @@ -9,12 +9,12 @@ public class DataField : Base { public DataField() { } - public DataField(string name, string type, string units, object? value = null) + public DataField(string name, string type, object? value, string? units = null) { this.name = name; this.type = type; - this.units = units; this.value = value; + this.units = units; } public string name { get; set; } @@ -23,5 +23,5 @@ public DataField(string name, string type, string units, object? value = null) public object? value { get; set; } - public string units { get; set; } + public string? units { get; set; } } From 8fe7878225ede1ac248c85b094360377da047e10 Mon Sep 17 00:00:00 2001 From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:57:28 +0100 Subject: [PATCH 03/12] CNX-9439 interacting with structural gh models in the viewer (#3451) * seperated Revit wall subclasses into own files * Updated build element constructors to use baseCurve if no displayValue is provided * Hopefully fixed all the problems * Beam * Reverted changes to revit wall subtypes * fix warnings * reverted some uneeded changes * Column * Schema info Beam call --- .../SchemaBuilder/CreateSchemaObject.cs | 3 +- .../PartialClasses/ConvertBrace.cs | 21 +- .../PartialClasses/ConvertColumn.cs | 57 +++--- .../PartialClasses/ConvertWall.cs | 27 +-- .../PartialClasses/ConvertBeam.cs | 14 +- .../BuiltElements/AdvanceSteel/AsteelBeam.cs | 4 +- .../BuiltElements/Archicad/ElementShape.cs | 16 +- Objects/Objects/BuiltElements/Beam.cs | 19 +- Objects/Objects/BuiltElements/Brace.cs | 15 +- Objects/Objects/BuiltElements/Column.cs | 21 +- Objects/Objects/BuiltElements/Duct.cs | 72 ++++--- .../Objects/BuiltElements/Revit/RevitBeam.cs | 25 ++- .../Objects/BuiltElements/Revit/RevitBrace.cs | 32 ++- .../BuiltElements/Revit/RevitColumn.cs | 115 ++++++----- .../Objects/BuiltElements/Revit/RevitDuct.cs | 193 +++++++++++------- .../Objects/BuiltElements/Revit/RevitWall.cs | 146 ++++++------- Objects/Objects/BuiltElements/Wall.cs | 41 ++-- Objects/Objects/Interfaces.cs | 14 +- Objects/Objects/Objects.csproj | 2 +- .../Objects/Structural/Geometry/Element1D.cs | 157 +++++++------- 20 files changed, 574 insertions(+), 420 deletions(-) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs index 3749d94648..67f00ce746 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/SchemaBuilder/CreateSchemaObject.cs @@ -252,13 +252,14 @@ public void SwitchConstructor(ConstructorInfo constructor) RegisterPropertyAsInputParameter(p, k++); } + SelectedConstructor = constructor; + UserInterfaceUtils.CreateCanvasDropdownForAllEnumInputs(this, props); Name = constructor.GetCustomAttribute().Name; Description = constructor.GetCustomAttribute().Description; Message = constructor.DeclaringType.FullName.Split('.')[0]; - SelectedConstructor = constructor; Params.Output[0].NickName = constructor.DeclaringType.Name; Params.OnParametersChanged(); diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs index 0613b4d8ab..8de864d03a 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertBrace.cs @@ -1,8 +1,10 @@ +using System; using Autodesk.Revit.DB.Structure; using Objects.BuiltElements; using Objects.BuiltElements.Revit; using Speckle.Core.Models; using System.Collections.Generic; +using Objects.Geometry; using DB = Autodesk.Revit.DB; namespace Objects.Converter.Revit; @@ -37,18 +39,21 @@ public ApplicationObject BraceToNative(Brace speckleBrace) private Base BraceToSpeckle(DB.FamilyInstance myFamily, out List notes) { - notes = new List(); - var myBeam = BeamToSpeckle(myFamily, out notes) as RevitBeam; + var myBeam = (RevitBeam)BeamToSpeckle(myFamily, out notes); - var myBrace = new RevitBrace() + var myBrace = new RevitBrace( + myBeam.family, + myBeam.type, + myBeam.baseLine, + myBeam.level, + myBeam.units, + myBeam.elementId, + Array.Empty() + ) { + displayValue = myBeam.displayValue, applicationId = myBeam.applicationId, - type = myBeam.type, - baseLine = myBeam.baseLine, - level = myBeam.level, - family = myBeam.family, parameters = myBeam.parameters, - displayValue = myBeam.displayValue, }; var dynamicProps = myBeam.GetMembers(DynamicBaseMemberType.Dynamic); diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs index 0f813d6165..94efd55a14 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertColumn.cs @@ -249,39 +249,29 @@ double topOffset public Base ColumnToSpeckle(DB.FamilyInstance revitColumn, out List notes) { notes = new List(); - var symbol = revitColumn.Document.GetElement(revitColumn.GetTypeId()) as FamilySymbol; - - var speckleColumn = new RevitColumn(); - speckleColumn.family = symbol.FamilyName; - speckleColumn.type = revitColumn.Document.GetElement(revitColumn.GetTypeId()).Name; - speckleColumn.level = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - speckleColumn.topLevel = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - speckleColumn.baseOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); - speckleColumn.topOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); - speckleColumn.facingFlipped = revitColumn.FacingFlipped; - speckleColumn.handFlipped = revitColumn.HandFlipped; - speckleColumn.isSlanted = revitColumn.IsSlantedColumn; - //speckleColumn.structural = revitColumn.StructuralType == StructuralType.Column; + var symbol = (FamilySymbol)revitColumn.Document.GetElement(revitColumn.GetTypeId()); + + RevitLevel level = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_PARAM); + RevitLevel topLevel = ConvertAndCacheLevel(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM); + double baseOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM); + double topOffset = GetParamValue(revitColumn, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM); //geometry var baseGeometry = LocationToSpeckle(revitColumn); var baseLine = baseGeometry as ICurve; - //make line from point and height if (baseLine == null && baseGeometry is Point basePoint) + //make line from point and height { - if ( - symbol.Family.FamilyPlacementType == FamilyPlacementType.OneLevelBased - || symbol.Family.FamilyPlacementType == FamilyPlacementType.WorkPlaneBased - ) + if (symbol.Family.FamilyPlacementType is FamilyPlacementType.OneLevelBased or FamilyPlacementType.WorkPlaneBased) { return RevitInstanceToSpeckle(revitColumn, out notes, null); } - var elevation = speckleColumn.topLevel.elevation; + var elevation = topLevel.elevation; baseLine = new Line( basePoint, - new Point(basePoint.x, basePoint.y, elevation + speckleColumn.topOffset, ModelUnits), + new Point(basePoint.x, basePoint.y, elevation + topOffset, ModelUnits), ModelUnits ); } @@ -291,7 +281,25 @@ public Base ColumnToSpeckle(DB.FamilyInstance revitColumn, out List note return RevitElementToSpeckle(revitColumn, out notes); } - speckleColumn.baseLine = baseLine; //all speckle columns should be line based + double rotation = revitColumn.Location is LocationPoint location ? location.Rotation : 0; + + var speckleColumn = new RevitColumn( + symbol.FamilyName, + revitColumn.Document.GetElement(revitColumn.GetTypeId()).Name, + baseLine, //all speckle columns should be line based + level, + topLevel, + ModelUnits, + revitColumn.Id.ToString(), + baseOffset, + topOffset, + revitColumn.FacingFlipped, + revitColumn.HandFlipped, + revitColumn.IsSlantedColumn, + rotation, + GetElementDisplayValue(revitColumn) + //structural: revitColumn.StructuralType == StructuralType.Column; + ); GetAllRevitParamsAndIds( speckleColumn, @@ -307,13 +315,6 @@ public Base ColumnToSpeckle(DB.FamilyInstance revitColumn, out List note } ); - if (revitColumn.Location is LocationPoint) - { - speckleColumn.rotation = ((LocationPoint)revitColumn.Location).Rotation; - } - - speckleColumn.displayValue = GetElementDisplayValue(revitColumn); - return speckleColumn; } } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs index 11bbd0ceaf..ef493e7fa9 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs @@ -187,18 +187,21 @@ public Base WallToSpeckle(DB.Wall revitWall, out List notes) return RevitElementToSpeckle(revitWall, out notes); } - RevitWall speckleWall = new(); - speckleWall.family = revitWall.WallType.FamilyName.ToString(); - speckleWall.type = revitWall.WallType.Name; - speckleWall.baseLine = (ICurve)baseGeometry; - speckleWall.level = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT); - speckleWall.topLevel = ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE); - speckleWall.height = GetParamValue(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM); - speckleWall.baseOffset = GetParamValue(revitWall, BuiltInParameter.WALL_BASE_OFFSET); - speckleWall.topOffset = GetParamValue(revitWall, BuiltInParameter.WALL_TOP_OFFSET); - speckleWall.structural = GetParamValue(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT); - speckleWall.flipped = revitWall.Flipped; - + RevitWall speckleWall = + new( + revitWall.WallType.FamilyName, + revitWall.WallType.Name, + (ICurve)baseGeometry, + ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_BASE_CONSTRAINT), + ConvertAndCacheLevel(revitWall, BuiltInParameter.WALL_HEIGHT_TYPE), + GetParamValue(revitWall, BuiltInParameter.WALL_USER_HEIGHT_PARAM), + ModelUnits, + revitWall.Id.ToString(), + GetParamValue(revitWall, BuiltInParameter.WALL_BASE_OFFSET), + GetParamValue(revitWall, BuiltInParameter.WALL_TOP_OFFSET), + revitWall.Flipped, + GetParamValue(revitWall, BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT) + ); //CreateVoids(revitWall, speckleWall); if (revitWall.CurtainGrid is not CurtainGrid grid) diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs index 8ad1e75f55..1c9f0980ff 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/PartialClasses/ConvertBeam.cs @@ -192,12 +192,14 @@ public TeklaBeam BeamToSpeckle(Tekla.Structures.Model.Beam beam) Point speckleStartPoint = new(startPoint.X, startPoint.Y, startPoint.Z, units); Point speckleEndPoint = new(endPoint.X, endPoint.Y, endPoint.Z, units); - speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units); - speckleBeam.baseLine.length = Math.Sqrt( - Math.Pow((startPoint.X - endPoint.X), 2) - + Math.Pow((startPoint.Y - endPoint.Y), 2) - + Math.Pow((startPoint.Z - endPoint.Z), 2) - ); + speckleBeam.baseLine = new Line(speckleStartPoint, speckleEndPoint, units) + { + length = Math.Sqrt( + Math.Pow((startPoint.X - endPoint.X), 2) + + Math.Pow((startPoint.Y - endPoint.Y), 2) + + Math.Pow((startPoint.Z - endPoint.Z), 2) + ), + }; speckleBeam.profile = GetBeamProfile(beam.Profile.ProfileString); speckleBeam.material = GetMaterial(beam.Material.MaterialString); var beamCS = beam.GetCoordinateSystem(); diff --git a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBeam.cs b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBeam.cs index 83db3e1c81..af9fde1bba 100644 --- a/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBeam.cs +++ b/Objects/Objects/BuiltElements/AdvanceSteel/AsteelBeam.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using Objects.Geometry; using Objects.Structural.Materials; using Objects.Structural.Properties.Profiles; using Speckle.Core.Kits; @@ -7,7 +5,7 @@ namespace Objects.BuiltElements.AdvanceSteel; -public class AsteelBeam : Beam, IDisplayValue>, IHasVolume, IHasArea, IAsteelObject +public class AsteelBeam : Beam, IHasVolume, IHasArea, IAsteelObject { [DetachProperty] public SectionProfile profile { get; set; } diff --git a/Objects/Objects/BuiltElements/Archicad/ElementShape.cs b/Objects/Objects/BuiltElements/Archicad/ElementShape.cs index 4da45cb3ae..cd78ab4717 100644 --- a/Objects/Objects/BuiltElements/Archicad/ElementShape.cs +++ b/Objects/Objects/BuiltElements/Archicad/ElementShape.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using Objects.Geometry; using Objects.Primitive; +using Speckle.Core.Kits; using Speckle.Core.Models; +using Speckle.Newtonsoft.Json; namespace Objects.BuiltElements.Archicad; @@ -19,6 +21,9 @@ public ElementShape(Polyline contourPolyline, List? holePolylines = nu public List? holePolylines { get; set; } + /// + /// This class is only used for Archicad interop + /// public sealed class PolylineSegment : Base, ICurve { public PolylineSegment() { } @@ -33,21 +38,30 @@ public PolylineSegment(Point startPoint, Point endPoint, double? arcAngle = null public Point startPoint { get; set; } public Point endPoint { get; set; } + + [JsonIgnore] + public string units => Units.Meters; public double arcAngle { get; set; } public bool? bodyFlag { get; set; } public double length { get; set; } public Interval domain { get; set; } = new(0, 1); } + /// + /// This class is only used for Archicad interop + /// public sealed class Polyline : Base, ICurve { public Polyline() { } public Polyline(List segments) { - polylineSegments = segments; + this.polylineSegments = segments; } + [JsonIgnore] + public string units => Units.Meters; + public List polylineSegments { get; set; } = new(); public double length { get; set; } public Interval domain { get; set; } = new(0, 1); diff --git a/Objects/Objects/BuiltElements/Beam.cs b/Objects/Objects/BuiltElements/Beam.cs index 7d917c6c93..d868921632 100644 --- a/Objects/Objects/BuiltElements/Beam.cs +++ b/Objects/Objects/BuiltElements/Beam.cs @@ -5,22 +5,31 @@ namespace Objects.BuiltElements; -public class Beam : Base, IDisplayValue> +public class Beam : Base, IDisplayValue> { public Beam() { } - [SchemaInfo("Beam", "Creates a Speckle beam", "BIM", "Structure")] - public Beam([SchemaMainParam] ICurve baseLine) + public Beam(ICurve baseLine, Level? level, string? units, IReadOnlyList? displayValue = null) { this.baseLine = baseLine; + this.level = level; + this.units = units; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseLine }; } public ICurve baseLine { get; set; } public virtual Level? level { get; internal set; } - public string units { get; set; } + public string? units { get; set; } [DetachProperty] - public List displayValue { get; set; } + public IReadOnlyList displayValue { get; set; } + + #region Schema Info Constructors + [SchemaInfo("Beam", "Creates a Speckle beam", "BIM", "Structure")] + public Beam([SchemaMainParam] ICurve baseLine) + : this(baseLine, null, null) { } + + #endregion } diff --git a/Objects/Objects/BuiltElements/Brace.cs b/Objects/Objects/BuiltElements/Brace.cs index c51cd56828..c8a90447ee 100644 --- a/Objects/Objects/BuiltElements/Brace.cs +++ b/Objects/Objects/BuiltElements/Brace.cs @@ -5,20 +5,25 @@ namespace Objects.BuiltElements; -public class Brace : Base, IDisplayValue> +public class Brace : Base, IDisplayValue> { public Brace() { } - [SchemaInfo("Brace", "Creates a Speckle brace", "BIM", "Structure")] - public Brace([SchemaMainParam] ICurve baseLine) + public Brace(ICurve baseLine, string? units, IReadOnlyList? displayValue = null) { this.baseLine = baseLine; + this.units = units; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseLine }; } public ICurve baseLine { get; set; } - public string units { get; set; } + public string? units { get; set; } [DetachProperty] - public List displayValue { get; set; } + public IReadOnlyList displayValue { get; set; } + + [SchemaInfo("Brace", "Creates a Speckle brace", "BIM", "Structure")] + public Brace([SchemaMainParam] ICurve baseLine) + : this(baseLine, null) { } } diff --git a/Objects/Objects/BuiltElements/Column.cs b/Objects/Objects/BuiltElements/Column.cs index e13e054eaa..3b4d405575 100644 --- a/Objects/Objects/BuiltElements/Column.cs +++ b/Objects/Objects/BuiltElements/Column.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Objects.Geometry; using Speckle.Core.Kits; @@ -5,22 +6,32 @@ namespace Objects.BuiltElements; -public class Column : Base, IDisplayValue> +public class Column : Base, IDisplayValue> { public Column() { } - [SchemaInfo("Column", "Creates a Speckle column", "BIM", "Structure")] - public Column([SchemaMainParam] ICurve baseLine) + public Column(ICurve baseLine, string? units, Level? level = null, IReadOnlyList? displayValue = null) { this.baseLine = baseLine; + this.units = units; + this.level = level; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseLine }; } public ICurve baseLine { get; set; } public virtual Level? level { get; internal set; } - public string units { get; set; } + public string? units { get; set; } [DetachProperty] - public List displayValue { get; set; } + public IReadOnlyList displayValue { get; set; } + + #region Schema Info Constructors + + [SchemaInfo("Column", "Creates a Speckle column", "BIM", "Structure")] + [SchemaDeprecated, Obsolete("Use other constructor")] + public Column([SchemaMainParam] ICurve baseLine) + : this(baseLine, null) { } + #endregion } diff --git a/Objects/Objects/BuiltElements/Duct.cs b/Objects/Objects/BuiltElements/Duct.cs index f530be6faf..6ef56bbc53 100644 --- a/Objects/Objects/BuiltElements/Duct.cs +++ b/Objects/Objects/BuiltElements/Duct.cs @@ -7,10 +7,47 @@ namespace Objects.BuiltElements; -public class Duct : Base, IDisplayValue> +public class Duct : Base, IDisplayValue> { public Duct() { } + public Duct( + ICurve baseCurve, + double width, + double height, + double diameter, + double length, + string? units, + double velocity = 0, + IReadOnlyList? displayValue = null + ) + { + this.baseCurve = baseCurve; + this.width = width; + this.height = height; + this.diameter = diameter; + this.length = length; + this.units = units; + this.velocity = velocity; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseCurve }; + } + + [JsonIgnore, Obsolete("Replaced with baseCurve property")] + public Line? baseLine { get; set; } + + public ICurve baseCurve { get; set; } + public double width { get; set; } + public double height { get; set; } + public double diameter { get; set; } + public double length { get; set; } + public double velocity { get; set; } + + public string? units { get; set; } + + [DetachProperty] + public IReadOnlyList displayValue { get; set; } + + #region Schema Info Constructors /// /// SchemaBuilder constructor for a Speckle duct /// @@ -22,13 +59,8 @@ public Duct() { } /// Assign units when using this constructor due to , , and params [SchemaInfo("Duct", "Creates a Speckle duct", "BIM", "MEP"), SchemaDeprecated] public Duct([SchemaMainParam] Line baseLine, double width, double height, double diameter, double velocity = 0) - { - baseCurve = baseLine; - this.width = width; - this.height = height; - this.diameter = diameter; - this.velocity = velocity; - } + : this(baseLine, width, height, diameter, default, null, velocity) //TODO: what to do with length??? + { } /// /// SchemaBuilder constructor for a Speckle duct @@ -41,26 +73,6 @@ public Duct([SchemaMainParam] Line baseLine, double width, double height, double /// Assign units when using this constructor due to , , and params [SchemaInfo("Duct", "Creates a Speckle duct", "BIM", "MEP")] public Duct([SchemaMainParam] ICurve baseCurve, double width, double height, double diameter, double velocity = 0) - { - this.baseCurve = baseCurve; - this.width = width; - this.height = height; - this.diameter = diameter; - this.velocity = velocity; - } - - [JsonIgnore, Obsolete("Replaced with baseCurve property")] - public Line baseLine { get; set; } - - public ICurve baseCurve { get; set; } - public double width { get; set; } - public double height { get; set; } - public double diameter { get; set; } - public double length { get; set; } - public double velocity { get; set; } - - public string units { get; set; } - - [DetachProperty] - public List displayValue { get; set; } + : this(baseCurve, width, height, diameter, default, null, velocity) { } //TODO: what to do with length??? + #endregion } diff --git a/Objects/Objects/BuiltElements/Revit/RevitBeam.cs b/Objects/Objects/BuiltElements/Revit/RevitBeam.cs index b483b12a11..6d7859e3da 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitBeam.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitBeam.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Objects.Geometry; using Objects.Utils; using Speckle.Core.Kits; using Speckle.Core.Models; @@ -9,20 +10,20 @@ public class RevitBeam : Beam { public RevitBeam() { } - [SchemaInfo("RevitBeam", "Creates a Revit beam by curve and base level.", "Revit", "Structure")] public RevitBeam( string family, string type, - [SchemaMainParam] ICurve baseLine, - Level level, + ICurve baseLine, + Level? level, + string? units, + List? displayValue = null, List? parameters = null ) + : base(baseLine, level, units, displayValue) { this.family = family; this.type = type; - this.baseLine = baseLine; this.parameters = parameters?.ToBase(); - this.level = level; } public string family { get; set; } @@ -35,4 +36,18 @@ public RevitBeam( get => base.level; set => base.level = value; } + + #region Schema Info Constructors + + [SchemaInfo("RevitBeam", "Creates a Revit beam by curve and base level.", "Revit", "Structure")] + public RevitBeam( + string family, + string type, + [SchemaMainParam] ICurve baseLine, + Level level, + List? parameters = null + ) + : this(family, type, baseLine, level, null, parameters: parameters) { } + + #endregion } diff --git a/Objects/Objects/BuiltElements/Revit/RevitBrace.cs b/Objects/Objects/BuiltElements/Revit/RevitBrace.cs index 99499f8826..dc92fbf296 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitBrace.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitBrace.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Objects.Geometry; using Objects.Utils; using Speckle.Core.Kits; using Speckle.Core.Models; @@ -9,25 +10,42 @@ public class RevitBrace : Brace { public RevitBrace() { } - [SchemaInfo("RevitBrace", "Creates a Revit brace by curve and base level.", "Revit", "Structure")] public RevitBrace( string family, string type, - [SchemaMainParam] ICurve baseLine, - Level level, + ICurve baseLine, + Level? level, + string? units, + string? elementId, + IReadOnlyList? displayValue = null, List? parameters = null ) + : base(baseLine, units, displayValue) { this.family = family; this.type = type; - this.baseLine = baseLine; - this.parameters = parameters?.ToBase(); this.level = level; + this.elementId = elementId; + this.parameters = parameters?.ToBase(); } public string family { get; set; } public string type { get; set; } public Base? parameters { get; set; } - public string elementId { get; set; } - public Level level { get; set; } + public string? elementId { get; set; } + public Level? level { get; set; } + + #region Schema Info Constructor + + [SchemaInfo("RevitBrace", "Creates a Revit brace by curve and base level.", "Revit", "Structure")] + public RevitBrace( + string family, + string type, + [SchemaMainParam] ICurve baseLine, + Level level, + List? parameters = null + ) + : this(family, type, baseLine, level, null, null, parameters: parameters) { } + + #endregion } diff --git a/Objects/Objects/BuiltElements/Revit/RevitColumn.cs b/Objects/Objects/BuiltElements/Revit/RevitColumn.cs index 5a770db9ba..64e4db93b0 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitColumn.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitColumn.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using Objects.Geometry; using Objects.Utils; using Speckle.Core.Kits; using Speckle.Core.Models; @@ -9,49 +11,82 @@ public class RevitColumn : Column { public RevitColumn() { } - /// - /// SchemaBuilder constructor for a Revit column - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to and params - [SchemaInfo("RevitColumn Vertical", "Creates a vertical Revit Column by point and levels.", "Revit", "Architecture")] public RevitColumn( string family, string type, - [SchemaParamInfo("Only the lower point of this line will be used as base point."), SchemaMainParam] ICurve baseLine, - Level level, - Level topLevel, + ICurve baseLine, + Level? level, + Level? topLevel, + string? units, + string? elementId, double baseOffset = 0, double topOffset = 0, - bool structural = false, - [SchemaParamInfo("Rotation angle in radians")] double rotation = 0, + bool facingFlipped = false, + bool handFlipped = false, + bool isSlanted = false, + double rotation = 0, + IReadOnlyList? displayValue = null, List? parameters = null ) + : base(baseLine, units, level, displayValue) { this.family = family; this.type = type; - this.baseLine = baseLine; this.topLevel = topLevel; + this.elementId = elementId; this.baseOffset = baseOffset; this.topOffset = topOffset; + this.facingFlipped = facingFlipped; + this.handFlipped = handFlipped; + this.isSlanted = isSlanted; this.rotation = rotation; this.parameters = parameters?.ToBase(); - this.level = level; } - [ - SchemaDeprecated, - SchemaInfo("RevitColumn Slanted (old)", "Creates a slanted Revit Column by curve.", "Revit", "Structure") - ] + public Level? topLevel { get; set; } + public double baseOffset { get; set; } + public double topOffset { get; set; } + public bool facingFlipped { get; set; } + public bool handFlipped { get; set; } + public double rotation { get; set; } + public bool isSlanted { get; set; } + public string family { get; set; } + public string type { get; set; } + public Base? parameters { get; set; } + public string? elementId { get; set; } + + #region Schema Info Constructors + + [SchemaInfo("RevitColumn Vertical", "Creates a vertical Revit Column by point and levels.", "Revit", "Architecture")] + public RevitColumn( + string family, + string type, + [SchemaParamInfo("Only the lower point of this line will be used as base point."), SchemaMainParam] ICurve baseLine, + Level level, + Level topLevel, + double baseOffset = 0, + double topOffset = 0, + bool structural = false, + [SchemaParamInfo("Rotation angle in radians")] double rotation = 0, + List? parameters = null + ) + : this( + family, + type, + baseLine, + level, + topLevel, + null, + null, + baseOffset, + topOffset, + rotation: rotation, + parameters: parameters + ) { } + + [Obsolete("Use other constructors")] + [SchemaDeprecated] + [SchemaInfo("RevitColumn Slanted (old)", "Creates a slanted Revit Column by curve.", "Revit", "Structure")] [System.Diagnostics.CodeAnalysis.SuppressMessage( "Style", "IDE0060:Remove unused parameter", @@ -84,31 +119,7 @@ public RevitColumn( bool structural = false, List? parameters = null ) - { - this.family = family; - this.type = type; - this.baseLine = baseLine; - this.level = level; - this.topLevel = topLevel; - isSlanted = true; - this.parameters = parameters?.ToBase(); - } - - public new Level? level - { - get => base.level; - set => base.level = value; - } + : this(family, type, baseLine, level, topLevel, null, null, displayValue: null, parameters: parameters) { } - public Level? topLevel { get; set; } - public double baseOffset { get; set; } - public double topOffset { get; set; } - public bool facingFlipped { get; set; } - public bool handFlipped { get; set; } - public double rotation { get; set; } - public bool isSlanted { get; set; } - public string family { get; set; } - public string type { get; set; } - public Base? parameters { get; set; } - public string elementId { get; set; } + #endregion } diff --git a/Objects/Objects/BuiltElements/Revit/RevitDuct.cs b/Objects/Objects/BuiltElements/Revit/RevitDuct.cs index 8c75f4ba04..1501466456 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitDuct.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitDuct.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Objects.BuiltElements.Revit.Interfaces; using Objects.Geometry; @@ -11,69 +12,52 @@ public class RevitDuct : Duct, IHasMEPConnectors { public RevitDuct() { } - /// - /// SchemaBuilder constructor for a Revit duct (deprecated) - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to , , and params - [SchemaInfo("RevitDuct", "Creates a Revit duct", "Revit", "MEP"), SchemaDeprecated] public RevitDuct( string family, string type, - [SchemaMainParam] Line baseLine, + ICurve baseCurve, string systemName, string systemType, Level level, double width, double height, double diameter, + double length, + string? units, + string? elementId, double velocity = 0, + IReadOnlyList? displayValue = null, List? parameters = null ) + : base(baseCurve, width, height, diameter, length, units, velocity, displayValue) { - baseCurve = baseLine; this.family = family; this.type = type; - this.width = width; - this.height = height; - this.diameter = diameter; - this.velocity = velocity; this.systemName = systemName; this.systemType = systemType; - this.parameters = parameters?.ToBase(); this.level = level; + this.parameters = parameters?.ToBase(); + this.elementId = elementId; } - /// - /// SchemaBuilder constructor for a Revit duct - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to , , and params - [SchemaInfo("RevitDuct", "Creates a Revit duct", "Revit", "MEP")] + public string family { get; set; } + public string type { get; set; } + public string systemName { get; set; } + public string systemType { get; set; } + public Level level { get; set; } + public Base? parameters { get; set; } + public string? elementId { get; set; } + public List Connectors { get; set; } = new(); + + #region Schema Info Constructors + + [SchemaInfo("RevitDuct (DEPRECATED)", "Creates a Revit duct", "Revit", "MEP")] + [SchemaDeprecated] + [Obsolete("Use other Constructor")] public RevitDuct( string family, string type, - [SchemaMainParam] ICurve baseCurve, + [SchemaMainParam] Line baseLine, string systemName, string systemType, Level level, @@ -84,7 +68,7 @@ public RevitDuct( List? parameters = null ) { - this.baseCurve = baseCurve; + baseCurve = baseLine; this.family = family; this.type = type; this.width = width; @@ -97,36 +81,44 @@ public RevitDuct( this.level = level; } - public string family { get; set; } - public string type { get; set; } - public string systemName { get; set; } - public string systemType { get; set; } - public Level level { get; set; } - public Base? parameters { get; set; } - public string elementId { get; set; } - public List Connectors { get; set; } = new(); + [SchemaInfo("RevitDuct", "Creates a Revit duct", "Revit", "MEP")] + public RevitDuct( + string family, + string type, + [SchemaMainParam] ICurve baseCurve, + string systemName, + string systemType, + Level level, + double width, + double height, + double diameter, + double velocity = 0, + List? parameters = null + ) + : this( + family, + type, + baseCurve, + systemName, + systemType, + level, + width, + height, + diameter, + default, //TODO: what to do with length? + null, + null, + velocity, + parameters: parameters + ) { } + + #endregion } public class RevitFlexDuct : RevitDuct { public RevitFlexDuct() { } - /// - /// SchemaBuilder constructor for a Revit flex duct - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to , , and params - [SchemaInfo("RevitFlexDuct", "Creates a Revit flex duct", "Revit", "MEP")] public RevitFlexDuct( string family, string type, @@ -137,27 +129,76 @@ public RevitFlexDuct( double width, double height, double diameter, + double length, Vector startTangent, Vector endTangent, + string? units, + string? elementId, double velocity = 0, + IReadOnlyList? displayValue = null, List? parameters = null ) + : base( + family, + type, + baseCurve, + systemName, + systemType, + level, + width, + height, + diameter, + length, + units, + elementId, + velocity, + displayValue, + parameters + ) { - this.baseCurve = baseCurve; - this.family = family; - this.type = type; - this.width = width; - this.height = height; - this.diameter = diameter; this.startTangent = startTangent; this.endTangent = endTangent; - this.velocity = velocity; - this.systemName = systemName; - this.systemType = systemType; - this.parameters = parameters?.ToBase(); - this.level = level; } public Vector startTangent { get; set; } public Vector endTangent { get; set; } + + #region Schema Info Constructor + + [SchemaInfo("RevitFlexDuct", "Creates a Revit flex duct", "Revit", "MEP")] + public RevitFlexDuct( + string family, + string type, + [SchemaMainParam] ICurve baseCurve, + string systemName, + string systemType, + Level level, + double width, + double height, + double diameter, + Vector startTangent, + Vector endTangent, + double velocity = 0, + List? parameters = null + ) + : this( + family, + type, + baseCurve, + systemName, + systemType, + level, + width, + height, + diameter, + 0, + startTangent, + endTangent, + null, + null, + velocity, + parameters: parameters + ) { } + + #endregion } diff --git a/Objects/Objects/BuiltElements/Revit/RevitWall.cs b/Objects/Objects/BuiltElements/Revit/RevitWall.cs index ac9d4bfe29..a9d59dc5ad 100644 --- a/Objects/Objects/BuiltElements/Revit/RevitWall.cs +++ b/Objects/Objects/BuiltElements/Revit/RevitWall.cs @@ -11,69 +11,84 @@ public class RevitWall : Wall { public RevitWall() { } - /// - /// SchemaBuilder constructor for a Revit wall - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to and params - [SchemaInfo( - "RevitWall by curve and levels", - "Creates a Revit wall with a top and base level.", - "Revit", - "Architecture" - )] public RevitWall( string family, string type, - [SchemaMainParam] ICurve baseLine, + ICurve baseLine, Level level, - Level topLevel, + Level? topLevel, + double height, + string? units, + string? elementId, double baseOffset = 0, double topOffset = 0, bool flipped = false, bool structural = false, - [SchemaParamInfo("Set in here any nested elements that this level might have.")] List? elements = null, + IReadOnlyList? displayValue = null, + List? elements = null, List? parameters = null ) + : base(height, units, baseLine, level, displayValue, elements) { this.family = family; this.type = type; - this.baseLine = baseLine; this.baseOffset = baseOffset; this.topOffset = topOffset; this.flipped = flipped; this.structural = structural; - this.level = level; + this.elementId = elementId; this.topLevel = topLevel; - this.elements = elements; this.parameters = parameters?.ToBase(); } - /// - /// SchemaBuilder constructor for a Revit wall - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Assign units when using this constructor due to , , and params + public string family { get; set; } + public string type { get; set; } + public double baseOffset { get; set; } + public double topOffset { get; set; } + public bool flipped { get; set; } + public bool structural { get; set; } + public Level? topLevel { get; set; } + public Base? parameters { get; set; } + public string? elementId { get; set; } + + #region Schema Info Constructors + + [SchemaInfo( + "RevitWall by curve and levels", + "Creates a Revit wall with a top and base level.", + "Revit", + "Architecture" + )] + public RevitWall( + string family, + string type, + [SchemaMainParam] ICurve baseLine, + Level level, + Level topLevel, + double baseOffset = 0, + double topOffset = 0, + bool flipped = false, + bool structural = false, + [SchemaParamInfo("Set in here any nested elements that this level might have.")] List? elements = null, + List? parameters = null + ) + : this( + family, + type, + baseLine, + level, + topLevel, + 0, + null, + null, + baseOffset, + topOffset, + flipped, + structural, + elements: elements, + parameters: parameters + ) { } + [SchemaInfo("RevitWall by curve and height", "Creates an unconnected Revit wall.", "Revit", "Architecture")] public RevitWall( string family, @@ -88,36 +103,23 @@ public RevitWall( [SchemaParamInfo("Set in here any nested elements that this wall might have.")] List? elements = null, List? parameters = null ) - { - this.family = family; - this.type = type; - this.baseLine = baseLine; - this.height = height; - this.baseOffset = baseOffset; - this.topOffset = topOffset; - this.flipped = flipped; - this.structural = structural; - this.level = level; - this.elements = elements; - this.parameters = parameters?.ToBase(); - } - - public string family { get; set; } - public string type { get; set; } - public double baseOffset { get; set; } - public double topOffset { get; set; } - public bool flipped { get; set; } - public bool structural { get; set; } - - public new Level? level - { - get => base.level; - set => base.level = value; - } - - public Level topLevel { get; set; } - public Base? parameters { get; set; } - public string elementId { get; set; } + : this( + family, + type, + baseLine, + level, + null, + height, + null, + null, + baseOffset, + topOffset, + flipped, + structural, + elements: elements, + parameters: parameters + ) { } + #endregion } public class RevitFaceWall : Wall diff --git a/Objects/Objects/BuiltElements/Wall.cs b/Objects/Objects/BuiltElements/Wall.cs index 9f6cb754d7..46b8684356 100644 --- a/Objects/Objects/BuiltElements/Wall.cs +++ b/Objects/Objects/BuiltElements/Wall.cs @@ -5,39 +5,48 @@ namespace Objects.BuiltElements; -public class Wall : Base, IDisplayValue> +public class Wall : Base, IDisplayValue> { public Wall() { } - /// - /// SchemaBuilder constructor for a Speckle wall - /// - /// - /// - /// - /// Assign units when using this constructor due to param - [SchemaInfo("Wall", "Creates a Speckle wall", "BIM", "Architecture")] public Wall( double height, - [SchemaMainParam] ICurve baseLine, - [SchemaParamInfo("Any nested elements that this wall might have")] List? elements = null + string? units, + ICurve baseLine, + Level? level = null, + IReadOnlyList? displayValue = null, + List? elements = null ) { this.height = height; + this.units = units; this.baseLine = baseLine; + this.level = level; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseLine }; this.elements = elements; } public double height { get; set; } - [DetachProperty] - public List? elements { get; set; } - + public string? units { get; set; } public ICurve baseLine { get; set; } public virtual Level? level { get; internal set; } - public string units { get; set; } + [DetachProperty] + public List? elements { get; set; } [DetachProperty] - public List displayValue { get; set; } + public IReadOnlyList displayValue { get; set; } + + #region SchemaInfo Ctors + + [SchemaInfo("Wall", "Creates a Speckle wall", "BIM", "Architecture")] + public Wall( + double height, + [SchemaMainParam] ICurve baseLine, + [SchemaParamInfo("Any nested elements that this wall might have")] List? elements = null + ) + : this(height, null, baseLine, null, null, elements) { } + + #endregion } diff --git a/Objects/Objects/Interfaces.cs b/Objects/Objects/Interfaces.cs index 4a4ff2d789..373e129d2e 100644 --- a/Objects/Objects/Interfaces.cs +++ b/Objects/Objects/Interfaces.cs @@ -28,7 +28,7 @@ public interface IHasArea /// /// The area of the object /// - double area { get; set; } + double area { get; } } /// @@ -39,7 +39,7 @@ public interface IHasVolume /// /// The volume of the object /// - double volume { get; set; } + double volume { get; } } /// @@ -50,12 +50,14 @@ public interface ICurve /// /// The length of the curve. /// - double length { get; set; } + double length { get; } /// /// The numerical domain driving the curve's internal parametrization. /// - Interval domain { get; set; } + Interval domain { get; } + + string units { get; } } /// @@ -101,13 +103,13 @@ public interface ITransformable /// Expected to be either a type or a of s, /// most likely or . /// -public interface IDisplayValue +public interface IDisplayValue { /// /// (s) will be used to display this /// if a native displayable object cannot be converted. /// - T displayValue { get; set; } + T displayValue { get; } } /// diff --git a/Objects/Objects/Objects.csproj b/Objects/Objects/Objects.csproj index 52f203fa66..62cb80c226 100644 --- a/Objects/Objects/Objects.csproj +++ b/Objects/Objects/Objects.csproj @@ -19,7 +19,7 @@ $(WarningsNotAsErrors); CA1008; CA1024; CA1034; CA1065; CA1708; CA1711; CA1716; CA1724; CA1725; - CA1819; + CA1819; CA2201; CA2225; CS0659; CS0661; CS0728; CS8618; IDE0041; IDE0060; IDE1006; diff --git a/Objects/Objects/Structural/Geometry/Element1D.cs b/Objects/Objects/Structural/Geometry/Element1D.cs index d1d74eab82..abce21d796 100644 --- a/Objects/Objects/Structural/Geometry/Element1D.cs +++ b/Objects/Objects/Structural/Geometry/Element1D.cs @@ -6,27 +6,74 @@ namespace Objects.Structural.Geometry; -public class Element1D : Base, IDisplayValue> +public class Element1D : Base, IDisplayValue> { public Element1D() { } - public Element1D(Line baseLine) + public Element1D( + Line baseLine, + Property1D property, + ElementType1D type, + string? name, + string? units, + Restraint? end1Releases = null, + Restraint? end2Releases = null, + Vector? end1Offset = null, + Vector? end2Offset = null, + Plane? localAxis = null, + Node? orientationNode = null, + double orientationAngle = 0, + IReadOnlyList? displayValue = null + ) { this.baseLine = baseLine; + this.property = property; + this.type = type; + this.name = name; + this.units = units; + this.end1Releases = end1Releases ?? new Restraint("FFFFFF"); + this.end2Releases = end2Releases ?? new Restraint("FFFFFF"); + this.end1Offset = end1Offset ?? new Vector(0, 0, 0); + this.end2Offset = end2Offset ?? new Vector(0, 0, 0); + this.localAxis = localAxis; + this.orientationNode = orientationNode; + this.orientationAngle = orientationAngle; + this.displayValue = ((IReadOnlyList?)displayValue) ?? new[] { (Base)baseLine }; } - /// - /// SchemaBuilder constructor for structural 1D element (based on local axis) - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// + public string? name { get; set; } //add unique id as base identifier, name can change too easily + public Line baseLine { get; set; } + + [DetachProperty] + public Property1D property { get; set; } + + public ElementType1D type { get; set; } + public Restraint end1Releases { get; set; } + public Restraint end2Releases { get; set; } + public Vector end1Offset { get; set; } + public Vector end2Offset { get; set; } + public Node? orientationNode { get; set; } + public double orientationAngle { get; set; } + public Plane? localAxis { get; set; } + + [DetachProperty] + public Base? parent { get; set; } //parent element + + [DetachProperty] + public Node? end1Node { get; set; } //startNode + + [DetachProperty] + public Node? end2Node { get; set; } //endNode + + [DetachProperty] + public List? topology { get; set; } + + public string? units { get; set; } + + [DetachProperty] + public IReadOnlyList displayValue { get; set; } + + #region Schema Info Constructors [SchemaInfo( "Element1D (from local axis)", "Creates a Speckle structural 1D element (from local axis)", @@ -46,31 +93,8 @@ public Element1D( [SchemaParamInfo("If null, defaults to no offsets")] Vector? end2Offset = null, Plane? localAxis = null ) - { - this.baseLine = baseLine; - this.property = property; - this.type = type; - this.name = name; - this.end1Releases = end1Releases ?? new Restraint("FFFFFF"); - this.end2Releases = end2Releases ?? new Restraint("FFFFFF"); - this.end1Offset = end1Offset ?? new Vector(0, 0, 0); - this.end2Offset = end2Offset ?? new Vector(0, 0, 0); - this.localAxis = localAxis; - } + : this(baseLine, property, type, name, null, end1Releases, end2Releases, end1Offset, end2Offset, localAxis) { } - /// - /// SchemaBuilder constructor for structural 1D element (based on orientation node and angle) - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// [SchemaInfo( "Element1D (from orientation node and angle)", "Creates a Speckle structural 1D element (from orientation node and angle)", @@ -91,48 +115,19 @@ public Element1D( Node? orientationNode = null, double orientationAngle = 0 ) - { - this.baseLine = baseLine; - this.property = property; - this.type = type; - this.name = name; - this.end1Releases = end1Releases ?? new Restraint("FFFFFF"); - this.end2Releases = end2Releases ?? new Restraint("FFFFFF"); - this.end1Offset = end1Offset ?? new Vector(0, 0, 0); - this.end2Offset = end2Offset ?? new Vector(0, 0, 0); - this.orientationNode = orientationNode; - this.orientationAngle = orientationAngle; - } - - public string? name { get; set; } //add unique id as base identifier, name can change too easily - public Line baseLine { get; set; } + : this( + baseLine, + property, + type, + name, + null, + end1Releases, + end2Releases, + end1Offset, + end2Offset, + orientationNode: orientationNode, + orientationAngle: orientationAngle + ) { } - [DetachProperty] - public Property1D property { get; set; } - - public ElementType1D type { get; set; } - public Restraint end1Releases { get; set; } - public Restraint end2Releases { get; set; } - public Vector end1Offset { get; set; } - public Vector end2Offset { get; set; } - public Node? orientationNode { get; set; } - public double orientationAngle { get; set; } - public Plane? localAxis { get; set; } - - [DetachProperty] - public Base parent { get; set; } //parent element - - [DetachProperty] - public Node end1Node { get; set; } //startNode - - [DetachProperty] - public Node end2Node { get; set; } //endNode - - [DetachProperty] - public List topology { get; set; } - - public string units { get; set; } - - [DetachProperty] - public List displayValue { get; set; } + #endregion } From 2e6e61f5f2e781b028f576ad477d7e93e6fa5742 Mon Sep 17 00:00:00 2001 From: Claire Kuang Date: Sat, 8 Jun 2024 08:20:50 -0700 Subject: [PATCH 04/12] CNX-9768: add additional properties to Civil3D pipes and structures (#3486) adds partdata to pressure pipes, and additional props to pipes and structures --- .../ConverterAutocadCivil.Civil.cs | 69 +++++++++++-------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs index fce119ee81..89f47ac800 100644 --- a/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs +++ b/Objects/Converters/ConverterAutocadCivil/ConverterAutocadCivilShared/ConverterAutocadCivil.Civil.cs @@ -12,7 +12,6 @@ using Civil = Autodesk.Civil; using Autodesk.AutoCAD.Geometry; using Acad = Autodesk.AutoCAD.Geometry; -using AcadDB = Autodesk.AutoCAD.DatabaseServices; using Objects.BuiltElements.Civil; using Alignment = Objects.BuiltElements.Alignment; @@ -1010,12 +1009,19 @@ public Structure StructureToSpeckle(CivilDB.Structure structure) }; // assign additional structure props - try { speckleStructure["grate"] = structure.Grate; } catch (Exception ex) when (!ex.IsFatal()) { } - try { speckleStructure["station"] = structure.Station; } catch (Exception ex) when (!ex.IsFatal()) { } - try { speckleStructure["network"] = structure.NetworkName; } catch (Exception ex) when (!ex.IsFatal()) { } AddNameAndDescriptionProperty(structure.Name, structure.Description, speckleStructure); speckleStructure["partData"] = PartDataRecordToSpeckle(structure.PartData); + try { speckleStructure["station"] = structure.Station; } catch (Exception ex) when (!ex.IsFatal()) { } + try { speckleStructure["network"] = structure.NetworkName; } catch (Exception ex) when (!ex.IsFatal()) { } + try { speckleStructure["rotation"] = structure.Rotation; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["sumpDepth"] = structure.SumpDepth; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["rimElevation"] = structure.RimElevation; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["sumpElevation"] = structure.SumpElevation; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["lengthOuter"] = structure.Length; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["lengthInner"] = structure.InnerLength; } catch (Exception e) when (!e.IsFatal()) { } + try { speckleStructure["structureId"] = structure.Id.ToString(); } catch (Exception ex) when (!ex.IsFatal()) { } + return speckleStructure; } @@ -1036,22 +1042,30 @@ private List PartDataRecordToSpeckle(PartDataRecord partData) return fields; } +#if CIVIL2022_OR_GREATER + /// + /// Converts PressureNetworkPartData into a list of DataField + /// + private List PartDataRecordToSpeckle(PressureNetworkPartData partData) + { + List fields = new(); + + foreach (PressurePartProperty partField in partData) + { + CivilDataField field = new(partField.Name, partField.GetType().ToString(), partField.Value, null, null, partField.DisplayName); + fields.Add(field); + } + + return fields; + } +#endif + // pipes // TODO: add pressure fittings public Pipe PipeToSpeckle(CivilDB.Pipe pipe) { - // get the pipe curve - ICurve curve; - switch (pipe.SubEntityType) - { - case PipeSubEntityType.Straight: - var line = new Acad.LineSegment3d(pipe.StartPoint, pipe.EndPoint); - curve = LineToSpeckle(line); - break; - default: - curve = CurveToSpeckle(pipe.BaseCurve); - break; - } + ICurve curve = CurveToSpeckle(pipe.BaseCurve); + Pipe specklePipe = new() { @@ -1075,8 +1089,9 @@ public Pipe PipeToSpeckle(CivilDB.Pipe pipe) try { specklePipe["endOffset"] = pipe.EndOffset; } catch(Exception ex) when(!ex.IsFatal()) { } try { specklePipe["startStation"] = pipe.StartStation; } catch(Exception ex) when(!ex.IsFatal()) { } try { specklePipe["endStation"] = pipe.EndStation; } catch(Exception ex) when(!ex.IsFatal()) { } - try { specklePipe["startStructure"] = pipe.StartStructureId.ToString(); } catch(Exception ex) when(!ex.IsFatal()) { } - try { specklePipe["endStructure"] = pipe.EndStructureId.ToString(); } catch(Exception ex) when(!ex.IsFatal()) { } + try { specklePipe["startStructureId"] = pipe.StartStructureId.ToString(); } catch(Exception ex) when(!ex.IsFatal()) { } + try { specklePipe["endStructureId"] = pipe.EndStructureId.ToString(); } catch(Exception ex) when(!ex.IsFatal()) { } + try { specklePipe["pipeId"] = pipe.Id.ToString(); } catch (Exception ex) when (!ex.IsFatal()) { } return specklePipe; } @@ -1084,17 +1099,7 @@ public Pipe PipeToSpeckle(CivilDB.Pipe pipe) public Pipe PipeToSpeckle(PressurePipe pipe) { // get the pipe curve - ICurve curve; - switch (pipe.BaseCurve) - { - case AcadDB.Line: - var line = new LineSegment3d(pipe.StartPoint, pipe.EndPoint); - curve = LineToSpeckle(line); - break; - default: - curve = CurveToSpeckle(pipe.BaseCurve); - break; - } + ICurve curve = CurveToSpeckle(pipe.BaseCurve); Pipe specklePipe = new() { @@ -1107,8 +1112,11 @@ public Pipe PipeToSpeckle(PressurePipe pipe) // assign additional pipe props AddNameAndDescriptionProperty(pipe.Name, pipe.Description, specklePipe); - specklePipe["isPressurePipe"] = true; +#if CIVIL2022_OR_GREATER + specklePipe["partData"] = PartDataRecordToSpeckle(pipe.PartData); +#endif + specklePipe["isPressurePipe"] = true; try { specklePipe["partType"] = pipe.PartType.ToString(); } catch (Exception e) when (!e.IsFatal()) { } try { specklePipe["slope"] = pipe.Slope; } catch (Exception e) when (!e.IsFatal()) { } try { specklePipe["network"] = pipe.NetworkName; } catch (Exception e) when (!e.IsFatal()) { } @@ -1116,6 +1124,7 @@ public Pipe PipeToSpeckle(PressurePipe pipe) try { specklePipe["endOffset"] = pipe.EndOffset; } catch (Exception e) when (!e.IsFatal()) { } try { specklePipe["startStation"] = pipe.StartStation; } catch (Exception e) when (!e.IsFatal()) { } try { specklePipe["endStation"] = pipe.EndStation; } catch (Exception e) when (!e.IsFatal()) { } + try { specklePipe["pipeId"] = pipe.Id.ToString(); } catch (Exception ex) when (!ex.IsFatal()) { } return specklePipe; } From c4cd55edac6ffa3c3e313a0201e64decd9a7af38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20L=2E=20Kiss?= <50739844+jozseflkiss@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:20:12 +0200 Subject: [PATCH 05/12] bug(Archicad): Properties not showing in viewer (#3472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * export properties of GDL objects * build fix * build fix --------- Co-authored-by: József L. Kiss <> --- .../Commands/Command_GetElementBaseData.cs | 17 ++++++----------- .../Converters/DirectShapeConverter.cs | 15 ++++++++++++--- .../Converters/Converters/Utils.cs | 3 ++- .../BuiltElements/Archicad/DirectShape.cs | 3 +++ 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs index 56fe20729e..82d9499427 100644 --- a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetElementBaseData.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; using System.Threading.Tasks; -using Speckle.Core.Kits; -using Speckle.Newtonsoft.Json; -using Objects.BuiltElements.Archicad; using ConnectorArchicad.Communication.Commands; +using Objects.BuiltElements.Archicad; +using Speckle.Newtonsoft.Json; namespace Archicad.Communication.Commands; -sealed internal class GetElementBaseData : GetDataBase, ICommand> +sealed internal class GetElementBaseData : GetDataBase, ICommand { [JsonObject(MemberSerialization.OptIn)] private sealed class Result @@ -19,17 +18,13 @@ private sealed class Result public GetElementBaseData(IEnumerable applicationIds, bool sendProperties, bool sendListingParameters) : base(applicationIds, sendProperties, sendListingParameters) { } - public async Task> Execute() + public async Task Execute() { - Result result = await HttpCommandExecutor.Execute( + dynamic result = await HttpCommandExecutor.Execute( "GetElementBaseData", new Parameters(ApplicationIds, SendProperties, SendListingParameters) ); - foreach (var directShape in result.Datas) - { - directShape.units = Units.Meters; - } - return result.Datas; + return (Speckle.Newtonsoft.Json.Linq.JArray)result["elements"]; } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs index c47a607798..fdb4711d10 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/DirectShapeConverter.cs @@ -7,6 +7,7 @@ using Archicad.Model; using Archicad.Operations; using Objects.Geometry; +using Speckle.Core.Kits; using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; @@ -73,6 +74,7 @@ CancellationToken token IEnumerable result; result = await AsyncCommandProcessor.Execute(new Communication.Commands.CreateDirectShape(directShapes), token); + return result is null ? new List() : result.ToList(); } @@ -83,7 +85,8 @@ ConversionOptions conversionOptions ) { var elementModels = elements as ElementModelData[] ?? elements.ToArray(); - IEnumerable data = await AsyncCommandProcessor.Execute( + + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( new Communication.Commands.GetElementBaseData( elementModels.Select(e => e.applicationId), conversionOptions.SendProperties, @@ -93,7 +96,7 @@ ConversionOptions conversionOptions ); var directShapes = new List(); - if (data is null) + if (jArray is null) { return directShapes; } @@ -103,12 +106,18 @@ ConversionOptions conversionOptions context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToSpeckle, Type.Name) ) { - foreach (Objects.BuiltElements.Archicad.DirectShape directShape in data) + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) { + // convert between DTOs + Objects.BuiltElements.Archicad.DirectShape directShape = + Archicad.Converters.Utils.ConvertToSpeckleDTOs(jToken); + { + directShape.units = Units.Meters; directShape.displayValue = Operations.ModelConverter.MeshesToSpeckle( elementModels.First(e => e.applicationId == directShape.applicationId).model ); + directShapes.Add(directShape); } } diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs index 792d1992e7..c2b992c49f 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs @@ -180,7 +180,8 @@ public static T ConvertToSpeckleDTOs(dynamic jObject) if (level != null) { - PropertyInfo propLevel = speckleObject.GetType().GetProperty("archicadLevel"); + PropertyInfo propLevel = + speckleObject.GetType().GetProperty("archicadLevel") ?? speckleObject.GetType().GetProperty("level"); propLevel.SetValue(speckleObject, level); } diff --git a/Objects/Objects/BuiltElements/Archicad/DirectShape.cs b/Objects/Objects/BuiltElements/Archicad/DirectShape.cs index 8b2f11caf0..8ae08ece91 100644 --- a/Objects/Objects/BuiltElements/Archicad/DirectShape.cs +++ b/Objects/Objects/BuiltElements/Archicad/DirectShape.cs @@ -16,7 +16,10 @@ public DirectShape(string applicationId, List displayValue) // Element base public string elementType { get; set; } + public List classifications { get; set; } + public Base? elementProperties { get; set; } + public Base? componentProperties { get; set; } public ArchicadLevel level { get; set; } From f37ad906940129f5e88d3d9775811556d1d9061d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zsef=20L=2E=20Kiss?= <50739844+jozseflkiss@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:24:54 +0200 Subject: [PATCH 06/12] feat(Archicad): Add support for openings (#3470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add support for openings Co-authored-by: József L. Kiss <> --- .../AddOn/Sources/AddOn/AddOnMain.cpp | 4 + .../Sources/AddOn/Commands/CreateOpening.cpp | 373 ++++++++++++++++++ .../Sources/AddOn/Commands/CreateOpening.hpp | 33 ++ .../AddOn/Commands/CreateOpeningBase.cpp | 9 +- .../Sources/AddOn/Commands/GetDoorData.hpp | 4 +- .../Sources/AddOn/Commands/GetOpeningData.cpp | 156 ++++++++ .../Sources/AddOn/Commands/GetOpeningData.hpp | 24 ++ .../AddOn/Sources/AddOn/FieldNames.hpp | 68 ++++ .../AddOn/Sources/AddOn/ResourceIds.hpp | 2 + .../AddOn/Sources/AddOn/TypeNameTables.cpp | 60 +++ .../AddOn/Sources/AddOn/TypeNameTables.hpp | 8 + .../Commands/Command_CreateOpening.cs | 42 ++ .../Commands/Command_GetOpening.cs | 21 + .../Converters/ConverterArchicad.cs | 1 + .../Converters/Converters/OpeningConverter.cs | 135 +++++++ .../Converters/Converters/Utils.cs | 8 + .../Converters/ElementConverterManager.cs | 22 +- .../Converters/ElementTypeProvider.cs | 4 +- .../Converters/ModelConverter.cs | 208 ++++++++++ .../BuiltElements/Archicad/ArchicadOpening.cs | 83 ++++ 20 files changed, 1259 insertions(+), 6 deletions(-) create mode 100644 ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.cpp create mode 100644 ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.hpp create mode 100644 ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.cpp create mode 100644 ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.hpp create mode 100644 ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateOpening.cs create mode 100644 ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetOpening.cs create mode 100644 ConnectorArchicad/ConnectorArchicad/Converters/Converters/OpeningConverter.cs create mode 100644 Objects/Objects/BuiltElements/Archicad/ArchicadOpening.cs diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp index 532f056af6..67e1d73399 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp @@ -18,6 +18,7 @@ #include "Commands/GetElementBaseData.hpp" #include "Commands/GetGridElementData.hpp" #include "Commands/GetObjectData.hpp" +#include "Commands/GetOpeningData.hpp" #include "Commands/GetSlabData.hpp" #include "Commands/GetRoofData.hpp" #include "Commands/GetShellData.hpp" @@ -31,6 +32,7 @@ #include "Commands/CreateColumn.hpp" #include "Commands/CreateGridElement.hpp" #include "Commands/CreateObject.hpp" +#include "Commands/CreateOpening.hpp" #include "Commands/CreateRoof.hpp" #include "Commands/CreateSkylight.hpp" #include "Commands/CreateSlab.hpp" @@ -200,6 +202,7 @@ static GSErrCode RegisterAddOnCommands () CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); + CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); @@ -213,6 +216,7 @@ static GSErrCode RegisterAddOnCommands () CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); + CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); CHECKERROR (ACAPI_AddOnAddOnCommunication_InstallAddOnCommandHandler (NewOwned ())); diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.cpp new file mode 100644 index 0000000000..7db770d5e1 --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.cpp @@ -0,0 +1,373 @@ +#include "CreateOpening.hpp" +#include "ResourceIds.hpp" +#include "ObjectState.hpp" +#include "Utility.hpp" +#include "Objects/Point.hpp" +#include "Objects/Vector.hpp" +#include "RealNumber.h" +#include "DGModule.hpp" +#include "LibpartImportManager.hpp" +#include "APIHelper.hpp" +#include "FieldNames.hpp" +#include "OnExit.hpp" +#include "ExchangeManager.hpp" +#include "TypeNameTables.hpp" +#include "Database.hpp" +#include "BM.hpp" + + +using namespace FieldNames; + + +namespace AddOnCommands +{ + + +GS::String CreateOpening::GetFieldName () const +{ + return FieldNames::Openings; +} + + +GS::UniString CreateOpening::GetUndoableCommandName () const +{ + return "CreateSpeckleOpening"; +} + + +GS::ErrCode CreateOpening::GetElementFromObjectState (const GS::ObjectState& os, + API_Element& element, + API_Element& elementMask, + API_ElementMemo& memo, + GS::UInt64& /*memoMask*/, + API_SubElement** /*marker*/, + AttributeManager& /*attributeManager*/, + LibpartImportManager& /*libpartImportManager*/, + GS::Array& log) const +{ + GS::ErrCode err = NoError; + + Utility::SetElementType (element.header, API_OpeningID); + + err = Utility::GetBaseElementData (element, &memo, nullptr, log); + if (err != NoError) + return err; + + err = GetElementBaseFromObjectState (os, element, elementMask); + if (err != NoError) + return err; + + if (!CheckEnvironment (os, element)) + return Error; + + if (os.Contains (Opening::FloorPlanDisplayMode)) { + GS::UniString floorPlanDisplayModeName; + os.Get (Opening::FloorPlanDisplayMode, floorPlanDisplayModeName); + + GS::Optional type = openingFloorPlanDisplayModeNames.FindValue (floorPlanDisplayModeName); + if (type.HasValue ()) { + element.opening.floorPlanParameters.floorPlanDisplayMode = type.Get (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.floorPlanDisplayMode); + } + } + + if (os.Contains (Opening::ConnectionMode)) { + GS::UniString connectionModeName; + os.Get (Opening::ConnectionMode, connectionModeName); + + GS::Optional type = openingFloorPlanConnectionModeNames.FindValue (connectionModeName); + if (type.HasValue ()) { + element.opening.floorPlanParameters.connectionMode = type.Get (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.connectionMode); + } + } + + if (os.Contains (Opening::CutSurfacesUseLineOfCutElements)) { + os.Get (Opening::CutSurfacesUseLineOfCutElements, element.opening.floorPlanParameters.cutSurfacesParameters.useLineOfCutElements); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.cutSurfacesParameters.useLineOfCutElements); + } + + if (os.Contains (Opening::CutSurfacesLinePenIndex)) { + os.Get (Opening::CutSurfacesLinePenIndex, element.opening.floorPlanParameters.cutSurfacesParameters.linePenIndex); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.cutSurfacesParameters.linePenIndex); + } + + GS::UniString attributeName; + if (os.Contains (Opening::CutSurfacesLineIndex)) { + + os.Get (Opening::CutSurfacesLineIndex, attributeName); + + if (!attributeName.IsEmpty ()) { + API_Attribute attrib; + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + CHCopyC (attributeName.ToCStr (), attrib.header.name); + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + element.opening.floorPlanParameters.cutSurfacesParameters.lineIndex = attrib.header.index; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.cutSurfacesParameters.lineIndex); + } + } + } + + if (os.Contains (Opening::OutlinesStyle)) { + GS::UniString outlinesStyleName; + os.Get (Opening::OutlinesStyle, outlinesStyleName); + + GS::Optional type = openingOutlinesStyleNames.FindValue (outlinesStyleName); + if (type.HasValue ()) { + element.opening.floorPlanParameters.outlinesParameters.outlinesStyle = type.Get (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.outlinesParameters.outlinesStyle); + } + } + + if (os.Contains (Opening::OutlinesUseLineOfCutElements)) { + os.Get (Opening::OutlinesUseLineOfCutElements, element.opening.floorPlanParameters.outlinesParameters.useLineOfCutElements); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.outlinesParameters.useLineOfCutElements); + } + + if (os.Contains (Opening::OutlinesUncutLineIndex)) { + + os.Get (Opening::OutlinesUncutLineIndex, attributeName); + + if (!attributeName.IsEmpty ()) { + API_Attribute attrib; + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + CHCopyC (attributeName.ToCStr (), attrib.header.name); + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + element.opening.floorPlanParameters.outlinesParameters.uncutLineIndex = attrib.header.index; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.outlinesParameters.uncutLineIndex); + } + } + } + + if (os.Contains (Opening::OutlinesOverheadLineIndex)) { + + os.Get (Opening::OutlinesOverheadLineIndex, attributeName); + + if (!attributeName.IsEmpty ()) { + API_Attribute attrib; + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + CHCopyC (attributeName.ToCStr (), attrib.header.name); + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + element.opening.floorPlanParameters.outlinesParameters.overheadLineIndex = attrib.header.index; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.outlinesParameters.overheadLineIndex); + } + } + } + + if (os.Contains (Opening::OutlinesOverheadLinePenIndex)) { + os.Get (Opening::OutlinesOverheadLinePenIndex, element.opening.floorPlanParameters.outlinesParameters.overheadLinePenIndex); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.outlinesParameters.overheadLinePenIndex); + } + + if (os.Contains (Opening::UseCoverFills)) { + os.Get (Opening::UseCoverFills, element.opening.floorPlanParameters.coverFillsParameters.useCoverFills); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.useCoverFills); + } + + if (os.Contains (Opening::UseFillsOfCutElements)) { + os.Get (Opening::UseFillsOfCutElements, element.opening.floorPlanParameters.coverFillsParameters.useFillsOfCutElements); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.useFillsOfCutElements); + } + + if (os.Contains (Opening::CoverFillIndex)) { + + os.Get (Opening::CoverFillIndex, attributeName); + + if (!attributeName.IsEmpty ()) { + API_Attribute attrib; + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_FilltypeID; + CHCopyC (attributeName.ToCStr (), attrib.header.name); + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + element.opening.floorPlanParameters.coverFillsParameters.coverFillIndex = attrib.header.index; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.coverFillIndex); + } + } + } + + if (os.Contains (Opening::CoverFillPenIndex)) { + os.Get (Opening::CoverFillPenIndex, element.opening.floorPlanParameters.coverFillsParameters.coverFillPenIndex); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.coverFillPenIndex); + } + + if (os.Contains (Opening::CoverFillBackgroundPenIndex)) { + os.Get (Opening::CoverFillBackgroundPenIndex, element.opening.floorPlanParameters.coverFillsParameters.coverFillBackgroundPenIndex); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.coverFillBackgroundPenIndex); + } + + if (os.Contains (Opening::CoverFillOrientation)) { + os.Get (Opening::CoverFillOrientation, element.opening.floorPlanParameters.coverFillsParameters.coverFillOrientation); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillsParameters.coverFillOrientation); + } + + if (os.Contains (Opening::CoverFillTransformationOrigoX)) { + os.Get (Opening::CoverFillTransformationOrigoX, element.opening.floorPlanParameters.coverFillTransformation.origo.x); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.origo.x); + } + + if (os.Contains (Opening::CoverFillTransformationOrigoY)) { + os.Get (Opening::CoverFillTransformationOrigoY, element.opening.floorPlanParameters.coverFillTransformation.origo.y); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.origo.y); + } + + if (os.Contains (Opening::CoverFillTransformationXAxisX)) { + os.Get (Opening::CoverFillTransformationXAxisX, element.opening.floorPlanParameters.coverFillTransformation.xAxis.x); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.xAxis.x); + } + + if (os.Contains (Opening::CoverFillTransformationXAxisY)) { + os.Get (Opening::CoverFillTransformationXAxisY, element.opening.floorPlanParameters.coverFillTransformation.xAxis.y); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.xAxis.y); + } + + if (os.Contains (Opening::CoverFillTransformationYAxisX)) { + os.Get (Opening::CoverFillTransformationYAxisX, element.opening.floorPlanParameters.coverFillTransformation.yAxis.x); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.yAxis.x); + } + + if (os.Contains (Opening::CoverFillTransformationYAxisY)) { + os.Get (Opening::CoverFillTransformationYAxisY, element.opening.floorPlanParameters.coverFillTransformation.yAxis.y); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.coverFillTransformation.yAxis.y); + } + + if (os.Contains (Opening::ShowReferenceAxis)) { + os.Get (Opening::ShowReferenceAxis, element.opening.floorPlanParameters.referenceAxisParameters.showReferenceAxis); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.referenceAxisParameters.showReferenceAxis); + } + + if (os.Contains (Opening::ReferenceAxisPenIndex)) { + os.Get (Opening::ReferenceAxisPenIndex, element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisPenIndex); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.referenceAxisParameters.referenceAxisPenIndex); + } + + if (os.Contains (Opening::ReferenceAxisLineTypeIndex)) { + + os.Get (Opening::ReferenceAxisLineTypeIndex, attributeName); + + if (!attributeName.IsEmpty ()) { + API_Attribute attrib; + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + CHCopyC (attributeName.ToCStr (), attrib.header.name); + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisLineTypeIndex = attrib.header.index; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.referenceAxisParameters.referenceAxisLineTypeIndex); + } + } + } + + if (os.Contains (Opening::ReferenceAxisOverhang)) { + os.Get (Opening::ReferenceAxisOverhang, element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisOverhang); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, floorPlanParameters.referenceAxisParameters.referenceAxisOverhang); + } + + Objects::Point3D basePoint; + if (os.Contains (Opening::ExtrusionGeometryBasePoint)) { + os.Get (Opening::ExtrusionGeometryBasePoint, basePoint); + element.opening.extrusionGeometryData.frame.basePoint = basePoint.ToAPI_Coord3D (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.frame.basePoint); + } + + Objects::Vector3D axisX; + if (os.Contains (Opening::ExtrusionGeometryXAxis)) { + os.Get (Opening::ExtrusionGeometryXAxis, axisX); + element.opening.extrusionGeometryData.frame.axisX = axisX.ToAPI_Vector3D (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.frame.axisX); + } + + Objects::Vector3D axisY; + if (os.Contains (Opening::ExtrusionGeometryYAxis)) { + os.Get (Opening::ExtrusionGeometryYAxis, axisY); + element.opening.extrusionGeometryData.frame.axisY = axisY.ToAPI_Vector3D (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.frame.axisY); + } + + Objects::Vector3D axisZ; + if (os.Contains (Opening::ExtrusionGeometryZAxis)) { + os.Get (Opening::ExtrusionGeometryZAxis, axisZ); + element.opening.extrusionGeometryData.frame.axisZ = axisZ.ToAPI_Vector3D (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.frame.axisZ); + } + + if (os.Contains (Opening::BasePolygonType)) { + GS::UniString basePolygonTypeName; + os.Get (Opening::BasePolygonType, basePolygonTypeName); + + GS::Optional type = openingBasePolygonTypeNames.FindValue (basePolygonTypeName); + if (type.HasValue ()) { + element.opening.extrusionGeometryData.parameters.basePolygonType = type.Get (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.basePolygonType); + } + } + + if (os.Contains (Opening::Width)) { + os.Get (Opening::Width, element.opening.extrusionGeometryData.parameters.width); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.width); + + element.opening.extrusionGeometryData.parameters.linkedStatus = API_OpeningNotLinked; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.linkedStatus); + } + + if (os.Contains (Opening::Height)) { + os.Get (Opening::Height, element.opening.extrusionGeometryData.parameters.height); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.height); + + element.opening.extrusionGeometryData.parameters.linkedStatus = API_OpeningNotLinked; + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.linkedStatus); + } + + if (os.Contains (Opening::Constraint)) { + os.Get (Opening::Constraint, element.opening.extrusionGeometryData.parameters.constraint); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.constraint); + } + + if (os.Contains (Opening::AnchorIndex)) { + os.Get (Opening::AnchorIndex, element.opening.extrusionGeometryData.parameters.anchor); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.anchor); + } + + if (os.Contains (Opening::AnchorAltitude)) { + os.Get (Opening::AnchorAltitude, element.opening.extrusionGeometryData.parameters.anchorAltitude); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.anchorAltitude); + } + + if (os.Contains (Opening::LimitType)) { + GS::UniString limitTypeName; + os.Get (Opening::LimitType, limitTypeName); + + GS::Optional type = openingLimitTypeNames.FindValue (limitTypeName); + if (type.HasValue ()) { + element.opening.extrusionGeometryData.parameters.limitType = type.Get (); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.limitType); + } + } + + if (os.Contains (Opening::ExtrusionStartOffSet)) { + os.Get (Opening::ExtrusionStartOffSet, element.opening.extrusionGeometryData.parameters.extrusionStartOffset); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.extrusionStartOffset); + } + + if (os.Contains (Opening::FiniteBodyLength)) { + os.Get (Opening::FiniteBodyLength, element.opening.extrusionGeometryData.parameters.finiteBodyLength); + ACAPI_ELEMENT_MASK_SET (elementMask, API_OpeningType, extrusionGeometryData.parameters.finiteBodyLength); + } + + return err; +} + + +GS::String CreateOpening::GetName () const +{ + return CreateOpeningCommandName; +} + + +} \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.hpp new file mode 100644 index 0000000000..8c9203b298 --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpening.hpp @@ -0,0 +1,33 @@ +#ifndef CREATE_OPENING_HPP +#define CREATE_OPENING_HPP + +#include "CreateOpeningBase.hpp" +#include "FieldNames.hpp" + + +namespace AddOnCommands { + + +class CreateOpening : public CreateOpeningBase { + GS::String GetFieldName () const override; + GS::UniString GetUndoableCommandName () const override; + + GSErrCode GetElementFromObjectState (const GS::ObjectState& os, + API_Element& element, + API_Element& elementMask, + API_ElementMemo& memo, + GS::UInt64& memoMask, + API_SubElement** marker, + AttributeManager& attributeManager, + LibpartImportManager& libpartImportManager, + GS::Array& log) const override; + +public: + virtual GS::String GetName () const override; +}; + + +} + + +#endif // !CREATE_OPENING_HPP \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpeningBase.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpeningBase.cpp index d9582c709a..4c91bc8095 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpeningBase.cpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/CreateOpeningBase.cpp @@ -29,7 +29,8 @@ bool CreateOpeningBase::CheckEnvironment (const GS::ObjectState& os, API_Element bool isParentWall = Utility::GetElementType (parentArchicadId) == API_WallID; bool isParentRoof = Utility::GetElementType (parentArchicadId) == API_RoofID; bool isParentShell = Utility::GetElementType (parentArchicadId) == API_ShellID; - if (!(parentExists && (isParentWall || isParentRoof || isParentShell))) { + bool isParentSlab = Utility::GetElementType (parentArchicadId) == API_SlabID; + if (!(parentExists && (isParentWall || isParentRoof || isParentShell || isParentSlab))) { return false; } @@ -45,6 +46,8 @@ bool CreateOpeningBase::CheckEnvironment (const GS::ObjectState& os, API_Element Utility::SetElementType (elem.header, API_RoofID); } else if (isParentShell) { Utility::SetElementType (elem.header, API_ShellID); + } else if (isParentSlab) { + Utility::SetElementType (elem.header, API_SlabID); } elem.header.guid = parentArchicadId; @@ -61,6 +64,10 @@ bool CreateOpeningBase::CheckEnvironment (const GS::ObjectState& os, API_Element element.window.owner = parentArchicadId; } else if (elementType == API_SkylightID) { element.skylight.owner = parentArchicadId; + } else if (elementType == API_OpeningID) { + element.opening.owner = parentArchicadId; + } else if (elementType == API_SlabID) { + element.opening.owner = parentArchicadId; } return true; diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetDoorData.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetDoorData.hpp index 317ad154f1..a5a69c739b 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetDoorData.hpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetDoorData.hpp @@ -1,5 +1,5 @@ -#ifndef GET_OPENING_DATA_HPP -#define GET_OPENING_DATA_HPP +#ifndef GET_DOOR_DATA_HPP +#define GET_DOOR_DATA_HPP #include "GetDataCommand.hpp" diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.cpp new file mode 100644 index 0000000000..54e4f1691f --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.cpp @@ -0,0 +1,156 @@ +#include "GetOpeningData.hpp" +#include "ResourceIds.hpp" +#include "ObjectState.hpp" +#include "Utility.hpp" +#include "Objects/Point.hpp" +#include "Objects/Vector.hpp" +#include "RealNumber.h" +#include "FieldNames.hpp" +#include "TypeNameTables.hpp" +using namespace FieldNames; + + +namespace AddOnCommands { + + +GS::String GetOpeningData::GetFieldName () const +{ + return Openings; +} + + +API_ElemTypeID GetOpeningData::GetElemTypeID () const +{ + return API_OpeningID; +} + + +GS::ErrCode GetOpeningData::SerializeElementType (const API_Element& element, + const API_ElementMemo& /*memo*/, + GS::ObjectState& os) const +{ + os.Add (ElementBase::ParentElementId, APIGuidToString (element.opening.owner)); + + API_Attribute attrib; + + // Opening Floor Parameters + os.Add (Opening::FloorPlanDisplayMode, openingFloorPlanDisplayModeNames.Get (element.opening.floorPlanParameters.floorPlanDisplayMode)); + os.Add (Opening::ConnectionMode, openingFloorPlanConnectionModeNames.Get (element.opening.floorPlanParameters.connectionMode)); + + // Opening Floor Plan Parameters - Cut Surfaces + os.Add (Opening::CutSurfacesUseLineOfCutElements, element.opening.floorPlanParameters.cutSurfacesParameters.useLineOfCutElements); + os.Add (Opening::CutSurfacesLinePenIndex, element.opening.floorPlanParameters.cutSurfacesParameters.linePenIndex); + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + attrib.header.index = element.opening.floorPlanParameters.cutSurfacesParameters.lineIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::CutSurfacesLineIndex, GS::UniString{attrib.header.name}); + } + + // Opening Floor Plan Parameters - Outlines Parameters + os.Add (Opening::OutlinesStyle, openingOutlinesStyleNames.Get (element.opening.floorPlanParameters.outlinesParameters.outlinesStyle)); + os.Add (Opening::OutlinesUseLineOfCutElements, element.opening.floorPlanParameters.outlinesParameters.useLineOfCutElements); + + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + attrib.header.index = element.opening.floorPlanParameters.outlinesParameters.uncutLineIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::OutlinesUncutLineIndex, GS::UniString{attrib.header.name}); + } + + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + attrib.header.index = element.opening.floorPlanParameters.outlinesParameters.overheadLineIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::OutlinesOverheadLineIndex, GS::UniString{attrib.header.name}); + } + + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + attrib.header.index = element.opening.floorPlanParameters.outlinesParameters.uncutLineIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::OutlinesUncutLineIndex, GS::UniString{attrib.header.name}); + } + os.Add (Opening::OutlinesOverheadLinePenIndex, element.opening.floorPlanParameters.outlinesParameters.overheadLinePenIndex); + + // Opening Floor Plan Parameters - Cover Fills + os.Add (Opening::UseCoverFills, element.opening.floorPlanParameters.coverFillsParameters.useCoverFills); + if (element.opening.floorPlanParameters.coverFillsParameters.useCoverFills) { + os.Add (Opening::UseFillsOfCutElements, element.opening.floorPlanParameters.coverFillsParameters.useFillsOfCutElements); + + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_FilltypeID; + attrib.header.index = element.opening.floorPlanParameters.coverFillsParameters.coverFillIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::CoverFillIndex, GS::UniString{attrib.header.name}); + } + + os.Add (Opening::CoverFillPenIndex, element.opening.floorPlanParameters.coverFillsParameters.coverFillPenIndex); + os.Add (Opening::CoverFillBackgroundPenIndex, element.opening.floorPlanParameters.coverFillsParameters.coverFillBackgroundPenIndex); + os.Add (Opening::CoverFillOrientation, element.opening.floorPlanParameters.coverFillsParameters.coverFillOrientation); + } + + // Opening Floor Plan Parameters - Cover Fill Transformation + os.Add (Opening::CoverFillTransformationOrigoX, element.opening.floorPlanParameters.coverFillTransformation.origo.x); + os.Add (Opening::CoverFillTransformationOrigoY, element.opening.floorPlanParameters.coverFillTransformation.origo.y); + os.Add (Opening::CoverFillTransformationXAxisX, element.opening.floorPlanParameters.coverFillTransformation.xAxis.x); + os.Add (Opening::CoverFillTransformationXAxisY, element.opening.floorPlanParameters.coverFillTransformation.xAxis.y); + os.Add (Opening::CoverFillTransformationYAxisX, element.opening.floorPlanParameters.coverFillTransformation.yAxis.x); + os.Add (Opening::CoverFillTransformationYAxisY, element.opening.floorPlanParameters.coverFillTransformation.yAxis.y); + + // Opening Floor Plan Parameters - Reference Axis + os.Add (Opening::ShowReferenceAxis, element.opening.floorPlanParameters.referenceAxisParameters.showReferenceAxis); + if (element.opening.floorPlanParameters.referenceAxisParameters.showReferenceAxis) { + os.Add (Opening::ReferenceAxisPenIndex, element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisPenIndex); + + BNZeroMemory (&attrib, sizeof (API_Attribute)); + attrib.header.typeID = API_LinetypeID; + attrib.header.index = element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisLineTypeIndex; + + if (NoError == ACAPI_Attribute_Get (&attrib)) { + os.Add (Opening::ReferenceAxisLineTypeIndex, GS::UniString{attrib.header.name}); + } + + os.Add (Opening::ReferenceAxisOverhang, element.opening.floorPlanParameters.referenceAxisParameters.referenceAxisOverhang); + } + + // Extrusion Geometry + os.Add (Opening::ExtrusionGeometryBasePoint, Objects::Point3D (element.opening.extrusionGeometryData.frame.basePoint)); + os.Add (Opening::ExtrusionGeometryXAxis, Objects::Vector3D(element.opening.extrusionGeometryData.frame.axisX)); + os.Add (Opening::ExtrusionGeometryYAxis, Objects::Vector3D (element.opening.extrusionGeometryData.frame.axisY)); + os.Add (Opening::ExtrusionGeometryZAxis, Objects::Vector3D (element.opening.extrusionGeometryData.frame.axisZ)); + + // Extrusion Geometry - Opening Extrusion Parameters + os.Add (Opening::BasePolygonType, openingBasePolygonTypeNames.Get (element.opening.extrusionGeometryData.parameters.basePolygonType)); + os.Add (Opening::Width, element.opening.extrusionGeometryData.parameters.width); + os.Add (Opening::Height, element.opening.extrusionGeometryData.parameters.height); + os.Add (Opening::Constraint, element.opening.extrusionGeometryData.parameters.constraint); + os.Add (Opening::Anchor, openingAnchorNames.Get (element.opening.extrusionGeometryData.parameters.anchor)); + os.Add (Opening::AnchorIndex, (element.opening.extrusionGeometryData.parameters.anchor)); + os.Add (Opening::AnchorAltitude, element.opening.extrusionGeometryData.parameters.anchorAltitude); + os.Add (Opening::LimitType, openingLimitTypeNames.Get (element.opening.extrusionGeometryData.parameters.limitType)); + os.Add (Opening::ExtrusionStartOffSet, element.opening.extrusionGeometryData.parameters.extrusionStartOffset); + os.Add (Opening::FiniteBodyLength, element.opening.extrusionGeometryData.parameters.finiteBodyLength); + os.Add (Opening::LinkedStatus, openingLinkedStatusNames.Get (element.opening.extrusionGeometryData.parameters.linkedStatus)); + + // Extrusion Geometry - Custom Base Polygon + if (element.opening.extrusionGeometryData.parameters.basePolygonType == API_OpeningBasePolygonCustom) { + // Reserved for future use + } + + return NoError; +} + + +GS::String GetOpeningData::GetName () const +{ + return GetOpeningDataCommandName; +} + + +} // namespace AddOnCommands diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.hpp new file mode 100644 index 0000000000..0a30edd766 --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOn/Commands/GetOpeningData.hpp @@ -0,0 +1,24 @@ +#ifndef GET_OPENING_DATA_HPP +#define GET_OPENING_DATA_HPP + +#include "GetDataCommand.hpp" + +namespace AddOnCommands { + + +class GetOpeningData : public GetDataCommand { + GS::String GetFieldName() const override; + API_ElemTypeID GetElemTypeID() const override; + GS::ErrCode SerializeElementType(const API_Element& elem, + const API_ElementMemo& memo, + GS::ObjectState& os) const override; + +public: + virtual GS::String GetName() const override; +}; + + +} + + +#endif // GET_OPENING_DATA_HPP \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/FieldNames.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/FieldNames.hpp index 64c80772da..3b05a70287 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/FieldNames.hpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/FieldNames.hpp @@ -83,6 +83,7 @@ static const char* Slabs = "slabs"; static const char* Walls = "walls"; static const char* Windows = "windows"; static const char* Zones = "zones"; +static const char* Openings = "openings"; static const char* Models = "models"; static const char* SubelementModels = "subelementModels"; @@ -474,6 +475,73 @@ static const char* pos = "pos"; static const char* transform = "transform"; } + +namespace Opening +{ +// Floor Plan Parameters +static const char* FloorPlanDisplayMode = "floorPlanDisplayMode"; +static const char* ConnectionMode = "connectionMode"; + +// Cut Surfaces Parameters +static const char* CutSurfacesUseLineOfCutElements = "cutsurfacesUseLineOfCutElements"; +static const char* CutSurfacesLinePenIndex = "cutsurfacesLinePenIndex"; +static const char* CutSurfacesLineIndex = "cutsurfacesLineIndex"; + +// Outlines Parameters +static const char* OutlinesStyle = "outlinesStyle"; +static const char* OutlinesUseLineOfCutElements = "outlinesUseLineOfCutElements"; // => Cut Surfaces Parameters-ben is megtallhat +static const char* OutlinesUncutLineIndex = "outlinesUncutLineIndex"; +static const char* OutlinesOverheadLineIndex = "outlinesOverheadLineIndex"; +static const char* OutlinesUncutLinePenIndex = "outlinesUncutLinePenIndex"; +static const char* OutlinesOverheadLinePenIndex = "outlinesOverheadLinePenIndex"; + +// Opening Cover Fills Parameters +static const char* UseCoverFills = "useCoverFills"; +static const char* UseFillsOfCutElements = "useFillsOfCutElements"; +static const char* CoverFillIndex = "coverFillIndex"; +static const char* CoverFillPenIndex = "coverFillPenIndex"; +static const char* CoverFillBackgroundPenIndex = "coverFillBackgroundPenIndex"; +static const char* CoverFillOrientation = "coverFillOrientation"; + +// Cover Fill Transformation Parameters +static const char* CoverFillTransformationOrigoX = "coverFillTransformationOrigoX"; +static const char* CoverFillTransformationOrigoY = "coverFillTransformationOrigoY"; +static const char* CoverFillTransformationOrigoZ = "coverFillTransformationOrigoZ"; +static const char* CoverFillTransformationXAxisX = "coverFillTransformationXAxisX"; +static const char* CoverFillTransformationXAxisY = "coverFillTransformationXAxisY"; +static const char* CoverFillTransformationXAxisZ = "coverFillTransformationXAxisZ"; +static const char* CoverFillTransformationYAxisX = "coverFillTransformationYAxisX"; +static const char* CoverFillTransformationYAxisY = "coverFillTransformationYAxisY"; +static const char* CoverFillTransformationYAxisZ = "coverFillTransformationYAxisZ"; + +// Reference Axis Parameters +static const char* ShowReferenceAxis = "showReferenceAxis"; +static const char* ReferenceAxisPenIndex = "referenceAxisPenIndex"; +static const char* ReferenceAxisLineTypeIndex = "referenceAxisLineTypeIndex"; +static const char* ReferenceAxisOverhang = "referenceAxisOverhang"; + +// Extrusion Geometry Parameters +static const char* ExtrusionGeometryBasePoint = "extrusionGeometryBasePoint"; +static const char* ExtrusionGeometryXAxis = "extrusionGeometryXAxis"; +static const char* ExtrusionGeometryYAxis = "extrusionGeometryYAxis"; +static const char* ExtrusionGeometryZAxis = "extrusionGeometryZAxis"; +static const char* BasePolygonType = "basePolygonType"; +static const char* Width = "width"; +static const char* Height = "height"; +static const char* Constraint = "constraint"; +static const char* Anchor = "anchor"; +static const char* AnchorIndex = "anchorIndex"; +static const char* AnchorAltitude = "anchorAltitude"; +static const char* LimitType = "limitType"; +static const char* ExtrusionStartOffSet = "extrusionStartOffSet"; +static const char* FiniteBodyLength = "finiteBodyLength"; +static const char* LinkedStatus = "linkedStatus"; +static const char* NCoords = "nCoords"; +static const char* NSubPolys = "nSubPolys"; +static const char* NArcs = "nArcs"; +} + + namespace GridElement { // Main diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/ResourceIds.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/ResourceIds.hpp index 147706b24e..3b71424e11 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/ResourceIds.hpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/ResourceIds.hpp @@ -24,6 +24,7 @@ #define GetElementBaseDataCommandName "GetElementBaseData"; #define GetGridElementCommandName "GetGridElementData"; #define GetObjectDataCommandName "GetObjectData"; +#define GetOpeningDataCommandName "GetOpeningData"; #define GetSlabDataCommandName "GetSlabData"; #define GetRoomDataCommandName "GetRoomData"; #define GetRoofDataCommandName "GetRoofData"; @@ -38,6 +39,7 @@ #define CreateColumnCommandName "CreateColumn"; #define CreateGridElementCommandName "CreateGridElement"; #define CreateObjectCommandName "CreateObject"; +#define CreateOpeningCommandName "CreateOpening"; #define CreateSlabCommandName "CreateSlab"; #define CreateSkylightCommandName "CreateSkylight"; #define CreateRoofCommandName "CreateRoof"; diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.cpp index 52c35275b6..610edbc1cc 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.cpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.cpp @@ -301,3 +301,63 @@ const GS::HashTable coreSymbolTypeNames { 3, "X"}, { 4, "CrossHair"} }; + + +const GS::HashTable openingFloorPlanDisplayModeNames +{ + { API_OpeningSymbolic, "Symbolic"}, + { API_OpeningSymbolicCut, "Symbolic Cut"}, + { API_OpeningSymbolicOverhead, "Symbolic Overhead"} +}; + + +const GS::HashTable openingFloorPlanConnectionModeNames +{ + { API_OpeningDisconnected, "Disconnected"}, + { API_OpeningConnected, "Connected"} +}; + + +const GS::HashTable openingOutlinesStyleNames +{ + { API_OpeningHideBorder, "Hide Border"}, + { API_OpeningShowUncutBorder, "Show Uncut Border"}, + { API_OpeningShowOverheadBorder, "Show Overhead Border"} +}; + + +const GS::HashTable openingBasePolygonTypeNames +{ + { API_OpeningBasePolygonRectangular, "Rectangular"}, + { API_OpeningBasePolygonCircular, "Circular"}, + { API_OpeningBasePolygonCustom, "Custom"} +}; + + +const GS::HashTable openingAnchorNames +{ + { APIAnc_LT, "Left Top"}, + { APIAnc_MT, "Middle Top"}, + { APIAnc_RT, "Right Top"}, + { APIAnc_LM, "Left Middle"}, + { APIAnc_MM, "Middle Middle"}, + { APIAnc_RM, "Right Middle"}, + { APIAnc_LB, "Left Bottom"}, + { APIAnc_MB, "Middle Bottom"}, + { APIAnc_RB, "Right Bottom"} +}; + + +const GS::HashTable openingLimitTypeNames +{ + { API_OpeningLimitInfinite, "Infinite"}, + { API_OpeningLimitFinite, "Finite"}, + { API_OpeningLimitHalfInfinite, "Half Infinite"} +}; + + +const GS::HashTable openingLinkedStatusNames +{ + { API_OpeningLinked, "Linked"}, + { API_OpeningNotLinked, "Not Linked"} +}; \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.hpp b/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.hpp index b478c0ca60..12d8488997 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.hpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/TypeNameTables.hpp @@ -45,4 +45,12 @@ extern const GS::HashTable venTypeNames; extern const GS::HashTable coreSymbolTypeNames; +extern const GS::HashTable openingFloorPlanDisplayModeNames; +extern const GS::HashTable openingFloorPlanConnectionModeNames; +extern const GS::HashTable openingOutlinesStyleNames; +extern const GS::HashTable openingBasePolygonTypeNames; +extern const GS::HashTable openingAnchorNames; + +extern const GS::HashTable openingLimitTypeNames; +extern const GS::HashTable openingLinkedStatusNames; #endif diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateOpening.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateOpening.cs new file mode 100644 index 0000000000..ab65f3dde1 --- /dev/null +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_CreateOpening.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Speckle.Core.Models; +using Speckle.Newtonsoft.Json; +using Objects.BuiltElements.Archicad; + +namespace Archicad.Communication.Commands; + +sealed internal class CreateOpening : ICommand> +{ + [JsonObject(MemberSerialization.OptIn)] + public sealed class Parameters + { + [JsonProperty("openings")] + private IEnumerable Datas { get; } + + public Parameters(IEnumerable datas) + { + Datas = datas; + } + } + + [JsonObject(MemberSerialization.OptIn)] + private sealed class Result + { + [JsonProperty("applicationObjects")] + public IEnumerable ApplicationObjects { get; private set; } + } + + private IEnumerable Datas { get; } + + public CreateOpening(IEnumerable datas) + { + Datas = datas; + } + + public async Task> Execute() + { + var result = await HttpCommandExecutor.Execute("CreateOpening", new Parameters(Datas)); + return result == null ? null : result.ApplicationObjects; + } +} diff --git a/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetOpening.cs b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetOpening.cs new file mode 100644 index 0000000000..5e64507ed7 --- /dev/null +++ b/ConnectorArchicad/ConnectorArchicad/Communication/Commands/Command_GetOpening.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ConnectorArchicad.Communication.Commands; + +namespace Archicad.Communication.Commands; + +sealed internal class GetOpeningData : GetDataBase, ICommand +{ + public GetOpeningData(IEnumerable applicationIds, bool sendProperties, bool sendListingParameters) + : base(applicationIds, sendProperties, sendListingParameters) { } + + public async Task Execute() + { + dynamic result = await HttpCommandExecutor.Execute( + "GetOpeningData", + new Parameters(ApplicationIds, SendProperties, SendListingParameters) + ); + + return (Speckle.Newtonsoft.Json.Linq.JArray)result["openings"]; + } +} diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs index 29506c6a58..c00821258c 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ConverterArchicad.cs @@ -68,6 +68,7 @@ public bool CanConvertToNativeImplemented(Base @object) Objects.BuiltElements.Roof _ => true, Objects.BuiltElements.Room _ => true, Objects.BuiltElements.Wall _ => true, + Objects.BuiltElements.Opening _ => true, // Archicad elements Objects.BuiltElements.Archicad.ArchicadDoor _ => true, diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/OpeningConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/OpeningConverter.cs new file mode 100644 index 0000000000..a7bf40d31f --- /dev/null +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/OpeningConverter.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Archicad.Communication; +using Archicad.Model; +using Speckle.Core.Kits; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using Speckle.Core.Models.GraphTraversal; + +namespace Archicad.Converters; + +public sealed class OpeningConverter : IConverter +{ + public Type Type => typeof(Objects.BuiltElements.Opening); + + public Task> ConvertToArchicad( + IEnumerable elements, + CancellationToken token + ) + { + var openings = new List(); + + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) + ) + { + foreach (var tc in elements) + { + token.ThrowIfCancellationRequested(); + + switch (tc.current) + { + case Objects.BuiltElements.Archicad.ArchicadOpening archicadOpening: + archicadOpening.parentApplicationId = tc.parent.current.id; + Archicad.Converters.Utils.ConvertToArchicadDTOs( + archicadOpening + ); + openings.Add(archicadOpening); + break; + case Objects.BuiltElements.Opening opening: + try + { + Objects.Geometry.Vector extrusionBasePoint, + extrusionXAxis, + extrusionYAxis, + extrusionZAxis; + double width, + height; + Operations.ModelConverter.GetExtrusionParametersFromOutline( + opening.outline, + out extrusionBasePoint, + out extrusionXAxis, + out extrusionYAxis, + out extrusionZAxis, + out width, + out height + ); + openings.Add( + new Objects.BuiltElements.Archicad.ArchicadOpening + { + id = opening.id, + applicationId = opening.applicationId, + parentApplicationId = tc.parent.current.id, + extrusionGeometryBasePoint = new Objects.Geometry.Point(extrusionBasePoint), + extrusionGeometryXAxis = extrusionXAxis, + extrusionGeometryYAxis = extrusionYAxis, + extrusionGeometryZAxis = extrusionZAxis, + width = width, + height = height, + anchorIndex = 4, + } + ); + } + catch (SpeckleException ex) + { + SpeckleLog.Logger.Error(ex.Message); + } + break; + } + } + + IEnumerable result; + result = AsyncCommandProcessor.Execute(new Communication.Commands.CreateOpening(openings), token).Result; + + return Task.FromResult(result is null ? new List() : result.ToList()); + } + } + + public async Task> ConvertToSpeckle( + IEnumerable elements, + CancellationToken token, + ConversionOptions conversionOptions + ) + { + var elementModels = elements as ElementModelData[] ?? elements.ToArray(); + + Speckle.Newtonsoft.Json.Linq.JArray jArray = await AsyncCommandProcessor.Execute( + new Communication.Commands.GetOpeningData( + elementModels.Select(e => e.applicationId), + conversionOptions.SendProperties, + conversionOptions.SendListingParameters + ), + token + ); + + List openings = new(); + if (jArray is null) + { + return openings; + } + + var context = Archicad.Helpers.Timer.Context.Peek; + using ( + context?.cumulativeTimer?.Begin(ConnectorArchicad.Properties.OperationNameTemplates.ConvertToNative, Type.Name) + ) + { + foreach (Speckle.Newtonsoft.Json.Linq.JToken jToken in jArray) + { + Objects.BuiltElements.Archicad.ArchicadOpening opening = + Archicad.Converters.Utils.ConvertToSpeckleDTOs(jToken); + { + opening.outline = Operations.ModelConverter.CreateOpeningOutline(opening); + opening.units = Units.Meters; + } + openings.Add(opening); + } + } + + return openings; + } +} diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs index c2b992c49f..eb0e7e1477 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/Converters/Utils.cs @@ -68,6 +68,14 @@ public static MeshModel.Vertex PointToNative(Point point, string? units = null) }; } + public static Vector ScaleToNative(Vector vector, string? units = null) + { + units ??= vector.units; + var scale = Units.GetConversionFactor(units, Units.Meters); + + return new Vector(vector.x * scale, vector.y * scale, vector.z * scale); + } + public static Polycurve PolycurveToSpeckle(ElementShape.Polyline archiPolyline) { var poly = new Polycurve diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs index 330860564c..287ba885c4 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ElementConverterManager.cs @@ -13,6 +13,7 @@ using Column = Objects.BuiltElements.Column; using Door = Objects.BuiltElements.Archicad.ArchicadDoor; using Fenestration = Objects.BuiltElements.Archicad.ArchicadFenestration; +using Opening = Objects.BuiltElements.Opening; using Floor = Objects.BuiltElements.Floor; using Roof = Objects.BuiltElements.Roof; using Wall = Objects.BuiltElements.Wall; @@ -20,6 +21,7 @@ using Skylight = Objects.BuiltElements.Archicad.ArchicadSkylight; using GridLine = Objects.BuiltElements.GridLine; using DesktopUI2.Models; +using Objects.BuiltElements.Archicad; namespace Archicad; @@ -95,13 +97,24 @@ private ElementConverterManager() allObjects.AddRange(objects); // subelements translated into "elements" property of the parent - if (typeof(Fenestration).IsAssignableFrom(elemenType)) + if (typeof(Fenestration).IsAssignableFrom(elemenType) || typeof(Opening).IsAssignableFrom(elemenType)) { Collection elementCollection = null; foreach (Base item in objects) { - Base parent = allObjects.Find(x => x.applicationId == ((Fenestration)item).parentApplicationId); + string parentApplicationId = null; + + if (item is Fenestration fenestration) + { + parentApplicationId = fenestration.parentApplicationId; + } + else if (item is ArchicadOpening opening) + { + parentApplicationId = opening.parentApplicationId; + } + + Base parent = allObjects.Find(x => x.applicationId == parentApplicationId); if (parent == null) { @@ -247,6 +260,11 @@ bool forReceive return Converters[typeof(Roof)]; } + if (elementType.IsSubclassOf(typeof(Opening))) + { + return Converters[typeof(Opening)]; + } + if (elementType.IsAssignableFrom(typeof(Objects.BuiltElements.Room))) { return Converters[typeof(Archicad.Room)]; diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs index da11c33ced..a2cb24e846 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ElementTypeProvider.cs @@ -10,6 +10,7 @@ using Wall = Objects.BuiltElements.Archicad.ArchicadWall; using Window = Objects.BuiltElements.Archicad.ArchicadWindow; using Skylight = Objects.BuiltElements.Archicad.ArchicadSkylight; +using Opening = Objects.BuiltElements.Archicad.ArchicadOpening; namespace Archicad; @@ -28,7 +29,8 @@ public static class ElementTypeProvider { "Door", typeof(Door) }, { "Window", typeof(Window) }, { "Skylight", typeof(Skylight) }, - { "GridElement", typeof(GridElement) } + { "GridElement", typeof(GridElement) }, + { "Opening", typeof(Opening) } }; public static Type GetTypeByName(string name) diff --git a/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs b/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs index f19785f14a..b8db6345f7 100644 --- a/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs +++ b/ConnectorArchicad/ConnectorArchicad/Converters/ModelConverter.cs @@ -3,6 +3,8 @@ using System.Linq; using Archicad.Converters; using Archicad.Model; +using Objects.BuiltElements.Archicad; +using Objects; using Objects.Geometry; using Objects.Other; using Objects.Utils; @@ -393,4 +395,210 @@ MeshModel meshModel return angleCos > angleCosLimit; } + + public static ICurve CreateOpeningOutline(ArchicadOpening opening) + { + double halfWidth = opening.width / 2.0 ?? 0.0; + double halfHeight = opening.height / 2.0 ?? 0.0; + Vector basePoint = new(0, 0, 0); + Vector extrusionBasePoint = new(opening.extrusionGeometryBasePoint); + + // Speckle datastructure does not handle the translation component, which we will use manually later, so its left empty. + System.DoubleNumerics.Matrix4x4 rotMatrix = + new( + (float)opening.extrusionGeometryXAxis.x, + (float)opening.extrusionGeometryXAxis.y, + (float)opening.extrusionGeometryXAxis.z, + 0, + (float)opening.extrusionGeometryYAxis.x, + (float)opening.extrusionGeometryYAxis.y, + (float)opening.extrusionGeometryYAxis.z, + 0, + (float)opening.extrusionGeometryZAxis.x, + (float)opening.extrusionGeometryZAxis.y, + (float)opening.extrusionGeometryZAxis.z, + 0, + 0, + 0, + 0, + 1 + ); + + Objects.Other.Transform transform = new(System.DoubleNumerics.Matrix4x4.Transpose(rotMatrix)); + + AdjustBasePoint(ref basePoint, halfWidth, halfHeight, opening.anchorIndex ?? 0); + + return opening.basePolygonType == "Rectangular" + ? CreateRectangle(basePoint, transform, extrusionBasePoint, halfWidth, halfHeight) + : CreateEllipse(basePoint, transform, extrusionBasePoint, halfWidth, halfHeight, opening); + } + + private static readonly Action[] anchorActions = new Action[] + { + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = halfWidth; + basePoint.y = -halfHeight; + }, // APIAnc_LT + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.y = -halfHeight; + }, // APIAnc_MT + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = -halfWidth; + basePoint.y = -halfHeight; + }, // APIAnc_RT + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = halfWidth; + }, // APIAnc_LM + (Vector basePoint, double halfWidth, double halfHeight) => { }, // APIAnc_MM + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = -halfWidth; + }, // APIAnc_RM + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = halfWidth; + basePoint.y = halfHeight; + }, // APIAnc_LB + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.y = halfHeight; + }, // APIAnc_MB + (Vector basePoint, double halfWidth, double halfHeight) => + { + basePoint.x = -halfWidth; + basePoint.y = halfHeight; + } // APIAnc_RB + }; + + private static void AdjustBasePoint(ref Vector basePoint, double halfWidth, double halfHeight, int anchor) + { + if (anchor >= 0 && anchor < anchorActions.Length) + { + anchorActions[anchor](basePoint, halfWidth, halfHeight); + } + } + + private static Polyline CreateRectangle( + Vector basePoint, + Objects.Other.Transform transform, + Vector extrusionBasePoint, + double halfWidth, + double halfHeight + ) + { + var poly = new Objects.Geometry.Polyline + { + value = new List(), + closed = true, + units = Units.Meters + }; + + // Coordinates of the four corners of the rectangle + Vector[] points = + { + new(-halfWidth, -halfHeight, 0), + new(halfWidth, -halfHeight, 0), + new(halfWidth, halfHeight, 0), + new(-halfWidth, halfHeight, 0) + }; + + // Transform the points to the correct position + foreach (var point in points) + { + Vector transformedPoint = point + basePoint; + transformedPoint.TransformTo(transform, out transformedPoint); + transformedPoint += extrusionBasePoint; + poly.value.AddRange(transformedPoint.ToList()); + } + + // Close the polyline + poly.value.AddRange(poly.value.Take(3)); + + return poly; + } + + private static Ellipse CreateEllipse( + Vector basePoint, + Objects.Other.Transform transform, + Vector extrusionBasePoint, + double halfWidth, + double halfHeight, + ArchicadOpening opening + ) + { + Vector centerPoint = new(basePoint.x, basePoint.y, basePoint.z); + centerPoint.TransformTo(transform, out centerPoint); + centerPoint += extrusionBasePoint; + + Point center = new(centerPoint.x, centerPoint.y, centerPoint.z); + + Objects.Geometry.Plane plane = + new(center, opening.extrusionGeometryZAxis, opening.extrusionGeometryXAxis, opening.extrusionGeometryYAxis); + + return new Ellipse(plane, halfWidth, halfHeight, Units.Meters); + } + + public static void GetExtrusionParametersFromOutline( + ICurve outline, + out Vector extrusionBasePoint, + out Vector extrusionXAxis, + out Vector extrusionYAxis, + out Vector extrusionZAxis, + out double width, + out double height + ) + { + // Assign default values to out parameters + extrusionBasePoint = new Vector(); + extrusionXAxis = new Vector(); + extrusionYAxis = new Vector(); + extrusionZAxis = new Vector(); + width = 0; + height = 0; + + if (outline is not Polyline polyline) + { + extrusionBasePoint = null; + extrusionXAxis = null; + extrusionYAxis = null; + extrusionZAxis = null; + return; + } + + // Form the 4 points of the rectangle from the polyline + List points = Enumerable + .Range(0, polyline.value.Count / 3) + .Select( + i => new Vector(polyline.value[i * 3], polyline.value[i * 3 + 1], polyline.value[i * 3 + 2], polyline.units) + ) + .ToList(); + + Vector bottomLeft = Utils.ScaleToNative(points[0]); + Vector topLeft = Utils.ScaleToNative(points[1]); + Vector topRight = Utils.ScaleToNative(points[2]); + Vector bottomRight = Utils.ScaleToNative(points[3]); + + // We set the anchor point to Middle-Middle, so we can calculate the extrusion base point more easily like so. + extrusionBasePoint = (bottomLeft + bottomRight + topRight + topLeft) * 0.25; + + Vector verticalDiff = topRight - bottomRight; + height = verticalDiff.Length; + + extrusionYAxis = verticalDiff / height; + + Vector horizontalDiff = bottomRight - bottomLeft; + width = horizontalDiff.Length; + + // Calculate the extrusion X axis + extrusionXAxis = horizontalDiff / width; + + // The last extrusion axis will be the cross product of the other two + extrusionZAxis = Vector.CrossProduct(extrusionXAxis, extrusionYAxis); + + extrusionZAxis.Normalize(); + } } diff --git a/Objects/Objects/BuiltElements/Archicad/ArchicadOpening.cs b/Objects/Objects/BuiltElements/Archicad/ArchicadOpening.cs new file mode 100644 index 0000000000..3c501c95bf --- /dev/null +++ b/Objects/Objects/BuiltElements/Archicad/ArchicadOpening.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using Speckle.Core.Kits; +using Speckle.Core.Models; +using Objects.Geometry; + +namespace Objects.BuiltElements.Archicad; + +public class ArchicadOpening : Opening +{ + [SchemaInfo("ArchicadOpening", "Creates an Archicad opening.", "Archicad", "Structure")] + public ArchicadOpening() { } + + public string parentApplicationId { get; set; } + + // Element base + public string? elementType { get; set; } /*APINullabe*/ + + public List? classifications { get; set; } /*APINullabe*/ + public Base? elementProperties { get; set; } + public Base? componentProperties { get; set; } + + // Floor Plan Parameters + public string? floorPlanDisplayMode { get; set; } /*APINullabe*/ + public string? connectionMode { get; set; } /*APINullabe*/ + + // Cut Surfaces Parameters + public bool? cutsurfacesUseLineOfCutElements { get; set; } /*APINullabe*/ + public short? cutsurfacesLinePenIndex { get; set; } /*APINullabe*/ + public string? cutsurfacesLineIndex { get; set; } /*APINullabe*/ + + // Outlines Parameters + public string? outlinesStyle { get; set; } /*APINullabe*/ + public bool? outlinesUseLineOfCutElements { get; set; } /*APINullabe*/ + public string? outlinesUncutLineIndex { get; set; } /*APINullabe*/ + public string? outlinesOverheadLineIndex { get; set; } /*APINullabe*/ + public short? outlinesUncutLinePenIndex { get; set; } /*APINullabe*/ + public short? outlinesOverheadLinePenIndex { get; set; } /*APINullabe*/ + + // Opening Cover Fills Parameters + public bool? useCoverFills { get; set; } /*APINullabe*/ + public bool? useFillsOfCutElements { get; set; } /*APINullabe*/ + public string? coverFillIndex { get; set; } /*APINullabe*/ + public short? coverFillPenIndex { get; set; } /*APINullabe*/ + public short? coverFillBackgroundPenIndex { get; set; } /*APINullabe*/ + public string? coverFillOrientation { get; set; } /*APINullabe*/ // Kérdéses.. + + // Cover Fill Transformation Parameters + public double? coverFillTransformationOrigoX { get; set; } + public double? coverFillTransformationOrigoY { get; set; } + public double? coverFillTransformationOrigoZ { get; set; } + public double? coverFillTransformationXAxisX { get; set; } + public double? coverFillTransformationXAxisY { get; set; } + public double? coverFillTransformationXAxisZ { get; set; } + public double? coverFillTransformationYAxisX { get; set; } + public double? coverFillTransformationYAxisY { get; set; } + public double? coverFillTransformationYAxisZ { get; set; } + + // Reference Axis Parameters + public bool? showReferenceAxis { get; set; } /*APINullabe*/ + public short? referenceAxisPenIndex { get; set; } /*APINullabe*/ + public string? referenceAxisLineTypeIndex { get; set; } /*APINullabe*/ + public double? referenceAxisOverhang { get; set; } /*APINullabe*/ + + // Extrusion Geometry Parameters + // Plane Frame + public Point extrusionGeometryBasePoint { get; set; } + public Vector extrusionGeometryXAxis { get; set; } + public Vector extrusionGeometryYAxis { get; set; } + public Vector extrusionGeometryZAxis { get; set; } + + // Opening Extrustion Parameters + public string? basePolygonType { get; set; } /*APINullabe*/ + public double? width { get; set; } /*APINullabe*/ + public double? height { get; set; } /*APINullabe*/ + public string? constraint { get; set; } /*APINullabe*/ + public string? anchor { get; set; } /*APINullabe */ + public int? anchorIndex { get; set; } /*APINullabe*/ + public double? anchorAltitude { get; set; } /*APINullabe*/ + public string? limitType { get; set; } /*APINullabe*/ + public double? extrusionStartOffSet { get; set; } /*APINullabe*/ + public double? finiteBodyLength { get; set; } /*APINullabe*/ + public string? linkedStatus { get; set; } /*APINullabe*/ +} From aa132d24ead30e4b5648b54be90d1e5cf94e79a8 Mon Sep 17 00:00:00 2001 From: Claire Kuang Date: Wed, 12 Jun 2024 21:21:28 +0100 Subject: [PATCH 07/12] Update README.md (#3502) --- ConnectorAutocadCivil/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ConnectorAutocadCivil/README.md b/ConnectorAutocadCivil/README.md index 9b74423e0d..02e9f4749b 100644 --- a/ConnectorAutocadCivil/README.md +++ b/ConnectorAutocadCivil/README.md @@ -4,13 +4,13 @@ ## Introduction -This is the ⚠ALPHA⚠ version of the Speckle 2.0 AutoCAD Civil3D Connector. Currently, it only supports the very most basic conversions - please leave any comments, suggestions, and feature requests in our [Making Speckle](https://discourse.speckle.works/t/new-speckle-2-0-autocad-civil3d-suggestions/1155) forum discussion thread! +This is the ⚠Beta⚠ version of the Speckle 2.0 AutoCAD Civil3D Connector. Currently, it supports the basic objects for both Autocad and Civil3D (refer to our docs for a full list) - please leave any comments, suggestions, and feature requests in our [Making Speckle](https://discourse.speckle.works/t/new-speckle-2-0-autocad-civil3d-suggestions/1155) forum discussion thread! ## Documentation Comprehensive developer and user documentation can be found in our: -#### 📚 [Speckle Docs website](https://speckle.guide/dev/) +#### 📚 [Speckle Docs website](https://speckle.guide/user/autocadcivil.html) ## Developing & Debugging @@ -21,8 +21,8 @@ Comprehensive developer and user documentation can be found in our: #### Supported versions -- AutoCAD: 2021, 2022 -- Civil3D: 2021, 2022 +- AutoCAD: 2021, 2022, 2023, 2024, 2025 +- Civil3D: 2021, 2022, 2023, 2024, 2025 ### Getting Started From 14788666f8c377abdbcf54a1905968fe33eb546f Mon Sep 17 00:00:00 2001 From: Alan Rynne Date: Thu, 13 Jun 2024 17:01:39 +0200 Subject: [PATCH 08/12] Archicad: Update connector icon on mac (#3503) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update connector icon for mac * use sln name * fix: Moved bundle and zipping steps after external PR check to ensure normal build CI works even with external contributors --------- Co-authored-by: József L. Kiss <> --- .circleci/scripts/config-template.yml | 51 +++++++++++------- .../AddOn/Sources/AddOn/AddOnMain.cpp | 43 +++++++-------- .../Sources/AddOnResources/RFIX/AddOnFix.grc | 8 ++- .../RFIX/Images/AddOnIconMac_18x18.svg | 18 +++++++ .../RFIX/Images/AddOnIconWin_18x18.svg | 17 ++++++ .../RFIX/Images/AddOnIcon_18x18.svg | 1 - .../ConnectorArchicad/Assets/icon-mac.icns | Bin 0 -> 37877 bytes .../ConnectorArchicad.csproj | 1 + .../ConnectorArchicad/Info.plist | 39 ++++++++++++++ 9 files changed, 133 insertions(+), 45 deletions(-) create mode 100644 ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconMac_18x18.svg create mode 100644 ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconWin_18x18.svg delete mode 100644 ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIcon_18x18.svg create mode 100644 ConnectorArchicad/ConnectorArchicad/Assets/icon-mac.icns create mode 100644 ConnectorArchicad/ConnectorArchicad/Info.plist diff --git a/.circleci/scripts/config-template.yml b/.circleci/scripts/config-template.yml index f64173dbb2..ff92a40566 100644 --- a/.circleci/scripts/config-template.yml +++ b/.circleci/scripts/config-template.yml @@ -341,6 +341,28 @@ jobs: # Each project will have individual jobs for each specific task it has to msbuild << parameters.slnname >>/<< parameters.slnname >>.sln /r /p:Configuration='<< parameters.build-config >>' /p:IsDesktopBuild=false /p:Version=$SEMVER /p:FileVersion=$VERSION environment: WORKFLOW_NUM: << pipeline.number >> + - unless: + condition: << parameters.build-with-mono >> + steps: + - run: + name: Publish x64 and arm64 + command: | + TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "2.0.999"; fi;) + SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//') + VER=$(echo "$SEMVER" | sed -e 's/-.*//') + VERSION=$(echo $VER.$WORKFLOW_NUM) + $HOME/.dotnet/dotnet publish << parameters.slnname >>/<< parameters.projname >>/<< parameters.projname >>.csproj -c Release -r osx-arm64 --self-contained /p:IsDesktopBuild=false /p:Version=$SEMVER /p:FileVersion=$VERSION + $HOME/.dotnet/dotnet publish << parameters.slnname >>/<< parameters.projname >>/<< parameters.projname >>.csproj -c Release -r osx-x64 --self-contained /p:IsDesktopBuild=false /p:Version=$SEMVER /p:FileVersion=$VERSION + environment: + WORKFLOW_NUM: << pipeline.number >> + # Create installer + - run: + name: Exit if External PR + command: if [ "$CIRCLE_PR_REPONAME" ]; then circleci-agent step halt; fi + # Zip files for installer + - when: + condition: << parameters.build-with-mono >> + steps: # Compress build files - run: name: Zip Objects Kit files @@ -362,34 +384,25 @@ jobs: # Each project will have individual jobs for each specific task it has to condition: << parameters.build-with-mono >> steps: - run: - name: Publish x64 and arm64 + name: Create app bundles command: | - TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "2.0.999"; fi;) - SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//') - VER=$(echo "$SEMVER" | sed -e 's/-.*//') - VERSION=$(echo $VER.$WORKFLOW_NUM) - $HOME/.dotnet/dotnet publish << parameters.slnname >>/<< parameters.projname >>/<< parameters.projname >>.csproj -c Release -r osx-arm64 --self-contained /p:IsDesktopBuild=false /p:Version=$SEMVER /p:FileVersion=$VERSION - $HOME/.dotnet/dotnet publish << parameters.slnname >>/<< parameters.projname >>/<< parameters.projname >>.csproj -c Release -r osx-x64 --self-contained /p:IsDesktopBuild=false /p:Version=$SEMVER /p:FileVersion=$VERSION - environment: - WORKFLOW_NUM: << pipeline.number >> + sh ./speckle-sharp-ci-tools/Mac/AppBundle/bundle.sh ./<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/publish/ ./<< parameters.slnname >>/<< parameters.slnname >>/Info.plist ./<< parameters.slnname >>/<< parameters.slnname >>/Assets/icon-mac.icns ./<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/<< parameters.slnname >> + sh ./speckle-sharp-ci-tools/Mac/AppBundle/bundle.sh ./<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-x64/publish/ ./<< parameters.slnname >>/<< parameters.slnname >>/Info.plist ./<< parameters.slnname >>/<< parameters.slnname >>/Assets/icon-mac.icns ./<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-x64/<< parameters.slnname >> - run: name: Zip Connector files command: | - cd "<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/publish" - zip -r << parameters.slug >>-mac-arm64.zip "./" - cd "../../osx-x64/publish" - zip -r << parameters.slug >>-mac-x64.zip "./" + cd "<< parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/" + zip -r << parameters.slug >>-mac-arm64.zip "./<< parameters.slnname >>.app" + cd "../osx-x64/" + zip -r << parameters.slug >>-mac-x64.zip "./<< parameters.slnname >>.app" # Copy installer files - run: name: Copy files to installer command: | mkdir -p speckle-sharp-ci-tools/Mac/<< parameters.installername >>/.installationFiles/ - cp << parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/publish/<< parameters.slug >>-mac-arm64.zip speckle-sharp-ci-tools/Mac/<>/.installationFiles - cp << parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-x64/publish/<< parameters.slug >>-mac-x64.zip speckle-sharp-ci-tools/Mac/<>/.installationFiles - # Create installer - - run: - name: Exit if External PR - command: if [ "$CIRCLE_PR_REPONAME" ]; then circleci-agent step halt; fi + cp << parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-arm64/<< parameters.slug >>-mac-arm64.zip speckle-sharp-ci-tools/Mac/<>/.installationFiles + cp << parameters.slnname >>/<< parameters.slnname >>/bin/Release/net6.0/osx-x64/<< parameters.slug >>-mac-x64.zip speckle-sharp-ci-tools/Mac/<>/.installationFiles + - run: name: Build Mac installer command: ~/.dotnet/dotnet publish speckle-sharp-ci-tools/Mac/<>/<>.sln -r osx-x64 -c Release diff --git a/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp b/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp index 67e1d73399..1fd3ac1daa 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp +++ b/ConnectorArchicad/AddOn/Sources/AddOn/AddOnMain.cpp @@ -92,46 +92,41 @@ class AvaloniaProcessManager { private: GS::UniString GetPlatformSpecificExecutablePath () { -#if defined (macintosh) - static const char* FileName = "ConnectorArchicad"; -#else - static const char* FileName = "ConnectorArchicad.exe"; -#endif - static const char* FolderNameCommon = "Common"; - static const char* FolderName = "ConnectorArchicad"; - IO::Location ownFileLoc; auto err = ACAPI_GetOwnLocation (&ownFileLoc); if (err != NoError) { return ""; } +#if defined (macintosh) + static const char* ProductionConnector = "../../../Common/ConnectorArchicad/ConnectorArchicad.app/Contents/MacOS/ConnectorArchicad"; +#else + static const char* ProductionConnector = "../../../Common/ConnectorArchicad/ConnectorArchicad.exe"; +#endif + IO::Location location (ownFileLoc); - location.DeleteLastLocalName (); - location.DeleteLastLocalName (); - location.DeleteLastLocalName (); - location.AppendToLocal (IO::Name (FolderNameCommon)); - location.AppendToLocal (IO::Name (FolderName)); - location.AppendToLocal (IO::Name (FileName)); + location.AppendToLocal (IO::RelativeLocation (ProductionConnector)); bool exist (false); err = IO::fileSystem.Contains (location, &exist); if (err != NoError || !exist) { location = ownFileLoc; - location.DeleteLastLocalName (); - location.DeleteLastLocalName (); - location.DeleteLastLocalName (); - location.DeleteLastLocalName (); - location.AppendToLocal (IO::Name (FolderName)); - location.AppendToLocal (IO::Name ("bin")); +#if defined (macintosh) #ifdef DEBUG - location.AppendToLocal (IO::Name ("Debug")); + static const char* DevelopmentConnector = "../../../../ConnectorArchicad/bin/Debug/net6.0/ConnectorArchicad"; #else - location.AppendToLocal (IO::Name ("Release")); + static const char* DevelopmentConnector = "../../../../ConnectorArchicad/bin/Release/net6.0/ConnectorArchicad"; #endif - location.AppendToLocal (IO::Name ("net6.0")); - location.AppendToLocal (IO::Name (FileName)); +#else +#ifdef DEBUG + static const char* DevelopmentConnector = "../../../../ConnectorArchicad/bin/Debug/net6.0/ConnectorArchicad.exe"; +#else + static const char* DevelopmentConnector = "../../../../ConnectorArchicad/bin/Release/net6.0/ConnectorArchicad.exe"; +#endif +#endif + + location.AppendToLocal (IO::RelativeLocation (DevelopmentConnector)); } GS::UniString executableStr; diff --git a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/AddOnFix.grc b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/AddOnFix.grc index 02d663f4d1..6ad0e355df 100644 --- a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/AddOnFix.grc +++ b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/AddOnFix.grc @@ -6,9 +6,15 @@ AC_MDID_LOC /* Set AC_MDID_LOC value as your local id. */ } +#ifdef macintosh 'GICN' 10001 "AddOnIcon" { - "AddOnIcon" + "AddOnIconMac" } +#else +'GICN' 10001 "AddOnIcon" { + "AddOnIconWin" +} +#endif 'STR#' ID_FIX_ELEMENT_TYPE_STRINGS "Element Type Strings" { /* [ 1] */ "Wall" diff --git a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconMac_18x18.svg b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconMac_18x18.svg new file mode 100644 index 0000000000..0f1cfa4bb2 --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconMac_18x18.svg @@ -0,0 +1,18 @@ + + AddOnIcon_18x18-svg + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconWin_18x18.svg b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconWin_18x18.svg new file mode 100644 index 0000000000..fbe59e2a11 --- /dev/null +++ b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIconWin_18x18.svg @@ -0,0 +1,17 @@ + + AddOnIconWin_18x18-svg + + + + + + + + + + + \ No newline at end of file diff --git a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIcon_18x18.svg b/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIcon_18x18.svg deleted file mode 100644 index 4031449236..0000000000 --- a/ConnectorArchicad/AddOn/Sources/AddOnResources/RFIX/Images/AddOnIcon_18x18.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/ConnectorArchicad/ConnectorArchicad/Assets/icon-mac.icns b/ConnectorArchicad/ConnectorArchicad/Assets/icon-mac.icns new file mode 100644 index 0000000000000000000000000000000000000000..6ef6c0c3337a38f7c3a4ec06f4b9d4b40c311f07 GIT binary patch literal 37877 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 ConnectorArchicad Assets\icon.ico + true diff --git a/ConnectorArchicad/ConnectorArchicad/Info.plist b/ConnectorArchicad/ConnectorArchicad/Info.plist new file mode 100644 index 0000000000..e42154e574 --- /dev/null +++ b/ConnectorArchicad/ConnectorArchicad/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleName + acconnector + CFBundleDisplayName + Archicad Connector + CFBundleIdentifier + systems.speckle.acconnector + CFBundleVersion + 2.0.0 + CFBundlePackageType + APPL + CFBundleSignature + spkl + CFBundleExecutable + ConnectorArchicad + CFBundleIconFile + icon-mac.icns + CFBundleShortVersionString + 2.0.0 + CFBundleURLTypes + + + CFBundleURLName + Speckle + CFBundleURLSchemes + + speckle + + + + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + + \ No newline at end of file From f5868d3a8de11762ad2cb4421e604c6a673117ba Mon Sep 17 00:00:00 2001 From: KatKatKateryna <89912278+KatKatKateryna@users.noreply.github.com> Date: Fri, 14 Jun 2024 22:11:41 +0800 Subject: [PATCH 09/12] fetching branchName for FE2 URLs (#3487) * fetching branchName for FE2 URLs * Revert "fetching branchName for FE2 URLs" This reverts commit 331927b5e9fc9c7adf944490d6a23d40bcca1a6c. * move hack to async ResetApiClient --- .../Operations.VariableInputReceiveComponent.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs index ce1a78b883..0b2e02996c 100644 --- a/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs +++ b/ConnectorGrasshopper/ConnectorGrasshopperShared/Ops/Operations.VariableInputReceiveComponent.cs @@ -547,6 +547,23 @@ public async Task ResetApiClient(StreamWrapper wrapper) try { account = wrapper?.GetAccount().Result; + + // hack for FE2 + // should we also fetch this for FE1-accounts that are trying to access FE2 stream? Probably not + if (account.serverInfo.frontend2 is true) + { + Client client = new(account); + var streamObj = client.StreamGet(StreamWrapper.StreamId, 100).Result; + foreach (Branch branch in streamObj.branches.items) + { + if (branch.id == StreamWrapper.BranchName) + { + StreamWrapper.BranchName = branch.name; + break; + } + } + client.Dispose(); + } } catch (SpeckleException e) { From d151cf579aab9ebdd2943dbd8d6dec120e8f4af4 Mon Sep 17 00:00:00 2001 From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:56:33 +0100 Subject: [PATCH 10/12] Added support for IReadOnlyList deserialization (#3520) * Added Unit tests for current state * Fixed Tests * Fixed comment * Fixed other issues * removed a couple types that weren't needed --- .../SerializationUtilities/ValueConverter.cs | 25 +++++- .../SerializerBreakingChanges.cs | 1 - .../SerializerNonBreakingChanges.cs | 46 +++++++++++ .../ModelPropertySupportedTypes.cs | 81 +++++++++++++++++++ 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 Objects/Tests/Objects.Tests.Unit/ModelPropertySupportedTypes.cs diff --git a/Core/Core/Serialisation/SerializationUtilities/ValueConverter.cs b/Core/Core/Serialisation/SerializationUtilities/ValueConverter.cs index f648f3274f..70246a1363 100644 --- a/Core/Core/Serialisation/SerializationUtilities/ValueConverter.cs +++ b/Core/Core/Serialisation/SerializationUtilities/ValueConverter.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.DoubleNumerics; using System.Drawing; using System.Globalization; @@ -157,16 +158,17 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV #endregion } - // Handle List - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + // Handle List<>, IList<>, and IReadOnlyList<> + if (type.IsGenericType && IsGenericList(type)) { if (value is not List valueList) { return false; } + var targetType = typeof(List<>).MakeGenericType(type.GenericTypeArguments); Type listElementType = type.GenericTypeArguments[0]; - IList ret = Activator.CreateInstance(type, valueList.Count) as IList; + IList ret = Activator.CreateInstance(targetType, valueList.Count) as IList; foreach (object inputListElement in valueList) { if (!ConvertValue(listElementType, inputListElement, out object? convertedListElement)) @@ -311,4 +313,21 @@ public static bool ConvertValue(Type type, object? value, out object? convertedV return false; } + + /// + /// Tests that the given is assignable from a generic type def + /// + /// + /// + [Pure] + private static bool IsGenericList(Type type) + { + if (!type.IsGenericType) + { + return false; + } + + Type typeDef = type.GetGenericTypeDefinition(); + return typeDef == typeof(List<>) || typeDef == typeof(IList<>) || typeDef == typeof(IReadOnlyList<>); + } } diff --git a/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerBreakingChanges.cs b/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerBreakingChanges.cs index 163d7abd21..0fc9549fd2 100644 --- a/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerBreakingChanges.cs +++ b/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerBreakingChanges.cs @@ -1,5 +1,4 @@ using NUnit.Framework; -using Speckle.Core.Logging; using Speckle.Core.Serialisation; namespace Speckle.Core.Tests.Unit.Serialisation; diff --git a/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs b/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs index ef2c5e501e..30dbea5d06 100644 --- a/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs +++ b/Core/Tests/Speckle.Core.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs @@ -87,6 +87,42 @@ public void ListToArray(double[] testCase) Assert.That(res.value, Is.EquivalentTo(testCase)); } + [Test, TestCaseSource(nameof(s_arrayTestCases))] + public void ListToIList(double[] testCase) + { + var from = new ListDoubleValueMock { value = testCase.ToList() }; + + var res = from.SerializeAsTAndDeserialize(); + Assert.That(res.value, Is.EquivalentTo(testCase)); + } + + [Test, TestCaseSource(nameof(s_arrayTestCases))] + public void ListToIReadOnlyList(double[] testCase) + { + var from = new ListDoubleValueMock { value = testCase.ToList() }; + + var res = from.SerializeAsTAndDeserialize(); + Assert.That(res.value, Is.EquivalentTo(testCase)); + } + + [Test, TestCaseSource(nameof(s_arrayTestCases))] + public void IListToList(double[] testCase) + { + var from = new IListDoubleValueMock { value = testCase.ToList() }; + + var res = from.SerializeAsTAndDeserialize(); + Assert.That(res.value, Is.EquivalentTo(testCase)); + } + + [Test, TestCaseSource(nameof(s_arrayTestCases))] + public void IReadOnlyListToList(double[] testCase) + { + var from = new IReadOnlyListDoubleValueMock { value = testCase.ToList() }; + + var res = from.SerializeAsTAndDeserialize(); + Assert.That(res.value, Is.EquivalentTo(testCase)); + } + [Test, TestCaseSource(nameof(MyEnums))] public void EnumToInt(MyEnum testCase) { @@ -171,6 +207,16 @@ public class ListDoubleValueMock : SerializerMock public List value { get; set; } } +public class IListDoubleValueMock : SerializerMock +{ + public IList value { get; set; } +} + +public class IReadOnlyListDoubleValueMock : SerializerMock +{ + public IReadOnlyList value { get; set; } +} + public class ArrayDoubleValueMock : SerializerMock { public double[] value { get; set; } diff --git a/Objects/Tests/Objects.Tests.Unit/ModelPropertySupportedTypes.cs b/Objects/Tests/Objects.Tests.Unit/ModelPropertySupportedTypes.cs new file mode 100644 index 0000000000..342e0cad23 --- /dev/null +++ b/Objects/Tests/Objects.Tests.Unit/ModelPropertySupportedTypes.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.DoubleNumerics; +using System.Drawing; +using System.Linq; +using NUnit.Framework; +using Speckle.Core.Models; +using Speckle.Core.Serialisation; +using Speckle.Newtonsoft.Json; + +namespace Objects.Tests.Unit; + +/// +/// Tests that all Base object models in the kit have properties that are an allowed type +/// This test is not exhaustive, there are plenty of generic arg combinations that will pass this test, +/// but still not work / are not defined behaviour. This test will just catch many types that definitely won't work +/// +public class ModelPropertySupportedTypes +{ + /// + /// Set of types that we support in Base objects + /// If it's not in the list, or is commented out, it's not supported by our serializer! + /// + /// + /// If you're tempted to add to this list, please ensure both our serializer and deserializer support properties of this type + /// Check the + /// Check the + /// (or is an interface where all concrete types are supported) + /// You should also consider adding a test in SerializerNonBreakingChanges + /// + private readonly HashSet _allowedTypes = + new() + { + typeof(Boolean), + typeof(Byte), + typeof(UInt32), + typeof(UInt64), + typeof(Int16), + typeof(Int32), + typeof(Int64), + //typeof(Half), + typeof(Single), + typeof(Double), + typeof(Char), + typeof(string), + typeof(DateTime), + typeof(Guid), + typeof(Color), + typeof(List<>), + typeof(Nullable<>), + typeof(IList<>), + typeof(IReadOnlyList<>), + typeof(Dictionary<,>), + //typeof(IDictionary<,>), + //typeof(IReadOnlyDictionary<,>), + typeof(ICurve), + typeof(Object), + typeof(Matrix4x4), + }; + + [Test] + [TestCaseSource(typeof(GenericTests), nameof(GenericTests.AvailableTypesInKit))] + public void TestObjects(Type t) + { + var members = DynamicBase.GetInstanceMembers(t).Where(p => !p.IsDefined(typeof(JsonIgnoreAttribute), true)); + + foreach (var prop in members) + { + if (prop.PropertyType.IsAssignableTo(typeof(Base))) + continue; + if (prop.PropertyType.IsEnum) + continue; + if (prop.PropertyType.IsSZArray) + continue; + + Type propType = prop.PropertyType; + Type typeDef = propType.IsGenericType ? propType.GetGenericTypeDefinition() : propType; + Assert.That(_allowedTypes, Does.Contain(typeDef), $"{typeDef} was not in allowedTypes"); + } + } +} From c9e27dea254646b70d7f173111192b7818b4746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuzhan=20Koral?= <45078678+oguzhankoral@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:52:48 +0300 Subject: [PATCH 11/12] CNX-9775 sending revit elements via dynamo (#3495) * POC: nullable cache * Remove commented out lines * fix: Formatting --------- Co-authored-by: Alan Rynne --- .../AllRevitCategories.cs | 124 +++++++++++------- .../ConverterRevitShared/ConversionUtils.cs | 76 ++++++----- .../ConverterRevitShared/ConverterRevit.cs | 3 +- .../PartialClasses/ConvertWall.cs | 36 +++-- .../RevitElementTypeUtils.cs | 6 + 5 files changed, 154 insertions(+), 91 deletions(-) diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs index cb51ab0a0f..14edc8539f 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/AllRevitCategories.cs @@ -36,27 +36,45 @@ public IRevitCategoryInfo GetRevitCategoryInfo(Base @base) return elementType; } - var matchingType = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetAllObjects() - .Where(catInfo => catInfo.ElementTypeType == typeof(T) && catInfo.BuiltInCategories.Count == 0) - .FirstOrDefault(); + IRevitCategoryInfo matchingType; + + if (revitDocumentAggregateCache is null) + { + matchingType = elementType; + } + else + { + matchingType = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetAllObjects() + .Where(catInfo => catInfo.ElementTypeType == typeof(T) && catInfo.BuiltInCategories.Count == 0) + .FirstOrDefault(); + } if (matchingType != null) { return matchingType; } - var categoryInfo = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetOrAdd( - typeof(T).Name, - () => - { - return new RevitCategoryInfo(typeof(T).Name, null, typeof(T), new List()); - }, - out _ - ); + IRevitCategoryInfo categoryInfo; + + if (revitDocumentAggregateCache is null) + { + categoryInfo = new RevitCategoryInfo(typeof(T).Name, null, typeof(T), new List()); + } + else + { + categoryInfo = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetOrAdd( + typeof(T).Name, + () => + { + return new RevitCategoryInfo(typeof(T).Name, null, typeof(T), new List()); + }, + out _ + ); + } return categoryInfo; } @@ -128,30 +146,26 @@ public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName) } categoryName = CategoryNameFormatted(categoryName); - var revitCategoryInfoCache = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory(); - categoryInfo = revitCategoryInfoCache.TryGet(categoryName); - if (categoryInfo != null) + IRevitObjectCache revitCategoryInfoCache; + if (revitDocumentAggregateCache is not null) { - return categoryInfo; - } + revitCategoryInfoCache = revitDocumentAggregateCache.GetOrInitializeWithDefaultFactory(); - foreach (var info in revitCategoryInfoCache.GetAllObjects()) - { - if (categoryName.IndexOf(info.CategoryName, StringComparison.OrdinalIgnoreCase) >= 0) + categoryInfo = revitCategoryInfoCache.TryGet(categoryName); + if (categoryInfo != null) { - return info; + return categoryInfo; } - foreach (var alias in info.CategoryAliases) + else { - if (categoryName.IndexOf(alias, StringComparison.OrdinalIgnoreCase) >= 0) - { - return info; - } + return SHC.Undefined; } } - - return SHC.Undefined; + else + { + return SHC.Undefined; + } } #endregion @@ -173,29 +187,43 @@ public IRevitCategoryInfo GetRevitCategoryInfo(string categoryName) // pre 2.16 we're passing the "category" string else { - var revitCat = revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .TryGet(unformattedCatName); - - if (revitCat == null) + if (revitDocumentAggregateCache is null) { return null; } + else + { + var revitCat = revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .TryGet(unformattedCatName); - bic = Categories.GetBuiltInCategory(revitCat); - formattedName = CategoryNameFormatted(unformattedCatName); + if (revitCat == null) + { + return null; + } + + bic = Categories.GetBuiltInCategory(revitCat); + formattedName = CategoryNameFormatted(unformattedCatName); + } } - return revitDocumentAggregateCache - .GetOrInitializeWithDefaultFactory() - .GetOrAdd( - formattedName, - () => - { - return new RevitCategoryInfo(formattedName, null, null, new List { bic }); - }, - out _ - ); + if (revitDocumentAggregateCache is null) + { + return new RevitCategoryInfo(formattedName, null, null, new List { bic }); + } + else + { + return revitDocumentAggregateCache + .GetOrInitializeWithDefaultFactory() + .GetOrAdd( + formattedName, + () => + { + return new RevitCategoryInfo(formattedName, null, null, new List { bic }); + }, + out _ + ); + } } private static string CategoryNameFormatted(string name) diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs index 5aae514f7a..307cca0e29 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConversionUtils.cs @@ -390,39 +390,46 @@ private Parameter ParameterToSpeckle( #else ForgeTypeId unitTypeId = null; #endif + ParameterToSpeckleData paramData; + + // Local function to create ParameterToSpeckleData + ParameterToSpeckleData CreateParamData() + { + var definition = rp.Definition; + var newParamData = new ParameterToSpeckleData() + { + Definition = definition, + InternalName = paramInternalName, + IsReadOnly = rp.IsReadOnly, + IsShared = rp.IsShared, + IsTypeParameter = isTypeParameter, + Name = definition.Name, + UnitType = definition.GetUnityTypeString(), + }; + if (rp.StorageType == StorageType.Double) + { + unitTypeId = rp.GetUnitTypeId(); + newParamData.UnitsSymbol = GetSymbolUnit(rp, definition, unitTypeId); + newParamData.ApplicationUnits = + unitsOverride != null ? UnitsToNative(unitsOverride).ToUniqueString() : unitTypeId.ToUniqueString(); + } + return newParamData; + } // The parameter definitions are cached using the ParameterToSpeckleData struct // This is done because in the case of type and instance parameter there is lots of redundant data that needs to be extracted from the Revit DB // Caching noticeably speeds up the send process // TODO : could add some generic getOrAdd overloads to avoid creating closures - var paramData = revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType(out _) - .GetOrAdd( - paramInternalName, - () => - { - var definition = rp.Definition; - var newParamData = new ParameterToSpeckleData() - { - Definition = definition, - InternalName = paramInternalName, - IsReadOnly = rp.IsReadOnly, - IsShared = rp.IsShared, - IsTypeParameter = isTypeParameter, - Name = definition.Name, - UnitType = definition.GetUnityTypeString(), - }; - if (rp.StorageType == StorageType.Double) - { - unitTypeId = rp.GetUnitTypeId(); - newParamData.UnitsSymbol = GetSymbolUnit(rp, definition, unitTypeId); - newParamData.ApplicationUnits = - unitsOverride != null ? UnitsToNative(unitsOverride).ToUniqueString() : unitTypeId.ToUniqueString(); - } - return newParamData; - }, - out _ - ); + if (revitDocumentAggregateCache is null) + { + paramData = CreateParamData(); + } + else + { + paramData = revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType(out _) + .GetOrAdd(paramInternalName, CreateParamData, out _); + } return paramData.GetParameterObjectWithValue(rp.GetValue(paramData.Definition, unitTypeId)); } @@ -450,9 +457,16 @@ ForgeTypeId unitTypeId return null; } - return revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType(out _) - .GetOrAdd(unitTypeId.ToUniqueString(), () => unitTypeId.GetSymbol(), out _); + if (revitDocumentAggregateCache is null) + { + return unitTypeId.GetSymbol(); + } + else + { + return revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType(out _) + .GetOrAdd(unitTypeId.ToUniqueString(), () => unitTypeId.GetSymbol(), out _); + } } /// diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs index 337f32a2f4..4c9a38d3f4 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/ConverterRevit.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Linq; @@ -109,7 +110,7 @@ public ConverterRevit() Report.Log($"Using converter: {Name} v{ver}"); } - private IRevitDocumentAggregateCache revitDocumentAggregateCache; + private IRevitDocumentAggregateCache? revitDocumentAggregateCache; private IConvertedObjectsCache receivedObjectsCache; private TransactionManager transactionManager; diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs index ef493e7fa9..73033b0442 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/PartialClasses/ConvertWall.cs @@ -264,19 +264,33 @@ private IEnumerable GetSubsetOfElementsInView(BuiltInCategory categor return children; } - var allSubelementsInView = revitDocumentAggregateCache - .GetOrInitializeEmptyCacheOfType>(out _) - .GetOrAdd( - category.ToString(), - () => - { - using var filter = new ElementCategoryFilter(category); - using var collector = new FilteredElementCollector(Doc, ViewSpecificOptions.View.Id); + var allSubelementsInView = new HashSet(); + + if (revitDocumentAggregateCache is null) + { + var filter = new ElementCategoryFilter(category); + var collector = new FilteredElementCollector(Doc, ViewSpecificOptions.View.Id); - return new HashSet(collector.WhereElementIsNotElementType().WherePasses(filter).ToElementIds()); - }, - out _ + allSubelementsInView = new HashSet( + collector.WhereElementIsNotElementType().WherePasses(filter).ToElementIds() ); + } + else + { + allSubelementsInView = revitDocumentAggregateCache + .GetOrInitializeEmptyCacheOfType>(out _) + .GetOrAdd( + category.ToString(), + () => + { + using var filter = new ElementCategoryFilter(category); + using var collector = new FilteredElementCollector(Doc, ViewSpecificOptions.View.Id); + + return new HashSet(collector.WhereElementIsNotElementType().WherePasses(filter).ToElementIds()); + }, + out _ + ); + } return children.Where(allSubelementsInView.Contains); } diff --git a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitElementTypeUtils.cs b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitElementTypeUtils.cs index f6ce277023..43678de1c8 100644 --- a/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitElementTypeUtils.cs +++ b/Objects/Converters/ConverterRevit/ConverterRevitShared/RevitElementTypeUtils.cs @@ -140,6 +140,12 @@ public void SetElementFamily(Base @base, string family) appObj.Update(logItem: $"Could not find valid incoming type for element of type \"{element.speckle_type}\""); } var typeInfo = AllCategories.GetRevitCategoryInfo(element); + + if (revitDocumentAggregateCache is null) + { + return default; + } + var types = revitDocumentAggregateCache .GetOrInitializeWithDefaultFactory>() .GetOrAddGroupOfTypes(typeInfo); From c3249949efa32431510ce9922d1da2937acf6f15 Mon Sep 17 00:00:00 2001 From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> Date: Tue, 2 Jul 2024 18:16:05 +0100 Subject: [PATCH 12/12] Fixes integration tests (#3551) --- .../Speckle.Core.Tests.Integration/ServerTransportTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/Tests/Speckle.Core.Tests.Integration/ServerTransportTests.cs b/Core/Tests/Speckle.Core.Tests.Integration/ServerTransportTests.cs index 0baa04ac9b..4d111f0e2e 100644 --- a/Core/Tests/Speckle.Core.Tests.Integration/ServerTransportTests.cs +++ b/Core/Tests/Speckle.Core.Tests.Integration/ServerTransportTests.cs @@ -46,6 +46,7 @@ public void TearDown() private void CleanData() { + _transport?.Dispose(); if (Directory.Exists(_basePath)) { Directory.Delete(_basePath, true); @@ -73,7 +74,7 @@ public async Task SendAndReceiveObjectWithBlobs() // NOTE: used to debug diffing // await Operations.Send(myObject, new List { transport }); - var receivedObject = await Operations.Receive(sentObjectId, _transport); + var receivedObject = await Operations.Receive(sentObjectId, _transport, new MemoryTransport()); var allFiles = Directory .GetFiles(_transport.BlobStorageFolder) @@ -104,7 +105,7 @@ public async Task SendWithBlobsWithoutSQLiteSendCache() var memTransport = new MemoryTransport(); var sentObjectId = await Operations.Send(myObject, new List { _transport, memTransport }); - var receivedObject = await Operations.Receive(sentObjectId, _transport); + var receivedObject = await Operations.Receive(sentObjectId, _transport, new MemoryTransport()); var allFiles = Directory .GetFiles(_transport.BlobStorageFolder)