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

Смышляев Дмитрий #209

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c0061ea
Подготовка структуры проекта
vafle228 Dec 15, 2024
61fec50
Пока так
vafle228 Dec 15, 2024
f86c527
Перенес решение из прошлой домашки
vafle228 Dec 15, 2024
f5d5492
Перенес тесты
vafle228 Dec 15, 2024
7adf502
Добавил файл ридер
vafle228 Dec 15, 2024
94abbd4
Добавил фильтры
vafle228 Dec 15, 2024
23d5b17
Добавил работу с командной строкой
vafle228 Dec 16, 2024
9f52604
Явно выделил клиент приложения
vafle228 Dec 16, 2024
096ec8b
Переход на концепцию настроек
vafle228 Dec 16, 2024
8abc226
Добавил зависимость от генератора изображений
vafle228 Dec 16, 2024
791aae8
Добавил сеттинги для клауд лейаутер
vafle228 Dec 16, 2024
77b4c6c
Добавил честное сохранение файла
vafle228 Dec 16, 2024
9365756
Добавил ридер для .docx файлов
vafle228 Dec 16, 2024
7473197
Добавил ридер сивс файлов
vafle228 Dec 16, 2024
122e73e
Дописал тесты для ридеров
vafle228 Dec 16, 2024
8f1e735
Уточнил поле Path
vafle228 Dec 16, 2024
b6b448f
Добавил разные форматы для изображений
vafle228 Dec 16, 2024
5ddc335
Добавил тесты на генератор
vafle228 Dec 16, 2024
524d391
Убрал лишние импорты
vafle228 Dec 16, 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
38 changes: 38 additions & 0 deletions TagCloud/CloudGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using TagCloud.ImageGenerator;
using TagCloud.ImageSaver;
using TagCloud.WordsFilter;
using TagCloud.WordsReader;

namespace TagCloud;

public class CloudGenerator(
IImageSaver saver,
IWordsReader reader,
BitmapGenerator imageGenerator,
IEnumerable<IWordsFilter> filters)
{
private const int MIN_FONT_SIZE = 10;
private const int MAX_FONT_SIZE = 80;

public string GenerateTagCloud()
{
var words = reader.ReadWords();

var freqDict = filters
.Aggregate(words, (c, f) => f.ApplyFilter(c))
.GroupBy(w => w)
.OrderByDescending(g => g.Count())
.ToDictionary(g => g.Key, g => g.Count());

var maxFreq = freqDict.Values.Max();
var tagsList = freqDict.Select(pair => ToWordTag(pair, maxFreq)).ToList();

return saver.Save(imageGenerator.GenerateWindowsBitmap(tagsList));
}

private static int TransformFreqToSize(int freq, int maxFreq)
=> (int)(MIN_FONT_SIZE + (float)freq / maxFreq * (MAX_FONT_SIZE - MIN_FONT_SIZE));

private static WordTag ToWordTag(KeyValuePair<string, int> pair, int maxFreq)
=> new(pair.Key, TransformFreqToSize(pair.Value, maxFreq));
}
8 changes: 8 additions & 0 deletions TagCloud/CloudLayouter/ICloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud.CloudLayouter;

public interface ICloudLayouter
{
public Rectangle PutNextRectangle(Size rectangleSize);
}
44 changes: 44 additions & 0 deletions TagCloud/CloudLayouter/PointLayouter/PointCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Drawing;
using TagCloud.CloudLayouter.PointLayouter.PointGenerator;
using TagCloud.CloudLayouter.Settings;

namespace TagCloud.CloudLayouter.PointLayouter;

