public static void MaximumPlacements(RoomPackage room, ZonePackage zone, ProgramManifest pm) { var maxPlacement = room.FillOrder .Select(x => pm.ProgramPackages[x].Quota == 0 ? 999 : zone.RemainingProgramTargets[x]).ToList(); room.MaxPlacement = maxPlacement; }
public static void InputGeometry(ZonePackage zone) { foreach (RoomPackage room in zone.Rooms) { foreach (PlacementPackage item in room.PlacedItems) { var activeProgram = item.Program; var drawingGeometry = new List <Curve>(); foreach (Curve curve in activeProgram.DrawingGeometry) { drawingGeometry.Add(new NurbsCurve(curve.ToNurbsCurve())); } foreach (Curve geo in drawingGeometry) { geo.Transform(Transform.Translation(new Vector3d(item.Dims.Center - activeProgram.Dims.Center))); geo.Transform(Transform.Rotation(Vector3d.YAxis, room.OrientationPlane.XAxis, item.Dims.Center)); //var testVector = new Vector3d(item.Dims.Center - room.Dims.Center); if (room.Dims.Height > room.Dims.Width ? room.OrientationPlane.XAxis.X > 0 == item.Orientation.YAxis.X > 0 : room.OrientationPlane.XAxis.Y > 0 == item.Orientation.YAxis.Y > 0) { geo.Transform(Transform.Mirror(new Plane(item.Dims.Center, room.OrientationPlane.YAxis, Vector3d.ZAxis))); } else { } } item.DrawingGeometry = drawingGeometry; } } }
public static void RemainingProgramTargets(ZonePackage zone, RoomPackage room) { for (int i = 0; i < room.NumProgramsPlaced.Count; i++) { zone.RemainingProgramTargets[i] = zone.RemainingProgramTargets[i] - room.NumProgramsPlaced[i]; } }
/// <summary> /// Since the zone-specific targets are estimates, if a zone is unable to meet its quotas, it passes them along to the next. /// </summary> /// <param name="zone"></param> /// <param name="nextZone"></param> /// <param name="pm"></param> public static void PassUnfulfilledTargets(ZonePackage zone, ZonePackage nextZone, ProgramManifest pm) { for (int i = 0; i < zone.RemainingProgramTargets.Count; i++) { var activeRemainder = zone.RemainingProgramTargets[i]; if (activeRemainder > 0 && pm.ProgramPackages[i].Quota != 0) { nextZone.ProgramTargets[i] = nextZone.ProgramTargets[i] + activeRemainder; } } }
/// <summary> /// Population routine for debugging. Places one instance of highest priority item in room. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> /// <param name="pm"></param> public static void PlaceOne(RoomPackage room, ZonePackage zone, ProgramManifest pm) { var firstWithTarget = pm.ProgramPackages[zone.ProgramTargets.IndexOf(zone.ProgramTargets.First(x => x > 0))]; var candidate = Stage.Program.InRoom(room, firstWithTarget); if (Collision.PlacementIsValid(room, candidate, pm)) { room.PlacedItems.Add(candidate); room.NumProgramsPlaced[firstWithTarget.Priority] = room.NumProgramsPlaced[firstWithTarget.Priority] + 1; } }
public static void ProgramFillOrder(RoomPackage room, ZonePackage zone, ProgramManifest pm) { var fillOrder = Enumerable.Range(0, zone.RemainingProgramTargets.Count) .Where(i => zone.RemainingProgramTargets[i] > 0 && pm.ProgramPackages[i].Quota != 0).ToList() .Select(x => pm.ProgramPackages[x]) .OrderByDescending(x => x.Dims.Height).ToList() .Select(x => x.Priority).ToList(); fillOrder.AddRange(pm.ProgramPackages .Where(x => x.Quota == 0).ToList() .Select(x => x.Priority)); room.FillOrder = fillOrder; }
public static void AffinityType(ZonePackage zp) { if (zp.IsCoreAdjacent) { zp.AffinityType = 1; } else if (zp.IsPerimeterAdjacent) { zp.AffinityType = 2; } else { zp.AffinityType = 3; } }
/// <summary> /// Selects best population strategy for room based on current conditions. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> /// <param name="pm"></param> public static void Room(RoomPackage room, ZonePackage zone, ProgramManifest pm) { //Prepare room for population routine based on current fill progress. room.PlacedItems = new List <PlacementPackage>(); Stage.Room.BaseAnchors(room); Stage.Room.ProgramFillOrder(room, zone, pm); Stage.Room.MaximumPlacements(room, zone, pm); //Select best population strategy based on room geometry and quotas. //TODO: Automate selection process and write base suite of strategies. Populate.ByMostRows(room, zone, pm); //After room is filled, adjust remaining quota for zone. Update.Zone.RemainingProgramTargets(zone, room); }
protected override void SolveInstance(IGH_DataAccess DA) { ZonePackage zp = null; if (!DA.GetData(0, ref zp)) { return; } var roomRegions = new List <Brep>(); var placedBounds = new List <Curve>(); var roomPlanes = new List <Plane>(); var anchorPoints = new List <Point3d>(); var drawingGeometry = new List <Curve>(); var drawingGeometryCount = new List <int>(); var roomCenter = new List <Point3d>(); foreach (RoomPackage room in zp.Rooms) { roomRegions.Add(room.Region); roomPlanes.Add(room.OrientationPlane); anchorPoints.Add(room.PrevAnchor); foreach (PlacementPackage placedItem in room.PlacedItems) { placedBounds.Add(placedItem.Bounds); roomCenter.Add(placedItem.Dims.Center); drawingGeometryCount.Add(placedItem.DrawingGeometry.Count); foreach (Curve geo in placedItem.DrawingGeometry) { drawingGeometry.Add(geo); } } } DA.SetDataList(0, roomRegions); DA.SetDataList(1, placedBounds); DA.SetDataList(2, roomPlanes); DA.SetDataList(3, anchorPoints); DA.SetDataList(4, drawingGeometry); DA.SetDataList(5, drawingGeometryCount); DA.SetDataList(6, roomCenter); }
public static ZoneManifest ZoneManifest(List <Brep> zonesToParse, ProgramManifest pm, TestFitPackage tf) { List <ZonePackage> zpList = new List <ZonePackage>(); double totalArea = 0; foreach (Brep zone in zonesToParse) { ZonePackage zp = new ZonePackage(zone); if (zp.BaseArea < 10) { //Stopgap solution for micro-zones generated by weird circulation corners. continue; } totalArea = totalArea + zp.BaseArea; EdgeCurves edgeCurvePackage = Select.ZoneEdgeCurves(zone, tf, zonesToParse); Update.Zone.EdgeClassification(zp, edgeCurvePackage); Update.Zone.Adjacencies(zp); Update.Zone.AffinityType(zp); zpList.Add(zp); } ZoneManifest zm = new ZoneManifest(zpList, totalArea) { FloorPlan = tf.FloorPlanPackage }; Update.Program.ZonePreference(pm, zm); Update.Zone.Popularity(zm, pm); Update.Zone.ProgramPriority(zm, pm); Update.Zone.ReservedArea(zm, pm); Update.Zone.ProgramTargets(zm, pm); Update.Zone.RoomConfiguration(zm, pm); return(zm); }
/// <summary> /// Generates a base plane for each room with +Y pointing towards circulation. /// Necessary to normalize placement of program across highly varied room geometry. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> public static void Orientation(RoomPackage room, ZonePackage zone) { var circEdge = Select.PrimaryCirculationEdge(zone); var basePoint = Utils.GetRegionCenter(room.Region); circEdge.ClosestPoint(basePoint, out double t); var circEdgePoint = circEdge.PointAt(t); var yDirVector = new Vector3d(circEdgePoint - basePoint); var yTestVal = Confirm.VectorProportionIsVertical(yDirVector) ? yDirVector.Y : yDirVector.X; var yAxis = Confirm.VectorProportionIsVertical(yDirVector) ? new Vector3d(0, yTestVal, 0) : new Vector3d(yTestVal, 0, 0); var xAxis = new Vector3d(yAxis); xAxis.Rotate(Math.PI / 2, Vector3d.ZAxis); var roomOrientationPlane = new Plane(basePoint, xAxis, yAxis); room.OrientationPlane = roomOrientationPlane; }
protected override void SolveInstance(IGH_DataAccess DA) { ZonePackage zp = null; if (!DA.GetData(0, ref zp)) { return; } DA.SetData(0, zp.Region); EdgeCurves edges = zp.EdgeCurves; DA.SetDataList(2, edges.PerimeterAdjacent); DA.SetDataList(3, edges.CirculationAdjacent); DA.SetDataList(4, edges.CoreAdjacent); DA.SetDataList(5, edges.ExemptionAdjacent); DA.SetDataList(6, edges.StructureAdjacent); DA.SetDataList(7, edges.ZoneAdjacent); DA.SetDataList(9, zp.ProgramTargets); }
/// <summary> /// Negotiates program quotas, affinities, and priority to assign each zone a "sub-quota" to meet. /// </summary> /// <param name="zm"></param> /// <param name="pm"></param> public static void ProgramTargets(ZoneManifest zm, ProgramManifest pm) { int numZones = zm.Zones.Count; int numPrograms = pm.ProgramPackages.Count; #region area based distribution //Distribute targets between zones based on their proportion of the total area. foreach (ZonePackage zone in zm.Zones) { List <double> proportionalTargets = new List <double>(); foreach (ProgramPackage program in pm.ProgramPackages) { proportionalTargets.Add(program.Target * (zone.BaseArea / zm.TotalArea)); } zone.ProportionalTargets = proportionalTargets; } #endregion #region safe rounding to integers //Round these proportional targets while maintaining overall quota total. List <int> newTargets = new List <int>(); for (int i = 0; i < numPrograms; i++) { int activeTarget = pm.ProgramPackages[i].Target; List <double> distForActiveProgram = new List <double>(); foreach (ZonePackage zone in zm.Zones) { distForActiveProgram.Add(zone.ProportionalTargets[i]); } newTargets = Utils.RoundWithinTotal(distForActiveProgram, activeTarget); for (int j = 0; j < zm.Zones.Count; j++) { if (i == 0) { zm.Zones[j].ProgramTargets = new List <int>(); } //RhinoApp.WriteLine(zm.Zones[j].ProgramTargets.Count.ToString()); zm.Zones[j].ProgramTargets.Add(newTargets[j]); } } #endregion #region horse trading //In reverse-prioroity order, maximize program target in zone. for (int i = numPrograms - 1; i >= 0; i--) { ProgramPackage activeProgram = pm.ProgramPackages[i]; //Decrement by zone target, on move into new zone, and by one for each trade. int remainingToMove = activeProgram.Target; //Increment when activeZone runs out of ejectionProgram quota to send. Cannot be >= numPrograms. int ejectionIndexModifier = 0; //Increment when sourceZone runs out of activeProgram quota to pull. Cannot be >= numZones. int sourceZoneIndexModifier = 0; //RhinoApp.WriteLine("---Beginning horse trade for program {0}.", i.ToString()); for (int j = 0; j < numZones; j++) { //Prepare base information for start of trading procedure in each zone. ZonePackage activeZone = zm.Zones[activeProgram.ZonePreference[j]]; ejectionIndexModifier = 0; sourceZoneIndexModifier = 0; double baseReservedArea = activeZone.ReservedArea[j][i]; double reservedAreaRemaining = baseReservedArea - (activeZone.ProgramTargets[i] * activeProgram.OccupationArea); //RhinoApp.WriteLine(String.Format("*Maximizing zone {0} (#{1} - {3}) ({2} sqft available.)", activeProgram.ZonePreference[j].ToString(), j.ToString(), reservedAreaRemaining.ToString(), activeZone.ToString())); if (reservedAreaRemaining < 0) { //Often for maximized program, and sometimes for others, the default distribution will be larger than the reserved area. //This is most common when the zone is desired by several programs. //Since the current setup solves from lowest priority to highest, the higher priority programs will kick out the others. //RhinoApp.WriteLine("...negative remaining area. Skip!"); continue; } //Pull from zone that activeProgram least prefers. while (zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]].ProgramTargets[i] <= 0) { //RhinoApp.WriteLine(">No program in zone {0} available to pull ({1}), incrementing zone.", activeProgram.ZonePreference[(numZones - (sourceZoneIndexModifier + 1))].ToString(), zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]].ToString()); sourceZoneIndexModifier++; if (sourceZoneIndexModifier >= numZones) { sourceZoneIndexModifier--; break; } } ZonePackage sourceZone = zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]]; //RhinoApp.WriteLine("First source zone: {0}", sourceZone.ToString()); //Eject program from activeZone that least wants to be there. //Its preference for the sourceZone is not considered. It should be thankful to be able to leave the place it hates so much. while (activeZone.ProgramTargets[activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]] <= 0) { int activeIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; //RhinoApp.WriteLine(">No program {0} available to eject, incrementing program.", activeIndex.ToString()); ejectionIndexModifier++; if (ejectionIndexModifier >= numPrograms) { ejectionIndexModifier--; break; } } int programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; //RhinoApp.WriteLine("First program to eject: {0}", programToEjectIndex.ToString()); double ejectedProgramSizeCache = 0; int currentLoopEjectedProgramDelta = 0; //Preflight tests: bool remaining = (remainingToMove != 0); bool availableToEject = (activeZone.ProgramTargets[programToEjectIndex] > 0); bool reservedAvailable = (reservedAreaRemaining > 0); bool availableToPull = (sourceZone.ProgramTargets[i] > 0); //RhinoApp.WriteLine(String.Format("Preflight tests: {0} | {1} | {2} | {3}", remaining, availableToEject, reservedAvailable, availableToPull)); //While there is still activeProgram to optimize, other program to send from activeZone, reserved area to fill in activeZone, and program to receive from sourceZone... //Proceed with horse trading. while (remainingToMove != 0 && activeZone.ProgramTargets[programToEjectIndex] > 0 && reservedAreaRemaining > 0 && sourceZone.ProgramTargets[i] > 0) { //Skip loop if trying to eject self. if (programToEjectIndex == i) { ejectionIndexModifier++; if (ejectionIndexModifier >= numPrograms) { break; } programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; //RhinoApp.WriteLine(">Self-ejection detected, moving on to program {0}.", programToEjectIndex); continue; } //Make necessary measurements for potential horse trade. int currentLoopActiveProgramDelta = 0; currentLoopEjectedProgramDelta++; double sizeOfProgramToEject = (pm.ProgramPackages[programToEjectIndex].OccupationArea * currentLoopEjectedProgramDelta) + ejectedProgramSizeCache; //RhinoApp.WriteLine("Blip."); //RhinoApp.WriteLine("Testing swap of {0}x program {1}. (Area {2}% filled.)", currentLoopEjectedProgramDelta.ToString(), programToEjectIndex.ToString(), ((sizeOfProgramToEject / activeProgram.OccupationArea) * 100).ToString()); //Because the area of one staged program may be multiple factors larger than the area of the activeProgram, we can't just increment by one. if (sizeOfProgramToEject > activeProgram.OccupationArea) { int potentialSwap = Convert.ToInt32(Math.Floor(sizeOfProgramToEject / activeProgram.OccupationArea)); int remainingAtSource = sourceZone.ProgramTargets[i]; while (remainingToMove > 0 && potentialSwap > 0) { potentialSwap--; remainingToMove--; currentLoopActiveProgramDelta++; } //RhinoApp.WriteLine(String.Format("Trade initiated! {0} ejected ({1} still available) | {2} pulled ({3} remaining at source)", currentLoopEjectedProgramDelta.ToString(), activeZone.ProgramTargets[programToEjectIndex].ToString(), currentLoopActiveProgramDelta.ToString(), sourceZone.ProgramTargets[i].ToString())); reservedAreaRemaining = reservedAreaRemaining - sizeOfProgramToEject; //RhinoApp.WriteLine("{0} reserved area left to fill.", reservedAreaRemaining.ToString()); ejectedProgramSizeCache = 0; } //If a trade has been identified, complete it and check for necessary changes before next loop. if (currentLoopActiveProgramDelta > 0) { sourceZone.ProgramTargets[i] = sourceZone.ProgramTargets[i] - currentLoopActiveProgramDelta; activeZone.ProgramTargets[i] = activeZone.ProgramTargets[i] + currentLoopActiveProgramDelta; activeZone.ProgramTargets[programToEjectIndex] = activeZone.ProgramTargets[programToEjectIndex] - currentLoopEjectedProgramDelta; sourceZone.ProgramTargets[programToEjectIndex] = sourceZone.ProgramTargets[programToEjectIndex] + currentLoopEjectedProgramDelta; remainingToMove = remainingToMove - currentLoopActiveProgramDelta; currentLoopEjectedProgramDelta = 0; currentLoopActiveProgramDelta = 0; if (remainingToMove == 0) { //Operation is complete, move to next program. (There is a second break outside of the while loop for this.) activeZone.ReservedArea[j][i] = reservedAreaRemaining; if (sourceZone.ProgramTargets[i] < 0) { int delta = Math.Abs(sourceZone.ProgramTargets[i]); sourceZone.ProgramTargets[i] = sourceZone.ProgramTargets[i] + delta; activeZone.ProgramTargets[i] = activeZone.ProgramTargets[i] - delta; } if (activeZone.ProgramTargets[programToEjectIndex] < 0) { int delta = Math.Abs(activeZone.ProgramTargets[programToEjectIndex]); activeZone.ProgramTargets[programToEjectIndex] = activeZone.ProgramTargets[programToEjectIndex] + delta; sourceZone.ProgramTargets[programToEjectIndex] = sourceZone.ProgramTargets[programToEjectIndex] - delta; } break; } if (reservedAreaRemaining < activeProgram.OccupationArea) { //activeZone has run out of available space, reset values for next zone. ejectionIndexModifier = 0; sourceZoneIndexModifier = 0; break; } if (sourceZone.ProgramTargets[i] <= 0) { //sourceZone has run out of activeProgram to pull. Increment sourceZoneIndexModifier. if (sourceZone.ProgramTargets[i] < 0) { int delta = Math.Abs(sourceZone.ProgramTargets[i]); sourceZone.ProgramTargets[i] = sourceZone.ProgramTargets[i] + delta; activeZone.ProgramTargets[i] = activeZone.ProgramTargets[i] - delta; } currentLoopEjectedProgramDelta = 0; ejectionIndexModifier = 0; programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; sourceZoneIndexModifier++; sourceZone = zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]]; //continue; } if (activeZone.ProgramTargets[programToEjectIndex] <= 0) { //activeZone has run out of currentProgram to eject. Increment ejectionIndexModifier. if (activeZone.ProgramTargets[programToEjectIndex] < 0) { int delta = Math.Abs(activeZone.ProgramTargets[programToEjectIndex]); activeZone.ProgramTargets[programToEjectIndex] = activeZone.ProgramTargets[programToEjectIndex] + delta; sourceZone.ProgramTargets[programToEjectIndex] = sourceZone.ProgramTargets[programToEjectIndex] - delta; } currentLoopEjectedProgramDelta = 0; ejectionIndexModifier++; programToEjectIndex = ejectionIndexModifier >= numPrograms ? numPrograms : activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; //continue; } if (programToEjectIndex >= numPrograms) { //No more program available to pull in zone. Reset board and increment sourceZone. currentLoopEjectedProgramDelta = 0; ejectedProgramSizeCache = 0; ejectionIndexModifier = 0; programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; sourceZoneIndexModifier++; sourceZone = zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]]; } if (sourceZoneIndexModifier >= numZones) { //No more zones to pull from. Program is as good as it's going to get. remainingToMove = 0; break; } //If none of those tests trigger, things are fine and the next loop in this zone will begin. } //Endchecks for when a trade is not completed. If any while-condition is about to fail, increment necessary modifier, prepare for next loop, or complete process. if (currentLoopActiveProgramDelta == 0) { if (remainingToMove == 0) { //Commit any outstanding deltas, move to next program. (There is a second break outside of the while loop for this.) activeZone.ReservedArea[j][i] = reservedAreaRemaining; break; } if (reservedAreaRemaining < activeProgram.OccupationArea) { //activeZone has run out of available space, reset values for next zone. programToEjectIndex = 0; sourceZoneIndexModifier = 0; break; } if (sourceZone.ProgramTargets[i] <= 0) { //sourceZone has run out of activeProgram to pull. Increment sourceZoneIndexModifier. if (sourceZone.ProgramTargets[i] < 0) { int delta = Math.Abs(sourceZone.ProgramTargets[i]); sourceZone.ProgramTargets[i] = sourceZone.ProgramTargets[i] + delta; activeZone.ProgramTargets[i] = activeZone.ProgramTargets[i] - delta; } currentLoopEjectedProgramDelta = 0; ejectionIndexModifier = 0; programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; sourceZoneIndexModifier++; sourceZone = zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]]; //continue; } if (activeZone.ProgramTargets[programToEjectIndex] <= 0) { //activeZone has run out of currentProgram to eject. Increment ejectionIndexModifier. if (activeZone.ProgramTargets[programToEjectIndex] < 0) { int delta = Math.Abs(activeZone.ProgramTargets[programToEjectIndex]); activeZone.ProgramTargets[programToEjectIndex] = activeZone.ProgramTargets[programToEjectIndex] + delta; sourceZone.ProgramTargets[programToEjectIndex] = sourceZone.ProgramTargets[programToEjectIndex] - delta; } currentLoopEjectedProgramDelta = 0; ejectionIndexModifier++; programToEjectIndex = ejectionIndexModifier >= numPrograms ? numPrograms : activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; ejectedProgramSizeCache = programToEjectIndex >= numPrograms ? 0 : currentLoopEjectedProgramDelta * pm.ProgramPackages[programToEjectIndex].OccupationArea; //ejectedProgramCountCache = 0; //continue; } if (ejectionIndexModifier >= numPrograms) { //No more program available to pull in zone. Reset board and increment sourceZone. currentLoopEjectedProgramDelta = 0; ejectedProgramSizeCache = 0; ejectionIndexModifier = 0; programToEjectIndex = activeZone.ProgramPriority[numPrograms - (ejectionIndexModifier + 1)]; sourceZoneIndexModifier++; sourceZone = zm.Zones[activeProgram.ZonePreference[numZones - (sourceZoneIndexModifier + 1)]]; } if (sourceZoneIndexModifier >= numZones) { //No more zones to pull from. Program is as good as it's going to get. remainingToMove = 0; break; } //If none of these tests trigger, the next loop should be able to run. Cache any contributions and begin next loop in this zone. //ejectedProgramCountCache = currentLoopEjectedProgramDelta; } } if (remainingToMove == 0) { break; } //Program has been optimized in zone. Clear all holdings. activeZone.ReservedArea[j][i] = reservedAreaRemaining; } #region forfeit procedure //Program has been optimized. Forfeit any remaining reserved area. //RhinoApp.WriteLine("---Procedure complete, forfeiting..."); int zoneCount = 0; foreach (ZonePackage zone in zm.Zones) { //RhinoApp.WriteLine("Zone number {0}: ", zoneCount.ToString()); zoneCount++; int priorityCount = 0; foreach (List <double> reservedAreas in zone.ReservedArea) { //RhinoApp.WriteLine("Priority level {0}: ", priorityCount.ToString()); priorityCount++; int remainingSuitors = 0; List <int> remainingSuitorIndices = new List <int>(); double availableToRedistribute = reservedAreas[i]; if (availableToRedistribute < 0) { reservedAreas[i] = 0; //RhinoApp.WriteLine("None available."); continue; } for (int c = 0; c < numPrograms; c++) { if (c != i && reservedAreas[c] != 0) { remainingSuitors++; remainingSuitorIndices.Add(c); } } if (remainingSuitors == 0) { reservedAreas[i] = 0; //RhinoApp.WriteLine("No one to distribute to."); continue; } double areaToDistribute = availableToRedistribute / remainingSuitors; //RhinoApp.WriteLine("Distributing {0} to {1} others.", areaToDistribute.ToString(), remainingSuitors.ToString()); foreach (int index in remainingSuitorIndices) { reservedAreas[index] = reservedAreas[index] + areaToDistribute; } reservedAreas[i] = 0; } } #endregion } #endregion }
/// <summary> /// Extracts indices of programs each lane was "designed for" during Update.Room.LaneConfiguration. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> /// <param name="i"></param> public static void ProgramHint(RoomPackage room, ZonePackage zone, int i) { room.ProgramHint = i >= zone.LanePackages.Count ? new List <int>() : zone.LanePackages[i].Programs; }
public static void Adjacencies(ZonePackage zp) { zp.IsCoreAdjacent = (zp.EdgeCurves.CoreAdjacent.Count > 0) ? true : false; zp.IsPerimeterAdjacent = (zp.EdgeCurves.PerimeterAdjacent.Count > 0) ? true : false; zp.IsIsland = (!zp.IsCoreAdjacent && !zp.IsPerimeterAdjacent) ? true : false; }
public static List <Brep> Rectangularize(ZonePackage zone) { var rectangularizedZones = new List <Brep>(); if (Utils.GetLongestCurve(new List <Curve>(Curve.JoinCurves(zone.Region.Curves3D))).SpanCount <= 4) { rectangularizedZones.Add(zone.Region); return(rectangularizedZones); } var boundsRect = new CurveBounds(new Rectangle3d(Plane.WorldXY, zone.Region.GetBoundingBox(Plane.WorldXY).Max, zone.Region.GetBoundingBox(Plane.WorldXY).Min).ToNurbsCurve()); var rectRangeX = boundsRect.RangeX; var rectRangeY = boundsRect.RangeY; var proportion = rectRangeX > rectRangeY ? rectRangeX / rectRangeY : rectRangeY / rectRangeX; if (boundsRect.Area < 2.5 * zone.BaseArea && proportion < 2) { rectangularizedZones.Add(zone.Region); return(rectangularizedZones); } var allRegionPerimeters = new List <Curve>(Curve.JoinCurves(zone.Region.Curves3D)); var regionBoundary = Utils.GetLongestCurve(allRegionPerimeters).Simplify(CurveSimplifyOptions.All, 0.1, 0.1); var otherPerimeters = new List <Curve>(); foreach (Curve curve in allRegionPerimeters) { if (Utils.EqualWithinTolerance(regionBoundary.GetLength(), curve.GetLength(), 1) == false) { otherPerimeters.Add(curve.Simplify(CurveSimplifyOptions.All, 0.1, 0.1)); } } Curve primaryCirculationEdge = Select.PrimaryCirculationEdge(zone); var splitters = new List <Curve>(); //Generate splitting curves based on discontinuities in exterior perimeter curve of zone. for (int i = 0; i <= regionBoundary.SpanCount; i++) { var activePoint = Point3d.Unset; if (i == regionBoundary.SpanCount) { activePoint = regionBoundary.PointAt(regionBoundary.SpanDomain(regionBoundary.SpanCount - 1).Max); } else { activePoint = regionBoundary.PointAt(regionBoundary.SpanDomain(i).Min); } if (Confirm.PointIsCornerPoint(activePoint, zone.Region)) { //Corner points generate undesirable splitting geometry. continue; } primaryCirculationEdge.ClosestPoint(activePoint, out double t); var pointOnCirculationEdge = primaryCirculationEdge.PointAt(t); if (activePoint.DistanceTo(pointOnCirculationEdge) < 0.1) { //Active point is coincident with circulation edge and is unusable. continue; } splitters.Add(new LineCurve(activePoint, pointOnCirculationEdge)); } //Generate splitting curves based on an interior exemptions, if they exist. if (otherPerimeters.Count > 0) { foreach (Curve perimeter in otherPerimeters) { var perimeterRegion = Brep.CreatePlanarBreps(perimeter)[0]; var activePoint = Point3d.Unset; for (int i = 0; i < perimeter.SpanCount; i++) { activePoint = perimeter.PointAt(perimeter.SpanDomain(i).Min); if (!Confirm.PointIsCornerPoint(activePoint, perimeterRegion)) { //For interior exemptions, corner points are desirable. continue; } primaryCirculationEdge.ClosestPoint(activePoint, out double t); var pointOnCirculationEdge = primaryCirculationEdge.PointAt(t); if (activePoint.DistanceTo(pointOnCirculationEdge) < 0.1) { //Active point is coincident with circulation edge and is unusable. continue; } splitters.Add(new LineCurve(activePoint, pointOnCirculationEdge)); } } } //Extend splitters to guarantee they traverse region boundary. for (int i = 0; i < splitters.Count; i++) { var extendedSplitter = Curves.ExtendToBounds(regionBoundary, splitters[i]); splitters[i] = extendedSplitter; } //Split region by all splitter curves. var roomRegions = Breps.SplitByCurves(zone.Region, splitters); return(roomRegions); }
/// <summary> /// Slices each zone into rectangular "lanes" based on dimensions of program targets. /// </summary> /// <param name="region"></param> /// <param name="zone"></param> /// <param name="pm"></param> public static void LaneConfiguration(Brep region, ZonePackage zone, ProgramManifest pm) { var zoneTargets = new List <int>(zone.ProgramTargets); var totalProjectedFill = new List <int>(); foreach (int target in zoneTargets) { totalProjectedFill.Add(0); } var regionInfo = new CurveBounds(Utils.GetBoundingBoxCurve(region)); var splitterCurves = new List <Curve>(); var sliceDirectionIsVertical = Confirm.RegionProportionIsVertical(region); var startVal = sliceDirectionIsVertical ? regionInfo.YMin : regionInfo.XMin; var maxVal = sliceDirectionIsVertical ? regionInfo.YMax : regionInfo.XMax; var activeSliceVal = startVal; var allLanePackages = new List <LanePackage>(); //Preflight checks. var targets = Confirm.Zone.TargetFulfilled(totalProjectedFill, zone.ProgramTargets); var inbounds = activeSliceVal < maxVal; //RhinoApp.WriteLine("Targets fulfilled: {0} | In bounds: {1}", targets, inbounds); while (!Confirm.Zone.TargetFulfilled(totalProjectedFill, zone.ProgramTargets) && activeSliceVal < maxVal) { //Slice lane based on remaining program. LanePackage lp = Select.NextLanePayload(zone, pm, totalProjectedFill, activeSliceVal, maxVal); allLanePackages.Add(lp); //RhinoApp.WriteLine("{0} => {1}", activeSliceVal, lp.SlicePosition); activeSliceVal = lp.SlicePosition; var splitter = sliceDirectionIsVertical ? new LineCurve(new Point2d(regionInfo.XMin, activeSliceVal), new Point2d(regionInfo.XMax, activeSliceVal)) : new LineCurve(new Point2d(activeSliceVal, regionInfo.YMax), new Point2d(activeSliceVal, regionInfo.YMin)); splitterCurves.Add(splitter); Update.Room.ProjectedFill(lp, region, splitterCurves, pm); for (int i = 0; i < lp.ProjectedFill.Count; i++) { totalProjectedFill[i] = totalProjectedFill[i] + lp.ProjectedFill[i]; } } zone.LanePackages = allLanePackages; var zoneSlices = Breps.SplitByCurves(region, splitterCurves); //RhinoApp.WriteLine("{0} splitter curves & {1} rooms.", splitterCurves.Count.ToString(), zoneSlices.Count); foreach (Brep lane in zoneSlices) { zone.Rooms.Add(new RoomPackage(lane, pm.ProgramPackages.Count)); } }
/// <summary> /// Populate room by marching along perimeter. Generate interior islands as necessary. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> /// <param name="pm"></param> public static void ByPerimeter(RoomPackage room, ZonePackage zone, ProgramManifest pm) { //TODO: Write this routine. Must solve lane generation problems for curvilinear zones first. }
public static void EdgeClassification(ZonePackage zp, EdgeCurves ec) { zp.EdgeCurves = ec; }
/// <summary> /// Populates room in rows along its Y axis. Packs along the left (-X) edge until passing the room's midpoint, then packs along right edge until full. /// </summary> /// <param name="room"></param> /// <param name="zone"></param> /// <param name="pm"></param> public static void ByMostRows(RoomPackage room, ZonePackage zone, ProgramManifest pm) { var lexFull = false; var rexFull = false; var openZones = !lexFull || !rexFull; var anchor = Point3d.Unset; //Parent population method. while (room.MaxPlacement.Select(x => x > 0).Any() && openZones) { //Iterate through programs as staged. // (Chuck) Important: room.MaxPlacement aligns to program indices in room.FillOrder. // These DO NOT align to pm.ProgramPackages, and often don't even contain all programs. // To get data for the active program from its ProgramPackage, or to use a list that aligns with it, reference with index at room.FillOrder[i]. for (int i = 0; i < room.MaxPlacement.Count; i++) { var activeProgram = pm.ProgramPackages[room.FillOrder[i]]; var activeProgramIndex = room.FillOrder[i]; //Begin packing program. while (room.MaxPlacement[i] - room.NumProgramsPlaced[activeProgramIndex] > 0) { PlacementPackage candidate = null; //Start in left half. if (!lexFull) { candidate = Stage.Program.ForLeftLane(room, Stage.Program.InRoom(room, activeProgram)); //Move candidate to next position. anchor = room.NextAnchor == Point3d.Unset ? room.BaseAnchorLeft : room.NextAnchor; candidate.Bounds.Transform(Transform.Translation(anchor - room.BaseAnchorLeft)); //Verify that placement is valid and stage next anchor point accordingly. if (Collision.PlacementIsValid(room, candidate, pm)) { room.PlacedItems.Add(candidate); room.NumProgramsPlaced[activeProgramIndex]++; candidate.Dims = new CurveBounds(candidate.Bounds); candidate.Orientation.Origin.Transform(Transform.Translation(anchor - room.BaseAnchorLeft)); var buffer = 0.0; if (candidate.Program.AccessDirections == "1111") { buffer = 3; } room.PrevAnchor = anchor; room.NextAnchor = Stage.Room.NextAnchorRows(room, activeProgram, anchor, 1, buffer); } //Otherwise shift anchor slightly and retry. else { room.PrevAnchor = anchor; room.NextAnchor = Stage.Room.NextAnchorRows(room, activeProgram, anchor, 1, 0.1); } if (!Confirm.PointInRegion(room.Region, room.NextAnchor)) { if (i == room.MaxPlacement.Count - 1) { room.NextAnchor = Point3d.Unset; lexFull = true; break; } room.NextAnchor = Point3d.Unset; break; } continue; } if (!rexFull) { candidate = Stage.Program.ForRightLane(room, Stage.Program.InRoom(room, activeProgram)); //Move candidate to next position. anchor = room.NextAnchor == Point3d.Unset ? room.BaseAnchorRight : room.NextAnchor; candidate.Bounds.Transform(Transform.Translation(anchor - room.BaseAnchorRight)); //Verify that placement is valid and stage next anchor point accordingly. if (Collision.PlacementIsValid(room, candidate, pm)) { room.PlacedItems.Add(candidate); room.NumProgramsPlaced[activeProgramIndex]++; candidate.Dims = new CurveBounds(candidate.Bounds); candidate.Orientation.Origin.Transform(Transform.Translation(anchor - room.BaseAnchorRight)); var buffer = 0.0; if (candidate.Program.AccessDirections == "1111") { buffer = 3; } room.PrevAnchor = anchor; room.NextAnchor = Stage.Room.NextAnchorRows(room, activeProgram, anchor, 1, buffer); } //Otherwise shift anchor slightly and retry. else { room.PrevAnchor = anchor; room.NextAnchor = Stage.Room.NextAnchorRows(room, activeProgram, anchor, 1, 0.1); } if (!Confirm.PointInRegion(room.Region, room.NextAnchor)) { if (i == room.MaxPlacement.Count - 1) { room.NextAnchor = Point3d.Unset; rexFull = true; break; } room.NextAnchor = Point3d.Unset; break; } continue; } openZones = false; break; } //Room has been populated. } } }