Ejemplo n.º 1
0
        public static bool ApplyLockRoom(AdvicePackage advice, ZoneManifest zm, ProgramManifest pm)
        {
            var bounds = advice.Bounds;

            foreach (ZonePackage zone in zm.Zones)
            {
                foreach (RoomPackage room in zone.Rooms)
                {
                    foreach (PlacementPackage item in room.PlacedItems)
                    {
                        PointContainment pc = bounds.Contains(item.Dims.Center);

                        if (pc == PointContainment.Inside)
                        {
                            if (advice.CapturedProgram == null)
                            {
                                advice.CapturedProgram = new List <PlacementPackage>();
                            }

                            advice.CapturedProgram.Add(item);

                            if (pm.ProgramPackages[item.Program.Priority].Quota > 0)
                            {
                                pm.ProgramPackages[item.Program.Priority].Quota--;
                            }
                        }
                    }
                }
            }

            zm.FloorPlan.ExemptionProfiles.Add(advice.Bounds);

            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parent method for all population methods.
        /// </summary>
        /// <param name="zm"></param>
        /// <param name="pm"></param>
        public static void Solution(ZoneManifest zm, ProgramManifest pm)
        {
            for (int i = 0; i < zm.Zones.Count; i++)
            {
                //Prepare zone for population.
                var activeZone = zm.Zones[i];
                activeZone.RemainingProgramTargets = new List <int>(activeZone.ProgramTargets);

                //TODO: Figure out why population order is running opposite to slicing order so I don't have to do this.
                activeZone.Rooms.Reverse();

                //Loop through and populate every room in active zone.
                for (int j = 0; j < zm.Zones[i].Rooms.Count; j++)
                {
                    var activeRoom = activeZone.Rooms[j];
                    Stage.Terrain.Room(activeRoom, activeZone, pm);
                }

                //If zone fails to meet its predefined program targets, pass remainder on to next zone.
                if (i != zm.Zones.Count - 1)
                {
                    Update.Zone.PassUnfulfilledTargets(activeZone, zm.Zones[i + 1], pm);
                }

                Draw.InputGeometry(activeZone);
            }

            Evaluate.QuotasMet(zm, pm);
        }
Ejemplo n.º 3
0
        public static void Popularity(ZoneManifest zm, ProgramManifest pm)
        {
            int zoneCount = zm.Zones.Count;

            for (int i = 0; i < zoneCount; i++)
            {
                List <int> popularity = new List <int>(zoneCount);

                for (int j = 0; j < zoneCount; j++)
                {
                    int wantedCounter = 0;

                    foreach (ProgramPackage program in pm.ProgramPackages)
                    {
                        if (program.ZonePreference[j] == i)
                        {
                            wantedCounter++;
                        }
                    }

                    popularity.Add(wantedCounter);
                }

                zm.Zones[i].Popularity = popularity;
            }
        }
Ejemplo n.º 4
0
        public static void ApplyAdvice(AdvicePackage advice, ZoneManifest zm, ProgramManifest pm)
        {
            var adviceDictionary = new Dictionary <string, Func <AdvicePackage, ZoneManifest, ProgramManifest, bool> >
            {
                { "Lock", ApplyLockRoom }
            };

            adviceDictionary[advice.Type](advice, zm, pm);
        }
Ejemplo n.º 5
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            TestFitPackage tf = null;

            DA.GetData(0, ref tf);

            bool active = false;

            DA.GetData(1, ref active);

            if (!active)
            {
                return;
            }

            //Parse FloorPlanPackage for main working area(s).
            List <Brep> baseFloorRegions = Identify.FloorPlateRegions(tf);

            //Categorize circulation segments into "main" and "option" types.
            CirculationPackage circ = Identify.CirculationTypes(tf);

            //Sanitization: generate and remove all obstacles from workable space. (Circulation, Structure, etc.)
            List <Brep> validFloorRegions = Identify.AvailableFloorSpace(baseFloorRegions, tf, circ);

            //First-pass subdivision: coarse division based on proximity and proportion.
            List <Brep> optimizedFloorRegions = Identify.OptimalFloorSpaceConfiguration(validFloorRegions, tf);

            //Parse ProgramPackage(s) and format information/relationships into manifest.
            ProgramManifest pm = Identify.ProgramManifest(tf);

            //Assign program targets to each zone, based on priority + affinity, and subdivide to rooms.
            ZoneManifest zm = Identify.ZoneManifest(optimizedFloorRegions, pm, tf);

            //Populate zones and solve test fit.
            Terrain.Solution(zm, pm);

            List <string> debugText = new List <string>();

            foreach (ZonePackage zone in zm.Zones)
            {
                string output = null;

                foreach (int target in zone.ProgramTargets)
                {
                    output = output + target + " ";
                }

                debugText.Add(output);
            }

            DA.SetData(0, pm);
            DA.SetData(1, zm);
            DA.SetDataList(2, debugText);
        }
