Skip to content
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

Sibogatov Rinat #221

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions cs/TagsCloudVizualization/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Drawing;

namespace TagsCloudVizualization;

public class CircularCloudLayouter : ICircularCloudLayouter
{
private readonly Point center;
private readonly List<Rectangle> rectangles;
private readonly Spiral spiral;

This comment was marked as resolved.


public CircularCloudLayouter(Point center)
{
this.center = center;
rectangles = new();
spiral = new(center, 0.02, 0.01);
}

public Point CloudCenter => center;
public IList<Rectangle> Rectangles => rectangles;

public Rectangle PutNextRectangle(Size rectangleSize)
{
ValidateRectangleSize(rectangleSize);

var currentRectangle = CreateNewRectangle(rectangleSize);
rectangles.Add(currentRectangle);

return currentRectangle;
}

private void ValidateRectangleSize(Size size)
{
if (size.Width <= 0 || size.Height <= 0)
{
throw new ArgumentException("Rectangle width and height must be positive");
}

}

private Rectangle CreateNewRectangle(Size rectangleSize)
{
Rectangle rectangle;
do
{
var pointOnSpiral = spiral.GetNextPointOnSpiral();
var rectangleLocation = GetUpperLeftCorner(pointOnSpiral, rectangleSize);
rectangle = new Rectangle(rectangleLocation, rectangleSize);
} while (IntersectsExisting(rectangle));

return rectangle;
}

private bool IntersectsExisting(Rectangle rectangle)
{
return rectangles.Any(rect => rect.IntersectsWith(rectangle));
}

private Point GetUpperLeftCorner(Point centerPoint, Size size)
{
return new Point(centerPoint.X - size.Width / 2, centerPoint.Y - size.Height / 2);
}
}
10 changes: 10 additions & 0 deletions cs/TagsCloudVizualization/ICircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagsCloudVizualization;

