Example #1
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;
        }
Example #2
0
        public static void InputGeometry(ZonePackage zone)
        {
            foreach (RoomPackage room in zone.Rooms)
            {
                foreach (PlacementPackage item in room.PlacedItems)
                {
                    var activeProgram   = item.Program;
                    var drawingGeometry = new List <Curve>();

                    foreach (Curve curve in activeProgram.DrawingGeometry)
                    {
                        drawingGeometry.Add(new NurbsCurve(curve.ToNurbsCurve()));
                    }

                    foreach (Curve geo in drawingGeometry)
                    {
                        geo.Transform(Transform.Translation(new Vector3d(item.Dims.Center - activeProgram.Dims.Center)));

                        geo.Transform(Transform.Rotation(Vector3d.YAxis, room.OrientationPlane.XAxis, item.Dims.Center));

                        //var testVector = new Vector3d(item.Dims.Center - room.Dims.Center);

                        if (room.Dims.Height > room.Dims.Width ? room.OrientationPlane.XAxis.X > 0 == item.Orientation.YAxis.X > 0 : room.OrientationPlane.XAxis.Y > 0 == item.Orientation.YAxis.Y > 0)
                        {
                            geo.Transform(Transform.Mirror(new Plane(item.Dims.Center, room.OrientationPlane.YAxis, Vector3d.ZAxis)));
                        }
                        else
                        {
                        }
                    }

                    item.DrawingGeometry = drawingGeometry;
                }
            }
        }
Example #3
0
 public static void RemainingProgramTargets(ZonePackage zone, RoomPackage room)
 {
     for (int i = 0; i < room.NumProgramsPlaced.Count; i++)
     {
         zone.RemainingProgramTargets[i] = zone.RemainingProgramTargets[i] - room.NumProgramsPlaced[i];
     }
 }
Example #4
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;
                }
            }
        }
Example #5
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;
            }
        }
Example #6
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;
        }
Example #7
0
 public static void AffinityType(ZonePackage zp)
 {
     if (zp.IsCoreAdjacent)
     {
         zp.AffinityType = 1;
     }
     else if (zp.IsPerimeterAdjacent)
     {
         zp.AffinityType = 2;
     }
     else
     {
         zp.AffinityType = 3;
     }
 }
Example #8
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);
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ZonePackage zp = null;

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

            var roomRegions          = new List <Brep>();
            var placedBounds         = new List <Curve>();
            var roomPlanes           = new List <Plane>();
            var anchorPoints         = new List <Point3d>();
            var drawingGeometry      = new List <Curve>();
            var drawingGeometryCount = new List <int>();
            var roomCenter           = new List <Point3d>();

            foreach (RoomPackage room in zp.Rooms)
            {
                roomRegions.Add(room.Region);
                roomPlanes.Add(room.OrientationPlane);
                anchorPoints.Add(room.PrevAnchor);

                foreach (PlacementPackage placedItem in room.PlacedItems)
                {
                    placedBounds.Add(placedItem.Bounds);
                    roomCenter.Add(placedItem.Dims.Center);

                    drawingGeometryCount.Add(placedItem.DrawingGeometry.Count);

                    foreach (Curve geo in placedItem.DrawingGeometry)
                    {
                        drawingGeometry.Add(geo);
                    }
                }
            }

            DA.SetDataList(0, roomRegions);
            DA.SetDataList(1, placedBounds);
            DA.SetDataList(2, roomPlanes);
            DA.SetDataList(3, anchorPoints);
            DA.SetDataList(4, drawingGeometry);
            DA.SetDataList(5, drawingGeometryCount);
            DA.SetDataList(6, roomCenter);
        }
Example #10
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);
        }
Example #11
0
        /// <summary>
        /// Generates a base plane for each room with +Y pointing towards circulation.
        /// Necessary to normalize placement of program across highly varied room geometry.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="zone"></param>
        public static void Orientation(RoomPackage room, ZonePackage zone)
        {
            var circEdge  = Select.PrimaryCirculationEdge(zone);
            var basePoint = Utils.GetRegionCenter(room.Region);

            circEdge.ClosestPoint(basePoint, out double t);
            var circEdgePoint = circEdge.PointAt(t);

            var yDirVector = new Vector3d(circEdgePoint - basePoint);

            var yTestVal = Confirm.VectorProportionIsVertical(yDirVector) ? yDirVector.Y : yDirVector.X;

            var yAxis = Confirm.VectorProportionIsVertical(yDirVector) ? new Vector3d(0, yTestVal, 0) : new Vector3d(yTestVal, 0, 0);
            var xAxis = new Vector3d(yAxis);

            xAxis.Rotate(Math.PI / 2, Vector3d.ZAxis);

            var roomOrientationPlane = new Plane(basePoint, xAxis, yAxis);

            room.OrientationPlane = roomOrientationPlane;
        }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            ZonePackage zp = null;

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

            DA.SetData(0, zp.Region);

            EdgeCurves edges = zp.EdgeCurves;

            DA.SetDataList(2, edges.PerimeterAdjacent);
            DA.SetDataList(3, edges.CirculationAdjacent);
            DA.SetDataList(4, edges.CoreAdjacent);
            DA.SetDataList(5, edges.ExemptionAdjacent);
            DA.SetDataList(6, edges.StructureAdjacent);
            DA.SetDataList(7, edges.ZoneAdjacent);

            DA.SetDataList(9, zp.ProgramTargets);
        }
Example #13
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
        }
