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

Попов Захар #257

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3b12dd6
Черновой вариант решения второго домашнего задания.
BlizPerfect Nov 13, 2024
cf3d993
TagsCloudVisualization.csproj явно добавлен в tdd.sln.
BlizPerfect Nov 17, 2024
0fddb27
Класс CircularCloudLayouterWorker теперь является статичным.
BlizPerfect Nov 17, 2024
335b4b0
Метод Save у CircularCloudLayouterPainter теперь принимает IList<Rect…
BlizPerfect Nov 17, 2024
cddc6c8
Добавлен интерфейс ICircularCloudLayouter.
BlizPerfect Nov 17, 2024
f2c3a04
Рефакторинг класса CircularCloudLayouter.
BlizPerfect Nov 17, 2024
29a85ee
Разделён функционал отрисовки прямоугольников и сохранения изображения
BlizPerfect Nov 17, 2024
cf7db73
Добавлена проверка входных данных у CircularCloudLayouterWorker.
BlizPerfect Nov 17, 2024
a675a75
Общий рефакторинг кода.
BlizPerfect Nov 17, 2024
d50927d
Update README.md
BlizPerfect Nov 17, 2024
e446905
Update README.md
BlizPerfect Nov 17, 2024
38e8bc0
Из проекта TagsCloudVisualization удалены библиотеки для тестирования.
BlizPerfect Nov 18, 2024
d8a9862
В проекте TagsCloudVisualization явно указан атрибут видимости intern…
BlizPerfect Nov 18, 2024
28e44b5
Рефакторинг тестов на проверку основным требованиям.
BlizPerfect Nov 18, 2024
b211486
Удаление неиспользуемых using.
BlizPerfect Nov 18, 2024
d6ec5ab
CircularCloudLayouterWorker приведён в более приятный глазу вид.
BlizPerfect Nov 18, 2024
d20e854
Код приведён к единообразию использованя var.
BlizPerfect Nov 18, 2024
1376542
Merge branch 'Dev' of https://github.com/BlizPerfect/tdd into Dev
BlizPerfect Nov 18, 2024
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
92 changes: 92 additions & 0 deletions cs/TagsCloudVisualization/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

namespace TagsCloudVisualization
{
internal class CircularCloudLayouter
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
{
public readonly Point Center;
private float _radius = 2.0f;
private Random _random = new Random();
private readonly List<Rectangle> _rectangles = new List<Rectangle>();
public IReadOnlyList<Rectangle> Rectangles => _rectangles.AsReadOnly();
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

public CircularCloudLayouter(Point center)
{
if (center.X < 0 || center.Y < 0)
{
throw new ArgumentException("Координаты центра не могут быть меньше нуля.");
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
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);
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

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;
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

for (int angle = 0; angle < 360; angle += step)

Choose a reason for hiding this comment

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

Почему в некоторых местах используется var, а в некоторых явное задание типа?

Copy link
Author

Choose a reason for hiding this comment

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

Это мне когда студия сама подсказывает код, я там забываю поменять иногда тип данных, но всегда сам использую var)

Choose a reason for hiding this comment

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

Понял. Но как и писал выше - хотелось бы видеть единобразный стиль во всём коде

Copy link
Author

Choose a reason for hiding this comment

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

Я полностью с Вами согласен - тоже считаю, что всё должно быть единообразно.

Конкретно с var в циклах у меня забавная ситуация:
При решении задач на Leetcode я сначала руками всё писал через var, потом начал принимать подсказки студии, но менять int в цикле на var, но в итоге сдался и перестал это замечать)

Choose a reason for hiding this comment

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

Возможно Visual Studio можно настраить, чтобы она давала правильные подскази? :)

Не знаю как в ней, но в rider для этого есть настраиваемые live templates
image

В vs code это называется snippets
В visual studio вроде тоже snippets

{
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;
}
}
}
57 changes: 57 additions & 0 deletions cs/TagsCloudVisualization/CircularCloudLayouterPainter.cs
Original file line number Diff line number Diff line change
@@ -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;
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

public void Save(List<Rectangle> rectangles, int? paddingPerSide = null)
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
{
if (rectangles.Count == 0)
{
return;
}

Choose a reason for hiding this comment

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

Правда ли пустое облако тегов не должно быть сохраено?
Из сигнатуры метода не понятно, что файла может не оказаться после вызова Save


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}");
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
}

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);
}
}
85 changes: 85 additions & 0 deletions cs/TagsCloudVisualization/CircularCloudLayouterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using NUnit.Framework;
using FluentAssertions;
using System.Drawing;

namespace TagsCloudVisualization
{
[TestFixture]
internal class CircularCloudLayouterTests
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
{
private CircularCloudLayouter _circularCloudLayouter;
private CircularCloudLayouterWorker _circularCloudLayouterWorker;
private CircularCloudLayouterPainter _circularCloudLayouterPainter;
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

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<ArgumentException>(() => 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();
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
for (int i = 0; i < rectanglesCount; i++)
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
{
var nextRectangleSize = _circularCloudLayouterWorker.GetNextRectangleSize();
Assert.Throws<ArgumentException>(() => _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)));
}
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

[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);
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
}
}
29 changes: 29 additions & 0 deletions cs/TagsCloudVisualization/CircularCloudLayouterWorker.cs
Original file line number Diff line number Diff line change
@@ -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
{
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
internal class CircularCloudLayouterWorker
{
private Size _minRectangleSize;
private Size _maxRectangleSize;
private Random _random = new Random();

public CircularCloudLayouterWorker(Size minRectangleSize, Size maxRectangleSize)
{
_minRectangleSize = minRectangleSize;
_maxRectangleSize = maxRectangleSize;
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

public Size GetNextRectangleSize()
{
var width = _random.Next(_minRectangleSize.Width, _maxRectangleSize.Width);
var height = _random.Next(_minRectangleSize.Height, _maxRectangleSize.Height);
return new Size(width, height);
}
}
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved
}
28 changes: 28 additions & 0 deletions cs/TagsCloudVisualization/Program.cs
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
20 changes: 20 additions & 0 deletions cs/TagsCloudVisualization/TagsCloudVisualization.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
BlizPerfect marked this conversation as resolved.
Show resolved Hide resolved

<PropertyGroup>
<StartupObject>TagsCloudVisualization.Program</StartupObject>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit.Console" Version="3.18.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
</ItemGroup>

</Project>