protected override void SolveInstance(IGH_DataAccess DA) { int quota = 0; DA.GetData(0, ref quota); string access = "0000"; DA.GetData(1, ref access); bool isPrivate = false; DA.GetData(2, ref isPrivate); Curve boundary = null; DA.GetData(3, ref boundary); List <Curve> geometry = new List <Curve>(); DA.GetDataList(4, geometry); ProgramPackage ProgramItem = new ProgramPackage(quota, access, isPrivate, boundary, geometry); DA.SetData(0, ProgramItem); }
/// <summary> /// Stages program in center of room. Distorts plane alignment, so only useful for debugging. /// </summary> /// <param name="room"></param> /// <param name="program"></param> /// <returns></returns> public static PlacementPackage CenteredInRoom(RoomPackage room, ProgramPackage program) { var roomPlane = room.OrientationPlane; var newBounds = new Rectangle3d(roomPlane, new Interval(program.Dims.Width / -2, program.Dims.Width / 2), new Interval(program.Dims.Height / -2, program.Dims.Height / 2)).ToNurbsCurve(); return(new PlacementPackage(program, roomPlane, newBounds)); }
/// <summary> /// Stages program with its base plane location and orientation aligned to room's. /// </summary> /// <param name="room"></param> /// <param name="program"></param> /// <returns></returns> public static PlacementPackage InRoom(RoomPackage room, ProgramPackage program) { var roomPlane = new Plane(room.OrientationPlane); var newBounds = new Rectangle3d(roomPlane, new Interval(0, program.Dims.Width), new Interval(0, program.Dims.Height * -1)).ToNurbsCurve(); return(new PlacementPackage(program, roomPlane, newBounds)); }
public void NullInput_IsValid() { int quota = 0; string access = "1000"; bool priv = false; Curve boundary = CurvesFactory.RectangleCWH(Point3d.Origin, 1, 1); List <Curve> geometry = new List <Curve>(); ProgramPackage TestProgramItem = new ProgramPackage(quota, access, priv, boundary, geometry); Assert.IsNotNull(TestProgramItem); }
protected override void SolveInstance(IGH_DataAccess DA) { ProgramPackage program = null; if (!DA.GetData(0, ref program)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Unable to read program input."); return; } DA.SetData(0, program.Distribution); DA.SetData(1, program.OccupationBoundary); DA.SetDataList(2, program.DrawingGeometry); DA.SetData(3, program.Quota); }
public static Point3d NextAnchorRows(RoomPackage room, ProgramPackage program, Point3d anchor, double multiplier, double buffer) { var step = 0.0; if (Confirm.VectorProportionIsVertical(room.OrientationPlane.YAxis)) { step = room.OrientationPlane.YAxis.Y > 0 ? program.Dims.Width * -1 : program.Dims.Width; step = (step * multiplier) + buffer; return(new Point3d(anchor.X, anchor.Y + step, 0)); } else { step = room.OrientationPlane.YAxis.X > 0 ? program.Dims.Width * -1 : program.Dims.Width; step = (step * multiplier) + buffer; return(new Point3d(anchor.X + step, anchor.Y, 0)); } }
/// <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 }