public SortingViewModel(IFileListGenerator fileListGenerator, ImageSortingModule.IImageSorter imageSorter, IDirectorySelector directorySelector, IDialogHostWrapper dialogHostWrapper)
 {
     this.fileListGenerator = fileListGenerator;
     sorter = imageSorter;
     this.directorySelector = directorySelector;
     this.dialogHostWrapper = dialogHostWrapper;
     Initialize();
 }
Exemple #2
0
 /// <summary>
 /// Constructs a MaxRects algorithm with a given image sorter
 /// </summary>
 /// <param name="sorter">Image sorter to be used</param>
 public MaximalRectanglesAlgorithm(IImageSorter sorter)
 {
     this.placementAlgorithm = new GuillotinePlacementAlgorithm(new BestAreaFitFreeRectangleExtractor(),
                                                                new MaxRectsFreeRectangleSplitter(),
                                                                new MaxRectsFreeRectangleSortedMerger(),
                                                                rectOrientationSelector: null,
                                                                new MaxRectsFreeRectanglePostProcessor(),
                                                                sorter);
 }
 private void StartSort()
 {
     try
     {
         string str             = this.commandLineParser.SortDirectory ?? this.systemContext.GetCurrentWorkingDirectory();
         string outputDirectory = string.IsNullOrWhiteSpace(this.commandLineParser.OutputDirectory) ? str : this.commandLineParser.OutputDirectory;
         this.RaiseSorterInitialized(str, outputDirectory);
         IImageSorter imageSorter = this.imageManipulatorFactory.CreateImageSorter(this.componentsFactory, this.systemContext);
         imageSorter.MessageSent     += new EventHandler <MessageSentEventArgs>(this.HandleMessageSent);
         imageSorter.UserInput       += new EventHandler <UserInputEventArgs>(this.HandleUserInput);
         imageSorter.ProgressChanged += new EventHandler <ProgressChangedEventArgs>(this.HandleProgressChanged);
         imageSorter.Completed       += new EventHandler <CompletedEventArgs>(this.HandleImageSorterCompleted);
         this.stopWatch.Start();
         imageSorter.SortImages(str, !this.commandLineParser.IsNoRotate, outputDirectory, this.commandLineParser.NamePattern);
         imageSorter.MessageSent     -= new EventHandler <MessageSentEventArgs>(this.HandleMessageSent);
         imageSorter.UserInput       -= new EventHandler <UserInputEventArgs>(this.HandleUserInput);
         imageSorter.ProgressChanged -= new EventHandler <ProgressChangedEventArgs>(this.HandleProgressChanged);
         imageSorter.Completed       -= new EventHandler <CompletedEventArgs>(this.HandleImageSorterCompleted);
     }
     catch (Exception ex)
     {
         this.SendMessage(new MessageSentEventArgs(ex.Message, MessageType.Error));
     }
 }
        /// <summary>
        /// Accepts additional parameters and runs the tests inside the given class
        /// </summary>
        /// <typeparam name="T">The type of class that contains the tests</typeparam>
        private static void RunTests <T>()
        {
            if (typeof(T) != typeof(IPlacementAlgorithm) &&
                typeof(T) != typeof(IMinimumBoundingBoxFinder))
            {
                throw new NotSupportedException();
            }

            string str = "";

            IImageSorter        selectedImageSorter        = null;
            IPlacementAlgorithm selectedPlacementAlgorithm = null;

            //Ask the user to select an image sorter that will parametrize the placement algorithm / minimum bounding box finder
            while (true)
            {
                do
                {
                    Console.WriteLine("Select image sorter to be used: ");
                    Console.WriteLine($"\tEnter 'a' to select {typeof(ByHeightAndWidthImageSorter).Name}");
                    Console.WriteLine($"\tEnter 'b' to select {typeof(ByHeightAndWidthImageSorterDesc).Name}");
                    Console.WriteLine($"\tEnter 'c' to select {typeof(PreserveOrderImageSorter).Name}");
                } while ((str = Console.ReadLine()).Length != 1);

                switch (str[0])
                {
                case 'a':
                    selectedImageSorter = new ByHeightAndWidthImageSorter();
                    break;

                case 'b':
                    selectedImageSorter = new ByHeightAndWidthImageSorterDesc();
                    break;

                case 'c':
                    selectedImageSorter = new PreserveOrderImageSorter();
                    break;

                default:
                    continue;
                }

                break;
            }

            //If the users wants to benchmark Minimum bounding box finders
            //  then ask the user to select an placement algorithm that will parametrize tminimum bounding box finders
            if (typeof(T) == typeof(IMinimumBoundingBoxFinder))
            {
                while (true)
                {
                    do
                    {
                        Console.WriteLine("Select placement algorithm to be used: ");
                        Console.WriteLine($"\tEnter 'a' to select {typeof(BLAlgorithmPacker).Name}");
                        Console.WriteLine($"\tEnter 'b' to select {typeof(SkylineAlgorithm).Name}");
                        Console.WriteLine($"\tEnter 'c' to select {typeof(MaximalRectanglesAlgorithm).Name}");
                    } while ((str = Console.ReadLine()).Length != 1);

                    switch (str[0])
                    {
                    case 'a':
                        selectedPlacementAlgorithm = new BLAlgorithmPacker();
                        break;

                    case 'b':
                        selectedPlacementAlgorithm = new SkylineAlgorithm();
                        break;

                    case 'c':
                        selectedPlacementAlgorithm = new MaximalRectanglesAlgorithm();
                        break;

                    default:
                        continue;
                    }

                    break;
                }
            }

            bool isItSquaresTest = true;
            int  numOfRects      = 0;
            int  seed            = 0;

            //Ask the user to select test type
            //Currently, two types of tests are implemented (differing in the input sequence)
            // 1) Input sequence consisting of n squares with sizes 1x1, ..., nxn (given in random order)
            // 2) Input sequence consisting of n rectangles with random (but upper-bounded) sizes (given in random order)
            while (true)
            {
                str = "";
                do
                {
                    Console.WriteLine("Select test type:");
                    Console.WriteLine("\tEnter 'a' to perform test with squares of sizes 1x1, 2x2, ..., nxn");
                    Console.WriteLine("\tEnter 'b' to perform test with n rectangles of random sizes");
                } while ((str = Console.ReadLine()).Length != 1);

                switch (str[0])
                {
                case 'b':
                case 'a':

                    isItSquaresTest = str[0] == 'a';

                    //Ask the user to enter number of rectangles/squares
                    while (true)
                    {
                        Console.WriteLine("\tEnter number of 'n' - rectangles(squares)");
                        str = Console.ReadLine();
                        if (Int32.TryParse(str, out numOfRects))
                        {
                            if (numOfRects > 0)
                            {
                                break;
                            }
                        }
                    }

                    //If it is the random rectangles test then ask the user to enter the random seed
                    //  The seed will be user to construct the random generator used to generate the random rectangle sizes
                    if (!isItSquaresTest)
                    {
                        while (true)
                        {
                            Console.WriteLine("\tEnter seed");
                            str = Console.ReadLine();
                            if (Int32.TryParse(str, out seed))
                            {
                                break;
                            }
                        }
                    }

                    break;

                default:
                    continue;
                }
                break;
            }

            //Now when the user has selected the type of test and all the parameters
            // It is time to actaully run the tests. But because we need to test types
            // that are contained within plugins and also because BenchmarkDotNet (in a standard scenario)
            // requires to use (static) attribute [Benchmark] on the methods that should be called
            // we have decided to generate the benchmark class (with benchmark methods) dynamically at runtime
            // and then compile the generated class and pass the type of this class to the BenchmarkRunner

            string assemblyName = Path.GetRandomFileName();

            //Assemblies referenced by the assembly that will be generated at runtime
            //For each type that will be used in the generated test, an assembly containing
            //the used type has to be loaded
            var references = new List <MetadataReference>()
            {
                MetadataReference.CreateFromFile(typeof(BenchmarkDotNet.Attributes.BenchmarkAttribute).Assembly.Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("Microsoft.CSharp")).Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("mscorlib")).Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("Unity.Container")).Location),
                MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("Unity.Abstractions")).Location),
                MetadataReference.CreateFromFile(typeof(IMinimumBoundingBoxFinder).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(TestUtil).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(CancellationToken).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(UnityContainerExtensions).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(Random).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(System.Collections.Concurrent.ConcurrentDictionary <string, int>).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(ValueTuple <long, long>).Assembly.Location)
            };

            //Create same IoC here and in the generated class
            //This is because inside this class we try if (using the same IoC container with same registrations)
            //a given type could be resolved and if it does not, we exclude benchmark for this type in the generated class
            using UnityContainer IoC = new UnityContainer();
            IoC.RegisterFactory <IImageSorter>(_ => selectedImageSorter);

            if (selectedPlacementAlgorithm != null)
            {
                IoC.RegisterFactory <IPlacementAlgorithm>(_ => selectedPlacementAlgorithm);
            }

            //The generated source
            var benchmarkClassTemplate = new StringBuilder();

            //Using statements
            benchmarkClassTemplate.AppendLine("using System;");
            benchmarkClassTemplate.AppendLine("using Unity;");
            benchmarkClassTemplate.AppendLine("using System.Linq;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.MBBF;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.Placement;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.Sorting;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.Placement.Skyline;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.Placement.Guillotine;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Core.Packing.Placement.MaximalRectangles;");
            benchmarkClassTemplate.AppendLine("using System.Collections.Generic;");
            benchmarkClassTemplate.AppendLine("using System.Threading;");
            benchmarkClassTemplate.AppendLine("using PaunPacker.Tests;");

            //Beginning of the class
            benchmarkClassTemplate.AppendLine($"public class {typeof(T).Name}Benchmarks");
            benchmarkClassTemplate.AppendLine("{");
            //Member declarations
            benchmarkClassTemplate.AppendLine(@"
                private static UnityContainer IoC { get; set; }
                private static Random rnd;
                private static List<PaunPacker.Core.Types.PPRect> randomRects;
                static System.Collections.Concurrent.ConcurrentDictionary<string, ValueTuple<long, long>> results;
");
            benchmarkClassTemplate.AppendLine($"\n\tstatic {typeof(T).Name}Benchmarks()");
            benchmarkClassTemplate.AppendLine("\t{");

            //Constructor code
            benchmarkClassTemplate.AppendLine($@"
                IoC = new UnityContainer();
                IoC.RegisterInstance<IImageSorter>(new {selectedImageSorter.GetType().Name}());

                results = new System.Collections.Concurrent.ConcurrentDictionary<string, ValueTuple<long, long>>();

                rnd = new Random(" + seed + @");
                randomRects = new List<PaunPacker.Core.Types.PPRect>(" + numOfRects + @");
                
                int dimensionBound = Int32.MaxValue / " + numOfRects + @";
                dimensionBound = dimensionBound > 2049 ? 2049 : dimensionBound;

                for (int i = 0; i < " + numOfRects + @"; i++)
                {
                    randomRects.Add(new PaunPacker.Core.Types.PPRect(0, 0, rnd.Next(1, dimensionBound), rnd.Next(1, dimensionBound)));
                }
");

            if (selectedPlacementAlgorithm != null)
            {
                benchmarkClassTemplate.AppendLine($"IoC.RegisterInstance<IPlacementAlgorithm>(new { selectedPlacementAlgorithm.GetType().Name }());");
            }

            benchmarkClassTemplate.AppendLine("\t}");
            //Constructor ends here

            if (isItSquaresTest)
            {
                benchmarkClassTemplate.AppendLine($@"
                [BenchmarkDotNet.Attributes.ParamsSourceAttribute(nameof(ValuesForN))]
                public int N;
                public IEnumerable<int> ValuesForN => System.Linq.Enumerable.Range(1, {numOfRects});
");
            }

            int numOfTests = 0;

            // We are testing minimum bounding box finders, so generate tests for them
            if (selectedPlacementAlgorithm != null)
            {
                foreach (var x in MinimumBoundingBoxFinderTypes)
                {
                    try
                    {
                        UnityContainerExtensions.Resolve(IoC, Type.GetType(x.AssemblyQualifiedName), null);
                        references.Add(MetadataReference.CreateFromFile(x.Assembly.Location));
                        benchmarkClassTemplate.AppendLine("\t[BenchmarkDotNet.Attributes.BenchmarkAttribute]");
                        benchmarkClassTemplate.AppendLine($"\tpublic void Test{x.Name}()");
                        benchmarkClassTemplate.AppendLine("{");
                        benchmarkClassTemplate.AppendLine($"\tvar x = Type.GetType(\"{x.AssemblyQualifiedName}\");");
                        benchmarkClassTemplate.AppendLine($"\tvar res = (UnityContainerExtensions.Resolve(IoC, x, null) as IMinimumBoundingBoxFinder).FindMinimumBoundingBox(TestUtil.Shuffle(" + (isItSquaresTest ? "TestUtil.GetIncreasingSquares(N)" : $"randomRects") + "), CancellationToken.None);");
                        benchmarkClassTemplate.AppendLine($"results.AddOrUpdate(\"Test{x.Name}\", (res.Width * res.Height, 1), (key, old) => ((long)(old.Item1 + (double)(res.Width * res.Height - old.Item1) / (double)(old.Item2 + 1)), old.Item2 + 1));");
                        benchmarkClassTemplate.AppendLine("}");
                        benchmarkClassTemplate.AppendLine();
                        numOfTests++;
                    }
                    catch (ResolutionFailedException)
                    {
                        //Do not add benchmark for types that could not be resolved (for example types that are extensible by other plugins
                        // via plugin view ...). These types will simply not be benchmarked.
                    }
                }
            }
            else
            {
                foreach (var x in PlacementAlgorithmTypes)
                {
                    try
                    {
                        UnityContainerExtensions.Resolve(IoC, Type.GetType(x.AssemblyQualifiedName), null);
                        references.Add(MetadataReference.CreateFromFile(x.Assembly.Location));
                        benchmarkClassTemplate.AppendLine("\t[BenchmarkDotNet.Attributes.BenchmarkAttribute]");
                        benchmarkClassTemplate.AppendLine($"\tpublic void Test{x.Name}()");
                        benchmarkClassTemplate.AppendLine("{");
                        benchmarkClassTemplate.AppendLine($"\tvar x = Type.GetType(\"{x.AssemblyQualifiedName}\");");
                        benchmarkClassTemplate.AppendLine($"\tvar res = (UnityContainerExtensions.Resolve(IoC, x, null) as IPlacementAlgorithm).PlaceRects(Int32.MaxValue, Int32.MaxValue, TestUtil.Shuffle(" + (isItSquaresTest ? "TestUtil.GetIncreasingSquares(N)" : $"randomRects") + "));");
                        benchmarkClassTemplate.AppendLine("long actualW = res.Rects.Max(y => y.Right); long actualH = res.Rects.Max(y => y.Bottom);");
                        benchmarkClassTemplate.AppendLine($"checked {{ results.AddOrUpdate(\"Test{x.Name}\", (actualW * actualH, 1), (key, old) => ((long)(old.Item1 + (double)(actualW * actualH - old.Item1) / (double)(old.Item2 + 1)), old.Item2 + 1));");
                        benchmarkClassTemplate.AppendLine("}}");
                        benchmarkClassTemplate.AppendLine();
                        numOfTests++;
                    }
                    catch (ResolutionFailedException)
                    {
                        //Do not add benchmark for types that could not be resolved (for example types that are extensible by other plugins
                        // via plugin view ...). These types will simply not be benchmarked.
                    }
                }
            }

            //Global cleanup method
            //Because BenchmarkDotNet does not allow to report benchmark methods return values
            //We had to "hack" around it by using these two methods
            //And save the method results inside a file and then (when showing the report) load it from the file
            //The GlobalCleanup should not be measured as a part of the benchmark
            //However we still need to somewhere remember the return value of the methods
            //Because writing to file in the benchmark method itself would totally kill the performance, we have decided to store it in dictionary
            //Which still causes some test distortion but it should be OK (all the tests use it so their base-line is just shifted)
            benchmarkClassTemplate.AppendLine(@"

            [BenchmarkDotNet.Attributes.GlobalCleanup]
            public void GlobalCleanup()
            {
                //We want to call it only once, not after every [Benchmark] method
                if (results.Count() == " + numOfTests + @")
                {
                    using (var sw = new System.IO.StreamWriter(""results.txt"", true))
                    {
                        //foreach (var r in randomRects) //for debug purposes
                        //    sw.WriteLine(r.Width + ""x"" + r.Height);
                        foreach (var res in results)
                            sw.WriteLine(res.Key + "";"" + res.Value.Item1 + "";"" + res.Value.Item1 + "";"" + res.Value.Item2);
                    }
                    results.Clear();
                }
            }
");

            benchmarkClassTemplate.AppendLine("}");
            //Benchmark class ends here

            Console.WriteLine("Please wait ... (Compiling the Benchmarks)");

            //Create syntax tree and compile it
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(benchmarkClassTemplate.ToString());

            CSharpCompilation compilation = CSharpCompilation.Create(
                assemblyName,
                syntaxTrees: new[] { syntaxTree },
                references: references,
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release));

            //Emit the CIL into memory stream
            using var ms = new MemoryStream();
            EmitResult result = compilation.Emit(ms);

            if (!result.Success)
            {
                IEnumerable <Microsoft.CodeAnalysis.Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                                                                                    diagnostic.IsWarningAsError ||
                                                                                                    diagnostic.Severity == DiagnosticSeverity.Error);

                foreach (Microsoft.CodeAnalysis.Diagnostic diagnostic in failures)
                {
                    Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                }
            }
            else
            {
                ms.Seek(0, SeekOrigin.Begin);
                Assembly assembly = Assembly.Load(ms.ToArray());
                Type     type     = assembly.GetType($"{typeof(T).Name}Benchmarks");
                Console.WriteLine("Starting the Benchmarks");
                var x = BenchmarkDotNet.Running.BenchmarkRunner.Run(type, new Config());
                Console.WriteLine("Done");
            }
        }
 /// <summary>
 /// Constructs a SkylineAlgorithm with a given image sorter and ISkylineRectAndPointPicker
 /// </summary>
 /// <param name="imageSorter">The image sorter to be used</param>
 /// <param name="rectangleAndPointPicker">The rectangle and point picker to be used</param>
 /// <remarks>
 /// When <paramref name="imageSorter"/> is null, the <see cref="ByHeightAndWidthImageSorterDesc"/> is used as a default image sorter
 /// When <paramref name="rectangleAndPointPicker"/> is null, the <see cref="MinimalAreaWasteRectAndPointPicker"/> is used as a default rect and point picker
 /// </remarks>
 public SkylineAlgorithm(IImageSorter imageSorter = null, ISkylineRectAndPointPicker rectangleAndPointPicker = null)
 {
     feasiblePoints          = new LinkedList <FeasiblePoint>();
     this.imageSorter        = imageSorter ?? new ByHeightAndWidthImageSorterDesc();
     this.rectAndPointPicker = rectangleAndPointPicker ?? new MinimalAreaWasteRectAndPointPicker();
 }
 /// <summary>
 /// Constructs a new GuillotineBestAreaFitAlgorithm with a given image sorter
 /// </summary>
 /// <param name="imageSorter">Image sorter to be used</param>
 public GuillotineBestAreaFitAlgorithm(IImageSorter imageSorter)
 {
     this.placementAlgorithm = new GuillotinePlacementAlgorithm(new BestAreaFitFreeRectangleExtractor(), new LongerAxisGuillotineFreeRectangleSplitter(), null, null, null, imageSorter);
 }
 /// <summary>
 /// Constructs a new Guillotine algorithm based on the passed parameters and ImageSorter
 /// </summary>
 /// <param name="freeRectExtractor">Free rectangle extractor (<seealso cref="IFreeRectangleExtractor"/>) used by the Guillotine algorithm</param>
 /// <param name="freeRectangleSplitter">Free rectangle splitter (<seealso cref="IFreeRectangleSplitter"/>) used by the Guillotine algorithm</param>
 /// <param name="freeRectangleMerger">Free rectangle extractor (<seealso cref="IFreeRectangleMerger"/>) used by the Guillotine algorithm</param>
 /// <param name="rectOrientationSelector">Rectangle orientation selector (<seealso cref="IRectOrientationSelector"/>) used by the Guillotine algorithm</param>
 /// <param name="freeRectanglePostProcessor">Free post processor (<seealso cref="IFreeRectanglePostProcessor"/>) used by the Guillotine algorithm</param>
 /// <param name="sorter">The image sorter</param>
 public GuillotinePlacementAlgorithm(IFreeRectangleExtractor freeRectExtractor, IFreeRectangleSplitter freeRectangleSplitter, IFreeRectangleMerger freeRectangleMerger, IRectOrientationSelector rectOrientationSelector, IFreeRectanglePostProcessor freeRectanglePostProcessor, IImageSorter sorter)
 {
     this.freeRectExtractor          = freeRectExtractor ?? new BestAreaFitFreeRectangleExtractor();
     this.freeRectangleSplitter      = freeRectangleSplitter ?? new LongerAxisGuillotineFreeRectangleSplitter();
     this.rectOrientationSelector    = rectOrientationSelector ?? new DummyRectOrientationSelector();
     this.freeRectangleMerger        = freeRectangleMerger ?? new GuillotineFreeRectangleSortedMerger();
     this.freeRectanglePostProcessor = freeRectanglePostProcessor;
     this.imageSorter   = sorter ?? new ByHeightAndWidthImageSorterDesc();
     freeRectanglesList = new List <PPRect>();
 }
Exemple #8
0
 /// <summary>
 /// Constructs a BLAlgorithmPacker using a given image sorter
 /// </summary>
 /// <param name="sorter">The image sorter to be used</param>
 public BLAlgorithmPacker(IImageSorter sorter)
 {
     this.sorter = sorter;
 }