public class PointCloudLayouter(Point center, IPointGenerator pointGenerator) : ICloudLayouter
{
private readonly List<Point> placedPoints = [];
private readonly List<Rectangle> placedRectangles = [];

public PointCloudLayouter(PointLayouterSettings settings)
: this(settings.Center, settings.Generator)
{ }

public Point Center { get; } = center;

public Rectangle PutNextRectangle(Size rectangleSize)
{
Rectangle placedRect;
try
{
placedRect = pointGenerator.StartFrom(Center)
.Except(placedPoints)
.Select(p => CreateRectangle(p, rectangleSize))
.First(r => !placedRectangles.Any(r.IntersectsWith));
}
catch (InvalidOperationException)
{
throw new ArgumentException("There are no more points in generator");
}

placedRectangles.Add(placedRect);
placedPoints.Add(placedRect.Location - placedRect.Size / 2);

return placedRect;
}

private static Rectangle CreateRectangle(Point center, Size rectangleSize)
{
var rectangleUpperLeft = center - rectangleSize / 2;
return new Rectangle(rectangleUpperLeft, rectangleSize);
}
}
24 changes: 24 additions & 0 deletions TagCloud/CloudLayouter/PointLayouter/PointGenerator/Direction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace TagCloud.CloudLayouter.PointLayouter.PointGenerator;

public enum Direction
{
Up,
Right,
Down,
Left,
}

internal static class DirectionExtensions
{
public static Direction AntiClockwiseRotate(this Direction direction)
{
return direction switch
{
Direction.Up => Direction.Left,
Direction.Left => Direction.Down,
Direction.Down => Direction.Right,
Direction.Right => Direction.Up,
_ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Drawing;
using TagCloud.CloudLayouter.Settings.Generators;

namespace TagCloud.CloudLayouter.PointLayouter.PointGenerator.Generators;

public class PolarArchimedesSpiral : IPointGenerator
{
public double Radius { get; }
public double AngleOffset { get; }

public PolarArchimedesSpiral(PolarSpiralSettings settings)
: this(settings.Radius, settings.AngleOffset)
{ }

public PolarArchimedesSpiral(double radius, double angleOffset)
{
if (radius <= 0 || angleOffset <= 0)
{
var argName = radius <= 0 ? nameof(radius) : nameof(angleOffset);
throw new ArgumentException("Spiral params should be positive.", argName);
}

Radius = radius;
AngleOffset = angleOffset * Math.PI / 180;
}

public IEnumerable<Point> StartFrom(Point startPoint)
{
var currentAngle = 0.0;
while (true)
{
var polarCoordinate = Radius / (2 * Math.PI) * currentAngle;

var xOffset = (int)Math.Round(polarCoordinate * Math.Cos(currentAngle));
var yOffset = (int)Math.Round(polarCoordinate * Math.Sin(currentAngle));

yield return startPoint + new Size(xOffset, yOffset);

currentAngle += AngleOffset;
}
// ReSharper disable once IteratorNeverReturns
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Drawing;
using TagCloud.CloudLayouter.Settings.Generators;

namespace TagCloud.CloudLayouter.PointLayouter.PointGenerator.Generators;

public class SquareArchimedesSpiral : IPointGenerator
{
public int Step { get; }

public SquareArchimedesSpiral(SquareSpiralSettings settings)
: this(settings.Step)
{ }

public SquareArchimedesSpiral(int step)
{
if (step <= 0)
throw new ArgumentException("Step should be positive number");

Step = step;
}

public IEnumerable<Point> StartFrom(Point startPoint)
{
var neededPoints = 1;
var pointsToPlace = 1;
var direction = Direction.Up;
var currentPoint = startPoint;

while (true)
{
yield return currentPoint;

pointsToPlace--;
currentPoint += GetOffsetSize(direction);

if (pointsToPlace == 0)
{
direction = direction.AntiClockwiseRotate();
if (direction is Direction.Up or Direction.Down) neededPoints++;
pointsToPlace = neededPoints;
}
}
}

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))
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Drawing;

namespace TagCloud.CloudLayouter.PointLayouter.PointGenerator;

public interface IPointGenerator
{
/*
* Infinite point generator
*/
public IEnumerable<Point> StartFrom(Point startPoint);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TagCloud.CloudLayouter.Settings.Generators;

public record PolarSpiralSettings(double Radius, double AngleOffset);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloud.CloudLayouter.Settings.Generators;

public enum PossibleGenerators
{
POLAR_SPIRAL,
SQUARE_SPIRAL,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TagCloud.CloudLayouter.Settings.Generators;

public record SquareSpiralSettings(int Step);
6 changes: 6 additions & 0 deletions TagCloud/CloudLayouter/Settings/PointLayouterSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System.Drawing;
using TagCloud.CloudLayouter.PointLayouter.PointGenerator;

namespace TagCloud.CloudLayouter.Settings;

public record PointLayouterSettings(Point Center, IPointGenerator Generator);
35 changes: 35 additions & 0 deletions TagCloud/ImageGenerator/BitmapGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Drawing;
using TagCloud.CloudLayouter;

namespace TagCloud.ImageGenerator;

#pragma warning disable CA1416
public class BitmapGenerator(Size size, FontFamily family, Color background, Color foreground, ICloudLayouter layouter)
{
public BitmapGenerator(BitmapSettings settings, ICloudLayouter layouter)
: this(settings.Sizes, settings.Font, settings.BackgroundColor, settings.ForegroundColor, layouter)
{ }

public Bitmap GenerateWindowsBitmap(List<WordTag> tags)
{
var bitmap = new Bitmap(size.Width, size.Height);
using var graphics = Graphics.FromImage(bitmap);

graphics.Clear(background);
var brush = new SolidBrush(foreground);

foreach (var tag in tags)
{
var font = new Font(family, tag.FontSize);
var wordSize = CeilSize(graphics.MeasureString(tag.Word, font));

var positionRect = layouter.PutNextRectangle(wordSize);
graphics.DrawString(tag.Word, font, brush, positionRect);
}
return bitmap;
}

private static Size CeilSize(SizeF size)
=> new((int)size.Width + 1, (int)size.Height + 1);
}
#pragma warning restore CA1416
9 changes: 9 additions & 0 deletions TagCloud/ImageGenerator/BitmapSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagCloud.ImageGenerator;

public record BitmapSettings(
Size Sizes,
FontFamily Font,
Color BackgroundColor,
Color ForegroundColor);
3 changes: 3 additions & 0 deletions TagCloud/ImageGenerator/WordTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TagCloud.ImageGenerator;

public record WordTag(string Word, int FontSize);
24 changes: 24 additions & 0 deletions TagCloud/ImageSaver/BitmapFileSaver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Drawing;

namespace TagCloud.ImageSaver;

#pragma warning disable CA1416
public class BitmapFileSaver(string imageName, string imageFormat) : IImageSaver
{
private readonly List<string> supportedFormats = ["png", "jpg", "jpeg", "bmp"];

public BitmapFileSaver(FileSaveSettings settings)
: this(settings.ImageName, settings.ImageFormat)
{ }

public string Save(Bitmap image)
{
if (!supportedFormats.Contains(imageFormat))
throw new ArgumentException($"Unsupported image format: {imageFormat}");

var fullImageName = $"{imageName}.{imageFormat}";
image.Save(fullImageName);
return Path.Combine(Directory.GetCurrentDirectory(), fullImageName);
}
}
#pragma warning restore CA1416
3 changes: 3 additions & 0 deletions TagCloud/ImageSaver/FileSaveSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TagCloud.ImageSaver;

public record FileSaveSettings(string ImageName, string ImageFormat);
8 changes: 8 additions & 0 deletions TagCloud/ImageSaver/IImageSaver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagCloud.ImageSaver;

public interface IImageSaver
{
public string Save(Bitmap image);
}
16 changes: 16 additions & 0 deletions TagCloud/TagCloud.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<ItemGroup>
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="DocX" Version="3.0.1" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Include="WeCantSpell.Hunspell" Version="5.2.1" />
</ItemGroup>

</Project>
Loading