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

Козлов Данил #213

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions cs/TagsCloudVisualization/TagsCloudVisualization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
![image](https://github.com/SenyaPevko/tdd/assets/71641148/cf705840-0fae-42c4-837c-eb3090003428)
![image](https://github.com/SenyaPevko/tdd/assets/71641148/9c297846-4147-4849-9cb6-b7ef87c012ee)
![image](https://github.com/SenyaPevko/tdd/assets/71641148/6f423444-7ef3-4a42-9d1e-cd077e18d514)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34202.233
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudVisualization", "TagsCloudVisualization\TagsCloudVisualization.csproj", "{3B411457-F79C-472E-ABE4-F0D60F3E71AD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{69E878CA-753E-41C2-829B-8BC74B179992}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3B411457-F79C-472E-ABE4-F0D60F3E71AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B411457-F79C-472E-ABE4-F0D60F3E71AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B411457-F79C-472E-ABE4-F0D60F3E71AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B411457-F79C-472E-ABE4-F0D60F3E71AD}.Release|Any CPU.Build.0 = Release|Any CPU
{69E878CA-753E-41C2-829B-8BC74B179992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69E878CA-753E-41C2-829B-8BC74B179992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69E878CA-753E-41C2-829B-8BC74B179992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69E878CA-753E-41C2-829B-8BC74B179992}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {04C00585-EA28-4409-AEE5-FB1348018BA4}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Drawing;
using TagsCloudVisualization.Interfaces;

namespace TagsCloudVisualization;

public class ArchimedeanSpiralPointer : IFormPointer
{
private readonly double _angleConst;
private readonly Point _center;
private readonly double _radiusConst;
private readonly double _step;
private double _сurrentDifference;

public ArchimedeanSpiralPointer(Point center, double step, double radiusConst, double angleConst)
{
if (step <= 0 || radiusConst <= 0 || angleConst <= 0)
throw new ArgumentException("either step or radius or angle is not possitive");

_center = center;
_сurrentDifference = step;
_step = step;
_radiusConst = radiusConst;
_angleConst = angleConst;
}

private double Angle => _сurrentDifference * _angleConst;
private double Radius => _сurrentDifference * _radiusConst;

public Point GetNextPoint()
{
_сurrentDifference += _step;
var x = _center.X + (int)(Radius * Math.Cos(Angle));
var y = _center.Y + (int)(Radius * Math.Sin(Angle));

return new Point(x, y);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Drawing;
using TagsCloudVisualization.Interfaces;

namespace TagsCloudVisualization;

public class CircularCloudLayouter : ICloudLayouter
{
private readonly IFormPointer _circularPlacer;
private readonly Cloud _cloud;

public CircularCloudLayouter(Point center)
{
_cloud = new Cloud(center, new List<Rectangle>());
_circularPlacer = new ArchimedeanSpiralPointer(center, 0.1, 0.5, 1);
}

public Rectangle PutNextRectangle(Size rectangleSize)
{
if (rectangleSize.Height <= 0 || rectangleSize.Width <= 0)
throw new ArgumentException("either width or height of rectangle size is not possitive");

var nextRectangle = Utils.Utils.GetRectangleFromCenter(_circularPlacer.GetNextPoint(), rectangleSize);
while (_cloud.Rectangles.Any(rectangle => rectangle.IntersectsWith(nextRectangle)))
nextRectangle = Utils.Utils.GetRectangleFromCenter(_circularPlacer.GetNextPoint(), rectangleSize);

_cloud.AddRectangle(nextRectangle);

return nextRectangle;
}

public void PutRectangles(List<Size> sizes)
{
if (sizes.Count == 0)
throw new ArgumentException("пустые размеры");
foreach (var size in sizes)
PutNextRectangle(size);
}

public Cloud GetCloud()
{
return _cloud;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Drawing;

namespace TagsCloudVisualization;

public class Cloud
{
public Cloud(Point center, List<Rectangle> rectangles)
{
Center = center;
Rectangles = rectangles ?? new List<Rectangle>();
}

public Point Center { get; private set; }
public List<Rectangle> Rectangles { get; }

public void AddRectangle(Rectangle rectangle)
{
Rectangles.Add(rectangle);
}

public int GetWidth()
{
return Rectangles.Max(rect => rect.X) - Rectangles.Min(rect => rect.X);
}

public int GetHeight()
{
return Rectangles.Max(rect => rect.Y) - Rectangles.Min(rect => rect.Y);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Drawing;
using System.Drawing.Drawing2D;

namespace TagsCloudVisualization;

public static class CloudDrawer
{
public static Bitmap DrawCloud(Cloud cloud, int imageWidth, int imageHeight)
{
if (cloud.Rectangles.Count == 0)
throw new ArgumentException("rectangles are empty");
if (imageWidth <= 0 || imageHeight <= 0)
throw new ArgumentException("either width or height of rectangle size is not positive");

var drawingScale = CalculateObjectDrawingScale(cloud.GetWidth(), cloud.GetHeight(), imageWidth, imageHeight);
var bitmap = new Bitmap(imageWidth, imageHeight);
var graphics = Graphics.FromImage(bitmap);
var pen = new Pen(Color.Black);

graphics.TranslateTransform(-cloud.Center.X, -cloud.Center.Y);
graphics.ScaleTransform(drawingScale, drawingScale, MatrixOrder.Append);
graphics.TranslateTransform(cloud.Center.X, cloud.Center.Y, MatrixOrder.Append);
graphics.Clear(Color.White);
graphics.DrawRectangles(pen, cloud.Rectangles.ToArray());

return bitmap;
}

public static float CalculateObjectDrawingScale(float width, float height, float imageWidth, float imageHeight)
{
var scale = 1f;
var scaleAccuracy = 0.03f;
var widthScale = scale;
var heightScale = scale;
if (width * scale > imageWidth)
widthScale = imageWidth / width - scaleAccuracy;
if (height * scale > imageHeight)
heightScale = imageHeight / height - scaleAccuracy;
return Math.Max(widthScale, heightScale);
}
}
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagsCloudVisualization.Interfaces;

public interface ICloudLayouter
dmnovikova marked this conversation as resolved.
Show resolved Hide resolved
{
Rectangle PutNextRectangle(Size rectangleSize);
Cloud GetCloud();
void PutRectangles(List<Size> sizes);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagsCloudVisualization.Interfaces;

public interface IFormPointer
{
Point GetNextPoint();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Drawing;

namespace TagsCloudVisualization;

internal class Program
{
public static void Main(string[] args)
{
var sizes = Utils.Utils.GenerateSizes(1000, 20, 100, 20);
var layouter = new CircularCloudLayouter(new Point(1000, 1000));
layouter.PutRectangles(sizes);
var cloud = layouter.GetCloud();
var bitmap = CloudDrawer.DrawCloud(cloud, 2000, 2000);
bitmap.Save(@$"{Environment.CurrentDirectory}..\..\..\..\Images\cloud000.jpg");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Drawing;

namespace TagsCloudVisualization.Utils;

public static class Utils
{
public static int CalculateShortestDistance(Rectangle rect1, Rectangle rect2)
{
var horizontalDistance = int.MaxValue;
var verticalDistance = int.MaxValue;

if (rect1.X + rect1.Width <= rect2.X)
horizontalDistance = rect2.X - (rect1.X + rect1.Width);
else if (rect2.X + rect2.Width <= rect1.X)
horizontalDistance = rect1.X - (rect2.X + rect2.Width);

if (rect1.Y + rect1.Height <= rect2.Y)
verticalDistance = rect2.Y - (rect1.Y + rect1.Height);
else if (rect2.Y + rect2.Height <= rect1.Y)
verticalDistance = rect1.Y - (rect2.Y + rect2.Height);

return Math.Min(horizontalDistance, verticalDistance);
}

public static List<Size> GenerateSizes(
int amount,
int minWidth = 10,
int maxWidth = 100,
int minHeight = 10,
int maxHeight = 100)
{
var rnd = new Random();
var sizes = new List<Size>(amount);
for (var i = 0; i < amount; i++)
sizes.Add(new Size(rnd.Next(minWidth, maxWidth), rnd.Next(minHeight, maxHeight)));

return sizes;
}

public static Rectangle GetRectangleFromCenter(Point center, Size size)
{
var x = center.X - size.Width / 2;
var y = center.Y - size.Height / 2;

return new Rectangle(new Point(x, y), size);
}

public static Point GetRectangleCenter(Rectangle rectangle)
{
var x = rectangle.X;
var y = rectangle.Y;
return new Point(x + rectangle.Width / 2, y + rectangle.Height / 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Drawing;
using NUnit.Framework;
using TagsCloudVisualization;

namespace Tests;

[TestFixture]
public class ArchimedeanSpiralTests
{
private static IEnumerable<TestCaseData> ConstructorArgumentException => new[]
{
new TestCaseData(new Point(1, 1), 0, 1, 1).SetName("WhenGivenNotPositiveStep"),
new TestCaseData(new Point(1, 1), 1, 0, 1).SetName("WhenGivenNotPositiveRadius"),
new TestCaseData(new Point(1, 1), 1, 1, 0).SetName("WhenGivenNotPositiveAngle")
};

[TestCaseSource(nameof(ConstructorArgumentException))]
public void Constructor_ShouldThrowArgumentException(Point center, double step, double radius, double angle)
{
Assert.Throws<ArgumentException>(() => new ArchimedeanSpiralPointer(center, step, radius, angle));
}
}
Loading