Ejemplo n.º 6
0
        public static void ProgramPriority(ZoneManifest zm, ProgramManifest pm)
        {
            int zoneCount    = zm.Zones.Count;
            int programCount = pm.ProgramPackages.Count;

            for (int i = 0; i < zoneCount; i++)
            {
                List <int> programPriority = new List <int>();

                for (int j = 0; j < zoneCount; j++)
                {
                    //Skip if we know zone is unloved at this priority.
                    if (zm.Zones[i].Popularity[j] == 0)
                    {
                        continue;
                    }

                    List <ProgramPackage> suitors      = new List <ProgramPackage>();
                    List <int>            programIndex = new List <int>();

                    //Grab programs that want to be with this zone, in order of preference.
                    for (int k = 0; k < programCount; k++)
                    {
                        if (pm.ProgramPackages[k].ZonePreference[j] == i)
                        {
                            suitors.Add(pm.ProgramPackages[k]);
                            programIndex.Add(k);
                        }
                    }

                    //In the case of multiple suitors, tiebreak based on program priority.
                    if (suitors.Count == 1)
                    {
                        programPriority.Add(programIndex[0]);
                    }
                    else
                    {
                        for (int k = 0; k < programCount; k++)
                        {
                            for (int t = 0; t < suitors.Count; t++)
                            {
                                if (suitors[t].Priority == k)
                                {
                                    programPriority.Add(programIndex[t]);
                                }
                            }
                        }
                    }
                }

                zm.Zones[i].ProgramPriority = programPriority;
            }
        }
Ejemplo n.º 7
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ZoneManifest zm = null;

            if (!DA.GetData(0, ref zm))
            {
                return;
            }

            List <ZonePackage> zones = new List <ZonePackage>();

            List <Brep>   regions      = new List <Brep>();
            List <string> targets      = new List <string>();
            List <string> popularities = new List <string>();

            foreach (ZonePackage zone in zm.Zones)
            {
                zones.Add(zone);

                regions.Add(zone.Region);

                string targetsCache = null;

                foreach (int val in zone.ProgramTargets)
                {
                    targetsCache = targetsCache + val.ToString().PadLeft(3, '0') + " ";
                }

                targets.Add(targetsCache);

                string popularityCache = null;

                foreach (int val in zone.Popularity)
                {
                    popularityCache = popularityCache + val.ToString().PadLeft(2, '0') + " ";
                }

                popularities.Add(popularityCache);
            }

            DA.SetDataList(0, zones);
            DA.SetDataList(1, regions);
            DA.SetDataList(2, targets);
            DA.SetDataList(3, popularities);
            DA.SetDataList(4, zm.PlacementTotals);
        }
