public void TestBarelyFittingRectangle() {
      CygonRectanglePacker packer = new CygonRectanglePacker(128, 128);

      Point placement = packer.Pack(128, 128);

      Assert.AreEqual(new Point(0, 0), placement);
    }
Exemple #2
0
        /// <summary>
        /// This method adds the collection of views to the existing ViewSheet and packs them
        /// </summary>
        /// <param name="views"></param>
        private void InternalAddViewsToSheetView(IEnumerable <Autodesk.Revit.DB.View> views)
        {
            var sheet = InternalViewSheet;

            TransactionManager.Instance.EnsureInTransaction(Document);

            // (sic) from Dynamo Legacy
            var width  = sheet.Outline.Max.U - sheet.Outline.Min.U;
            var height = sheet.Outline.Max.V - sheet.Outline.Min.V;
            var packer = new CygonRectanglePacker(width, height);
            int count  = 0;

            foreach (var view in views)
            {
                var viewWidth  = view.Outline.Max.U - view.Outline.Min.U;
                var viewHeight = view.Outline.Max.V - view.Outline.Min.V;

                Autodesk.Revit.DB.UV placement = null;
                if (packer.TryPack(viewWidth, viewHeight, out placement))
                {
                    var dbViews = sheet.GetAllPlacedViews().Select(x => Document.GetElement(x)).
                                  OfType <Autodesk.Revit.DB.View>();
                    if (dbViews.Contains(view))
                    {
                        //move the view
                        //find the corresponding viewport
                        var enumerable =
                            DocumentManager.Instance.ElementsOfType <Autodesk.Revit.DB.Viewport>()
                            .Where(x => x.SheetId == sheet.Id && x.ViewId == view.Id).ToArray();

                        if (!enumerable.Any())
                        {
                            continue;
                        }

                        var viewport = enumerable.First();
                        viewport.SetBoxCenter(new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                    }
                    else
                    {
                        //place the view on the sheet
                        if (Autodesk.Revit.DB.Viewport.CanAddViewToSheet(Document, sheet.Id, view.Id))
                        {
                            var viewport = Autodesk.Revit.DB.Viewport.Create(Document, sheet.Id, view.Id,
                                                                             new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                        }
                    }
                }
                else
                {
                    throw new Exception(String.Format("View {0} could not be packed on the Sheet.  The sheet is {1} x {2} and the view to be added is {3} x {4}",
                                                      count, width, height, viewWidth, viewHeight));
                }

                count++;
            }

            TransactionManager.Instance.TransactionTaskDone();
        }
    public void TestTooLargeRectangle() {
      CygonRectanglePacker packer = new CygonRectanglePacker(128, 128);
      Point placement;

      bool result = packer.TryPack(129, 10, out placement);
      Assert.IsFalse(result);

      result = packer.TryPack(10, 129, out placement);
      Assert.IsFalse(result);
    }
Exemple #4
0
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (Children.Count != 0)
            {
                double top     = 0;
                double left    = 0;
                double width   = _tileWidth;
                double height  = _tileHeight;
                Size   spacing = _tileSpacing;
                bool   first   = true;
                var    crp     = new CygonRectanglePacker(finalSize.Width, finalSize.Height);

                var sizedElements = Children.OrderBy(child => child.DesiredSize.Area()).Reverse();
                foreach (UIElement element in sizedElements)
                {
                    if (element.Visibility != Visibility.Collapsed)
                    {
                        Point placement;
                        crp.TryPack(element.DesiredSize.Width, element.DesiredSize.Height, out placement);
                        Rect finalRect = new Rect(placement, element.DesiredSize);
                        element.Arrange(finalRect);
                        //element.SetValue(BoundsProperty, finalRect);
                        //if(first == false)
                        //{
                        //    left += spacing.Width;
                        //}
                        //ArrangeElement(element, new Rect(left, top, width, height));
                        //left = left + width;

                        //if((left + spacing.Width + width) > finalSize.Width)
                        //{
                        //    left = 0;
                        //    top += height + spacing.Height;
                        //    first = true;
                        //}
                        //else
                        //{
                        //    first = false;
                        //}
                    }
                    element.RenderTransform = new CompositeTransform()
                    {
                        Rotation = _rnd.Next(-5, 5),
                        CenterX  = element.DesiredSize.Width / 2,
                        CenterY  = element.DesiredSize.Height / 2,
                        //TranslateX = _rnd.Next((int)-(element.DesiredSize.Width / 10), (int)(element.DesiredSize.Width / 10)),
                        //TranslateY = _rnd.Next((int)-(element.DesiredSize.Height / 10), (int)(element.DesiredSize.Height / 10))
                    };
                }
            }

            return(finalSize);
        }
Exemple #5
0
        protected override Size ArrangeOverride(Size finalSize)
        {
            if(Children.Count != 0)
            {
                double top = 0;
                double left = 0;
                double width = _tileWidth;
                double height = _tileHeight;
                Size spacing = _tileSpacing;
                bool first = true;
                var crp = new CygonRectanglePacker(finalSize.Width, finalSize.Height);

                var sizedElements = Children.OrderBy(child => child.DesiredSize.Area()).Reverse();
                foreach(UIElement element in sizedElements)
                {
                    if(element.Visibility != Visibility.Collapsed)
                    {
                        Point placement;
                        crp.TryPack(element.DesiredSize.Width, element.DesiredSize.Height, out placement);
                        Rect finalRect = new Rect(placement, element.DesiredSize);
                        element.Arrange(finalRect);
                        //element.SetValue(BoundsProperty, finalRect);
                        //if(first == false)
                        //{
                        //    left += spacing.Width;
                        //}
                        //ArrangeElement(element, new Rect(left, top, width, height));
                        //left = left + width;

                        //if((left + spacing.Width + width) > finalSize.Width)
                        //{
                        //    left = 0;
                        //    top += height + spacing.Height;
                        //    first = true;
                        //}
                        //else
                        //{
                        //    first = false;
                        //}
                    }
                    element.RenderTransform = new CompositeTransform()
                                                  {
                                                      Rotation = _rnd.Next(-5, 5),
                                                      CenterX = element.DesiredSize.Width / 2,
                                                      CenterY = element.DesiredSize.Height / 2,
                                                      //TranslateX = _rnd.Next((int)-(element.DesiredSize.Width / 10), (int)(element.DesiredSize.Width / 10)),
                                                      //TranslateY = _rnd.Next((int)-(element.DesiredSize.Height / 10), (int)(element.DesiredSize.Height / 10))
                                                  };
                }
            }

            return finalSize;
        }
Exemple #6
0
        /*
         * Constructor for Engine class
         * @param side, an int of the lenght of a side. Only one as it works with a square
         * @param images, a collection of ImageInfo objects
         * Takes a collection of images and trys to fit them to a square,
         * increasing the size of square if they don't fit
         */
        public Engine(int side, IEnumerable <ImageInfo> images)
        {
            /// Collection of images not fitting
            List <ImageInfo> dontFit = new List <ImageInfo>();

            /// A check of whether all images are mapped
            bool check = true;

            while (check)
            {
                /// Initalise a packer object
                packer = new CygonRectanglePacker(side, side);

                /// Creating a Point object, for positioning images
                Point placement;

                /// Iterates through images, and trys to place it on the square
                foreach (ImageInfo image in images)
                {
                    /// Checking to see if it fits, else it is added to dontFit
                    if (packer.TryPack(image.Width, image.Height, out placement))
                    {
                        image.Position = placement;
                    }//end if
                    else
                    {
                        dontFit.Add(image);
                    } //end else
                }     // end foreach

                /// If images didn't fit, the loop will go again, otherwise it will finsih
                if (dontFit.Count == 0)
                {
                    check = false;
                }// end if
                else
                {
                    side = side * 2;
                    dontFit.Clear();
                }// end else
            }

            /// Initalising size with final square side lenght
            size = side;
        }
Exemple #7
0
        public static List <Point> ByCoordinateSystems(IEnumerable <BoundingBox> boundingBoxes, double width, double height, double gap)
        {
            var locs = new List <Point>();

            var packer = new CygonRectanglePacker(width, height);

            foreach (var bbox in boundingBoxes)
            {
                var packLocation = UV.ByCoordinates();
                var w            = bbox.MaxPoint.X - bbox.MinPoint.X + gap;
                var h            = bbox.MaxPoint.Y - bbox.MinPoint.Y + gap;
                if (packer.TryPack(w, h, out packLocation))
                {
                    locs.Add(Point.ByCoordinates(packLocation.U, packLocation.V, 0));
                }
            }

            return(locs);
        }
Exemple #8
0
        private bool TryPacking(IEnumerable <Window> windows, double scale)
        {
            var packer = new CygonRectanglePacker(Width, Height);

            foreach (var window in windows)
            {
                try
                {
                    var rect = window.Rectangle;

                    var ts = (rect.Width * rect.Height < 10000) ? 1.0 : scale; // show tiny windows at full size
                    window.TargetRectangle = new Rectangle(
                        packer.Pack((int)(rect.Width * ts), (int)(rect.Height * ts)),
                        new Size((int)(rect.Width * ts), (int)(rect.Height * ts)));
                }
                catch
                {
                    return(false);
                }
            }
            return(true);
        }
Exemple #9
0
		/// <summary>
		/// Collect information about the images and bin pack them using the chosen algorithm
		/// </summary>
		/// <param name="imagesInfo"></param>
		/// <param name="spriteSize"></param>
		public void GetImagesInfo(out List<SpriteImageItem> imagesInfo, out Size spriteSize, int padding)
		{
			imagesInfo = new List<SpriteImageItem>();

			// calculate initial sprite size to optimize process speed
			//	-> make sure that the widest and the tallest images fit
			//	-> make sure the resulting area is the same as the sum of all images area
			int maxW = 0;
			int maxH = 0;
			//int totalArea = 0;
			foreach (var file in GetFiles())
			{
				var image = Image.FromFile(file.FullName);
				imagesInfo.Add(new SpriteImageItem() { Image = image, Name = file.Name });

				if (image.Width > maxW)
					maxW = image.Width;
				if (image.Height > maxH)
					maxH = image.Height;

				//totalArea = image.Width * image.Height;
			}

			int finalW = 0;
			int finalH = 0;

			//int totalW = (int)Math.Ceiling((decimal)totalArea / 2);
			//int totalH = totalW;

			finalW = maxW;// maxW > totalW ? maxW : totalW;
			finalH = maxH; // maxH > totalH ? maxH : totalH;

			List<SpriteImageItem> unfitImagesInfo = new List<SpriteImageItem>();
			bool finished = false;
			while (!finished)
			{
				// start packing process
				RectanglePacker packer = null;
				switch (this.Options.BinPackingLevel)
				{
					case 1:		// faster and less compless algorithm
						packer = new SimpleRectanglePacker(finalW, finalH);
						break;
					case 2:		// still fast and much better packing algorithm
						packer = new CygonRectanglePacker(finalW, finalH);
						break;
					case 3:		// the best packing algorithm. Addicional processing time might not be noticeable
						packer = new ArevaloRectanglePacker(finalW, finalH);
						break;
					default:	// default
						packer = new CygonRectanglePacker(finalW, finalH);
						break;
				}

				//var usedArea = 0;
				foreach (var iInfo in imagesInfo)
				{
					// Find a place for a rectangle of size 30x20 in the packing area
					Point placement;
                    if (packer.TryPack(iInfo.Image.Width + padding, iInfo.Image.Height + padding, out placement))
					{
						iInfo.Position = placement;
						//usedArea += iInfo.Image.Width * iInfo.Image.Height;
					}
					else
					{
						unfitImagesInfo.Add(iInfo);
					}
				}

				if (unfitImagesInfo.Count == 0)
				{
					finished = true;
				}
				else
				{
					// add the diff between the used area and the remaining images area
					//var extraW = 0;
					//var extraH = 0;
					//foreach (var unfit in unfitImagesInfo)
					//{
					//    extraW += unfit.Image.Width;
					//    extraH += unfit.Image.Height;
					//}

					// after some tests the speed and result are quite the same as adding a few more pixels to the 
					//	sprite final size and run the whole process again
					finalW += 10;
					finalH += 10;

					unfitImagesInfo.Clear();
				}
			}

			spriteSize = new Size(finalW, finalH);
		}
Exemple #10
0
        public override Value Evaluate(FSharpList <Value> args)
        {
            var name   = ((Value.String)args[0]).Item;
            var number = ((Value.String)args[1]).Item;
            var tb     = (FamilySymbol)((Value.Container)args[2]).Item;

            if (!args[3].IsList)
            {
                throw new Exception("The views input must be a list of views.");
            }

            var views = ((Value.List)args[3]).Item;

            Autodesk.Revit.DB.ViewSheet sheet = null;

            if (this.Elements.Any())
            {
                if (dynUtils.TryGetElement(this.Elements[0], out sheet))
                {
                    if (sheet.Name != null && sheet.Name != name)
                    {
                        sheet.Name = name;
                    }
                    if (number != null && sheet.SheetNumber != number)
                    {
                        sheet.SheetNumber = number;
                    }
                }
                else
                {
                    //create a new view sheet
                    sheet             = Autodesk.Revit.DB.ViewSheet.Create(dynRevitSettings.Doc.Document, tb.Id);
                    sheet.Name        = name;
                    sheet.SheetNumber = number;
                    Elements[0]       = sheet.Id;
                }
            }
            else
            {
                sheet             = Autodesk.Revit.DB.ViewSheet.Create(dynRevitSettings.Doc.Document, tb.Id);
                sheet.Name        = name;
                sheet.SheetNumber = number;
                Elements.Add(sheet.Id);
            }

            //rearrange views on sheets
            //first clear the collection of views on the sheet
            //sheet.Views.Clear();

            var width  = sheet.Outline.Max.U - sheet.Outline.Min.U;
            var height = sheet.Outline.Max.V - sheet.Outline.Min.V;
            var packer = new CygonRectanglePacker(width, height);

            foreach (var val in views)
            {
                var view = (View)((Value.Container)val).Item;

                var viewWidth  = view.Outline.Max.U - view.Outline.Min.U;
                var viewHeight = view.Outline.Max.V - view.Outline.Min.V;

                UV placement = null;
                if (packer.TryPack(viewWidth, viewHeight, out placement))
                {
                    if (sheet.Views.Contains(view))
                    {
                        //move the view
                        //find the corresponding viewport
                        var collector = new FilteredElementCollector(dynRevitSettings.Doc.Document);
                        collector.OfClass(typeof(Viewport));
                        var found =
                            collector.ToElements()
                            .Cast <Viewport>()
                            .Where(x => x.SheetId == sheet.Id && x.ViewId == view.Id);

                        var enumerable = found as Viewport[] ?? found.ToArray();
                        if (!enumerable.Any())
                        {
                            continue;
                        }

                        var viewport = enumerable.First();
                        viewport.SetBoxCenter(new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                    }
                    else
                    {
                        //place the view on the sheet
                        if (Viewport.CanAddViewToSheet(dynRevitSettings.Doc.Document, sheet.Id, view.Id))
                        {
                            var viewport = Viewport.Create(dynRevitSettings.Doc.Document, sheet.Id, view.Id,
                                                           new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                        }
                    }
                }
                else
                {
                    throw new Exception("View could not be packed on sheet.");
                }
            }

            return(Value.NewContainer(sheet));
        }
Exemple #11
0
        public override Value Evaluate(FSharpList<Value> args)
        {
            var name = ((Value.String)args[0]).Item;
            var number = ((Value.String)args[1]).Item;
            var tb = (FamilySymbol)((Value.Container)args[2]).Item;

            if (!args[3].IsList)
                throw new Exception("The views input must be a list of views.");

            var views = ((Value.List)args[3]).Item;

            Autodesk.Revit.DB.ViewSheet sheet = null;

            if (this.Elements.Any())
            {
                if (dynUtils.TryGetElement(this.Elements[0], out sheet))
                {
                    if(sheet.Name != null && sheet.Name != name)
                        sheet.Name = name;
                    if(number != null && sheet.SheetNumber != number)
                        sheet.SheetNumber = number;
                }
                else
                {
                    //create a new view sheet
                    sheet = Autodesk.Revit.DB.ViewSheet.Create(dynRevitSettings.Doc.Document, tb.Id);
                    sheet.Name = name;
                    sheet.SheetNumber = number;
                    Elements[0] = sheet.Id;
                }
            }
            else
            {
                sheet = Autodesk.Revit.DB.ViewSheet.Create(dynRevitSettings.Doc.Document, tb.Id);
                sheet.Name = name;
                sheet.SheetNumber = number;
                Elements.Add(sheet.Id);
            }

            //rearrange views on sheets
            //first clear the collection of views on the sheet
            //sheet.Views.Clear();

            var width = sheet.Outline.Max.U - sheet.Outline.Min.U;
            var height = sheet.Outline.Max.V - sheet.Outline.Min.V;
            var packer = new CygonRectanglePacker(width, height);
            foreach (var val in views)
            {
                var view = (View)((Value.Container) val).Item;

                var viewWidth = view.Outline.Max.U - view.Outline.Min.U;
                var viewHeight = view.Outline.Max.V - view.Outline.Min.V;

                UV placement = null;
                if (packer.TryPack(viewWidth, viewHeight, out placement))
                {
                    if (sheet.Views.Contains(view))
                    {
                        //move the view
                        //find the corresponding viewport
                        var collector = new FilteredElementCollector(dynRevitSettings.Doc.Document);
                        collector.OfClass(typeof (Viewport));
                        var found =
                            collector.ToElements()
                                     .Cast<Viewport>()
                                     .Where(x => x.SheetId == sheet.Id && x.ViewId == view.Id);

                        var enumerable = found as Viewport[] ?? found.ToArray();
                        if (!enumerable.Any())
                            continue;

                        var viewport = enumerable.First();
                        viewport.SetBoxCenter(new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                    }
                    else
                    {
                        //place the view on the sheet
                        if (Viewport.CanAddViewToSheet(dynRevitSettings.Doc.Document, sheet.Id, view.Id))
                        {
                            var viewport = Viewport.Create(dynRevitSettings.Doc.Document, sheet.Id, view.Id,
                                                           new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                        }
                    }
                }
                else
                {
                    throw new Exception("View(s) do not fit on sheet.");
                }
            }

            return Value.NewContainer(sheet);
        }
Exemple #12
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (Children.Count == 0)
            {
                return(new Size(0, 0));
            }
            var crp = new CygonRectanglePacker(availableSize.Width, availableSize.Height);

            foreach (UIElement element in Children)
            {
                element.Measure(Infinite);
                Point placement;
                crp.TryPack(element.DesiredSize.Width, element.DesiredSize.Height, out placement);
            }

            //var sizedElements = Children.OrderBy(child => child.DesiredSize.Area()).Reverse.ToList();

            _tileWidth = Children
                         .Where(child => child.Visibility != Visibility.Collapsed)
                         .Max(child => child.DesiredSize.Width);

            _tileHeight = Children
                          .Where(child => child.Visibility != Visibility.Collapsed)
                          .Max(child => child.DesiredSize.Height);

            double top  = 0;
            double left = 0;

            bool first = true;

            foreach (UIElement element in Children)
            {
                if (element.Visibility != Visibility.Collapsed)
                {
                    if (first == false)
                    {
                        left += _tileSpacing.Width;
                    }

                    left += _tileWidth;

                    if ((left + _tileSpacing.Width + _tileWidth) > availableSize.Width)
                    {
                        left  = 0;
                        top  += _tileHeight + _tileSpacing.Height;
                        first = true;
                    }
                    else
                    {
                        first = false;
                    }
                }
            }

            if (left == 0)
            {
                return(new Size(availableSize.Width, top));
            }
            //return new Size(double.IsPositiveInfinity(availableSize.Width) ? _tileWidth*4 : availableSize.Width, top + _tileHeight);
            return(new Size(
                       double.IsPositiveInfinity(availableSize.Width) ? _tileWidth * 3.5 : availableSize.Width,
                       double.IsPositiveInfinity(availableSize.Height) ? _tileHeight * 2 : availableSize.Height));
        }
Exemple #13
0
        /// <summary>
        /// This method adds the collection of views to the existing ViewSheet and packs them 
        /// </summary>
        /// <param name="views"></param>
        private void InternalAddViewsToSheetView(IEnumerable<Autodesk.Revit.DB.View> views)
        {
            var sheet = InternalViewSheet;

            TransactionManager.Instance.EnsureInTransaction(Document);

            // (sic) from Dynamo Legacy
            var width = sheet.Outline.Max.U - sheet.Outline.Min.U;
            var height = sheet.Outline.Max.V - sheet.Outline.Min.V;
            var packer = new CygonRectanglePacker(width, height);
            int count = 0;

            foreach (var view in views)
            {
                var viewWidth = view.Outline.Max.U - view.Outline.Min.U;
                var viewHeight = view.Outline.Max.V - view.Outline.Min.V;

                Autodesk.Revit.DB.UV placement = null;
                if (packer.TryPack(viewWidth, viewHeight, out placement))
                {
                    if (sheet.Views.Contains(view))
                    {
                        //move the view
                        //find the corresponding viewport
                        var enumerable =
                            DocumentManager.Instance.ElementsOfType<Autodesk.Revit.DB.Viewport>()
                                .Where(x => x.SheetId == sheet.Id && x.ViewId == view.Id).ToArray();

                        if (!enumerable.Any())
                            continue;

                        var viewport = enumerable.First();
                        viewport.SetBoxCenter(new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                    }
                    else
                    {
                        //place the view on the sheet
                        if (Viewport.CanAddViewToSheet(Document, sheet.Id, view.Id))
                        {
                            var viewport = Viewport.Create(Document, sheet.Id, view.Id,
                                                           new XYZ(placement.U + viewWidth / 2, placement.V + viewHeight / 2, 0));
                        }
                    }
                }
                else
                {
                    throw new Exception( String.Format("View {0} could not be packed on the Sheet.  The sheet is {1} x {2} and the view to be added is {3} x {4}", 
                        count, width, height, viewWidth, viewHeight));
                }

                count++;
            }

            TransactionManager.Instance.TransactionTaskDone();
        }
 public void TestThrowOnTooLargeRectangle() {
   CygonRectanglePacker packer = new CygonRectanglePacker(128, 128);
   Assert.Throws<OutOfSpaceException>(
     delegate() { packer.Pack(129, 129); }
   );
 }
Exemple #15
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if(Children.Count == 0)
            {
                return new Size(0, 0);
            }
            var crp = new CygonRectanglePacker(availableSize.Width, availableSize.Height);

            foreach(UIElement element in Children)
            {
                element.Measure(Infinite);
                Point placement;
                crp.TryPack(element.DesiredSize.Width, element.DesiredSize.Height, out placement);
            }

            //var sizedElements = Children.OrderBy(child => child.DesiredSize.Area()).Reverse.ToList();

            _tileWidth = Children
                .Where(child => child.Visibility != Visibility.Collapsed)
                .Max(child => child.DesiredSize.Width);

            _tileHeight = Children
                .Where(child => child.Visibility != Visibility.Collapsed)
                .Max(child => child.DesiredSize.Height);

            double top = 0;
            double left = 0;

            bool first = true;
            foreach(UIElement element in Children)
            {
                if(element.Visibility != Visibility.Collapsed)
                {
                    if(first == false)
                    {
                        left += _tileSpacing.Width;
                    }

                    left += _tileWidth;

                    if((left + _tileSpacing.Width + _tileWidth) > availableSize.Width)
                    {
                        left = 0;
                        top += _tileHeight + _tileSpacing.Height;
                        first = true;
                    }
                    else
                    {
                        first = false;
                    }
                }
            }

            if(left == 0)
            {
                return new Size(availableSize.Width, top);
            }
            //return new Size(double.IsPositiveInfinity(availableSize.Width) ? _tileWidth*4 : availableSize.Width, top + _tileHeight);
            return new Size(
                double.IsPositiveInfinity(availableSize.Width) ? _tileWidth*3.5 : availableSize.Width,
                double.IsPositiveInfinity(availableSize.Height) ? _tileHeight * 2 : availableSize.Height);
        }
Exemple #16
0
        private bool TryPacking(IEnumerable<Window> windows, double scale)
        {
            var packer = new CygonRectanglePacker(Width, Height);
            foreach (var window in windows)
            {
                try
                {
                    var rect = window.Rectangle;

                    var ts = (rect.Width * rect.Height < 10000) ? 1.0 : scale; // show tiny windows at full size
                    window.TargetRectangle = new Rectangle(
                        packer.Pack((int)(rect.Width * ts), (int)(rect.Height * ts)),
                        new Size((int)(rect.Width * ts), (int)(rect.Height * ts)));
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }