diff --git a/TagsCloudContainer/App/ConsoleApp.cs b/TagsCloudContainer/App/ConsoleApp.cs new file mode 100644 index 000000000..b4ce42a04 --- /dev/null +++ b/TagsCloudContainer/App/ConsoleApp.cs @@ -0,0 +1,55 @@ +using System.Drawing.Imaging; +using TagsCloudContainer.App.Extensions; +using TagsCloudContainer.App.Interfaces; +using TagsCloudContainer.DrawRectangle.Interfaces; +using TagsCloudContainer.FileReader; +using TagsCloudContainer.WordProcessing; + +namespace TagsCloudContainer.App; + +public class ConsoleApp : IApp +{ + private readonly FileReaderFactory _readerFactory; + private readonly Settings _settings; + private readonly WordProcessor _processor; + private readonly IDraw _draw; + + public ConsoleApp(FileReaderFactory readerFactory, Settings settings, WordProcessor processor, + IDraw draw) + { + _readerFactory = readerFactory; + _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + _processor = processor; + _draw = draw; + } + + public void Run() + { + var text = GetText(_settings.File); + var boringText = GetText(_settings.BoringWordsFileName); + var words = _processor.ProcessWords(text, boringText); + var bitmap = _draw.CreateImage(words); + var projectDirectory = Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName; + var rnd = new Random(); + bitmap.Save(projectDirectory + "\\Images", $"Rectangles{rnd.Next(1, 1000)}", GetImageFormat(_settings.ImageFormat)); + + } + + private ImageFormat GetImageFormat(string imageFormat) + { + return imageFormat.ToLower() switch + { + "png" => ImageFormat.Png, + "jpeg" => ImageFormat.Jpeg, + _ => throw new NotSupportedException("Unsupported image format.") + }; + } + + private string GetText(string filename) + { + if (!File.Exists(filename)) + throw new ArgumentException($"Файл не найден {filename}"); + + return _readerFactory.GetReader(filename).GetTextFromFile(filename); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/App/Extensions/BitmapExtension.cs b/TagsCloudContainer/App/Extensions/BitmapExtension.cs new file mode 100644 index 000000000..8c5de0f38 --- /dev/null +++ b/TagsCloudContainer/App/Extensions/BitmapExtension.cs @@ -0,0 +1,12 @@ +using System.Drawing; +using System.Drawing.Imaging; + +namespace TagsCloudContainer.App.Extensions; + +public static class BitmapExtension +{ + public static void Save(this Bitmap bitmap, string path, string filename, ImageFormat format) + { + bitmap.Save($"{path}\\{filename}.{format}", format); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/App/Interfaces/IApp.cs b/TagsCloudContainer/App/Interfaces/IApp.cs new file mode 100644 index 000000000..72b3450b2 --- /dev/null +++ b/TagsCloudContainer/App/Interfaces/IApp.cs @@ -0,0 +1,6 @@ +namespace TagsCloudContainer.App.Interfaces; + +public interface IApp +{ + public void Run(); +} \ No newline at end of file diff --git a/TagsCloudContainer/Cloud/CircularCloudLayouter.cs b/TagsCloudContainer/Cloud/CircularCloudLayouter.cs new file mode 100644 index 000000000..0c113dd56 --- /dev/null +++ b/TagsCloudContainer/Cloud/CircularCloudLayouter.cs @@ -0,0 +1,64 @@ +using System.Drawing; + +namespace TagsCloudContainer.Cloud +{ + public class CircularCloudLayouter + { + public List _rectangles; + private readonly SpiralFunction spiralFunction; + private readonly Point _center; + + public CircularCloudLayouter(Point center) + { + _center = center; + _rectangles = new List(); + spiralFunction = new SpiralFunction(center, 2); + } + + public Rectangle PutNextRectangle(Size sizeRectangle) + { + if (sizeRectangle.Width < 0 || sizeRectangle.Height < 0 || sizeRectangle.IsEmpty) + throw new ArgumentException("Width and Height Size should positive"); + + Rectangle rectangle; + + while(true) + { + rectangle = new Rectangle(spiralFunction.GetNextPoint(), sizeRectangle); + if(rectangle.IsIntersectOthersRectangles(_rectangles)) + break; + } + rectangle = MoveRectangleToCenter(rectangle); + _rectangles.Add(rectangle); + return rectangle; + } + + + private Rectangle MoveRectangleToCenter(Rectangle rectangle) + { + + Rectangle newRectangle; + newRectangle = MoveRectangleAxis(rectangle, rectangle.GetCenter().X, _center.X, + new Point(rectangle.GetCenter().X < _center.X ? 1 : -1, 0)); + newRectangle = MoveRectangleAxis(newRectangle, newRectangle.GetCenter().Y, _center.Y, + new Point(0, rectangle.GetCenter().Y < _center.Y ? 1 : -1)); + return newRectangle; + } + + private Rectangle MoveRectangleAxis(Rectangle newRectangle, int currentPosition, int desiredPosition, Point stepPoint) + { + while (newRectangle.IsIntersectOthersRectangles(_rectangles) && desiredPosition != currentPosition) + { + currentPosition += currentPosition < desiredPosition ? 1 : -1; + newRectangle.Location = newRectangle.Location.DecreasingCoordinate(stepPoint); + } + + if (!newRectangle.IsIntersectOthersRectangles(_rectangles)) + { + newRectangle.Location = newRectangle.Location.IncreasingCoordinate(stepPoint); + } + + return newRectangle; + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Cloud/Extensions/RectangleExtension.cs b/TagsCloudContainer/Cloud/Extensions/RectangleExtension.cs new file mode 100644 index 000000000..2a28163e0 --- /dev/null +++ b/TagsCloudContainer/Cloud/Extensions/RectangleExtension.cs @@ -0,0 +1,19 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public static class RectangleExtension +{ + public static Point DecreasingCoordinate(this Point selfPoint, Point otherPoint) => + new(selfPoint.X + otherPoint.X, selfPoint.Y + otherPoint.Y); + + public static Point IncreasingCoordinate(this Point selfPoint, Point otherPoint) => + new(selfPoint.X - otherPoint.X, selfPoint.Y - otherPoint.Y); + + public static Point GetCenter(this Rectangle rectangle) => + new(rectangle.Location.X + rectangle.Width / 2, rectangle.Location.Y + rectangle.Height / 2); + + public static bool IsIntersectOthersRectangles(this Rectangle rectangle, List rectangles) => + rectangles.All(rect => !rectangle.IntersectsWith(rect)); + +} \ No newline at end of file diff --git a/TagsCloudContainer/Cloud/SpiralFunction.cs b/TagsCloudContainer/Cloud/SpiralFunction.cs new file mode 100644 index 000000000..88d05fdf4 --- /dev/null +++ b/TagsCloudContainer/Cloud/SpiralFunction.cs @@ -0,0 +1,26 @@ +using System.Drawing; + +namespace TagsCloudContainer.Cloud +{ + public class SpiralFunction + { + private double angle; + private readonly Point _pastPoint; + private readonly double _step; + + public SpiralFunction(Point start, double step) + { + _pastPoint = start; + _step = step; + } + + public Point GetNextPoint() + { + var newX = (int)(_pastPoint.X + _step * angle * Math.Cos(angle)); + var newY = (int)(_pastPoint.Y + _step * angle * Math.Sin(angle)); + angle += Math.PI / 50; + + return new Point(newX, newY); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Console/CommandLineOptions.cs b/TagsCloudContainer/Console/CommandLineOptions.cs new file mode 100644 index 000000000..8f29ef558 --- /dev/null +++ b/TagsCloudContainer/Console/CommandLineOptions.cs @@ -0,0 +1,35 @@ +//NuGet CommandLineParser + +using System.Drawing.Imaging; +using System.Runtime.CompilerServices; +using CommandLine; + +namespace TagsCloudContainer; + +public class CommandLineOptions +{ + [Option('i', "Input", Required = false, HelpText = "Укажите путь до файла", Default = "../../../TextFiles/Text.docx")] + public string PathToInputFile { get; set; } + + [Option('b', "Boring", Required = false, HelpText = "Укажите путь до файла со скучными словами", Default = "../../../TextFiles/Boring.docx")] + public string PathToBoringWordsFile { get; set; }// = + //@"C:\Users\nikit\RiderProjects\di\TagsCloudContainer\TextFiles\Boring.txt"; + + [Option('c', "Color", Required = false, HelpText = "Цвет слов")] + public string Color { get; set; } = "White"; + + [Option('f', "FontName", Required = false, HelpText = "Тип шрифта")] + public string FontName { get; set; } = "Ariel"; + + [Option('s', "FontSize", Required = false, HelpText = "Размер шрифта")] + public int FontSize { get; set; } = 14; + + [Option('x', "CenterX", Required = false, HelpText = "Координата х для центра")] + public int CenterX { get; set; } = 0; + + [Option('y', "CenterY", Required = false, HelpText = "Координата у для центра")] + public int CenterY { get; set; } = 0; + + [Option('o', "ImageFormat", Required = false, HelpText = "Формат изображения", Default = "png")] + public string ImageFormat { get; set; } +} \ No newline at end of file diff --git a/TagsCloudContainer/Console/Settings.cs b/TagsCloudContainer/Console/Settings.cs new file mode 100644 index 000000000..d553e2e75 --- /dev/null +++ b/TagsCloudContainer/Console/Settings.cs @@ -0,0 +1,14 @@ +using System.Drawing; +using System.Drawing.Imaging; + +namespace TagsCloudContainer; + +public class Settings +{ + public string FontName { get; set; } + public int FontSize { get; set; } + public Color Color { get; set; } + public string File { get; set; } + public string BoringWordsFileName { get; set; } + public string ImageFormat { get; set; } +} \ No newline at end of file diff --git a/TagsCloudContainer/Container/Container.cs b/TagsCloudContainer/Container/Container.cs new file mode 100644 index 000000000..6332bea78 --- /dev/null +++ b/TagsCloudContainer/Container/Container.cs @@ -0,0 +1,38 @@ +using System.Drawing; +using Autofac; +using TagsCloudContainer.App; +using TagsCloudContainer.App.Interfaces; +using TagsCloudContainer.DrawRectangle; +using TagsCloudContainer.Cloud; +using TagsCloudContainer.DrawRectangle.Interfaces; +using TagsCloudContainer.FileReader; +using TagsCloudContainer.WordProcessing; + +namespace TagsCloudContainer; + +public static class Container +{ + public static IContainer SetDiBuilder(CommandLineOptions options) + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(new Settings() + { + Color = Color.FromName(options.Color), + FontName = options.FontName, + FontSize = options.FontSize, + File = options.PathToInputFile, + BoringWordsFileName = options.PathToBoringWordsFile, + ImageFormat = options.ImageFormat + }) + .As(); + builder.RegisterType().AsSelf(); + builder.RegisterType().AsSelf(); + builder.Register(x => + new CircularCloudLayouter(new Point(options.CenterX, options.CenterY))) + .As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + return builder.Build(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/DrawRectangle/Interfaces/IDraw.cs b/TagsCloudContainer/DrawRectangle/Interfaces/IDraw.cs new file mode 100644 index 000000000..8bab86e45 --- /dev/null +++ b/TagsCloudContainer/DrawRectangle/Interfaces/IDraw.cs @@ -0,0 +1,9 @@ +using System.Drawing; +using TagsCloudContainer.WordProcessing; + +namespace TagsCloudContainer.DrawRectangle.Interfaces; + +public interface IDraw +{ + public Bitmap CreateImage(List words); +} \ No newline at end of file diff --git a/TagsCloudContainer/DrawRectangle/RectangleDraw.cs b/TagsCloudContainer/DrawRectangle/RectangleDraw.cs new file mode 100644 index 000000000..2876651bc --- /dev/null +++ b/TagsCloudContainer/DrawRectangle/RectangleDraw.cs @@ -0,0 +1,49 @@ +using System.Drawing; +using TagsCloudContainer.Cloud; +using TagsCloudContainer.DrawRectangle.Interfaces; +using TagsCloudContainer.WordProcessing; +using Color = System.Drawing.Color; + +namespace TagsCloudContainer.DrawRectangle; + +public class RectangleDraw : IDraw +{ + private readonly Settings _settings; + private readonly CircularCloudLayouter _layouter; + + public RectangleDraw(CircularCloudLayouter layouter, Settings settings) + { + _layouter = layouter; + _settings = settings; + } + + private Bitmap CreateBitmap(List rectangles) + { + var width = rectangles.Max(rectangle => rectangle.Right) - + rectangles.Min(rectangle => rectangle.Left); + var height = rectangles.Max(rectangle => rectangle.Bottom) - + rectangles.Min(rectangle => rectangle.Top); + return new Bitmap(width * 2, height * 2); + } + public Bitmap CreateImage(List words) + { + var rectangles = WordRectangleGenerator.GenerateRectangles(words, _layouter, _settings); + var bitmap = CreateBitmap(rectangles); + var shiftToBitmapCenter = new Size(bitmap.Width / 2, bitmap.Height / 2); + using var g = Graphics.FromImage(bitmap); + using var pen = new Pen(_settings.Color); + g.Clear(Color.Black); + var count = 0; + foreach (var word in words) + { + var rectangle = new Rectangle( + rectangles[count].Location + shiftToBitmapCenter, + rectangles[count].Size); + using var font = new Font(_settings.FontName, word.Size); + g.DrawString(word.Value, font, pen.Brush, rectangle); + count++; + } + + return bitmap; + } +} \ No newline at end of file diff --git a/TagsCloudContainer/FileReader/DocxFileReader.cs b/TagsCloudContainer/FileReader/DocxFileReader.cs new file mode 100644 index 000000000..7404b6289 --- /dev/null +++ b/TagsCloudContainer/FileReader/DocxFileReader.cs @@ -0,0 +1,25 @@ +using System.Text; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using TagsCloudContainer.FileReader.Interfaces; + +namespace TagsCloudContainer.FileReader; +public class DocxFileReader : ITextReader +{ + public string GetTextFromFile(string filePath) + { + var sb = new StringBuilder(); + using (var doc = WordprocessingDocument.Open(filePath, false)) + { + var body = doc.MainDocumentPart?.Document.Body; + + foreach (var paragraph in body?.Elements()!) + { + var paragraphText = paragraph.InnerText.ToLower(); + sb.AppendLine(paragraphText); + } + } + + return sb.ToString(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/FileReader/FileReaderFactory.cs b/TagsCloudContainer/FileReader/FileReaderFactory.cs new file mode 100644 index 000000000..5a0e3438b --- /dev/null +++ b/TagsCloudContainer/FileReader/FileReaderFactory.cs @@ -0,0 +1,17 @@ +using TagsCloudContainer.FileReader.Interfaces; + +namespace TagsCloudContainer.FileReader; + +public class FileReaderFactory +{ + public ITextReader GetReader(string filePath) + { + var fileExtension = Path.GetExtension(filePath); + return fileExtension switch + { + ".docx" => new DocxFileReader(), + ".txt" => new TxtFileReader(), + _ => throw new ArgumentException($"Неверный формат файла: {fileExtension}") + }; + } +} \ No newline at end of file diff --git a/TagsCloudContainer/FileReader/Interfaces/ITextReader.cs b/TagsCloudContainer/FileReader/Interfaces/ITextReader.cs new file mode 100644 index 000000000..6a8460073 --- /dev/null +++ b/TagsCloudContainer/FileReader/Interfaces/ITextReader.cs @@ -0,0 +1,6 @@ +namespace TagsCloudContainer.FileReader.Interfaces; + +public interface ITextReader +{ + public string GetTextFromFile(string filePath); +} \ No newline at end of file diff --git a/TagsCloudContainer/FileReader/TxtFileReader.cs b/TagsCloudContainer/FileReader/TxtFileReader.cs new file mode 100644 index 000000000..e9447a43e --- /dev/null +++ b/TagsCloudContainer/FileReader/TxtFileReader.cs @@ -0,0 +1,22 @@ +using System.Text; +using TagsCloudContainer.FileReader.Interfaces; + +namespace TagsCloudContainer.FileReader; +public class TxtFileReader : ITextReader +{ + public string GetTextFromFile(string filePath) + { + var sb = new StringBuilder(); + using (var sr = new StreamReader(filePath)) + { + var words = sr.ReadLine(); + while (words != null) + { + sb.Append(words + Environment.NewLine); + words = sr.ReadLine(); + } + } + + return sb.ToString(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Images/BlueText.Png b/TagsCloudContainer/Images/BlueText.Png new file mode 100644 index 000000000..8619fb2f0 Binary files /dev/null and b/TagsCloudContainer/Images/BlueText.Png differ diff --git a/TagsCloudContainer/Images/Default.Png b/TagsCloudContainer/Images/Default.Png new file mode 100644 index 000000000..ae66d3f89 Binary files /dev/null and b/TagsCloudContainer/Images/Default.Png differ diff --git a/TagsCloudContainer/Images/JpegImageFormat.Jpeg b/TagsCloudContainer/Images/JpegImageFormat.Jpeg new file mode 100644 index 000000000..302c23ebc Binary files /dev/null and b/TagsCloudContainer/Images/JpegImageFormat.Jpeg differ diff --git a/TagsCloudContainer/Images/PurpleText.Png b/TagsCloudContainer/Images/PurpleText.Png new file mode 100644 index 000000000..f1b696f33 Binary files /dev/null and b/TagsCloudContainer/Images/PurpleText.Png differ diff --git a/TagsCloudContainer/Images/RedText.Png b/TagsCloudContainer/Images/RedText.Png new file mode 100644 index 000000000..5d0e6bdd4 Binary files /dev/null and b/TagsCloudContainer/Images/RedText.Png differ diff --git a/TagsCloudContainer/Images/ShiftCenterX.Png b/TagsCloudContainer/Images/ShiftCenterX.Png new file mode 100644 index 000000000..dcf8c7d03 Binary files /dev/null and b/TagsCloudContainer/Images/ShiftCenterX.Png differ diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs new file mode 100644 index 000000000..371936048 --- /dev/null +++ b/TagsCloudContainer/Program.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using Autofac; +using CommandLine; +using DocumentFormat.OpenXml.Spreadsheet; +using TagsCloudContainer.App; +using TagsCloudContainer.App.Interfaces; + +namespace TagsCloudContainer +{ + internal static class Program + { + public static void Main(string[] args) + { + var options = Parser.Default.ParseArguments(args).Value; + var container = Container.SetDiBuilder(options); + var app = container.Resolve(); + app.Run(); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj new file mode 100644 index 000000000..b63f096ac --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -0,0 +1,28 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + diff --git a/TagsCloudContainer/TextFiles/Boring.docx b/TagsCloudContainer/TextFiles/Boring.docx new file mode 100644 index 000000000..1b7c18bb8 Binary files /dev/null and b/TagsCloudContainer/TextFiles/Boring.docx differ diff --git a/TagsCloudContainer/TextFiles/Boring.txt b/TagsCloudContainer/TextFiles/Boring.txt new file mode 100644 index 000000000..3ee1d6e30 --- /dev/null +++ b/TagsCloudContainer/TextFiles/Boring.txt @@ -0,0 +1,19 @@ +Наверное +Круто +Ну +В целом +Как бы +Вот так +Конечно +Ого +Ага +Угу +Круто +Поэтому +Блин +Черт +Хрыщ +Хаха +Хихи +Вау +Типа \ No newline at end of file diff --git a/TagsCloudContainer/TextFiles/Text.docx b/TagsCloudContainer/TextFiles/Text.docx new file mode 100644 index 000000000..bba3a5c28 Binary files /dev/null and b/TagsCloudContainer/TextFiles/Text.docx differ diff --git a/TagsCloudContainer/TextFiles/Text.txt b/TagsCloudContainer/TextFiles/Text.txt new file mode 100644 index 000000000..ca0bb7fca --- /dev/null +++ b/TagsCloudContainer/TextFiles/Text.txt @@ -0,0 +1,5 @@ +В одном небольшом IT-городе ну живет обычная типа команда разработчиков: мистер и миссис Кодеровы со типа своим молодым сыном. Ранним ну утром во вторник глава команды как обычно запускает свой компьютер и направляется на работу в офис. В течение дня ему неоднократно встречаются странные люди в футболках с логотипами, которые что-то празднуют. Один из них даже делится секретом эффективной сортировки, и мистер Кодер думает, что бедняга, наверное, спятил. При этом упоминаются некие Фреймворки, а такую технологию, между прочим, используют родственники Кодеровых, которых последние всячески избегают. Странной была и роботизированная кофеварка, которая следила за мистером Кодеровым при выходе из кухни. По его возвращении с работы кофеварка опять оказывается на прежнем месте, будто готовила кофе там весь день. А в новостях по телевизору сообщают о необычных событиях — о код-ревью, в большом количестве проводимых повсюду посреди бела дня, и об устраиваемых в разных местах хакатонах, напоминающих битву идей. + +Уже ночью, ну после того, как типа Кодеровы ну ложатся спать, на Git-улице появляется ну человек с огромными ну наклейками ну кода, в худи и с ноутбуком — Альберт Девмакрос, который с помощью дебаггера выявляет ну все баги в проекте. Он подсаживается на окно к кофеварке и начинает разговаривать с ней, после чего та принимает облик строгого архитектора, которого Девмакрос называет профессором Архи Дизайна. + +Эти двое странных людей типа начинают обсуждать последние новости, связанные типа между собой: выпуск ну новой версии языка типа программирования и гибель бага в коде, из-за которого типа ну многие функции перестали работать. Очевидно, команде удалось выжить в ситуации, в которой ломались многие проекты. По заданию Девмакроса Рубеус Хакгид должен забрать команду из офиса и привезти сюда, на Git-улицу. Девмакрос собирается отдать команду на попечение в новый проект, поскольку Анна Кодерова была лучшей подругой Линукса и приходится всей команде единственной дружной связью. Профессор Архи Дизайна шокирована этой новостью. Она говорит, что этот проект — просто ужасный среди всех проектов, и команда будет тут глубоко несчастна. Альберт Девмакрос доказывает ей, что в мире программирования им будет ещё хуже, ведь они уже знамениты, и, стало быть, есть большая опасность для них стать этакими гуру, избалованными чужим вниманием... \ No newline at end of file diff --git a/TagsCloudContainer/WordProcessing/Word.cs b/TagsCloudContainer/WordProcessing/Word.cs new file mode 100644 index 000000000..1ed22dce4 --- /dev/null +++ b/TagsCloudContainer/WordProcessing/Word.cs @@ -0,0 +1,17 @@ +namespace TagsCloudContainer.WordProcessing; + +public class Word +{ + public int Count { get; set; } + public float Size { get; set; } + public string Value { get; } + + public Word(string value) + { + Value = value; + Count = 1; + } + + public void GenerateFontSize(Settings settings, int wordCount) => + Size = Count / (float)wordCount * 100 * settings.FontSize; +} \ No newline at end of file diff --git a/TagsCloudContainer/WordProcessing/WordProcessor.cs b/TagsCloudContainer/WordProcessing/WordProcessor.cs new file mode 100644 index 000000000..3f2ee09db --- /dev/null +++ b/TagsCloudContainer/WordProcessing/WordProcessor.cs @@ -0,0 +1,49 @@ +namespace TagsCloudContainer.WordProcessing; + +public class WordProcessor +{ + private Dictionary _boringWords; + private readonly Settings _settings; + private readonly string[] _separators = {"\r", "\n", ", ", ". ", " "}; + + public WordProcessor(Settings settings) + { + _settings = settings; + } + + private void LoadBoringWords(string text) + { + _boringWords = CreateWordDictionaryBasedOnText(text); + } + + public List ProcessWords(string text, string boringText = "") + { + LoadBoringWords(boringText); + + var wordsDictionary = CreateWordDictionaryBasedOnText(text); + var filteredWords = wordsDictionary + .Select(wordPair => wordPair.Value) + .Where(word => !_boringWords.ContainsKey(word.Value) && word.Value.Length >= 3) + .ToList(); + + foreach (var word in filteredWords ) + word.GenerateFontSize(_settings, filteredWords .Count); + + return filteredWords; + } + + private Dictionary CreateWordDictionaryBasedOnText(string text) + { + var wordDictionary = new Dictionary(); + foreach (var word in text.Split(_separators, StringSplitOptions.RemoveEmptyEntries)) + { + var wordKey = word.ToLower(); + if (!wordDictionary.ContainsKey(wordKey)) + wordDictionary.Add(wordKey, new Word(wordKey)); + else + wordDictionary[wordKey].Count++; + } + + return wordDictionary; + } +} \ No newline at end of file diff --git a/TagsCloudContainer/WordProcessing/WordRectangleGenerator.cs b/TagsCloudContainer/WordProcessing/WordRectangleGenerator.cs new file mode 100644 index 000000000..9c73ddebd --- /dev/null +++ b/TagsCloudContainer/WordProcessing/WordRectangleGenerator.cs @@ -0,0 +1,30 @@ +using System.Drawing; +using TagsCloudContainer.Cloud; + +namespace TagsCloudContainer.WordProcessing; + +public class WordRectangleGenerator +{ + public static List GenerateRectangles(List words, CircularCloudLayouter layouter, + Settings settings) + { + return words.Select(word => + { + var font = new Font(settings.FontName, word.Size); + var size = EditingWordSize(word.Value, font); + return layouter.PutNextRectangle(size); + }).ToList(); + } + + private static Size EditingWordSize(string word, Font font) + { + var bitmap = new Bitmap(1, 1); + var graphics = Graphics.FromImage(bitmap); + var result = graphics.MeasureString(word, font).ToSize(); + // var result = graphics.MeasureString(word, font); + // result = result.ToSize(); + if (result.Width == 0) result.Width = 1; + if (result.Height == 0) result.Height = 1; + return result; //.ToSize(); + } +} \ No newline at end of file diff --git a/TagsCloudContainerTests/CircularCloudLayouterTest.cs b/TagsCloudContainerTests/CircularCloudLayouterTest.cs new file mode 100644 index 000000000..a5b34bb11 --- /dev/null +++ b/TagsCloudContainerTests/CircularCloudLayouterTest.cs @@ -0,0 +1,76 @@ +using System.Drawing; +using TagsCloudContainer; +using TagsCloudContainer.Cloud; + +namespace TagsCloudContainerTests; + +public class CircularCloudLayouterTest +{ + [TestCase(0, 0, 1)] + [TestCase(2, 10, 2)] + public void CorrectParameters_ShouldNotGiveErrors(int x, int y, double step) + { + Action action = () => new SpiralFunction(new Point(x, y), step); + action.Should().NotThrow(); + } + [TestFixture] + public class CircularCloudLayouter_Should + { + private Random _random = new(1); + private Point _center; + private static CircularCloudLayouter _layouter; + private List _rectangles = new(); + + + [SetUp] + public void SetUp() + { + _center = new Point(0, 0); + _layouter = new CircularCloudLayouter(_center); + } + + [TestCase(0, 0)] + [TestCase(-1, -1)] + public void PutNextRectangle_ShouldThrowArgumentException_WhenIncorrectSize(int sizeX, int sizeY) + { + Action action = () => _layouter.PutNextRectangle(new Size(sizeX, sizeY)); + action.Should().Throw().WithMessage("Width and Height Size should positive"); + } + + [TestCase(10, 10, 10)] + public void PutNextRectangle_AddRectangles(int sizeX, int sizeY, int count) + { + for (var i = 0; i < count; i++) + _layouter.PutNextRectangle(new Size(sizeX, sizeY)); + + _layouter._rectangles.Count.Should().Be(count); + } + + [Test] + public void CreateEmptyRectangle() + { + _layouter = new CircularCloudLayouter(new Point()); + _layouter._rectangles.Should().BeEmpty(); + } + + [TestCase(30)] + [TestCase(50)] + [TestCase(100)] + public void PlacedRectangles_ShouldTrue_WhenCorrectNotIntersects(int countRectangles) + { + var isIntersectsWith = false; + + for (var i = 0; i < countRectangles; i++) + { + var size = new Size(_random.Next(50, 100), _random.Next(40, 80)); + var rectangle = _layouter.PutNextRectangle(size); + if (rectangle.IsIntersectOthersRectangles(_rectangles)) + { + isIntersectsWith = true; + } + _rectangles.Add(rectangle); + } + isIntersectsWith.Should().BeTrue(); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainerTests/FileReaderTest.cs b/TagsCloudContainerTests/FileReaderTest.cs new file mode 100644 index 000000000..63f128709 --- /dev/null +++ b/TagsCloudContainerTests/FileReaderTest.cs @@ -0,0 +1,33 @@ +using TagsCloudContainer.FileReader; + +namespace TagsCloudContainerTests +{ + [TestFixture] + public class FileReaderTest + { + + [TestCase("Text.txt")] + [TestCase("Boring.txt")] + public void GetReader_ShouldCorrectTxtReader(string fileName) + { + var reader = new FileReaderFactory().GetReader(fileName); + reader.Should().BeOfType(); + } + + [TestCase("Text.docx")] + [TestCase("Boring.docx")] + public void GetReader_ShouldCorrectDocxReader(string fileName) + { + var reader = new FileReaderFactory().GetReader(fileName); + reader.Should().BeOfType(); + } + + [TestCase("Text.mp4")] + [TestCase("Boring.cs")] + public void GetReader_ShouldThrowArgumentException(string fileName) + { + Action action = () => new FileReaderFactory().GetReader(fileName); + action.Should().Throw(); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainerTests/GlobalUsings.cs b/TagsCloudContainerTests/GlobalUsings.cs new file mode 100644 index 000000000..25c79abfb --- /dev/null +++ b/TagsCloudContainerTests/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using NUnit.Framework; +global using FluentAssertions; \ No newline at end of file diff --git a/TagsCloudContainerTests/TagsCloudContainerTests.csproj b/TagsCloudContainerTests/TagsCloudContainerTests.csproj new file mode 100644 index 000000000..2f5820d7d --- /dev/null +++ b/TagsCloudContainerTests/TagsCloudContainerTests.csproj @@ -0,0 +1,25 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + diff --git a/TagsCloudContainerTests/TextFiles/Boring.docx b/TagsCloudContainerTests/TextFiles/Boring.docx new file mode 100644 index 000000000..1b7c18bb8 Binary files /dev/null and b/TagsCloudContainerTests/TextFiles/Boring.docx differ diff --git a/TagsCloudContainerTests/TextFiles/Boring.txt b/TagsCloudContainerTests/TextFiles/Boring.txt new file mode 100644 index 000000000..3ee1d6e30 --- /dev/null +++ b/TagsCloudContainerTests/TextFiles/Boring.txt @@ -0,0 +1,19 @@ +Наверное +Круто +Ну +В целом +Как бы +Вот так +Конечно +Ого +Ага +Угу +Круто +Поэтому +Блин +Черт +Хрыщ +Хаха +Хихи +Вау +Типа \ No newline at end of file diff --git a/TagsCloudContainerTests/TextFiles/Text.docx b/TagsCloudContainerTests/TextFiles/Text.docx new file mode 100644 index 000000000..bba3a5c28 Binary files /dev/null and b/TagsCloudContainerTests/TextFiles/Text.docx differ diff --git a/TagsCloudContainerTests/TextFiles/Text.txt b/TagsCloudContainerTests/TextFiles/Text.txt new file mode 100644 index 000000000..ca0bb7fca --- /dev/null +++ b/TagsCloudContainerTests/TextFiles/Text.txt @@ -0,0 +1,5 @@ +В одном небольшом IT-городе ну живет обычная типа команда разработчиков: мистер и миссис Кодеровы со типа своим молодым сыном. Ранним ну утром во вторник глава команды как обычно запускает свой компьютер и направляется на работу в офис. В течение дня ему неоднократно встречаются странные люди в футболках с логотипами, которые что-то празднуют. Один из них даже делится секретом эффективной сортировки, и мистер Кодер думает, что бедняга, наверное, спятил. При этом упоминаются некие Фреймворки, а такую технологию, между прочим, используют родственники Кодеровых, которых последние всячески избегают. Странной была и роботизированная кофеварка, которая следила за мистером Кодеровым при выходе из кухни. По его возвращении с работы кофеварка опять оказывается на прежнем месте, будто готовила кофе там весь день. А в новостях по телевизору сообщают о необычных событиях — о код-ревью, в большом количестве проводимых повсюду посреди бела дня, и об устраиваемых в разных местах хакатонах, напоминающих битву идей. + +Уже ночью, ну после того, как типа Кодеровы ну ложатся спать, на Git-улице появляется ну человек с огромными ну наклейками ну кода, в худи и с ноутбуком — Альберт Девмакрос, который с помощью дебаггера выявляет ну все баги в проекте. Он подсаживается на окно к кофеварке и начинает разговаривать с ней, после чего та принимает облик строгого архитектора, которого Девмакрос называет профессором Архи Дизайна. + +Эти двое странных людей типа начинают обсуждать последние новости, связанные типа между собой: выпуск ну новой версии языка типа программирования и гибель бага в коде, из-за которого типа ну многие функции перестали работать. Очевидно, команде удалось выжить в ситуации, в которой ломались многие проекты. По заданию Девмакроса Рубеус Хакгид должен забрать команду из офиса и привезти сюда, на Git-улицу. Девмакрос собирается отдать команду на попечение в новый проект, поскольку Анна Кодерова была лучшей подругой Линукса и приходится всей команде единственной дружной связью. Профессор Архи Дизайна шокирована этой новостью. Она говорит, что этот проект — просто ужасный среди всех проектов, и команда будет тут глубоко несчастна. Альберт Девмакрос доказывает ей, что в мире программирования им будет ещё хуже, ведь они уже знамениты, и, стало быть, есть большая опасность для них стать этакими гуру, избалованными чужим вниманием... \ No newline at end of file diff --git a/TagsCloudContainerTests/TextFiles/UpperWords.txt b/TagsCloudContainerTests/TextFiles/UpperWords.txt new file mode 100644 index 000000000..8cfbb3c88 --- /dev/null +++ b/TagsCloudContainerTests/TextFiles/UpperWords.txt @@ -0,0 +1,12 @@ +ПРИВЕТ +ПРИВЕТ +ПРИВЕТ +КАК +КАК +КАК +КАК +КАК +ДЕЛА +ДЕЛА +У +ТЕБЯ \ No newline at end of file diff --git a/TagsCloudContainerTests/WordProcessingTest.cs b/TagsCloudContainerTests/WordProcessingTest.cs new file mode 100644 index 000000000..e3a03b92d --- /dev/null +++ b/TagsCloudContainerTests/WordProcessingTest.cs @@ -0,0 +1,29 @@ +using TagsCloudContainer; +using TagsCloudContainer.FileReader; +using TagsCloudContainer.WordProcessing; + +namespace TagsCloudContainerTests; + +[TestFixture] +public class WordProcessingTest +{ + [TestCase("UpperWords.txt")] + public void WordProcessing_ShouldCorrectToLowerAndCountWords(string filename) + { + var testWords = new List() + { + new("привет") { Count = 3 }, + new("как") { Count = 5 }, + new("дела") { Count = 2 }, + new("у") { Count = 1 }, + new("тебя") { Count = 1 } + }; + filename = "../../../../TagsCloudContainerTests/TextFiles/" + filename; + var settings = new Settings(); + var reader = new FileReaderFactory().GetReader(filename); + var file = reader.GetTextFromFile(filename); + var words = new WordProcessor(settings).ProcessWords(file); + for (var i = 0; i < words.Count; i++) + words[i].Count.Should().Be(testWords[i].Count); + } +} \ No newline at end of file diff --git a/di.sln b/di.sln index b27b7c05d..aba633838 100644 --- a/di.sln +++ b/di.sln @@ -2,6 +2,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FractalPainter", "FractalPainter\FractalPainter.csproj", "{4D70883B-6F8B-4166-802F-8EDC9BE93199}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainer", "TagsCloudContainer\TagsCloudContainer.csproj", "{37217157-A81C-4A85-940E-4707CF7E3C7C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainerTests", "TagsCloudContainerTests\TagsCloudContainerTests.csproj", "{663057DE-1A8D-4ED6-A7C1-1A5CBE92B8CF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +16,13 @@ Global {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Release|Any CPU.Build.0 = Release|Any CPU + {37217157-A81C-4A85-940E-4707CF7E3C7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37217157-A81C-4A85-940E-4707CF7E3C7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37217157-A81C-4A85-940E-4707CF7E3C7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37217157-A81C-4A85-940E-4707CF7E3C7C}.Release|Any CPU.Build.0 = Release|Any CPU + {663057DE-1A8D-4ED6-A7C1-1A5CBE92B8CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {663057DE-1A8D-4ED6-A7C1-1A5CBE92B8CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {663057DE-1A8D-4ED6-A7C1-1A5CBE92B8CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {663057DE-1A8D-4ED6-A7C1-1A5CBE92B8CF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal