From 8ef5f530c5ce6e2fca01a9c198c23ba17bb70066 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Wed, 18 Dec 2024 19:12:13 +0500 Subject: [PATCH 01/20] Create Project and Add Code from Past Task --- .../TagCloudContainerTests.csproj | 24 ++++++++++++ TagCloudContainerTests/UnitTest1.cs | 16 ++++++++ .../Layouters/CircularCloudLayouter.cs | 12 ++++++ TagsCloudContainer/Program.cs | 2 + TagsCloudContainer/TagsCloudContainer.csproj | 10 +++++ TagsCloudContainer/TagsCloudContainer.sln | 25 ++++++++++++ .../Visualizers/ImageCreater.cs | 39 +++++++++++++++++++ 7 files changed, 128 insertions(+) create mode 100644 TagCloudContainerTests/TagCloudContainerTests.csproj create mode 100644 TagCloudContainerTests/UnitTest1.cs create mode 100644 TagsCloudContainer/Layouters/CircularCloudLayouter.cs create mode 100644 TagsCloudContainer/Program.cs create mode 100644 TagsCloudContainer/TagsCloudContainer.csproj create mode 100644 TagsCloudContainer/TagsCloudContainer.sln create mode 100644 TagsCloudContainer/Visualizers/ImageCreater.cs diff --git a/TagCloudContainerTests/TagCloudContainerTests.csproj b/TagCloudContainerTests/TagCloudContainerTests.csproj new file mode 100644 index 00000000..8b5797ec --- /dev/null +++ b/TagCloudContainerTests/TagCloudContainerTests.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/TagCloudContainerTests/UnitTest1.cs b/TagCloudContainerTests/UnitTest1.cs new file mode 100644 index 00000000..6e38d288 --- /dev/null +++ b/TagCloudContainerTests/UnitTest1.cs @@ -0,0 +1,16 @@ +namespace TagCloudContainerTests +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs new file mode 100644 index 00000000..e8be7fe4 --- /dev/null +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.Layouters +{ + internal class CircularCloudLayouter + { + } +} diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs new file mode 100644 index 00000000..3751555c --- /dev/null +++ b/TagsCloudContainer/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj new file mode 100644 index 00000000..2150e379 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/TagsCloudContainer/TagsCloudContainer.sln b/TagsCloudContainer/TagsCloudContainer.sln new file mode 100644 index 00000000..08d5d84b --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainer", "TagsCloudContainer.csproj", "{468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1090FEC2-F19E-4634-8E98-CBE768CB11D4} + EndGlobalSection +EndGlobal diff --git a/TagsCloudContainer/Visualizers/ImageCreater.cs b/TagsCloudContainer/Visualizers/ImageCreater.cs new file mode 100644 index 00000000..8c69aef4 --- /dev/null +++ b/TagsCloudContainer/Visualizers/ImageCreater.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; + +namespace TagsCloudContainer.Visualizers +{ + public class ImageCreater + { + private readonly int Width; + private readonly int Height; + + public ImageCreater(int width, int height) + { + Width = width; + Height = height; + } + + public void Generate(IEnumerable items, string directory) + { + var image = new Bitmap(Width, Height); + var g = Graphics.FromImage(image); + var pen = new Pen(Brushes.AliceBlue, 2); + var count = 0; + foreach (var item in items) + { + count++; + g.DrawRectangle(pen, item); + } + + image.Save(directory, ImageFormat.Jpeg); + + } + } +} From 97d8e0b18012f48d952eccfee7876afdc5ce6d42 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Sun, 22 Dec 2024 15:27:12 +0500 Subject: [PATCH 02/20] Add Logic Scheme --- .../Layouters/CircularCloudLayouter.cs | 66 +++++++++++++++++-- TagsCloudContainer/Layouters/ILayouter.cs | 12 ++++ TagsCloudContainer/Parsers/IParser.cs | 12 ++++ TagsCloudContainer/Program.cs | 11 +++- TagsCloudContainer/TagsCloudContainer.csproj | 5 ++ TagsCloudContainer/TagsCloudContainer.sln | 8 ++- .../TextHadlers/ITextHandler.cs | 12 ++++ TagsCloudContainer/Visualizers/IVisualizer.cs | 12 ++++ .../Visualizers/ImageCreater.cs | 8 +-- .../WordClasses/RectangleWord.cs | 12 ++++ TagsCloudContainer/WordClasses/SizeWord.cs | 12 ++++ TagsCloudContainer/WordSizer/ISizer.cs | 12 ++++ 12 files changed, 166 insertions(+), 16 deletions(-) create mode 100644 TagsCloudContainer/Layouters/ILayouter.cs create mode 100644 TagsCloudContainer/Parsers/IParser.cs create mode 100644 TagsCloudContainer/TextHadlers/ITextHandler.cs create mode 100644 TagsCloudContainer/Visualizers/IVisualizer.cs create mode 100644 TagsCloudContainer/WordClasses/RectangleWord.cs create mode 100644 TagsCloudContainer/WordClasses/SizeWord.cs create mode 100644 TagsCloudContainer/WordSizer/ISizer.cs diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index e8be7fe4..b232426c 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -1,12 +1,66 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudContainer.Layouters { - internal class CircularCloudLayouter + public class CircularCloudLayouter : ILayouter { + public readonly List rectangles; + public readonly Point center; + private double angle; + private double spiralStep = 0.1; + private double radiusStep = 0.5; + + public CircularCloudLayouter(Point center) + { + this.center = center; + rectangles = new List(); + } + + public IEnumerable GetLayout(IOrderedEnumerable words) + { + foreach (var word in words) + { + var rectangleSize = word.Size; + Rectangle newRect; + do + { + var location = GetNextLocation(rectangleSize); + newRect = new Rectangle(location, rectangleSize); + } + while (IsIntersecting(newRect)); + rectangles.Add(new RectangleWord(word.Value, newRect)); + } + return rectangles; + } + + + private Point GetNextLocation(Size rectangleSize) + { + var radius = radiusStep * angle; + var centerX = center.X + (int)(radius * Math.Cos(angle)); + var centerY = center.Y + (int)(radius * Math.Sin(angle)); + angle += spiralStep; + return GetCornerPoint(new Point(centerX, centerY), rectangleSize); + } + + private bool IsIntersecting(Rectangle rectangle) + { + foreach (var existingRectangle in rectangles) + { + if (existingRectangle.IntersectsWith(rectangle)) + return true; + } + return false; + } + + public static Point GetCornerPoint(Point center, Size size) + { + return new Point(center.X - size.Width / 2, center.Y - size.Height / 2); + } + + public static Point GetCenterPoint(Rectangle rect) + { + return new Point(rect.Location.X + rect.Width / 2, rect.Location.Y + rect.Height / 2); + } } } diff --git a/TagsCloudContainer/Layouters/ILayouter.cs b/TagsCloudContainer/Layouters/ILayouter.cs new file mode 100644 index 00000000..1bb53d2c --- /dev/null +++ b/TagsCloudContainer/Layouters/ILayouter.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.Layouters +{ + internal interface ILayouter + { + } +} diff --git a/TagsCloudContainer/Parsers/IParser.cs b/TagsCloudContainer/Parsers/IParser.cs new file mode 100644 index 00000000..0c82522f --- /dev/null +++ b/TagsCloudContainer/Parsers/IParser.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.Parsers +{ + internal interface IParser + { + } +} diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 3751555c..bd9e4ae3 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,2 +1,9 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using Autofac; + +public static class Program +{ + public static void Main() + { + var builder = new ContainerBuilder(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 2150e379..7bda4840 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -7,4 +7,9 @@ enable + + + + + diff --git a/TagsCloudContainer/TagsCloudContainer.sln b/TagsCloudContainer/TagsCloudContainer.sln index 08d5d84b..327c990b 100644 --- a/TagsCloudContainer/TagsCloudContainer.sln +++ b/TagsCloudContainer/TagsCloudContainer.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.11.35303.130 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainer", "TagsCloudContainer.csproj", "{468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudContainer", "TagsCloudContainer.csproj", "{468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagCloudContainerTests", "..\TagCloudContainerTests\TagCloudContainerTests.csproj", "{AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {468DF4A6-3C4A-4517-A5A5-30B96E2D8EC8}.Release|Any CPU.Build.0 = Release|Any CPU + {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TagsCloudContainer/TextHadlers/ITextHandler.cs b/TagsCloudContainer/TextHadlers/ITextHandler.cs new file mode 100644 index 00000000..31395562 --- /dev/null +++ b/TagsCloudContainer/TextHadlers/ITextHandler.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.TextHadlers +{ + internal interface ITextHandler + { + } +} diff --git a/TagsCloudContainer/Visualizers/IVisualizer.cs b/TagsCloudContainer/Visualizers/IVisualizer.cs new file mode 100644 index 00000000..41d728d7 --- /dev/null +++ b/TagsCloudContainer/Visualizers/IVisualizer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.Visualizers +{ + internal interface IVisualizer + { + } +} diff --git a/TagsCloudContainer/Visualizers/ImageCreater.cs b/TagsCloudContainer/Visualizers/ImageCreater.cs index 8c69aef4..a73ae92b 100644 --- a/TagsCloudContainer/Visualizers/ImageCreater.cs +++ b/TagsCloudContainer/Visualizers/ImageCreater.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Drawing; +using System.Drawing; using System.Drawing.Imaging; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static System.Net.Mime.MediaTypeNames; namespace TagsCloudContainer.Visualizers { diff --git a/TagsCloudContainer/WordClasses/RectangleWord.cs b/TagsCloudContainer/WordClasses/RectangleWord.cs new file mode 100644 index 00000000..2c16703f --- /dev/null +++ b/TagsCloudContainer/WordClasses/RectangleWord.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer +{ + internal class RectangleWord + { + } +} diff --git a/TagsCloudContainer/WordClasses/SizeWord.cs b/TagsCloudContainer/WordClasses/SizeWord.cs new file mode 100644 index 00000000..b6e77e28 --- /dev/null +++ b/TagsCloudContainer/WordClasses/SizeWord.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer +{ + internal class SizeWord + { + } +} diff --git a/TagsCloudContainer/WordSizer/ISizer.cs b/TagsCloudContainer/WordSizer/ISizer.cs new file mode 100644 index 00000000..d7ba8632 --- /dev/null +++ b/TagsCloudContainer/WordSizer/ISizer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.WordSizer +{ + internal interface ISizer + { + } +} From 5699f10e35d8bf5adab66c4c726ea1712a0f6d44 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Sun, 22 Dec 2024 21:30:59 +0500 Subject: [PATCH 03/20] Add FileReader Logic --- TagCloudContainerTests/FileReadTest.cs | 50 ++ TagCloudContainerTests/Files/wordsDOC.doc | Bin 0 -> 90624 bytes TagCloudContainerTests/Files/wordsDOCX.docx | Bin 0 -> 37134 bytes TagCloudContainerTests/Files/wordsTXT.txt | 500 ++++++++++++++++++ ...ileReadTest.Reader_DocReading.verified.txt | 100 ++++ ...leReadTest.Reader_DocxReading.verified.txt | 100 ++++ ...ileReadTest.Reader_TxtReading.verified.txt | 500 ++++++++++++++++++ .../TagCloudContainerTests.csproj | 21 +- TagCloudContainerTests/UnitTest1.cs | 16 - .../FileReaders/DocFileReader.cs | 22 + .../FileReaders/DocxFileReader.cs | 30 ++ TagsCloudContainer/FileReaders/IReader.cs | 7 + .../FileReaders/TxtFileReader.cs | 18 + .../Layouters/CircularCloudLayouter.cs | 8 +- TagsCloudContainer/Layouters/ILayouter.cs | 5 +- TagsCloudContainer/Parsers/IParser.cs | 4 +- TagsCloudContainer/TagsCloudContainer.csproj | 2 + .../TextHadlers/ITextHandler.cs | 3 +- TagsCloudContainer/Visualizers/IVisualizer.cs | 4 +- .../Visualizers/ImageCreater.cs | 1 + .../WordClasses/RectangleWord.cs | 7 +- TagsCloudContainer/WordClasses/SizeWord.cs | 12 +- TagsCloudContainer/WordSizer/ISizer.cs | 5 +- 23 files changed, 1372 insertions(+), 43 deletions(-) create mode 100644 TagCloudContainerTests/FileReadTest.cs create mode 100644 TagCloudContainerTests/Files/wordsDOC.doc create mode 100644 TagCloudContainerTests/Files/wordsDOCX.docx create mode 100644 TagCloudContainerTests/Files/wordsTXT.txt create mode 100644 TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocReading.verified.txt create mode 100644 TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocxReading.verified.txt create mode 100644 TagCloudContainerTests/Snapshots/FileReadTest.Reader_TxtReading.verified.txt delete mode 100644 TagCloudContainerTests/UnitTest1.cs create mode 100644 TagsCloudContainer/FileReaders/DocFileReader.cs create mode 100644 TagsCloudContainer/FileReaders/DocxFileReader.cs create mode 100644 TagsCloudContainer/FileReaders/IReader.cs create mode 100644 TagsCloudContainer/FileReaders/TxtFileReader.cs diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs new file mode 100644 index 00000000..bda05179 --- /dev/null +++ b/TagCloudContainerTests/FileReadTest.cs @@ -0,0 +1,50 @@ +using FluentAssertions; +using NPOI.SS.Formula.Functions; +using System.Data; +using TagsCloudContainer.FileReaders; + +namespace TagCloudContainerTests +{ + public class FileReadTest + { + private static readonly VerifySettings Settings = new(); + private IReader Reader; + private string FolderPath; + + [SetUp] + public void Setup() + { + Settings.UseDirectory("Snapshots"); + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); + FolderPath = Path.Combine(projectDirectory, "Files"); + } + + [Test] + public Task Reader_TxtReading() + { + Reader = new TxtFileReader(); + var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); + } + + [Test] + public Task Reader_DocxReading() + { + Reader = new DocxFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); + } + + [Test] + public Task Reader_DocReading() + { + Reader = new DocFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); + } + } +} \ No newline at end of file diff --git a/TagCloudContainerTests/Files/wordsDOC.doc b/TagCloudContainerTests/Files/wordsDOC.doc new file mode 100644 index 0000000000000000000000000000000000000000..8b4b098670ee2a34a26627d094dae9d98037bb07 GIT binary patch literal 90624 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∓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 literal 0 HcmV?d00001 diff --git a/TagCloudContainerTests/Files/wordsTXT.txt b/TagCloudContainerTests/Files/wordsTXT.txt new file mode 100644 index 00000000..e2dde216 --- /dev/null +++ b/TagCloudContainerTests/Files/wordsTXT.txt @@ -0,0 +1,500 @@ +ежевика +клубника +клубника +банан +киви +киви +папайя +манго +инжир +мандарин +облепиха +лимон +айва +финик +черешня +мандарин +инжир +манго +ваниль +арбуз +апельсин +черешня +арбуз +ежевика +ваниль +финик +папайя +клубника +финик +финик +юзу +яблоко +дыня +вишня +виноград +апельсин +мандарин +юзу +облепиха +айва +вишня +айва +нектарин +облепиха +лимон +дыня +мандарин +апельсин +арбуз +черешня +дыня +мандарин +киви +нектарин +вишня +айва +ежевика +манго +банан +папайя +инжир +киви +апельсин +цуккини +папайя +малина +дыня +ежевика +юзу +дыня +апельсин +облепиха +ежевика +дыня +банан +нектарин +ваниль +банан +ежевика +вишня +яблоко +лимон +виноград +клубника +малина +яблоко +облепиха +юзу +арбуз +киви +дыня +инжир +мандарин +дыня +манго +нектарин +айва +ваниль +финик +финик +клубника +папайя +банан +яблоко +цуккини +апельсин +клубника +клубника +апельсин +клубника +киви +цуккини +мандарин +айва +финик +папайя +лимон +черешня +клубника +финик +манго +виноград +цуккини +виноград +малина +ваниль +ежевика +ежевика +виноград +нектарин +айва +банан +ежевика +цуккини +клубника +киви +инжир +виноград +вишня +малина +яблоко +нектарин +малина +манго +банан +дыня +ваниль +киви +нектарин +вишня +ваниль +цуккини +виноград +ежевика +апельсин +банан +клубника +виноград +киви +вишня +нектарин +лимон +банан +малина +облепиха +финик +ваниль +арбуз +дыня +виноград +ежевика +юзу +лимон +черешня +финик +арбуз +яблоко +облепиха +виноград +вишня +яблоко +нектарин +дыня +арбуз +малина +облепиха +черешня +арбуз +манго +манго +облепиха +лимон +манго +дыня +ежевика +нектарин +нектарин +мандарин +черешня +папайя +клубника +финик +яблоко +лимон +апельсин +клубника +киви +манго +апельсин +виноград +айва +нектарин +арбуз +малина +виноград +дыня +ваниль +айва +лимон +малина +апельсин +вишня +виноград +киви +мандарин +ваниль +киви +дыня +клубника +вишня +лимон +мандарин +ежевика +банан +цуккини +вишня +облепиха +нектарин +виноград +яблоко +арбуз +облепиха +юзу +папайя +черешня +клубника +нектарин +папайя +манго +цуккини +лимон +нектарин +клубника +апельсин +малина +киви +виноград +ежевика +дыня +дыня +финик +дыня +инжир +черешня +манго +арбуз +ежевика +ваниль +арбуз +нектарин +инжир +арбуз +мандарин +ваниль +манго +вишня +облепиха +арбуз +вишня +инжир +банан +вишня +виноград +финик +юзу +арбуз +инжир +цуккини +облепиха +яблоко +дыня +юзу +ваниль +киви +инжир +облепиха +ваниль +апельсин +дыня +нектарин +яблоко +лимон +папайя +апельсин +малина +ежевика +ежевика +апельсин +лимон +папайя +апельсин +дыня +дыня +финик +юзу +киви +цуккини +вишня +клубника +лимон +вишня +дыня +айва +ваниль +ваниль +мандарин +мандарин +яблоко +апельсин +юзу +вишня +клубника +финик +облепиха +юзу +ваниль +юзу +дыня +манго +цуккини +апельсин +цуккини +клубника +апельсин +папайя +ежевика +лимон +цуккини +айва +облепиха +дыня +мандарин +лимон +киви +мандарин +юзу +банан +виноград +виноград +киви +черешня +манго +ежевика +айва +яблоко +цуккини +банан +виноград +черешня +апельсин +киви +арбуз +малина +нектарин +киви +банан +манго +ваниль +облепиха +юзу +нектарин +яблоко +вишня +нектарин +лимон +арбуз +лимон +папайя +цуккини +апельсин +инжир +банан +виноград +финик +айва +дыня +вишня +финик +ваниль +мандарин +малина +киви +инжир +киви +банан +цуккини +лимон +вишня +облепиха +инжир +финик +юзу +цуккини +инжир +апельсин +малина +апельсин +дыня +банан +виноград +киви +юзу +дыня +цуккини +дыня +манго +вишня +айва +черешня +яблоко +вишня +киви +апельсин +айва +лимон +банан +финик +инжир +финик +киви +клубника +черешня +вишня +малина +вишня +манго +киви +арбуз +папайя +арбуз +цуккини +айва +манго +черешня +дыня +черешня +ежевика +инжир +юзу +нектарин +манго +банан +нектарин +нектарин +айва +апельсин +инжир +папайя +ежевика +инжир +финик +апельсин +киви +клубника +манго +яблоко +инжир +цуккини +виноград +папайя +черешня +нектарин +виноград +арбуз +клубника +лимон +арбуз +яблоко +инжир +арбуз +ежевика +киви +мандарин +черешня +мандарин +яблоко +манго +ежевика +папайя +мандарин \ No newline at end of file diff --git a/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocReading.verified.txt b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocReading.verified.txt new file mode 100644 index 00000000..c4925179 --- /dev/null +++ b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocReading.verified.txt @@ -0,0 +1,100 @@ +площадь +автомобиль +ресторан +улица +успех +цветок +дом +автомобиль +дружба +кафе +учитель +кафе +страна +путешествие +успех +студент +искусство +музыка +город +фотография +солнце +интернет +учитель +парк +алгоритм +город +небо +город +песня +программирование +площадь +алгоритм +студент +город +птица +работа +ресторан +работа +телефон +любовь +дружба +математика +наука +счастье +еда +телефон +небо +любовь +еда +собака +путешествие +кафе +дом +компьютер +еда +дружба +фильм +река +город +путешествие +море +шарик +алгоритм +небо +солнце +шарик +фотография +город +школа +искусство +город +город +птица +актёр +успех +автомобиль +страна +алгоритм +еда +математика +небо +кинематограф +путешествие +счастье +съёмка +фильм +страна +солнце +собака +интернет +город +гора +площадь +путешествие +море +телефон +кот +дом +любовь +компьютер diff --git a/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocxReading.verified.txt b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocxReading.verified.txt new file mode 100644 index 00000000..c4925179 --- /dev/null +++ b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_DocxReading.verified.txt @@ -0,0 +1,100 @@ +площадь +автомобиль +ресторан +улица +успех +цветок +дом +автомобиль +дружба +кафе +учитель +кафе +страна +путешествие +успех +студент +искусство +музыка +город +фотография +солнце +интернет +учитель +парк +алгоритм +город +небо +город +песня +программирование +площадь +алгоритм +студент +город +птица +работа +ресторан +работа +телефон +любовь +дружба +математика +наука +счастье +еда +телефон +небо +любовь +еда +собака +путешествие +кафе +дом +компьютер +еда +дружба +фильм +река +город +путешествие +море +шарик +алгоритм +небо +солнце +шарик +фотография +город +школа +искусство +город +город +птица +актёр +успех +автомобиль +страна +алгоритм +еда +математика +небо +кинематограф +путешествие +счастье +съёмка +фильм +страна +солнце +собака +интернет +город +гора +площадь +путешествие +море +телефон +кот +дом +любовь +компьютер diff --git a/TagCloudContainerTests/Snapshots/FileReadTest.Reader_TxtReading.verified.txt b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_TxtReading.verified.txt new file mode 100644 index 00000000..4776a9f7 --- /dev/null +++ b/TagCloudContainerTests/Snapshots/FileReadTest.Reader_TxtReading.verified.txt @@ -0,0 +1,500 @@ +ежевика +клубника +клубника +банан +киви +киви +папайя +манго +инжир +мандарин +облепиха +лимон +айва +финик +черешня +мандарин +инжир +манго +ваниль +арбуз +апельсин +черешня +арбуз +ежевика +ваниль +финик +папайя +клубника +финик +финик +юзу +яблоко +дыня +вишня +виноград +апельсин +мандарин +юзу +облепиха +айва +вишня +айва +нектарин +облепиха +лимон +дыня +мандарин +апельсин +арбуз +черешня +дыня +мандарин +киви +нектарин +вишня +айва +ежевика +манго +банан +папайя +инжир +киви +апельсин +цуккини +папайя +малина +дыня +ежевика +юзу +дыня +апельсин +облепиха +ежевика +дыня +банан +нектарин +ваниль +банан +ежевика +вишня +яблоко +лимон +виноград +клубника +малина +яблоко +облепиха +юзу +арбуз +киви +дыня +инжир +мандарин +дыня +манго +нектарин +айва +ваниль +финик +финик +клубника +папайя +банан +яблоко +цуккини +апельсин +клубника +клубника +апельсин +клубника +киви +цуккини +мандарин +айва +финик +папайя +лимон +черешня +клубника +финик +манго +виноград +цуккини +виноград +малина +ваниль +ежевика +ежевика +виноград +нектарин +айва +банан +ежевика +цуккини +клубника +киви +инжир +виноград +вишня +малина +яблоко +нектарин +малина +манго +банан +дыня +ваниль +киви +нектарин +вишня +ваниль +цуккини +виноград +ежевика +апельсин +банан +клубника +виноград +киви +вишня +нектарин +лимон +банан +малина +облепиха +финик +ваниль +арбуз +дыня +виноград +ежевика +юзу +лимон +черешня +финик +арбуз +яблоко +облепиха +виноград +вишня +яблоко +нектарин +дыня +арбуз +малина +облепиха +черешня +арбуз +манго +манго +облепиха +лимон +манго +дыня +ежевика +нектарин +нектарин +мандарин +черешня +папайя +клубника +финик +яблоко +лимон +апельсин +клубника +киви +манго +апельсин +виноград +айва +нектарин +арбуз +малина +виноград +дыня +ваниль +айва +лимон +малина +апельсин +вишня +виноград +киви +мандарин +ваниль +киви +дыня +клубника +вишня +лимон +мандарин +ежевика +банан +цуккини +вишня +облепиха +нектарин +виноград +яблоко +арбуз +облепиха +юзу +папайя +черешня +клубника +нектарин +папайя +манго +цуккини +лимон +нектарин +клубника +апельсин +малина +киви +виноград +ежевика +дыня +дыня +финик +дыня +инжир +черешня +манго +арбуз +ежевика +ваниль +арбуз +нектарин +инжир +арбуз +мандарин +ваниль +манго +вишня +облепиха +арбуз +вишня +инжир +банан +вишня +виноград +финик +юзу +арбуз +инжир +цуккини +облепиха +яблоко +дыня +юзу +ваниль +киви +инжир +облепиха +ваниль +апельсин +дыня +нектарин +яблоко +лимон +папайя +апельсин +малина +ежевика +ежевика +апельсин +лимон +папайя +апельсин +дыня +дыня +финик +юзу +киви +цуккини +вишня +клубника +лимон +вишня +дыня +айва +ваниль +ваниль +мандарин +мандарин +яблоко +апельсин +юзу +вишня +клубника +финик +облепиха +юзу +ваниль +юзу +дыня +манго +цуккини +апельсин +цуккини +клубника +апельсин +папайя +ежевика +лимон +цуккини +айва +облепиха +дыня +мандарин +лимон +киви +мандарин +юзу +банан +виноград +виноград +киви +черешня +манго +ежевика +айва +яблоко +цуккини +банан +виноград +черешня +апельсин +киви +арбуз +малина +нектарин +киви +банан +манго +ваниль +облепиха +юзу +нектарин +яблоко +вишня +нектарин +лимон +арбуз +лимон +папайя +цуккини +апельсин +инжир +банан +виноград +финик +айва +дыня +вишня +финик +ваниль +мандарин +малина +киви +инжир +киви +банан +цуккини +лимон +вишня +облепиха +инжир +финик +юзу +цуккини +инжир +апельсин +малина +апельсин +дыня +банан +виноград +киви +юзу +дыня +цуккини +дыня +манго +вишня +айва +черешня +яблоко +вишня +киви +апельсин +айва +лимон +банан +финик +инжир +финик +киви +клубника +черешня +вишня +малина +вишня +манго +киви +арбуз +папайя +арбуз +цуккини +айва +манго +черешня +дыня +черешня +ежевика +инжир +юзу +нектарин +манго +банан +нектарин +нектарин +айва +апельсин +инжир +папайя +ежевика +инжир +финик +апельсин +киви +клубника +манго +яблоко +инжир +цуккини +виноград +папайя +черешня +нектарин +виноград +арбуз +клубника +лимон +арбуз +яблоко +инжир +арбуз +ежевика +киви +мандарин +черешня +мандарин +яблоко +манго +ежевика +папайя +мандарин \ No newline at end of file diff --git a/TagCloudContainerTests/TagCloudContainerTests.csproj b/TagCloudContainerTests/TagCloudContainerTests.csproj index 8b5797ec..ae79cc67 100644 --- a/TagCloudContainerTests/TagCloudContainerTests.csproj +++ b/TagCloudContainerTests/TagCloudContainerTests.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -10,11 +10,20 @@ - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/TagCloudContainerTests/UnitTest1.cs b/TagCloudContainerTests/UnitTest1.cs deleted file mode 100644 index 6e38d288..00000000 --- a/TagCloudContainerTests/UnitTest1.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace TagCloudContainerTests -{ - public class Tests - { - [SetUp] - public void Setup() - { - } - - [Test] - public void Test1() - { - Assert.Pass(); - } - } -} \ No newline at end of file diff --git a/TagsCloudContainer/FileReaders/DocFileReader.cs b/TagsCloudContainer/FileReaders/DocFileReader.cs new file mode 100644 index 00000000..17ebc63e --- /dev/null +++ b/TagsCloudContainer/FileReaders/DocFileReader.cs @@ -0,0 +1,22 @@ +using Spire.Doc; + +namespace TagsCloudContainer.FileReaders +{ + public class DocFileReader : IReader + { + public string Read(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); + + var document = new Document(); + document.LoadFromFile(path); + var text = document.GetText(); + return text; + } + } + +} diff --git a/TagsCloudContainer/FileReaders/DocxFileReader.cs b/TagsCloudContainer/FileReaders/DocxFileReader.cs new file mode 100644 index 00000000..71dbfd8f --- /dev/null +++ b/TagsCloudContainer/FileReaders/DocxFileReader.cs @@ -0,0 +1,30 @@ +using NPOI.XWPF.UserModel; + +namespace TagsCloudContainer.FileReaders +{ + public class DocxFileReader : IReader + { + public string Read(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); + + using (FileStream stream = File.OpenRead(path)) + { + var docx = new XWPFDocument(stream); + using (var writer = new StringWriter()) + { + foreach (var paragraph in docx.Paragraphs) + { + writer.WriteLine(paragraph.Text); + } + return writer.ToString(); + } + } + } + } + +} diff --git a/TagsCloudContainer/FileReaders/IReader.cs b/TagsCloudContainer/FileReaders/IReader.cs new file mode 100644 index 00000000..ed143288 --- /dev/null +++ b/TagsCloudContainer/FileReaders/IReader.cs @@ -0,0 +1,7 @@ +namespace TagsCloudContainer.FileReaders +{ + public interface IReader + { + string Read(string path); + } +} diff --git a/TagsCloudContainer/FileReaders/TxtFileReader.cs b/TagsCloudContainer/FileReaders/TxtFileReader.cs new file mode 100644 index 00000000..d4d49a84 --- /dev/null +++ b/TagsCloudContainer/FileReaders/TxtFileReader.cs @@ -0,0 +1,18 @@ +namespace TagsCloudContainer.FileReaders +{ + public class TxtFileReader : IReader + { + public string Read(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); + + + return File.ReadAllText(path); + } + } + +} diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index b232426c..8d5db3a6 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -1,4 +1,5 @@ using System.Drawing; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Layouters { @@ -16,7 +17,7 @@ public CircularCloudLayouter(Point center) rectangles = new List(); } - public IEnumerable GetLayout(IOrderedEnumerable words) + public IEnumerable GetLayout(IEnumerable words) { foreach (var word in words) { @@ -33,7 +34,6 @@ public IEnumerable GetLayout(IOrderedEnumerable words) return rectangles; } - private Point GetNextLocation(Size rectangleSize) { var radius = radiusStep * angle; @@ -47,7 +47,7 @@ private bool IsIntersecting(Rectangle rectangle) { foreach (var existingRectangle in rectangles) { - if (existingRectangle.IntersectsWith(rectangle)) + if (existingRectangle.Bounds.IntersectsWith(rectangle)) return true; } return false; @@ -62,5 +62,7 @@ public static Point GetCenterPoint(Rectangle rect) { return new Point(rect.Location.X + rect.Width / 2, rect.Location.Y + rect.Height / 2); } + + } } diff --git a/TagsCloudContainer/Layouters/ILayouter.cs b/TagsCloudContainer/Layouters/ILayouter.cs index 1bb53d2c..39bfeb33 100644 --- a/TagsCloudContainer/Layouters/ILayouter.cs +++ b/TagsCloudContainer/Layouters/ILayouter.cs @@ -3,10 +3,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using TagsCloudContainer.WordClasses; +using TagsCloudContainer.WordSizer; namespace TagsCloudContainer.Layouters { - internal interface ILayouter + public interface ILayouter { + public IEnumerable GetLayout(IEnumerable words); } } diff --git a/TagsCloudContainer/Parsers/IParser.cs b/TagsCloudContainer/Parsers/IParser.cs index 0c82522f..7b50c7c8 100644 --- a/TagsCloudContainer/Parsers/IParser.cs +++ b/TagsCloudContainer/Parsers/IParser.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TagsCloudContainer.Parsers { - internal interface IParser + public interface IParser { + public IDictionary Parse(string text); } } diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 7bda4840..e489c589 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -9,6 +9,8 @@ + + diff --git a/TagsCloudContainer/TextHadlers/ITextHandler.cs b/TagsCloudContainer/TextHadlers/ITextHandler.cs index 31395562..a9b0b048 100644 --- a/TagsCloudContainer/TextHadlers/ITextHandler.cs +++ b/TagsCloudContainer/TextHadlers/ITextHandler.cs @@ -6,7 +6,8 @@ namespace TagsCloudContainer.TextHadlers { - internal interface ITextHandler + public interface ITextHandler { + public string Handle(string text); } } diff --git a/TagsCloudContainer/Visualizers/IVisualizer.cs b/TagsCloudContainer/Visualizers/IVisualizer.cs index 41d728d7..4054197a 100644 --- a/TagsCloudContainer/Visualizers/IVisualizer.cs +++ b/TagsCloudContainer/Visualizers/IVisualizer.cs @@ -3,10 +3,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Visualizers { - internal interface IVisualizer + public interface IVisualizer { + public void GenerateImage(IEnumerable words); } } diff --git a/TagsCloudContainer/Visualizers/ImageCreater.cs b/TagsCloudContainer/Visualizers/ImageCreater.cs index a73ae92b..4e185531 100644 --- a/TagsCloudContainer/Visualizers/ImageCreater.cs +++ b/TagsCloudContainer/Visualizers/ImageCreater.cs @@ -24,6 +24,7 @@ public void Generate(IEnumerable items, string directory) { count++; g.DrawRectangle(pen, item); + g.DrawString("text", SystemFonts.DialogFont, Brushes.Aqua, item.Location); } image.Save(directory, ImageFormat.Jpeg); diff --git a/TagsCloudContainer/WordClasses/RectangleWord.cs b/TagsCloudContainer/WordClasses/RectangleWord.cs index 2c16703f..f8c683b7 100644 --- a/TagsCloudContainer/WordClasses/RectangleWord.cs +++ b/TagsCloudContainer/WordClasses/RectangleWord.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace TagsCloudContainer +namespace TagsCloudContainer.WordClasses { - internal class RectangleWord - { - } + public record RectangleWord(string Value, Rectangle Bounds); } diff --git a/TagsCloudContainer/WordClasses/SizeWord.cs b/TagsCloudContainer/WordClasses/SizeWord.cs index b6e77e28..7c263f89 100644 --- a/TagsCloudContainer/WordClasses/SizeWord.cs +++ b/TagsCloudContainer/WordClasses/SizeWord.cs @@ -1,12 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; -namespace TagsCloudContainer +namespace TagsCloudContainer.WordClasses { - internal class SizeWord - { - } + public record SizeWord(string Value, Size Size); } diff --git a/TagsCloudContainer/WordSizer/ISizer.cs b/TagsCloudContainer/WordSizer/ISizer.cs index d7ba8632..d4970901 100644 --- a/TagsCloudContainer/WordSizer/ISizer.cs +++ b/TagsCloudContainer/WordSizer/ISizer.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.WordSizer { - internal interface ISizer + public interface ISizer { + public IOrderedEnumerable GetSizes(IDictionary words); } } From d5a233b620fcc40d879d9ff130b2d471c9e3e0d7 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Mon, 23 Dec 2024 19:07:48 +0500 Subject: [PATCH 04/20] Add Words Filter Logic and Parser Logic --- TagsCloudContainer/Filters/IFilter.cs | 11 ++ TagsCloudContainer/Filters/WordsFilter.cs | 71 ++++++++++++ TagsCloudContainer/Parsers/SimpleParser.cs | 40 +++++++ TagsCloudContainer/Parsers/stopwords.txt | 109 ++++++++++++++++++ TagsCloudContainer/Program.cs | 9 ++ .../TextHadlers/ITextHandler.cs | 13 --- 6 files changed, 240 insertions(+), 13 deletions(-) create mode 100644 TagsCloudContainer/Filters/IFilter.cs create mode 100644 TagsCloudContainer/Filters/WordsFilter.cs create mode 100644 TagsCloudContainer/Parsers/SimpleParser.cs create mode 100644 TagsCloudContainer/Parsers/stopwords.txt delete mode 100644 TagsCloudContainer/TextHadlers/ITextHandler.cs diff --git a/TagsCloudContainer/Filters/IFilter.cs b/TagsCloudContainer/Filters/IFilter.cs new file mode 100644 index 00000000..d8788c46 --- /dev/null +++ b/TagsCloudContainer/Filters/IFilter.cs @@ -0,0 +1,11 @@ +namespace TagsCloudContainer.Filters +{ + public interface IFilter + { + void AddStopWord(string word); + void AddStopWords(string[] wordArray); + bool Contains(string word); + void RemoveStopWord(string word); + void RemoveStopWords(string[] wordArray); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs new file mode 100644 index 00000000..8189ac91 --- /dev/null +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -0,0 +1,71 @@ +using Org.BouncyCastle.Asn1.Mozilla; +using System.IO; +using System.Text.RegularExpressions; + +namespace TagsCloudContainer.Filters +{ + public class WordsFilter : IFilter + { + private HashSet words; + public WordsFilter() + { + words = new HashSet(); + + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); + var path = Path.Combine(projectDirectory, "Parsers\\stopwords.txt"); + + if (!File.Exists(path)) + { + throw new FileNotFoundException("Файл не найден.", path); + } + + string text = File.ReadAllText(path); + + string pattern = @"\b[а-яА-ЯёЁa-zA-Z]+\b"; + + var matches = Regex.Matches(text, pattern); + + for (var i = 0; i < matches.Count; i++) + { + if (!words.Contains(matches[i].Value)) + words.Add(matches[i].Value); + } + } + + public bool Contains(string word) + { + return words.Contains(word); + } + + public void AddStopWord(string word) + { + if (!words.Contains(word)) + words.Add(word); + } + + public void RemoveStopWord(string word) + { + if (words.Contains(word)) + words.Remove(word); + } + + public void AddStopWords(string[] wordArray) + { + foreach (var word in wordArray) + { + if (!words.Contains(word)) + words.Add(word); + } + } + + public void RemoveStopWords(string[] wordArray) + { + foreach (var word in wordArray) + { + if (words.Contains(word)) + words.Remove(word); + } + } + } +} diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs new file mode 100644 index 00000000..e7f28e99 --- /dev/null +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -0,0 +1,40 @@ +using System.Text.RegularExpressions; +using TagsCloudContainer.Filters; + +namespace TagsCloudContainer.Parsers +{ + public class SimpleParser : IParser + { + private IFilter wordsFilter; + public SimpleParser(IFilter wordsFilter) + { + this.wordsFilter = wordsFilter; + } + + public IDictionary Parse(string text) + { + var dict = new Dictionary(); + string pattern = @"\b[а-яА-ЯёЁa-zA-Z]+\b"; + + var words = Regex.Matches(text, pattern); + + var wordArray = new List(); + for (int i = 0; i < words.Count; i++) + { + var word = words[i].Value; + if (!wordsFilter.Contains(word)) + { + if (dict.Keys.Contains(word)) + { + dict[word]++; + } + else + { + dict.Add(word,1); + } + } + } + return dict; + } + } +} diff --git a/TagsCloudContainer/Parsers/stopwords.txt b/TagsCloudContainer/Parsers/stopwords.txt new file mode 100644 index 00000000..273be4ac --- /dev/null +++ b/TagsCloudContainer/Parsers/stopwords.txt @@ -0,0 +1,109 @@ +а +без +близ +будто +бы +в +во +вне +вот +всё +все +всего +всегда +да +даже +для +до +его +её +ей +если +есть +же +за +и +из +или +им +ими +их +к +как +кем +ко +когда +который +кто +ли +либо +между +меня +мне +мной +много +моё +может +моя +мы +на +над +надо +нам +нами +нас +наш +не +него +неё +нет +ни +них +но +о +об +однако +он +она +они +оно +от +по +под +при +про +раз +с +сам +сами +свой +со +тебе +тебя +тем +то +тобой +тоже +того +тогда +той +только +том +тот +три +ты +у +уж +уже +чего +чей +чем +что +чтоб +чтобы +чья +эта +эти +это +этот +я \ No newline at end of file diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index bd9e4ae3..616a088a 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,9 +1,18 @@ using Autofac; +using TagsCloudContainer.FileReaders; +using TagsCloudContainer.Filters; +using TagsCloudContainer.Parsers; +using WeCantSpell.Hunspell; public static class Program { public static void Main() { var builder = new ContainerBuilder(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + var container = builder.Build(); } } \ No newline at end of file diff --git a/TagsCloudContainer/TextHadlers/ITextHandler.cs b/TagsCloudContainer/TextHadlers/ITextHandler.cs deleted file mode 100644 index a9b0b048..00000000 --- a/TagsCloudContainer/TextHadlers/ITextHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudContainer.TextHadlers -{ - public interface ITextHandler - { - public string Handle(string text); - } -} From 321858b4fc5c3a7940eecde0933ab13ac3ce4ad7 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Mon, 23 Dec 2024 22:05:41 +0500 Subject: [PATCH 05/20] Add Console Client Logic --- TagsCloudContainer/Clients/ConsoleClient.cs | 60 ++++++++++++++++++++ TagsCloudContainer/Clients/IClient.cs | 12 ++++ TagsCloudContainer/Config.cs | 21 +++++++ TagsCloudContainer/Program.cs | 10 +++- TagsCloudContainer/TagsCloudContainer.csproj | 1 + TagsCloudContainer/WordSizer/SimpleSizer.cs | 33 +++++++++++ 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 TagsCloudContainer/Clients/ConsoleClient.cs create mode 100644 TagsCloudContainer/Clients/IClient.cs create mode 100644 TagsCloudContainer/Config.cs create mode 100644 TagsCloudContainer/WordSizer/SimpleSizer.cs diff --git a/TagsCloudContainer/Clients/ConsoleClient.cs b/TagsCloudContainer/Clients/ConsoleClient.cs new file mode 100644 index 00000000..d58c321a --- /dev/null +++ b/TagsCloudContainer/Clients/ConsoleClient.cs @@ -0,0 +1,60 @@ +using System; +using System.Drawing; +using McMaster.Extensions.CommandLineUtils; +using System.Linq; +using System.Runtime.InteropServices; + +namespace TagsCloudContainer.Clients +{ + public class ConsoleClient + { + [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] + public string InputFile { get; set; } + + [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] + public string OutputFile { get; set; } + + [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] + public int PictureWidth { get; set; } + + [Option("--height", "Height of the picture.", CommandOptionType.SingleValue)] + public int PictureHeight { get; set; } + + [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] + public string Font { get; set; } + + [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] + public string StopWordsInput { get; set; } + + [Option("--colors", "Comma-separated list of colors in ARGB format (0,0,255).", CommandOptionType.SingleValue)] + public string ColorsInput { get; set; } + + public string[] StopWords => StopWordsInput?.Split(',') ?? Array.Empty(); + + public Color[] PictureColors => + ColorsInput?.Split(',').Select(color => + { + var components = color.Split(' ').Select(int.Parse).ToArray(); + return Color.FromArgb(components[0], components[1], components[2]); + }).ToArray() ?? Array.Empty(); + + public static ConsoleClient ParseArguments(string[] args) + { + var app = new CommandLineApplication(); + app.Conventions.UseDefaultConventions(); + app.Execute(args); + return app.Model; + } + + private void OnExecute() + { + Console.WriteLine($"Input File: {InputFile}"); + Console.WriteLine($"Output File: {OutputFile}"); + Console.WriteLine($"Picture Width: {PictureWidth}"); + Console.WriteLine($"Picture Height: {PictureHeight}"); + Console.WriteLine($"Font: {Font}"); + Console.WriteLine($"Stop Words: {string.Join(", ", StopWords)}"); + Console.WriteLine($"Picture Colors: {string.Join(", ", PictureColors.Select(c => c.ToString()))}"); + } + } +} diff --git a/TagsCloudContainer/Clients/IClient.cs b/TagsCloudContainer/Clients/IClient.cs new file mode 100644 index 00000000..3fe0deb6 --- /dev/null +++ b/TagsCloudContainer/Clients/IClient.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.Clients +{ + public interface IClient + { + } +} diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs new file mode 100644 index 00000000..67a50f9a --- /dev/null +++ b/TagsCloudContainer/Config.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer +{ + public class Config + { + public string InputFile { get; set; } + public string OutputFile { get; set; } + public int PictureWidth { get; set; } + public int PictureHeight { get; set; } + public string Font { get; set; } + public string[] StopWords { get; set; } + public Color[] PictureColors { get; set; } + + } +} diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 616a088a..7afd397b 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,18 +1,22 @@ using Autofac; +using McMaster.Extensions.CommandLineUtils; +using TagsCloudContainer.Clients; using TagsCloudContainer.FileReaders; using TagsCloudContainer.Filters; using TagsCloudContainer.Parsers; -using WeCantSpell.Hunspell; public static class Program { - public static void Main() + public static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); - var container = builder.Build(); + + var app = ConsoleClient.ParseArguments(args); + Console.WriteLine(app.InputFile); + Console.ReadLine(); } } \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index e489c589..55b2deb5 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -10,6 +10,7 @@ + diff --git a/TagsCloudContainer/WordSizer/SimpleSizer.cs b/TagsCloudContainer/WordSizer/SimpleSizer.cs new file mode 100644 index 00000000..6c900115 --- /dev/null +++ b/TagsCloudContainer/WordSizer/SimpleSizer.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TagsCloudContainer.WordClasses; + +namespace TagsCloudContainer.WordSizer +{ + public class SimpleSizer : ISizer + { + public IOrderedEnumerable GetSizes(IDictionary words) + { + var orderedKeys = words.OrderByDescending(x => x.Key).ToDictionary().Keys; + return default; + } + + static SizeF GetTextSize(string text, string fontName, float fontSize) + { + using (var font = new Font(fontName, fontSize)) + { + using (var tempBitmap = new Bitmap(1, 1)) + { + using (var graphics = Graphics.FromImage(tempBitmap)) + { + return graphics.MeasureString(text, font); + } + } + } + } + } +} From 3053fe8cc487dd84c4308656d75bcc4c0ae4393d Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 11:10:37 +0500 Subject: [PATCH 06/20] Connect all project, Separate Client and Logic, add logic to ISizer --- ConsoleClient/ConsoleClient.cs | 58 ++ ConsoleClient/ConsoleClient.csproj | 18 + .../TagCloudContainerTests.csproj | 2 +- TagsCloudContainer/Clients/ConsoleClient.cs | 60 --- TagsCloudContainer/Clients/IClient.cs | 12 - TagsCloudContainer/Config.cs | 33 +- TagsCloudContainer/Constants.cs | 43 ++ TagsCloudContainer/Filters/WordsFilter.cs | 10 +- .../Layouters/CircularCloudLayouter.cs | 17 +- TagsCloudContainer/Parsers/SimpleParser.cs | 5 +- TagsCloudContainer/Program.cs | 54 +- .../Properties/launchSettings.json | 11 + TagsCloudContainer/TagsCloudContainer.csproj | 7 +- TagsCloudContainer/TagsCloudContainer.sln | 6 + .../Visualizers/ImageCreater.cs | 34 -- .../Visualizers/ImageVisualizer.cs | 32 ++ .../WordClasses/RectangleWord.cs | 2 +- TagsCloudContainer/WordClasses/SizeWord.cs | 2 +- TagsCloudContainer/WordSizer/ISizer.cs | 2 +- TagsCloudContainer/WordSizer/SimpleSizer.cs | 57 +- TagsCloudContainer/defaultTxt.txt | 500 ++++++++++++++++++ TagsCloudContainer/defaultTxt1.txt | 29 + TagsCloudContainer/picture.jpg | Bin 0 -> 54314 bytes 23 files changed, 834 insertions(+), 160 deletions(-) create mode 100644 ConsoleClient/ConsoleClient.cs create mode 100644 ConsoleClient/ConsoleClient.csproj delete mode 100644 TagsCloudContainer/Clients/ConsoleClient.cs delete mode 100644 TagsCloudContainer/Clients/IClient.cs create mode 100644 TagsCloudContainer/Constants.cs create mode 100644 TagsCloudContainer/Properties/launchSettings.json delete mode 100644 TagsCloudContainer/Visualizers/ImageCreater.cs create mode 100644 TagsCloudContainer/Visualizers/ImageVisualizer.cs create mode 100644 TagsCloudContainer/defaultTxt.txt create mode 100644 TagsCloudContainer/defaultTxt1.txt create mode 100644 TagsCloudContainer/picture.jpg diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs new file mode 100644 index 00000000..20374a36 --- /dev/null +++ b/ConsoleClient/ConsoleClient.cs @@ -0,0 +1,58 @@ +using McMaster.Extensions.CommandLineUtils; +using System.Drawing; +using TagsCloudContainer; + +public class ConsoleClient +{ + [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] + public string InputDirectory { get; set; } + + [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] + public string OutputDirectory { get; set; } + + [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] + public int PictureWidth { get; set; } + + [Option("--height", "Height of the picture.", CommandOptionType.SingleValue)] + public int PictureHeight { get; set; } + + [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] + public string Font { get; set; } + + [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] + public string StopWordsInput { get; set; } + + [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] + public string ColorsInput { get; set; } + + public string[] StopWords => StopWordsInput?.Split(',') ?? Array.Empty(); + + public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); + //ColorsInput?.Split(',').Select(color => + //{ + // var components = color.Split(' ').Select(int.Parse).ToArray(); + // return Color.FromArgb(components[0], components[1], components[2], components[3]); + //}).ToArray() ?? Array.Empty(); + + public static int Main(string[] args) + { + return CommandLineApplication.Execute(args); + } + + private void OnExecute() + { + var config = new Config( + InputDirectory is null ? Constants.InputDirectory : InputDirectory, + OutputDirectory is null ? Constants.OutputDirectory : OutputDirectory, + PictureWidth == default ? Constants.PictureWidth : PictureWidth, + PictureHeight == default ? Constants.PictureHeight : PictureHeight, + Font is null ? Constants.Font : Font, + StopWords is null ? Constants.StopWords : StopWords, + PictureColors is null ? Constants.PictureColors : PictureColors + ); + + TagsCloudContainer.Program.Main(config); + Console.WriteLine(config); + } +} + diff --git a/ConsoleClient/ConsoleClient.csproj b/ConsoleClient/ConsoleClient.csproj new file mode 100644 index 00000000..7aba20c5 --- /dev/null +++ b/ConsoleClient/ConsoleClient.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0-windows + enable + enable + + + + + + + + + + + diff --git a/TagCloudContainerTests/TagCloudContainerTests.csproj b/TagCloudContainerTests/TagCloudContainerTests.csproj index ae79cc67..b3eef997 100644 --- a/TagCloudContainerTests/TagCloudContainerTests.csproj +++ b/TagCloudContainerTests/TagCloudContainerTests.csproj @@ -1,7 +1,7 @@  - net8.0 + net8.0-windows enable enable diff --git a/TagsCloudContainer/Clients/ConsoleClient.cs b/TagsCloudContainer/Clients/ConsoleClient.cs deleted file mode 100644 index d58c321a..00000000 --- a/TagsCloudContainer/Clients/ConsoleClient.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Drawing; -using McMaster.Extensions.CommandLineUtils; -using System.Linq; -using System.Runtime.InteropServices; - -namespace TagsCloudContainer.Clients -{ - public class ConsoleClient - { - [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] - public string InputFile { get; set; } - - [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] - public string OutputFile { get; set; } - - [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] - public int PictureWidth { get; set; } - - [Option("--height", "Height of the picture.", CommandOptionType.SingleValue)] - public int PictureHeight { get; set; } - - [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] - public string Font { get; set; } - - [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] - public string StopWordsInput { get; set; } - - [Option("--colors", "Comma-separated list of colors in ARGB format (0,0,255).", CommandOptionType.SingleValue)] - public string ColorsInput { get; set; } - - public string[] StopWords => StopWordsInput?.Split(',') ?? Array.Empty(); - - public Color[] PictureColors => - ColorsInput?.Split(',').Select(color => - { - var components = color.Split(' ').Select(int.Parse).ToArray(); - return Color.FromArgb(components[0], components[1], components[2]); - }).ToArray() ?? Array.Empty(); - - public static ConsoleClient ParseArguments(string[] args) - { - var app = new CommandLineApplication(); - app.Conventions.UseDefaultConventions(); - app.Execute(args); - return app.Model; - } - - private void OnExecute() - { - Console.WriteLine($"Input File: {InputFile}"); - Console.WriteLine($"Output File: {OutputFile}"); - Console.WriteLine($"Picture Width: {PictureWidth}"); - Console.WriteLine($"Picture Height: {PictureHeight}"); - Console.WriteLine($"Font: {Font}"); - Console.WriteLine($"Stop Words: {string.Join(", ", StopWords)}"); - Console.WriteLine($"Picture Colors: {string.Join(", ", PictureColors.Select(c => c.ToString()))}"); - } - } -} diff --git a/TagsCloudContainer/Clients/IClient.cs b/TagsCloudContainer/Clients/IClient.cs deleted file mode 100644 index 3fe0deb6..00000000 --- a/TagsCloudContainer/Clients/IClient.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudContainer.Clients -{ - public interface IClient - { - } -} diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index 67a50f9a..72aff19f 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -9,13 +9,30 @@ namespace TagsCloudContainer { public class Config { - public string InputFile { get; set; } - public string OutputFile { get; set; } - public int PictureWidth { get; set; } - public int PictureHeight { get; set; } - public string Font { get; set; } - public string[] StopWords { get; set; } - public Color[] PictureColors { get; set; } - + public string InputDirectory { get; init; } + public string OutputDirectory { get; init; } + public int PictureWidth { get; init; } + public int PictureHeight { get; init; } + public string Font { get; init; } + public string[] StopWords { get; init; } + public string[] PictureColors { get; init; } + + public Config( + string inputDirectory, + string outputDirectory, + int pictureWidth, + int pictureHeight, + string font, + string[] stopWords, + string[] pictureColors) + { + InputDirectory = inputDirectory; + OutputDirectory = outputDirectory; + PictureWidth = pictureWidth; + PictureHeight = pictureHeight; + Font = font; + StopWords = stopWords; + PictureColors = pictureColors; + } } } diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs new file mode 100644 index 00000000..3ed0049e --- /dev/null +++ b/TagsCloudContainer/Constants.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace TagsCloudContainer +{ + public static class Constants + { + public static string InputDirectory + { + get + { + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\defaultTxt1.txt"); + } + } + + public static string OutputDirectory { get + { + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\picture.jpg"); + } + } + public static int PictureWidth { get { return 1000; } } + + public static int PictureHeight { get { return 1000; } } + + public static string Font { get { return "Arial"; } } + + public static string[] StopWords { get { return []; } } + + public static string[] PictureColors { get { return []; } } + + public static Regex wordsSplitRegex = new(pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", + options: RegexOptions.Compiled | RegexOptions.IgnoreCase); + + } +} diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 8189ac91..3680d2ea 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -9,11 +9,11 @@ public class WordsFilter : IFilter private HashSet words; public WordsFilter() { - words = new HashSet(); + words = []; var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); - var path = Path.Combine(projectDirectory, "Parsers\\stopwords.txt"); + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + var path = Path.Combine(projectDirectory, "TagsCloudContainer\\Parsers\\stopwords.txt"); if (!File.Exists(path)) { @@ -22,9 +22,7 @@ public WordsFilter() string text = File.ReadAllText(path); - string pattern = @"\b[а-яА-ЯёЁa-zA-Z]+\b"; - - var matches = Regex.Matches(text, pattern); + var matches = Constants.wordsSplitRegex.Matches(text); for (var i = 0; i < matches.Count; i++) { diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index 8d5db3a6..61e4504b 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -5,20 +5,21 @@ namespace TagsCloudContainer.Layouters { public class CircularCloudLayouter : ILayouter { - public readonly List rectangles; - public readonly Point center; + public readonly List rectangles = []; + public Point center; private double angle; - private double spiralStep = 0.1; - private double radiusStep = 0.5; + private const double spiralStep = 0.1; + private const double radiusStep = 0.5; + private readonly Config config; - public CircularCloudLayouter(Point center) + public CircularCloudLayouter(Config config) { - this.center = center; - rectangles = new List(); + this.config = config; } public IEnumerable GetLayout(IEnumerable words) { + center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); foreach (var word in words) { var rectangleSize = word.Size; @@ -29,7 +30,7 @@ public IEnumerable GetLayout(IEnumerable words) newRect = new Rectangle(location, rectangleSize); } while (IsIntersecting(newRect)); - rectangles.Add(new RectangleWord(word.Value, newRect)); + rectangles.Add(new RectangleWord(word.Value, newRect, word.font)); } return rectangles; } diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs index e7f28e99..fccc17db 100644 --- a/TagsCloudContainer/Parsers/SimpleParser.cs +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -14,12 +14,11 @@ public SimpleParser(IFilter wordsFilter) public IDictionary Parse(string text) { var dict = new Dictionary(); - string pattern = @"\b[а-яА-ЯёЁa-zA-Z]+\b"; - var words = Regex.Matches(text, pattern); + var words = Constants.wordsSplitRegex.Matches(text.ToLower()); var wordArray = new List(); - for (int i = 0; i < words.Count; i++) + for (var i = 0; i < words.Count; i++) { var word = words[i].Value; if (!wordsFilter.Contains(word)) diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 7afd397b..ab1377cc 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,22 +1,50 @@ using Autofac; -using McMaster.Extensions.CommandLineUtils; -using TagsCloudContainer.Clients; +using NPOI.SS.Formula.Functions; +using Org.BouncyCastle.Crypto; using TagsCloudContainer.FileReaders; using TagsCloudContainer.Filters; +using TagsCloudContainer.Layouters; using TagsCloudContainer.Parsers; +using TagsCloudContainer.Visualizers; +using TagsCloudContainer.WordSizer; -public static class Program +namespace TagsCloudContainer { - public static void Main(string[] args) + public static class Program { - var builder = new ContainerBuilder(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - var container = builder.Build(); + public static void Main() + { + } + public static void Main(Config config) + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(config).As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + var container = builder.Build(); - var app = ConsoleClient.ParseArguments(args); - Console.WriteLine(app.InputFile); - Console.ReadLine(); + var reader = container.Resolve(); + var filter = container.Resolve(); + var parser = container.Resolve(); + var sizer = container.Resolve(); + var layouter = container.Resolve(); + var visualizer = container.Resolve(); + + visualizer.GenerateImage( + layouter.GetLayout( + sizer.GetSizes( + parser.Parse( + reader.Read( + config.InputDirectory + ) + ) + ) + ) + ); + } } -} \ No newline at end of file +} diff --git a/TagsCloudContainer/Properties/launchSettings.json b/TagsCloudContainer/Properties/launchSettings.json new file mode 100644 index 00000000..5139a453 --- /dev/null +++ b/TagsCloudContainer/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "TagsCloudContainer": { + "commandName": "Project" + }, + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 55b2deb5..e2dac9f3 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -2,17 +2,22 @@ Exe - net8.0 + net8.0-windows enable enable + + + + + diff --git a/TagsCloudContainer/TagsCloudContainer.sln b/TagsCloudContainer/TagsCloudContainer.sln index 327c990b..eb748b23 100644 --- a/TagsCloudContainer/TagsCloudContainer.sln +++ b/TagsCloudContainer/TagsCloudContainer.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudContainer", "TagsC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagCloudContainerTests", "..\TagCloudContainerTests\TagCloudContainerTests.csproj", "{AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleClient", "..\ConsoleClient\ConsoleClient.csproj", "{8F98E6EF-0BD6-4B65-9FD0-F22234E878BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU {AAFEE184-BFF5-47B3-9B3B-97654DED9DBF}.Release|Any CPU.Build.0 = Release|Any CPU + {8F98E6EF-0BD6-4B65-9FD0-F22234E878BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F98E6EF-0BD6-4B65-9FD0-F22234E878BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F98E6EF-0BD6-4B65-9FD0-F22234E878BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F98E6EF-0BD6-4B65-9FD0-F22234E878BD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TagsCloudContainer/Visualizers/ImageCreater.cs b/TagsCloudContainer/Visualizers/ImageCreater.cs deleted file mode 100644 index 4e185531..00000000 --- a/TagsCloudContainer/Visualizers/ImageCreater.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; - -namespace TagsCloudContainer.Visualizers -{ - public class ImageCreater - { - private readonly int Width; - private readonly int Height; - - public ImageCreater(int width, int height) - { - Width = width; - Height = height; - } - - public void Generate(IEnumerable items, string directory) - { - var image = new Bitmap(Width, Height); - var g = Graphics.FromImage(image); - var pen = new Pen(Brushes.AliceBlue, 2); - var count = 0; - foreach (var item in items) - { - count++; - g.DrawRectangle(pen, item); - g.DrawString("text", SystemFonts.DialogFont, Brushes.Aqua, item.Location); - } - - image.Save(directory, ImageFormat.Jpeg); - - } - } -} diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs new file mode 100644 index 00000000..a99fe64c --- /dev/null +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -0,0 +1,32 @@ +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using TagsCloudContainer.WordClasses; + +namespace TagsCloudContainer.Visualizers +{ + public class ImageVisualizer : IVisualizer + { + private Config config; + public ImageVisualizer(Config config) + { + this.config = config; + } + + public void GenerateImage(IEnumerable words) + { + var image = new Bitmap(config.PictureWidth, config.PictureWidth); + var g = Graphics.FromImage(image); + var pen = new Pen(Brushes.AliceBlue, 2); + var count = 0; + foreach (var item in words) + { + count++; + g.DrawRectangle(pen, item.Bounds); + g.DrawString(item.Value, item.font, Brushes.Orange, item.Bounds.Location); + } + + image.Save(config.OutputDirectory, ImageFormat.Jpeg); + } + } +} diff --git a/TagsCloudContainer/WordClasses/RectangleWord.cs b/TagsCloudContainer/WordClasses/RectangleWord.cs index f8c683b7..bb3771d6 100644 --- a/TagsCloudContainer/WordClasses/RectangleWord.cs +++ b/TagsCloudContainer/WordClasses/RectangleWord.cs @@ -7,5 +7,5 @@ namespace TagsCloudContainer.WordClasses { - public record RectangleWord(string Value, Rectangle Bounds); + public record RectangleWord(string Value, Rectangle Bounds, Font font); } diff --git a/TagsCloudContainer/WordClasses/SizeWord.cs b/TagsCloudContainer/WordClasses/SizeWord.cs index 7c263f89..35418731 100644 --- a/TagsCloudContainer/WordClasses/SizeWord.cs +++ b/TagsCloudContainer/WordClasses/SizeWord.cs @@ -2,5 +2,5 @@ namespace TagsCloudContainer.WordClasses { - public record SizeWord(string Value, Size Size); + public record SizeWord(string Value, Size Size, Font font); } diff --git a/TagsCloudContainer/WordSizer/ISizer.cs b/TagsCloudContainer/WordSizer/ISizer.cs index d4970901..f35bb33a 100644 --- a/TagsCloudContainer/WordSizer/ISizer.cs +++ b/TagsCloudContainer/WordSizer/ISizer.cs @@ -10,6 +10,6 @@ namespace TagsCloudContainer.WordSizer { public interface ISizer { - public IOrderedEnumerable GetSizes(IDictionary words); + public IEnumerable GetSizes(IDictionary words); } } diff --git a/TagsCloudContainer/WordSizer/SimpleSizer.cs b/TagsCloudContainer/WordSizer/SimpleSizer.cs index 6c900115..8bb67e12 100644 --- a/TagsCloudContainer/WordSizer/SimpleSizer.cs +++ b/TagsCloudContainer/WordSizer/SimpleSizer.cs @@ -1,7 +1,9 @@ -using System; +using NPOI.OpenXmlFormats.Dml; +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using System.Net.WebSockets; using System.Text; using System.Threading.Tasks; using TagsCloudContainer.WordClasses; @@ -10,24 +12,57 @@ namespace TagsCloudContainer.WordSizer { public class SimpleSizer : ISizer { - public IOrderedEnumerable GetSizes(IDictionary words) + private readonly Config config; + + public SimpleSizer(Config config) { - var orderedKeys = words.OrderByDescending(x => x.Key).ToDictionary().Keys; - return default; + this.config = config; } - static SizeF GetTextSize(string text, string fontName, float fontSize) + public IEnumerable GetSizes(IDictionary words) { - using (var font = new Font(fontName, fontSize)) + var screeenSize = config.PictureHeight * config.PictureWidth; + var sum = words.Sum(x => x.Value); + var list = new List(); + + foreach (var item in words.OrderByDescending(x => x.Value)) { - using (var tempBitmap = new Bitmap(1, 1)) + var part = (double)item.Value / sum; + var maxHeight = (int)(config.PictureHeight * part); + var maxWidth = (int)(config.PictureWidth * part); + var maxSize = new Size(maxWidth, maxHeight); + var (size, font) = GetFontSize(maxSize, config.Font, item.Key); + list.Add(new SizeWord(item.Key, size, font)); + //list.Add(new SizeWord(item.Key, maxSize, new Font("Arial", 23))); + } + return list; + } + + private static (Size, Font) GetFontSize(Size maxSize, string fontName, string text) + { + var maxFontSize = 200; + var minFontSize = 1; + + var tempBitmap = new Bitmap(1, 1); + var graphics = Graphics.FromImage(tempBitmap); + Size textSize; + Font font; + + for (var i = maxFontSize; i >= minFontSize; i--) + { + font = new Font(fontName, i); + var t = graphics.MeasureString(text, font); + textSize = t.ToSize(); + if (textSize.Width * textSize.Height <= maxSize.Width * maxSize.Height) { - using (var graphics = Graphics.FromImage(tempBitmap)) - { - return graphics.MeasureString(text, font); - } + return (textSize, font); } } + + font = new Font(fontName, 1); + textSize = graphics.MeasureString(text, font).ToSize(); + return (textSize, font); } + } } diff --git a/TagsCloudContainer/defaultTxt.txt b/TagsCloudContainer/defaultTxt.txt new file mode 100644 index 00000000..e2dde216 --- /dev/null +++ b/TagsCloudContainer/defaultTxt.txt @@ -0,0 +1,500 @@ +ежевика +клубника +клубника +банан +киви +киви +папайя +манго +инжир +мандарин +облепиха +лимон +айва +финик +черешня +мандарин +инжир +манго +ваниль +арбуз +апельсин +черешня +арбуз +ежевика +ваниль +финик +папайя +клубника +финик +финик +юзу +яблоко +дыня +вишня +виноград +апельсин +мандарин +юзу +облепиха +айва +вишня +айва +нектарин +облепиха +лимон +дыня +мандарин +апельсин +арбуз +черешня +дыня +мандарин +киви +нектарин +вишня +айва +ежевика +манго +банан +папайя +инжир +киви +апельсин +цуккини +папайя +малина +дыня +ежевика +юзу +дыня +апельсин +облепиха +ежевика +дыня +банан +нектарин +ваниль +банан +ежевика +вишня +яблоко +лимон +виноград +клубника +малина +яблоко +облепиха +юзу +арбуз +киви +дыня +инжир +мандарин +дыня +манго +нектарин +айва +ваниль +финик +финик +клубника +папайя +банан +яблоко +цуккини +апельсин +клубника +клубника +апельсин +клубника +киви +цуккини +мандарин +айва +финик +папайя +лимон +черешня +клубника +финик +манго +виноград +цуккини +виноград +малина +ваниль +ежевика +ежевика +виноград +нектарин +айва +банан +ежевика +цуккини +клубника +киви +инжир +виноград +вишня +малина +яблоко +нектарин +малина +манго +банан +дыня +ваниль +киви +нектарин +вишня +ваниль +цуккини +виноград +ежевика +апельсин +банан +клубника +виноград +киви +вишня +нектарин +лимон +банан +малина +облепиха +финик +ваниль +арбуз +дыня +виноград +ежевика +юзу +лимон +черешня +финик +арбуз +яблоко +облепиха +виноград +вишня +яблоко +нектарин +дыня +арбуз +малина +облепиха +черешня +арбуз +манго +манго +облепиха +лимон +манго +дыня +ежевика +нектарин +нектарин +мандарин +черешня +папайя +клубника +финик +яблоко +лимон +апельсин +клубника +киви +манго +апельсин +виноград +айва +нектарин +арбуз +малина +виноград +дыня +ваниль +айва +лимон +малина +апельсин +вишня +виноград +киви +мандарин +ваниль +киви +дыня +клубника +вишня +лимон +мандарин +ежевика +банан +цуккини +вишня +облепиха +нектарин +виноград +яблоко +арбуз +облепиха +юзу +папайя +черешня +клубника +нектарин +папайя +манго +цуккини +лимон +нектарин +клубника +апельсин +малина +киви +виноград +ежевика +дыня +дыня +финик +дыня +инжир +черешня +манго +арбуз +ежевика +ваниль +арбуз +нектарин +инжир +арбуз +мандарин +ваниль +манго +вишня +облепиха +арбуз +вишня +инжир +банан +вишня +виноград +финик +юзу +арбуз +инжир +цуккини +облепиха +яблоко +дыня +юзу +ваниль +киви +инжир +облепиха +ваниль +апельсин +дыня +нектарин +яблоко +лимон +папайя +апельсин +малина +ежевика +ежевика +апельсин +лимон +папайя +апельсин +дыня +дыня +финик +юзу +киви +цуккини +вишня +клубника +лимон +вишня +дыня +айва +ваниль +ваниль +мандарин +мандарин +яблоко +апельсин +юзу +вишня +клубника +финик +облепиха +юзу +ваниль +юзу +дыня +манго +цуккини +апельсин +цуккини +клубника +апельсин +папайя +ежевика +лимон +цуккини +айва +облепиха +дыня +мандарин +лимон +киви +мандарин +юзу +банан +виноград +виноград +киви +черешня +манго +ежевика +айва +яблоко +цуккини +банан +виноград +черешня +апельсин +киви +арбуз +малина +нектарин +киви +банан +манго +ваниль +облепиха +юзу +нектарин +яблоко +вишня +нектарин +лимон +арбуз +лимон +папайя +цуккини +апельсин +инжир +банан +виноград +финик +айва +дыня +вишня +финик +ваниль +мандарин +малина +киви +инжир +киви +банан +цуккини +лимон +вишня +облепиха +инжир +финик +юзу +цуккини +инжир +апельсин +малина +апельсин +дыня +банан +виноград +киви +юзу +дыня +цуккини +дыня +манго +вишня +айва +черешня +яблоко +вишня +киви +апельсин +айва +лимон +банан +финик +инжир +финик +киви +клубника +черешня +вишня +малина +вишня +манго +киви +арбуз +папайя +арбуз +цуккини +айва +манго +черешня +дыня +черешня +ежевика +инжир +юзу +нектарин +манго +банан +нектарин +нектарин +айва +апельсин +инжир +папайя +ежевика +инжир +финик +апельсин +киви +клубника +манго +яблоко +инжир +цуккини +виноград +папайя +черешня +нектарин +виноград +арбуз +клубника +лимон +арбуз +яблоко +инжир +арбуз +ежевика +киви +мандарин +черешня +мандарин +яблоко +манго +ежевика +папайя +мандарин \ No newline at end of file diff --git a/TagsCloudContainer/defaultTxt1.txt b/TagsCloudContainer/defaultTxt1.txt new file mode 100644 index 00000000..929e3de9 --- /dev/null +++ b/TagsCloudContainer/defaultTxt1.txt @@ -0,0 +1,29 @@ +python +python +python +python +python +python +python +python +python +python +code +code +code +code +code +code +code +code +developer +developer +developer +developer +developer +algorithm +algorithm +algorithm +data +data +analysis \ No newline at end of file diff --git a/TagsCloudContainer/picture.jpg b/TagsCloudContainer/picture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d6532e87ce1542bcf94937b39867b3622c8feef GIT binary patch literal 54314 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 Date: Thu, 26 Dec 2024 11:35:40 +0500 Subject: [PATCH 07/20] Refactor IFilter logic and move all files to folder --- ConsoleClient/ConsoleClient.cs | 5 --- TagsCloudContainer/Constants.cs | 19 +++++++--- TagsCloudContainer/{ => Files}/defaultTxt.txt | 0 .../{ => Files}/defaultTxt1.txt | 0 .../stopwords.txt => Files/filterwords.txt} | 0 TagsCloudContainer/Files/picture.jpg | Bin 0 -> 38860 bytes TagsCloudContainer/Filters/WordsFilter.cs | 33 +++++++----------- TagsCloudContainer/picture.jpg | Bin 54314 -> 0 bytes 8 files changed, 27 insertions(+), 30 deletions(-) rename TagsCloudContainer/{ => Files}/defaultTxt.txt (100%) rename TagsCloudContainer/{ => Files}/defaultTxt1.txt (100%) rename TagsCloudContainer/{Parsers/stopwords.txt => Files/filterwords.txt} (100%) create mode 100644 TagsCloudContainer/Files/picture.jpg delete mode 100644 TagsCloudContainer/picture.jpg diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 20374a36..808f4a14 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -28,11 +28,6 @@ public class ConsoleClient public string[] StopWords => StopWordsInput?.Split(',') ?? Array.Empty(); public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); - //ColorsInput?.Split(',').Select(color => - //{ - // var components = color.Split(' ').Select(int.Parse).ToArray(); - // return Color.FromArgb(components[0], components[1], components[2], components[3]); - //}).ToArray() ?? Array.Empty(); public static int Main(string[] args) { diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index 3ed0049e..089c4a95 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -15,7 +15,7 @@ public static string InputDirectory { var projectDirectory = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\defaultTxt1.txt"); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); } } @@ -23,12 +23,23 @@ public static string OutputDirectory { get { var projectDirectory = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\picture.jpg"); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\picture.jpg"); } } - public static int PictureWidth { get { return 1000; } } - public static int PictureHeight { get { return 1000; } } + public static string FilterWordsDirectory + { + get + { + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); + } + } + + public static int PictureWidth { get { return 800; } } + + public static int PictureHeight { get { return 800; } } public static string Font { get { return "Arial"; } } diff --git a/TagsCloudContainer/defaultTxt.txt b/TagsCloudContainer/Files/defaultTxt.txt similarity index 100% rename from TagsCloudContainer/defaultTxt.txt rename to TagsCloudContainer/Files/defaultTxt.txt diff --git a/TagsCloudContainer/defaultTxt1.txt b/TagsCloudContainer/Files/defaultTxt1.txt similarity index 100% rename from TagsCloudContainer/defaultTxt1.txt rename to TagsCloudContainer/Files/defaultTxt1.txt diff --git a/TagsCloudContainer/Parsers/stopwords.txt b/TagsCloudContainer/Files/filterwords.txt similarity index 100% rename from TagsCloudContainer/Parsers/stopwords.txt rename to TagsCloudContainer/Files/filterwords.txt diff --git a/TagsCloudContainer/Files/picture.jpg b/TagsCloudContainer/Files/picture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95d88b0dff142f3007876180627b6ec66d0b9a63 GIT binary patch literal 38860 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 H*Vumpoh;zI literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 3680d2ea..548e6b4e 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -1,34 +1,31 @@ using Org.BouncyCastle.Asn1.Mozilla; using System.IO; using System.Text.RegularExpressions; +using TagsCloudContainer.FileReaders; namespace TagsCloudContainer.Filters { public class WordsFilter : IFilter { private HashSet words; - public WordsFilter() + private Config config; + public WordsFilter(Config config) { - words = []; - - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - var path = Path.Combine(projectDirectory, "TagsCloudContainer\\Parsers\\stopwords.txt"); - - if (!File.Exists(path)) - { - throw new FileNotFoundException("Файл не найден.", path); - } + this.config = config; - string text = File.ReadAllText(path); + words = []; + var reader = new TxtFileReader(); + var filterWords = reader.Read(Constants.FilterWordsDirectory); - var matches = Constants.wordsSplitRegex.Matches(text); + var matches = Constants.wordsSplitRegex.Matches(filterWords); for (var i = 0; i < matches.Count; i++) { if (!words.Contains(matches[i].Value)) words.Add(matches[i].Value); } + + AddStopWords(config.StopWords); } public bool Contains(string word) @@ -51,19 +48,13 @@ public void RemoveStopWord(string word) public void AddStopWords(string[] wordArray) { foreach (var word in wordArray) - { - if (!words.Contains(word)) - words.Add(word); - } + AddStopWord(word); } public void RemoveStopWords(string[] wordArray) { foreach (var word in wordArray) - { - if (words.Contains(word)) - words.Remove(word); - } + RemoveStopWord(word); } } } diff --git a/TagsCloudContainer/picture.jpg b/TagsCloudContainer/picture.jpg deleted file mode 100644 index 3d6532e87ce1542bcf94937b39867b3622c8feef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54314 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 Date: Thu, 26 Dec 2024 11:45:27 +0500 Subject: [PATCH 08/20] Refactor all code to file-scoped namespace --- TagCloudContainerTests/FileReadTest.cs | 76 +++++++------ TagsCloudContainer/Config.cs | 52 +++++---- TagsCloudContainer/Constants.cs | 62 ++++++----- .../FileReaders/DocFileReader.cs | 25 ++--- .../FileReaders/DocxFileReader.cs | 31 +++--- TagsCloudContainer/FileReaders/IReader.cs | 8 +- .../FileReaders/TxtFileReader.cs | 19 ++-- TagsCloudContainer/Filters/IFilter.cs | 16 ++- TagsCloudContainer/Filters/WordsFilter.cs | 84 +++++++-------- .../Layouters/CircularCloudLayouter.cs | 100 +++++++++--------- TagsCloudContainer/Layouters/ILayouter.cs | 8 +- TagsCloudContainer/Parsers/IParser.cs | 8 +- TagsCloudContainer/Parsers/SimpleParser.cs | 46 ++++---- .../{Files => Pictures}/picture.jpg | Bin TagsCloudContainer/Program.cs | 60 +++++------ TagsCloudContainer/TagsCloudContainer.csproj | 4 - TagsCloudContainer/Visualizers/IVisualizer.cs | 8 +- .../Visualizers/ImageVisualizer.cs | 38 ++++--- .../WordClasses/RectangleWord.cs | 6 +- TagsCloudContainer/WordClasses/SizeWord.cs | 6 +- TagsCloudContainer/WordSizer/ISizer.cs | 8 +- TagsCloudContainer/WordSizer/SimpleSizer.cs | 83 +++++++-------- 22 files changed, 349 insertions(+), 399 deletions(-) rename TagsCloudContainer/{Files => Pictures}/picture.jpg (100%) diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs index bda05179..def36e1a 100644 --- a/TagCloudContainerTests/FileReadTest.cs +++ b/TagCloudContainerTests/FileReadTest.cs @@ -3,48 +3,46 @@ using System.Data; using TagsCloudContainer.FileReaders; -namespace TagCloudContainerTests +namespace TagCloudContainerTests; +public class FileReadTest { - public class FileReadTest - { - private static readonly VerifySettings Settings = new(); - private IReader Reader; - private string FolderPath; + private static readonly VerifySettings Settings = new(); + private IReader Reader; + private string FolderPath; - [SetUp] - public void Setup() - { - Settings.UseDirectory("Snapshots"); - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); - FolderPath = Path.Combine(projectDirectory, "Files"); - } + [SetUp] + public void Setup() + { + Settings.UseDirectory("Snapshots"); + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); + FolderPath = Path.Combine(projectDirectory, "Files"); + } - [Test] - public Task Reader_TxtReading() - { - Reader = new TxtFileReader(); - var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); - var actual = Reader.Read(filePath); - return Verify(actual, Settings); - } + [Test] + public Task Reader_TxtReading() + { + Reader = new TxtFileReader(); + var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); + } - [Test] - public Task Reader_DocxReading() - { - Reader = new DocxFileReader(); - var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); - var actual = Reader.Read(filePath); - return Verify(actual, Settings); - } + [Test] + public Task Reader_DocxReading() + { + Reader = new DocxFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); + } - [Test] - public Task Reader_DocReading() - { - Reader = new DocFileReader(); - var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); - var actual = Reader.Read(filePath); - return Verify(actual, Settings); - } + [Test] + public Task Reader_DocReading() + { + Reader = new DocFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); + var actual = Reader.Read(filePath); + return Verify(actual, Settings); } -} \ No newline at end of file +} diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index 72aff19f..5a61757a 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -5,34 +5,32 @@ using System.Text; using System.Threading.Tasks; -namespace TagsCloudContainer +namespace TagsCloudContainer; +public class Config { - public class Config - { - public string InputDirectory { get; init; } - public string OutputDirectory { get; init; } - public int PictureWidth { get; init; } - public int PictureHeight { get; init; } - public string Font { get; init; } - public string[] StopWords { get; init; } - public string[] PictureColors { get; init; } + public string InputDirectory { get; init; } + public string OutputDirectory { get; init; } + public int PictureWidth { get; init; } + public int PictureHeight { get; init; } + public string Font { get; init; } + public string[] StopWords { get; init; } + public string[] PictureColors { get; init; } - public Config( - string inputDirectory, - string outputDirectory, - int pictureWidth, - int pictureHeight, - string font, - string[] stopWords, - string[] pictureColors) - { - InputDirectory = inputDirectory; - OutputDirectory = outputDirectory; - PictureWidth = pictureWidth; - PictureHeight = pictureHeight; - Font = font; - StopWords = stopWords; - PictureColors = pictureColors; - } + public Config( + string inputDirectory, + string outputDirectory, + int pictureWidth, + int pictureHeight, + string font, + string[] stopWords, + string[] pictureColors) + { + InputDirectory = inputDirectory; + OutputDirectory = outputDirectory; + PictureWidth = pictureWidth; + PictureHeight = pictureHeight; + Font = font; + StopWords = stopWords; + PictureColors = pictureColors; } } diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index 089c4a95..50c10eb8 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -5,50 +5,48 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace TagsCloudContainer +namespace TagsCloudContainer; +public static partial class Constants { - public static class Constants + public static string InputDirectory { - public static string InputDirectory + get { - get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); - } + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); } + } - public static string OutputDirectory { get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\picture.jpg"); - } - } + public static string OutputDirectory { get + { + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Pictures\\picture.jpg"); + } + } - public static string FilterWordsDirectory + public static string FilterWordsDirectory + { + get { - get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); - } + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); } + } - public static int PictureWidth { get { return 800; } } - - public static int PictureHeight { get { return 800; } } + public static int PictureWidth { get { return 800; } } - public static string Font { get { return "Arial"; } } + public static int PictureHeight { get { return 800; } } - public static string[] StopWords { get { return []; } } + public static string Font { get { return "Arial"; } } - public static string[] PictureColors { get { return []; } } + public static string[] StopWords { get { return []; } } - public static Regex wordsSplitRegex = new(pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", - options: RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static string[] PictureColors { get { return []; } } - } + public static Regex wordsSplitRegex1 = new( + pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", + options: RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/TagsCloudContainer/FileReaders/DocFileReader.cs b/TagsCloudContainer/FileReaders/DocFileReader.cs index 17ebc63e..061f3f16 100644 --- a/TagsCloudContainer/FileReaders/DocFileReader.cs +++ b/TagsCloudContainer/FileReaders/DocFileReader.cs @@ -1,22 +1,19 @@ using Spire.Doc; -namespace TagsCloudContainer.FileReaders +namespace TagsCloudContainer.FileReaders; +public class DocFileReader : IReader { - public class DocFileReader : IReader + public string Read(string path) { - public string Read(string path) - { - if (string.IsNullOrEmpty(path)) - throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); - if (!File.Exists(path)) - throw new FileNotFoundException("File not found.", path); + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); - var document = new Document(); - document.LoadFromFile(path); - var text = document.GetText(); - return text; - } + var document = new Document(); + document.LoadFromFile(path); + var text = document.GetText(); + return text; } - } diff --git a/TagsCloudContainer/FileReaders/DocxFileReader.cs b/TagsCloudContainer/FileReaders/DocxFileReader.cs index 71dbfd8f..5379f521 100644 --- a/TagsCloudContainer/FileReaders/DocxFileReader.cs +++ b/TagsCloudContainer/FileReaders/DocxFileReader.cs @@ -1,30 +1,27 @@ using NPOI.XWPF.UserModel; -namespace TagsCloudContainer.FileReaders +namespace TagsCloudContainer.FileReaders; +public class DocxFileReader : IReader { - public class DocxFileReader : IReader + public string Read(string path) { - public string Read(string path) - { - if (string.IsNullOrEmpty(path)) - throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); - if (!File.Exists(path)) - throw new FileNotFoundException("File not found.", path); + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); - using (FileStream stream = File.OpenRead(path)) + using (FileStream stream = File.OpenRead(path)) + { + var docx = new XWPFDocument(stream); + using (var writer = new StringWriter()) { - var docx = new XWPFDocument(stream); - using (var writer = new StringWriter()) + foreach (var paragraph in docx.Paragraphs) { - foreach (var paragraph in docx.Paragraphs) - { - writer.WriteLine(paragraph.Text); - } - return writer.ToString(); + writer.WriteLine(paragraph.Text); } + return writer.ToString(); } } } - } diff --git a/TagsCloudContainer/FileReaders/IReader.cs b/TagsCloudContainer/FileReaders/IReader.cs index ed143288..07759e0b 100644 --- a/TagsCloudContainer/FileReaders/IReader.cs +++ b/TagsCloudContainer/FileReaders/IReader.cs @@ -1,7 +1,5 @@ -namespace TagsCloudContainer.FileReaders +namespace TagsCloudContainer.FileReaders; +public interface IReader { - public interface IReader - { - string Read(string path); - } + string Read(string path); } diff --git a/TagsCloudContainer/FileReaders/TxtFileReader.cs b/TagsCloudContainer/FileReaders/TxtFileReader.cs index d4d49a84..57232ad6 100644 --- a/TagsCloudContainer/FileReaders/TxtFileReader.cs +++ b/TagsCloudContainer/FileReaders/TxtFileReader.cs @@ -1,18 +1,15 @@ -namespace TagsCloudContainer.FileReaders +namespace TagsCloudContainer.FileReaders; +public class TxtFileReader : IReader { - public class TxtFileReader : IReader + public string Read(string path) { - public string Read(string path) - { - if (string.IsNullOrEmpty(path)) - throw new ArgumentException("Path cannot be null or empty.", nameof(path)); + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Path cannot be null or empty.", nameof(path)); - if (!File.Exists(path)) - throw new FileNotFoundException("File not found.", path); + if (!File.Exists(path)) + throw new FileNotFoundException("File not found.", path); - return File.ReadAllText(path); - } + return File.ReadAllText(path); } - } diff --git a/TagsCloudContainer/Filters/IFilter.cs b/TagsCloudContainer/Filters/IFilter.cs index d8788c46..449ba443 100644 --- a/TagsCloudContainer/Filters/IFilter.cs +++ b/TagsCloudContainer/Filters/IFilter.cs @@ -1,11 +1,9 @@ -namespace TagsCloudContainer.Filters +namespace TagsCloudContainer.Filters; +public interface IFilter { - public interface IFilter - { - void AddStopWord(string word); - void AddStopWords(string[] wordArray); - bool Contains(string word); - void RemoveStopWord(string word); - void RemoveStopWords(string[] wordArray); - } + void AddStopWord(string word); + void AddStopWords(string[] wordArray); + bool Contains(string word); + void RemoveStopWord(string word); + void RemoveStopWords(string[] wordArray); } \ No newline at end of file diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 548e6b4e..3eda8363 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -3,58 +3,56 @@ using System.Text.RegularExpressions; using TagsCloudContainer.FileReaders; -namespace TagsCloudContainer.Filters +namespace TagsCloudContainer.Filters; +public class WordsFilter : IFilter { - public class WordsFilter : IFilter + private HashSet words; + private Config config; + public WordsFilter(Config config) { - private HashSet words; - private Config config; - public WordsFilter(Config config) - { - this.config = config; - - words = []; - var reader = new TxtFileReader(); - var filterWords = reader.Read(Constants.FilterWordsDirectory); - - var matches = Constants.wordsSplitRegex.Matches(filterWords); + this.config = config; - for (var i = 0; i < matches.Count; i++) - { - if (!words.Contains(matches[i].Value)) - words.Add(matches[i].Value); - } + words = []; + var reader = new TxtFileReader(); + var filterWords = reader.Read(Constants.FilterWordsDirectory); - AddStopWords(config.StopWords); - } + var matches = Constants.wordsSplitRegex.Matches(filterWords); - public bool Contains(string word) + for (var i = 0; i < matches.Count; i++) { - return words.Contains(word); + if (!words.Contains(matches[i].Value)) + words.Add(matches[i].Value); } - public void AddStopWord(string word) - { - if (!words.Contains(word)) - words.Add(word); - } + AddStopWords(config.StopWords); + } - public void RemoveStopWord(string word) - { - if (words.Contains(word)) - words.Remove(word); - } + public bool Contains(string word) + { + return words.Contains(word); + } - public void AddStopWords(string[] wordArray) - { - foreach (var word in wordArray) - AddStopWord(word); - } + public void AddStopWord(string word) + { + if (!words.Contains(word)) + words.Add(word); + } - public void RemoveStopWords(string[] wordArray) - { - foreach (var word in wordArray) - RemoveStopWord(word); - } + public void RemoveStopWord(string word) + { + if (words.Contains(word)) + words.Remove(word); + } + + public void AddStopWords(string[] wordArray) + { + foreach (var word in wordArray) + AddStopWord(word); + } + + public void RemoveStopWords(string[] wordArray) + { + foreach (var word in wordArray) + RemoveStopWord(word); } -} +} \ No newline at end of file diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index 61e4504b..90c5e0a5 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -1,69 +1,65 @@ using System.Drawing; using TagsCloudContainer.WordClasses; -namespace TagsCloudContainer.Layouters +namespace TagsCloudContainer.Layouters; +public class CircularCloudLayouter : ILayouter { - public class CircularCloudLayouter : ILayouter - { - public readonly List rectangles = []; - public Point center; - private double angle; - private const double spiralStep = 0.1; - private const double radiusStep = 0.5; - private readonly Config config; - - public CircularCloudLayouter(Config config) - { - this.config = config; - } - - public IEnumerable GetLayout(IEnumerable words) - { - center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); - foreach (var word in words) - { - var rectangleSize = word.Size; - Rectangle newRect; - do - { - var location = GetNextLocation(rectangleSize); - newRect = new Rectangle(location, rectangleSize); - } - while (IsIntersecting(newRect)); - rectangles.Add(new RectangleWord(word.Value, newRect, word.font)); - } - return rectangles; - } + public readonly List rectangles = []; + public Point center; + private double angle; + private const double spiralStep = 0.1; + private const double radiusStep = 0.5; + private readonly Config config; - private Point GetNextLocation(Size rectangleSize) - { - var radius = radiusStep * angle; - var centerX = center.X + (int)(radius * Math.Cos(angle)); - var centerY = center.Y + (int)(radius * Math.Sin(angle)); - angle += spiralStep; - return GetCornerPoint(new Point(centerX, centerY), rectangleSize); - } + public CircularCloudLayouter(Config config) + { + this.config = config; + } - private bool IsIntersecting(Rectangle rectangle) + public IEnumerable GetLayout(IEnumerable words) + { + center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); + foreach (var word in words) { - foreach (var existingRectangle in rectangles) + var rectangleSize = word.Size; + Rectangle newRect; + do { - if (existingRectangle.Bounds.IntersectsWith(rectangle)) - return true; + var location = GetNextLocation(rectangleSize); + newRect = new Rectangle(location, rectangleSize); } - return false; + while (IsIntersecting(newRect)); + rectangles.Add(new RectangleWord(word.Value, newRect, word.font)); } + return rectangles; + } - public static Point GetCornerPoint(Point center, Size size) - { - return new Point(center.X - size.Width / 2, center.Y - size.Height / 2); - } + private Point GetNextLocation(Size rectangleSize) + { + var radius = radiusStep * angle; + var centerX = center.X + (int)(radius * Math.Cos(angle)); + var centerY = center.Y + (int)(radius * Math.Sin(angle)); + angle += spiralStep; + return GetCornerPoint(new Point(centerX, centerY), rectangleSize); + } - public static Point GetCenterPoint(Rectangle rect) + private bool IsIntersecting(Rectangle rectangle) + { + foreach (var existingRectangle in rectangles) { - return new Point(rect.Location.X + rect.Width / 2, rect.Location.Y + rect.Height / 2); + if (existingRectangle.Bounds.IntersectsWith(rectangle)) + return true; } + return false; + } - + public static Point GetCornerPoint(Point center, Size size) + { + return new Point(center.X - size.Width / 2, center.Y - size.Height / 2); } + + public static Point GetCenterPoint(Rectangle rect) + { + return new Point(rect.Location.X + rect.Width / 2, rect.Location.Y + rect.Height / 2); + } } diff --git a/TagsCloudContainer/Layouters/ILayouter.cs b/TagsCloudContainer/Layouters/ILayouter.cs index 39bfeb33..e8abe710 100644 --- a/TagsCloudContainer/Layouters/ILayouter.cs +++ b/TagsCloudContainer/Layouters/ILayouter.cs @@ -6,10 +6,8 @@ using TagsCloudContainer.WordClasses; using TagsCloudContainer.WordSizer; -namespace TagsCloudContainer.Layouters +namespace TagsCloudContainer.Layouters; +public interface ILayouter { - public interface ILayouter - { - public IEnumerable GetLayout(IEnumerable words); - } + public IEnumerable GetLayout(IEnumerable words); } diff --git a/TagsCloudContainer/Parsers/IParser.cs b/TagsCloudContainer/Parsers/IParser.cs index 7b50c7c8..aa7e43ab 100644 --- a/TagsCloudContainer/Parsers/IParser.cs +++ b/TagsCloudContainer/Parsers/IParser.cs @@ -5,10 +5,8 @@ using System.Text; using System.Threading.Tasks; -namespace TagsCloudContainer.Parsers +namespace TagsCloudContainer.Parsers; +public interface IParser { - public interface IParser - { - public IDictionary Parse(string text); - } + public IDictionary Parse(string text); } diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs index fccc17db..b9f10602 100644 --- a/TagsCloudContainer/Parsers/SimpleParser.cs +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -1,39 +1,37 @@ using System.Text.RegularExpressions; using TagsCloudContainer.Filters; -namespace TagsCloudContainer.Parsers +namespace TagsCloudContainer.Parsers; +public class SimpleParser : IParser { - public class SimpleParser : IParser + private IFilter wordsFilter; + public SimpleParser(IFilter wordsFilter) { - private IFilter wordsFilter; - public SimpleParser(IFilter wordsFilter) - { - this.wordsFilter = wordsFilter; - } + this.wordsFilter = wordsFilter; + } - public IDictionary Parse(string text) - { - var dict = new Dictionary(); + public IDictionary Parse(string text) + { + var dict = new Dictionary(); - var words = Constants.wordsSplitRegex.Matches(text.ToLower()); + var words = Constants.wordsSplitRegex.Matches(text.ToLower()); - var wordArray = new List(); - for (var i = 0; i < words.Count; i++) + var wordArray = new List(); + for (var i = 0; i < words.Count; i++) + { + var word = words[i].Value; + if (!wordsFilter.Contains(word)) { - var word = words[i].Value; - if (!wordsFilter.Contains(word)) + if (dict.Keys.Contains(word)) + { + dict[word]++; + } + else { - if (dict.Keys.Contains(word)) - { - dict[word]++; - } - else - { - dict.Add(word,1); - } + dict.Add(word,1); } } - return dict; } + return dict; } } diff --git a/TagsCloudContainer/Files/picture.jpg b/TagsCloudContainer/Pictures/picture.jpg similarity index 100% rename from TagsCloudContainer/Files/picture.jpg rename to TagsCloudContainer/Pictures/picture.jpg diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index ab1377cc..0d16e12c 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -8,43 +8,41 @@ using TagsCloudContainer.Visualizers; using TagsCloudContainer.WordSizer; -namespace TagsCloudContainer +namespace TagsCloudContainer; +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - } - public static void Main(Config config) - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(config).As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - var container = builder.Build(); + } + public static void Main(Config config) + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(config).As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + var container = builder.Build(); - var reader = container.Resolve(); - var filter = container.Resolve(); - var parser = container.Resolve(); - var sizer = container.Resolve(); - var layouter = container.Resolve(); - var visualizer = container.Resolve(); + var reader = container.Resolve(); + var filter = container.Resolve(); + var parser = container.Resolve(); + var sizer = container.Resolve(); + var layouter = container.Resolve(); + var visualizer = container.Resolve(); - visualizer.GenerateImage( - layouter.GetLayout( - sizer.GetSizes( - parser.Parse( - reader.Read( - config.InputDirectory - ) + visualizer.GenerateImage( + layouter.GetLayout( + sizer.GetSizes( + parser.Parse( + reader.Read( + config.InputDirectory ) ) ) - ); - } + ) + ); } } diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index e2dac9f3..a3d2e46a 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -16,8 +16,4 @@ - - - - diff --git a/TagsCloudContainer/Visualizers/IVisualizer.cs b/TagsCloudContainer/Visualizers/IVisualizer.cs index 4054197a..0d67f8fb 100644 --- a/TagsCloudContainer/Visualizers/IVisualizer.cs +++ b/TagsCloudContainer/Visualizers/IVisualizer.cs @@ -5,10 +5,8 @@ using System.Threading.Tasks; using TagsCloudContainer.WordClasses; -namespace TagsCloudContainer.Visualizers +namespace TagsCloudContainer.Visualizers; +public interface IVisualizer { - public interface IVisualizer - { - public void GenerateImage(IEnumerable words); - } + public void GenerateImage(IEnumerable words); } diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index a99fe64c..b283c102 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -3,30 +3,28 @@ using System.IO; using TagsCloudContainer.WordClasses; -namespace TagsCloudContainer.Visualizers +namespace TagsCloudContainer.Visualizers; +public class ImageVisualizer : IVisualizer { - public class ImageVisualizer : IVisualizer + private Config config; + public ImageVisualizer(Config config) { - private Config config; - public ImageVisualizer(Config config) - { - this.config = config; - } + this.config = config; + } - public void GenerateImage(IEnumerable words) + public void GenerateImage(IEnumerable words) + { + var image = new Bitmap(config.PictureWidth, config.PictureWidth); + var g = Graphics.FromImage(image); + var pen = new Pen(Brushes.AliceBlue, 2); + var count = 0; + foreach (var item in words) { - var image = new Bitmap(config.PictureWidth, config.PictureWidth); - var g = Graphics.FromImage(image); - var pen = new Pen(Brushes.AliceBlue, 2); - var count = 0; - foreach (var item in words) - { - count++; - g.DrawRectangle(pen, item.Bounds); - g.DrawString(item.Value, item.font, Brushes.Orange, item.Bounds.Location); - } - - image.Save(config.OutputDirectory, ImageFormat.Jpeg); + count++; + g.DrawRectangle(pen, item.Bounds); + g.DrawString(item.Value, item.font, Brushes.Orange, item.Bounds.Location); } + + image.Save(config.OutputDirectory, ImageFormat.Jpeg); } } diff --git a/TagsCloudContainer/WordClasses/RectangleWord.cs b/TagsCloudContainer/WordClasses/RectangleWord.cs index bb3771d6..df091202 100644 --- a/TagsCloudContainer/WordClasses/RectangleWord.cs +++ b/TagsCloudContainer/WordClasses/RectangleWord.cs @@ -5,7 +5,5 @@ using System.Text; using System.Threading.Tasks; -namespace TagsCloudContainer.WordClasses -{ - public record RectangleWord(string Value, Rectangle Bounds, Font font); -} +namespace TagsCloudContainer.WordClasses; +public record RectangleWord(string Value, Rectangle Bounds, Font font); diff --git a/TagsCloudContainer/WordClasses/SizeWord.cs b/TagsCloudContainer/WordClasses/SizeWord.cs index 35418731..b8a07243 100644 --- a/TagsCloudContainer/WordClasses/SizeWord.cs +++ b/TagsCloudContainer/WordClasses/SizeWord.cs @@ -1,6 +1,4 @@ using System.Drawing; -namespace TagsCloudContainer.WordClasses -{ - public record SizeWord(string Value, Size Size, Font font); -} +namespace TagsCloudContainer.WordClasses; +public record SizeWord(string Value, Size Size, Font font); diff --git a/TagsCloudContainer/WordSizer/ISizer.cs b/TagsCloudContainer/WordSizer/ISizer.cs index f35bb33a..55263035 100644 --- a/TagsCloudContainer/WordSizer/ISizer.cs +++ b/TagsCloudContainer/WordSizer/ISizer.cs @@ -6,10 +6,8 @@ using System.Threading.Tasks; using TagsCloudContainer.WordClasses; -namespace TagsCloudContainer.WordSizer +namespace TagsCloudContainer.WordSizer; +public interface ISizer { - public interface ISizer - { - public IEnumerable GetSizes(IDictionary words); - } + public IEnumerable GetSizes(IDictionary words); } diff --git a/TagsCloudContainer/WordSizer/SimpleSizer.cs b/TagsCloudContainer/WordSizer/SimpleSizer.cs index 8bb67e12..7601d27c 100644 --- a/TagsCloudContainer/WordSizer/SimpleSizer.cs +++ b/TagsCloudContainer/WordSizer/SimpleSizer.cs @@ -8,61 +8,58 @@ using System.Threading.Tasks; using TagsCloudContainer.WordClasses; -namespace TagsCloudContainer.WordSizer +namespace TagsCloudContainer.WordSizer; +public class SimpleSizer : ISizer { - public class SimpleSizer : ISizer + private readonly Config config; + + public SimpleSizer(Config config) { - private readonly Config config; + this.config = config; + } - public SimpleSizer(Config config) - { - this.config = config; - } + public IEnumerable GetSizes(IDictionary words) + { + var screeenSize = config.PictureHeight * config.PictureWidth; + var sum = words.Sum(x => x.Value); + var list = new List(); - public IEnumerable GetSizes(IDictionary words) + foreach (var item in words.OrderByDescending(x => x.Value)) { - var screeenSize = config.PictureHeight * config.PictureWidth; - var sum = words.Sum(x => x.Value); - var list = new List(); - - foreach (var item in words.OrderByDescending(x => x.Value)) - { - var part = (double)item.Value / sum; - var maxHeight = (int)(config.PictureHeight * part); - var maxWidth = (int)(config.PictureWidth * part); - var maxSize = new Size(maxWidth, maxHeight); - var (size, font) = GetFontSize(maxSize, config.Font, item.Key); - list.Add(new SizeWord(item.Key, size, font)); - //list.Add(new SizeWord(item.Key, maxSize, new Font("Arial", 23))); - } - return list; + var part = (double)item.Value / sum; + var maxHeight = (int)(config.PictureHeight * part); + var maxWidth = (int)(config.PictureWidth * part); + var maxSize = new Size(maxWidth, maxHeight); + var (size, font) = GetFontSize(maxSize, config.Font, item.Key); + list.Add(new SizeWord(item.Key, size, font)); + //list.Add(new SizeWord(item.Key, maxSize, new Font("Arial", 23))); } + return list; + } - private static (Size, Font) GetFontSize(Size maxSize, string fontName, string text) - { - var maxFontSize = 200; - var minFontSize = 1; + private static (Size, Font) GetFontSize(Size maxSize, string fontName, string text) + { + var maxFontSize = 200; + var minFontSize = 1; - var tempBitmap = new Bitmap(1, 1); - var graphics = Graphics.FromImage(tempBitmap); - Size textSize; - Font font; + var tempBitmap = new Bitmap(1, 1); + var graphics = Graphics.FromImage(tempBitmap); + Size textSize; + Font font; - for (var i = maxFontSize; i >= minFontSize; i--) + for (var i = maxFontSize; i >= minFontSize; i--) + { + font = new Font(fontName, i); + var t = graphics.MeasureString(text, font); + textSize = t.ToSize(); + if (textSize.Width * textSize.Height <= maxSize.Width * maxSize.Height) { - font = new Font(fontName, i); - var t = graphics.MeasureString(text, font); - textSize = t.ToSize(); - if (textSize.Width * textSize.Height <= maxSize.Width * maxSize.Height) - { - return (textSize, font); - } + return (textSize, font); } - - font = new Font(fontName, 1); - textSize = graphics.MeasureString(text, font).ToSize(); - return (textSize, font); } + font = new Font(fontName, 1); + textSize = graphics.MeasureString(text, font).ToSize(); + return (textSize, font); } } From 23f4ab1823c6d1bca3b52109d985a3f101d68e23 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 12:22:33 +0500 Subject: [PATCH 09/20] Fix small problems --- ConsoleClient/ConsoleClient.cs | 2 +- TagCloudContainerTests/FileReadTest.cs | 3 --- TagsCloudContainer/Constants.cs | 2 +- .../FileReaders/DocxFileReader.cs | 17 +++++++---------- TagsCloudContainer/Filters/WordsFilter.cs | 5 +---- .../Layouters/CircularCloudLayouter.cs | 18 +++++++----------- TagsCloudContainer/Parsers/SimpleParser.cs | 10 ++-------- TagsCloudContainer/Pictures/picture.jpg | Bin 38860 -> 0 bytes TagsCloudContainer/Program.cs | 1 - TagsCloudContainer/TagsCloudContainer.csproj | 6 ++++-- .../Visualizers/ImageVisualizer.cs | 7 +++---- TagsCloudContainer/WordSizer/SimpleSizer.cs | 5 +++-- 12 files changed, 29 insertions(+), 47 deletions(-) delete mode 100644 TagsCloudContainer/Pictures/picture.jpg diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 808f4a14..20213cdd 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -25,7 +25,7 @@ public class ConsoleClient [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] public string ColorsInput { get; set; } - public string[] StopWords => StopWordsInput?.Split(',') ?? Array.Empty(); + public string[] StopWords => StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs index def36e1a..2a0b7b43 100644 --- a/TagCloudContainerTests/FileReadTest.cs +++ b/TagCloudContainerTests/FileReadTest.cs @@ -1,6 +1,3 @@ -using FluentAssertions; -using NPOI.SS.Formula.Functions; -using System.Data; using TagsCloudContainer.FileReaders; namespace TagCloudContainerTests; diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index 50c10eb8..6b1124e9 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -46,7 +46,7 @@ public static string FilterWordsDirectory public static string[] PictureColors { get { return []; } } - public static Regex wordsSplitRegex1 = new( + public static Regex wordsSplitRegex = new( pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", options: RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/TagsCloudContainer/FileReaders/DocxFileReader.cs b/TagsCloudContainer/FileReaders/DocxFileReader.cs index 5379f521..0de10712 100644 --- a/TagsCloudContainer/FileReaders/DocxFileReader.cs +++ b/TagsCloudContainer/FileReaders/DocxFileReader.cs @@ -11,17 +11,14 @@ public string Read(string path) if (!File.Exists(path)) throw new FileNotFoundException("File not found.", path); - using (FileStream stream = File.OpenRead(path)) + using var stream = File.OpenRead(path); + using var writer = new StringWriter(); + + var docx = new XWPFDocument(stream); + foreach (var paragraph in docx.Paragraphs) { - var docx = new XWPFDocument(stream); - using (var writer = new StringWriter()) - { - foreach (var paragraph in docx.Paragraphs) - { - writer.WriteLine(paragraph.Text); - } - return writer.ToString(); - } + writer.WriteLine(paragraph.Text); } + return writer.ToString(); } } diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 3eda8363..2d23f1aa 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -20,8 +20,7 @@ public WordsFilter(Config config) for (var i = 0; i < matches.Count; i++) { - if (!words.Contains(matches[i].Value)) - words.Add(matches[i].Value); + words.Add(matches[i].Value); } AddStopWords(config.StopWords); @@ -34,13 +33,11 @@ public bool Contains(string word) public void AddStopWord(string word) { - if (!words.Contains(word)) words.Add(word); } public void RemoveStopWord(string word) { - if (words.Contains(word)) words.Remove(word); } diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index 90c5e0a5..5c267421 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -4,8 +4,8 @@ namespace TagsCloudContainer.Layouters; public class CircularCloudLayouter : ILayouter { - public readonly List rectangles = []; - public Point center; + private readonly List rectangles = []; + private Point center; private double angle; private const double spiralStep = 0.1; private const double radiusStep = 0.5; @@ -19,9 +19,8 @@ public CircularCloudLayouter(Config config) public IEnumerable GetLayout(IEnumerable words) { center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); - foreach (var word in words) + foreach (var (value, rectangleSize, font) in words) { - var rectangleSize = word.Size; Rectangle newRect; do { @@ -29,7 +28,7 @@ public IEnumerable GetLayout(IEnumerable words) newRect = new Rectangle(location, rectangleSize); } while (IsIntersecting(newRect)); - rectangles.Add(new RectangleWord(word.Value, newRect, word.font)); + rectangles.Add(new RectangleWord(value, newRect, font)); } return rectangles; } @@ -45,12 +44,9 @@ private Point GetNextLocation(Size rectangleSize) private bool IsIntersecting(Rectangle rectangle) { - foreach (var existingRectangle in rectangles) - { - if (existingRectangle.Bounds.IntersectsWith(rectangle)) - return true; - } - return false; + return rectangles. + Any(existingRectangle => + existingRectangle.Bounds.IntersectsWith(rectangle)); } public static Point GetCornerPoint(Point center, Size size) diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs index b9f10602..a62a99b8 100644 --- a/TagsCloudContainer/Parsers/SimpleParser.cs +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -1,5 +1,4 @@ -using System.Text.RegularExpressions; -using TagsCloudContainer.Filters; +using TagsCloudContainer.Filters; namespace TagsCloudContainer.Parsers; public class SimpleParser : IParser @@ -16,20 +15,15 @@ public IDictionary Parse(string text) var words = Constants.wordsSplitRegex.Matches(text.ToLower()); - var wordArray = new List(); for (var i = 0; i < words.Count; i++) { var word = words[i].Value; if (!wordsFilter.Contains(word)) { - if (dict.Keys.Contains(word)) + if (!dict.TryAdd(word, 1)) { dict[word]++; } - else - { - dict.Add(word,1); - } } } return dict; diff --git a/TagsCloudContainer/Pictures/picture.jpg b/TagsCloudContainer/Pictures/picture.jpg deleted file mode 100644 index 95d88b0dff142f3007876180627b6ec66d0b9a63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38860 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 H*Vumpoh;zI diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 0d16e12c..4c383c1b 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -27,7 +27,6 @@ public static void Main(Config config) var container = builder.Build(); var reader = container.Resolve(); - var filter = container.Resolve(); var parser = container.Resolve(); var sizer = container.Resolve(); var layouter = container.Resolve(); diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index a3d2e46a..47796e12 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -9,11 +9,13 @@ - - + + + + diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index b283c102..b5fb1473 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -14,13 +14,12 @@ public ImageVisualizer(Config config) public void GenerateImage(IEnumerable words) { - var image = new Bitmap(config.PictureWidth, config.PictureWidth); - var g = Graphics.FromImage(image); + using var image = new Bitmap(config.PictureWidth, config.PictureWidth); + using var g = Graphics.FromImage(image); var pen = new Pen(Brushes.AliceBlue, 2); - var count = 0; + foreach (var item in words) { - count++; g.DrawRectangle(pen, item.Bounds); g.DrawString(item.Value, item.font, Brushes.Orange, item.Bounds.Location); } diff --git a/TagsCloudContainer/WordSizer/SimpleSizer.cs b/TagsCloudContainer/WordSizer/SimpleSizer.cs index 7601d27c..ba6f1292 100644 --- a/TagsCloudContainer/WordSizer/SimpleSizer.cs +++ b/TagsCloudContainer/WordSizer/SimpleSizer.cs @@ -42,8 +42,9 @@ private static (Size, Font) GetFontSize(Size maxSize, string fontName, string te var maxFontSize = 200; var minFontSize = 1; - var tempBitmap = new Bitmap(1, 1); - var graphics = Graphics.FromImage(tempBitmap); + using var tempBitmap = new Bitmap(1, 1); + using var graphics = Graphics.FromImage(tempBitmap); + Size textSize; Font font; From 3177d5bf39f51f2e0807a954ee254d208c640cc2 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 19:12:02 +0500 Subject: [PATCH 10/20] Add Layouter Tests --- ConsoleClient/ConsoleClient.cs | 8 +- ConsoleClient/FilterTests.cs | 12 ++ ...youter_Constructor_CorrectlySetCenter.jpeg | Bin 0 -> 10627 bytes ...ectangle_PlacesFirstRectangleToCenter.jpeg | Bin 0 -> 11619 bytes .../CircularCloudLayouterTests.cs | 149 ++++++++++++++++++ TagCloudContainerTests/FileReadTest.cs | 1 + TagsCloudContainer/Config.cs | 51 +++--- TagsCloudContainer/Constants.cs | 69 +++----- .../FileReaders/DocFileReader.cs | 1 + .../FileReaders/DocxFileReader.cs | 1 + TagsCloudContainer/FileReaders/IReader.cs | 1 + .../FileReaders/TxtFileReader.cs | 1 + TagsCloudContainer/Filters/IFilter.cs | 1 + TagsCloudContainer/Filters/WordsFilter.cs | 17 +- .../Layouters/CircularCloudLayouter.cs | 19 +-- TagsCloudContainer/Layouters/ILayouter.cs | 9 +- TagsCloudContainer/Parsers/IParser.cs | 8 +- TagsCloudContainer/Parsers/SimpleParser.cs | 3 +- TagsCloudContainer/Program.cs | 2 - TagsCloudContainer/Visualizers/IVisualizer.cs | 8 +- .../Visualizers/ImageVisualizer.cs | 2 +- .../WordClasses/RectangleWord.cs | 8 +- TagsCloudContainer/WordClasses/SizeWord.cs | 1 + TagsCloudContainer/WordSizer/ISizer.cs | 9 +- TagsCloudContainer/WordSizer/SimpleSizer.cs | 11 +- 25 files changed, 261 insertions(+), 131 deletions(-) create mode 100644 ConsoleClient/FilterTests.cs create mode 100644 FailedTestTagCloud.CircularCloudLayouter_Constructor_CorrectlySetCenter.jpeg create mode 100644 FailedTestTagCloud.PutNextRectangle_PlacesFirstRectangleToCenter.jpeg create mode 100644 TagCloudContainerTests/CircularCloudLayouterTests.cs diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 20213cdd..fb4a0048 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -1,5 +1,4 @@ using McMaster.Extensions.CommandLineUtils; -using System.Drawing; using TagsCloudContainer; public class ConsoleClient @@ -22,11 +21,16 @@ public class ConsoleClient [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] public string StopWordsInput { get; set; } + [Option("--rightwords", "Comma-separated list of right words.", CommandOptionType.SingleValue)] + public string RightWordsInput { get; set; } + [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] public string ColorsInput { get; set; } public string[] StopWords => StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); + public string[] RightWords => RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); + public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); public static int Main(string[] args) @@ -43,11 +47,11 @@ private void OnExecute() PictureHeight == default ? Constants.PictureHeight : PictureHeight, Font is null ? Constants.Font : Font, StopWords is null ? Constants.StopWords : StopWords, + RightWords is null ? Constants.RightWords : RightWords, PictureColors is null ? Constants.PictureColors : PictureColors ); TagsCloudContainer.Program.Main(config); - Console.WriteLine(config); } } diff --git a/ConsoleClient/FilterTests.cs b/ConsoleClient/FilterTests.cs new file mode 100644 index 00000000..5d710ae9 --- /dev/null +++ b/ConsoleClient/FilterTests.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleClient +{ + class FilterTests + { + } +} diff --git a/FailedTestTagCloud.CircularCloudLayouter_Constructor_CorrectlySetCenter.jpeg b/FailedTestTagCloud.CircularCloudLayouter_Constructor_CorrectlySetCenter.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d5823ee81dac194afeb051c73918bb892cefa4de GIT binary patch literal 10627 zcmeIwIZPB$0LJn6=FPb~8<^b%m(AjyxQijgogD>?#sIns9eAKtg0~%bpe7dJO^3Hu z;)!;scvYgPXon|YBi>qpHx`aFYA~@@y#e%*u2{novr~B5M-! z5h*9KC`zIrOOm80vP1Q{RHswTaeFenx&GkTTz?=CiWSB~k%DL-kSNM8n2%cq9}Vg0X%d4*^)3t5v!2&Yk|QL~!_388{@Tl>O42jv(q zh?1;0oYscUOu|vdIGzat&s)1US>Fk-3GQ&RRP`#+T#I8y8RHk2fYxDk?6STt0n9dgiQ(%Gq<~&a0WfVBz8=OP4KQv2xYwHEY*3 zuHUe6^OmjKw(r>4vTOIAz5DhbIC$vD(PPI?oNPaJ`pnsLo#!uHyma~MweIUTZuZ=| zedq4I`wt%W^$!d_dHU@6iAcp;n=-KAAhZM`R=H_6_z*0zo=C7P-p%BpMVb!5kk!MtHR?R(jug*E?E*=X3W zt^uMlYCRs)$TTwYwIy+w!@@s+0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7 gfB_hQ0T_S*7=Qs7fB_hQ0T_S*82HZ(WSITm0K3P>BLDyZ literal 0 HcmV?d00001 diff --git a/FailedTestTagCloud.PutNextRectangle_PlacesFirstRectangleToCenter.jpeg b/FailedTestTagCloud.PutNextRectangle_PlacesFirstRectangleToCenter.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..2c002f974e933b6d01a677bc67699ad545035b49 GIT binary patch literal 11619 zcmeI$cTkgO90%|xdl0|?VF`pK1Q8SnGGvGd8aYLlsDP({pjJeXr7VHsh%M*BfhZCM z!5R=KLsXRID0MIbB3{F?qR0rymb`t__Ux73^|XK0yXSrH_s8?(d2`SA$tSVOxSETQ{T$g($vP-jBP4;6AXnyp-It{rKOckwbZmszxYD#13DR} ziQX7(fTd$_bPQ4lm;hi1=x!w&{`10Mad-leM5a)s&;_OQ02YJ8VevQu0gp#l$D^+U zJe?q?W#T}TciTqN4pT5qI+0D*Sy5EYaBm#eHS-Torcf1?lvPw0=;^Zz7P8HkT3A|H zJFawcUbULD#>3NVgZIWwn*##32LVrFxY6caCAID%Y-QB;6~aOCa-OpL{?aF zBD<)XqGRSh%t?d&~O;^!^6>mJ(v=6S(mY} z;2A&z&;T?54L}3X05kv%Km*VKGyn}i1JD3801bSB0jX)@V|g*hyi?XR@x_g?c0 zXYiEn%K+l&l;~qz{*vdkMCu>IccRTxGg7qWu-n*9Xe%r zfH{jEY@?jlS~>9u^U(BkeYB0g)n!kL)_g~kSESt7X~Df@;mC#$_A{Xf;OQ24xQK}P zy!w5LSy9{4UPt|Wn~@?DyTmT{mdMj@^G@fswYG5?2|=fWvOUgEi4CqiA1t+9?9>=% zebR4|+p1U0(H1xCXjM@g=_qMfdLZS*vs>2{%Z;K%dSe4Og3Fo*we;PS#rB5ukooQR zpIY@YJ%)U9PxUb8?TE?>Y#vkM3a#kHhN)u@I>RQtTn7eR-%s4U@Nj#T=BpC0#W$jX zep{ox&{`#O^{A0~_`%G&?iI+b$i*~@d%K* z)-5|rV@~O#-@H1vx#P>bK6911Fm9)$vlk?G$j;K$nZuO{nh1Dajm|}(jnye!wH4jn zG4Cud!5%yGheBxT$GuRN=T>u&1Y}NQR&ZHYm+-hO01KW0Gyn}i1JD3801ZF`&;T?5 W4L}3X05kv%Km*XgXBxmE?Y{w?eZge_ literal 0 HcmV?d00001 diff --git a/TagCloudContainerTests/CircularCloudLayouterTests.cs b/TagCloudContainerTests/CircularCloudLayouterTests.cs new file mode 100644 index 00000000..9bc67357 --- /dev/null +++ b/TagCloudContainerTests/CircularCloudLayouterTests.cs @@ -0,0 +1,149 @@ +using FluentAssertions; +using NUnit.Framework.Interfaces; +using System.Drawing; +using TagsCloudContainer; +using TagsCloudContainer.Layouters; +using TagsCloudContainer.Visualizers; +using TagsCloudContainer.WordClasses; + +namespace TagCloudContainerTests +{ + [TestFixture] + public class CircularCloudLayouterTests + { + + private CircularCloudLayouter layouter; + private Config config; + private IVisualizer visualizer; + + private readonly string text = "text"; + private readonly Font font = new("Arial", 15); + + [SetUp] + public void Setup() + { + config = new Config(); + layouter = new CircularCloudLayouter(config); + visualizer = new ImageVisualizer(config); + } + + [TearDown] + public void Teardown() + { + var testResult = TestContext.CurrentContext.Result.Outcome; + var testName = TestContext.CurrentContext.Test.Name; + if (Equals(testResult, ResultState.Failure) || + Equals(testResult == ResultState.Error)) + { + var drawer = visualizer; + var directory = Path.Combine(Constants.ProjectDirectory, $"FailedTestTagCloud.{testName}.jpeg"); + config.OutputDirectory = directory; + drawer.GenerateImage(layouter.Rectangles); + Console.WriteLine($"Tag cloud visualization saved to file {directory}"); + } + } + + private SizeWord GetDefaultSizeWord(Size size) + { + return new SizeWord(text, size, font); + } + + [Test] + public void CircularCloudLayouter_Constructor_CorrectlySetCenter() + { + layouter.GetLayout([]); + layouter.Center + .Should() + .Be(new Point(config.PictureWidth / 2, config.PictureHeight / 2)); + } + + [Test] + public void PutNextRectangle_PlacesFirstRectangleToCenter() + { + var size = new Size(50, 50); + var rectangles = layouter.GetLayout([GetDefaultSizeWord(size)]); + var centerRecLocation = CircularCloudLayouter. + GetCornerPoint(layouter.Center, size); + rectangles + .First() + .Bounds + .Location + .Should() + .Be(centerRecLocation); + } + + [Test] + public void PutNextRectangle_RectanglesDoesNotIntersect() + { + var sizeList = new List(); + + for (int i = 10; i < 100; i += 10) + for (int j = 5; j < 50; j += 5) + sizeList.Add(GetDefaultSizeWord(new Size(i, j))); + + var rectangles = layouter.GetLayout(sizeList); + var length = layouter.Rectangles.Count; + for (int i = 0; i < length - 1; i++) + for (int j = 0; j < length - 1; j++) + { + if (i != j) + layouter.Rectangles[i] + .Bounds + .IntersectsWith(layouter.Rectangles[j].Bounds) + .Should().BeFalse(); + } + } + + [Test] + public void PutNextRectangle_IncreaseDistanceFromCenter_WithMoreRectangles() + { + var sizeList = new List + { + GetDefaultSizeWord(new Size(20,10)) + }; + + + for (int i = 10; i < 100; i += 10) + for (int j = 10; j < 50; j += 10) + sizeList.Add(GetDefaultSizeWord(new Size(i, j))); + sizeList.Add(GetDefaultSizeWord(new (20, 30))); + + var rectangles = layouter.GetLayout(sizeList); + var firstRectangle = rectangles.First(); + var lastRectangle = rectangles.Last(); + + var firstDistance = FindDistance(layouter.Center, firstRectangle.Bounds.Location); + var lastDistance = FindDistance(layouter.Center, lastRectangle.Bounds.Location); + + lastDistance.Should().BeGreaterThan(firstDistance); + } + + private double FindDistance(Point r1, Point r2) + { + return Math.Sqrt(Math.Pow(r2.X - r1.X, 2) + Math.Pow(r2.Y - r1.Y, 2)); + } + + [Test] + public void PutNextRectangle_ShouldPlaceRectanglesInSpiral() + { + var sizeList = new List + { + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)) + }; + + var rectangles = layouter.GetLayout(sizeList); + var firstRectangle = rectangles.First().Bounds; + + CircularCloudLayouter.GetCenterPoint(firstRectangle).Should().Be(layouter.Center); + for (int i = 1; i < 4; i++) + { + var rect = layouter.Rectangles[i]; + FindDistance(firstRectangle.Location, rect.Bounds.Location).Should().BeLessThan(30); + } + } + } +} diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs index 2a0b7b43..f90a8530 100644 --- a/TagCloudContainerTests/FileReadTest.cs +++ b/TagCloudContainerTests/FileReadTest.cs @@ -1,6 +1,7 @@ using TagsCloudContainer.FileReaders; namespace TagCloudContainerTests; + public class FileReadTest { private static readonly VerifySettings Settings = new(); diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index 5a61757a..40c5ddf5 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -1,29 +1,27 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Spire.Doc.Documents; namespace TagsCloudContainer; + public class Config { - public string InputDirectory { get; init; } - public string OutputDirectory { get; init; } - public int PictureWidth { get; init; } - public int PictureHeight { get; init; } - public string Font { get; init; } - public string[] StopWords { get; init; } - public string[] PictureColors { get; init; } + public string InputDirectory { get; set; } + public string OutputDirectory { get; set; } + public int PictureWidth { get; set; } + public int PictureHeight { get; set; } + public string Font { get; set; } + public string[] StopWords { get; set; } + public string[] RightWords { get; set; } + public string[] PictureColors { get; set; } public Config( - string inputDirectory, - string outputDirectory, - int pictureWidth, - int pictureHeight, - string font, - string[] stopWords, - string[] pictureColors) + string inputDirectory, + string outputDirectory, + int pictureWidth, + int pictureHeight, + string font, + string[] stopWords, + string[] rightWords, + string[] pictureColors) { InputDirectory = inputDirectory; OutputDirectory = outputDirectory; @@ -31,6 +29,19 @@ public Config( PictureHeight = pictureHeight; Font = font; StopWords = stopWords; + RightWords = rightWords; PictureColors = pictureColors; } + + public Config() + { + InputDirectory = Constants.InputDirectory; + OutputDirectory = Constants.OutputDirectory; + PictureWidth = Constants.PictureWidth; + PictureHeight = Constants.PictureHeight; + Font = Constants.Font; + StopWords = Constants.StopWords; + RightWords = Constants.RightWords; + PictureColors = Constants.PictureColors; + } } diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index 6b1124e9..a99265ff 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -1,52 +1,33 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; +using System.Text.RegularExpressions; namespace TagsCloudContainer; public static partial class Constants { public static string InputDirectory - { - get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); - } - } - - public static string OutputDirectory { get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Pictures\\picture.jpg"); - } - } - - public static string FilterWordsDirectory - { - get - { - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); - return Path.Combine(projectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); - } - } - - public static int PictureWidth { get { return 800; } } - - public static int PictureHeight { get { return 800; } } - - public static string Font { get { return "Arial"; } } - - public static string[] StopWords { get { return []; } } - - public static string[] PictureColors { get { return []; } } - - public static Regex wordsSplitRegex = new( + => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); + + public static string OutputDirectory + => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Pictures\\picture.jpg"); + + public static string FilterWordsDirectory + => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); + + public static string ProjectDirectory + => Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\..\")); + + public static int PictureWidth => 800; + + public static int PictureHeight => 800; + + public static string Font => "Arial"; + + public static string[] StopWords => []; + + public static string[] RightWords => []; + + public static string[] PictureColors => []; + + public readonly static Regex WordsSplitRegex = new( pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", options: RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/TagsCloudContainer/FileReaders/DocFileReader.cs b/TagsCloudContainer/FileReaders/DocFileReader.cs index 061f3f16..bd22cbb6 100644 --- a/TagsCloudContainer/FileReaders/DocFileReader.cs +++ b/TagsCloudContainer/FileReaders/DocFileReader.cs @@ -1,6 +1,7 @@ using Spire.Doc; namespace TagsCloudContainer.FileReaders; + public class DocFileReader : IReader { public string Read(string path) diff --git a/TagsCloudContainer/FileReaders/DocxFileReader.cs b/TagsCloudContainer/FileReaders/DocxFileReader.cs index 0de10712..1fb19e65 100644 --- a/TagsCloudContainer/FileReaders/DocxFileReader.cs +++ b/TagsCloudContainer/FileReaders/DocxFileReader.cs @@ -1,6 +1,7 @@ using NPOI.XWPF.UserModel; namespace TagsCloudContainer.FileReaders; + public class DocxFileReader : IReader { public string Read(string path) diff --git a/TagsCloudContainer/FileReaders/IReader.cs b/TagsCloudContainer/FileReaders/IReader.cs index 07759e0b..6b617736 100644 --- a/TagsCloudContainer/FileReaders/IReader.cs +++ b/TagsCloudContainer/FileReaders/IReader.cs @@ -1,4 +1,5 @@ namespace TagsCloudContainer.FileReaders; + public interface IReader { string Read(string path); diff --git a/TagsCloudContainer/FileReaders/TxtFileReader.cs b/TagsCloudContainer/FileReaders/TxtFileReader.cs index 57232ad6..bfd46e7c 100644 --- a/TagsCloudContainer/FileReaders/TxtFileReader.cs +++ b/TagsCloudContainer/FileReaders/TxtFileReader.cs @@ -1,4 +1,5 @@ namespace TagsCloudContainer.FileReaders; + public class TxtFileReader : IReader { public string Read(string path) diff --git a/TagsCloudContainer/Filters/IFilter.cs b/TagsCloudContainer/Filters/IFilter.cs index 449ba443..f0bb1df2 100644 --- a/TagsCloudContainer/Filters/IFilter.cs +++ b/TagsCloudContainer/Filters/IFilter.cs @@ -1,4 +1,5 @@ namespace TagsCloudContainer.Filters; + public interface IFilter { void AddStopWord(string word); diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 2d23f1aa..f64e8480 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -1,22 +1,18 @@ -using Org.BouncyCastle.Asn1.Mozilla; -using System.IO; -using System.Text.RegularExpressions; -using TagsCloudContainer.FileReaders; +using TagsCloudContainer.FileReaders; namespace TagsCloudContainer.Filters; + public class WordsFilter : IFilter { private HashSet words; - private Config config; + public WordsFilter(Config config) { - this.config = config; - words = []; var reader = new TxtFileReader(); var filterWords = reader.Read(Constants.FilterWordsDirectory); - var matches = Constants.wordsSplitRegex.Matches(filterWords); + var matches = Constants.WordsSplitRegex.Matches(filterWords); for (var i = 0; i < matches.Count; i++) { @@ -24,6 +20,7 @@ public WordsFilter(Config config) } AddStopWords(config.StopWords); + RemoveStopWords(config.RightWords); } public bool Contains(string word) @@ -33,12 +30,12 @@ public bool Contains(string word) public void AddStopWord(string word) { - words.Add(word); + words.Add(word); } public void RemoveStopWord(string word) { - words.Remove(word); + words.Remove(word); } public void AddStopWords(string[] wordArray) diff --git a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs index 5c267421..1ea4b220 100644 --- a/TagsCloudContainer/Layouters/CircularCloudLayouter.cs +++ b/TagsCloudContainer/Layouters/CircularCloudLayouter.cs @@ -2,10 +2,11 @@ using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Layouters; + public class CircularCloudLayouter : ILayouter { - private readonly List rectangles = []; - private Point center; + public readonly List Rectangles = []; // public нужен для тестов + public Point Center; private double angle; private const double spiralStep = 0.1; private const double radiusStep = 0.5; @@ -18,7 +19,7 @@ public CircularCloudLayouter(Config config) public IEnumerable GetLayout(IEnumerable words) { - center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); + Center = new Point(config.PictureWidth / 2, config.PictureHeight / 2); foreach (var (value, rectangleSize, font) in words) { Rectangle newRect; @@ -28,23 +29,23 @@ public IEnumerable GetLayout(IEnumerable words) newRect = new Rectangle(location, rectangleSize); } while (IsIntersecting(newRect)); - rectangles.Add(new RectangleWord(value, newRect, font)); + Rectangles.Add(new RectangleWord(value, newRect, font)); } - return rectangles; + return Rectangles; } private Point GetNextLocation(Size rectangleSize) { var radius = radiusStep * angle; - var centerX = center.X + (int)(radius * Math.Cos(angle)); - var centerY = center.Y + (int)(radius * Math.Sin(angle)); + var centerX = Center.X + (int)(radius * Math.Cos(angle)); + var centerY = Center.Y + (int)(radius * Math.Sin(angle)); angle += spiralStep; return GetCornerPoint(new Point(centerX, centerY), rectangleSize); } - private bool IsIntersecting(Rectangle rectangle) + public bool IsIntersecting(Rectangle rectangle) { - return rectangles. + return Rectangles. Any(existingRectangle => existingRectangle.Bounds.IntersectsWith(rectangle)); } diff --git a/TagsCloudContainer/Layouters/ILayouter.cs b/TagsCloudContainer/Layouters/ILayouter.cs index e8abe710..06f0b0af 100644 --- a/TagsCloudContainer/Layouters/ILayouter.cs +++ b/TagsCloudContainer/Layouters/ILayouter.cs @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using TagsCloudContainer.WordClasses; -using TagsCloudContainer.WordSizer; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Layouters; + public interface ILayouter { public IEnumerable GetLayout(IEnumerable words); diff --git a/TagsCloudContainer/Parsers/IParser.cs b/TagsCloudContainer/Parsers/IParser.cs index aa7e43ab..565ce65d 100644 --- a/TagsCloudContainer/Parsers/IParser.cs +++ b/TagsCloudContainer/Parsers/IParser.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace TagsCloudContainer.Parsers; -namespace TagsCloudContainer.Parsers; public interface IParser { public IDictionary Parse(string text); diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs index a62a99b8..57b19dec 100644 --- a/TagsCloudContainer/Parsers/SimpleParser.cs +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -1,6 +1,7 @@ using TagsCloudContainer.Filters; namespace TagsCloudContainer.Parsers; + public class SimpleParser : IParser { private IFilter wordsFilter; @@ -13,7 +14,7 @@ public IDictionary Parse(string text) { var dict = new Dictionary(); - var words = Constants.wordsSplitRegex.Matches(text.ToLower()); + var words = Constants.WordsSplitRegex.Matches(text.ToLower()); for (var i = 0; i < words.Count; i++) { diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 4c383c1b..1adf8f20 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,6 +1,4 @@ using Autofac; -using NPOI.SS.Formula.Functions; -using Org.BouncyCastle.Crypto; using TagsCloudContainer.FileReaders; using TagsCloudContainer.Filters; using TagsCloudContainer.Layouters; diff --git a/TagsCloudContainer/Visualizers/IVisualizer.cs b/TagsCloudContainer/Visualizers/IVisualizer.cs index 0d67f8fb..9d7e140a 100644 --- a/TagsCloudContainer/Visualizers/IVisualizer.cs +++ b/TagsCloudContainer/Visualizers/IVisualizer.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using TagsCloudContainer.WordClasses; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Visualizers; + public interface IVisualizer { public void GenerateImage(IEnumerable words); diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index b5fb1473..f4fbc784 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -1,9 +1,9 @@ using System.Drawing; using System.Drawing.Imaging; -using System.IO; using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Visualizers; + public class ImageVisualizer : IVisualizer { private Config config; diff --git a/TagsCloudContainer/WordClasses/RectangleWord.cs b/TagsCloudContainer/WordClasses/RectangleWord.cs index df091202..7cc442f5 100644 --- a/TagsCloudContainer/WordClasses/RectangleWord.cs +++ b/TagsCloudContainer/WordClasses/RectangleWord.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudContainer.WordClasses; + public record RectangleWord(string Value, Rectangle Bounds, Font font); diff --git a/TagsCloudContainer/WordClasses/SizeWord.cs b/TagsCloudContainer/WordClasses/SizeWord.cs index b8a07243..9f0a7004 100644 --- a/TagsCloudContainer/WordClasses/SizeWord.cs +++ b/TagsCloudContainer/WordClasses/SizeWord.cs @@ -1,4 +1,5 @@ using System.Drawing; namespace TagsCloudContainer.WordClasses; + public record SizeWord(string Value, Size Size, Font font); diff --git a/TagsCloudContainer/WordSizer/ISizer.cs b/TagsCloudContainer/WordSizer/ISizer.cs index 55263035..9ec4d806 100644 --- a/TagsCloudContainer/WordSizer/ISizer.cs +++ b/TagsCloudContainer/WordSizer/ISizer.cs @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using TagsCloudContainer.WordClasses; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.WordSizer; + public interface ISizer { public IEnumerable GetSizes(IDictionary words); diff --git a/TagsCloudContainer/WordSizer/SimpleSizer.cs b/TagsCloudContainer/WordSizer/SimpleSizer.cs index ba6f1292..69e6bb01 100644 --- a/TagsCloudContainer/WordSizer/SimpleSizer.cs +++ b/TagsCloudContainer/WordSizer/SimpleSizer.cs @@ -1,14 +1,8 @@ -using NPOI.OpenXmlFormats.Dml; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Net.WebSockets; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.WordSizer; + public class SimpleSizer : ISizer { private readonly Config config; @@ -32,7 +26,6 @@ public IEnumerable GetSizes(IDictionary words) var maxSize = new Size(maxWidth, maxHeight); var (size, font) = GetFontSize(maxSize, config.Font, item.Key); list.Add(new SizeWord(item.Key, size, font)); - //list.Add(new SizeWord(item.Key, maxSize, new Font("Arial", 23))); } return list; } From 235f95817aebaf2dd1b770ccbe7f7f6e6b1d8a5d Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 19:53:29 +0500 Subject: [PATCH 11/20] Add Filter Tests --- .../CircularCloudLayouterTests.cs | 232 +++++++++--------- TagCloudContainerTests/FileReadTest.cs | 7 + TagCloudContainerTests/FilterTests.cs | 115 +++++++++ .../ParserTests.cs | 10 +- TagCloudContainerTests/SizerTests.cs | 53 ++++ TagsCloudContainer/Filters/IFilter.cs | 4 +- TagsCloudContainer/Filters/WordsFilter.cs | 8 +- TagsCloudContainer/Pictures/picture.jpg | Bin 0 -> 38860 bytes 8 files changed, 303 insertions(+), 126 deletions(-) create mode 100644 TagCloudContainerTests/FilterTests.cs rename ConsoleClient/FilterTests.cs => TagCloudContainerTests/ParserTests.cs (52%) create mode 100644 TagCloudContainerTests/SizerTests.cs create mode 100644 TagsCloudContainer/Pictures/picture.jpg diff --git a/TagCloudContainerTests/CircularCloudLayouterTests.cs b/TagCloudContainerTests/CircularCloudLayouterTests.cs index 9bc67357..60b34f2e 100644 --- a/TagCloudContainerTests/CircularCloudLayouterTests.cs +++ b/TagCloudContainerTests/CircularCloudLayouterTests.cs @@ -6,144 +6,144 @@ using TagsCloudContainer.Visualizers; using TagsCloudContainer.WordClasses; -namespace TagCloudContainerTests +namespace TagCloudContainerTests; + +[TestFixture] +public class CircularCloudLayouterTests { - [TestFixture] - public class CircularCloudLayouterTests - { - private CircularCloudLayouter layouter; - private Config config; - private IVisualizer visualizer; + private CircularCloudLayouter layouter; + private Config config; + private IVisualizer visualizer; - private readonly string text = "text"; - private readonly Font font = new("Arial", 15); + private readonly string text = "text"; + private readonly Font font = new("Arial", 15); - [SetUp] - public void Setup() - { - config = new Config(); - layouter = new CircularCloudLayouter(config); - visualizer = new ImageVisualizer(config); - } + [SetUp] + public void Setup() + { + config = new Config(); + layouter = new CircularCloudLayouter(config); + visualizer = new ImageVisualizer(config); + } - [TearDown] - public void Teardown() + [TearDown] + public void Teardown() + { + var testResult = TestContext.CurrentContext.Result.Outcome; + var testName = TestContext.CurrentContext.Test.Name; + if (Equals(testResult, ResultState.Failure) || + Equals(testResult == ResultState.Error)) { - var testResult = TestContext.CurrentContext.Result.Outcome; - var testName = TestContext.CurrentContext.Test.Name; - if (Equals(testResult, ResultState.Failure) || - Equals(testResult == ResultState.Error)) - { - var drawer = visualizer; - var directory = Path.Combine(Constants.ProjectDirectory, $"FailedTestTagCloud.{testName}.jpeg"); - config.OutputDirectory = directory; - drawer.GenerateImage(layouter.Rectangles); - Console.WriteLine($"Tag cloud visualization saved to file {directory}"); - } + var drawer = visualizer; + var directory = Path.Combine(Constants.ProjectDirectory, $"FailedTestTagCloud.{testName}.jpeg"); + config.OutputDirectory = directory; + drawer.GenerateImage(layouter.Rectangles); + Console.WriteLine($"Tag cloud visualization saved to file {directory}"); } + } - private SizeWord GetDefaultSizeWord(Size size) - { - return new SizeWord(text, size, font); - } + private SizeWord GetDefaultSizeWord(Size size) + { + return new SizeWord(text, size, font); + } - [Test] - public void CircularCloudLayouter_Constructor_CorrectlySetCenter() - { - layouter.GetLayout([]); - layouter.Center - .Should() - .Be(new Point(config.PictureWidth / 2, config.PictureHeight / 2)); - } + [Test] + public void CircularCloudLayouter_Constructor_CorrectlySetCenter() + { + layouter.GetLayout([]); + layouter.Center + .Should() + .Be(new Point(config.PictureWidth / 2, config.PictureHeight / 2)); + } - [Test] - public void PutNextRectangle_PlacesFirstRectangleToCenter() - { - var size = new Size(50, 50); - var rectangles = layouter.GetLayout([GetDefaultSizeWord(size)]); - var centerRecLocation = CircularCloudLayouter. - GetCornerPoint(layouter.Center, size); - rectangles - .First() - .Bounds - .Location - .Should() - .Be(centerRecLocation); - } + [Test] + public void PutNextRectangle_PlacesFirstRectangleToCenter() + { + var size = new Size(50, 50); + + var rectangles = layouter.GetLayout([GetDefaultSizeWord(size)]); + var centerRecLocation = CircularCloudLayouter. + GetCornerPoint(layouter.Center, size); + + rectangles + .First() + .Bounds + .Location + .Should() + .Be(centerRecLocation); + } - [Test] - public void PutNextRectangle_RectanglesDoesNotIntersect() - { - var sizeList = new List(); + [Test] + public void PutNextRectangle_RectanglesDoesNotIntersect() + { + var sizeList = new List(); - for (int i = 10; i < 100; i += 10) - for (int j = 5; j < 50; j += 5) - sizeList.Add(GetDefaultSizeWord(new Size(i, j))); + for (int i = 10; i < 100; i += 10) + for (int j = 5; j < 50; j += 5) + sizeList.Add(GetDefaultSizeWord(new Size(i, j))); - var rectangles = layouter.GetLayout(sizeList); - var length = layouter.Rectangles.Count; - for (int i = 0; i < length - 1; i++) - for (int j = 0; j < length - 1; j++) - { - if (i != j) - layouter.Rectangles[i] - .Bounds - .IntersectsWith(layouter.Rectangles[j].Bounds) - .Should().BeFalse(); - } - } + var rectangles = layouter.GetLayout(sizeList); + var length = layouter.Rectangles.Count; + for (int i = 0; i < length - 1; i++) + for (int j = 0; j < length - 1; j++) + { + if (i != j) + layouter.Rectangles[i] + .Bounds + .IntersectsWith(layouter.Rectangles[j].Bounds) + .Should().BeFalse(); + } + } - [Test] - public void PutNextRectangle_IncreaseDistanceFromCenter_WithMoreRectangles() + [Test] + public void PutNextRectangle_IncreaseDistanceFromCenter_WithMoreRectangles() + { + var sizeList = new List { - var sizeList = new List - { - GetDefaultSizeWord(new Size(20,10)) - }; - + GetDefaultSizeWord(new Size(20,10)) + }; - for (int i = 10; i < 100; i += 10) - for (int j = 10; j < 50; j += 10) - sizeList.Add(GetDefaultSizeWord(new Size(i, j))); - sizeList.Add(GetDefaultSizeWord(new (20, 30))); + for (int i = 10; i < 100; i += 10) + for (int j = 10; j < 50; j += 10) + sizeList.Add(GetDefaultSizeWord(new Size(i, j))); + sizeList.Add(GetDefaultSizeWord(new (20, 30))); - var rectangles = layouter.GetLayout(sizeList); - var firstRectangle = rectangles.First(); - var lastRectangle = rectangles.Last(); + var rectangles = layouter.GetLayout(sizeList); + var firstRectangle = rectangles.First(); + var lastRectangle = rectangles.Last(); - var firstDistance = FindDistance(layouter.Center, firstRectangle.Bounds.Location); - var lastDistance = FindDistance(layouter.Center, lastRectangle.Bounds.Location); + var firstDistance = FindDistance(layouter.Center, firstRectangle.Bounds.Location); + var lastDistance = FindDistance(layouter.Center, lastRectangle.Bounds.Location); - lastDistance.Should().BeGreaterThan(firstDistance); - } + lastDistance.Should().BeGreaterThan(firstDistance); + } - private double FindDistance(Point r1, Point r2) - { - return Math.Sqrt(Math.Pow(r2.X - r1.X, 2) + Math.Pow(r2.Y - r1.Y, 2)); - } + private double FindDistance(Point r1, Point r2) + { + return Math.Sqrt(Math.Pow(r2.X - r1.X, 2) + Math.Pow(r2.Y - r1.Y, 2)); + } - [Test] - public void PutNextRectangle_ShouldPlaceRectanglesInSpiral() + [Test] + public void PutNextRectangle_ShouldPlaceRectanglesInSpiral() + { + var sizeList = new List { - var sizeList = new List - { - GetDefaultSizeWord(new Size(10,10)), - GetDefaultSizeWord(new Size(10,10)), - GetDefaultSizeWord(new Size(10,10)), - GetDefaultSizeWord(new Size(10,10)), - GetDefaultSizeWord(new Size(10,10)) - }; - - var rectangles = layouter.GetLayout(sizeList); - var firstRectangle = rectangles.First().Bounds; - - CircularCloudLayouter.GetCenterPoint(firstRectangle).Should().Be(layouter.Center); - for (int i = 1; i < 4; i++) - { - var rect = layouter.Rectangles[i]; - FindDistance(firstRectangle.Location, rect.Bounds.Location).Should().BeLessThan(30); - } + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)), + GetDefaultSizeWord(new Size(10,10)) + }; + + var rectangles = layouter.GetLayout(sizeList); + var firstRectangle = rectangles.First().Bounds; + + CircularCloudLayouter.GetCenterPoint(firstRectangle).Should().Be(layouter.Center); + for (int i = 1; i < 4; i++) + { + var rect = layouter.Rectangles[i]; + FindDistance(firstRectangle.Location, rect.Bounds.Location).Should().BeLessThan(30); } } } diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs index f90a8530..425b39f7 100644 --- a/TagCloudContainerTests/FileReadTest.cs +++ b/TagCloudContainerTests/FileReadTest.cs @@ -2,6 +2,7 @@ namespace TagCloudContainerTests; +[TestFixture] public class FileReadTest { private static readonly VerifySettings Settings = new(); @@ -21,8 +22,10 @@ public void Setup() public Task Reader_TxtReading() { Reader = new TxtFileReader(); + var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); var actual = Reader.Read(filePath); + return Verify(actual, Settings); } @@ -30,8 +33,10 @@ public Task Reader_TxtReading() public Task Reader_DocxReading() { Reader = new DocxFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); var actual = Reader.Read(filePath); + return Verify(actual, Settings); } @@ -39,8 +44,10 @@ public Task Reader_DocxReading() public Task Reader_DocReading() { Reader = new DocFileReader(); + var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); var actual = Reader.Read(filePath); + return Verify(actual, Settings); } } diff --git a/TagCloudContainerTests/FilterTests.cs b/TagCloudContainerTests/FilterTests.cs new file mode 100644 index 00000000..e894946e --- /dev/null +++ b/TagCloudContainerTests/FilterTests.cs @@ -0,0 +1,115 @@ +using TagsCloudContainer.FileReaders; +using TagsCloudContainer; +using TagsCloudContainer.Filters; +using FluentAssertions; + +namespace TagCloudContainerTests; + +[TestFixture] +public class FilterTests +{ + private Config config; + private string filterWordsFile; + + [SetUp] + public void Setup() + { + config = new Config(); + var folderPath = Path.Combine(Constants.ProjectDirectory, "TagCloudConrainerTests\\Files"); + filterWordsFile = Path.Combine(folderPath, "FilterWords.txt"); + } + + [Test] + public void Filter_ReadWordsFromFile() + { + var filter = new WordsFilter(config); + var reader = new TxtFileReader(); + + var filterWords = + reader + .Read(Constants.FilterWordsDirectory) + .Split("\r\n") + .ToArray(); + + foreach (var word in filterWords) + { + filter.Contains(word).Should().BeTrue(); + } + } + + [TestCase("Абрикос")] + [TestCase("Яблоко")] + [TestCase("Глицерин")] + [TestCase("Сталин")] + [TestCase("Car")] + public void Filter_AddStopWord_FromMethod(string stopWord) + { + var filter = new WordsFilter(config); + filter.AddStopWord(stopWord); + + filter.Contains(stopWord).Should().BeTrue(); + } + + + public void Filter_AddStopWords_FromMethod() + { + var filter = new WordsFilter(config); + var stopWord = new string[] { "Карамель", "Ирис", "Шоколадка", "Трансформер" }; + filter.AddStopWords(stopWord); + + foreach (var word in stopWord) + { + filter.Contains(word).Should().BeTrue(); + } + } + + [TestCase("а")] + [TestCase("в")] + [TestCase("за")] + [TestCase("под")] + [TestCase("из")] + public void Filter_RemoveRightWord_FromMethod(string stopWord) + { + var filter = new WordsFilter(config); + filter.RemoveRightWord(stopWord); + + filter.Contains(stopWord).Should().BeFalse(); + } + + [Test] + public void Filter_RemoveRightWords_FromMethod() + { + var filter = new WordsFilter(config); + var rightWord = new string[] { "он", "она", "они", "оно" }; + filter.RemoveRightWords(rightWord); + + foreach (var word in rightWord) + { + filter.Contains(word).Should().BeFalse(); + } + } + + [Test] + public void Filter_AddStopWords_FromConfig() + { + config.StopWords = ["Моска", "Волгоград"]; + var filter = new WordsFilter(config); + + foreach (var word in config.StopWords) + { + filter.Contains(word).Should().BeTrue(); + } + } + + public void Filter_RemoveRightWords_FromConfig() + { + config.StopWords = ["он", "она", "они", "оно"]; + var filter = new WordsFilter(config); + + foreach (var word in config.StopWords) + { + filter.Contains(word).Should().BeFalse(); + } + } +} + diff --git a/ConsoleClient/FilterTests.cs b/TagCloudContainerTests/ParserTests.cs similarity index 52% rename from ConsoleClient/FilterTests.cs rename to TagCloudContainerTests/ParserTests.cs index 5d710ae9..168b27cc 100644 --- a/ConsoleClient/FilterTests.cs +++ b/TagCloudContainerTests/ParserTests.cs @@ -3,10 +3,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using TagsCloudContainer.FileReaders; -namespace ConsoleClient +namespace TagCloudContainerTests; + +[TestFixture] +public class ParserTests { - class FilterTests - { - } + } diff --git a/TagCloudContainerTests/SizerTests.cs b/TagCloudContainerTests/SizerTests.cs new file mode 100644 index 00000000..6b022831 --- /dev/null +++ b/TagCloudContainerTests/SizerTests.cs @@ -0,0 +1,53 @@ +using TagsCloudContainer.FileReaders; + +namespace TagCloudContainerTests; + +[TestFixture] +public class SizerTests +{ + private static readonly VerifySettings Settings = new(); + private IReader Reader; + private string FolderPath; + + [SetUp] + public void Setup() + { + Settings.UseDirectory("Snapshots"); + var projectDirectory = + Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); + FolderPath = Path.Combine(projectDirectory, "Files"); + } + + [Test] + public Task Reader_TxtReading() + { + Reader = new TxtFileReader(); + + var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); + var actual = Reader.Read(filePath); + + return Verify(actual, Settings); + } + + [Test] + public Task Reader_DocxReading() + { + Reader = new DocxFileReader(); + + var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); + var actual = Reader.Read(filePath); + + return Verify(actual, Settings); + } + + [Test] + public Task Reader_DocReading() + { + Reader = new DocFileReader(); + + var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); + var actual = Reader.Read(filePath); + + return Verify(actual, Settings); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/Filters/IFilter.cs b/TagsCloudContainer/Filters/IFilter.cs index f0bb1df2..56a6f16b 100644 --- a/TagsCloudContainer/Filters/IFilter.cs +++ b/TagsCloudContainer/Filters/IFilter.cs @@ -5,6 +5,6 @@ public interface IFilter void AddStopWord(string word); void AddStopWords(string[] wordArray); bool Contains(string word); - void RemoveStopWord(string word); - void RemoveStopWords(string[] wordArray); + void RemoveRightWord(string word); + void RemoveRightWords(string[] wordArray); } \ No newline at end of file diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index f64e8480..be441ee2 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -20,7 +20,7 @@ public WordsFilter(Config config) } AddStopWords(config.StopWords); - RemoveStopWords(config.RightWords); + RemoveRightWords(config.RightWords); } public bool Contains(string word) @@ -33,7 +33,7 @@ public void AddStopWord(string word) words.Add(word); } - public void RemoveStopWord(string word) + public void RemoveRightWord(string word) { words.Remove(word); } @@ -44,9 +44,9 @@ public void AddStopWords(string[] wordArray) AddStopWord(word); } - public void RemoveStopWords(string[] wordArray) + public void RemoveRightWords(string[] wordArray) { foreach (var word in wordArray) - RemoveStopWord(word); + RemoveRightWord(word); } } \ No newline at end of file diff --git a/TagsCloudContainer/Pictures/picture.jpg b/TagsCloudContainer/Pictures/picture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..95d88b0dff142f3007876180627b6ec66d0b9a63 GIT binary patch literal 38860 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 H*Vumpoh;zI literal 0 HcmV?d00001 From 03f49ddbe04f3124beb6eb721d69af719c5c8515 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 20:20:19 +0500 Subject: [PATCH 12/20] Add Parser Tests --- TagCloudContainerTests/ParserTests.cs | 86 ++++++++++++++++++++++-- TagCloudContainerTests/SizerTests.cs | 45 ------------- TagsCloudContainer/Files/filterwords.txt | 1 - 3 files changed, 81 insertions(+), 51 deletions(-) diff --git a/TagCloudContainerTests/ParserTests.cs b/TagCloudContainerTests/ParserTests.cs index 168b27cc..5c607e65 100644 --- a/TagCloudContainerTests/ParserTests.cs +++ b/TagCloudContainerTests/ParserTests.cs @@ -1,14 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using FluentAssertions; +using TagsCloudContainer; using TagsCloudContainer.FileReaders; +using TagsCloudContainer.Filters; +using TagsCloudContainer.Parsers; namespace TagCloudContainerTests; [TestFixture] public class ParserTests { + private Config config; + private WordsFilter defaultFilter; + [SetUp] + public void Setup() + { + config = new Config(); + defaultFilter = new WordsFilter(config); + var folderPath = Path.Combine(Constants.ProjectDirectory, "TagCloudConrainerTests\\Files"); + } + + [TestCase("Шла Саша шоссе")] + [TestCase("Бублик Печенька")] + [TestCase("Автобот качели")] + [TestCase("мимино квадрат малевич")] + public void Parser_CorrectWithSimpleWords(string text) + { + var parser = new SimpleParser(defaultFilter); + + var parsed = parser.Parse(text); + + foreach (var word in text.Split(' ')) + { + parsed.ContainsKey(word.ToLower()).Should().BeTrue(); + } + } + + [TestCase("Шла %1--Саша @#^%шоссе", "шла саша шоссе")] + [TestCase("Бублик@ -Печенька", "бублик печенька")] + [TestCase("()()()Автобот _+качели", "автобот качели")] + [TestCase("мимино% квадрат$ #малевич++", "мимино квадрат малевич")] + [TestCase("%:(*?кролик:%**)", "кролик")] + public void Parser_CorrectWithNonLettericSymbols(string text, string correct) + { + var parser = new SimpleParser(defaultFilter); + + var parsed = parser.Parse(text); + + foreach (var word in correct.Split(' ')) + { + parsed.ContainsKey(word).Should().BeTrue(); + } + } + + + [TestCase("шла я и саша по шоссе", "шла саша шоссе")] + [TestCase("бублик под печенькой", "бублик печенькой")] + [TestCase("автобот от качелей", "автобот качелей")] + [TestCase("мимино оно как квадрат малевича", "мимино квадрат малевича")] + public void Parser_FilterStopWords(string text, string correct) + { + var parser = new SimpleParser(defaultFilter); + + var parsed = parser.Parse(text); + + foreach (var word in correct.Split(' ')) + { + parsed.ContainsKey(word).Should().BeTrue(); + } + } + + [Test] + public void Parser_GiveCorrectWeightToWords() + { + var parser = new SimpleParser(defaultFilter); + var text = "один два два три три три четыре четыре четыре четыре"; + var correct = new Dictionary + { + { "один", 1}, + { "два", 2}, + { "три", 3}, + { "четыре", 4}, + }; + + var parsed = parser.Parse(text); + + parsed.Should().BeEquivalentTo(correct); + } } diff --git a/TagCloudContainerTests/SizerTests.cs b/TagCloudContainerTests/SizerTests.cs index 6b022831..72967861 100644 --- a/TagCloudContainerTests/SizerTests.cs +++ b/TagCloudContainerTests/SizerTests.cs @@ -5,49 +5,4 @@ namespace TagCloudContainerTests; [TestFixture] public class SizerTests { - private static readonly VerifySettings Settings = new(); - private IReader Reader; - private string FolderPath; - - [SetUp] - public void Setup() - { - Settings.UseDirectory("Snapshots"); - var projectDirectory = - Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\")); - FolderPath = Path.Combine(projectDirectory, "Files"); - } - - [Test] - public Task Reader_TxtReading() - { - Reader = new TxtFileReader(); - - var filePath = Path.Combine(FolderPath, "wordsTXT.txt"); - var actual = Reader.Read(filePath); - - return Verify(actual, Settings); - } - - [Test] - public Task Reader_DocxReading() - { - Reader = new DocxFileReader(); - - var filePath = Path.Combine(FolderPath, "wordsDOCX.docx"); - var actual = Reader.Read(filePath); - - return Verify(actual, Settings); - } - - [Test] - public Task Reader_DocReading() - { - Reader = new DocFileReader(); - - var filePath = Path.Combine(FolderPath, "wordsDOC.doc"); - var actual = Reader.Read(filePath); - - return Verify(actual, Settings); - } } \ No newline at end of file diff --git a/TagsCloudContainer/Files/filterwords.txt b/TagsCloudContainer/Files/filterwords.txt index 273be4ac..f1ff69b1 100644 --- a/TagsCloudContainer/Files/filterwords.txt +++ b/TagsCloudContainer/Files/filterwords.txt @@ -90,7 +90,6 @@ только том тот -три ты у уж From f227cdb96885ec17a4b1d5b459a325bd9d1826f8 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 20:41:30 +0500 Subject: [PATCH 13/20] Add Sizer Tests --- TagCloudContainerTests/ParserTests.cs | 1 - TagCloudContainerTests/SizerTests.cs | 54 ++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/TagCloudContainerTests/ParserTests.cs b/TagCloudContainerTests/ParserTests.cs index 5c607e65..2204ecb0 100644 --- a/TagCloudContainerTests/ParserTests.cs +++ b/TagCloudContainerTests/ParserTests.cs @@ -17,7 +17,6 @@ public void Setup() { config = new Config(); defaultFilter = new WordsFilter(config); - var folderPath = Path.Combine(Constants.ProjectDirectory, "TagCloudConrainerTests\\Files"); } [TestCase("Шла Саша шоссе")] diff --git a/TagCloudContainerTests/SizerTests.cs b/TagCloudContainerTests/SizerTests.cs index 72967861..95a0e0de 100644 --- a/TagCloudContainerTests/SizerTests.cs +++ b/TagCloudContainerTests/SizerTests.cs @@ -1,8 +1,60 @@ -using TagsCloudContainer.FileReaders; +using FluentAssertions; +using System.Drawing; +using TagsCloudContainer; +using TagsCloudContainer.WordSizer; namespace TagCloudContainerTests; [TestFixture] public class SizerTests { + private Config config; + private Dictionary defaultDictionary; + + [SetUp] + public void Setup() + { + config = new Config(); + + defaultDictionary = new Dictionary + { + { "один", 1}, + { "два", 2}, + { "три", 3}, + { "четыре", 4}, + }; + + var folderPath = Path.Combine(Constants.ProjectDirectory, "TagCloudConrainerTests\\Files"); + } + + [Test] + public void Sizer_ReturnSizeForAllWords() + { + var sizer = new SimpleSizer(config); + + var sized = sizer.GetSizes(defaultDictionary); + + sized.Count().Should().Be(defaultDictionary.Keys.Count); + sized.All(x => defaultDictionary.ContainsKey(x.Value)).Should().BeTrue(); + } + + [Test] + public void Sizer_GiveBiggerSizeToHeavierWord() + { + var sizer = new SimpleSizer(config); + + var sized = sizer.GetSizes(defaultDictionary).ToArray(); + for (var i = 0; i < sized.Length - 2; i++) + { + var heavierWord = GetSizeSquare(sized[i].Size); + var lighterWord = GetSizeSquare(sized[i + 1].Size); + heavierWord.Should().BeGreaterThan(lighterWord); + } + } + + private int GetSizeSquare(Size size) + { + return size.Width * size.Height; + } + } \ No newline at end of file From 474eff00f526d420cfc74be6ad861ff520eda246 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 21:08:00 +0500 Subject: [PATCH 14/20] Refactor Communication with Console Client --- ConsoleClient/ConsoleClient.cs | 113 ++++++++++++++---- TagCloudContainerTests/FileReadTest.cs | 3 + TagCloudContainerTests/FilterTests.cs | 1 + TagsCloudContainer/ApplicationRunner.cs | 112 +++++++++++++++++ TagsCloudContainer/IApplicationRunner.cs | 13 ++ TagsCloudContainer/Pictures/picture.jpg | Bin 38860 -> 0 bytes TagsCloudContainer/Program.cs | 42 +------ .../Visualizers/ImageVisualizer.cs | 2 - 8 files changed, 226 insertions(+), 60 deletions(-) create mode 100644 TagsCloudContainer/ApplicationRunner.cs create mode 100644 TagsCloudContainer/IApplicationRunner.cs delete mode 100644 TagsCloudContainer/Pictures/picture.jpg diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index fb4a0048..9a4e9368 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -1,13 +1,78 @@ -using McMaster.Extensions.CommandLineUtils; +//using Autofac; +//using McMaster.Extensions.CommandLineUtils; +//using TagsCloudContainer; +//using TagsCloudContainer.FileReaders; +//using TagsCloudContainer.Filters; +//using TagsCloudContainer.Layouters; +//using TagsCloudContainer.Parsers; +//using TagsCloudContainer.Visualizers; +//using TagsCloudContainer.WordSizer; + +//public class ConsoleClient +//{ +// [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] +// public string InputDirectory { get; set; } + +// [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] +// public string OutputDirectory { get; set; } + +// [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] +// public int PictureWidth { get; set; } + +// [Option("--height", "Height of the picture.", CommandOptionType.SingleValue)] +// public int PictureHeight { get; set; } + +// [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] +// public string Font { get; set; } + +// [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] +// public string StopWordsInput { get; set; } + +// [Option("--rightwords", "Comma-separated list of right words.", CommandOptionType.SingleValue)] +// public string RightWordsInput { get; set; } + +// [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] +// public string ColorsInput { get; set; } + +// public string[] StopWords => StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); + +// public string[] RightWords => RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); + +// public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); + +// public static int Main(string[] args) +// { +// return CommandLineApplication.Execute(args); +// } + +// private void OnExecute() +// { +// var config = new Config( +// InputDirectory is null ? Constants.InputDirectory : InputDirectory, +// OutputDirectory is null ? Constants.OutputDirectory : OutputDirectory, +// PictureWidth == default ? Constants.PictureWidth : PictureWidth, +// PictureHeight == default ? Constants.PictureHeight : PictureHeight, +// Font is null ? Constants.Font : Font, +// StopWords is null ? Constants.StopWords : StopWords, +// RightWords is null ? Constants.RightWords : RightWords, +// PictureColors is null ? Constants.PictureColors : PictureColors +// ); + +// TagsCloudContainer.Program.Main(config); +// } +//} + +using McMaster.Extensions.CommandLineUtils; +using Autofac; using TagsCloudContainer; public class ConsoleClient { [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] - public string InputDirectory { get; set; } + public string? InputDirectory { get; set; } [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] - public string OutputDirectory { get; set; } + public string? OutputDirectory { get; set; } [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] public int PictureWidth { get; set; } @@ -16,24 +81,23 @@ public class ConsoleClient public int PictureHeight { get; set; } [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] - public string Font { get; set; } + public string? Font { get; set; } [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] - public string StopWordsInput { get; set; } + public string? StopWordsInput { get; set; } [Option("--rightwords", "Comma-separated list of right words.", CommandOptionType.SingleValue)] - public string RightWordsInput { get; set; } + public string? RightWordsInput { get; set; } [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] - public string ColorsInput { get; set; } - - public string[] StopWords => StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); - - public string[] RightWords => RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); - - public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); + public string? ColorsInput { get; set; } public static int Main(string[] args) + { + return RunConsoleClient(args); + } + + private static int RunConsoleClient(string[] args) { return CommandLineApplication.Execute(args); } @@ -41,17 +105,24 @@ public static int Main(string[] args) private void OnExecute() { var config = new Config( - InputDirectory is null ? Constants.InputDirectory : InputDirectory, - OutputDirectory is null ? Constants.OutputDirectory : OutputDirectory, + InputDirectory ?? Constants.InputDirectory, + OutputDirectory ?? Constants.OutputDirectory, PictureWidth == default ? Constants.PictureWidth : PictureWidth, PictureHeight == default ? Constants.PictureHeight : PictureHeight, - Font is null ? Constants.Font : Font, - StopWords is null ? Constants.StopWords : StopWords, - RightWords is null ? Constants.RightWords : RightWords, - PictureColors is null ? Constants.PictureColors : PictureColors - ); + Font ?? Constants.Font, + StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Constants.StopWords, + RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Constants.RightWords, + ColorsInput?.Split(',') ?? Constants.PictureColors + ); - TagsCloudContainer.Program.Main(config); + var container = ApplicationRunner.BuildContainer(config); + + using var scope = container.BeginLifetimeScope(); + var runner = scope.Resolve(); + runner.Run(); } + + } + diff --git a/TagCloudContainerTests/FileReadTest.cs b/TagCloudContainerTests/FileReadTest.cs index 425b39f7..f36c3d16 100644 --- a/TagCloudContainerTests/FileReadTest.cs +++ b/TagCloudContainerTests/FileReadTest.cs @@ -19,6 +19,7 @@ public void Setup() } [Test] + [Parallelizable(ParallelScope.Self)] public Task Reader_TxtReading() { Reader = new TxtFileReader(); @@ -30,6 +31,7 @@ public Task Reader_TxtReading() } [Test] + [Parallelizable(ParallelScope.Self)] public Task Reader_DocxReading() { Reader = new DocxFileReader(); @@ -41,6 +43,7 @@ public Task Reader_DocxReading() } [Test] + [Parallelizable(ParallelScope.Self)] public Task Reader_DocReading() { Reader = new DocFileReader(); diff --git a/TagCloudContainerTests/FilterTests.cs b/TagCloudContainerTests/FilterTests.cs index e894946e..25c5f417 100644 --- a/TagCloudContainerTests/FilterTests.cs +++ b/TagCloudContainerTests/FilterTests.cs @@ -20,6 +20,7 @@ public void Setup() } [Test] + [Parallelizable(ParallelScope.Self)] public void Filter_ReadWordsFromFile() { var filter = new WordsFilter(config); diff --git a/TagsCloudContainer/ApplicationRunner.cs b/TagsCloudContainer/ApplicationRunner.cs new file mode 100644 index 00000000..f904e58e --- /dev/null +++ b/TagsCloudContainer/ApplicationRunner.cs @@ -0,0 +1,112 @@ +using Autofac; +using TagsCloudContainer; +using TagsCloudContainer.FileReaders; +using TagsCloudContainer.Filters; +using TagsCloudContainer.Layouters; +using TagsCloudContainer.Parsers; +using TagsCloudContainer.Visualizers; +using TagsCloudContainer.WordSizer; +//using TagsCloudContainer.FileReaders; +//using TagsCloudContainer.Filters; +//using TagsCloudContainer.Layouters; +//using TagsCloudContainer.Parsers; +//using TagsCloudContainer.Visualizers; +//using TagsCloudContainer.WordSizer; + +//namespace TagsCloudContainer; +//public static class Program +//{ +// public static void Main() +// { +// } +// public static void Main(Config config) +// { +// var builder = new ContainerBuilder(); +// builder.RegisterInstance(config).As(); +// builder.RegisterType().As(); +// builder.RegisterType().As(); +// builder.RegisterType().As(); +// builder.RegisterType().As(); +// builder.RegisterType().As(); +// builder.RegisterType().As(); +// var container = builder.Build(); + +// var reader = container.Resolve(); +// var parser = container.Resolve(); +// var sizer = container.Resolve(); +// var layouter = container.Resolve(); +// var visualizer = container.Resolve(); + +// visualizer.GenerateImage( +// layouter.GetLayout( +// sizer.GetSizes( +// parser.Parse( +// reader.Read( +// config.InputDirectory +// ) +// ) +// ) +// ) +// ); +// } +//} + + + +public class ApplicationRunner : IApplicationRunner +{ + private readonly Config config; + private readonly IReader reader; + private readonly IParser parser; + private readonly ISizer sizer; + private readonly ILayouter layouter; + private readonly IVisualizer visualizer; + + public ApplicationRunner( + Config config, + IReader reader, + IParser parser, + ISizer sizer, + ILayouter layouter, + IVisualizer visualizer) + { + this.config = config; + this.reader = reader; + this.parser = parser; + this.sizer = sizer; + this.layouter = layouter; + this.visualizer = visualizer; + } + + public void Run() + { + visualizer.GenerateImage( + layouter.GetLayout( + sizer.GetSizes( + parser.Parse( + reader.Read( + config.InputDirectory + ) + ) + ) + ) + ); + } + + public static IContainer BuildContainer(Config config) + { + var builder = new ContainerBuilder(); + + builder.RegisterInstance(config).As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + builder.RegisterType().As(); + + return builder.Build(); + } +} diff --git a/TagsCloudContainer/IApplicationRunner.cs b/TagsCloudContainer/IApplicationRunner.cs new file mode 100644 index 00000000..cc76cdd0 --- /dev/null +++ b/TagsCloudContainer/IApplicationRunner.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer +{ + public interface IApplicationRunner + { + void Run(); + } +} diff --git a/TagsCloudContainer/Pictures/picture.jpg b/TagsCloudContainer/Pictures/picture.jpg deleted file mode 100644 index 95d88b0dff142f3007876180627b6ec66d0b9a63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38860 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 H*Vumpoh;zI diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 1adf8f20..2bcc4458 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,10 +1,8 @@ -using Autofac; -using TagsCloudContainer.FileReaders; -using TagsCloudContainer.Filters; -using TagsCloudContainer.Layouters; -using TagsCloudContainer.Parsers; -using TagsCloudContainer.Visualizers; -using TagsCloudContainer.WordSizer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; namespace TagsCloudContainer; public static class Program @@ -12,34 +10,4 @@ public static class Program public static void Main() { } - public static void Main(Config config) - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(config).As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - var container = builder.Build(); - - var reader = container.Resolve(); - var parser = container.Resolve(); - var sizer = container.Resolve(); - var layouter = container.Resolve(); - var visualizer = container.Resolve(); - - visualizer.GenerateImage( - layouter.GetLayout( - sizer.GetSizes( - parser.Parse( - reader.Read( - config.InputDirectory - ) - ) - ) - ) - ); - } } diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index f4fbc784..2f179b5c 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -16,11 +16,9 @@ public void GenerateImage(IEnumerable words) { using var image = new Bitmap(config.PictureWidth, config.PictureWidth); using var g = Graphics.FromImage(image); - var pen = new Pen(Brushes.AliceBlue, 2); foreach (var item in words) { - g.DrawRectangle(pen, item.Bounds); g.DrawString(item.Value, item.font, Brushes.Orange, item.Bounds.Location); } From c36e7418565c0eb4518e85f83029886deaec7154 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 21:17:09 +0500 Subject: [PATCH 15/20] Add Extension Points --- TagCloudContainerTests/CircularCloudLayouterTests.cs | 1 + TagCloudContainerTests/FilterTests.cs | 6 ++++++ TagCloudContainerTests/SizerTests.cs | 1 + TagsCloudContainer/Parsers/IParser.cs | 4 ++++ TagsCloudContainer/Parsers/SimpleParser.cs | 10 ++++++++++ TagsCloudContainer/Visualizers/IVisualizer.cs | 7 ++++++- TagsCloudContainer/Visualizers/ImageVisualizer.cs | 10 ++++++++++ 7 files changed, 38 insertions(+), 1 deletion(-) diff --git a/TagCloudContainerTests/CircularCloudLayouterTests.cs b/TagCloudContainerTests/CircularCloudLayouterTests.cs index 60b34f2e..9f9bf3b8 100644 --- a/TagCloudContainerTests/CircularCloudLayouterTests.cs +++ b/TagCloudContainerTests/CircularCloudLayouterTests.cs @@ -52,6 +52,7 @@ private SizeWord GetDefaultSizeWord(Size size) public void CircularCloudLayouter_Constructor_CorrectlySetCenter() { layouter.GetLayout([]); + layouter.Center .Should() .Be(new Point(config.PictureWidth / 2, config.PictureHeight / 2)); diff --git a/TagCloudContainerTests/FilterTests.cs b/TagCloudContainerTests/FilterTests.cs index 25c5f417..75fb65f4 100644 --- a/TagCloudContainerTests/FilterTests.cs +++ b/TagCloudContainerTests/FilterTests.cs @@ -46,6 +46,7 @@ public void Filter_ReadWordsFromFile() public void Filter_AddStopWord_FromMethod(string stopWord) { var filter = new WordsFilter(config); + filter.AddStopWord(stopWord); filter.Contains(stopWord).Should().BeTrue(); @@ -56,6 +57,7 @@ public void Filter_AddStopWords_FromMethod() { var filter = new WordsFilter(config); var stopWord = new string[] { "Карамель", "Ирис", "Шоколадка", "Трансформер" }; + filter.AddStopWords(stopWord); foreach (var word in stopWord) @@ -72,6 +74,7 @@ public void Filter_AddStopWords_FromMethod() public void Filter_RemoveRightWord_FromMethod(string stopWord) { var filter = new WordsFilter(config); + filter.RemoveRightWord(stopWord); filter.Contains(stopWord).Should().BeFalse(); @@ -82,6 +85,7 @@ public void Filter_RemoveRightWords_FromMethod() { var filter = new WordsFilter(config); var rightWord = new string[] { "он", "она", "они", "оно" }; + filter.RemoveRightWords(rightWord); foreach (var word in rightWord) @@ -94,6 +98,7 @@ public void Filter_RemoveRightWords_FromMethod() public void Filter_AddStopWords_FromConfig() { config.StopWords = ["Моска", "Волгоград"]; + var filter = new WordsFilter(config); foreach (var word in config.StopWords) @@ -105,6 +110,7 @@ public void Filter_AddStopWords_FromConfig() public void Filter_RemoveRightWords_FromConfig() { config.StopWords = ["он", "она", "они", "оно"]; + var filter = new WordsFilter(config); foreach (var word in config.StopWords) diff --git a/TagCloudContainerTests/SizerTests.cs b/TagCloudContainerTests/SizerTests.cs index 95a0e0de..904a4216 100644 --- a/TagCloudContainerTests/SizerTests.cs +++ b/TagCloudContainerTests/SizerTests.cs @@ -44,6 +44,7 @@ public void Sizer_GiveBiggerSizeToHeavierWord() var sizer = new SimpleSizer(config); var sized = sizer.GetSizes(defaultDictionary).ToArray(); + for (var i = 0; i < sized.Length - 2; i++) { var heavierWord = GetSizeSquare(sized[i].Size); diff --git a/TagsCloudContainer/Parsers/IParser.cs b/TagsCloudContainer/Parsers/IParser.cs index 565ce65d..917c6aee 100644 --- a/TagsCloudContainer/Parsers/IParser.cs +++ b/TagsCloudContainer/Parsers/IParser.cs @@ -3,4 +3,8 @@ public interface IParser { public IDictionary Parse(string text); + + public string BringWordsToOriginalForm(string text); + + public string TakeOnlyOnePartOfSpeech(string text, string partOfSpeech); } diff --git a/TagsCloudContainer/Parsers/SimpleParser.cs b/TagsCloudContainer/Parsers/SimpleParser.cs index 57b19dec..cb7f73c1 100644 --- a/TagsCloudContainer/Parsers/SimpleParser.cs +++ b/TagsCloudContainer/Parsers/SimpleParser.cs @@ -29,4 +29,14 @@ public IDictionary Parse(string text) } return dict; } + + public string TakeOnlyOnePartOfSpeech(string text, string partOfSpeech) + { + throw new NotImplementedException(); + } + + public string BringWordsToOriginalForm(string text) + { + throw new NotImplementedException(); + } } diff --git a/TagsCloudContainer/Visualizers/IVisualizer.cs b/TagsCloudContainer/Visualizers/IVisualizer.cs index 9d7e140a..e674b9e2 100644 --- a/TagsCloudContainer/Visualizers/IVisualizer.cs +++ b/TagsCloudContainer/Visualizers/IVisualizer.cs @@ -1,8 +1,13 @@ -using TagsCloudContainer.WordClasses; +using System.Drawing; +using TagsCloudContainer.WordClasses; namespace TagsCloudContainer.Visualizers; public interface IVisualizer { public void GenerateImage(IEnumerable words); + + public Color GetWordColor(RectangleWord word); + + public string GetImageFotmat(); } diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index 2f179b5c..1a799477 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -24,4 +24,14 @@ public void GenerateImage(IEnumerable words) image.Save(config.OutputDirectory, ImageFormat.Jpeg); } + + public string GetImageFotmat() + { + throw new NotImplementedException(); + } + + public Color GetWordColor(RectangleWord word) + { + throw new NotImplementedException(); + } } From d658b56baed64c2d7a13a2def4884cd3b02c6e27 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 21:19:29 +0500 Subject: [PATCH 16/20] Remove comments --- ConsoleClient/ConsoleClient.cs | 59 ------------------------- TagsCloudContainer/ApplicationRunner.cs | 46 ------------------- 2 files changed, 105 deletions(-) diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 9a4e9368..9d3117da 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -3,65 +3,6 @@ //using TagsCloudContainer; //using TagsCloudContainer.FileReaders; //using TagsCloudContainer.Filters; -//using TagsCloudContainer.Layouters; -//using TagsCloudContainer.Parsers; -//using TagsCloudContainer.Visualizers; -//using TagsCloudContainer.WordSizer; - -//public class ConsoleClient -//{ -// [Option("--input", "Path to the input file.", CommandOptionType.SingleValue)] -// public string InputDirectory { get; set; } - -// [Option("--output", "Path to the output file.", CommandOptionType.SingleValue)] -// public string OutputDirectory { get; set; } - -// [Option("--width", "Width of the picture.", CommandOptionType.SingleValue)] -// public int PictureWidth { get; set; } - -// [Option("--height", "Height of the picture.", CommandOptionType.SingleValue)] -// public int PictureHeight { get; set; } - -// [Option("--font", "Font for the picture text.", CommandOptionType.SingleValue)] -// public string Font { get; set; } - -// [Option("--stopwords", "Comma-separated list of stop words.", CommandOptionType.SingleValue)] -// public string StopWordsInput { get; set; } - -// [Option("--rightwords", "Comma-separated list of right words.", CommandOptionType.SingleValue)] -// public string RightWordsInput { get; set; } - -// [Option("--colors", "Comma-separated list of colors in ARGB format (e.g., 255,0,0,255).", CommandOptionType.SingleValue)] -// public string ColorsInput { get; set; } - -// public string[] StopWords => StopWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); - -// public string[] RightWords => RightWordsInput?.Split(',').Select(x => x.ToLower()).ToArray() ?? Array.Empty(); - -// public string[] PictureColors => ColorsInput?.Split(',') ?? Array.Empty(); - -// public static int Main(string[] args) -// { -// return CommandLineApplication.Execute(args); -// } - -// private void OnExecute() -// { -// var config = new Config( -// InputDirectory is null ? Constants.InputDirectory : InputDirectory, -// OutputDirectory is null ? Constants.OutputDirectory : OutputDirectory, -// PictureWidth == default ? Constants.PictureWidth : PictureWidth, -// PictureHeight == default ? Constants.PictureHeight : PictureHeight, -// Font is null ? Constants.Font : Font, -// StopWords is null ? Constants.StopWords : StopWords, -// RightWords is null ? Constants.RightWords : RightWords, -// PictureColors is null ? Constants.PictureColors : PictureColors -// ); - -// TagsCloudContainer.Program.Main(config); -// } -//} - using McMaster.Extensions.CommandLineUtils; using Autofac; using TagsCloudContainer; diff --git a/TagsCloudContainer/ApplicationRunner.cs b/TagsCloudContainer/ApplicationRunner.cs index f904e58e..9eb8cbd8 100644 --- a/TagsCloudContainer/ApplicationRunner.cs +++ b/TagsCloudContainer/ApplicationRunner.cs @@ -6,52 +6,6 @@ using TagsCloudContainer.Parsers; using TagsCloudContainer.Visualizers; using TagsCloudContainer.WordSizer; -//using TagsCloudContainer.FileReaders; -//using TagsCloudContainer.Filters; -//using TagsCloudContainer.Layouters; -//using TagsCloudContainer.Parsers; -//using TagsCloudContainer.Visualizers; -//using TagsCloudContainer.WordSizer; - -//namespace TagsCloudContainer; -//public static class Program -//{ -// public static void Main() -// { -// } -// public static void Main(Config config) -// { -// var builder = new ContainerBuilder(); -// builder.RegisterInstance(config).As(); -// builder.RegisterType().As(); -// builder.RegisterType().As(); -// builder.RegisterType().As(); -// builder.RegisterType().As(); -// builder.RegisterType().As(); -// builder.RegisterType().As(); -// var container = builder.Build(); - -// var reader = container.Resolve(); -// var parser = container.Resolve(); -// var sizer = container.Resolve(); -// var layouter = container.Resolve(); -// var visualizer = container.Resolve(); - -// visualizer.GenerateImage( -// layouter.GetLayout( -// sizer.GetSizes( -// parser.Parse( -// reader.Read( -// config.InputDirectory -// ) -// ) -// ) -// ) -// ); -// } -//} - - public class ApplicationRunner : IApplicationRunner { From 5ee9f7642a6c4e9f1f1f3c56a37cdd663d943b17 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 21:21:25 +0500 Subject: [PATCH 17/20] Fix small problems --- ConsoleClient/ConsoleClient.cs | 7 +------ TagsCloudContainer/Config.cs | 4 +--- TagsCloudContainer/IApplicationRunner.cs | 8 +------- TagsCloudContainer/Program.cs | 8 +------- 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 9d3117da..06267d5f 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -1,9 +1,4 @@ -//using Autofac; -//using McMaster.Extensions.CommandLineUtils; -//using TagsCloudContainer; -//using TagsCloudContainer.FileReaders; -//using TagsCloudContainer.Filters; -using McMaster.Extensions.CommandLineUtils; +using McMaster.Extensions.CommandLineUtils; using Autofac; using TagsCloudContainer; diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index 40c5ddf5..c83f7217 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -1,6 +1,4 @@ -using Spire.Doc.Documents; - -namespace TagsCloudContainer; +namespace TagsCloudContainer; public class Config { diff --git a/TagsCloudContainer/IApplicationRunner.cs b/TagsCloudContainer/IApplicationRunner.cs index cc76cdd0..c0cf0dfe 100644 --- a/TagsCloudContainer/IApplicationRunner.cs +++ b/TagsCloudContainer/IApplicationRunner.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudContainer +namespace TagsCloudContainer { public interface IApplicationRunner { diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 2bcc4458..81d67a20 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudContainer; +namespace TagsCloudContainer; public static class Program { public static void Main() From 21bd13bcdff93c15108192eb6b3c1721790c07f9 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 22:05:29 +0500 Subject: [PATCH 18/20] Add Validation for config and mark CloudContainer as library --- ConsoleClient/ConsoleClient.cs | 15 ++++--- TagCloudContainerTests/ConsoleTests.cs | 44 +++++++++++++++++++ .../TagCloudContainerTests.csproj | 1 + TagsCloudContainer/Config.cs | 42 +++++++++++++++++- TagsCloudContainer/TagsCloudContainer.csproj | 2 +- 5 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 TagCloudContainerTests/ConsoleTests.cs diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 06267d5f..0059fb42 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -51,14 +51,15 @@ private void OnExecute() ColorsInput?.Split(',') ?? Constants.PictureColors ); - var container = ApplicationRunner.BuildContainer(config); - - using var scope = container.BeginLifetimeScope(); - var runner = scope.Resolve(); - runner.Run(); + if (Config.TryValidateConfig(config)) + { + var container = ApplicationRunner.BuildContainer(config); + + using var scope = container.BeginLifetimeScope(); + var runner = scope.Resolve(); + runner.Run(); + } } - - } diff --git a/TagCloudContainerTests/ConsoleTests.cs b/TagCloudContainerTests/ConsoleTests.cs new file mode 100644 index 00000000..ffb42dad --- /dev/null +++ b/TagCloudContainerTests/ConsoleTests.cs @@ -0,0 +1,44 @@ +using TagsCloudContainer; +using TagsCloudContainer.Filters; +using TagsCloudContainer.Parsers; + +namespace TagCloudContainerTests +{ + [TestFixture] + class ConsoleTests + { + + [SetUp] + public void Setup() + { + } + + [Test] + public void ConsoleClient_CorrectCommandsRead() + { + var input = "--input \"file\""; + var output = "--output \"outfile\""; + var width = "--width 1000"; + var height = "--height 900"; + var font = "--font \"Arial\""; + var stopwords = "--stopwords car,lemon,granade"; + var rightwords = "--rightwords tomato,king"; + var colors = "--colors 150,150,150,0"; + + var args = new List { }; + args.Add(String + .Join(" ", + input, + output, + width, + height, + font, + stopwords, + rightwords, + colors) + ); + + ConsoleClient.Main(args.ToArray()); + } + } +} diff --git a/TagCloudContainerTests/TagCloudContainerTests.csproj b/TagCloudContainerTests/TagCloudContainerTests.csproj index b3eef997..5734929d 100644 --- a/TagCloudContainerTests/TagCloudContainerTests.csproj +++ b/TagCloudContainerTests/TagCloudContainerTests.csproj @@ -23,6 +23,7 @@ + diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index c83f7217..be0993de 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -1,4 +1,9 @@ -namespace TagsCloudContainer; +using Org.BouncyCastle.Asn1.Esf; +using System.Drawing; +using System.Drawing.Text; +using System.IO; + +namespace TagsCloudContainer; public class Config { @@ -42,4 +47,39 @@ public Config() RightWords = Constants.RightWords; PictureColors = Constants.PictureColors; } + + public static bool TryValidateConfig(Config config) + { + if (!Path.Exists(config.InputDirectory)) + throw new FileNotFoundException("File not found.", config.InputDirectory); + + if (!Path.Exists(config.OutputDirectory)) + throw new FileNotFoundException("File not found.", config.OutputDirectory); + + if (config.PictureWidth <= 0 || config.PictureWidth > 3000) + throw new ArgumentException("Picture Width shoud be more than zero and less than 3000", config.OutputDirectory); + + if (config.PictureHeight <= 0 || config.PictureHeight > 3000) + throw new ArgumentException("Picture Height shoud be more than zero and less than 3000", config.OutputDirectory); + + if (!IsFontAvailable(config.Font)) + throw new ArgumentException("Font doesn't exist in system", config.Font); + + return true; + } + + private static bool IsFontAvailable(string fontName) + { + try + { + using (var font = new Font(fontName, 12)) + { + return font.Name.Equals(fontName, StringComparison.InvariantCultureIgnoreCase); + } + } + catch + { + return false; + } + } } diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 47796e12..c50e50be 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -1,7 +1,7 @@  - Exe + Library net8.0-windows enable enable From ea1627e204666a5c9be04c9409194e1daaab3a92 Mon Sep 17 00:00:00 2001 From: Emi1337-ops Date: Thu, 26 Dec 2024 23:23:21 +0500 Subject: [PATCH 19/20] Logic and Tests refactor --- TagCloudContainerTests/ConsoleTests.cs | 40 +++++++++++----------- TagCloudContainerTests/FilterTests.cs | 7 ++++ TagCloudContainerTests/GeneralTests.cs | 26 ++++++++++++++ TagCloudContainerTests/SizerTests.cs | 6 ++-- TagsCloudContainer/Config.cs | 2 +- TagsCloudContainer/Constants.cs | 8 +++-- TagsCloudContainer/Files/General.txt | 35 +++++++++++++++++++ TagsCloudContainer/Files/itWords.txt | 26 ++++++++++++++ TagsCloudContainer/Filters/WordsFilter.cs | 3 +- TagsCloudContainer/Pictures/picture.jpg | Bin 0 -> 33039 bytes TagsCloudContainer/Pictures/picture1.jpg | Bin 0 -> 22129 bytes TagsCloudContainer/Pictures/picture2.jpg | Bin 0 -> 34284 bytes 12 files changed, 127 insertions(+), 26 deletions(-) create mode 100644 TagCloudContainerTests/GeneralTests.cs create mode 100644 TagsCloudContainer/Files/General.txt create mode 100644 TagsCloudContainer/Files/itWords.txt create mode 100644 TagsCloudContainer/Pictures/picture.jpg create mode 100644 TagsCloudContainer/Pictures/picture1.jpg create mode 100644 TagsCloudContainer/Pictures/picture2.jpg diff --git a/TagCloudContainerTests/ConsoleTests.cs b/TagCloudContainerTests/ConsoleTests.cs index ffb42dad..e1186e14 100644 --- a/TagCloudContainerTests/ConsoleTests.cs +++ b/TagCloudContainerTests/ConsoleTests.cs @@ -16,28 +16,28 @@ public void Setup() [Test] public void ConsoleClient_CorrectCommandsRead() { - var input = "--input \"file\""; - var output = "--output \"outfile\""; - var width = "--width 1000"; - var height = "--height 900"; - var font = "--font \"Arial\""; - var stopwords = "--stopwords car,lemon,granade"; - var rightwords = "--rightwords tomato,king"; - var colors = "--colors 150,150,150,0"; + var input = "--input file "; + var output = "--output outfile "; + var width = "--width 1000 "; + var height = "--height 900 "; + var font = "--font Arial "; + var stopwords = "--stopwords car,lemon,granade "; + var rightwords = "--rightwords tomato,king "; + var colors = "--colors 150,150,150,0 "; - var args = new List { }; - args.Add(String - .Join(" ", - input, - output, - width, - height, - font, - stopwords, - rightwords, - colors) - ); + var args = new string[] + { + input, + output, + width, + height, + font, + stopwords, + rightwords, + colors + }; + ConsoleClient.Main(args.ToArray()); } } diff --git a/TagCloudContainerTests/FilterTests.cs b/TagCloudContainerTests/FilterTests.cs index 75fb65f4..f8e6f011 100644 --- a/TagCloudContainerTests/FilterTests.cs +++ b/TagCloudContainerTests/FilterTests.cs @@ -75,6 +75,8 @@ public void Filter_RemoveRightWord_FromMethod(string stopWord) { var filter = new WordsFilter(config); + filter.Contains(stopWord).Should().BeTrue(); + filter.RemoveRightWord(stopWord); filter.Contains(stopWord).Should().BeFalse(); @@ -86,6 +88,11 @@ public void Filter_RemoveRightWords_FromMethod() var filter = new WordsFilter(config); var rightWord = new string[] { "он", "она", "они", "оно" }; + foreach (var word in rightWord) + { + filter.Contains(word).Should().BeTrue(); + } + filter.RemoveRightWords(rightWord); foreach (var word in rightWord) diff --git a/TagCloudContainerTests/GeneralTests.cs b/TagCloudContainerTests/GeneralTests.cs new file mode 100644 index 00000000..2f8e822f --- /dev/null +++ b/TagCloudContainerTests/GeneralTests.cs @@ -0,0 +1,26 @@ +using TagsCloudContainer; +using TagsCloudContainer.FileReaders; + +namespace TagCloudContainerTests +{ + [TestFixture] + public class GeneralTests + { + private Config config; + + [SetUp] + public void Setup() + { + config = new Config(); + config.InputDirectory = @"C:\Users\dima0\source\repos\di-updated\TagsCloudContainer\Files\General.txt"; + config.OutputDirectory = @"C:\Users\dima0\source\repos\di-updated\TagsCloudContainer\Pictures\general.jpg"; + config.PictureWidth = 600; + config.PictureHeight = 700; + config.StopWords = ["отпуск", "птица", "любовь"]; + config.RightWords = ["я"]; + } + + + + } +} diff --git a/TagCloudContainerTests/SizerTests.cs b/TagCloudContainerTests/SizerTests.cs index 904a4216..d24db0c7 100644 --- a/TagCloudContainerTests/SizerTests.cs +++ b/TagCloudContainerTests/SizerTests.cs @@ -34,8 +34,10 @@ public void Sizer_ReturnSizeForAllWords() var sized = sizer.GetSizes(defaultDictionary); - sized.Count().Should().Be(defaultDictionary.Keys.Count); - sized.All(x => defaultDictionary.ContainsKey(x.Value)).Should().BeTrue(); + sized + .Select(x => x.Value) + .Should() + .BeEquivalentTo(defaultDictionary.Keys); } [Test] diff --git a/TagsCloudContainer/Config.cs b/TagsCloudContainer/Config.cs index be0993de..33333e64 100644 --- a/TagsCloudContainer/Config.cs +++ b/TagsCloudContainer/Config.cs @@ -53,7 +53,7 @@ public static bool TryValidateConfig(Config config) if (!Path.Exists(config.InputDirectory)) throw new FileNotFoundException("File not found.", config.InputDirectory); - if (!Path.Exists(config.OutputDirectory)) + if (!Path.Exists(Path.Combine(config.OutputDirectory, @"..\"))) throw new FileNotFoundException("File not found.", config.OutputDirectory); if (config.PictureWidth <= 0 || config.PictureWidth > 3000) diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index a99265ff..26e25169 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -4,10 +4,10 @@ namespace TagsCloudContainer; public static partial class Constants { public static string InputDirectory - => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Files\\defaultTxt1.txt"); + => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Files\\defaultTxt.txt"); public static string OutputDirectory - => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Pictures\\picture.jpg"); + => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Pictures\\picture4.jpg"); public static string FilterWordsDirectory => Path.Combine(ProjectDirectory, "TagsCloudContainer\\Files\\filterwords.txt"); @@ -30,4 +30,8 @@ public static string ProjectDirectory public readonly static Regex WordsSplitRegex = new( pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", options: RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public readonly static Regex OnlyLettersRegex = new( + pattern: @"^[a-zA-Z]+$", + options: RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/TagsCloudContainer/Files/General.txt b/TagsCloudContainer/Files/General.txt new file mode 100644 index 00000000..93cd09c6 --- /dev/null +++ b/TagsCloudContainer/Files/General.txt @@ -0,0 +1,35 @@ +солнце +дом +дом +работа +работа +работа +улица +человек +человек +человек +птица +мир +река +река +река +любовь +еда +город +город +город +путешествие +машина +книга +отпуск +собака +собака +дерево +дерево +дерево +семья +друзья +погода +время +время +время \ No newline at end of file diff --git a/TagsCloudContainer/Files/itWords.txt b/TagsCloudContainer/Files/itWords.txt new file mode 100644 index 00000000..562442c2 --- /dev/null +++ b/TagsCloudContainer/Files/itWords.txt @@ -0,0 +1,26 @@ +разработчик +разработчик +разработчик +разработчик +разработчик +разработчик +разработчик +алгоритм +алгоритм +алгоритм +алгоритм +алгоритм +алгоритм +программирование +программирование +программирование +программирование +данные +данные +данные +данные +данные +код +код +код +анализ diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index be441ee2..382c2df3 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -30,7 +30,8 @@ public bool Contains(string word) public void AddStopWord(string word) { - words.Add(word); + if (Constants.OnlyLettersRegex.IsMatch(word)) + words.Add(word); } public void RemoveRightWord(string word) diff --git a/TagsCloudContainer/Pictures/picture.jpg b/TagsCloudContainer/Pictures/picture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b6fb77436f1c88a80c99549c69c688acf0a5a0d2 GIT binary patch literal 33039 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 U;BO85t%1Ka@SoHG)t{0717iGGY5)KL literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/Pictures/picture1.jpg b/TagsCloudContainer/Pictures/picture1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b275096cbdead4b1e08794d6ea3cf5f949368b67 GIT binary patch literal 22129 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 literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/Pictures/picture2.jpg b/TagsCloudContainer/Pictures/picture2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..08e7d7aecb7441c70775f80571e30471f2675f75 GIT binary patch literal 34284 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 Date: Thu, 26 Dec 2024 23:55:16 +0500 Subject: [PATCH 20/20] Add General test and refactor some logic --- TagCloudContainerTests/ConsoleTests.cs | 44 ----------------- TagCloudContainerTests/GeneralTests.cs | 46 +++++++++++++++++- TagsCloudContainer/Constants.cs | 4 -- TagsCloudContainer/Files/General.txt | 6 ++- TagsCloudContainer/Filters/WordsFilter.cs | 2 +- TagsCloudContainer/Pictures/general.jpg | Bin 0 -> 16515 bytes .../Visualizers/ImageVisualizer.cs | 2 +- 7 files changed, 51 insertions(+), 53 deletions(-) delete mode 100644 TagCloudContainerTests/ConsoleTests.cs create mode 100644 TagsCloudContainer/Pictures/general.jpg diff --git a/TagCloudContainerTests/ConsoleTests.cs b/TagCloudContainerTests/ConsoleTests.cs deleted file mode 100644 index e1186e14..00000000 --- a/TagCloudContainerTests/ConsoleTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -using TagsCloudContainer; -using TagsCloudContainer.Filters; -using TagsCloudContainer.Parsers; - -namespace TagCloudContainerTests -{ - [TestFixture] - class ConsoleTests - { - - [SetUp] - public void Setup() - { - } - - [Test] - public void ConsoleClient_CorrectCommandsRead() - { - var input = "--input file "; - var output = "--output outfile "; - var width = "--width 1000 "; - var height = "--height 900 "; - var font = "--font Arial "; - var stopwords = "--stopwords car,lemon,granade "; - var rightwords = "--rightwords tomato,king "; - var colors = "--colors 150,150,150,0 "; - - var args = new string[] - { - input, - output, - width, - height, - font, - stopwords, - rightwords, - colors - }; - - - ConsoleClient.Main(args.ToArray()); - } - } -} diff --git a/TagCloudContainerTests/GeneralTests.cs b/TagCloudContainerTests/GeneralTests.cs index 2f8e822f..6f0ee2d3 100644 --- a/TagCloudContainerTests/GeneralTests.cs +++ b/TagCloudContainerTests/GeneralTests.cs @@ -1,5 +1,13 @@ -using TagsCloudContainer; +using FluentAssertions; +using System.Drawing; +using TagsCloudContainer; using TagsCloudContainer.FileReaders; +using TagsCloudContainer.Filters; +using TagsCloudContainer.Layouters; +using TagsCloudContainer.Parsers; +using TagsCloudContainer.Visualizers; +using TagsCloudContainer.WordClasses; +using TagsCloudContainer.WordSizer; namespace TagCloudContainerTests { @@ -7,6 +15,8 @@ namespace TagCloudContainerTests public class GeneralTests { private Config config; + private string[] stopWords; + [SetUp] public void Setup() @@ -16,11 +26,43 @@ public void Setup() config.OutputDirectory = @"C:\Users\dima0\source\repos\di-updated\TagsCloudContainer\Pictures\general.jpg"; config.PictureWidth = 600; config.PictureHeight = 700; + config.Font = "Impact"; config.StopWords = ["отпуск", "птица", "любовь"]; config.RightWords = ["я"]; + + stopWords = config.StopWords; } + [Test] + public void CircularCloudContainer_GeneralTest() + { + var reader = new TxtFileReader(); + var filter = new WordsFilter(config); + var parser = new SimpleParser(filter); + var sizer = new SimpleSizer(config); + var layouter = new CircularCloudLayouter(config); + var visualizer = new ImageVisualizer(config); - + var words = reader.Read(config.InputDirectory); + var filteredWords = parser.Parse(words); + var wordSizes = sizer.GetSizes(filteredWords); + var layout = layouter.GetLayout(wordSizes); + visualizer.GenerateImage(layout); + + stopWords.All(x => filter.Contains(x)).Should().BeTrue(); + filter.Contains("я").Should().BeFalse(); + + wordSizes.All(x => filter.Contains(x.Value)).Should().BeFalse(); + wordSizes.All(x => x.font.Name == "Impact").Should().BeTrue(); + wordSizes.Any(x => x.Value == "я").Should().BeTrue(); + + layout.All(x => filter.Contains(x.Value)).Should().BeFalse(); + layout.All(x => x.font.Name == "Impact").Should().BeTrue(); + layout.Any(x => x.Value == "я").Should().BeTrue(); + + using Image image = Image.FromFile(config.OutputDirectory); + image.Width.Should().Be(600); + image.Height.Should().Be(700); + } } } diff --git a/TagsCloudContainer/Constants.cs b/TagsCloudContainer/Constants.cs index 26e25169..8b3d03ca 100644 --- a/TagsCloudContainer/Constants.cs +++ b/TagsCloudContainer/Constants.cs @@ -30,8 +30,4 @@ public static string ProjectDirectory public readonly static Regex WordsSplitRegex = new( pattern: @"\b[а-яА-ЯёЁa-zA-Z]+\b", options: RegexOptions.Compiled | RegexOptions.IgnoreCase); - - public readonly static Regex OnlyLettersRegex = new( - pattern: @"^[a-zA-Z]+$", - options: RegexOptions.Compiled | RegexOptions.IgnoreCase); } diff --git a/TagsCloudContainer/Files/General.txt b/TagsCloudContainer/Files/General.txt index 93cd09c6..a18aaf63 100644 --- a/TagsCloudContainer/Files/General.txt +++ b/TagsCloudContainer/Files/General.txt @@ -32,4 +32,8 @@ погода время время -время \ No newline at end of file +время +я +я +я +я \ No newline at end of file diff --git a/TagsCloudContainer/Filters/WordsFilter.cs b/TagsCloudContainer/Filters/WordsFilter.cs index 382c2df3..6a06e211 100644 --- a/TagsCloudContainer/Filters/WordsFilter.cs +++ b/TagsCloudContainer/Filters/WordsFilter.cs @@ -30,7 +30,7 @@ public bool Contains(string word) public void AddStopWord(string word) { - if (Constants.OnlyLettersRegex.IsMatch(word)) + if (word.All(c => char.IsLetter(c))) words.Add(word); } diff --git a/TagsCloudContainer/Pictures/general.jpg b/TagsCloudContainer/Pictures/general.jpg new file mode 100644 index 0000000000000000000000000000000000000000..120d72cd801b214131381e44333fff9f66a97e65 GIT binary patch literal 16515 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 J14_8*e*$sIERp~K literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/Visualizers/ImageVisualizer.cs b/TagsCloudContainer/Visualizers/ImageVisualizer.cs index 1a799477..61fe5f69 100644 --- a/TagsCloudContainer/Visualizers/ImageVisualizer.cs +++ b/TagsCloudContainer/Visualizers/ImageVisualizer.cs @@ -14,7 +14,7 @@ public ImageVisualizer(Config config) public void GenerateImage(IEnumerable words) { - using var image = new Bitmap(config.PictureWidth, config.PictureWidth); + using var image = new Bitmap(config.PictureWidth, config.PictureHeight); using var g = Graphics.FromImage(image); foreach (var item in words)