Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        /// <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));
        }
Ejemplo n.º 3
0
        /// <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));
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 6
0
        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));
            }
        }
Ejemplo n.º 7
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
        }