-
Notifications
You must be signed in to change notification settings - Fork 306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Дмитрий Леонтьев #248
base: master
Are you sure you want to change the base?
Дмитрий Леонтьев #248
Changes from all commits
0397783
25ef8f2
da0a95b
9023ff6
1ed59c7
ab4bc98
c467e75
f9f8199
f241aed
f33f6c7
5caad72
fe86382
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.Drawing; | ||
using TagsCloudVisualization.CloudLayouter; | ||
using TagsCloudVisualization.Draw; | ||
using TagsCloudVisualization.Extension; | ||
using TagsCloudVisualization.RectangleGenerator; | ||
using TagsCloudVisualization.Saver; | ||
|
||
var center = new Point(0, 0); | ||
var randomRectangles = RectangleGenerator.GenerateRandomRectangles(1000); | ||
var layouter = new CircularCloudLayouter(center); | ||
layouter.PutRectangles(randomRectangles); | ||
var drawer = new RectangleDraftsman(1500, 1500); | ||
const string filename = "CloudRectangles1000.png"; | ||
drawer.CreateImage(layouter.Rectangles); | ||
drawer.SaveImageToFile(filename); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Samples\Samples.csproj" /> | ||
<ProjectReference Include="..\TagsCloudVisualization\TagsCloudVisualization.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
using System.Drawing; | ||
using FluentAssertions; | ||
using NUnit.Framework; | ||
using NUnit.Framework.Interfaces; | ||
using TagsCloudVisualization.CloudLayouter; | ||
using TagsCloudVisualization.Draw; | ||
using TagsCloudVisualization.Extension; | ||
using TagsCloudVisualization.RectangleGenerator; | ||
using TagsCloudVisualization.Saver; | ||
|
||
namespace TagsCloudVisualizationTests; | ||
|
||
[TestFixture] | ||
public class CircularCloudLayouterTest() | ||
{ | ||
private IReadOnlyList<Rectangle> rectanglesForCrashTest; | ||
|
||
[TearDown] | ||
public void TearDown() | ||
{ | ||
if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) | ||
{ | ||
var drawer = new RectangleDraftsman(1500, 1500); | ||
var filename = $"{TestContext.CurrentContext.WorkDirectory}\\{TestContext.CurrentContext.Test.Name}.png"; | ||
drawer.CreateImage(rectanglesForCrashTest); | ||
drawer.SaveImageToFile(filename); | ||
|
||
Console.WriteLine($"Tag cloud visualization saved to file {filename}"); | ||
} | ||
} | ||
|
||
[Test] | ||
public void PutNextRectangle_PlaceFirstRectangleAtCenter() | ||
{ | ||
var center = new Point(1, 1); | ||
var layouter = new CircularCloudLayouter(center); | ||
var nextRectangle = layouter.PutNextRectangle(new Size(10, 10)); | ||
|
||
rectanglesForCrashTest = layouter.Rectangles; | ||
nextRectangle.GetCenter().Should().Be(center); | ||
} | ||
|
||
[TestCase(0, 0)] | ||
[TestCase(-1, -1)] | ||
public void PutNextRectangle_WhenIncorrectSize_Throw(int sizeX, int sizeY) | ||
{ | ||
var center = new Point(0, 0); | ||
var layouter = new CircularCloudLayouter(center); | ||
|
||
Action action = () => layouter.PutNextRectangle(new Size(sizeX, sizeY)); | ||
action.Should().Throw<ArgumentException>().WithMessage("Width and height should be greater than zero."); | ||
} | ||
|
||
[TestCase(1, 1, 10)] | ||
public void PutNextRectangle_AddRectangles(int sizeX, int sizeY, int count) | ||
{ | ||
var center = new Point(0, 0); | ||
var layouter = new CircularCloudLayouter(center); | ||
|
||
for (var i = 0; i < count; i++) | ||
{ | ||
layouter.PutNextRectangle(new Size(sizeX, sizeY)); | ||
} | ||
|
||
rectanglesForCrashTest = layouter.Rectangles; | ||
layouter.Rectangles.Count.Should().Be(count); | ||
} | ||
|
||
[TestCase(30)] | ||
[TestCase(50)] | ||
[TestCase(100)] | ||
[TestCase(1000)] | ||
public void PutNextRectangle_CreateLayoutWithoutIntersections(int countRectangles) | ||
{ | ||
var center = new Point(0, 0); | ||
var layouter = new CircularCloudLayouter(center); | ||
var rectangles = RectangleGenerator.GenerateRandomRectangles(countRectangles).ToList(); | ||
layouter.PutRectangles(rectangles); | ||
rectanglesForCrashTest = layouter.Rectangles; | ||
|
||
for (var i = 0; i < rectangles.Count; i++) | ||
{ | ||
for (var j = i + 1; j < rectangles.Count; j++) | ||
{ | ||
layouter.Rectangles[i].IntersectsWith(layouter.Rectangles[j]).Should().BeFalse(); | ||
} | ||
} | ||
} | ||
|
||
[TestCase(0, 0, 10, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(0, 0, 100, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(0, 0, 1000, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(100, 100, 10, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(100, 100, 100, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(100, 100, 1000, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 10, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 100, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 1000, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 10, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 100, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 1000, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 10, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 100, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 1000, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
public void PutNextRectangle_CreateLaoyoutWithMore40PercentRoundLayout_OnRandomNumberRectangles( | ||
int xCenter, | ||
int yCenter, | ||
int countRectangles) | ||
{ | ||
var center = new Point(xCenter, yCenter); | ||
var randomRectangles = RectangleGenerator.GenerateRandomRectangles(countRectangles); | ||
var layouter = new CircularCloudLayouter(center); | ||
layouter.PutRectangles(randomRectangles); | ||
|
||
var maxX = GetMaxX(layouter.Rectangles); | ||
var minX = GetMinX(layouter.Rectangles); | ||
var maxY = GetMaxY(layouter.Rectangles); | ||
var minY = GetMinY(layouter.Rectangles); | ||
|
||
// Вычитаю центр, чтобы сместить нашу окружность в начало координат | ||
var radius = Max(maxX - center.X, minX - center.X, maxY - center.Y, minY - center.Y); | ||
|
||
var deviationMaxXFromRadius = Math.Abs(radius - maxX); | ||
var deviationMinXFromRadius = Math.Abs(radius - minX); | ||
var deviationMaxYFromRadius = Math.Abs(radius - maxY); | ||
var deviationMinYFromRadius = Math.Abs(radius - minY); | ||
var numberOfPointsToMeasure = 4.0; | ||
var averageSizeOfRectangles = layouter.Rectangles.Average(r => r.Height * r.Width); | ||
|
||
var percentageOfRoundLayout = | ||
1 - (deviationMaxXFromRadius + deviationMinXFromRadius + deviationMaxYFromRadius + | ||
deviationMinYFromRadius) / numberOfPointsToMeasure / averageSizeOfRectangles; | ||
|
||
percentageOfRoundLayout.Should().BeInRange(0.4, 1); | ||
} | ||
|
||
[TestCase(0, 0, 10, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(0, 0, 100, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(0, 0, 1000, Description = "Center at the center of the coordinate axis")] | ||
[TestCase(100, 100, 10, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(100, 100, 100, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(100, 100, 1000, Description = "Center in the first quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 10, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 100, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 1000, Description = "Center in the second quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 10, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 100, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, -100, 1000, Description = "Center in the third quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 10, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 100, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
[TestCase(-100, 100, 1000, Description = "Center in the fourth quadrant of the coordinate axis")] | ||
public void PutNextRectangle_CreateLaoyoutWithOver75PercentDensity_OnRandomNumberRectangles( | ||
int xCenter, | ||
int yCenter, | ||
int countRectangles) | ||
{ | ||
var center = new Point(xCenter, yCenter); | ||
var randomRectangles = RectangleGenerator.GenerateRandomRectangles(countRectangles); | ||
var layouter = new CircularCloudLayouter(center); | ||
layouter.PutRectangles(randomRectangles); | ||
rectanglesForCrashTest = layouter.Rectangles; | ||
|
||
var distancesFromCenterToRectangles = GetDistancesFromCenterToRectangles(layouter.Rectangles, center); | ||
var averageDistanceFromCenterToRectangles = distancesFromCenterToRectangles.Average(); | ||
var radiusOfCircleAroundRectangles = GetMostDistantFromCenterToRectangles(layouter.Rectangles, center); | ||
var areaOfCircle = GetAreaOfCircle(radiusOfCircleAroundRectangles); | ||
var areaOfRectangles = GetAreaOfRectangles(layouter.Rectangles); | ||
var densityCoefficient = GetDensityCoefficient(areaOfRectangles, areaOfCircle, | ||
averageDistanceFromCenterToRectangles, radiusOfCircleAroundRectangles); | ||
|
||
densityCoefficient.Should().BeLessThan(0.36); | ||
} | ||
|
||
private static IEnumerable<double> GetDistancesFromCenterToRectangles( | ||
IEnumerable<Rectangle> rectangles, | ||
Point center) => | ||
rectangles | ||
.Select(r => Math.Sqrt(Math.Pow(r.Location.X - center.X, 2) + Math.Pow(r.Location.Y - center.Y, 2))); | ||
|
||
private static double GetMostDistantFromCenterToRectangles(IEnumerable<Rectangle> rectangles, Point center) | ||
{ | ||
var mostDistantToLeftTopRectangles = rectangles | ||
.Select(r => Math.Max(Math.Abs(r.Location.X - center.X), | ||
Math.Abs(r.Location.Y - center.Y))) | ||
.Max(); | ||
var mostDistantToRightTopRectangles = rectangles | ||
.Select(r => Math.Max(Math.Abs(r.Location.X + r.Width - center.X), | ||
Math.Abs(r.Location.Y - center.Y))) | ||
.Max(); | ||
var mostDistantToLeftBottomRectangles = rectangles | ||
.Select(r => Math.Max(Math.Abs(r.Location.X - center.X), | ||
Math.Abs(r.Location.Y - r.Height - center.Y))) | ||
.Max(); | ||
var mostDistantToRightBottomRectangles = rectangles | ||
.Select(r => Math.Max(Math.Abs(r.Location.X + r.Width - center.X), | ||
Math.Abs(r.Location.Y - r.Height - center.Y))) | ||
.Max(); | ||
|
||
var mostDistant = Max(mostDistantToLeftTopRectangles, mostDistantToRightTopRectangles, | ||
mostDistantToLeftBottomRectangles, mostDistantToRightBottomRectangles); | ||
|
||
return Math.Sqrt(Math.Pow(mostDistant, 2) + | ||
Math.Pow(mostDistant, 2)); | ||
} | ||
|
||
private static double GetAreaOfCircle(double radius) => Math.PI * Math.Pow(radius, 2); | ||
|
||
private static int GetAreaOfRectangles(IEnumerable<Rectangle> rectangles) => | ||
rectangles.Sum(r => r.Width * r.Height); | ||
|
||
private static double GetDensityCoefficient( | ||
double areaOfRectangles, | ||
double areaOfCircle, | ||
double averageDistance, | ||
double radius) => | ||
areaOfRectangles / areaOfCircle * (1 - averageDistance / radius); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не понимаю, что здесь дает второй множитель? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А первый множитель расчитан неправильно. Перепроверь пожалуйста. |
||
|
||
private static int GetMaxX(IEnumerable<Rectangle> rectangles) => rectangles.Max(r => r.Location.X); | ||
|
||
private static int GetMaxY(IEnumerable<Rectangle> rectangles) => rectangles.Max(r => r.Location.Y); | ||
|
||
private static int GetMinX(IEnumerable<Rectangle> rectangles) => rectangles.Min(r => r.Location.X); | ||
|
||
private static int GetMinY(IEnumerable<Rectangle> rectangles) => rectangles.Min(r => r.Location.Y); | ||
|
||
private static int Max(int p1, int p2, int p3, int p4) => Math.Max(Math.Max(p1, p2), Math.Max(p3, p4)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System.Drawing; | ||
using System.Runtime.InteropServices; | ||
using FluentAssertions; | ||
using NUnit.Framework; | ||
using TagsCloudVisualization.CloudLayouter; | ||
using TagsCloudVisualization.Draw; | ||
using TagsCloudVisualization.Extension; | ||
using TagsCloudVisualization.RectangleGenerator; | ||
using TagsCloudVisualization.Saver; | ||
|
||
namespace TagsCloudVisualizationTests; | ||
|
||
[TestFixture] | ||
public class ImageSaverTest | ||
{ | ||
private Point center; | ||
private CircularCloudLayouter layouter; | ||
private IEnumerable<Rectangle> rectangles; | ||
private RectangleDraftsman drawer; | ||
|
||
[SetUp] | ||
public void SetUp() | ||
{ | ||
center = new Point(0, 0); | ||
layouter = new CircularCloudLayouter(center); | ||
rectangles = RectangleGenerator.GenerateRandomRectangles(10); | ||
layouter.PutRectangles(rectangles); | ||
drawer = new RectangleDraftsman(1500, 1500); | ||
} | ||
|
||
[TestCase(null)] | ||
public void CreateImage_OnInvalidParameters_ThrowsArgumentException(string filename) | ||
{ | ||
drawer.CreateImage(layouter.Rectangles); | ||
var action = () => drawer.SaveImageToFile(filename); | ||
action.Should().Throw<ArgumentException>(); | ||
} | ||
|
||
[TestCase("12\\")] | ||
[TestCase("@#$\\")] | ||
public void CreateImage_OnInvalidParameters_ThrowsDirectoryNotFoundException(string filename) | ||
{ | ||
drawer.CreateImage(layouter.Rectangles); | ||
var action = () => drawer.SaveImageToFile(filename); | ||
action.Should().Throw<DirectoryNotFoundException>(); | ||
} | ||
|
||
[TestCase("abc|123")] | ||
[TestCase("123|abc")] | ||
[TestCase("123\n")] | ||
[TestCase("123\r")] | ||
[TestCase("\\")] | ||
[TestCase("")] | ||
public void CreateImage_OnInvalidParameters_ThrowsExternalException(string filename) | ||
{ | ||
drawer.CreateImage(layouter.Rectangles); | ||
var action = () => drawer.SaveImageToFile(filename); | ||
action.Should().Throw<ExternalException>(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using System.Drawing; | ||
using NUnit.Framework; | ||
using FluentAssertions; | ||
using TagsCloudVisualization.Extension; | ||
|
||
namespace TagsCloudVisualizationTests; | ||
|
||
[TestFixture] | ||
public class PointExtensionTest | ||
{ | ||
[TestCase(0, 0, 0, 0, 0, 0, Description = "Subtract of zero points")] | ||
[TestCase(1, 1, 1, 1, 0, 0, Description = "Subtract of positive points")] | ||
[TestCase(-1, -1, -1, -1, 0, 0, Description = "Subtract of negative points")] | ||
public void Subtract_ReturnsDifferenceOfPointCoordinates( | ||
int xPoint1, | ||
int yPoint1, | ||
int xPoint2, | ||
int yPoint2, | ||
int xResult, | ||
int yResult) | ||
{ | ||
var point1 = new Point(xPoint1, yPoint1); | ||
var point2 = new Point(xPoint2, yPoint2); | ||
var result = point1.Subtract(point2); | ||
result.X.Should().Be(xResult); | ||
result.Y.Should().Be(yResult); | ||
} | ||
|
||
[Test] | ||
[TestCaseSource(nameof(PointerSumTestCases))] | ||
public Point Add_ReturnsSumOfPointCoordinates( | ||
Point point1, | ||
Point point2, | ||
Point correctResult) | ||
{ | ||
return point1.Add(point2); | ||
} | ||
|
||
private static IEnumerable<TestCaseData> PointerSumTestCases() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Потренировался - молодец) |
||
{ | ||
yield return new TestCaseData(new Point(0, 0), new Point(0, 0), new Point(0, 0)) | ||
.Returns(Point.Empty) | ||
.SetName("Addition of zero points"); | ||
yield return new TestCaseData(new Point(1, 1), new Point(1, 1), new Point(2, 2)) | ||
.Returns(new Point(2, 2)) | ||
.SetName("Addition of positive points"); | ||
yield return new TestCaseData(new Point(-1, -1), new Point(-1, -1), new Point(-2, -2)) | ||
.Returns(new Point(-2, -2)) | ||
.SetName("Addition of negative points"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Молодец, что разобрался с этим)