Ejemplo n.º 8
0
        public static void QuotasMet(ZoneManifest zm, ProgramManifest pm)
        {
            var programsPlaced = pm.ProgramPackages.Select(x => 0).ToList();

            foreach (ZonePackage zone in zm.Zones)
            {
                foreach (RoomPackage room in zone.Rooms)
                {
                    for (int i = 0; i < room.NumProgramsPlaced.Count; i++)
                    {
                        programsPlaced[i] = programsPlaced[i] + room.NumProgramsPlaced[i];
                    }
                }
            }

            zm.PlacementTotals = programsPlaced;

            //Utils.Debug.PrintList(ref programsPlaced);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        public static void ReservedArea(ZoneManifest zm, ProgramManifest pm)
        {
            int zoneCount    = zm.Zones.Count;
            int programCount = pm.ProgramPackages.Count;

            for (int i = 0; i < zoneCount; i++)
            {
                List <List <double> > reservedArea = new List <List <double> >();

                for (int j = 0; j < zoneCount; j++)
                {
                    List <double> reservedAtThisPriority = new List <double>();

                    for (int k = 0; k < programCount; k++)
                    {
                        if (zm.Zones[i].Popularity[j] == 0)
                        {
                            reservedAtThisPriority.Add(0);
                        }
                        else
                        {
                            double portion = zm.Zones[i].BaseArea / zm.Zones[i].Popularity[j];

                            if (pm.ProgramPackages[k].ZonePreference[j] == i)
                            {
                                reservedAtThisPriority.Add(portion);
                            }
                            else
                            {
                                reservedAtThisPriority.Add(0);
                            }
                        }
                    }

                    reservedArea.Add(reservedAtThisPriority);
                }

                zm.Zones[i].ReservedArea = reservedArea;
            }
        }
Ejemplo n.º 11
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ProgramManifest pmOld = null;

            if (!DA.GetData(0, ref pmOld))
            {
                return;
            }

            var pm = Utils.DeepClone(pmOld);

            ZoneManifest zmOld = null;

            if (!DA.GetData(1, ref zmOld))
            {
                return;
            }

            var zm = Utils.DeepClone(zmOld);

            var allAdvice = new List <AdvicePackage>();

            DA.GetDataList(2, allAdvice);

            if (pm.AllAdvice != null)
            {
                allAdvice.AddRange(pm.AllAdvice);
            }

            foreach (AdvicePackage advice in allAdvice)
            {
                Logic.Update.Iteration.ApplyAdvice(advice, zm, pm);
            }

            var tf = new TestFitPackage(zm.FloorPlan, pm.ProgramPackages, allAdvice);

            DA.SetData(0, tf);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Breaks initial zones into generally rectangular pieces.
        /// Subdivides those pieces into rooms based on program sizes and quotas.
        /// </summary>
        /// <param name="zm"></param>
        /// <param name="pm"></param>
        public static void RoomConfiguration(ZoneManifest zm, ProgramManifest pm)
        {
            foreach (ZonePackage zone in zm.Zones)
            {
                zone.Rooms = new List <RoomPackage>();

                List <Brep> rectangularizedZoneRegions = Breps.Rectangularize(zone);

                //Slice rectangularized zone regions into room lanes.
                foreach (Brep region in rectangularizedZoneRegions)
                {
                    Update.Room.LaneConfiguration(region, zone, pm);
                }

                //Perform final measurements and prepare rooms for population.
                for (int i = 0; i < zone.Rooms.Count; i++)
                {
                    var room = zone.Rooms[i];

                    Update.Room.Orientation(room, zone);
                    Update.Room.ProgramHint(room, zone, i);
                }
            }
        }
Ejemplo n.º 13
0
        public static void ZonePreference(ProgramManifest pm, ZoneManifest zm)
        {
            foreach (ProgramPackage program in pm.ProgramPackages)
            {
                int zoneCount = zm.Zones.Count;

                List <int> zonePreference = new List <int>(zoneCount);

                //Add most preferred zones first.
                for (int i = 0; i < zoneCount; i++)
                {
                    if (program.Affinity.Count == 0)
                    {
                        break;
                    }

                    foreach (int preferred in program.Affinity)
                    {
                        if (zm.Zones[i].AffinityType == preferred)
                        {
                            zonePreference.Add(i);
                        }
                    }
                }

                //Then add neutral zones.
                for (int i = 0; i < zoneCount; i++)
                {
                    if (zonePreference.Contains(i) == false)
                    {
                        if (program.Enmity.Count == 0)
                        {
                            zonePreference.Add(i);
                        }
                        else
                        {
                            foreach (int dispreferred in program.Enmity)
                            {
                                if (zm.Zones[i].AffinityType != dispreferred)
                                {
                                    zonePreference.Add(i);
                                }
                            }
                        }
                    }
                }

                //Last, add dispreferred zones, making sure least preferred is last.
                for (int i = 0; i < zoneCount; i++)
                {
                    for (int j = program.Enmity.Count - 1; j >= 0; j--)
                    {
                        if (program.Enmity[j] == zm.Zones[i].AffinityType)
                        {
                            zonePreference.Add(i);
                        }
                    }
                }

                program.ZonePreference = zonePreference;
            }
        }
Ejemplo n.º 14
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
        }