Example #14
0
 /// <summary>
 /// Extracts indices of programs each lane was "designed for" during Update.Room.LaneConfiguration.
 /// </summary>
 /// <param name="room"></param>
 /// <param name="zone"></param>
 /// <param name="i"></param>
 public static void ProgramHint(RoomPackage room, ZonePackage zone, int i)
 {
     room.ProgramHint = i >= zone.LanePackages.Count ? new List <int>() : zone.LanePackages[i].Programs;
 }
Example #15
0
 public static void Adjacencies(ZonePackage zp)
 {
     zp.IsCoreAdjacent      = (zp.EdgeCurves.CoreAdjacent.Count > 0) ? true : false;
     zp.IsPerimeterAdjacent = (zp.EdgeCurves.PerimeterAdjacent.Count > 0) ? true : false;
     zp.IsIsland            = (!zp.IsCoreAdjacent && !zp.IsPerimeterAdjacent) ? true : false;
 }
Example #16
0
        public static List <Brep> Rectangularize(ZonePackage zone)
        {
            var rectangularizedZones = new List <Brep>();

            if (Utils.GetLongestCurve(new List <Curve>(Curve.JoinCurves(zone.Region.Curves3D))).SpanCount <= 4)
            {
                rectangularizedZones.Add(zone.Region);
                return(rectangularizedZones);
            }

            var boundsRect = new CurveBounds(new Rectangle3d(Plane.WorldXY, zone.Region.GetBoundingBox(Plane.WorldXY).Max, zone.Region.GetBoundingBox(Plane.WorldXY).Min).ToNurbsCurve());
            var rectRangeX = boundsRect.RangeX;
            var rectRangeY = boundsRect.RangeY;

            var proportion = rectRangeX > rectRangeY ? rectRangeX / rectRangeY : rectRangeY / rectRangeX;

            if (boundsRect.Area < 2.5 * zone.BaseArea && proportion < 2)
            {
                rectangularizedZones.Add(zone.Region);
                return(rectangularizedZones);
            }

            var allRegionPerimeters = new List <Curve>(Curve.JoinCurves(zone.Region.Curves3D));

            var regionBoundary  = Utils.GetLongestCurve(allRegionPerimeters).Simplify(CurveSimplifyOptions.All, 0.1, 0.1);
            var otherPerimeters = new List <Curve>();

            foreach (Curve curve in allRegionPerimeters)
            {
                if (Utils.EqualWithinTolerance(regionBoundary.GetLength(), curve.GetLength(), 1) == false)
                {
                    otherPerimeters.Add(curve.Simplify(CurveSimplifyOptions.All, 0.1, 0.1));
                }
            }

            Curve primaryCirculationEdge = Select.PrimaryCirculationEdge(zone);

            var splitters = new List <Curve>();

            //Generate splitting curves based on discontinuities in exterior perimeter curve of zone.
            for (int i = 0; i <= regionBoundary.SpanCount; i++)
            {
                var activePoint = Point3d.Unset;

                if (i == regionBoundary.SpanCount)
                {
                    activePoint = regionBoundary.PointAt(regionBoundary.SpanDomain(regionBoundary.SpanCount - 1).Max);
                }
                else
                {
                    activePoint = regionBoundary.PointAt(regionBoundary.SpanDomain(i).Min);
                }

                if (Confirm.PointIsCornerPoint(activePoint, zone.Region))
                {
                    //Corner points generate undesirable splitting geometry.
                    continue;
                }

                primaryCirculationEdge.ClosestPoint(activePoint, out double t);
                var pointOnCirculationEdge = primaryCirculationEdge.PointAt(t);

                if (activePoint.DistanceTo(pointOnCirculationEdge) < 0.1)
                {
                    //Active point is coincident with circulation edge and is unusable.
                    continue;
                }

                splitters.Add(new LineCurve(activePoint, pointOnCirculationEdge));
            }

            //Generate splitting curves based on an interior exemptions, if they exist.
            if (otherPerimeters.Count > 0)
            {
                foreach (Curve perimeter in otherPerimeters)
                {
                    var perimeterRegion = Brep.CreatePlanarBreps(perimeter)[0];
                    var activePoint     = Point3d.Unset;

                    for (int i = 0; i < perimeter.SpanCount; i++)
                    {
                        activePoint = perimeter.PointAt(perimeter.SpanDomain(i).Min);

                        if (!Confirm.PointIsCornerPoint(activePoint, perimeterRegion))
                        {
                            //For interior exemptions, corner points are desirable.
                            continue;
                        }

                        primaryCirculationEdge.ClosestPoint(activePoint, out double t);
                        var pointOnCirculationEdge = primaryCirculationEdge.PointAt(t);

                        if (activePoint.DistanceTo(pointOnCirculationEdge) < 0.1)
                        {
                            //Active point is coincident with circulation edge and is unusable.
                            continue;
                        }

                        splitters.Add(new LineCurve(activePoint, pointOnCirculationEdge));
                    }
                }
            }

            //Extend splitters to guarantee they traverse region boundary.
            for (int i = 0; i < splitters.Count; i++)
            {
                var extendedSplitter = Curves.ExtendToBounds(regionBoundary, splitters[i]);

                splitters[i] = extendedSplitter;
            }

            //Split region by all splitter curves.
            var roomRegions = Breps.SplitByCurves(zone.Region, splitters);

            return(roomRegions);
        }
Example #17
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));
            }
        }
Example #18
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.
 }
Example #19
0
 public static void EdgeClassification(ZonePackage zp, EdgeCurves ec)
 {
     zp.EdgeCurves = ec;
 }
Example #20
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.
                }
            }
        }