From 3b12dd6de6d61806d3af934ba9262ee39ce7d21b Mon Sep 17 00:00:00 2001 From: Zakhar Date: Thu, 14 Nov 2024 01:30:37 +0500 Subject: [PATCH 01/17] =?UTF-8?q?=D0=A7=D0=B5=D1=80=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20?= =?UTF-8?q?=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=BD?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouter.cs | 92 +++++++++++++++++++ .../CircularCloudLayouterPainter.cs | 57 ++++++++++++ .../CircularCloudLayouterTests.cs | 85 +++++++++++++++++ .../CircularCloudLayouterWorker.cs | 29 ++++++ cs/TagsCloudVisualization/Program.cs | 28 ++++++ .../TagsCloudVisualization.csproj | 20 ++++ 6 files changed, 311 insertions(+) create mode 100644 cs/TagsCloudVisualization/CircularCloudLayouter.cs create mode 100644 cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs create mode 100644 cs/TagsCloudVisualization/CircularCloudLayouterTests.cs create mode 100644 cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs create mode 100644 cs/TagsCloudVisualization/Program.cs create mode 100644 cs/TagsCloudVisualization/TagsCloudVisualization.csproj diff --git a/cs/TagsCloudVisualization/CircularCloudLayouter.cs b/cs/TagsCloudVisualization/CircularCloudLayouter.cs new file mode 100644 index 000000000..9269a382d --- /dev/null +++ b/cs/TagsCloudVisualization/CircularCloudLayouter.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal class CircularCloudLayouter + { + public readonly Point Center; + private float _radius = 2.0f; + private Random _random = new Random(); + private readonly List _rectangles = new List(); + public IReadOnlyList Rectangles => _rectangles.AsReadOnly(); + + public CircularCloudLayouter(Point center) + { + if (center.X < 0 || center.Y < 0) + { + throw new ArgumentException("Координаты центра не могут быть меньше нуля."); + } + Center = center; + } + + public Rectangle PutNextRectangle(Size rectangleSize) + { + if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0) + { + throw new ArgumentException("Размеры прямоугольника не могут быть меньше либо равны нуля."); + } + + var result = new Rectangle(); + _radius -= 1.0f; + var isPlaced = false; + while (!isPlaced) + { + var points = GetCoordinatesOnEllipse(Center, _radius); + var pointsStartIndex = _random.Next(points.Length); + + for (int j = 0; j < points.Length; j++) + { + var index = (pointsStartIndex + j) % points.Length; + + int x = points[index].X - rectangleSize.Width / 2; + int y = points[index].Y - rectangleSize.Height / 2; + var location = new Point(x, y); + + var nextRectangle = new Rectangle(location, rectangleSize); + + var isIntersects = false; + foreach (var rect in _rectangles) + { + if (rect.IntersectsWith(nextRectangle)) + { + isIntersects = true; + break; + } + } + + if (!isIntersects) + { + _rectangles.Add(nextRectangle); + isPlaced = true; + result = nextRectangle; + break; + } + } + _radius += 1.0f; + } + return result; + } + + private Point[] GetCoordinatesOnEllipse(Point rectangleCenter, float radius) + { + var result = new Point[360]; + var step = 1; + + for (int angle = 0; angle < 360; angle += step) + { + double angleInRadians = angle * Math.PI / 180; + + var x = (int)(rectangleCenter.X + radius * Math.Cos(angleInRadians)); + var y = (int)(rectangleCenter.Y + radius * Math.Sin(angleInRadians)); + + result[angle] = new Point(x, y); + } + return result; + } + } +} diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs new file mode 100644 index 000000000..428a30e61 --- /dev/null +++ b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal class CircularCloudLayouterPainter + { + private string _fileName; + public CircularCloudLayouterPainter(string fileName) + { + _fileName = fileName; + } + + public void Save(List rectangles, int? paddingPerSide = null) + { + if (rectangles.Count == 0) + { + return; + } + + var correctPaddingPerSide = paddingPerSide ?? 10; + + var minimums = new Point(rectangles.Min(r => r.Left), rectangles.Min(r => r.Top)); + var maximums = new Point(rectangles.Max(r => r.Right), rectangles.Max(r => r.Bottom)); + + var imageSize = GetImageSize(minimums, maximums, correctPaddingPerSide); + using (var bitmap = new Bitmap(imageSize.Width, imageSize.Height)) + { + using (var graphics = Graphics.FromImage(bitmap)) + { + graphics.Clear(Color.White); + using (var pen = new Pen(Color.Black, 1)) + { + for (int i = 0; i < rectangles.Count; i++) + { + var currentRectangle = rectangles[i]; + var positionOnCanvas = GetPositionOnCanvas(currentRectangle, minimums, correctPaddingPerSide); + graphics.DrawRectangle(pen, positionOnCanvas.X, positionOnCanvas.Y, currentRectangle.Width, currentRectangle.Height); + } + } + bitmap.Save(_fileName, System.Drawing.Imaging.ImageFormat.Png); + } + } + Console.WriteLine($"Изображение сохранено как {_fileName}"); + } + + private Point GetPositionOnCanvas(Rectangle rectangle, Point minimums, int padding) + => new Point(rectangle.X - minimums.X + padding, rectangle.Y - minimums.Y + padding); + + private Size GetImageSize(Point minimums, Point maximums, int paddingPerSide) + => new Size(maximums.X - minimums.X + 2 * paddingPerSide, maximums.Y - minimums.Y + 2 * paddingPerSide); + } +} diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs b/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs new file mode 100644 index 000000000..0d8c3a5b1 --- /dev/null +++ b/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs @@ -0,0 +1,85 @@ +using System; +using NUnit.Framework; +using FluentAssertions; +using System.Drawing; + +namespace TagsCloudVisualization +{ + [TestFixture] + internal class CircularCloudLayouterTests + { + private CircularCloudLayouter _circularCloudLayouter; + private CircularCloudLayouterWorker _circularCloudLayouterWorker; + private CircularCloudLayouterPainter _circularCloudLayouterPainter; + + public void SetUp(int x = 400, + int y = 400, + int minRectangleWidth = 30, + int minRectangleHeight = 20, + int maxRectangleWidth = 70, + int maxRectangleHeight = 50, + string imageFileName = "circularCloudLayouter.png") + { + var center = new Point(x, y); + var minRectangleSize = new Size(minRectangleWidth, minRectangleHeight); + var maxRectangleSize = new Size(maxRectangleWidth, maxRectangleHeight); + + _circularCloudLayouter = new CircularCloudLayouter(center); + _circularCloudLayouterWorker = new CircularCloudLayouterWorker(minRectangleSize, maxRectangleSize); + _circularCloudLayouterPainter = new CircularCloudLayouterPainter(imageFileName); + } + + [TestCase(-1, 0)] + [TestCase(0, -1)] + [TestCase(-1, -1)] + public void CircularCloudLayouter_ThrowsArgumentException_OnNegativeCenterPoint(int x, int y) + { + var center = new Point(x, y); + Assert.Throws(() => new CircularCloudLayouter(center)); + } + + + [TestCase(0, 100, 1)] + [TestCase(-1, 100, 1)] + [TestCase(100, 0, 1)] + [TestCase(100, -1, 1)] + + public void PutNextRectangle_ThrowsArgumentException_OnAnyNegativeOrZeroSize(int width, int height, int rectanglesCount) + { + SetUp(); + for (int i = 0; i < rectanglesCount; i++) + { + var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); + Assert.Throws(() => _circularCloudLayouter.PutNextRectangle(new Size(width, height))); + } + } + + [TestCase(1)] + public void PutNextRectangle_ReturnsRectangleType(int rectanglesCount) + { + SetUp(); + for (int i = 0; i < rectanglesCount; i++) + { + var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); + Assert.That(_circularCloudLayouter.PutNextRectangle(nextRectangleSize), Is.TypeOf(typeof(Rectangle))); + } + } + + [TestCase(1, "TestFile.png", ExpectedResult = true)] + [TestCase(0, "TestFile.png", ExpectedResult = false)] + public bool CircularCloudLayouterPainter_CreatesFile(int rectanglesCount, string fileName) + { + SetUp(imageFileName: fileName); + File.Delete(fileName); + + for (int i = 0; i < rectanglesCount; i++) + { + var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); + _circularCloudLayouter.PutNextRectangle(nextRectangleSize); + } + + _circularCloudLayouterPainter.Save(_circularCloudLayouter.Rectangles.ToList()); + return File.Exists(fileName); + } + } +} diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs new file mode 100644 index 000000000..8aa07d150 --- /dev/null +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal class CircularCloudLayouterWorker + { + private Size _minRectangleSize; + private Size _maxRectangleSize; + private Random _random = new Random(); + + public CircularCloudLayouterWorker(Size minRectangleSize, Size maxRectangleSize) + { + _minRectangleSize = minRectangleSize; + _maxRectangleSize = maxRectangleSize; + } + + public Size GetNextRectangleSize() + { + var width = _random.Next(_minRectangleSize.Width, _maxRectangleSize.Width); + var height = _random.Next(_minRectangleSize.Height, _maxRectangleSize.Height); + return new Size(width, height); + } + } +} diff --git a/cs/TagsCloudVisualization/Program.cs b/cs/TagsCloudVisualization/Program.cs new file mode 100644 index 000000000..b47045808 --- /dev/null +++ b/cs/TagsCloudVisualization/Program.cs @@ -0,0 +1,28 @@ +using System.Drawing; + +namespace TagsCloudVisualization +{ + internal class Program + { + static void Main(string[] args) + { + var center = new Point(400, 400); + var minRectangleSize = new Size(30, 20); + var maxRectangleSize = new Size(70, 50); + var rectanglesCount = 100; + var imageFileName = "circularCloudLayouter.png"; + + var circularCloudLayouter = new CircularCloudLayouter(center); + var circularCloudLayouterWorker = new CircularCloudLayouterWorker(minRectangleSize, maxRectangleSize); + var circularCloudLayouterPainter = new CircularCloudLayouterPainter(imageFileName); + + for (int i = 0; i < rectanglesCount; i++) + { + var nextRectangleSize = circularCloudLayouterWorker.GetNextRectangleSize(); + circularCloudLayouter.PutNextRectangle(nextRectangleSize); + } + + circularCloudLayouterPainter.Save(circularCloudLayouter.Rectangles.ToList()); + } + } +} diff --git a/cs/TagsCloudVisualization/TagsCloudVisualization.csproj b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj new file mode 100644 index 000000000..465af9204 --- /dev/null +++ b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj @@ -0,0 +1,20 @@ + + + + TagsCloudVisualization.Program + Exe + net8.0 + enable + enable + + + + + + + + + + + + From cf3d9930991c6a113aae6b75fa2afec3b16ace38 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 15:07:54 +0500 Subject: [PATCH 02/17] =?UTF-8?q?TagsCloudVisualization.csproj=20=D1=8F?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B2=20tdd.sln.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/tdd.sln | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/cs/tdd.sln b/cs/tdd.sln index c8f523d63..996b53a71 100644 --- a/cs/tdd.sln +++ b/cs/tdd.sln @@ -1,11 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BowlingGame", "BowlingGame\BowlingGame.csproj", "{AD0F018A-732E-4074-8527-AB2EEC8D0BF3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BowlingGame", "BowlingGame\BowlingGame.csproj", "{C85E7A84-31BB-4BF0-9FE3-7BA9849DA0D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{B5108E20-2ACF-4ED9-84FE-2A718050FC94}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples", "Samples\Samples.csproj", "{659717CA-38A3-4CE2-BB32-18142E4C5373}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudVisualization", "TagsCloudVisualization\TagsCloudVisualization.csproj", "{1E0AAECB-7355-4B9F-95FB-11961EE556E7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,16 +15,23 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AD0F018A-732E-4074-8527-AB2EEC8D0BF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD0F018A-732E-4074-8527-AB2EEC8D0BF3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD0F018A-732E-4074-8527-AB2EEC8D0BF3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD0F018A-732E-4074-8527-AB2EEC8D0BF3}.Release|Any CPU.Build.0 = Release|Any CPU - {B5108E20-2ACF-4ED9-84FE-2A718050FC94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5108E20-2ACF-4ED9-84FE-2A718050FC94}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5108E20-2ACF-4ED9-84FE-2A718050FC94}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5108E20-2ACF-4ED9-84FE-2A718050FC94}.Release|Any CPU.Build.0 = Release|Any CPU + {C85E7A84-31BB-4BF0-9FE3-7BA9849DA0D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C85E7A84-31BB-4BF0-9FE3-7BA9849DA0D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C85E7A84-31BB-4BF0-9FE3-7BA9849DA0D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C85E7A84-31BB-4BF0-9FE3-7BA9849DA0D5}.Release|Any CPU.Build.0 = Release|Any CPU + {659717CA-38A3-4CE2-BB32-18142E4C5373}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {659717CA-38A3-4CE2-BB32-18142E4C5373}.Debug|Any CPU.Build.0 = Debug|Any CPU + {659717CA-38A3-4CE2-BB32-18142E4C5373}.Release|Any CPU.ActiveCfg = Release|Any CPU + {659717CA-38A3-4CE2-BB32-18142E4C5373}.Release|Any CPU.Build.0 = Release|Any CPU + {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EBCD5248-163A-4DB3-9D95-B245CFD2D6FD} + EndGlobalSection EndGlobal From 0fddb270f8b3f4c3ac8b9ca01963477a2410c58a Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 15:09:59 +0500 Subject: [PATCH 03/17] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=20Circular?= =?UTF-8?q?CloudLayouterWorker=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D1=8F=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D0=B8=D1=87=D0=BD=D1=8B=D0=BC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Класс CircularCloudLayouterWorker был переписан как статичный для избежания создания экземпляра класса. --- .../CircularCloudLayouterWorker.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs index 8aa07d150..5a6d290f3 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -7,22 +7,14 @@ namespace TagsCloudVisualization { - internal class CircularCloudLayouterWorker + internal static class CircularCloudLayouterWorker { - private Size _minRectangleSize; - private Size _maxRectangleSize; - private Random _random = new Random(); + private static Random _random = new Random(); - public CircularCloudLayouterWorker(Size minRectangleSize, Size maxRectangleSize) + public static Size GetNextRectangleSize(Size minRectangleSize, Size maxRectangleSize) { - _minRectangleSize = minRectangleSize; - _maxRectangleSize = maxRectangleSize; - } - - public Size GetNextRectangleSize() - { - var width = _random.Next(_minRectangleSize.Width, _maxRectangleSize.Width); - var height = _random.Next(_minRectangleSize.Height, _maxRectangleSize.Height); + var width = _random.Next(minRectangleSize.Width, maxRectangleSize.Width); + var height = _random.Next(minRectangleSize.Height, maxRectangleSize.Height); return new Size(width, height); } } From 335b4b0335db8113f1d34d2d6cb39c25ac3dca6a Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 17:04:57 +0500 Subject: [PATCH 04/17] =?UTF-8?q?=D0=9C=D0=B5=D1=82=D0=BE=D0=B4=20Save=20?= =?UTF-8?q?=D1=83=20CircularCloudLayouterPainter=20=D1=82=D0=B5=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D1=8C=20=D0=BF=D1=80=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20IList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs index 428a30e61..b4a912f1a 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs @@ -15,7 +15,7 @@ public CircularCloudLayouterPainter(string fileName) _fileName = fileName; } - public void Save(List rectangles, int? paddingPerSide = null) + public void Save(IList rectangles, int? paddingPerSide = null) { if (rectangles.Count == 0) { From cddc6c828cb0671318eb12a7aceeb96b776a246d Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 17:06:31 +0500 Subject: [PATCH 05/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9?= =?UTF-8?q?=D1=81=20ICircularCloudLayouter.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Добавлен интерфейс ICircularCloudLayouter. 2. Класс CircularCloudLayouter теперь реализует интерфейс ICircularCloudLayouter. --- cs/TagsCloudVisualization/CircularCloudLayouter.cs | 14 ++------------ .../ICircularCloudLayouter.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 cs/TagsCloudVisualization/ICircularCloudLayouter.cs diff --git a/cs/TagsCloudVisualization/CircularCloudLayouter.cs b/cs/TagsCloudVisualization/CircularCloudLayouter.cs index 9269a382d..13f7075f4 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouter.cs @@ -7,22 +7,12 @@ namespace TagsCloudVisualization { - internal class CircularCloudLayouter + internal class CircularCloudLayouter(Point center) : ICircularCloudLayouter { - public readonly Point Center; + public readonly Point Center = center; private float _radius = 2.0f; private Random _random = new Random(); private readonly List _rectangles = new List(); - public IReadOnlyList Rectangles => _rectangles.AsReadOnly(); - - public CircularCloudLayouter(Point center) - { - if (center.X < 0 || center.Y < 0) - { - throw new ArgumentException("Координаты центра не могут быть меньше нуля."); - } - Center = center; - } public Rectangle PutNextRectangle(Size rectangleSize) { diff --git a/cs/TagsCloudVisualization/ICircularCloudLayouter.cs b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs new file mode 100644 index 000000000..df7edab5c --- /dev/null +++ b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal interface ICircularCloudLayouter + { + Rectangle PutNextRectangle(Size rectangleSize); + } +} From f2c3a048e93d073e17d2f469e475cc63c6fb6d39 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 17:53:48 +0500 Subject: [PATCH 06/17] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81?= =?UTF-8?q?=D0=B0=20CircularCloudLayouter.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Рефакторинг класса CircularCloudLayouter. 2. Выделение сущности Circle, отвечающей за полчение координат на окружности. --- cs/TagsCloudVisualization/Circle.cs | 30 ++++++++++ .../CircularCloudLayouter.cs | 60 +++++++------------ 2 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 cs/TagsCloudVisualization/Circle.cs diff --git a/cs/TagsCloudVisualization/Circle.cs b/cs/TagsCloudVisualization/Circle.cs new file mode 100644 index 000000000..b47cccd5b --- /dev/null +++ b/cs/TagsCloudVisualization/Circle.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal class Circle(Point center, float startRadius = 2.0f) + { + private Point _center = center; + public float Radius { get; set; } = startRadius; + + public IEnumerable GetCoordinatesOnCircle( + int startAngle, + int step = 1) + { + for (int dAngle = 0; dAngle < 360; dAngle += step) + { + var angle = (startAngle + dAngle) % 360; + + double angleInRadians = angle * Math.PI / 180; + var x = (int)(_center.X + Radius * Math.Cos(angleInRadians)); + var y = (int)(_center.Y + Radius * Math.Sin(angleInRadians)); + yield return new Point(x, y); + } + } + } +} diff --git a/cs/TagsCloudVisualization/CircularCloudLayouter.cs b/cs/TagsCloudVisualization/CircularCloudLayouter.cs index 13f7075f4..074d7eb00 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouter.cs @@ -9,8 +9,7 @@ namespace TagsCloudVisualization { internal class CircularCloudLayouter(Point center) : ICircularCloudLayouter { - public readonly Point Center = center; - private float _radius = 2.0f; + private Circle _arrangementСircle = new Circle(center); private Random _random = new Random(); private readonly List _rectangles = new List(); @@ -22,34 +21,17 @@ public Rectangle PutNextRectangle(Size rectangleSize) } var result = new Rectangle(); - _radius -= 1.0f; + _arrangementСircle.Radius -= 1.0f; + var isPlaced = false; while (!isPlaced) { - var points = GetCoordinatesOnEllipse(Center, _radius); - var pointsStartIndex = _random.Next(points.Length); - - for (int j = 0; j < points.Length; j++) + var startAngle = _random.Next(360); + foreach (var coordinate in _arrangementСircle.GetCoordinatesOnCircle(startAngle)) { - var index = (pointsStartIndex + j) % points.Length; - - int x = points[index].X - rectangleSize.Width / 2; - int y = points[index].Y - rectangleSize.Height / 2; - var location = new Point(x, y); - + var location = GetRectangleLocation(coordinate, rectangleSize); var nextRectangle = new Rectangle(location, rectangleSize); - - var isIntersects = false; - foreach (var rect in _rectangles) - { - if (rect.IntersectsWith(nextRectangle)) - { - isIntersects = true; - break; - } - } - - if (!isIntersects) + if (!IsIntersectionWithAlreadyPlaced(nextRectangle)) { _rectangles.Add(nextRectangle); isPlaced = true; @@ -57,26 +39,28 @@ public Rectangle PutNextRectangle(Size rectangleSize) break; } } - _radius += 1.0f; + _arrangementСircle.Radius += 1.0f; } return result; } - private Point[] GetCoordinatesOnEllipse(Point rectangleCenter, float radius) + private bool IsIntersectionWithAlreadyPlaced(Rectangle rectangle) { - var result = new Point[360]; - var step = 1; - - for (int angle = 0; angle < 360; angle += step) + foreach (var rect in _rectangles) { - double angleInRadians = angle * Math.PI / 180; - - var x = (int)(rectangleCenter.X + radius * Math.Cos(angleInRadians)); - var y = (int)(rectangleCenter.Y + radius * Math.Sin(angleInRadians)); - - result[angle] = new Point(x, y); + if (rect.IntersectsWith(rectangle)) + { + return true; + } } - return result; + return false; + } + + private Point GetRectangleLocation(Point pointOnCircle, Size rectangleSize) + { + var x = pointOnCircle.X - rectangleSize.Width / 2; + var y = pointOnCircle.Y - rectangleSize.Height / 2; + return new Point(x, y); } } } From 29a85eeebee24f88b0f71f4cc5ab6e48c3c72be5 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 18:28:54 +0500 Subject: [PATCH 07/17] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BF=D1=80=D1=8F=D0=BC=D0=BE=D1=83=D0=B3=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=B8=20=D1=81=D0=BE?= =?UTF-8?q?=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouterPainter.cs | 50 +++++++++---------- cs/TagsCloudVisualization/ImageSaver.cs | 27 ++++++++++ 2 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 cs/TagsCloudVisualization/ImageSaver.cs diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs index b4a912f1a..53f3edbc5 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs @@ -7,19 +7,13 @@ namespace TagsCloudVisualization { - internal class CircularCloudLayouterPainter + internal static class CircularCloudLayouterPainter { - private string _fileName; - public CircularCloudLayouterPainter(string fileName) - { - _fileName = fileName; - } - - public void Save(IList rectangles, int? paddingPerSide = null) + public static Bitmap Draw(IList rectangles, int? paddingPerSide = null) { if (rectangles.Count == 0) { - return; + throw new ArgumentException("Список прямоугольников пуст."); } var correctPaddingPerSide = paddingPerSide ?? 10; @@ -28,30 +22,32 @@ public void Save(IList rectangles, int? paddingPerSide = null) var maximums = new Point(rectangles.Max(r => r.Right), rectangles.Max(r => r.Bottom)); var imageSize = GetImageSize(minimums, maximums, correctPaddingPerSide); - using (var bitmap = new Bitmap(imageSize.Width, imageSize.Height)) + var result = new Bitmap(imageSize.Width, imageSize.Height); + + using var graphics = Graphics.FromImage(result); + graphics.Clear(Color.White); + using var pen = new Pen(Color.Black, 1); + for (int i = 0; i < rectangles.Count; i++) { - using (var graphics = Graphics.FromImage(bitmap)) - { - graphics.Clear(Color.White); - using (var pen = new Pen(Color.Black, 1)) - { - for (int i = 0; i < rectangles.Count; i++) - { - var currentRectangle = rectangles[i]; - var positionOnCanvas = GetPositionOnCanvas(currentRectangle, minimums, correctPaddingPerSide); - graphics.DrawRectangle(pen, positionOnCanvas.X, positionOnCanvas.Y, currentRectangle.Width, currentRectangle.Height); - } - } - bitmap.Save(_fileName, System.Drawing.Imaging.ImageFormat.Png); - } + var positionOnCanvas = GetPositionOnCanvas( + rectangles[i], + minimums, + correctPaddingPerSide); + graphics.DrawRectangle( + pen, + positionOnCanvas.X, + positionOnCanvas.Y, + rectangles[i].Width, + rectangles[i].Height); } - Console.WriteLine($"Изображение сохранено как {_fileName}"); + + return result; } - private Point GetPositionOnCanvas(Rectangle rectangle, Point minimums, int padding) + private static Point GetPositionOnCanvas(Rectangle rectangle, Point minimums, int padding) => new Point(rectangle.X - minimums.X + padding, rectangle.Y - minimums.Y + padding); - private Size GetImageSize(Point minimums, Point maximums, int paddingPerSide) + private static Size GetImageSize(Point minimums, Point maximums, int paddingPerSide) => new Size(maximums.X - minimums.X + 2 * paddingPerSide, maximums.Y - minimums.Y + 2 * paddingPerSide); } } diff --git a/cs/TagsCloudVisualization/ImageSaver.cs b/cs/TagsCloudVisualization/ImageSaver.cs new file mode 100644 index 000000000..7a97e085d --- /dev/null +++ b/cs/TagsCloudVisualization/ImageSaver.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization +{ + internal static class ImageSaver + { + public static void SaveOnFile(Bitmap image, string fileName) + { + if (image is null) + { + throw new ArgumentNullException("Передаваемое изображение не должно быть null"); + } + + if (string.IsNullOrWhiteSpace(fileName)) + { + throw new ArgumentException("Некорректное имя файла для созранения"); + } + + image.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); + } + } +} From cf7db7341ce892836e0984f92d584f4a1062d256 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 18:33:01 +0500 Subject: [PATCH 08/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=85=D0=BE=D0=B4=D0=BD=D1=8B=D1=85=20=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=83=20CircularCloudLayouter?= =?UTF-8?q?Worker.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouterWorker.cs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs index 5a6d290f3..fe71525ec 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -11,11 +11,48 @@ internal static class CircularCloudLayouterWorker { private static Random _random = new Random(); - public static Size GetNextRectangleSize(Size minRectangleSize, Size maxRectangleSize) + public static Size GetNextRectangleSize( + int minRectangleWidth, + int maxRectangleWidth, + int minRectangleHeight, + int maxRectangleHeight) { - var width = _random.Next(minRectangleSize.Width, maxRectangleSize.Width); - var height = _random.Next(minRectangleSize.Height, maxRectangleSize.Height); + if (!IsMinAndMaxValuesPositive( + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight)) + { + throw new ArgumentException("Ширина и высота прямоугольника не может быть отрицательной либо нулём"); + } + + if (!IsMinAndMaxValuesCorrect( + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight)) + { + throw new ArgumentException("Минимальное значение ширины или высоты не может быть больше максимального"); + } + + var width = _random.Next(minRectangleWidth, maxRectangleWidth); + var height = _random.Next(minRectangleHeight, maxRectangleHeight); return new Size(width, height); } + + private static bool IsMinAndMaxValuesCorrect( + int minRectangleWidth, + int maxRectangleWidth, + int minRectangleHeight, + int maxRectangleHeight) + => minRectangleWidth <= maxRectangleWidth && minRectangleHeight <= maxRectangleHeight; + + private static bool IsMinAndMaxValuesPositive( + int minRectangleWidth, + int maxRectangleWidth, + int minRectangleHeight, + int maxRectangleHeight) + => minRectangleWidth > 0 && maxRectangleWidth > 0 + && minRectangleHeight > 0 && maxRectangleHeight > 0; } } From a675a757c35255fcbe26c8e77eb875d5f854e8f3 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Sun, 17 Nov 2024 23:08:00 +0500 Subject: [PATCH 09/17] =?UTF-8?q?=D0=9E=D0=B1=D1=89=D0=B8=D0=B9=20=D1=80?= =?UTF-8?q?=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Добавление новых тестов. 2. Общий рефакторинг кода. --- ...cularCloudLayouterMainRequirementsTests.cs | 138 ++++++++++++++++++ .../CircularCloudLayouterPainterTests.cs | 38 +++++ .../CircularCloudLayouterTests.cs | 26 ++++ .../CircularCloudLayouterWorkerTests.cs | 35 +++++ .../ImageSaverTest.cs | 58 ++++++++ .../RectangleExtensions.cs | 18 +++ .../TagsCloudVisualization.Tests.csproj | 34 +++++ cs/TagsCloudVisualization/Circle.cs | 2 +- .../CircularCloudLayouter.cs | 5 +- .../CircularCloudLayouterPainter.cs | 8 +- .../CircularCloudLayouterTests.cs | 85 ----------- .../CircularCloudLayouterWorker.cs | 26 ++-- .../ICircularCloudLayouter.cs | 2 +- cs/TagsCloudVisualization/ImageSaver.cs | 6 +- cs/TagsCloudVisualization/Program.cs | 23 +-- .../TagsCloudVisualization.csproj | 2 +- cs/tdd.sln | 6 + 17 files changed, 395 insertions(+), 117 deletions(-) create mode 100644 cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs create mode 100644 cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs create mode 100644 cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs create mode 100644 cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs create mode 100644 cs/TagsCloudVisualization.Tests/ImageSaverTest.cs create mode 100644 cs/TagsCloudVisualization.Tests/RectangleExtensions.cs create mode 100644 cs/TagsCloudVisualization.Tests/TagsCloudVisualization.Tests.csproj delete mode 100644 cs/TagsCloudVisualization/CircularCloudLayouterTests.cs diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs new file mode 100644 index 000000000..3f71c7138 --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs @@ -0,0 +1,138 @@ +using FluentAssertions; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization.Tests +{ + [TestFixture] + internal class CircularCloudLayouterMainRequirementsTests + { + private Point _center; + private Rectangle[] _rectangles; + private string _failedTestsDirectory = "FailedTest"; + + [OneTimeSetUp] + public void Init() + { + Directory.CreateDirectory(_failedTestsDirectory); + } + + [SetUp] + public void SetUp() + { + _center = new Point(400, 400); + var minRectangleWidth = 30; + var maxRectangleWidth = 70; + var minRectangleHeight = 20; + var maxRectangleHeight = 50; + var rectanglesCount = 1000; + + _rectangles = new Rectangle[rectanglesCount]; + var circularCloudLayouter = new CircularCloudLayouter(_center); + for (int i = 0; i < rectanglesCount; i++) + { + var nextRectangleSize = CircularCloudLayouterWorker.GetNextRectangleSize( + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight); + _rectangles[i] = circularCloudLayouter.PutNextRectangle(nextRectangleSize); + } + } + + [TestCase(1.1, ExpectedResult = true)] + [Repeat(10)] + public bool ShouldPlaceRectanglesInCircle(double goodAspectRatio) + { + var boundingBoxSize = GetBoundingBoxSize(); + var actualAspectRatio = + (double)Math.Max(boundingBoxSize.Width, boundingBoxSize.Height) + / Math.Min(boundingBoxSize.Width, boundingBoxSize.Height); + return actualAspectRatio <= goodAspectRatio; + } + + [TestCase(0.1, ExpectedResult = true)] + [Repeat(10)] + public bool ShouldPlaceRectanglesNearCenter(double percentFromBoundingBoxMaxSize) + { + var centerX = _rectangles.Average(r => r.Left + r.Width / 2.0); + var centerY = _rectangles.Average(r => r.Top + r.Height / 2.0); + var actualCenter = new Point((int)centerX, (int)centerY); + + var distance = Math.Sqrt(Math.Pow(actualCenter.X - _center.X, 2) + + Math.Pow(actualCenter.Y - _center.Y, 2)); + + var boundingBoxSize = GetBoundingBoxSize(); + + var maxAllowedDistance = Math.Max(boundingBoxSize.Width, boundingBoxSize.Height) + * percentFromBoundingBoxMaxSize; + + return maxAllowedDistance >= distance; + } + + [Test] + [Repeat(10)] + public void ShouldPlaceRectanglesWithoutOverlap() + { + for (var i = 0; i < _rectangles.Length; i++) + { + for (var j = i + 1; j < _rectangles.Length; j++) + { + Assert.That( + _rectangles[i].IntersectsWith(_rectangles[j]) == false, + $"Прямоугольники пересекаются:\n" + + $"{_rectangles[i].ToFormatedString()}\n" + + $"{_rectangles[j].ToFormatedString()}"); + } + } + } + + + [TestCase(0.55, ExpectedResult = true)] + [Repeat(10)] + public bool ShouldPlaceRectanglesTightly(double tight) + { + var boundingBoxSize = GetBoundingBoxSize(); + var boundingBoxArea = boundingBoxSize.Width * boundingBoxSize.Height; + var filledArea = _rectangles.Sum(r => r.Width * r.Height); + return ((double)filledArea / boundingBoxArea) >= tight; + } + + [TearDown] + public void Cleanup() + { + if (TestContext.CurrentContext.Result.FailCount == 0) + { + return; + } + + var name = $"{TestContext.CurrentContext.Test.Name}.png"; + var path = Path.Combine(_failedTestsDirectory, name); + ImageSaver.SaveFile(CircularCloudLayouterPainter.Draw(_rectangles), path); + Console.WriteLine($"Tag cloud visualization saved to file {path}"); + } + + [OneTimeTearDown] + public void OneTimeCleanup() + { + if (Directory.Exists(_failedTestsDirectory) + && Directory.GetFiles(_failedTestsDirectory).Length == 0) + { + Directory.Delete(_failedTestsDirectory); + } + } + + private Size GetBoundingBoxSize() + { + var minX = _rectangles.Min(r => r.Left); + var minY = _rectangles.Min(r => r.Top); + var maxX = _rectangles.Max(r => r.Right); + var maxY = _rectangles.Max(r => r.Bottom); + return new Size(maxX - minX, maxY - minY); + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs new file mode 100644 index 000000000..e9095d3d5 --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static System.Net.Mime.MediaTypeNames; + +namespace TagsCloudVisualization.Tests +{ + [TestFixture] + internal class CircularCloudLayouterPainterTests + { + private int _defaultPadding = 10; + + [Test] + public void Draw_ThrowsArgumentException_OnEmptyRectangleList() + { + Assert.Throws( + () => CircularCloudLayouterPainter.Draw(new List())); + } + + [TestCase(null, ExpectedResult = true)] + [TestCase(100, ExpectedResult = true)] + public bool Draw_CalculatesImageSizeCorrectly(int? padding) + { + var correctPadding = padding ?? _defaultPadding; + var rectangles = new List() + { + new Rectangle(new Point(0, 0), new Size(10, 10)) + }; + + var image = CircularCloudLayouterPainter.Draw(rectangles, padding); + return image.Height == rectangles[0].Height + 2 * correctPadding + && image.Width == rectangles[0].Width + 2 * correctPadding; + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs new file mode 100644 index 000000000..67b91ace3 --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization.Tests +{ + [TestFixture] + internal class CircularCloudLayouterTests + { + [TestCase(0, 100)] + [TestCase(-1, 100)] + [TestCase(100, 0)] + [TestCase(100, -1)] + public void PutNextRectangle_ThrowsArgumentException_OnAnyNegativeOrZeroSize( + int width, + int height) + { + var size = new Size(width, height); + Assert.Throws( + () => new CircularCloudLayouter(new Point()).PutNextRectangle(size)); + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs new file mode 100644 index 000000000..b3ea2fc2e --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization.Tests +{ + [TestFixture] + internal class CircularCloudLayouterWorkerTests + { + [TestCase(0, 100)] + [TestCase(-1, 100)] + [TestCase(100, 0)] + [TestCase(100, -1)] + public void GetNextRectangleSize_ThrowsArgumentException_OnAnyNegativeOrZeroSize(int width, int height) + { + Assert.Throws( + () => CircularCloudLayouterWorker.GetNextRectangleSize(width, width, height, height)); + } + + [TestCase(50, 25, 25, 50)] + [TestCase(25, 50, 50, 25)] + public void GetNextRectangleSize_ThrowsArgumentException_OnNonConsecutiveSizeValues( + int minWidth, + int maxWidth, + int minHeight, + int maxHeight) + { + Assert.Throws( + () => CircularCloudLayouterWorker.GetNextRectangleSize(minWidth, maxWidth, minHeight, maxHeight)); + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs new file mode 100644 index 000000000..142e62881 --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization.Tests +{ + [TestFixture] + internal class ImageSaverTest + { + private string _directoryPath = "TempFilesForTests"; + + [OneTimeSetUp] + public void Init() + { + Directory.CreateDirectory(_directoryPath); + } + + [TestCase("Test.png")] + public void SaveFile_ArgumentNullException_WithNullBitmap(string filename) + { + var path = Path.Combine(_directoryPath, filename); + Assert.Throws(() => ImageSaver.SaveFile(null, path)); + } + + [TestCase(null)] + [TestCase("")] + [TestCase(" ")] + public void SaveFile_ThrowsArgumentException_WithInvalidFilename(string filename) + { + var dummyImage = new Bitmap(1, 1); + Assert.Throws(() => ImageSaver.SaveFile(dummyImage, filename)); + } + + [TestCase("Test.png", ExpectedResult = true)] + public bool SaveFile_SavesFile(string filename) + { + var dummyImage = new Bitmap(1, 1); + var path = Path.Combine(_directoryPath, filename); + + File.Delete(path); + ImageSaver.SaveFile(dummyImage, path); + return File.Exists(path); + } + + + [OneTimeTearDown] + public void OneTimeCleanup() + { + if (Directory.Exists(_directoryPath)) + { + Directory.Delete(_directoryPath, true); + } + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs new file mode 100644 index 000000000..ec972eca4 --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudVisualization.Tests +{ + internal static class RectangleExtensions + { + public static string ToFormatedString(this Rectangle rectangle) + { + return $"X={rectangle.X}, Y={rectangle.Y}, Width={rectangle.Width}, Height={rectangle.Height}"; + } + } +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/TagsCloudVisualization.Tests.csproj b/cs/TagsCloudVisualization.Tests/TagsCloudVisualization.Tests.csproj new file mode 100644 index 000000000..135636cdc --- /dev/null +++ b/cs/TagsCloudVisualization.Tests/TagsCloudVisualization.Tests.csproj @@ -0,0 +1,34 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + diff --git a/cs/TagsCloudVisualization/Circle.cs b/cs/TagsCloudVisualization/Circle.cs index b47cccd5b..d177f2ab8 100644 --- a/cs/TagsCloudVisualization/Circle.cs +++ b/cs/TagsCloudVisualization/Circle.cs @@ -27,4 +27,4 @@ public IEnumerable GetCoordinatesOnCircle( } } } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/CircularCloudLayouter.cs b/cs/TagsCloudVisualization/CircularCloudLayouter.cs index 074d7eb00..c1ff834db 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouter.cs @@ -39,8 +39,10 @@ public Rectangle PutNextRectangle(Size rectangleSize) break; } } + _arrangementСircle.Radius += 1.0f; } + return result; } @@ -53,6 +55,7 @@ private bool IsIntersectionWithAlreadyPlaced(Rectangle rectangle) return true; } } + return false; } @@ -63,4 +66,4 @@ private Point GetRectangleLocation(Point pointOnCircle, Size rectangleSize) return new Point(x, y); } } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs index 53f3edbc5..483cfa6b0 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs @@ -9,6 +9,8 @@ namespace TagsCloudVisualization { internal static class CircularCloudLayouterPainter { + private static int _defaultPadding = 10; + public static Bitmap Draw(IList rectangles, int? paddingPerSide = null) { if (rectangles.Count == 0) @@ -16,7 +18,7 @@ public static Bitmap Draw(IList rectangles, int? paddingPerSide = nul throw new ArgumentException("Список прямоугольников пуст."); } - var correctPaddingPerSide = paddingPerSide ?? 10; + var correctPaddingPerSide = paddingPerSide ?? _defaultPadding; var minimums = new Point(rectangles.Min(r => r.Left), rectangles.Min(r => r.Top)); var maximums = new Point(rectangles.Max(r => r.Right), rectangles.Max(r => r.Bottom)); @@ -27,7 +29,7 @@ public static Bitmap Draw(IList rectangles, int? paddingPerSide = nul using var graphics = Graphics.FromImage(result); graphics.Clear(Color.White); using var pen = new Pen(Color.Black, 1); - for (int i = 0; i < rectangles.Count; i++) + for (var i = 0; i < rectangles.Count; i++) { var positionOnCanvas = GetPositionOnCanvas( rectangles[i], @@ -50,4 +52,4 @@ private static Point GetPositionOnCanvas(Rectangle rectangle, Point minimums, in private static Size GetImageSize(Point minimums, Point maximums, int paddingPerSide) => new Size(maximums.X - minimums.X + 2 * paddingPerSide, maximums.Y - minimums.Y + 2 * paddingPerSide); } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs b/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs deleted file mode 100644 index 0d8c3a5b1..000000000 --- a/cs/TagsCloudVisualization/CircularCloudLayouterTests.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using NUnit.Framework; -using FluentAssertions; -using System.Drawing; - -namespace TagsCloudVisualization -{ - [TestFixture] - internal class CircularCloudLayouterTests - { - private CircularCloudLayouter _circularCloudLayouter; - private CircularCloudLayouterWorker _circularCloudLayouterWorker; - private CircularCloudLayouterPainter _circularCloudLayouterPainter; - - public void SetUp(int x = 400, - int y = 400, - int minRectangleWidth = 30, - int minRectangleHeight = 20, - int maxRectangleWidth = 70, - int maxRectangleHeight = 50, - string imageFileName = "circularCloudLayouter.png") - { - var center = new Point(x, y); - var minRectangleSize = new Size(minRectangleWidth, minRectangleHeight); - var maxRectangleSize = new Size(maxRectangleWidth, maxRectangleHeight); - - _circularCloudLayouter = new CircularCloudLayouter(center); - _circularCloudLayouterWorker = new CircularCloudLayouterWorker(minRectangleSize, maxRectangleSize); - _circularCloudLayouterPainter = new CircularCloudLayouterPainter(imageFileName); - } - - [TestCase(-1, 0)] - [TestCase(0, -1)] - [TestCase(-1, -1)] - public void CircularCloudLayouter_ThrowsArgumentException_OnNegativeCenterPoint(int x, int y) - { - var center = new Point(x, y); - Assert.Throws(() => new CircularCloudLayouter(center)); - } - - - [TestCase(0, 100, 1)] - [TestCase(-1, 100, 1)] - [TestCase(100, 0, 1)] - [TestCase(100, -1, 1)] - - public void PutNextRectangle_ThrowsArgumentException_OnAnyNegativeOrZeroSize(int width, int height, int rectanglesCount) - { - SetUp(); - for (int i = 0; i < rectanglesCount; i++) - { - var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); - Assert.Throws(() => _circularCloudLayouter.PutNextRectangle(new Size(width, height))); - } - } - - [TestCase(1)] - public void PutNextRectangle_ReturnsRectangleType(int rectanglesCount) - { - SetUp(); - for (int i = 0; i < rectanglesCount; i++) - { - var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); - Assert.That(_circularCloudLayouter.PutNextRectangle(nextRectangleSize), Is.TypeOf(typeof(Rectangle))); - } - } - - [TestCase(1, "TestFile.png", ExpectedResult = true)] - [TestCase(0, "TestFile.png", ExpectedResult = false)] - public bool CircularCloudLayouterPainter_CreatesFile(int rectanglesCount, string fileName) - { - SetUp(imageFileName: fileName); - File.Delete(fileName); - - for (int i = 0; i < rectanglesCount; i++) - { - var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize(); - _circularCloudLayouter.PutNextRectangle(nextRectangleSize); - } - - _circularCloudLayouterPainter.Save(_circularCloudLayouter.Rectangles.ToList()); - return File.Exists(fileName); - } - } -} diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs index fe71525ec..d249ad6c2 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -18,21 +18,22 @@ public static Size GetNextRectangleSize( int maxRectangleHeight) { if (!IsMinAndMaxValuesPositive( - minRectangleWidth, - maxRectangleWidth, - minRectangleHeight, - maxRectangleHeight)) + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight)) { - throw new ArgumentException("Ширина и высота прямоугольника не может быть отрицательной либо нулём"); + throw new ArgumentException("Ширина или высота прямоугольника должна быть положительной"); } if (!IsMinAndMaxValuesCorrect( - minRectangleWidth, - maxRectangleWidth, - minRectangleHeight, - maxRectangleHeight)) + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight)) { - throw new ArgumentException("Минимальное значение ширины или высоты не может быть больше максимального"); + throw new ArgumentException( + "Минимальное значение ширины или высоты не может быть больше максимального"); } var width = _random.Next(minRectangleWidth, maxRectangleWidth); @@ -52,7 +53,6 @@ private static bool IsMinAndMaxValuesPositive( int maxRectangleWidth, int minRectangleHeight, int maxRectangleHeight) - => minRectangleWidth > 0 && maxRectangleWidth > 0 - && minRectangleHeight > 0 && maxRectangleHeight > 0; + => minRectangleWidth > 0 && maxRectangleWidth > 0 && minRectangleHeight > 0 && maxRectangleHeight > 0; } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/ICircularCloudLayouter.cs b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs index df7edab5c..66d0bbe4b 100644 --- a/cs/TagsCloudVisualization/ICircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs @@ -11,4 +11,4 @@ internal interface ICircularCloudLayouter { Rectangle PutNextRectangle(Size rectangleSize); } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/ImageSaver.cs b/cs/TagsCloudVisualization/ImageSaver.cs index 7a97e085d..d40110816 100644 --- a/cs/TagsCloudVisualization/ImageSaver.cs +++ b/cs/TagsCloudVisualization/ImageSaver.cs @@ -9,7 +9,7 @@ namespace TagsCloudVisualization { internal static class ImageSaver { - public static void SaveOnFile(Bitmap image, string fileName) + public static void SaveFile(Bitmap image, string fileName) { if (image is null) { @@ -18,10 +18,10 @@ public static void SaveOnFile(Bitmap image, string fileName) if (string.IsNullOrWhiteSpace(fileName)) { - throw new ArgumentException("Некорректное имя файла для созранения"); + throw new ArgumentException("Некорректное имя файла для создания"); } image.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); } } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/Program.cs b/cs/TagsCloudVisualization/Program.cs index b47045808..a322a698d 100644 --- a/cs/TagsCloudVisualization/Program.cs +++ b/cs/TagsCloudVisualization/Program.cs @@ -7,22 +7,27 @@ internal class Program static void Main(string[] args) { var center = new Point(400, 400); - var minRectangleSize = new Size(30, 20); - var maxRectangleSize = new Size(70, 50); - var rectanglesCount = 100; + var minRectangleWidth = 30; + var maxRectangleWidth = 70; + var minRectangleHeight = 20; + var maxRectangleHeight = 50; + var rectanglesCount = 1000; var imageFileName = "circularCloudLayouter.png"; + var rectangles = new Rectangle[rectanglesCount]; var circularCloudLayouter = new CircularCloudLayouter(center); - var circularCloudLayouterWorker = new CircularCloudLayouterWorker(minRectangleSize, maxRectangleSize); - var circularCloudLayouterPainter = new CircularCloudLayouterPainter(imageFileName); for (int i = 0; i < rectanglesCount; i++) { - var nextRectangleSize = circularCloudLayouterWorker.GetNextRectangleSize(); - circularCloudLayouter.PutNextRectangle(nextRectangleSize); + var nextRectangleSize = CircularCloudLayouterWorker.GetNextRectangleSize( + minRectangleWidth, + maxRectangleWidth, + minRectangleHeight, + maxRectangleHeight); + rectangles[i] = circularCloudLayouter.PutNextRectangle(nextRectangleSize); } - circularCloudLayouterPainter.Save(circularCloudLayouter.Rectangles.ToList()); + ImageSaver.SaveFile(CircularCloudLayouterPainter.Draw(rectangles), imageFileName); } } -} +} \ No newline at end of file diff --git a/cs/TagsCloudVisualization/TagsCloudVisualization.csproj b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj index 465af9204..82cf0ca1e 100644 --- a/cs/TagsCloudVisualization/TagsCloudVisualization.csproj +++ b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj @@ -14,7 +14,7 @@ - + diff --git a/cs/tdd.sln b/cs/tdd.sln index 996b53a71..6f484716d 100644 --- a/cs/tdd.sln +++ b/cs/tdd.sln @@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples", "Samples\Samples. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudVisualization", "TagsCloudVisualization\TagsCloudVisualization.csproj", "{1E0AAECB-7355-4B9F-95FB-11961EE556E7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudVisualization.Tests", "TagsCloudVisualization.Tests\TagsCloudVisualization.Tests.csproj", "{743C21B9-556A-4097-B188-21A0B29BA967}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Release|Any CPU.ActiveCfg = Release|Any CPU {1E0AAECB-7355-4B9F-95FB-11961EE556E7}.Release|Any CPU.Build.0 = Release|Any CPU + {743C21B9-556A-4097-B188-21A0B29BA967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {743C21B9-556A-4097-B188-21A0B29BA967}.Debug|Any CPU.Build.0 = Debug|Any CPU + {743C21B9-556A-4097-B188-21A0B29BA967}.Release|Any CPU.ActiveCfg = Release|Any CPU + {743C21B9-556A-4097-B188-21A0B29BA967}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d50927d124f18ae87de2d3c7cb27c19338c02098 Mon Sep 17 00:00:00 2001 From: Zakhar Popov <55971950+BlizPerfect@users.noreply.github.com> Date: Sun, 17 Nov 2024 23:10:57 +0500 Subject: [PATCH 10/17] Update README.md --- README.md | 68 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3d6e24382..872753e4f 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,33 @@ -# Test Driven Development - -Пройдя блок, ты: - -- Узнаешь, почему полезно писать тесты вместе с кодом -- Скорее всего поймешь, что никогда раньше не писал тесты в стиле TDD по-настоящему :-) -- Получишь опыт парного TDD. -- Станешь считать стиль TDD естественным и удобным в работе - - -## Необходимые знания - -Понадобится знание C# или JS - -Рекомендуется пройти блок [Тестирование](https://github.com/kontur-courses/testing) - - -## Самостоятельная подготовка - -Посмотри [видеодемонстрацию TDD](https://www.youtube.com/watch?v=lLTv2JSrCBY) (10 минут) - - -## Очная встреча - -~ 3.5 часа - - -[Инструкция для дистанционного формата](https://docs.google.com/document/d/18YYaIoyWfNzf1HXT_DCWnsqJA_3yoNkjetj_E4omMY8/edit?usp=sharing) - - -## Закрепление материала - -1. Выполни задание [Облако тегов](HomeExercise.md) -2. Спецзадание __TDD__ -Выполни ещё какую-нибудь ближайшую задачу в стиле TDD. Рабочую задачу, если уже работаешь, или учебную, если ещё учишься. +Примеры работ с разными параметрами: +1. +- Число прямоугольников = 100; +- Ширина прямоугольников от 30 до 70 пикселей; +- Высота прямоугольников от 20 до 50 пикселей. +![circularCloudLayouter](https://github.com/user-attachments/assets/7f83aa24-c3be-4c38-a042-6c67ea48f026) + +2. +- Число прямоугольников = 10000; +- Ширина прямоугольников от 30 до 70 пикселей; +- Высота прямоугольников от 20 до 50 пикселей. +![circularCloudLayouter](https://github.com/user-attachments/assets/fa3162c6-1428-465b-821e-fc748274c106) + +3. +- Число прямоугольников = 100; +- Ширина прямоугольников от 30 до 700 пикселей; +- Высота прямоугольников от 20 до 500 пикселей. +![circularCloudLayouter](https://github.com/user-attachments/assets/5cf95ab5-fb7e-457f-8842-530b99b4be0d) + +4. +- Число прямоугольников = 10; +- Ширина прямоугольников от 30 до 700 пикселей; +- Высота прямоугольников от 20 до 500 пикселей. +![circularCloudLayouter](https://github.com/user-attachments/assets/839af33d-aaba-4259-a111-2218710a45df) + +5. +- Число прямоугольников = 10; +- Ширина прямоугольников от 30 до 700 пикселей; +- Высота прямоугольников от 20 до 500 пикселей. +![circularCloudLayouter](https://github.com/user-attachments/assets/9f0ac478-2ca5-4522-b9b1-a2764f2f4493) + +Принцип расположения прямоугольников: +Прямоугольники ставятся на окружности увеличивающегося радиуса с центром в точке, совпадающей с центром первого поставленного прямоугольника. From e446905ff3c00b0db9f5e1b28dc5a63d3dd7644d Mon Sep 17 00:00:00 2001 From: Zakhar Popov <55971950+BlizPerfect@users.noreply.github.com> Date: Sun, 17 Nov 2024 23:11:55 +0500 Subject: [PATCH 11/17] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 872753e4f..7e48c806d 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,35 @@ - Число прямоугольников = 100; - Ширина прямоугольников от 30 до 70 пикселей; - Высота прямоугольников от 20 до 50 пикселей. + ![circularCloudLayouter](https://github.com/user-attachments/assets/7f83aa24-c3be-4c38-a042-6c67ea48f026) 2. - Число прямоугольников = 10000; - Ширина прямоугольников от 30 до 70 пикселей; - Высота прямоугольников от 20 до 50 пикселей. + ![circularCloudLayouter](https://github.com/user-attachments/assets/fa3162c6-1428-465b-821e-fc748274c106) 3. - Число прямоугольников = 100; - Ширина прямоугольников от 30 до 700 пикселей; - Высота прямоугольников от 20 до 500 пикселей. + ![circularCloudLayouter](https://github.com/user-attachments/assets/5cf95ab5-fb7e-457f-8842-530b99b4be0d) 4. - Число прямоугольников = 10; - Ширина прямоугольников от 30 до 700 пикселей; - Высота прямоугольников от 20 до 500 пикселей. + ![circularCloudLayouter](https://github.com/user-attachments/assets/839af33d-aaba-4259-a111-2218710a45df) 5. - Число прямоугольников = 10; - Ширина прямоугольников от 30 до 700 пикселей; - Высота прямоугольников от 20 до 500 пикселей. + ![circularCloudLayouter](https://github.com/user-attachments/assets/9f0ac478-2ca5-4522-b9b1-a2764f2f4493) Принцип расположения прямоугольников: From 38e8bc09ce752729b6996aeedb49bcc88e149aa6 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 17:52:55 +0500 Subject: [PATCH 12/17] =?UTF-8?q?=D0=98=D0=B7=20=D0=BF=D1=80=D0=BE=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=B0=20TagsCloudVisualization=20=D1=83=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/TagsCloudVisualization/TagsCloudVisualization.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cs/TagsCloudVisualization/TagsCloudVisualization.csproj b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj index 82cf0ca1e..4a7be45e0 100644 --- a/cs/TagsCloudVisualization/TagsCloudVisualization.csproj +++ b/cs/TagsCloudVisualization/TagsCloudVisualization.csproj @@ -9,11 +9,6 @@ - - - - - From d8a98621a8c4d3ef04bdd09436ed8f51efbeb8c5 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 17:53:46 +0500 Subject: [PATCH 13/17] =?UTF-8?q?=D0=92=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B5=20TagsCloudVisualization=20=D1=8F=D0=B2=D0=BD?= =?UTF-8?q?=D0=BE=20=D1=83=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=20=D0=B0=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=B1=D1=83=D1=82=20=D0=B2=D0=B8=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20internal=20=D0=BA=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/TagsCloudVisualization/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cs/TagsCloudVisualization/Program.cs b/cs/TagsCloudVisualization/Program.cs index a322a698d..fdfcb3ba3 100644 --- a/cs/TagsCloudVisualization/Program.cs +++ b/cs/TagsCloudVisualization/Program.cs @@ -1,5 +1,7 @@ using System.Drawing; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("TagsCloudVisualization.Tests")] namespace TagsCloudVisualization { internal class Program From 28e44b5fee1bbe7b6bdd70dc8fbd4f73eb7648c6 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 20:55:41 +0500 Subject: [PATCH 14/17] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=82=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D1=83=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B=D0=BC?= =?UTF-8?q?=20=D1=82=D1=80=D0=B5=D0=B1=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Тесты ShouldPlaceRectanglesInCircle и ShouldPlaceRectanglesTightly были заменены на более точный тест ShouldPlaceRectanglesInCircle, обьединяющий их функциональность. 2. ShouldPlaceRectanglesNearCenter переименован в ShouldPlaceCenterOfMassOfRectanglesNearCenter, так как предыдущее название вводило в заблуждение по функциональности теста. 3. Рефакторинг тестов. --- ...cularCloudLayouterMainRequirementsTests.cs | 104 ++++++++++++------ .../ImageSaverTest.cs | 2 +- .../RectangleExtensions.cs | 8 +- 3 files changed, 77 insertions(+), 37 deletions(-) diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs index 3f71c7138..b6ae1d1be 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs @@ -1,4 +1,5 @@ using FluentAssertions; +using NUnit.Framework.Constraints; using System; using System.Collections.Generic; using System.Drawing; @@ -44,20 +45,22 @@ public void SetUp() } } - [TestCase(1.1, ExpectedResult = true)] + [TestCase(0.7, 1000)] [Repeat(10)] - public bool ShouldPlaceRectanglesInCircle(double goodAspectRatio) + public void ShouldPlaceRectanglesInCircle(double expectedCoverageRatio, int gridSize) { - var boundingBoxSize = GetBoundingBoxSize(); - var actualAspectRatio = - (double)Math.Max(boundingBoxSize.Width, boundingBoxSize.Height) - / Math.Min(boundingBoxSize.Width, boundingBoxSize.Height); - return actualAspectRatio <= goodAspectRatio; + var maxRadius = _rectangles.Max(r => r.GetMaxDistanceFromPointToRectangleAngles(_center)); + var step = (2 * maxRadius) / gridSize; + + var occupancyGrid = GetOccupancyGrid(gridSize, maxRadius, step); + + var actualCoverageRatio = GetOccupancyGridRatio(occupancyGrid, maxRadius, step); + actualCoverageRatio.Should().BeGreaterThanOrEqualTo(expectedCoverageRatio); } - [TestCase(0.1, ExpectedResult = true)] + [TestCase(10)] [Repeat(10)] - public bool ShouldPlaceRectanglesNearCenter(double percentFromBoundingBoxMaxSize) + public void ShouldPlaceCenterOfMassOfRectanglesNearCenter(int tolerance) { var centerX = _rectangles.Average(r => r.Left + r.Width / 2.0); var centerY = _rectangles.Average(r => r.Top + r.Height / 2.0); @@ -66,12 +69,7 @@ public bool ShouldPlaceRectanglesNearCenter(double percentFromBoundingBoxMaxSize var distance = Math.Sqrt(Math.Pow(actualCenter.X - _center.X, 2) + Math.Pow(actualCenter.Y - _center.Y, 2)); - var boundingBoxSize = GetBoundingBoxSize(); - - var maxAllowedDistance = Math.Max(boundingBoxSize.Width, boundingBoxSize.Height) - * percentFromBoundingBoxMaxSize; - - return maxAllowedDistance >= distance; + distance.Should().BeLessThanOrEqualTo(tolerance); } [Test] @@ -85,23 +83,12 @@ public void ShouldPlaceRectanglesWithoutOverlap() Assert.That( _rectangles[i].IntersectsWith(_rectangles[j]) == false, $"Прямоугольники пересекаются:\n" + - $"{_rectangles[i].ToFormatedString()}\n" + - $"{_rectangles[j].ToFormatedString()}"); + $"{_rectangles[i].ToString()}\n" + + $"{_rectangles[j].ToString()}"); } } } - - [TestCase(0.55, ExpectedResult = true)] - [Repeat(10)] - public bool ShouldPlaceRectanglesTightly(double tight) - { - var boundingBoxSize = GetBoundingBoxSize(); - var boundingBoxArea = boundingBoxSize.Width * boundingBoxSize.Height; - var filledArea = _rectangles.Sum(r => r.Width * r.Height); - return ((double)filledArea / boundingBoxArea) >= tight; - } - [TearDown] public void Cleanup() { @@ -126,13 +113,62 @@ public void OneTimeCleanup() } } - private Size GetBoundingBoxSize() + private (int start, int end) GetGridIndexesInterval( + int rectangleStartValue, + int rectangleCorrespondingSize, + double maxRadius, + double step) + { + var start = (int)((rectangleStartValue - _center.X + maxRadius) / step); + var end = (int)((rectangleStartValue + rectangleCorrespondingSize - _center.X + maxRadius) / step); + return (start, end); + } + + private bool[,] GetOccupancyGrid(int gridSize, double maxRadius, double step) { - var minX = _rectangles.Min(r => r.Left); - var minY = _rectangles.Min(r => r.Top); - var maxX = _rectangles.Max(r => r.Right); - var maxY = _rectangles.Max(r => r.Bottom); - return new Size(maxX - minX, maxY - minY); + var result = new bool[gridSize, gridSize]; + foreach (var rect in _rectangles) + { + var xInterval = GetGridIndexesInterval(rect.X, rect.Width, maxRadius, step); + var yInterval = GetGridIndexesInterval(rect.Y, rect.Height, maxRadius, step); + for (int x = xInterval.start; x <= xInterval.end; x++) + { + for (int y = yInterval.start; y <= yInterval.end; y++) + { + result[x, y] = true; + } + } + } + return result; + } + + private double GetOccupancyGridRatio(bool[,] occupancyGrid, double maxRadius, double step) + { + var totalCellsInsideCircle = 0; + var coveredCellsInsideCircle = 0; + for (int x = 0; x < occupancyGrid.GetLength(0); x++) + { + for (int y = 0; y < occupancyGrid.GetLength(0); y++) + { + var cellCenterX = x * step - maxRadius + _center.X; + var cellCenterY = y * step - maxRadius + _center.Y; + + var distance = Math.Sqrt( + Math.Pow(cellCenterX - _center.X, 2) + Math.Pow(cellCenterY - _center.Y, 2)); + + if (distance > maxRadius) + { + continue; + } + + totalCellsInsideCircle += 1; + if (occupancyGrid[x, y]) + { + coveredCellsInsideCircle += 1; + } + } + } + return (double)coveredCellsInsideCircle / totalCellsInsideCircle; } } } \ No newline at end of file diff --git a/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs index 142e62881..539223f5b 100644 --- a/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs +++ b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs @@ -28,7 +28,7 @@ public void SaveFile_ArgumentNullException_WithNullBitmap(string filename) [TestCase(null)] [TestCase("")] [TestCase(" ")] - public void SaveFile_ThrowsArgumentException_WithInvalidFilename(string filename) + public void SaveFile_ThrowsArgumentException_WithInvalidFilename(string? filename) { var dummyImage = new Bitmap(1, 1); Assert.Throws(() => ImageSaver.SaveFile(dummyImage, filename)); diff --git a/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs index ec972eca4..4ba93d484 100644 --- a/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs +++ b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs @@ -10,9 +10,13 @@ namespace TagsCloudVisualization.Tests { internal static class RectangleExtensions { - public static string ToFormatedString(this Rectangle rectangle) + public static double GetMaxDistanceFromPointToRectangleAngles(this Rectangle rectangle, Point point) { - return $"X={rectangle.X}, Y={rectangle.Y}, Width={rectangle.Width}, Height={rectangle.Height}"; + var dx = Math.Max( + Math.Abs(rectangle.X - point.X), Math.Abs(rectangle.X + rectangle.Width - point.X)); + var dy = Math.Max( + Math.Abs(rectangle.Y - point.Y), Math.Abs(rectangle.Y + rectangle.Height - point.Y)); + return Math.Sqrt(dx * dx + dy * dy); } } } \ No newline at end of file From b2114866c5981b6c2bc17c432a52e22d5d0f29b7 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 20:58:39 +0500 Subject: [PATCH 15/17] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D1=85=20using.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouterMainRequirementsTests.cs | 6 ------ .../CircularCloudLayouterPainterTests.cs | 8 +------- .../CircularCloudLayouterTests.cs | 7 +------ .../CircularCloudLayouterWorkerTests.cs | 9 +-------- cs/TagsCloudVisualization.Tests/ImageSaverTest.cs | 7 +------ .../RectangleExtensions.cs | 8 +------- cs/TagsCloudVisualization/Circle.cs | 7 +------ cs/TagsCloudVisualization/CircularCloudLayouter.cs | 11 +++-------- .../CircularCloudLayouterPainter.cs | 7 +------ .../CircularCloudLayouterWorker.cs | 7 +------ cs/TagsCloudVisualization/ICircularCloudLayouter.cs | 7 +------ cs/TagsCloudVisualization/ImageSaver.cs | 7 +------ 12 files changed, 13 insertions(+), 78 deletions(-) diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs index b6ae1d1be..7bd9bb03f 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs @@ -1,11 +1,5 @@ using FluentAssertions; -using NUnit.Framework.Constraints; -using System; -using System.Collections.Generic; using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace TagsCloudVisualization.Tests { diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs index e9095d3d5..13ee37ef3 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterPainterTests.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static System.Net.Mime.MediaTypeNames; +using System.Drawing; namespace TagsCloudVisualization.Tests { diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs index 67b91ace3..c14f814f9 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterTests.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization.Tests { diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs index b3ea2fc2e..7017fa5cf 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterWorkerTests.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudVisualization.Tests +namespace TagsCloudVisualization.Tests { [TestFixture] internal class CircularCloudLayouterWorkerTests diff --git a/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs index 539223f5b..8d1feaa6d 100644 --- a/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs +++ b/cs/TagsCloudVisualization.Tests/ImageSaverTest.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization.Tests { diff --git a/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs index 4ba93d484..2b3873ec0 100644 --- a/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs +++ b/cs/TagsCloudVisualization.Tests/RectangleExtensions.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization.Tests { diff --git a/cs/TagsCloudVisualization/Circle.cs b/cs/TagsCloudVisualization/Circle.cs index d177f2ab8..629fef3df 100644 --- a/cs/TagsCloudVisualization/Circle.cs +++ b/cs/TagsCloudVisualization/Circle.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { diff --git a/cs/TagsCloudVisualization/CircularCloudLayouter.cs b/cs/TagsCloudVisualization/CircularCloudLayouter.cs index c1ff834db..b531b8d9f 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouter.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { internal class CircularCloudLayouter(Point center) : ICircularCloudLayouter { - private Circle _arrangementСircle = new Circle(center); - private Random _random = new Random(); + private readonly Circle _arrangementСircle = new Circle(center); + private readonly Random _random = new Random(); private readonly List _rectangles = new List(); public Rectangle PutNextRectangle(Size rectangleSize) diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs index 483cfa6b0..1cca46837 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs index d249ad6c2..7a6958333 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { diff --git a/cs/TagsCloudVisualization/ICircularCloudLayouter.cs b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs index 66d0bbe4b..1e1fcd2df 100644 --- a/cs/TagsCloudVisualization/ICircularCloudLayouter.cs +++ b/cs/TagsCloudVisualization/ICircularCloudLayouter.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { diff --git a/cs/TagsCloudVisualization/ImageSaver.cs b/cs/TagsCloudVisualization/ImageSaver.cs index d40110816..80e589806 100644 --- a/cs/TagsCloudVisualization/ImageSaver.cs +++ b/cs/TagsCloudVisualization/ImageSaver.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace TagsCloudVisualization { From d6ec5ab01371ca8931c31329c7cf483d1f70f62d Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 21:07:48 +0500 Subject: [PATCH 16/17] =?UTF-8?q?CircularCloudLayouterWorker=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=B2=D0=B5=D0=B4=D1=91=D0=BD=20=D0=B2=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=BF=D1=80=D0=B8=D1=8F=D1=82=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=B3=D0=BB=D0=B0=D0=B7=D1=83=20=D0=B2=D0=B8?= =?UTF-8?q?=D0=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...cularCloudLayouterMainRequirementsTests.cs | 2 +- .../CircularCloudLayouterWorker.cs | 31 ++++--------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs index 7bd9bb03f..38c48d9d6 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs @@ -52,7 +52,7 @@ public void ShouldPlaceRectanglesInCircle(double expectedCoverageRatio, int grid actualCoverageRatio.Should().BeGreaterThanOrEqualTo(expectedCoverageRatio); } - [TestCase(10)] + [TestCase(15)] [Repeat(10)] public void ShouldPlaceCenterOfMassOfRectanglesNearCenter(int tolerance) { diff --git a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs index 7a6958333..7cc720e7f 100644 --- a/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs +++ b/cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs @@ -12,20 +12,15 @@ public static Size GetNextRectangleSize( int minRectangleHeight, int maxRectangleHeight) { - if (!IsMinAndMaxValuesPositive( - minRectangleWidth, - maxRectangleWidth, - minRectangleHeight, - maxRectangleHeight)) + if (minRectangleWidth <= 0 || maxRectangleWidth <= 0 + || minRectangleHeight <= 0 || maxRectangleHeight <= 0) { - throw new ArgumentException("Ширина или высота прямоугольника должна быть положительной"); + throw new ArgumentException( + "Ширина или высота прямоугольника должна быть положительной"); } - if (!IsMinAndMaxValuesCorrect( - minRectangleWidth, - maxRectangleWidth, - minRectangleHeight, - maxRectangleHeight)) + if (minRectangleWidth > maxRectangleWidth + || minRectangleHeight > maxRectangleHeight) { throw new ArgumentException( "Минимальное значение ширины или высоты не может быть больше максимального"); @@ -35,19 +30,5 @@ public static Size GetNextRectangleSize( var height = _random.Next(minRectangleHeight, maxRectangleHeight); return new Size(width, height); } - - private static bool IsMinAndMaxValuesCorrect( - int minRectangleWidth, - int maxRectangleWidth, - int minRectangleHeight, - int maxRectangleHeight) - => minRectangleWidth <= maxRectangleWidth && minRectangleHeight <= maxRectangleHeight; - - private static bool IsMinAndMaxValuesPositive( - int minRectangleWidth, - int maxRectangleWidth, - int minRectangleHeight, - int maxRectangleHeight) - => minRectangleWidth > 0 && maxRectangleWidth > 0 && minRectangleHeight > 0 && maxRectangleHeight > 0; } } \ No newline at end of file From d20e854de863d3b7ef551db4c3d33c516e1a9be4 Mon Sep 17 00:00:00 2001 From: Zakhar Date: Mon, 18 Nov 2024 21:11:39 +0500 Subject: [PATCH 17/17] =?UTF-8?q?=D0=9A=D0=BE=D0=B4=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=B2=D0=B5=D0=B4=D1=91=D0=BD=20=D0=BA=20=D0=B5=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=D0=BE=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=B8=D1=8E=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D1=8F=20var.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouterMainRequirementsTests.cs | 10 +++++----- cs/TagsCloudVisualization/Circle.cs | 2 +- cs/TagsCloudVisualization/Program.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs index 38c48d9d6..5d16b5648 100644 --- a/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs +++ b/cs/TagsCloudVisualization.Tests/CircularCloudLayouterMainRequirementsTests.cs @@ -28,7 +28,7 @@ public void SetUp() _rectangles = new Rectangle[rectanglesCount]; var circularCloudLayouter = new CircularCloudLayouter(_center); - for (int i = 0; i < rectanglesCount; i++) + for (var i = 0; i < rectanglesCount; i++) { var nextRectangleSize = CircularCloudLayouterWorker.GetNextRectangleSize( minRectangleWidth, @@ -125,9 +125,9 @@ public void OneTimeCleanup() { var xInterval = GetGridIndexesInterval(rect.X, rect.Width, maxRadius, step); var yInterval = GetGridIndexesInterval(rect.Y, rect.Height, maxRadius, step); - for (int x = xInterval.start; x <= xInterval.end; x++) + for (var x = xInterval.start; x <= xInterval.end; x++) { - for (int y = yInterval.start; y <= yInterval.end; y++) + for (var y = yInterval.start; y <= yInterval.end; y++) { result[x, y] = true; } @@ -140,9 +140,9 @@ private double GetOccupancyGridRatio(bool[,] occupancyGrid, double maxRadius, do { var totalCellsInsideCircle = 0; var coveredCellsInsideCircle = 0; - for (int x = 0; x < occupancyGrid.GetLength(0); x++) + for (var x = 0; x < occupancyGrid.GetLength(0); x++) { - for (int y = 0; y < occupancyGrid.GetLength(0); y++) + for (var y = 0; y < occupancyGrid.GetLength(0); y++) { var cellCenterX = x * step - maxRadius + _center.X; var cellCenterY = y * step - maxRadius + _center.Y; diff --git a/cs/TagsCloudVisualization/Circle.cs b/cs/TagsCloudVisualization/Circle.cs index 629fef3df..20a6fa960 100644 --- a/cs/TagsCloudVisualization/Circle.cs +++ b/cs/TagsCloudVisualization/Circle.cs @@ -11,7 +11,7 @@ public IEnumerable GetCoordinatesOnCircle( int startAngle, int step = 1) { - for (int dAngle = 0; dAngle < 360; dAngle += step) + for (var dAngle = 0; dAngle < 360; dAngle += step) { var angle = (startAngle + dAngle) % 360; diff --git a/cs/TagsCloudVisualization/Program.cs b/cs/TagsCloudVisualization/Program.cs index fdfcb3ba3..c34afe758 100644 --- a/cs/TagsCloudVisualization/Program.cs +++ b/cs/TagsCloudVisualization/Program.cs @@ -19,7 +19,7 @@ static void Main(string[] args) var rectangles = new Rectangle[rectanglesCount]; var circularCloudLayouter = new CircularCloudLayouter(center); - for (int i = 0; i < rectanglesCount; i++) + for (var i = 0; i < rectanglesCount; i++) { var nextRectangleSize = CircularCloudLayouterWorker.GetNextRectangleSize( minRectangleWidth,