diff --git a/LayoutFunctions/LayoutFunctionCommon/ISpaceBoundary.cs b/LayoutFunctions/LayoutFunctionCommon/ISpaceBoundary.cs index d6a96717..5894e12b 100644 --- a/LayoutFunctions/LayoutFunctionCommon/ISpaceBoundary.cs +++ b/LayoutFunctions/LayoutFunctionCommon/ISpaceBoundary.cs @@ -21,6 +21,9 @@ public interface ISpaceBoundary public string DefaultWallType { get; set; } + [JsonProperty("Config Id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ConfigId { get; set; } + } } \ No newline at end of file diff --git a/LayoutFunctions/LayoutFunctionCommon/LayoutGeneration.cs b/LayoutFunctions/LayoutFunctionCommon/LayoutGeneration.cs index a146563f..04fad27a 100644 --- a/LayoutFunctions/LayoutFunctionCommon/LayoutGeneration.cs +++ b/LayoutFunctions/LayoutFunctionCommon/LayoutGeneration.cs @@ -61,6 +61,12 @@ public virtual LayoutGenerationResult StandardLayoutOnAllLevels(string programTy }; boundaryCurves.AddRange(spaceBoundary.Voids ?? new List()); + var configsForRoom = configs; + if (room.ConfigId != null) + { + configsForRoom = LayoutStrategies.LimitConfigsToId(configs, room, wallCandidateOptions); + } + var possibleConfigs = new List<(ConfigInfo configInfo, List wallCandidates)>(); foreach (var (OrientationGuideEdge, WallCandidates) in wallCandidateOptions) { @@ -68,7 +74,7 @@ public virtual LayoutGenerationResult StandardLayoutOnAllLevels(string programTy var grid = new Grid2d(boundaryCurves, orientationTransform); foreach (var cell in grid.GetCells()) { - var config = FindConfigByFit(configs, cell); + var config = FindConfigByFit(configsForRoom, cell); if (config != null) { possibleConfigs.Add((config.Value, WallCandidates)); @@ -238,7 +244,7 @@ protected virtual SpaceConfiguration DeserializeConfigJson(string configJson) KeyValuePair? selectedConfigPair = null; foreach (var configPair in orderedConfigs) { - if (configPair.Value.CellBoundary.Width < width && configPair.Value.CellBoundary.Depth < length) + if (configPair.Value.CellBoundary.Width < (width + Vector3.EPSILON) && configPair.Value.CellBoundary.Depth < (length + Vector3.EPSILON)) { selectedConfigPair = configPair; break; diff --git a/LayoutFunctions/LayoutFunctionCommon/LayoutStrategies.cs b/LayoutFunctions/LayoutFunctionCommon/LayoutStrategies.cs index 87190ea8..5347bfcb 100644 --- a/LayoutFunctions/LayoutFunctionCommon/LayoutStrategies.cs +++ b/LayoutFunctions/LayoutFunctionCommon/LayoutStrategies.cs @@ -211,7 +211,13 @@ public static HashSet StandardLayoutOnAllLevels(); - var layoutSucceeded = ProcessRoom(room, outputModel, countSeats, configs, corridorSegments, levelVolume, wallCandidateLines); + + var configsForRoom = configs; + if (room.ConfigId != null) + { + configsForRoom = LimitConfigsToId(configs, room); + } + var layoutSucceeded = ProcessRoom(room, outputModel, countSeats, configsForRoom, corridorSegments, levelVolume, wallCandidateLines); if (layoutSucceeded) { processedSpaces.Add(room.Id); } double height = room.Height == 0 ? 3 : room.Height; @@ -240,6 +246,38 @@ public static HashSet StandardLayoutOnAllLevels + /// Pringle-specific behavior to pick a specific config and orientation. This code only executes if the room has a `ConfigId` property, which is only set on pringle. + /// + public static SpaceConfiguration LimitConfigsToId(SpaceConfiguration configs, TSpaceBoundary room, List<(RoomEdge OrientationGuideEdge, List WallCandidates)> wallCandidateOptions = null) where TSpaceBoundary : Element, ISpaceBoundary + { + // If a set of wall candidate options are provided, limit to the one that aligns with the boundary's first edge. + // In the future, as room shapes become more editable, we might want to pass in an explicit "orientation edge" instead of just using the first edge. + if (wallCandidateOptions != null) + { + var roomOrientationEdge = room.Boundary.Perimeter.Segments().First(); + for (int i = wallCandidateOptions.Count - 1; i >= 0; i--) + { + var (OrientationGuideEdge, _) = wallCandidateOptions[i]; + if (OrientationGuideEdge.Line.Mid().DistanceTo(roomOrientationEdge.Mid()) > 0.01) + { + wallCandidateOptions.RemoveAt(i); + } + } + } + + // Limit the possible configs to the one specified by the room's ConfigId property. + var configId = room.ConfigId; + var config = new SpaceConfiguration(); + if (configs.ContainsKey(configId)) + { + config.Add(configId, configs[configId]); + return config; + } + + return configs; + } + /// /// Basically the same as StandardLayoutOnAllLevels, but without the actual furniture layout part — just the wall creation. diff --git a/LayoutFunctions/MeetingRoomLayout/dependencies/SpaceBoundary.cs b/LayoutFunctions/MeetingRoomLayout/dependencies/SpaceBoundary.cs index ed244d1f..7f3af68c 100644 --- a/LayoutFunctions/MeetingRoomLayout/dependencies/SpaceBoundary.cs +++ b/LayoutFunctions/MeetingRoomLayout/dependencies/SpaceBoundary.cs @@ -1,9 +1,11 @@ using Elements.Geometry; +using Newtonsoft.Json; namespace Elements { public partial class SpaceBoundary : GeometricElement, ISpaceBoundary { public Vector3? ParentCentroid { get; set; } - + [JsonProperty("Config Id")] + public string ConfigId { get; set; } } } \ No newline at end of file