From 3ac7e601c20d27512059445ca1461fdbbdae3923 Mon Sep 17 00:00:00 2001 From: "AMCBRIDGE\\ksloboda" Date: Tue, 14 Nov 2023 12:34:51 +0200 Subject: [PATCH 1/2] add SpaceMetrics project --- WorkplaceStrategy/SpaceMetrics/.gitignore | 9 + WorkplaceStrategy/SpaceMetrics/README.md | 19 ++ .../SpaceMetrics/SpaceMetrics.sln | 34 ++++ .../dependencies/SpaceBoundary.cs | 8 + .../dependencies/SpaceBoundary.g.cs | 107 ++++++++++ .../dependencies/SpaceMetric.g.cs | 69 +++++++ .../SpaceMetrics.Dependencies.csproj | 14 ++ .../dependencies/SpaceMetricsInputs.g.cs | 183 ++++++++++++++++++ .../dependencies/SpaceMetricsOutputs.g.cs | 29 +++ .../dependencies/SpaceMetricsOverride.g.cs | 104 ++++++++++ WorkplaceStrategy/SpaceMetrics/global.json | 7 + WorkplaceStrategy/SpaceMetrics/hypar.json | 101 ++++++++++ .../SpaceMetrics/src/Function.g.cs | 73 +++++++ .../SpaceMetrics/src/SpaceMetrics.cs | 140 ++++++++++++++ .../SpaceMetrics/src/SpaceMetrics.csproj | 13 ++ .../SpaceMetrics/test/FunctionTest.g.cs | 24 +++ .../SpaceMetrics/test/GlobalUsings.cs | 1 + .../test/SpaceMetrics.Tests.csproj | 29 +++ 18 files changed, 964 insertions(+) create mode 100644 WorkplaceStrategy/SpaceMetrics/.gitignore create mode 100644 WorkplaceStrategy/SpaceMetrics/README.md create mode 100644 WorkplaceStrategy/SpaceMetrics/SpaceMetrics.sln create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetric.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetrics.Dependencies.csproj create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsInputs.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOutputs.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOverride.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/global.json create mode 100644 WorkplaceStrategy/SpaceMetrics/hypar.json create mode 100644 WorkplaceStrategy/SpaceMetrics/src/Function.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.csproj create mode 100644 WorkplaceStrategy/SpaceMetrics/test/FunctionTest.g.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/test/GlobalUsings.cs create mode 100644 WorkplaceStrategy/SpaceMetrics/test/SpaceMetrics.Tests.csproj diff --git a/WorkplaceStrategy/SpaceMetrics/.gitignore b/WorkplaceStrategy/SpaceMetrics/.gitignore new file mode 100644 index 00000000..f1d4f671 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/.gitignore @@ -0,0 +1,9 @@ + +bin/ +obj/ +*.glb +output.json +input.json +.vs/ +server/ +test/Generated/ \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/README.md b/WorkplaceStrategy/SpaceMetrics/README.md new file mode 100644 index 00000000..9857fb16 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/README.md @@ -0,0 +1,19 @@ + + +# Space Metrics + +Override various workplace metrics from a layout. + +|Input Name|Type|Description| +|---|---|---| + + +
+ +|Output Name|Type|Description| +|---|---|---| + + +
+ +## Additional Information \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/SpaceMetrics.sln b/WorkplaceStrategy/SpaceMetrics/SpaceMetrics.sln new file mode 100644 index 00000000..105301a0 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/SpaceMetrics.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceMetrics", "src\SpaceMetrics.csproj", "{6FF5C3A5-79FC-426A-9F58-25DF57530B78}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceMetrics.Dependencies", "dependencies\SpaceMetrics.Dependencies.csproj", "{CDB3F17C-D096-4BEB-94D8-BFDB3E1888F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceMetrics.Tests", "test\SpaceMetrics.Tests.csproj", "{360608A1-942E-4751-B878-E5239BF0595D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6FF5C3A5-79FC-426A-9F58-25DF57530B78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FF5C3A5-79FC-426A-9F58-25DF57530B78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FF5C3A5-79FC-426A-9F58-25DF57530B78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FF5C3A5-79FC-426A-9F58-25DF57530B78}.Release|Any CPU.Build.0 = Release|Any CPU + {CDB3F17C-D096-4BEB-94D8-BFDB3E1888F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDB3F17C-D096-4BEB-94D8-BFDB3E1888F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDB3F17C-D096-4BEB-94D8-BFDB3E1888F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDB3F17C-D096-4BEB-94D8-BFDB3E1888F8}.Release|Any CPU.Build.0 = Release|Any CPU + {360608A1-942E-4751-B878-E5239BF0595D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {360608A1-942E-4751-B878-E5239BF0595D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {360608A1-942E-4751-B878-E5239BF0595D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {360608A1-942E-4751-B878-E5239BF0595D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.cs new file mode 100644 index 00000000..ed41d5d2 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.cs @@ -0,0 +1,8 @@ +using Elements.Geometry; +namespace Elements +{ + public partial class SpaceBoundary + { + public Vector3? ParentCentroid { get; set; } + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.g.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.g.cs new file mode 100644 index 00000000..8ce5974d --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceBoundary.g.cs @@ -0,0 +1,107 @@ +//---------------------- +// +// Generated using the NJsonSchema v10.1.21.0 (Newtonsoft.Json v13.0.0.0) (http://NJsonSchema.org) +// +//---------------------- +using Elements; +using Elements.GeoJSON; +using Elements.Geometry; +using Elements.Geometry.Solids; +using Elements.Spatial; +using Elements.Validators; +using Elements.Serialization.JSON; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Line = Elements.Geometry.Line; +using Polygon = Elements.Geometry.Polygon; + +namespace Elements +{ + #pragma warning disable // Disable all warnings + + /// A profile with a program assigned to it, and optional internal cell geometry. + [JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + public partial class SpaceBoundary : GeometricElement + { + [JsonConstructor] + public SpaceBoundary(Profile @boundary, IList @cells, double @area, double? @length, double? @depth, double @height, string @programGroup, string @programType, System.Guid? @programRequirement, System.Guid? @level, System.Guid? @levelLayout, string @hyparSpaceType, string @defaultWallType, Transform @transform = null, Material @material = null, Representation @representation = null, bool @isElementDefinition = false, System.Guid @id = default, string @name = null) + : base(transform, material, representation, isElementDefinition, id, name) + { + this.Boundary = @boundary; + this.Cells = @cells; + this.Area = @area; + this.Length = @length; + this.Depth = @depth; + this.Height = @height; + this.ProgramGroup = @programGroup; + this.ProgramType = @programType; + this.ProgramRequirement = @programRequirement; + this.Level = @level; + this.LevelLayout = @levelLayout; + this.HyparSpaceType = @hyparSpaceType; + this.DefaultWallType = @defaultWallType; + } + + + // Empty constructor + public SpaceBoundary() + : base() + { + } + + /// The boundary of the space + [JsonProperty("Boundary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Profile Boundary { get; set; } + + /// Component cells making up the boundary + [JsonProperty("Cells", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public IList Cells { get; set; } + + /// The area of the boundary + [JsonProperty("Area", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Area { get; set; } + + /// The rough length of this space boundary, parallel to the accessible edge + [JsonProperty("Length", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Length { get; set; } + + /// The rough depth of the space boundary, perpendicular to the accessible edge + [JsonProperty("Depth", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Depth { get; set; } + + /// The height of this space boundary + [JsonProperty("Height", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Height { get; set; } + + /// A program grouping, like a department. + [JsonProperty("Program Group", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ProgramGroup { get; set; } + + /// The name of the program type assigned to this space (like "Open Office" or "Meeting Room") + [JsonProperty("Program Type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ProgramType { get; set; } + + [JsonProperty("Program Requirement", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid? ProgramRequirement { get; set; } + + [JsonProperty("Level", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid? Level { get; set; } + + /// The layout, if any, which generated this space boundary. + [JsonProperty("Level Layout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid? LevelLayout { get; set; } + + /// The hypar-recognized space type name which will be used to determine which layout function to apply. In older space boundaries, this may not be set — fall back to the Name property for this purpose if not provided. + [JsonProperty("Hypar Space Type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string HyparSpaceType { get; set; } + + /// What wall type should generally be created for this space type? This may get overridden later on for a specific wall. + [JsonProperty("Default Wall Type", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DefaultWallType { get; set; } + + + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetric.g.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetric.g.cs new file mode 100644 index 00000000..5b05e4bc --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetric.g.cs @@ -0,0 +1,69 @@ +//---------------------- +// +// Generated using the NJsonSchema v10.1.21.0 (Newtonsoft.Json v13.0.0.0) (http://NJsonSchema.org) +// +//---------------------- +using Elements; +using Elements.GeoJSON; +using Elements.Geometry; +using Elements.Geometry.Solids; +using Elements.Spatial; +using Elements.Validators; +using Elements.Serialization.JSON; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Line = Elements.Geometry.Line; +using Polygon = Elements.Geometry.Polygon; + +namespace Elements +{ + #pragma warning disable // Disable all warnings + + /// Attach these to spaces to include information useful for metrics and calculations + [JsonConverter(typeof(Elements.Serialization.JSON.JsonInheritanceConverter), "discriminator")] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + public partial class SpaceMetric : Element + { + [JsonConstructor] + public SpaceMetric(System.Guid? @space, double @seats, double @headcount, double @desks, double @collaborationSeats, System.Guid @id = default, string @name = null) + : base(id, name) + { + this.Space = @space; + this.Seats = @seats; + this.Headcount = @headcount; + this.Desks = @desks; + this.CollaborationSeats = @collaborationSeats; + } + + + // Empty constructor + public SpaceMetric() + : base() + { + } + + /// The space we are attaching metrics to + [JsonProperty("Space", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid? Space { get; set; } + + /// Seat count for this space. + [JsonProperty("Seats", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Seats { get; set; } + + /// Headcount for this space. + [JsonProperty("Headcount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Headcount { get; set; } + + /// Desks for this space. + [JsonProperty("Desks", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Desks { get; set; } + + /// Seats for collaboration in this space. + [JsonProperty("Collaboration Seats", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CollaborationSeats { get; set; } + + + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetrics.Dependencies.csproj b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetrics.Dependencies.csproj new file mode 100644 index 00000000..69448574 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetrics.Dependencies.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsInputs.g.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsInputs.g.cs new file mode 100644 index 00000000..f578d6c6 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsInputs.g.cs @@ -0,0 +1,183 @@ +// This code was generated by Hypar. +// Edits to this code will be overwritten the next time you run 'hypar init'. +// DO NOT EDIT THIS FILE. + +using Elements; +using Elements.GeoJSON; +using Elements.Geometry; +using Elements.Geometry.Solids; +using Elements.Validators; +using Elements.Serialization.JSON; +using Hypar.Functions; +using Hypar.Functions.Execution; +using Hypar.Functions.Execution.AWS; +using Hypar.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using Line = Elements.Geometry.Line; +using Polygon = Elements.Geometry.Polygon; + +namespace SpaceMetrics +{ + #pragma warning disable // Disable all warnings + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + + public class SpaceMetricsInputs : ArgsBase + + { + [Newtonsoft.Json.JsonConstructor] + + public SpaceMetricsInputs(Overrides @overrides, Dictionary modelInputKeys, string gltfKey, string elementsKey, string ifcKey): + base(modelInputKeys, gltfKey, elementsKey, ifcKey) + { + var validator = Validator.Instance.GetFirstValidatorForType(); + if(validator != null) + { + validator.PreConstruct(new object[]{ @overrides}); + } + + this.Overrides = @overrides ?? this.Overrides; + + if(validator != null) + { + validator.PostConstruct(this); + } + } + + [Newtonsoft.Json.JsonProperty("overrides", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Overrides Overrides { get; set; } = new Overrides(); + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + + public partial class Overrides + + { + public Overrides() { } + + [Newtonsoft.Json.JsonConstructor] + public Overrides(IList @spaceMetrics) + { + var validator = Validator.Instance.GetFirstValidatorForType(); + if(validator != null) + { + validator.PreConstruct(new object[]{ @spaceMetrics}); + } + + this.SpaceMetrics = @spaceMetrics ?? this.SpaceMetrics; + + if(validator != null) + { + validator.PostConstruct(this); + } + } + + [Newtonsoft.Json.JsonProperty("Space Metrics", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public IList SpaceMetrics { get; set; } = new List(); + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + + public partial class SpaceMetricsOverride + + { + [Newtonsoft.Json.JsonConstructor] + public SpaceMetricsOverride(string @id, SpaceMetricsIdentity @identity, SpaceMetricsValue @value) + { + var validator = Validator.Instance.GetFirstValidatorForType(); + if(validator != null) + { + validator.PreConstruct(new object[]{ @id, @identity, @value}); + } + + this.Id = @id; + this.Identity = @identity; + this.Value = @value; + + if(validator != null) + { + validator.PostConstruct(this); + } + } + + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + [Newtonsoft.Json.JsonProperty("Identity", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public SpaceMetricsIdentity Identity { get; set; } + + [Newtonsoft.Json.JsonProperty("Value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public SpaceMetricsValue Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + + public partial class SpaceMetricsIdentity + + { + [Newtonsoft.Json.JsonConstructor] + public SpaceMetricsIdentity(Vector3 @parentCentroid) + { + var validator = Validator.Instance.GetFirstValidatorForType(); + if(validator != null) + { + validator.PreConstruct(new object[]{ @parentCentroid}); + } + + this.ParentCentroid = @parentCentroid; + + if(validator != null) + { + validator.PostConstruct(this); + } + } + + [Newtonsoft.Json.JsonProperty("ParentCentroid", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Vector3 ParentCentroid { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.21.0 (Newtonsoft.Json v13.0.0.0)")] + + public partial class SpaceMetricsValue + + { + [Newtonsoft.Json.JsonConstructor] + public SpaceMetricsValue(double @seats, double @headcount, double @desks, double @collaborationSeats) + { + var validator = Validator.Instance.GetFirstValidatorForType(); + if(validator != null) + { + validator.PreConstruct(new object[]{ @seats, @headcount, @desks, @collaborationSeats}); + } + + this.Seats = @seats; + this.Headcount = @headcount; + this.Desks = @desks; + this.CollaborationSeats = @collaborationSeats; + + if(validator != null) + { + validator.PostConstruct(this); + } + } + + [Newtonsoft.Json.JsonProperty("Seats", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Seats { get; set; } + + [Newtonsoft.Json.JsonProperty("Headcount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Headcount { get; set; } + + [Newtonsoft.Json.JsonProperty("Desks", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Desks { get; set; } + + [Newtonsoft.Json.JsonProperty("Collaboration Seats", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CollaborationSeats { get; set; } + + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOutputs.g.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOutputs.g.cs new file mode 100644 index 00000000..7ac0c500 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOutputs.g.cs @@ -0,0 +1,29 @@ +// This code was generated by Hypar. +// Edits to this code will be overwritten the next time you run 'hypar init'. +// DO NOT EDIT THIS FILE. + +using Elements; +using Elements.GeoJSON; +using Elements.Geometry; +using Hypar.Functions; +using Hypar.Functions.Execution; +using Hypar.Functions.Execution.AWS; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System.Collections.Generic; + +namespace SpaceMetrics +{ + public class SpaceMetricsOutputs: SystemResults + { + + /// + /// Construct a SpaceMetricsOutputs with default inputs. + /// This should be used for testing only. + /// + public SpaceMetricsOutputs() : base() + { + } + + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOverride.g.cs b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOverride.g.cs new file mode 100644 index 00000000..1464e595 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/dependencies/SpaceMetricsOverride.g.cs @@ -0,0 +1,104 @@ +using Elements; +using System.Collections.Generic; +using System; +using System.Linq; + +namespace SpaceMetrics +{ + /// + /// Override metadata for SpaceMetricsOverride + /// + public partial class SpaceMetricsOverride : IOverride + { + public static string Name = "Space Metrics"; + public static string Dependency = "Space Planning Zones"; + public static string Context = "[*discriminator=Elements.SpaceBoundary]"; + public static string Paradigm = "Edit"; + + /// + /// Get the override name for this override. + /// + public string GetName() { + return Name; + } + + public object GetIdentity() { + + return Identity; + } + + /// + /// Get context elements that are applicable to this override. + /// + /// Dictionary of input models, or any other kind of dictionary of models. + /// List of context elements that match what is defined on the override. + public static IEnumerable> ContextProxies(Dictionary models) { + return models.AllElementsOfType(Dependency).Proxies(Dependency); + } + } + public static class SpaceMetricsOverrideExtensions + { + /// + /// Apply Space Metrics edit overrides to a collection of existing elements + /// + /// The Space Metrics Overrides to apply + /// A collection of existing elements to which to apply the overrides. + /// A function returning a boolean which indicates whether an element is a match for an override's identity. + /// A function to modify a matched element, returning the modified element. + /// The element type this override applies to. Should match the type(s) in the override's context. + /// A collection of elements, including unmodified and modified elements from the supplied collection. + public static List Apply( + this IList overrideData, + IEnumerable existingElements, + Func identityMatch, + Func modifyElement) where T : Element + { + var resultElements = new List(existingElements); + if (overrideData != null) + { + foreach (var overrideValue in overrideData) + { + // Assuming there will only be one match per identity, find the first element that matches. + var matchingElement = existingElements.FirstOrDefault(e => identityMatch(e, overrideValue.Identity)); + // if we found a match, + if (matchingElement != null) + { + // remove the old matching element + resultElements.Remove(matchingElement); + // apply the modification function to it + var modifiedElement = modifyElement(matchingElement, overrideValue); + // set the identity + Identity.AddOverrideIdentity(modifiedElement, overrideValue); + //and re-add it to the collection + resultElements.Add(modifiedElement); + } + } + } + return resultElements; + } + + /// + /// Apply Space Metrics edit overrides to a collection of existing elements + /// + /// A collection of existing elements to which to apply the overrides. + /// The Space Metrics Overrides to apply — typically `input.Overrides.SpaceMetrics` + /// A function returning a boolean which indicates whether an element is a match for an override's identity. + /// A function to modify a matched element, returning the modified element. + /// The element type this override applies to. Should match the type(s) in the override's context. + /// A collection of elements, including unmodified and modified elements from the supplied collection. + public static void ApplyOverrides( + this List existingElements, + IList overrideData, + Func identityMatch, + Func modifyElement + ) where T : Element + { + var updatedElements = overrideData.Apply(existingElements, identityMatch, modifyElement); + existingElements.Clear(); + existingElements.AddRange(updatedElements); + } + + } + + +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/global.json b/WorkplaceStrategy/SpaceMetrics/global.json new file mode 100644 index 00000000..4aef4472 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/global.json @@ -0,0 +1,7 @@ + +{ + "sdk": { + "version": "6.0.400", + "rollForward": "latestMinor" + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/hypar.json b/WorkplaceStrategy/SpaceMetrics/hypar.json new file mode 100644 index 00000000..b94475df --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/hypar.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://hypar.io/Schemas/Function.json", + "id": "2a34af5b-0d9b-4b11-8a0b-27728a079673", + "name": "Space Metrics", + "description": "Override various workplace metrics from a layout.", + "language": "C#", + "model_output": "Space Metrics", + "model_dependencies": [ + { + "autohide": false, + "name": "Space Planning Zones", + "optional": false + }, + { + "autohide": false, + "name": "Open Office Layout", + "optional": true + }, + { + "autohide": false, + "name": "Meeting Room Layout", + "optional": true + }, + { + "autohide": false, + "name": "Classroom Layout", + "optional": true + }, + { + "autohide": false, + "name": "Phone Booth Layout", + "optional": true + }, + { + "autohide": false, + "name": "Open Collaboration Layout", + "optional": true + }, + { + "autohide": false, + "name": "Private Office Layout", + "optional": true + }, + { + "autohide": false, + "name": "Lounge Layout", + "optional": true + }, + { + "autohide": false, + "name": "Pantry Layout", + "optional": true + }, + { + "autohide": false, + "name": "Reception Layout", + "optional": true + } + ], + "input_schema": { + "type": "object", + "properties": { + } + }, + "overrides": { + "Space Metrics": { + "$hyparOrder": 1, + "dependency": "Space Planning Zones", + "context": "[*discriminator=Elements.SpaceBoundary]", + "identity": { + "ParentCentroid": { + "$ref": "https://hypar.io/Schemas/Geometry/Vector3.json" + } + }, + "paradigm": "edit", + "schema": { + "Seats": { + "type": "number" + }, + "Headcount": { + "type": "number" + }, + "Desks": { + "type": "number" + }, + "Collaboration Seats": { + "type": "number" + } + } + } + }, + "outputs": [], + "element_types": [ + "https://schemas.hypar.io/SpaceMetric.json", + "https://schemas.hypar.io/SpaceBoundary.json" + ], + "repository_url": "", + "filters": {}, + "last_updated": "0001-01-01T00:00:00", + "cli_version": "1.10.0" +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/src/Function.g.cs b/WorkplaceStrategy/SpaceMetrics/src/Function.g.cs new file mode 100644 index 00000000..64eabb32 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/src/Function.g.cs @@ -0,0 +1,73 @@ +// This code was generated by Hypar. +// Edits to this code will be overwritten the next time you run 'hypar init'. +// DO NOT EDIT THIS FILE. + +using Amazon.Lambda.Core; +using Hypar.Functions.Execution; +using Hypar.Functions.Execution.AWS; +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] +namespace SpaceMetrics +{ + public class Function + { + // Cache the model store for use by subsequent + // executions of this lambda. + private UrlModelStore store; + + public async Task Handler(SpaceMetricsInputs args) + { + // Preload dependencies (if they exist), + // so that they are available during model deserialization. + + var sw = System.Diagnostics.Stopwatch.StartNew(); + var asmLocation = this.GetType().Assembly.Location; + var asmDir = Path.GetDirectoryName(asmLocation); + + // Explicitly load the dependencies project, it might have types + // that aren't used in the function but are necessary for correct + // deserialization. + var asmName = Path.GetFileNameWithoutExtension(asmLocation); + var depPath = Path.Combine(asmDir, $"{asmName}.Dependencies.dll"); + if(File.Exists(depPath)) + { + Console.WriteLine($"Loading dependencies assembly from: {depPath}..."); + Assembly.LoadFrom(depPath); + Console.WriteLine("Dependencies assembly loaded."); + } + + // Load all reference assemblies. + Console.WriteLine($"Loading all referenced assemblies."); + foreach (var asm in this.GetType().Assembly.GetReferencedAssemblies()) + { + try + { + Console.WriteLine($"Assembly Name: {asm.FullName}"); + Assembly.Load(asm); + } + catch (Exception e) + { + Console.WriteLine($"Failed to load {asm.FullName}"); + Console.WriteLine(e.Message); + } + } + sw.Stop(); + Console.WriteLine($"Time to load assemblies: {sw.Elapsed.TotalSeconds})"); + + if(this.store == null) + { + this.store = new UrlModelStore(); + } + + + var l = new InvocationWrapper (store, SpaceMetrics.Execute); + var output = await l.InvokeAsync(args); + return output; + } + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs new file mode 100644 index 00000000..8a55f731 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs @@ -0,0 +1,140 @@ +using Elements; +using Elements.Geometry; +using System.Collections.Generic; + +namespace SpaceMetrics +{ + public static class SpaceMetrics + { + private static readonly List> proxies = new List>(); + private static readonly string SpaceMetricDependencyName = SpaceMetricsOverride.Dependency; + + private const string _openOffice = "Open Office"; + private const string _openCollab = "Open Collaboration"; + + /// + /// + /// + /// The input model. + /// The arguments to the execution. + /// A SpaceMetricsOutputs instance containing computed results and the model with any new elements. + public static SpaceMetricsOutputs Execute(Dictionary inputModels, SpaceMetricsInputs input) + { + proxies.Clear(); + var output = new SpaceMetricsOutputs(); + + if (inputModels.TryGetValue("Space Planning Zones", out var zonesModel)) + { + inputModels.TryGetValue(_openOffice + " Layout", out var openOfficeModel); + inputModels.TryGetValue(_openCollab + " Layout", out var openCollabModel); + + var allSpaceBoundaries = zonesModel?.AllElementsAssignableFromType().ToList(); + var openOfficeBoundaries = openOfficeModel?.AllElementsAssignableFromType().ToList(); + var openCollabSpaceMetrics = openCollabModel?.AllElementsAssignableFromType().ToList(); + + var layoutNames = new string[] { _openOffice, _openCollab, "Meeting Room", "Classroom", "Phone Booth", "Private Office", "Lounge", "Reception", "Pantry" }; + foreach (var layoutName in layoutNames) + { + UpdateSpaceMetricsByLayoutType(inputModels, input.Overrides.SpaceMetrics.ToList(), layoutName, allSpaceBoundaries, openOfficeBoundaries, openCollabSpaceMetrics); + } + } + + output.Model.AddElements(proxies); + return output; + } + + private static void UpdateSpaceMetricsByLayoutType( + Dictionary inputModels, + List overrides, + string layoutName, + List boundaries, + List openOfficeBoundaries, + List openCollabSpaceMetrics) + { + if (!inputModels.TryGetValue(layoutName + " Layout", out var layoutModel)) + { + return; + } + + foreach (var sm in layoutModel.AllElementsOfType()) + { + var room = boundaries.FirstOrDefault(b => b.Id == sm.Space); + if (room == null) + { + continue; + } + + if (layoutName == _openOffice && openOfficeBoundaries != null && openCollabSpaceMetrics != null) + { + var openCollabBoundaries = openOfficeBoundaries.Where(b => room.Boundary.Perimeter.Contains(b.Boundary.Perimeter.Centroid())); + foreach (var openCollabBoundary in openCollabBoundaries) + { + var openCollabSM = openCollabSpaceMetrics.FirstOrDefault(osm => osm.Space == openCollabBoundary.Id); + sm.Seats += openCollabSM.Seats; + sm.Headcount += openCollabSM.Headcount; + sm.Desks += openCollabSM.Desks; + sm.CollaborationSeats += openCollabSM.CollaborationSeats; + } + } + + var proxy = GetElementProxy(room, boundaries.Proxies(SpaceMetricDependencyName)); + MatchApplicableOverride(overrides, proxy, sm); + } + } + + private static SpaceMetricsOverride MatchApplicableOverride( + List overridesById, + ElementProxy boundaryProxy, + SpaceMetric defaultMetric = null) + { + var overrideName = SpaceMetricsOverride.Name; + SpaceMetricsOverride config = null; + + // See if we already have matching override attached + var existingOverrideId = boundaryProxy.OverrideIds(overrideName).FirstOrDefault(); + if (existingOverrideId != null) + { + config = overridesById.Find(o => o.Id == existingOverrideId); + if (config != null) + { + return config; + } + } + + // Try to match from identity in configs + config ??= overridesById.Find(o => o.Identity.ParentCentroid.IsAlmostEqualTo(boundaryProxy.Element.ParentCentroid.Value)); + + // Use a default in case none found + if (config == null) + { + config = new SpaceMetricsOverride( + Guid.NewGuid().ToString(), + new SpaceMetricsIdentity(boundaryProxy.Element.ParentCentroid.Value), + new SpaceMetricsValue( + defaultMetric?.Seats ?? 0, + defaultMetric?.Headcount ?? 0, + defaultMetric?.Desks ?? 0, + defaultMetric?.CollaborationSeats ?? 0) + ); + overridesById.Add(config); + } + + // Attach the identity and values data to the proxy + boundaryProxy.AddOverrideIdentity(overrideName, config.Id, config.Identity); + boundaryProxy.AddOverrideValue(overrideName, config.Value); + + // Make sure proxies list has the proxy so that it will serialize in the model. + if (!proxies.Contains(boundaryProxy)) + { + proxies.Add(boundaryProxy); + } + + return config; + } + + private static ElementProxy GetElementProxy(SpaceBoundary spaceBoundary, IEnumerable> allSpaceBoundaries) + { + return allSpaceBoundaries.Proxy(spaceBoundary) ?? spaceBoundary.Proxy(SpaceMetricDependencyName); + } + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.csproj b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.csproj new file mode 100644 index 00000000..c0c5fc33 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.csproj @@ -0,0 +1,13 @@ + + + + + + + + net6.0 + enable + enable + + + diff --git a/WorkplaceStrategy/SpaceMetrics/test/FunctionTest.g.cs b/WorkplaceStrategy/SpaceMetrics/test/FunctionTest.g.cs new file mode 100644 index 00000000..849938dc --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/test/FunctionTest.g.cs @@ -0,0 +1,24 @@ +// This code was generated by Hypar. +// Edits to this code will be overwritten the next time you run 'hypar init'. +// DO NOT EDIT THIS FILE. + +using Xunit; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using Xunit.Abstractions; +using System; +using System.Collections.Generic; + +namespace SpaceMetrics.Tests +{ + public class FunctionTests + { + private readonly ITestOutputHelper output; + + public FunctionTests(ITestOutputHelper output) + { + this.output = output; + } + } +} \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/test/GlobalUsings.cs b/WorkplaceStrategy/SpaceMetrics/test/GlobalUsings.cs new file mode 100644 index 00000000..8c927eb7 --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/test/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/WorkplaceStrategy/SpaceMetrics/test/SpaceMetrics.Tests.csproj b/WorkplaceStrategy/SpaceMetrics/test/SpaceMetrics.Tests.csproj new file mode 100644 index 00000000..b6e1b61e --- /dev/null +++ b/WorkplaceStrategy/SpaceMetrics/test/SpaceMetrics.Tests.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + From a61fa99228ec79c1ec9310dc59211d27aa297b4c Mon Sep 17 00:00:00 2001 From: "AMCBRIDGE\\ksloboda" Date: Tue, 14 Nov 2023 14:52:56 +0200 Subject: [PATCH 2/2] add space metric overrides to WorkplaceMetrics --- .../SpaceMetrics/src/SpaceMetrics.cs | 14 +++++++--- .../dependencies/LevelVolume.g.cs | 2 +- WorkplaceStrategy/WorkplaceMetrics/hypar.json | 4 +++ .../WorkplaceMetrics/src/WorkplaceMetrics.cs | 27 ++++++++++++++----- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs index 8a55f731..89d17f29 100644 --- a/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs +++ b/WorkplaceStrategy/SpaceMetrics/src/SpaceMetrics.cs @@ -23,6 +23,7 @@ public static SpaceMetricsOutputs Execute(Dictionary inputModels, proxies.Clear(); var output = new SpaceMetricsOutputs(); + var spaceMetrics = new List(); if (inputModels.TryGetValue("Space Planning Zones", out var zonesModel)) { inputModels.TryGetValue(_openOffice + " Layout", out var openOfficeModel); @@ -35,15 +36,16 @@ public static SpaceMetricsOutputs Execute(Dictionary inputModels, var layoutNames = new string[] { _openOffice, _openCollab, "Meeting Room", "Classroom", "Phone Booth", "Private Office", "Lounge", "Reception", "Pantry" }; foreach (var layoutName in layoutNames) { - UpdateSpaceMetricsByLayoutType(inputModels, input.Overrides.SpaceMetrics.ToList(), layoutName, allSpaceBoundaries, openOfficeBoundaries, openCollabSpaceMetrics); + spaceMetrics.AddRange(UpdateSpaceMetricsByLayoutType(inputModels, input.Overrides.SpaceMetrics.ToList(), layoutName, allSpaceBoundaries, openOfficeBoundaries, openCollabSpaceMetrics)); } } output.Model.AddElements(proxies); + output.Model.AddElements(spaceMetrics); return output; } - private static void UpdateSpaceMetricsByLayoutType( + private static List UpdateSpaceMetricsByLayoutType( Dictionary inputModels, List overrides, string layoutName, @@ -51,9 +53,10 @@ private static void UpdateSpaceMetricsByLayoutType( List openOfficeBoundaries, List openCollabSpaceMetrics) { + var spaceMetrics = new List(); if (!inputModels.TryGetValue(layoutName + " Layout", out var layoutModel)) { - return; + return spaceMetrics; } foreach (var sm in layoutModel.AllElementsOfType()) @@ -78,8 +81,11 @@ private static void UpdateSpaceMetricsByLayoutType( } var proxy = GetElementProxy(room, boundaries.Proxies(SpaceMetricDependencyName)); - MatchApplicableOverride(overrides, proxy, sm); + var config = MatchApplicableOverride(overrides, proxy, sm); + spaceMetrics.Add(new SpaceMetric(room.Id, config.Value.Seats, config.Value.Headcount, config.Value.Desks, config.Value.CollaborationSeats)); } + + return spaceMetrics; } private static SpaceMetricsOverride MatchApplicableOverride( diff --git a/WorkplaceStrategy/WorkplaceMetrics/dependencies/LevelVolume.g.cs b/WorkplaceStrategy/WorkplaceMetrics/dependencies/LevelVolume.g.cs index be2fb359..d437122c 100644 --- a/WorkplaceStrategy/WorkplaceMetrics/dependencies/LevelVolume.g.cs +++ b/WorkplaceStrategy/WorkplaceMetrics/dependencies/LevelVolume.g.cs @@ -76,7 +76,7 @@ public LevelVolume() public System.Guid? PlanView { get; set; } /// Multiple profiles used for a collection of volumes - [JsonProperty("Profiles", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [JsonProperty("Profiles", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public IList Profiles { get; set; } diff --git a/WorkplaceStrategy/WorkplaceMetrics/hypar.json b/WorkplaceStrategy/WorkplaceMetrics/hypar.json index ddea9d7b..9b812306 100644 --- a/WorkplaceStrategy/WorkplaceMetrics/hypar.json +++ b/WorkplaceStrategy/WorkplaceMetrics/hypar.json @@ -72,6 +72,10 @@ { "name": "Circulation", "optional": true + }, + { + "name": "Space Metrics", + "optional": true } ], "input_schema": { diff --git a/WorkplaceStrategy/WorkplaceMetrics/src/WorkplaceMetrics.cs b/WorkplaceStrategy/WorkplaceMetrics/src/WorkplaceMetrics.cs index aaca0e65..7b1ba6da 100644 --- a/WorkplaceStrategy/WorkplaceMetrics/src/WorkplaceMetrics.cs +++ b/WorkplaceStrategy/WorkplaceMetrics/src/WorkplaceMetrics.cs @@ -32,8 +32,6 @@ public static WorkplaceMetricsOutputs Execute(Dictionary inputMod var hasFloors = inputModels.TryGetValue("Floors", out var floorsModel); var hasMass = inputModels.TryGetValue("Conceptual Mass", out var massModel); var hasCirculation = inputModels.TryGetValue("Circulation", out var circulationModel); - inputModels.TryGetValue(_openOffice + " Layout", out var openOfficeModel); - inputModels.TryGetValue(_openCollab + " Layout", out var openCollabModel); // Get program requirements var hasProgramRequirements = inputModels.TryGetValue("Program Requirements", out var programReqsModel); @@ -92,8 +90,6 @@ public static WorkplaceMetricsOutputs Execute(Dictionary inputMod outputModel.AddElement(settings); var allSpaceBoundaries = zonesModel.AllElementsAssignableFromType().ToList(); - var openOfficeBoundaries = openOfficeModel?.AllElementsAssignableFromType().ToList(); - var openCollabSpaceMetrics = openCollabModel?.AllElementsAssignableFromType().ToList(); // convert circulation to space boundaries if (hasCirculation) @@ -131,11 +127,19 @@ public static WorkplaceMetricsOutputs Execute(Dictionary inputMod } + inputModels.TryGetValue(_openOffice + " Layout", out var openOfficeModel); + inputModels.TryGetValue(_openCollab + " Layout", out var openCollabModel); + inputModels.TryGetValue("Space Metrics", out var spaceMetricsModel); + + var spaceMetricOverrides = spaceMetricsModel?.AllElementsOfType().ToList(); + var openOfficeBoundaries = openOfficeModel?.AllElementsAssignableFromType().ToList(); + var openCollabSpaceMetrics = openCollabModel?.AllElementsAssignableFromType().ToList(); + var layoutNames = new string[] { _openOffice, _meetingRoom, _classroom, _phoneBooth, _openCollab, _privateOffice, _lounge, _reception, _pantry }; var metricByLayouts = new Dictionary(); foreach (var layoutName in layoutNames) { - metricByLayouts[layoutName] = CountWorkplaceTyped(inputModels, input, layoutName, allSpaceBoundaries, openOfficeBoundaries, openCollabSpaceMetrics); + metricByLayouts[layoutName] = CountWorkplaceTyped(inputModels, input, layoutName, allSpaceBoundaries, openOfficeBoundaries, openCollabSpaceMetrics, spaceMetricOverrides); } var meetingRoomCount = allSpaceBoundaries.Count(sb => sb.Name == "Meeting Room"); @@ -216,7 +220,8 @@ private static SpaceMetric CountWorkplaceTyped( string layoutName, List boundaries, List openOfficeBoundaries, - List openCollabSpaceMetrics) + List openCollabSpaceMetrics, + List spaceMetricOverrides) { var metric = new SpaceMetric(); if (inputModels.TryGetValue(layoutName + " Layout", out var layoutModel)) @@ -226,7 +231,15 @@ private static SpaceMetric CountWorkplaceTyped( var room = boundaries.FirstOrDefault(b => b.Id == sm.Space); if (room != null) { - if (layoutName == _openOffice && openOfficeBoundaries != null && openCollabSpaceMetrics != null) + var smOverride = spaceMetricOverrides?.FirstOrDefault(o => o.Space == sm.Space); + if (smOverride != null) + { + sm.Seats = smOverride.Seats; + sm.Headcount = smOverride.Headcount; + sm.Desks = smOverride.Desks; + sm.CollaborationSeats = smOverride.CollaborationSeats; + } + else if (layoutName == _openOffice && openOfficeBoundaries != null && openCollabSpaceMetrics != null) { var openCollabBoundaries = openOfficeBoundaries.Where(b => room.Boundary.Perimeter.Contains(b.Boundary.Perimeter.Centroid())); foreach (var openCollabBoundary in openCollabBoundaries)