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);
        }
Beispiel #2
0
        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;
        }
Beispiel #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;
            }
        }
Beispiel #4
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);
        }
        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);
        }
Beispiel #6
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);
        }
Beispiel #7
0
        /// <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;
            }
        }
Beispiel #8
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;
            }
        }
Beispiel #9
0
        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;
        }
Beispiel #10
0
        /// <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);
        }
Beispiel #11
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);
        }
Beispiel #12
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);
        }
Beispiel #13
0
        public static ProgramManifest ProgramManifest(TestFitPackage tf)
        {
            //Parse base statistics from floor areas.
            var approximateTotalArea = tf.FloorPlanPackage.BaseArea;

            //Perform measurements and confirmations.
            var isPossible     = Confirm.Program.RequestIsPossible(tf.ProgramPackages, approximateTotalArea);
            var maximizedCount = Confirm.Program.MaximizedCount(tf.ProgramPackages);

            Update.Program.Distribution(tf);
            Update.Program.Target(tf);
            Update.Program.Affinity(tf);
            Update.Program.Enmity(tf);
            Update.Program.Priority(tf);

            ProgramManifest pm = new ProgramManifest(tf.ProgramPackages, isPossible, maximizedCount);

            pm.AllAdvice = tf.AllAdvice;

            return(pm);
        }
Beispiel #14
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;
            }
        }
Beispiel #15
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);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ProgramManifest pm = null;

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

            DA.SetDataList(0, pm.ProgramPackages);
            DA.SetDataList(1, pm.AllAdvice);

            List <string> zonePreferences = new List <string>();
            List <double> distributions   = new List <double>();
            List <int>    priorities      = new List <int>();

            foreach (ProgramPackage program in pm.ProgramPackages)
            {
                string preferenceCache = null;

                foreach (int val in program.ZonePreference)
                {
                    preferenceCache = preferenceCache + val + " ";
                }

                zonePreferences.Add(preferenceCache);

                distributions.Add(program.Distribution);

                priorities.Add(program.Priority);
            }

            DA.SetDataList(2, zonePreferences);
            DA.SetDataList(3, distributions);
            DA.SetDataList(4, priorities);
        }
Beispiel #17
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);
                }
            }
        }
Beispiel #18
0
        /// <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;
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// Method responsible for estimating the effectiveness of each lane.
        /// Plan is to use this in the future to segment lanes if needed.
        /// </summary>
        /// <param name="lp"></param>
        /// <param name="region">Region for entire zone.</param>
        /// <param name="splitters">All currently determined splitters.</param>
        /// <param name="pm"></param>
        public static void ProjectedFill(LanePackage lp, Brep region, List <Curve> splitters, ProgramManifest pm)
        {
            //Determine approximate depth of lane.
            var depth = 0.0;

            if (splitters.Count == 1)
            {
                depth = Curves.TrimWithClosedCurve(Utils.GetRegionPerimeter(region), splitters[0]).GetLength();
            }
            else
            {
                var depthL = Curves.TrimWithClosedCurve(Utils.GetRegionPerimeter(region), splitters[splitters.Count - 2]).GetLength();
                var depthR = Curves.TrimWithClosedCurve(Utils.GetRegionPerimeter(region), splitters[splitters.Count - 1]).GetLength();

                depth = (depthL + depthR) / 2;
            }

            lp.Depth = depth;

            lp.ProjectedFill = new List <int>();

            foreach (ProgramPackage program in pm.ProgramPackages)
            {
                lp.ProjectedFill.Add(0);
            }

            for (int i = 0; i < lp.Programs.Count; i++)
            {
                var selectedProgramIndex = lp.Programs[i];
                var selectedProgram      = pm.ProgramPackages[selectedProgramIndex];
                var selectedProgramDims  = selectedProgram.Dims;

                var estimatedFill = Convert.ToInt32(Math.Floor(depth / selectedProgramDims.Width));

                if (selectedProgram.AccessDirections == "1000")
                {
                    estimatedFill = estimatedFill * 2;
                }

                lp.ProjectedFill[selectedProgramIndex] = estimatedFill;
            }
        }
Beispiel #20
0
        /// <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));
            }
        }
Beispiel #21
0
 /// <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.
 }
Beispiel #22
0
        /// <summary>
        /// Basic collision detection routine for single item placement.
        /// </summary>
        /// <param name="room">Room currently being populated.</param>
        /// <param name="candidate">PlacementPackaged being checked for fidelity.</param>
        /// <param name="pm"></param>
        /// <returns></returns>
        public static bool PlacementIsValid(RoomPackage room, PlacementPackage candidate, ProgramManifest pm)
        {
            //Verify placed item does not clash with previously placed items.
            foreach (PlacementPackage placedItem in room.PlacedItems)
            {
                if (Confirm.CurvesIntersect(placedItem.Bounds, candidate.Bounds, true))
                {
                    if (Confirm.CurvesIntersect(placedItem.Bounds, candidate.Bounds, false))
                    {
                        return(false);
                    }

                    CurveIntersections ccx = Intersection.CurveCurve(placedItem.Bounds, candidate.Bounds, 0.1, 0.1);

                    if (ccx.Count(x => x.IsOverlap) > 1)
                    {
                        return(false);
                    }
                }

                PointContainment insideCheck = placedItem.Bounds.Contains(candidate.Bounds.GetBoundingBox(Plane.WorldXY).Center);

                if (insideCheck == PointContainment.Inside || insideCheck == PointContainment.Coincident)
                {
                    return(false);
                }
            }

            //Verify item is completely within boundary of room.
            foreach (Curve edgeCurve in room.AllEdgeCurves)
            {
                if (Confirm.CurvesIntersect(candidate.Bounds, edgeCurve, false))
                {
                    return(false);
                }

                /*
                 * if (!Confirm.PointInRegion(room.Region, new CurveBounds(candidate.Bounds).Center))
                 * {
                 *  return false;
                 * }
                 */
            }

            //Verify program area is not larger than total room area.
            if (room.Region.GetArea() < pm.ProgramPackages[candidate.ProgramIndex].OccupationArea)
            {
                return(false);
            }

            return(true);
        }
Beispiel #23
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;
            }
        }
Beispiel #24
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
        }
Beispiel #25
0
        /// <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.
                }
            }
        }