diff --git a/.gitignore b/.gitignore index bfca666a..64efe93a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ bld/ msbuild.log msbuild.err msbuild.wrn +FractalPainter/ \ No newline at end of file diff --git a/ConsoleClient/ConsoleClient.csproj b/ConsoleClient/ConsoleClient.csproj new file mode 100644 index 00000000..1ab0ce0e --- /dev/null +++ b/ConsoleClient/ConsoleClient.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + diff --git a/ConsoleClient/DependencyInjectionConfig.cs b/ConsoleClient/DependencyInjectionConfig.cs new file mode 100644 index 00000000..958cb660 --- /dev/null +++ b/ConsoleClient/DependencyInjectionConfig.cs @@ -0,0 +1,72 @@ +using System.Drawing; +using System.Runtime.InteropServices; +using Autofac; +using DrawingTagsCloudVisualization; +using TagsCloudVisualization; +using TagsCloudVisualization.FilesProcessing; +using TagsCloudVisualization.ManagingRendering; + +namespace ConsoleClient; + +public static class DependencyInjectionConfig +{ + public static IContainer BuildContainer(Options options) + { + var builder = new ContainerBuilder(); + var pathToMystem = ""; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + pathToMystem = "mystem.exe"; + else + pathToMystem = "mystem"; + builder.RegisterInstance(new MyStemWrapper.MyStem + { + PathToMyStem = pathToMystem, + Parameters = "-ni" + }).As().SingleInstance(); + + builder.RegisterType() + .As() + .InstancePerDependency(); + + builder.RegisterType() + .As() + .InstancePerDependency(); + + builder.Register(c => + { + var centerPoint = new Point(options.CenterX, options.CenterY); + return options.AlgorithmForming switch + { + "Circle" => new ArchimedeanSpiral(centerPoint, 1), + _ => new FermatSpiral(centerPoint, 20), + }; + }).As().InstancePerDependency(); + + builder.RegisterType() + .As() + .InstancePerDependency(); + builder.RegisterType() + .As() + .InstancePerDependency(); + builder.RegisterType() + .As() + .InstancePerDependency(); + + switch (options.AlgorithmDrawing) + { + case "Altering": + builder.RegisterType().As() + .InstancePerDependency(); + break; + default: + builder.RegisterType().As() + .InstancePerDependency(); + break; + } + builder.RegisterType() + .As() + .InstancePerDependency(); + + return builder.Build(); + } +} diff --git a/ConsoleClient/Examples/README.md b/ConsoleClient/Examples/README.md new file mode 100644 index 00000000..0424d369 --- /dev/null +++ b/ConsoleClient/Examples/README.md @@ -0,0 +1,39 @@ +# 1 example: + +Agrs: dotnet run +![alt text](example.png) + +# 2 example: + +Args: dotnet run -- -o Examples/example1.png -l 500 -w 500 +![alt text](example1.png) + +# 3 example: + +Args: dotnet run -- -o Examples/example2.png -x 150 -y 300 +![alt text](example2.png) + +# 4 example: + +Args: dotnet run -- -c pink -o Examples/example3.png +![alt text](example3.png) + +# 5 example: + +Args: dotnet run -- -a Fermat -o Examples/example4.png +![alt text](example4.png) + +# 6 example: + +Args: dotnet run -- -p S -o Examples/example5.png +![alt text](example5.png) + +# 7 example: + +Args: dotnet run -- -d Altering -o Examples/example7.png +![alt text](example7.png) + +# 8 example: + +Args: dotnet run -- -p A,V -o Examples/example8.png -i Examples/example1.txt +![alt text](example8.png) \ No newline at end of file diff --git a/ConsoleClient/Examples/example.png b/ConsoleClient/Examples/example.png new file mode 100644 index 00000000..0a4b0046 Binary files /dev/null and b/ConsoleClient/Examples/example.png differ diff --git a/ConsoleClient/Examples/example.txt b/ConsoleClient/Examples/example.txt new file mode 100644 index 00000000..a13659a9 --- /dev/null +++ b/ConsoleClient/Examples/example.txt @@ -0,0 +1,27 @@ +да +о +кошка +кошка +большой +большой +большой +дом +дом +красиво +красиво +красиво +красиво +и +книга +книга +азбука +азбука +кружка +кружка +кружка +алгебра +алгебра +алгебра +носок +носок +не \ No newline at end of file diff --git a/ConsoleClient/Examples/example1.png b/ConsoleClient/Examples/example1.png new file mode 100644 index 00000000..a5a693c9 Binary files /dev/null and b/ConsoleClient/Examples/example1.png differ diff --git a/ConsoleClient/Examples/example1.txt b/ConsoleClient/Examples/example1.txt new file mode 100644 index 00000000..6e00102e --- /dev/null +++ b/ConsoleClient/Examples/example1.txt @@ -0,0 +1,49 @@ +да +о +кошка +кошка +большой +большой +большой +дом +дом +дом +красиво +красиво +красиво +красиво +и +книга +книга +азбука +азбука +кружка +кружка +кружка +алгебра +алгебра +алгебра +носок +носок +носок +не +говно +говно +говно +хуй +хуй +хуй +залупа +залупа +мошонник +мошонник +мошонник +мошонник +говнохуй +говнохуй +говнохуй +говнохуй +влиять +влиять +бегать +бегать \ No newline at end of file diff --git a/ConsoleClient/Examples/example2.png b/ConsoleClient/Examples/example2.png new file mode 100644 index 00000000..e19d6f89 Binary files /dev/null and b/ConsoleClient/Examples/example2.png differ diff --git a/ConsoleClient/Examples/example3.png b/ConsoleClient/Examples/example3.png new file mode 100644 index 00000000..83256a1e Binary files /dev/null and b/ConsoleClient/Examples/example3.png differ diff --git a/ConsoleClient/Examples/example4.png b/ConsoleClient/Examples/example4.png new file mode 100644 index 00000000..1ed487eb Binary files /dev/null and b/ConsoleClient/Examples/example4.png differ diff --git a/ConsoleClient/Examples/example5.png b/ConsoleClient/Examples/example5.png new file mode 100644 index 00000000..a1e05590 Binary files /dev/null and b/ConsoleClient/Examples/example5.png differ diff --git a/ConsoleClient/Examples/example6.png b/ConsoleClient/Examples/example6.png new file mode 100644 index 00000000..27959002 Binary files /dev/null and b/ConsoleClient/Examples/example6.png differ diff --git a/ConsoleClient/Examples/example7.png b/ConsoleClient/Examples/example7.png new file mode 100644 index 00000000..f5ea62da Binary files /dev/null and b/ConsoleClient/Examples/example7.png differ diff --git a/ConsoleClient/Examples/example8.png b/ConsoleClient/Examples/example8.png new file mode 100644 index 00000000..7ae28138 Binary files /dev/null and b/ConsoleClient/Examples/example8.png differ diff --git a/ConsoleClient/ITagsCloudDrawingFacade.cs b/ConsoleClient/ITagsCloudDrawingFacade.cs new file mode 100644 index 00000000..dc7cc69d --- /dev/null +++ b/ConsoleClient/ITagsCloudDrawingFacade.cs @@ -0,0 +1,5 @@ +namespace ConsoleClient; +public interface ITagsCloudDrawingFacade +{ + void DrawRectangle(Options options); +} \ No newline at end of file diff --git a/ConsoleClient/Options.cs b/ConsoleClient/Options.cs new file mode 100644 index 00000000..c7049a8f --- /dev/null +++ b/ConsoleClient/Options.cs @@ -0,0 +1,35 @@ +using CommandLine; +namespace ConsoleClient; + +public class Options +{ + [Option('i', "input", Default = "Examples/example.txt", HelpText = "Путь к входному текстовому файлу.")] + public required string InputFilePath { get; set; } + + [Option('o', "output", Default = "Examples/example.png", HelpText = "Путь к выходному изображению.")] + public required string OutputFilePath { get; set; } + + [Option('x', "centerX", Default = 200, HelpText = "Координата X центра.")] + public int CenterX { get; set; } + + [Option('y', "centerY", Default = 200, HelpText = "Координата Y центра.")] + public int CenterY { get; set; } + + [Option('l', "length", Default = 400, HelpText = "Длина изображения")] + public int Length { get; set; } + + [Option('w', "width", Default = 400, HelpText = "Ширина изображения")] + public int Width{ get; set; } + + [Option('c', "color", Default = "black", HelpText = "Цвет текста")] + public string Color{ get; set; } + + [Option('a', "algorithmf", Default = "Circle", HelpText = "Алгоритм формирования(квадрат, круг)")] + public string AlgorithmForming{ get; set; } + + [Option('p', "excludedpartofspeech", Required = false, HelpText = "Исключить часть речи S V A ADV NUM SPRO ANUM ADVPRO")] + public string ExcludedPartOfSpeech{ get; set; } + + [Option('d', "algorithmd", Default = "Standart", HelpText = "Алгоритм рисования(Standart, Altering)")] + public string AlgorithmDrawing{ get; set; } +} \ No newline at end of file diff --git a/ConsoleClient/Program.cs b/ConsoleClient/Program.cs new file mode 100644 index 00000000..cb4f2c74 --- /dev/null +++ b/ConsoleClient/Program.cs @@ -0,0 +1,81 @@ +using Autofac; +using CommandLine; + +namespace ConsoleClient; + + +public class Program +{ + static void Main(string[] args) + { + Parser.Default.ParseArguments(args) + .WithParsed(RunApplication) + .WithNotParsed(HandleErrors); + } + readonly static private HashSet validPartsOfSpeech = + [ + "S", "V", "A", "ADV", "NUM", "SPRO", "ADVPRO", "ANUM" + ]; + + private static void RunApplication(Options options) + { + if (options.AlgorithmForming != "Circle" && options.AlgorithmForming != "Fermat") + { + Console.WriteLine($"Ошибка: Неизвестный алгоритм '{options.AlgorithmForming}'. Допустимые значения: 'Circle', 'Fermat'."); + return; + } + if (!string.IsNullOrEmpty(options.ExcludedPartOfSpeech)) + { + var excludedParts = options.ExcludedPartOfSpeech.Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(part => part.Trim().ToUpper()); + + var invalidParts = excludedParts.Where(part => !validPartsOfSpeech.Contains(part)).ToList(); + + if (invalidParts.Count != 0) + { + Console.WriteLine($"Ошибка: Неизвестные части речи '{string.Join(", ", invalidParts)}'"); + return; + } + } + if (options.AlgorithmDrawing != "Standart" && options.AlgorithmDrawing != "Altering") + { + Console.WriteLine($"Ошибка: Неизвестный алгоритм рассказки '{options.AlgorithmDrawing}'"); + return; + } + var container = DependencyInjectionConfig.BuildContainer(options); + + using var scope = container.BeginLifetimeScope(); + try + { + scope.Resolve().DrawRectangle(options); + Console.WriteLine($"Облако тегов успешно сохранено в файл: {options.OutputFilePath}"); + } + catch (Exception ex) + { + Console.WriteLine($"Произошла ошибка: {ex.Message}"); + } + } + + private static void HandleErrors(IEnumerable errors) + { + Console.WriteLine("Ошибка при обработке аргументов командной строки."); + foreach (var error in errors) + { + switch (error) + { + case UnknownOptionError unknownOptionError: + Console.WriteLine($"- Неизвестный параметр: {unknownOptionError.Token}"); + break; + case SetValueExceptionError setValueExceptionError: + Console.WriteLine($"- Ошибка установки значения: {setValueExceptionError.Exception.Message}"); + break; + case MissingValueOptionError missingValueOptionError: + Console.WriteLine($"- Отсутствует значение: {missingValueOptionError.NameInfo}"); + break; + default: + Console.WriteLine($"- Неизвестная ошибка: {error.GetType().Name}"); + break; + } + } + } +} diff --git a/ConsoleClient/TagsCloudDrawingFacade.cs b/ConsoleClient/TagsCloudDrawingFacade.cs new file mode 100644 index 00000000..97c0eead --- /dev/null +++ b/ConsoleClient/TagsCloudDrawingFacade.cs @@ -0,0 +1,20 @@ +using System.Drawing; +using DrawingTagsCloudVisualization; +using TagsCloudVisualization; +namespace ConsoleClient; + +public class TagsCloudDrawingFacade( + IWordHandler wordHandler, + IRectangleGenerator rectangleGenerator, IImageSaver imageSaver) : ITagsCloudDrawingFacade +{ + private readonly IWordHandler _wordHandler = wordHandler; + private readonly IRectangleGenerator _rectangleGenerator = rectangleGenerator; + private readonly IImageSaver _imageSaver = imageSaver; + + public void DrawRectangle(Options options) + { + var frequencyRectangles = _wordHandler.ProcessFile(options.InputFilePath, options.ExcludedPartOfSpeech); + var arrRect = _rectangleGenerator.ExecuteRectangles(frequencyRectangles, new Point(options.CenterX, options.CenterY)); + _imageSaver.SaveToFile(options.OutputFilePath, options.Length, options.Width, options.Color, arrRect); + } +} diff --git a/ConsoleClient/mystem b/ConsoleClient/mystem new file mode 100755 index 00000000..78e1ae76 Binary files /dev/null and b/ConsoleClient/mystem differ diff --git a/ConsoleClient/mystem.exe b/ConsoleClient/mystem.exe new file mode 100755 index 00000000..e7158ff1 Binary files /dev/null and b/ConsoleClient/mystem.exe differ diff --git a/DrawingTagsCloudVisualization/AlternatingColorsTagsCloudDrawer.cs b/DrawingTagsCloudVisualization/AlternatingColorsTagsCloudDrawer.cs new file mode 100644 index 00000000..87e15ac4 --- /dev/null +++ b/DrawingTagsCloudVisualization/AlternatingColorsTagsCloudDrawer.cs @@ -0,0 +1,48 @@ +using Microsoft.Maui.Graphics; +using TagsCloudVisualization; + +namespace DrawingTagsCloudVisualization; + +public class AlternatingColorsTagsCloudDrawer() : ITagsCloudDrawer +{ + private readonly List colors = new List + { + Colors.White, + Colors.Red, + Colors.Green, + Colors.Yellow, + Colors.Blue, + Colors.Pink, + Colors.Black + }; + + public ICanvas Draw(ICanvas canvas, string color, List rectangleInformation) + { + for (int i = 0; i < rectangleInformation.Count; i++) + { + var rectInfo = rectangleInformation[i]; + var rect = rectInfo.rectangle; + var text = rectInfo.word; + + var currentColor = colors[i % colors.Count]; + canvas.FontColor = currentColor; + + float fontSize = rect.Height; + var textBounds = canvas.GetStringSize(text, Font.Default, fontSize); + + while ((textBounds.Width > rect.Width || textBounds.Height > rect.Height) && fontSize > 1) + { + fontSize -= 1; + textBounds = canvas.GetStringSize(text, Font.Default, fontSize); + } + + canvas.FontSize = fontSize; + var textX = rect.X + (rect.Width - textBounds.Width) / 2; + var textY = rect.Y + (rect.Height - textBounds.Height) / 2; + + canvas.DrawString(text, textX, textY, HorizontalAlignment.Left); + } + + return canvas; + } +} \ No newline at end of file diff --git a/DrawingTagsCloudVisualization/DecreasingRectangles120.png b/DrawingTagsCloudVisualization/DecreasingRectangles120.png new file mode 100644 index 00000000..9590045b Binary files /dev/null and b/DrawingTagsCloudVisualization/DecreasingRectangles120.png differ diff --git a/DrawingTagsCloudVisualization/DrawingTagsCloudVisualization.csproj b/DrawingTagsCloudVisualization/DrawingTagsCloudVisualization.csproj new file mode 100644 index 00000000..4d1e5a44 --- /dev/null +++ b/DrawingTagsCloudVisualization/DrawingTagsCloudVisualization.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + + false + false + + + + + + + + + + + + diff --git a/DrawingTagsCloudVisualization/EqualsRectangles250.png b/DrawingTagsCloudVisualization/EqualsRectangles250.png new file mode 100644 index 00000000..b8855894 Binary files /dev/null and b/DrawingTagsCloudVisualization/EqualsRectangles250.png differ diff --git a/DrawingTagsCloudVisualization/IImageSaver.cs b/DrawingTagsCloudVisualization/IImageSaver.cs new file mode 100644 index 00000000..8302a11e --- /dev/null +++ b/DrawingTagsCloudVisualization/IImageSaver.cs @@ -0,0 +1,8 @@ +using TagsCloudVisualization; + +namespace DrawingTagsCloudVisualization; + +public interface IImageSaver +{ + public void SaveToFile(string filePath, int lenght, int width, string color, List rectangleInformation); +} \ No newline at end of file diff --git a/DrawingTagsCloudVisualization/ITagsCloudDrawer.cs b/DrawingTagsCloudVisualization/ITagsCloudDrawer.cs new file mode 100644 index 00000000..180953d2 --- /dev/null +++ b/DrawingTagsCloudVisualization/ITagsCloudDrawer.cs @@ -0,0 +1,9 @@ +using Microsoft.Maui.Graphics; +using TagsCloudVisualization; + +namespace DrawingTagsCloudVisualization; + +public interface ITagsCloudDrawer +{ + public ICanvas Draw(ICanvas canvas, string color, List rectangleInformation); +} \ No newline at end of file diff --git a/DrawingTagsCloudVisualization/ImageSaver.cs b/DrawingTagsCloudVisualization/ImageSaver.cs new file mode 100644 index 00000000..678f7e06 --- /dev/null +++ b/DrawingTagsCloudVisualization/ImageSaver.cs @@ -0,0 +1,21 @@ +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Skia; +using TagsCloudVisualization; + +namespace DrawingTagsCloudVisualization; + +public class ImageSaver(ITagsCloudDrawer tagsCloudDrawer) : IImageSaver +{ + readonly ITagsCloudDrawer tagsCloudDrawer = tagsCloudDrawer; + + public void SaveToFile(string filePath, int lenght, int width, string color, List rectangleInformation) + { + using var bitmapContext = new SkiaBitmapExportContext(lenght, width, 2.0f); + var canvas = bitmapContext.Canvas; + canvas.FontColor = Colors.Black; + canvas = tagsCloudDrawer.Draw(canvas, color, rectangleInformation); + using var image = bitmapContext.Image; + using var stream = File.OpenWrite(filePath); + image.Save(stream); + } +} \ No newline at end of file diff --git a/DrawingTagsCloudVisualization/MixedRectangles320.png b/DrawingTagsCloudVisualization/MixedRectangles320.png new file mode 100644 index 00000000..f1f7cfde Binary files /dev/null and b/DrawingTagsCloudVisualization/MixedRectangles320.png differ diff --git a/DrawingTagsCloudVisualization/README.md b/DrawingTagsCloudVisualization/README.md new file mode 100644 index 00000000..1f0b3536 --- /dev/null +++ b/DrawingTagsCloudVisualization/README.md @@ -0,0 +1,10 @@ +Увеличивающися по размеру прямоугольники +![alt text](DecreasingRectangles120.png) + + +Одинаковые прямоугольники +![alt text](EqualsRectangles250.png) + + +Прямоугольники разных размеров +![alt text](MixedRectangles320.png) \ No newline at end of file diff --git a/DrawingTagsCloudVisualization/StandartTagsCloudDrawer.cs b/DrawingTagsCloudVisualization/StandartTagsCloudDrawer.cs new file mode 100644 index 00000000..088e4ba1 --- /dev/null +++ b/DrawingTagsCloudVisualization/StandartTagsCloudDrawer.cs @@ -0,0 +1,46 @@ +using Microsoft.Maui.Graphics; +using TagsCloudVisualization; + +namespace DrawingTagsCloudVisualization; + +public class StandartTagsCloudDrawer() : ITagsCloudDrawer +{ + private readonly Dictionary dictColors = new(){ + { "white", Colors.White }, + { "red", Colors.Red }, + { "green", Colors.Green }, + { "yellow", Colors.Yellow }, + { "blue", Colors.Blue }, + { "pink", Colors.Pink }, + { "black", Colors.Black }, + }; + + public ICanvas Draw(ICanvas canvas, string color, List rectangleInformation) + { + foreach (var rectInfo in rectangleInformation) + { + var rect = rectInfo.rectangle; + var text = rectInfo.word; + + float fontSize = rect.Height; + if (!dictColors.TryGetValue(color, out var colorGet)) + colorGet = Colors.Black; + canvas.FontColor = colorGet; + var textBounds = canvas.GetStringSize(text, Font.Default, fontSize); + + while ((textBounds.Width > rect.Width || textBounds.Height > rect.Height) && fontSize > 1) + { + fontSize -= 1; + textBounds = canvas.GetStringSize(text, Font.Default, fontSize); + } + + canvas.FontSize = fontSize; + var textX = rect.X + (rect.Width - textBounds.Width) / 2; + var textY = rect.Y + (rect.Height - textBounds.Height) / 2; + + canvas.DrawString(text, textX, textY, HorizontalAlignment.Left); + } + + return canvas; + } +} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/DragonFractalAction.cs b/FractalPainter/Application/Actions/DragonFractalAction.cs deleted file mode 100644 index fa55e68f..00000000 --- a/FractalPainter/Application/Actions/DragonFractalAction.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Application.Fractals; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; -using Microsoft.Extensions.DependencyInjection; - -namespace FractalPainting.Application.Actions; - -public class DragonFractalAction : IApiAction, INeed -{ - private readonly JsonSerializerOptions jsonSerializerOptions = - new() { Converters = { new FigureJsonConverter() } }; - private IImageSettingsProvider imageSettingsProvider = null!; - - public void SetDependency(IImageSettingsProvider dependency) - { - imageSettingsProvider = dependency; - } - - public string Endpoint => "/dragonFractal"; - - public string HttpMethod => "POST"; - - public int Perform(Stream inputStream, Stream outputStream) - { - var dragonSettings = JsonSerializer.Deserialize(inputStream); - var services = new ServiceCollection(); - services.AddSingleton(dragonSettings!); - services.AddSingleton(imageSettingsProvider); - services.AddSingleton(); - var sp = services.BuildServiceProvider(); - - var painter = sp.GetRequiredService(); - var figures = painter.Paint(); - JsonSerializer.Serialize(outputStream, figures, options: jsonSerializerOptions); - - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/GetImageSettingsAction.cs b/FractalPainter/Application/Actions/GetImageSettingsAction.cs deleted file mode 100644 index 5448ce14..00000000 --- a/FractalPainter/Application/Actions/GetImageSettingsAction.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; - -namespace FractalPainting.Application.Actions; - -public class GetImageSettingsAction : IApiAction, INeed -{ - private IImageSettingsProvider? imageSettingsProvider; - - public void SetDependency(IImageSettingsProvider dependency) - { - imageSettingsProvider = dependency; - } - - public string Endpoint => "/settings"; - - public string HttpMethod => "GET"; - - public int Perform(Stream inputStream, Stream outputStream) - { - var settings = imageSettingsProvider?.ImageSettings; - JsonSerializer.Serialize(outputStream, settings); - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/GetPaletteSettingsAction.cs b/FractalPainter/Application/Actions/GetPaletteSettingsAction.cs deleted file mode 100644 index 06927f5e..00000000 --- a/FractalPainter/Application/Actions/GetPaletteSettingsAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; - -namespace FractalPainting.Application.Actions; - -public class GetPaletteSettingsAction : IApiAction, INeed -{ - private Palette palette = null!; - - public void SetDependency(Palette dependency) - { - palette = dependency; - } - - public string Endpoint => "/palette"; - - public string HttpMethod => "GET"; - - public int Perform(Stream inputStream, Stream outputStream) - { - JsonSerializer.Serialize(outputStream, palette); - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/KochFractalAction.cs b/FractalPainter/Application/Actions/KochFractalAction.cs deleted file mode 100644 index cce9488b..00000000 --- a/FractalPainter/Application/Actions/KochFractalAction.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Application.Fractals; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; -using Microsoft.Extensions.DependencyInjection; - -namespace FractalPainting.Application.Actions; - -public class KochFractalAction : IApiAction, INeed, INeed -{ - private readonly JsonSerializerOptions jsonSerializerOptions = - new() { Converters = { new FigureJsonConverter() } }; - private Palette palette = null!; - private IImageSettingsProvider imageSettingsProvider = null!; - - public void SetDependency(Palette dependency) - { - palette = dependency; - } - - public void SetDependency(IImageSettingsProvider dependency) - { - imageSettingsProvider = dependency; - } - - public string Endpoint => "/kochFractal"; - - public string HttpMethod => "POST"; - - public int Perform(Stream inputStream, Stream outputStream) - { - var services = new ServiceCollection(); - services.AddSingleton(palette); - services.AddSingleton(imageSettingsProvider); - services.AddSingleton(); - var sp = services.BuildServiceProvider(); - - var painter = sp.GetRequiredService(); - var figures = painter.Paint(); - JsonSerializer.Serialize(outputStream, figures, options: jsonSerializerOptions); - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/UpdateImageSettingsAction.cs b/FractalPainter/Application/Actions/UpdateImageSettingsAction.cs deleted file mode 100644 index d74652ca..00000000 --- a/FractalPainter/Application/Actions/UpdateImageSettingsAction.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; - -namespace FractalPainting.Application.Actions; - -public class UpdateImageSettingsAction : IApiAction, INeed -{ - private IImageSettingsProvider imageSettingsProvider = null!; - - public void SetDependency(IImageSettingsProvider dependency) - { - imageSettingsProvider = dependency; - } - - public string Endpoint => "/settings"; - public string HttpMethod => "PUT"; - - public int Perform(Stream inputStream, Stream outputStream) - { - var updatedSettings = JsonSerializer.Deserialize(inputStream); - var settings = imageSettingsProvider.ImageSettings; - settings.Height = updatedSettings?.Height ?? settings.Height; - settings.Width = updatedSettings?.Width ?? settings.Width; - JsonSerializer.Serialize(outputStream, settings); - - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Actions/UpdatePaletteSettingsAction.cs b/FractalPainter/Application/Actions/UpdatePaletteSettingsAction.cs deleted file mode 100644 index 016d73eb..00000000 --- a/FractalPainter/Application/Actions/UpdatePaletteSettingsAction.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; - -namespace FractalPainting.Application.Actions; - -public class UpdatePaletteSettingsAction : IApiAction, INeed -{ - private Palette palette = null!; - - public void SetDependency(Palette dependency) - { - palette = dependency; - } - - public string Endpoint => "/palette"; - - public string HttpMethod => "PUT"; - - public int Perform(Stream inputStream, Stream outputStream) - { - var updatedPalette = JsonSerializer.Deserialize(inputStream); - palette.BackgroundColor = updatedPalette?.BackgroundColor ?? palette.BackgroundColor; - palette.PrimaryColor = updatedPalette?.PrimaryColor ?? palette.PrimaryColor; - palette.SecondaryColor = updatedPalette?.SecondaryColor ?? palette.SecondaryColor; - JsonSerializer.Serialize(outputStream, palette); - - return (int)HttpStatusCode.OK; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/App.cs b/FractalPainter/Application/App.cs deleted file mode 100644 index 828dbec9..00000000 --- a/FractalPainter/Application/App.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Net; -using System.Text.Json; -using FractalPainting.Application.Actions; -using FractalPainting.Application.Models; -using FractalPainting.Infrastructure.Common; -using FractalPainting.Infrastructure.Injection; -using FractalPainting.Infrastructure.UiActions; -using Microsoft.Extensions.DependencyInjection; - -namespace FractalPainting.Application; - -internal sealed class App -{ - private const string Endpoint = "http://localhost:8080/"; - private readonly HttpListener httpListener; - private readonly IReadOnlyDictionary routeActions; - - public App() : this( - new IApiAction[] - { - new KochFractalAction(), - new DragonFractalAction(), - new UpdateImageSettingsAction(), - new GetImageSettingsAction(), - new UpdatePaletteSettingsAction(), - new GetPaletteSettingsAction() - }) - { - } - - public App(IEnumerable actions) - { - var actionsArray = actions.ToArray(); - httpListener = new HttpListener(); - httpListener.Prefixes.Add(Endpoint); - routeActions = actionsArray.ToDictionary(action => $"{action.HttpMethod} {action.Endpoint}", action => action); - DependencyInjector.Inject(actionsArray, CreateSettingsManager().Load()); - DependencyInjector.Inject(actionsArray, new Palette()); - } - - public async Task Run() - { - httpListener.Start(); - Console.WriteLine($"Listening at {Endpoint}"); - while (true) - { - var context = await httpListener.GetContextAsync(); - - // Обработка запроса - try - { - var actionKey = $"{context.Request.HttpMethod} {context.Request.Url!.AbsolutePath}"; - - if (actionKey == "GET /") - { - context.Response.ContentType = "text/html"; - await using var fileStream = File.OpenRead(Path.Join(".", "static", "index.html")); - await fileStream.CopyToAsync(context.Response.OutputStream); - continue; - } - - if (!routeActions.TryGetValue(actionKey, out var action)) - { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; - context.Response.Close(); - continue; - } - - action.Perform(context.Request.InputStream, context.Response.OutputStream); - } - // Перехват ошибок - catch (Exception e) - { - context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - await JsonSerializer.SerializeAsync(context.Response.OutputStream, new ResultError(e.Message)); - } - finally - { - context.Response.Close(); - } - } - // ReSharper disable once FunctionNeverReturns - } - - private static SettingsManager CreateSettingsManager() - { - var services = new ServiceCollection(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - var sp = services.BuildServiceProvider(); - var settingsManager = sp.GetRequiredService(); - - return settingsManager; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/AppSettings.cs b/FractalPainter/Application/AppSettings.cs deleted file mode 100644 index fdd68373..00000000 --- a/FractalPainter/Application/AppSettings.cs +++ /dev/null @@ -1,8 +0,0 @@ -using FractalPainting.Infrastructure.Common; - -namespace FractalPainting.Application; - -public class AppSettings : IImageSettingsProvider -{ - public ImageSettings ImageSettings { get; init; } = null!; -} \ No newline at end of file diff --git a/FractalPainter/Application/FigureJsonConverter.cs b/FractalPainter/Application/FigureJsonConverter.cs deleted file mode 100644 index b3c5bc61..00000000 --- a/FractalPainter/Application/FigureJsonConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using FractalPainting.Application.Models; - -namespace FractalPainting.Application; - -internal sealed class FigureJsonConverter : JsonConverter
-{ - public override Figure? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } - - public override void Write(Utf8JsonWriter writer, Figure value, JsonSerializerOptions options) - { - switch (value) - { - case Line line: - writer.WriteRawValue(JsonSerializer.Serialize(line)); - return; - - case Rectangle rect: - writer.WriteRawValue(JsonSerializer.Serialize(rect)); - break; - } - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Fractals/DragonPainter.cs b/FractalPainter/Application/Fractals/DragonPainter.cs deleted file mode 100644 index 21799c16..00000000 --- a/FractalPainter/Application/Fractals/DragonPainter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Drawing; -using FractalPainting.Application.Models; -using FractalPainting.Infrastructure.Common; -using Color = FractalPainting.Application.Models.Color; -using Point = FractalPainting.Application.Models.Point; -using Rectangle = FractalPainting.Application.Models.Rectangle; - -namespace FractalPainting.Application.Fractals; - -public class DragonPainter(DragonSettings settings, IImageSettingsProvider imageSettingsProvider) -{ - public IReadOnlyCollection
Paint() - { - var imageSettings = imageSettingsProvider.ImageSettings; - var size = Math.Min(imageSettings.Width, imageSettings.Height) / 2.1f; - - var backgroundColor = new Color(0, 0, 0); - var foregroundColor = new Color(255, 255, 0); - - var figures = new List
(); - figures.Add(new Rectangle(imageSettings.Width, imageSettings.Height, new Point(0, 0), backgroundColor)); - var r = new Random(); - var cosa = (float)Math.Cos(settings.Angle1); - var sina = (float)Math.Sin(settings.Angle1); - var cosb = (float)Math.Cos(settings.Angle2); - var sinb = (float)Math.Sin(settings.Angle2); - var shiftX = settings.ShiftX * size * 0.8f; - var shiftY = settings.ShiftY * size * 0.8f; - var scale = settings.Scale; - var p = new PointF(0, 0); - foreach (var _ in Enumerable.Range(0, settings.IterationsCount)) - { - figures.Add(new Rectangle(1, 1, - new Point((int)(imageSettings.Width / 3f + p.X), (int)(imageSettings.Height / 2f + p.Y)), - foregroundColor)); - if (r.Next(0, 2) == 0) - p = new PointF(scale * (p.X * cosa - p.Y * sina), scale * (p.X * sina + p.Y * cosa)); - else - p = new PointF(scale * (p.X * cosb - p.Y * sinb) + shiftX, - scale * (p.X * sinb + p.Y * cosb) + shiftY); - } - - return figures; - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Fractals/DragonSettings.cs b/FractalPainter/Application/Fractals/DragonSettings.cs deleted file mode 100644 index 1553078b..00000000 --- a/FractalPainter/Application/Fractals/DragonSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace FractalPainting.Application.Fractals; - -public class DragonSettings -{ - public double Angle1 { get; set; } = Math.PI / 4; - public double Angle2 { get; set; } = 3 * Math.PI / 4; - public float ShiftX { get; set; } = 1; - public float ShiftY { get; set; } = 0; - public float Scale { get; set; } = (float)(1 / Math.Sqrt(2)); - public int IterationsCount { get; set; } = 20000; -} \ No newline at end of file diff --git a/FractalPainter/Application/Fractals/KochPainter.cs b/FractalPainter/Application/Fractals/KochPainter.cs deleted file mode 100644 index 2ea61a2b..00000000 --- a/FractalPainter/Application/Fractals/KochPainter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using FractalPainting.Application.Models; -using FractalPainting.Infrastructure.Common; -using Color = FractalPainting.Application.Models.Color; -using Point = FractalPainting.Application.Models.Point; -using Rectangle = FractalPainting.Application.Models.Rectangle; - -namespace FractalPainting.Application.Fractals; - -public class KochPainter(Palette palette, IImageSettingsProvider imageSettingsProvider) -{ - public IReadOnlyCollection
Paint() - { - var imageSettings = imageSettingsProvider.ImageSettings; - var figures = new List
(); - var bgColor = palette.BackgroundColor; - figures.Add(new Rectangle(imageSettings.Width, imageSettings.Height, new Point(0, 0), - new Color(bgColor.R, bgColor.G, bgColor.B))); - DrawSegment(figures, 0, imageSettings.Height * 0.9f, imageSettings.Width, imageSettings.Height * 0.9f, true); - return figures; - } - - private void DrawSegment(List
figures, float x0, float y0, float x1, float y1, bool primaryColor) - { - var len2 = (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1); - if (len2 < 4) - { - if (y0 < 0 || y1 < 0) return; - var color = primaryColor ? palette.PrimaryColor : palette.SecondaryColor; - figures.Add(new Line(new Point((int)x0, (int)y0), new Point((int)x1, (int)y1), - new Color(color.R, color.G, color.B))); - } - else - { - var vx = (x1 - x0) / 3; - var vy = (y1 - y0) / 3; - DrawSegment(figures, x0, y0, x0 + vx, y0 + vy, primaryColor); - var k = (float)Math.Sqrt(3) / 2f; - var px = (x0 + x1) / 2 + vy * k; - var py = (y0 + y1) / 2 - vx * k; - DrawSegment(figures, x0 + vx, y0 + vy, px, py, !primaryColor); - DrawSegment(figures, px, py, x0 + 2 * vx, y0 + 2 * vy, !primaryColor); - DrawSegment(figures, x0 + 2 * vx, y0 + 2 * vy, x1, y1, primaryColor); - } - } -} \ No newline at end of file diff --git a/FractalPainter/Application/Models/Color.cs b/FractalPainter/Application/Models/Color.cs deleted file mode 100644 index 2bcef8c8..00000000 --- a/FractalPainter/Application/Models/Color.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace FractalPainting.Application.Models; - -public sealed record Color(byte R, byte G, byte B); \ No newline at end of file diff --git a/FractalPainter/Application/Models/Figure.cs b/FractalPainter/Application/Models/Figure.cs deleted file mode 100644 index 920b5bc4..00000000 --- a/FractalPainter/Application/Models/Figure.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FractalPainting.Application.Models; - -public abstract record Figure -{ - public abstract string Type { get; } -}; \ No newline at end of file diff --git a/FractalPainter/Application/Models/Line.cs b/FractalPainter/Application/Models/Line.cs deleted file mode 100644 index 21725c22..00000000 --- a/FractalPainter/Application/Models/Line.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FractalPainting.Application.Models; - -internal sealed record Line(Point Begin, Point End, Color Color) : Figure -{ - public override string Type => "Line"; -} \ No newline at end of file diff --git a/FractalPainter/Application/Models/Point.cs b/FractalPainter/Application/Models/Point.cs deleted file mode 100644 index 3b53622d..00000000 --- a/FractalPainter/Application/Models/Point.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace FractalPainting.Application.Models; - -public sealed record Point(int X, int Y); \ No newline at end of file diff --git a/FractalPainter/Application/Models/Rectangle.cs b/FractalPainter/Application/Models/Rectangle.cs deleted file mode 100644 index 348e1e91..00000000 --- a/FractalPainter/Application/Models/Rectangle.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FractalPainting.Application.Models; - -public sealed record Rectangle(int Width, int Height, Point Begin, Color Color) : Figure -{ - public override string Type => "Rectangle"; -} \ No newline at end of file diff --git a/FractalPainter/Application/Models/ResultError.cs b/FractalPainter/Application/Models/ResultError.cs deleted file mode 100644 index 93987740..00000000 --- a/FractalPainter/Application/Models/ResultError.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace FractalPainting.Application.Models; - -internal sealed record ResultError(string Message); diff --git a/FractalPainter/Application/SettingsManager.cs b/FractalPainter/Application/SettingsManager.cs deleted file mode 100644 index 627dafcb..00000000 --- a/FractalPainter/Application/SettingsManager.cs +++ /dev/null @@ -1,40 +0,0 @@ -using FractalPainting.Infrastructure.Common; - -namespace FractalPainting.Application; - -public class SettingsManager(IObjectSerializer serializer, IBlobStorage storage) -{ - private readonly string settingsFilename = "app.settings"; - - public AppSettings Load() - { - try - { - var data = storage.Get(settingsFilename); - if (data == null) - { - var defaultSettings = CreateDefaultSettings(); - Save(defaultSettings); - return defaultSettings; - } - return serializer.Deserialize(data)!; - } - catch (Exception) - { - return CreateDefaultSettings(); - } - } - - private static AppSettings CreateDefaultSettings() - { - return new AppSettings - { - ImageSettings = new ImageSettings() - }; - } - - private void Save(AppSettings settings) - { - storage.Set(settingsFilename, serializer.Serialize(settings)); - } -} \ No newline at end of file diff --git a/FractalPainter/Application/static/index.html b/FractalPainter/Application/static/index.html deleted file mode 100644 index 29857108..00000000 --- a/FractalPainter/Application/static/index.html +++ /dev/null @@ -1,520 +0,0 @@ - - - - - FractalPainting - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/FileBlobStorage.cs b/FractalPainter/Infrastructure/Common/FileBlobStorage.cs deleted file mode 100644 index 2b1075f5..00000000 --- a/FractalPainter/Infrastructure/Common/FileBlobStorage.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace FractalPainting.Infrastructure.Common; - -public class FileBlobStorage : IBlobStorage -{ - public byte[]? Get(string name) - { - return File.Exists(name) ? File.ReadAllBytes(name) : null; - } - - public void Set(string name, byte[] content) - { - File.WriteAllBytes(name, content); - } -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/IBlobStorage.cs b/FractalPainter/Infrastructure/Common/IBlobStorage.cs deleted file mode 100644 index 14ebfdbc..00000000 --- a/FractalPainter/Infrastructure/Common/IBlobStorage.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FractalPainting.Infrastructure.Common; - -public interface IBlobStorage -{ - byte[]? Get(string name); - void Set(string name, byte[] content); -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/IDragonPainterFactory.cs b/FractalPainter/Infrastructure/Common/IDragonPainterFactory.cs deleted file mode 100644 index b1a887fc..00000000 --- a/FractalPainter/Infrastructure/Common/IDragonPainterFactory.cs +++ /dev/null @@ -1,8 +0,0 @@ -using FractalPainting.Application.Fractals; - -namespace FractalPainting.Infrastructure.Common; - -public interface IDragonPainterFactory -{ - DragonPainter Create(DragonSettings settings); -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/IImageSettingsProvider.cs b/FractalPainter/Infrastructure/Common/IImageSettingsProvider.cs deleted file mode 100644 index 6b6a3857..00000000 --- a/FractalPainter/Infrastructure/Common/IImageSettingsProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FractalPainting.Infrastructure.Common; - -public interface IImageSettingsProvider -{ - ImageSettings ImageSettings { get; } -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/IObjectSerializer.cs b/FractalPainter/Infrastructure/Common/IObjectSerializer.cs deleted file mode 100644 index 3f47929d..00000000 --- a/FractalPainter/Infrastructure/Common/IObjectSerializer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FractalPainting.Infrastructure.Common; - -public interface IObjectSerializer -{ - T? Deserialize(byte[] bytes); - byte[] Serialize(T obj); -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/ImageSettings.cs b/FractalPainter/Infrastructure/Common/ImageSettings.cs deleted file mode 100644 index 0b57342c..00000000 --- a/FractalPainter/Infrastructure/Common/ImageSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace FractalPainting.Infrastructure.Common; - -public class ImageSettings -{ - public int Width { get; set; } = 300; - public int Height { get; set; } = 300; -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/Palette.cs b/FractalPainter/Infrastructure/Common/Palette.cs deleted file mode 100644 index c74a2b1a..00000000 --- a/FractalPainter/Infrastructure/Common/Palette.cs +++ /dev/null @@ -1,10 +0,0 @@ -using FractalPainting.Application.Models; - -namespace FractalPainting.Infrastructure.Common; - -public class Palette -{ - public Color PrimaryColor { get; set; } = new(255, 255, 0); // 255 255 0 - public Color SecondaryColor { get; set; } = new(255, 0, 0); // 255 0 0 - public Color BackgroundColor { get; set; } = new(0, 0, 139); // 0 0 139 -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Common/XmlObjectSerializer.cs b/FractalPainter/Infrastructure/Common/XmlObjectSerializer.cs deleted file mode 100644 index b14c36a2..00000000 --- a/FractalPainter/Infrastructure/Common/XmlObjectSerializer.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Xml.Serialization; - -namespace FractalPainting.Infrastructure.Common; - -public class XmlObjectSerializer : IObjectSerializer -{ - public T? Deserialize(byte[] bytes) - { - using var ms = new MemoryStream(bytes); - return (T) new XmlSerializer(typeof(T)).Deserialize(ms)!; - } - - public byte[] Serialize(T obj) - { - using var ms = new MemoryStream(); - new XmlSerializer(typeof(T)).Serialize(ms, obj); - return ms.ToArray(); - } -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Injection/DependencyInjector.cs b/FractalPainter/Infrastructure/Injection/DependencyInjector.cs deleted file mode 100644 index 98e0812d..00000000 --- a/FractalPainter/Infrastructure/Injection/DependencyInjector.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections; - -namespace FractalPainting.Infrastructure.Injection; - -public class DependencyInjector -{ - public static void Inject(object service, TDependency dependency) - { - var need = service as INeed; - need?.SetDependency(dependency); - } - - public static void Inject(IEnumerable services, TDependency dependency) - { - foreach (var service in services) - Inject(service, dependency); - } -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/Injection/INeed.cs b/FractalPainter/Infrastructure/Injection/INeed.cs deleted file mode 100644 index fada0114..00000000 --- a/FractalPainter/Infrastructure/Injection/INeed.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FractalPainting.Infrastructure.Injection; - -public interface INeed -{ - void SetDependency(T dependency); -} \ No newline at end of file diff --git a/FractalPainter/Infrastructure/UiActions/IApiAction.cs b/FractalPainter/Infrastructure/UiActions/IApiAction.cs deleted file mode 100644 index 04f96862..00000000 --- a/FractalPainter/Infrastructure/UiActions/IApiAction.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace FractalPainting.Infrastructure.UiActions; - -public interface IApiAction -{ - string Endpoint { get; } - - string HttpMethod { get; } - - int Perform(Stream inputStream, Stream outputStream); -} \ No newline at end of file diff --git a/FractalPainter/Program.cs b/FractalPainter/Program.cs deleted file mode 100644 index 5ba58fc2..00000000 --- a/FractalPainter/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using FractalPainting.Application; -using Microsoft.Extensions.DependencyInjection; - -var services = new ServiceCollection(); - -// services.AddSingleton(); -// services.AddSingleton(); -// -// var serviceProvider = services.BuildServiceProvider(); -// var app = serviceProvider.GetRequiredService. Изучите код KochFractalAction. - Изучите механику работы INeed и DependencyInjector. - Оцените такой подход к управлению зависимостями. - -3. Рефакторинг. Измените класс KochFractalAction так, - чтобы его зависимости IImageSettingsProvider и Palette инжектировались - явно через конструктор, без использования интерфейса INeed. - -Подсказка. Сложность в том, чтобы в App и KochFractalAction -оказались ссылки на один и тот же объект AppSettings. - -Убедитесь, что настройка палитры для рисования кривой Коха всё ещё работает. - -4. Еще рефакторинг. Изучите KochFractalAction и поймите, что - на самом деле IImageSettingsProvider и Palette ему не нужны. Измените его так, - чтобы он принимал только KochPainter. - -5. Фабрика. Аналогично удалите INeed, - и явное использование контейнера из класса DragonFractalAction. - Дополнительное ограничение — нельзя менять публичный интерфейс DragonPainter. - Особенность в том, что одна из зависимостей DragonPainter — - DragonSettings оказывается известной только в процессе работы экшена. - Из-за этого вы не можете просить инжектировать в конструктор уже готовый Painter. - Вместо этого инжектируйте фабрику DragonPainter-ов. В проекте уже есть интерфейс IDragonPainterFactory. - Создайте класс, реализующий этот интерфейс и проверьте, что изменение настроек работает - -6. Новая зависимость. Переведите DragonPainter на использование цветов палитры, - как это сделано в KochPainter. - -Убедитесь, что экшен настройки палитры работает как надо. -Если вы всё сделали правильно, то для добавления зависимости вам не пришлось -править код работы с контейнером вообще. Магия! - -7. Избавьтесь от остальных использований INeed и удалите этот интерфейс - и класс DependencyInjector из проекта. diff --git a/FractalPainter/app.settings b/FractalPainter/app.settings deleted file mode 100644 index 30095b56..00000000 --- a/FractalPainter/app.settings +++ /dev/null @@ -1,8 +0,0 @@ - - - . - - 300 - 300 - - \ No newline at end of file diff --git a/FractalPainter/di.csproj b/FractalPainter/di.csproj deleted file mode 100644 index d4847a1d..00000000 --- a/FractalPainter/di.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - Exe - net8.0 - enable - enable - FractalPainting - FractalPainting - - - - - - - - - - - - diff --git a/TagsCloudVisualization/FilesProcessing/IFileProcessor.cs b/TagsCloudVisualization/FilesProcessing/IFileProcessor.cs new file mode 100644 index 00000000..4ab53844 --- /dev/null +++ b/TagsCloudVisualization/FilesProcessing/IFileProcessor.cs @@ -0,0 +1,5 @@ +namespace TagsCloudVisualization.FilesProcessing; +public interface IFileProcessor +{ + IEnumerable ReadWords(string filePath); +} diff --git a/TagsCloudVisualization/FilesProcessing/TxtFileProcessor.cs b/TagsCloudVisualization/FilesProcessing/TxtFileProcessor.cs new file mode 100644 index 00000000..c3a51a0d --- /dev/null +++ b/TagsCloudVisualization/FilesProcessing/TxtFileProcessor.cs @@ -0,0 +1,13 @@ +namespace TagsCloudVisualization.FilesProcessing; +public class TxtFileProcessor : IFileProcessor +{ + public IEnumerable ReadWords(string filePath) + { + if (!File.Exists(filePath)) + throw new FileNotFoundException(filePath); + + return File.ReadLines(filePath) + .Select(line => line.Trim()) + .Where(word => !string.IsNullOrEmpty(word)); + } +} \ No newline at end of file diff --git a/TagsCloudVisualization/IMorphologicalAnalyzer.cs b/TagsCloudVisualization/IMorphologicalAnalyzer.cs new file mode 100644 index 00000000..b447a19a --- /dev/null +++ b/TagsCloudVisualization/IMorphologicalAnalyzer.cs @@ -0,0 +1,6 @@ +namespace TagsCloudVisualization; + +public interface IMorphologicalAnalyzer +{ + bool IsExcludedWord(string word, string excludedPartOfSpeech); +} diff --git a/TagsCloudVisualization/IRectangleGenerator.cs b/TagsCloudVisualization/IRectangleGenerator.cs new file mode 100644 index 00000000..ffaaf53b --- /dev/null +++ b/TagsCloudVisualization/IRectangleGenerator.cs @@ -0,0 +1,8 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +public interface IRectangleGenerator +{ + public List ExecuteRectangles(Dictionary frequencyRectangles, Point center); +} \ No newline at end of file diff --git a/TagsCloudVisualization/IWordHandler.cs b/TagsCloudVisualization/IWordHandler.cs new file mode 100644 index 00000000..3fd477b3 --- /dev/null +++ b/TagsCloudVisualization/IWordHandler.cs @@ -0,0 +1,6 @@ +namespace TagsCloudVisualization; + +public interface IWordHandler +{ + public Dictionary ProcessFile(string filePath, string option); +} \ No newline at end of file diff --git a/TagsCloudVisualization/ManagingRendering/ArchimedeanSpiral.cs b/TagsCloudVisualization/ManagingRendering/ArchimedeanSpiral.cs new file mode 100644 index 00000000..afa17328 --- /dev/null +++ b/TagsCloudVisualization/ManagingRendering/ArchimedeanSpiral.cs @@ -0,0 +1,32 @@ +using System.Drawing; + +namespace TagsCloudVisualization.ManagingRendering; + +public class ArchimedeanSpiral : ISpiral +{ + private readonly Point startPoint; + private readonly double radiusStep; + private readonly double angleStep; + private double currentAngle; + + public ArchimedeanSpiral(Point startPoint, double radiusStep = 1) + { + if (radiusStep <= 0) throw new ArgumentOutOfRangeException(nameof(radiusStep), "radius step must be positive"); + + angleStep = Math.PI / 180; + this.startPoint = startPoint; + this.radiusStep = radiusStep; + currentAngle = 0; + } + + public Point GetNextPoint() + { + var radius = radiusStep * currentAngle; + + var x = (int)(startPoint.X + radius * Math.Cos(currentAngle)); + var y = (int)(startPoint.Y + radius * Math.Sin(currentAngle)); + currentAngle += angleStep; + + return new Point(x, y); + } +} \ No newline at end of file diff --git a/TagsCloudVisualization/ManagingRendering/CloudTags.cs b/TagsCloudVisualization/ManagingRendering/CloudTags.cs new file mode 100644 index 00000000..23ba1bcb --- /dev/null +++ b/TagsCloudVisualization/ManagingRendering/CloudTags.cs @@ -0,0 +1,82 @@ +using System.Drawing; + +namespace TagsCloudVisualization.ManagingRendering; + +public class CircularCloudLayouter +{ + public CircularCloudLayouter(ISpiral spiral, Point center){ + this.spiral = spiral; + this.centerСloud = center; + } + private Point centerСloud; + private readonly ISpiral spiral; + + private List rectangles = []; + + public Point CenterCloud => centerСloud; + + public List GetRectangles => rectangles; + + public Rectangle PutNextRectangle(Size rectangleSize) + { + if (rectangleSize.IsEmpty) + { + throw new ArgumentNullException(nameof(rectangleSize), "rectangle is empty"); + } + if (rectangleSize.Height <= 0 || rectangleSize.Width <= 0) + { + throw new ArgumentOutOfRangeException(nameof(rectangleSize), "side less or equal zero"); + } + Rectangle tempRectangle; + do + { + Point nextPoint = spiral.GetNextPoint(); + tempRectangle = new Rectangle(new Point(nextPoint.X, nextPoint.Y), rectangleSize); + } + while (IsRectangleIntersect(tempRectangle)); + if (rectangles.Count > 1) + tempRectangle = TryToMoveRectangleNearToCenter(tempRectangle); + rectangles.Add(tempRectangle); + return tempRectangle; + } + + private Rectangle TryToMoveRectangleNearToCenter(Rectangle rectangle) + { + while (true) + { + var tempRectangle = rectangle; + if (rectangle.X != centerСloud.X) + { + var directionX = rectangle.X < centerСloud.X ? 1 : -1; + rectangle = MovingRectangleIfPossible(rectangle, true, directionX); + } + if (rectangle.Y != centerСloud.Y) + { + var directionY = rectangle.Y < centerСloud.Y ? 1 : -1; + rectangle = MovingRectangleIfPossible(rectangle, false, directionY); + } + + if (tempRectangle.Equals(rectangle)) + break; + } + return rectangle; + } + + private Rectangle MovingRectangleIfPossible(Rectangle rectangle, bool isX, int direction) + { + var shiftPoint = isX ? new Point(direction, 0) : new Point(0, direction); + var movedRectangle = rectangle with + { + Location = new Point(rectangle.X + shiftPoint.X, rectangle.Y + shiftPoint.Y) + }; + + if (!IsRectangleIntersect(movedRectangle)) + { + rectangle = movedRectangle; + } + return rectangle; + } + + private bool IsRectangleIntersect(Rectangle rectangleChecked) => + rectangles.Any(rectangleChecked.IntersectsWith); +} \ No newline at end of file diff --git a/TagsCloudVisualization/ManagingRendering/FermatSpiral.cs b/TagsCloudVisualization/ManagingRendering/FermatSpiral.cs new file mode 100644 index 00000000..896fc068 --- /dev/null +++ b/TagsCloudVisualization/ManagingRendering/FermatSpiral.cs @@ -0,0 +1,31 @@ +using System.Drawing; + +namespace TagsCloudVisualization.ManagingRendering; + +public class FermatSpiral : ISpiral +{ + private readonly Point startPoint; + private readonly double scaleFactor; + private double currentAngle; + + public FermatSpiral(Point startPoint, double scaleFactor = 1) + { + if (scaleFactor <= 0) + throw new ArgumentOutOfRangeException(nameof(scaleFactor), "Scale factor must be positive"); + + this.startPoint = startPoint; + this.scaleFactor = scaleFactor; + this.currentAngle = 0; + } + + public Point GetNextPoint() + { + var radius = scaleFactor * Math.Sqrt(currentAngle); + var x = (int)(startPoint.X + radius * Math.Cos(currentAngle)); + var y = (int)(startPoint.Y + radius * Math.Sin(currentAngle)); + + currentAngle += Math.PI / 36; + + return new Point(x, y); + } +} diff --git a/TagsCloudVisualization/ManagingRendering/ISpiral.cs b/TagsCloudVisualization/ManagingRendering/ISpiral.cs new file mode 100644 index 00000000..bd7e9790 --- /dev/null +++ b/TagsCloudVisualization/ManagingRendering/ISpiral.cs @@ -0,0 +1,7 @@ +using System.Drawing; + +namespace TagsCloudVisualization.ManagingRendering; + +public interface ISpiral{ + public Point GetNextPoint(); +} \ No newline at end of file diff --git a/TagsCloudVisualization/MorphologicalProcessing.cs b/TagsCloudVisualization/MorphologicalProcessing.cs new file mode 100644 index 00000000..4264b88d --- /dev/null +++ b/TagsCloudVisualization/MorphologicalProcessing.cs @@ -0,0 +1,37 @@ +using System.Text.RegularExpressions; +using MyStemWrapper; + +namespace TagsCloudVisualization; + +public class MorphologicalProcessing(MyStem mystem) : IMorphologicalAnalyzer +{ + private readonly MyStem _mystem = mystem; + + public bool IsExcludedWord(string word, string excludedPartOfSpeech) + { + var analysisResult = _mystem.Analysis(word); + + if (string.IsNullOrWhiteSpace(excludedPartOfSpeech)) + { + return ContainsPartOfSpeech(analysisResult, ["CONJ", "INTJ", "PART", "PR", "SPRO", "COM"]); + } + var excludedParts = excludedPartOfSpeech.Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(part => part.Trim().ToUpper()) + .ToArray(); + + return ContainsPartOfSpeech(analysisResult, [.. excludedParts, "CONJ", "INTJ", "PART", "PR", "SPRO", "COM"]); + } + + private static bool ContainsPartOfSpeech(string analysisResult, string[] partsOfSpeech) + { + foreach (var part in partsOfSpeech) + { + var regex = $@"\b.*?={Regex.Escape(part)}\W"; + if (Regex.IsMatch(analysisResult, regex, RegexOptions.IgnoreCase)) + { + return true; + } + } + return false; + } +} diff --git a/TagsCloudVisualization/RectangleInformation.cs b/TagsCloudVisualization/RectangleInformation.cs new file mode 100644 index 00000000..dfcd3b7c --- /dev/null +++ b/TagsCloudVisualization/RectangleInformation.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +public record RectangleInformation(Rectangle Rectangle, string Word) +{ + public readonly Rectangle rectangle = Rectangle; + public readonly string word = Word; +} \ No newline at end of file diff --git a/TagsCloudVisualization/RectanglesGenerator.cs b/TagsCloudVisualization/RectanglesGenerator.cs new file mode 100644 index 00000000..8b203d5d --- /dev/null +++ b/TagsCloudVisualization/RectanglesGenerator.cs @@ -0,0 +1,38 @@ +using System.Drawing; +using TagsCloudVisualization.ManagingRendering; + +namespace TagsCloudVisualization; + +public class RectangleGenerator(ISpiral spiral) : IRectangleGenerator +{ + readonly ISpiral spiral = spiral; + private static readonly List rectangleInformation = []; + private static readonly Dictionary rectangleData = []; + private static void GenerateRectangles(Dictionary frequencyRectangles) + { + var totalCountWords = frequencyRectangles.Sum(x => x.Value); + var sortedWords = frequencyRectangles.OrderByDescending(word => word.Value); + foreach (var word in sortedWords) + { + var width = word.Value * 500 / totalCountWords; + var height = word.Value * 300 / totalCountWords; + var rectangleSize = new Size(Math.Max(width, 1), Math.Max(height, 1)); + rectangleData.Add(word.Key, rectangleSize); + } + } + private List PutRectangles(Point center) + { + var layouter = new CircularCloudLayouter(spiral, center); + foreach (var rect in rectangleData) + { + var tempRect = layouter.PutNextRectangle(rect.Value); + rectangleInformation.Add(new RectangleInformation(tempRect, rect.Key)); + } + return rectangleInformation; + } + public List ExecuteRectangles(Dictionary frequencyRectangles, Point center) + { + GenerateRectangles(frequencyRectangles); + return PutRectangles(center); + } +} \ No newline at end of file diff --git a/TagsCloudVisualization/TagsCloudVisualization.csproj b/TagsCloudVisualization/TagsCloudVisualization.csproj new file mode 100644 index 00000000..a7d399df --- /dev/null +++ b/TagsCloudVisualization/TagsCloudVisualization.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + false + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/TagsCloudVisualization/WordHandler.cs b/TagsCloudVisualization/WordHandler.cs new file mode 100644 index 00000000..b7a9c4f9 --- /dev/null +++ b/TagsCloudVisualization/WordHandler.cs @@ -0,0 +1,32 @@ +using TagsCloudVisualization.FilesProcessing; +namespace TagsCloudVisualization; + +public class WordHandler : IWordHandler +{ + public WordHandler(IMorphologicalAnalyzer morphologicalAnalyzer, IFileProcessor fileProcessor) + { + _morphologicalAnalyzer = morphologicalAnalyzer; + _fileProcessor = fileProcessor; + } + private readonly Dictionary keyValueWords = []; + private readonly IMorphologicalAnalyzer _morphologicalAnalyzer; + private readonly IFileProcessor _fileProcessor; + + public Dictionary ProcessFile(string filePath, string option) + { + var words = _fileProcessor.ReadWords(filePath); + + foreach (var word in words) + { + var normalizedWord = word.ToLower(); + if (!_morphologicalAnalyzer.IsExcludedWord(word, option)) + { + if (keyValueWords.ContainsKey(normalizedWord)) + keyValueWords[normalizedWord]++; + else + keyValueWords[normalizedWord] = 1; + } + } + return keyValueWords; + } +} \ No newline at end of file diff --git a/TestsTagsCloudVisualization/TestsSpiral.cs b/TestsTagsCloudVisualization/TestsSpiral.cs new file mode 100644 index 00000000..361e6c3c --- /dev/null +++ b/TestsTagsCloudVisualization/TestsSpiral.cs @@ -0,0 +1,40 @@ +using FluentAssertions; +using System.Drawing; +using TagsCloudVisualization.ManagingRendering; + +namespace TagsCloudVisualizationTests; + +public class TestsSpiral +{ + + ArchimedeanSpiral currentSpiral; + [SetUp] + public void SetUp() + { + currentSpiral = new ArchimedeanSpiral(new Point(0, 0)); + } + + [Test] + public void Spiral_ThrowingWhenRadiusNonPositive() + { + Action action = new Action(() => new ArchimedeanSpiral(new Point(0, 0), -9)); + action.Should().Throw().Which.Message.Should().Contain("radius step must be positive"); + } + + [Test] + public void GetNextPoint_CenterPointSetting() + { + currentSpiral.GetNextPoint().Should().Be(new Point(0, 0)); + } + + [Test] + public void GetNextPoint_SeveralPointSetting() + { + for (int i = 0; i < 180; i++) + { + currentSpiral.GetNextPoint(); + } + currentSpiral.GetNextPoint().Should().Be(new Point((int)-Math.PI, 0)); + } + +} \ No newline at end of file diff --git a/TestsTagsCloudVisualization/TestsTagsCloudVisualization.cs b/TestsTagsCloudVisualization/TestsTagsCloudVisualization.cs new file mode 100644 index 00000000..e09cbf27 --- /dev/null +++ b/TestsTagsCloudVisualization/TestsTagsCloudVisualization.cs @@ -0,0 +1,167 @@ +using FluentAssertions; +using System.Drawing; +using TagsCloudVisualization.ManagingRendering; +using NUnit.Framework.Interfaces; +using DrawingTagsCloudVisualization; +using TagsCloudVisualization; + + +namespace TagsCloudVisualizationTests; + +public class TestsCloudVisualization +{ + private CircularCloudLayouter circularCloudLayouter; + + [SetUp] + public void SetUp() + { + var startPoint = new Point(0, 0); + circularCloudLayouter = new CircularCloudLayouter(new ArchimedeanSpiral(startPoint), startPoint); + } + + [TearDown] + public void TearDown() + { + var context = TestContext.CurrentContext; + if (context.Result.Outcome == ResultState.Failure) + { + var rectanglesInfo = new List(); + ImageSaver drawingTagsCloud = new(new StandartTagsCloudDrawer()); + var pathToSave = context.Test.MethodName + ".png"; + drawingTagsCloud.SaveToFile(pathToSave, 400, 400, "white", rectanglesInfo); //сохраняется в bin + Console.WriteLine($"Tag cloud visualization saved to file {pathToSave}"); + } + } + + [Test] + public void CircularCloudLayouter_SettingCenter() + { + var center = new Point(2, 4); + CircularCloudLayouter circularLayouter = new CircularCloudLayouter(new ArchimedeanSpiral(center), center); + circularLayouter.CenterCloud.X.Should().Be(2); + circularLayouter.CenterCloud.Y.Should().Be(4); + } + + [Test] + public void CircularCloudLayouter_StartWithoutExceptions() + { + var center = new Point(2, 6); + Action action = new Action(() => new CircularCloudLayouter(new ArchimedeanSpiral(center), center)); + action.Should().NotThrow(); + } + + [Test] + public void PutNextRectangle_ThrowingWhenLengthsNegative() + { + Action action = new Action(() => circularCloudLayouter.PutNextRectangle(new Size(-1, -1))); + action.Should().Throw().Which.Message.Should().Contain("side less or equal zero"); + } + + [Test] + public void PutNextRectangle_ThrowingWhenRectangleEmpty() + { + Action action = new Action(() => circularCloudLayouter.PutNextRectangle(Size.Empty)); + action.Should().Throw().Which.Message.Should().Contain("rectangle is empty"); + } + + [Test] + public void CircularCloudLayouter_RectanglesEmptyAfterInitialization() + { + circularCloudLayouter.GetRectangles.Should().BeEmpty(); + } + + [Test] + public void PutNextRectangle_PutFirstRectangle() + { + Size rectangleSize = new Size(3, 7); + Rectangle expectedRectangle = new Rectangle(new Point(0, 0), rectangleSize); + circularCloudLayouter.PutNextRectangle(rectangleSize); + + circularCloudLayouter.GetRectangles.Should().ContainSingle(x => x == expectedRectangle); + } + + [Test] + public void PutNextRectangle_PutSeveralRectangles() + { + Size rectangleSize = new Size(3, 7); + for (int i = 0; i < 20; i++) + { + circularCloudLayouter.PutNextRectangle(rectangleSize); + } + circularCloudLayouter.GetRectangles.Should().HaveCount(20); + circularCloudLayouter.GetRectangles.Should().AllBeOfType(typeof(Rectangle)); + } + + [Test] + public void PutNextRectangle_FirstFailedTestForCheckTearDown() + { + for (int i = 0; i < 200; i++) + circularCloudLayouter.PutNextRectangle(new Size(8, 5)); + + for (int i = 0; i < 20; i++) + { + circularCloudLayouter.PutNextRectangle(new Size(3, 7)); + } + circularCloudLayouter.GetRectangles.Should().HaveCount(20); + } + + [Test] + public void PutNextRectangle_SecondFailedTestForCheckTearDown() + { + for (int i = 0; i < 150; i++) + circularCloudLayouter.PutNextRectangle(new Size(2, 4)); + + for (int i = 0; i < 200; i++) + { + circularCloudLayouter.PutNextRectangle(new Size(2, 2)); + } + circularCloudLayouter.GetRectangles.Should().HaveCount(20); + } + + [Test] + public void PutNextRectangle_SeveralRectanglesDontIntersect() + { + var rectanglesSizes = new List + { + new Size(10, 5), + new Size(8, 8), + new Size(12, 3), + new Size(6, 10) + }; + + foreach (var size in rectanglesSizes) + { + circularCloudLayouter.PutNextRectangle(size); + } + + List rectanglesTemp = circularCloudLayouter.GetRectangles; + for (int i = 0; i < rectanglesTemp.Count; i++) + { + for (int j = i + 1; j < rectanglesTemp.Count; j++) + rectanglesTemp[i].IntersectsWith(rectanglesTemp[j]).Should().BeFalse(); + } + } + [Test] + public void Test_TagCloud() + { + var rectanglesSizes = new List + { + new Size(10, 5), + new Size(8, 8), + new Size(12, 3), + new Size(6, 10) + }; + + foreach (var size in rectanglesSizes) + { + circularCloudLayouter.PutNextRectangle(size); + } + + List rectanglesTemp = circularCloudLayouter.GetRectangles; + for (int i = 0; i < rectanglesTemp.Count; i++) + { + for (int j = i + 1; j < rectanglesTemp.Count; j++) + rectanglesTemp[i].IntersectsWith(rectanglesTemp[j]).Should().BeFalse(); + } + } +} \ No newline at end of file diff --git a/TestsTagsCloudVisualization/TestsTagsCloudVisualization.csproj b/TestsTagsCloudVisualization/TestsTagsCloudVisualization.csproj new file mode 100644 index 00000000..768edbed --- /dev/null +++ b/TestsTagsCloudVisualization/TestsTagsCloudVisualization.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/di.sln b/di.sln index a50991da..f8419e8f 100644 --- a/di.sln +++ b/di.sln @@ -1,6 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "di", "FractalPainter/di.csproj", "{4B70F6B3-5C20-40D2-BFC9-D95C18D65DD6}" +# +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrawingTagsCloudVisualization", "DrawingTagsCloudVisualization\DrawingTagsCloudVisualization.csproj", "{ED288448-602B-4CC4-9A3F-6826B7C4A750}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudVisualization", "TagsCloudVisualization\TagsCloudVisualization.csproj", "{37F47827-A9ED-4FDD-97DC-418F5221521A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsTagsCloudVisualization", "TestsTagsCloudVisualization\TestsTagsCloudVisualization.csproj", "{4B2F6F86-946B-45CB-8C86-78DB4027A02F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleClient", "ConsoleClient\ConsoleClient.csproj", "{9947D364-443F-43AB-A764-ED71B0DF06A9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +17,24 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4B70F6B3-5C20-40D2-BFC9-D95C18D65DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4B70F6B3-5C20-40D2-BFC9-D95C18D65DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4B70F6B3-5C20-40D2-BFC9-D95C18D65DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4B70F6B3-5C20-40D2-BFC9-D95C18D65DD6}.Release|Any CPU.Build.0 = Release|Any CPU + {ED288448-602B-4CC4-9A3F-6826B7C4A750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED288448-602B-4CC4-9A3F-6826B7C4A750}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED288448-602B-4CC4-9A3F-6826B7C4A750}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED288448-602B-4CC4-9A3F-6826B7C4A750}.Release|Any CPU.Build.0 = Release|Any CPU + {37F47827-A9ED-4FDD-97DC-418F5221521A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37F47827-A9ED-4FDD-97DC-418F5221521A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37F47827-A9ED-4FDD-97DC-418F5221521A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37F47827-A9ED-4FDD-97DC-418F5221521A}.Release|Any CPU.Build.0 = Release|Any CPU + {4B2F6F86-946B-45CB-8C86-78DB4027A02F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B2F6F86-946B-45CB-8C86-78DB4027A02F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B2F6F86-946B-45CB-8C86-78DB4027A02F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B2F6F86-946B-45CB-8C86-78DB4027A02F}.Release|Any CPU.Build.0 = Release|Any CPU + {9947D364-443F-43AB-A764-ED71B0DF06A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9947D364-443F-43AB-A764-ED71B0DF06A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9947D364-443F-43AB-A764-ED71B0DF06A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9947D364-443F-43AB-A764-ED71B0DF06A9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal