Skip to content
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
17 changes: 17 additions & 0 deletions TagCloud2/CloudForms/CircularSpiral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Drawing;

namespace TagCloud2.CloudForms;

public class CircularSpiral(Point center) : ICloudForm
{
private double _angle;
private const double AngleStep = 0.01;

public Point GetNextPoint()
{
_angle += AngleStep;
var x = (int) (center.X + _angle * Math.Cos(_angle));
var y = (int) (center.Y + _angle * Math.Sin(_angle));
return new Point(x, y);
}
}
9 changes: 9 additions & 0 deletions TagCloud2/CloudForms/Direction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TagCloud2.CloudForms;

public enum Direction
{
Up,
Right,
Down,
Left,
}
16 changes: 16 additions & 0 deletions TagCloud2/CloudForms/DirectionExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace TagCloud2.CloudForms;

public static class DirectionExtension
{
public static Direction ClockwiseRotate(this Direction direction)
{
return direction switch
{
Direction.Up => Direction.Right,
Direction.Right => Direction.Down,
Direction.Down => Direction.Left,
Direction.Left => Direction.Up,
_ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Вместо исключений всюду в программе используй паттерн Result

};
}
}
8 changes: 8 additions & 0 deletions TagCloud2/CloudForms/ICloudForm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud2.CloudForms;

public interface ICloudForm
{
public Point GetNextPoint();
}
42 changes: 42 additions & 0 deletions TagCloud2/CloudForms/SquareSpiral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Drawing;

namespace TagCloud2.CloudForms;

public class SquareSpiral(Point centre) : ICloudForm
{
private const int Step = 1;
private int _stepCounter = 1;
private int _neededSteps = 1;
private Direction _direction = Direction.Up;
private Point _previus = centre;

public Point GetNextPoint()
{
_previus += GetOffsetSize(_direction);

_stepCounter--;

if (_stepCounter == 0)
{
_direction = _direction.ClockwiseRotate();

if (_direction == Direction.Up || _direction == Direction.Down)
{
_neededSteps++;
}

_stepCounter = _neededSteps;
}

return _previus;
}

private Size GetOffsetSize(Direction direction) => direction switch
{
Direction.Up => new Size(0, Step),
Direction.Right => new Size(Step, 0),
Direction.Down => new Size(0, -Step),
Direction.Left => new Size(-Step, 0),
_ => throw new ArgumentOutOfRangeException(nameof(direction))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Вместо исключений всюду в программе используй паттерн Result

};
}
8 changes: 8 additions & 0 deletions TagCloud2/CloudGenerator/IRectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TagCloud;

namespace TagCloud2.CloudGenerator;

public interface IRectanglesGenerator
{
public Result<IList<WordInShape>> GetWordsInShape(IDictionary<string, int> wordToWeight);
}
50 changes: 50 additions & 0 deletions TagCloud2/CloudGenerator/RectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Drawing;
using TagCloud;
using TagCloud2.CloudLayout;
using TagCloud2.Drawer;

namespace TagCloud2.CloudGenerator;

public class RectanglesGenerator(ICloudLayouter cloudLayouter, DrawerSettings drawerSettings) : IRectanglesGenerator
{
private readonly List<WordInShape> _wordsInShape = new();
private const int MinRectangleWidth = 5;
private const int MinRectangleHeight = 5;


public Result<IList<WordInShape>> GetWordsInShape(IDictionary<string, int> wordToWeight)
{
foreach (var word in wordToWeight)
{
var current = word.Key;
var size = GenerateRectangleSize(word, wordToWeight.Count);
var rectangle = cloudLayouter.PutNextRectangle(size);
if (rectangle.Width / current.Length < 1)
{
return Result.Fail<IList<WordInShape>>("Too small cloud size, try to take greater parameter");
}

var fontSize = GenerateFontSize(rectangle, current);
_wordsInShape.Add(new WordInShape(current, rectangle, fontSize));
}

return _wordsInShape;
}

private float GenerateFontSize(Rectangle rectangle, string word)
{
var fontSizeWidth = rectangle.Width / word.Length;
var fontSizeHeight = rectangle.Height;
return Math.Min(fontSizeWidth, fontSizeHeight);
}

private Size GenerateRectangleSize(KeyValuePair<string, int> word, int count)
{
var length = word.Key.Length;
var value = word.Value;
var width = length * value * drawerSettings.CloudSize.Width / count;
var height = value * drawerSettings.CloudSize.Height / count;
return new Size(Math.Max(width, MinRectangleWidth),
Math.Max(height, MinRectangleHeight));
}
}
5 changes: 5 additions & 0 deletions TagCloud2/CloudGenerator/WordInShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using System.Drawing;

namespace TagCloud2.CloudGenerator;

public record WordInShape(string Word, Rectangle Rectangle, float FontSize);
17 changes: 17 additions & 0 deletions TagCloud2/CloudLayout/CloudExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Drawing;
using TagCloud2.CloudGenerator;

namespace TagCloud2.CloudLayout;

public static class CloudExtension
{
public static Size GetCloudSize(this IList<WordInShape> words)
{
var left = words.Min(x => x.Rectangle.Left);
var right = words.Max(x => x.Rectangle.Right);
var top = words.Min(x => x.Rectangle.Top);
var bottom = words.Max(x => x.Rectangle.Bottom);
var size = new Size( Math.Abs(right) + Math.Abs(left),Math.Abs(bottom) + Math.Abs(top));
return size;
}
}
24 changes: 24 additions & 0 deletions TagCloud2/CloudLayout/CloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Drawing;
using TagCloud2.CloudForms;

namespace TagCloud2.CloudLayout;

public class CloudLayouter(ICloudForm cloudForm) : ICloudLayouter
{
public readonly List<Rectangle> Rectangles = new();

public Rectangle PutNextRectangle(Size rectangleSize)
{
Rectangle rectangle;

do
{
var point = cloudForm.GetNextPoint();
point.Offset(-rectangleSize.Width / 2, -rectangleSize.Height / 2);
rectangle = new Rectangle(point, rectangleSize);
} while (Rectangles.Any(r => r.IntersectsWith(rectangle)));

Rectangles.Add(rectangle);
return rectangle;
}
}
8 changes: 8 additions & 0 deletions TagCloud2/CloudLayout/ICloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud2.CloudLayout;

public interface ICloudLayouter
{
public Rectangle PutNextRectangle(Size rectangleSize);
}
23 changes: 23 additions & 0 deletions TagCloud2/ColoringAlgorithms/GradientColor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Drawing;
using TagCloud;

namespace TagCloud2.ColoringAlgorithms;

public class GradientColor(Color gradientFrom, Color gradientTo) : IColorAlgorithm
{
public Result<Color[]> GetColors(int count)
{
if (!gradientFrom.IsKnownColor || !gradientTo.IsKnownColor)
{
return Result.Fail<Color[]>("Gradient colors are unknown");
}

return Enumerable.Range(0, count)
.Select(i => Color.FromArgb(
(int) (gradientFrom.R + (gradientTo.R - gradientFrom.R) * (float) i / (count - 1)),
(int) (gradientFrom.G + (gradientTo.G - gradientFrom.G) * (float) i / (count - 1)),
(int) (gradientFrom.B + (gradientTo.B - gradientFrom.B) * (float) i / (count - 1))
))
.ToArray();
}
}
9 changes: 9 additions & 0 deletions TagCloud2/ColoringAlgorithms/IColorAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;
using TagCloud;

namespace TagCloud2.ColoringAlgorithms;

public interface IColorAlgorithm
{
public Result<Color[]> GetColors(int count);
}
19 changes: 19 additions & 0 deletions TagCloud2/ColoringAlgorithms/RandomColor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Drawing;
using TagCloud;

namespace TagCloud2.ColoringAlgorithms;

public class RandomColor : IColorAlgorithm
{
public Result<Color[]> GetColors(int count)
{
Random random = new Random();

return Enumerable.Range(0, count)
.Select(_ => Color.FromArgb(
random.Next(256),
random.Next(256),
random.Next(256)))
.ToArray();
}
}
14 changes: 14 additions & 0 deletions TagCloud2/ColoringAlgorithms/SingleColor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Drawing;
using TagCloud;

namespace TagCloud2.ColoringAlgorithms;

public class SingleColor(Color color) : IColorAlgorithm
{
public Result<Color[]> GetColors(int count)
{
return !color.IsKnownColor
? Result.Fail<Color[]>("Unknown color")
: Enumerable.Repeat(color, count).ToArray();
}
}
6 changes: 6 additions & 0 deletions TagCloud2/Drawer/DrawerSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System.Drawing;
using TagCloud2.ColoringAlgorithms;

namespace TagCloud2.Drawer;

public record DrawerSettings(IColorAlgorithm WordsColor, Size CloudSize, string Font);
8 changes: 8 additions & 0 deletions TagCloud2/Drawer/ICloudDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TagCloud;

namespace TagCloud2.Drawer;

public interface ICloudDrawer
{
public Result<None> DrawTagsCloudFromFile(string filepath);
}
68 changes: 68 additions & 0 deletions TagCloud2/Drawer/RectanglesCloudDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Drawing;
using TagCloud;
using TagCloud.TextPreparator;
using TagCloud2.CloudGenerator;
using TagCloud2.CloudLayout;
using Color = System.Drawing.Color;
using Font = System.Drawing.Font;
using Size = System.Drawing.Size;


namespace TagCloud2.Drawer;

public class RectanglesCloudDrawer(
DrawerSettings drawerSettings,
IWordsFrequency wordsFrequency,
IRectanglesGenerator rectanglesGenerator)
: ICloudDrawer
{
private Result<Bitmap> DrawCloud(IList<WordInShape> words, Size size)
{
var bmp = new Bitmap(size.Width, size.Height);
using var graphics = Graphics.FromImage(bmp);

var bgColor = Color.White;
graphics.Clear(bgColor);
var colors = drawerSettings.WordsColor.GetColors(words.Count);
var colorsValue = colors.Value;
if (!colors.IsSuccess)
{
return Result.Fail<Bitmap>(colors.Error);
}

var rectBrush = new SolidBrush(bgColor);
var i = 0;
var fontFamilies = FontFamily.Families;
var isFontExist = fontFamilies.Any(f =>
f.Name.Equals(drawerSettings.Font, StringComparison.OrdinalIgnoreCase));
if (!isFontExist)
{
return Result.Fail<Bitmap>("Current font doesn't exist");
}

foreach (var (word, rect, fontSize) in words)
{
var textBrush = new SolidBrush(colorsValue[i++]);
graphics.FillRectangle(rectBrush, rect);
var font = new Font(drawerSettings.Font, fontSize);

var stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};

graphics.DrawString(word, font, textBrush, rect, stringFormat);
}

return bmp;
}

public Result<None> DrawTagsCloudFromFile(string filepath)
{
return wordsFrequency.GetWordsFrequencyFromFile(filepath)
.Then(word => rectanglesGenerator.GetWordsInShape(word))
.Then(wordsInShape => DrawCloud(wordsInShape, wordsInShape.GetCloudSize()))
.Then(result => SaviorImages.SaveImage(result, "TagCloud", "PNG"));
}
}
8 changes: 8 additions & 0 deletions TagCloud2/FileReader/IFileReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TagCloud;

namespace TagCloud2.FileReader;

public interface IFileReader
{
public Result<IEnumerable<string>> TryReadFile(string filePath);
}
Loading