public interface ICircularCloudLayouter
{
public Point CloudCenter { get; }
public IList<Rectangle> Rectangles { get; }
Rectangle PutNextRectangle(Size rectangleSize);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added cs/TagsCloudVizualization/Images/8_Rectangles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions cs/TagsCloudVizualization/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Drawing;

namespace TagsCloudVizualization;

public class Program
{
public const int ImageWidth = 720;
public const int ImageHeight = 720;
public const int CountRectangles = 10000;
public const string PathToImages = @"..\..\..\Images";

public static void Main(string[] args)
{
var layouter = CreateLayouter();
GenerateRandomRectangles(layouter);

var image = VisualizeLayout(layouter);

SaveImage(image);
}

private static CircularCloudLayouter CreateLayouter()
{
var center = new Point(ImageWidth / 2, ImageHeight / 2);
return new CircularCloudLayouter(center);
}

private static void GenerateRandomRectangles(CircularCloudLayouter layouter)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По названию метода ожидается, что он вернет прямоугольники

{
var random = new Random();
for (int i = 0; i < CountRectangles; i++)
{
var rectangleSize = new Size(random.Next(5, 20), random.Next(5, 20));
layouter.PutNextRectangle(rectangleSize);
}
}

private static Bitmap VisualizeLayout(CircularCloudLayouter layouter)
{
return Visualizer.VisualizeRectangles(layouter.Rectangles, ImageWidth, ImageHeight);
}

private static void SaveImage(Bitmap image)
{
var fileName = $"{CountRectangles}_Rectangles.png";
Visualizer.SaveBitmap(image, fileName, PathToImages);
}
}
9 changes: 9 additions & 0 deletions cs/TagsCloudVizualization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# TagsCouldVizualization

![8 Rectangles](Images/8_Rectangles.png)

![128 Rectangles](Images/128_Rectangles.png)

![500 Rectangles](Images/500_Rectangles.png)

![1000 Rectangles](Images/1000_Rectangles.png)
18 changes: 18 additions & 0 deletions cs/TagsCloudVizualization/TagsCloudVizualization.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<Folder Include="Images\" />
</ItemGroup>

</Project>
39 changes: 39 additions & 0 deletions cs/TagsCloudVizualization/Utility/Spiral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Drawing;

namespace TagsCloudVizualization;

This comment was marked as resolved.


public class Spiral
{
private readonly Point center;
private readonly double angleStep;
private readonly double radiusStep;
private double radius;
private double angle;

This comment was marked as resolved.


public Spiral(Point center, double angleStep, double radiusStep)
{
if (angleStep <= 0 || radiusStep <= 0)
{
throw new ArgumentException("Step values should be positive.");
}
this.center = center;
this.angleStep = angleStep;
this.radiusStep = radiusStep;
radius = 0;
angle = 0;
}
public Point GetNextPointOnSpiral()
{
var currentPoint = ConvertFromPolarToCartesian();
angle += angleStep;
radius += radiusStep;
return currentPoint;
}

private Point ConvertFromPolarToCartesian()
{
var x = (int)Math.Round(center.X + Math.Cos(angle) * radius);
var y = (int)Math.Round(center.Y + Math.Sin(angle) * radius);
return new Point(x, y);
}
}
47 changes: 47 additions & 0 deletions cs/TagsCloudVizualization/Utility/Visualizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Drawing;

namespace TagsCloudVizualization;

This comment was marked as resolved.


public static class Visualizer
{
public static Bitmap VisualizeRectangles(IList<Rectangle> rectangles, int bitmapWidth, int bitmapHeight)
{
var bitmap = new Bitmap(bitmapWidth, bitmapHeight);
using var graphics = Graphics.FromImage(bitmap);

DrawRectangles(rectangles, graphics);

return bitmap;
}

private static void DrawRectangles(IEnumerable<Rectangle> rectangles, Graphics graphics)
{
var pen = new Pen(Color.Green);
foreach (var rect in rectangles)
{
graphics.DrawRectangle(pen, rect);
}
}

public static void SaveBitmap(Bitmap bitmap, string fileName, string pathToDirectory)
{
EnsureDirectoryExists(pathToDirectory);

var safeFileName = GetSafeFileName(fileName);
bitmap.Save(Path.Combine(pathToDirectory, safeFileName), System.Drawing.Imaging.ImageFormat.Png);
}

private static void EnsureDirectoryExists(string directory)
{
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
}

private static string GetSafeFileName(string fileName)
{
var invalidChars = Path.GetInvalidFileNameChars();
return string.Concat(fileName.Split(invalidChars, StringSplitOptions.RemoveEmptyEntries));
}
}
72 changes: 72 additions & 0 deletions cs/TagsCloudVizualizationTests/CircularCloudLayouterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Drawing;
using TagsCloudVizualization;
using FluentAssertions;

namespace TagsCloudVizualizationTests;

public class CircularCloudLayouterTests

This comment was marked as resolved.

This comment was marked as resolved.

{
private CircularCloudLayouter sut;
private Point center = new(720, 720);

[SetUp]
public void Setup()
{
sut = new CircularCloudLayouter(center);
}

[Test]
public void Constructor_ShouldNotThrow()
{
Assert.DoesNotThrow(() => new CircularCloudLayouter(center));
}

[TestCase(-4, 16, TestName = "PutNextRectangle_WidthNotPositive_ThrowsArgumentException")]

This comment was marked as resolved.

[TestCase(77, -8, TestName = "PutNextRectangle_HeightNotPositive_ThrowsArgumentException")]
public void PutNextRectangle_InvalidSize_ThrowsArgumentException(int rectangleWidth, int rectangleHeight)
{
Assert.Throws<ArgumentException>(() => sut.PutNextRectangle(new Size(rectangleWidth, rectangleHeight)));
}

[Test]
public void PutNextRectangle_ShouldReturnCorrectRectangleSize()
{
var rectangle = sut.PutNextRectangle(new Size(8, 8));

rectangle.Size.Should().Be(new Size(8, 8));
}

[Test]
public void PutNextRectangle_FirstRectangle_ShouldHaveCenterAtLayoutCenter()
{
var rectangle = sut.PutNextRectangle(new Size(8, 8));

var expectedRectangleCenter = new Point(rectangle.Left + rectangle.Width / 2, rectangle.Top + rectangle.Height / 2);
expectedRectangleCenter.Should().Be(center);
}

[Test]
public void PutNextRectangle_TwoRectangles_SecondRectangleCenterShouldNotBeAtLayoutCenter()
{
sut.PutNextRectangle(new Size(8, 8));

var secondRectangle = sut.PutNextRectangle(new Size(6, 6));

var expectedRectangleCenter = new Point(
secondRectangle.Left + secondRectangle.Width / 2,
secondRectangle.Top + secondRectangle.Height / 2);

expectedRectangleCenter.Should().NotBe(center);
}

[Test]
public void PutNextRectangle_TwoRectangles_ShouldNotIntersect()
{
var firstRectangle = sut.PutNextRectangle(new Size(8, 8));

var secondRectangle = sut.PutNextRectangle(new Size(77, 77));

secondRectangle.IntersectsWith(firstRectangle).Should().BeFalse();
}

}
1 change: 1 addition & 0 deletions cs/TagsCloudVizualizationTests/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using NUnit.Framework;
26 changes: 26 additions & 0 deletions cs/TagsCloudVizualizationTests/SpiralTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Drawing;
using TagsCloudVizualization;
using FluentAssertions;

namespace TagsCloudVizualizationTests;

public class SpiralTests
{
private Point center = new(250, 250);

[Test]
public void Constructor_ShouldNotThrow_WithValidArguments()
{
Action constructorAction = () => new Spiral(center, 0.1, 0.2);
constructorAction.Should().NotThrow();
}

[TestCase(0, 0, TestName = "Constructor_ZeroStep_ThrowsArgumentException")]
[TestCase(-0.1, 0.2, TestName = "Constructor_NegativeAngleStep_ThrowsArgumentException")]
[TestCase(0.1, -0.2, TestName = "Constructor_NegativeRadiusStep_ThrowsArgumentException")]
public void Constructor_InvalidStepValues_ThrowsArgumentException(double angleStep, double radiusStep)
{
Action constructorAction = () => new Spiral(center, angleStep, radiusStep);
constructorAction.Should().Throw<ArgumentException>();
}
}
25 changes: 25 additions & 0 deletions cs/TagsCloudVizualizationTests/TagsCloudVizualizationTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2"/>
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
<PackageReference Include="coverlet.collector" Version="3.2.0"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TagsCloudVizualization\TagsCloudVizualization.csproj" />
</ItemGroup>

</Project>
Loading