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

Шевелев Георгий #180

Open
wants to merge 6 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
19 changes: 19 additions & 0 deletions TagCloudResult/Applications/ConsoleApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using TagCloudResult.Drawer;

namespace TagCloudResult.Applications
{
public class ConsoleApplication(IDrawer drawer, Settings settings) : IApplication
{
public Result Run()
{
var imageResult = drawer.GetImage();
if (!imageResult.IsSuccess)
return imageResult.Fail();

imageResult.Value.Save($"{settings.SavePath}.{settings.ImageFormat.ToLower()}", settings.GetFormat());
Console.WriteLine($"Saved to {settings.SavePath + '.' + settings.ImageFormat.ToLower()}");

return Result.Ok();
}
}
}
7 changes: 7 additions & 0 deletions TagCloudResult/Applications/IApplication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudResult.Applications
{
public interface IApplication
{
Result Run();
}
}
33 changes: 33 additions & 0 deletions TagCloudResult/Container.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Drawing;
using Autofac;
using TagCloudResult.Applications;
using TagCloudResult.Drawer;
using TagCloudResult.Layouter;
using TagCloudResult.TextProcessing;
using IContainer = Autofac.IContainer;

namespace TagCloudResult
{
public static class Container
{
public static IContainer SetupContainer(Settings settings)
{
var builder = new ContainerBuilder();
builder.Register(c => settings);
builder.Register(c =>
new ArchimedeanSpiral(new Point(
c.Resolve<Settings>().ImageWidth / 2,
c.Resolve<Settings>().ImageHeight / 2),
c.Resolve<Settings>()))
.As<IPointGenerator>();
builder.RegisterType<CircularCloudLayouter>().As<ILayouter>();
builder.RegisterType<FileTextReader>().As<ITextReader>();
builder.RegisterType<TextProcessor>().As<ITextProcessor>();
builder.RegisterType<RectanglesGenerator>().As<IRectanglesGenerator>();
builder.RegisterType<Drawer.Drawer>().As<IDrawer>();
builder.RegisterType<ConsoleApplication>().As<IApplication>();

return builder.Build();
}
}
}
31 changes: 31 additions & 0 deletions TagCloudResult/Drawer/Drawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Drawing;
using TagCloudResult.Layouter;

namespace TagCloudResult.Drawer
{
public class Drawer(Settings settings, IRectanglesGenerator rectanglesGenerator) : IDrawer
{
public Result<Image> GetImage()
{
var backColorResult = Result.Of(() => Color.FromName(settings.BackColor), "Wrong background color");
if (!backColorResult.IsSuccess)
return backColorResult.Fail<Image>();
var colorResult = Result.Of(() => Color.FromName(settings.TextColor), "Wrong text color");
if (!colorResult.IsSuccess)
return colorResult.Fail<Image>();
var rectanglesDataResult = rectanglesGenerator.GetRectanglesData();
if (!rectanglesDataResult.IsSuccess)
return rectanglesDataResult.Fail<Image>();

var image = new Bitmap(settings.ImageWidth, settings.ImageHeight);
using var gr = Graphics.FromImage(image);
gr.Clear(backColorResult.Value);
var brush = new SolidBrush(colorResult.Value);
foreach (var rectangleData in rectanglesDataResult.Value)
using (var font = new Font(settings.FontName, rectangleData.fontSize, FontStyle.Regular))
gr.DrawString(rectangleData.word, font, brush, rectangleData.rectangle);

return image;
}
}
}
9 changes: 9 additions & 0 deletions TagCloudResult/Drawer/IDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagCloudResult.Drawer
{
public interface IDrawer
{
public Result<Image> GetImage();
}
}
Binary file added TagCloudResult/Examples/1.png
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 TagCloudResult/Examples/Custom_Image_Size.png
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 TagCloudResult/Examples/DifferentColors.png
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 TagCloudResult/Examples/DifferentFormat.jpeg
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 TagCloudResult/Examples/Different_Font.png
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 TagCloudResult/Examples/Save.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions TagCloudResult/Excluded.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Exclude
21 changes: 21 additions & 0 deletions TagCloudResult/Layouter/ArchimedeanSpiral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Drawing;

namespace TagCloudResult.Layouter
{
public class ArchimedeanSpiral(Point centerPoint, Settings settings) : IPointGenerator
{
private double angle { get; set; }
private const double DeltaAngle = Math.PI / 180;
private readonly int scale = settings.SpiralScale;
public Point CenterPoint => centerPoint;

public Point GetNextPoint()
{
var newX = (int)(centerPoint.X + scale * angle * Math.Cos(angle));
var newY = (int)(centerPoint.Y + scale * angle * Math.Sin(angle));
angle += DeltaAngle;

return new Point(newX, newY);
}
}
}
78 changes: 78 additions & 0 deletions TagCloudResult/Layouter/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Drawing;

namespace TagCloudResult.Layouter
{
public class CircularCloudLayouter : ILayouter
{
private readonly IPointGenerator pointGenerator;
public List<Rectangle> Rectangles { get; } = [];

public CircularCloudLayouter(IPointGenerator pointGenerator)
{
this.pointGenerator = pointGenerator;
}

public Result<Rectangle> PutNextRectangle(Size rectangleSize)
{
if (rectangleSize.Height <= 0 || rectangleSize.Width <= 0)
return Result.Fail<Rectangle>($"rectangleSize with zero or negative height or width is prohibited!");
while (true)
{
var nextPoint = pointGenerator.GetNextPoint();
var newPoint = new Point(nextPoint.X - rectangleSize.Width / 2, nextPoint.Y - rectangleSize.Height / 2);
var rectangle = new Rectangle(newPoint, rectangleSize);
if (IsIntersectsWithOthers(rectangle)) continue;
rectangle = GetCloserToCenterRectangle(rectangle);
Rectangles.Add(rectangle);
break;
}

return Rectangles[^1];
}

private bool IsIntersectsWithOthers(Rectangle rectangle) =>
Rectangles.Any(x => x.IntersectsWith(rectangle));

private Rectangle GetCloserToCenterRectangle(Rectangle rectangle)
{
var directions = GetDirection(rectangle);
foreach (var direction in directions)
{
var newRectangle = GetMovedRectangle(rectangle, direction.X, direction.Y);
while (!IsIntersectsWithOthers(newRectangle))
{
if (pointGenerator.CenterPoint.X - newRectangle.Size.Width / 2 == newRectangle.X
|| pointGenerator.CenterPoint.Y - newRectangle.Size.Height / 2 == newRectangle.Y)
break;
rectangle = newRectangle;
newRectangle = GetMovedRectangle(rectangle, direction.X, direction.Y);
}
}

return rectangle;
}

private List<(int X, int Y)> GetDirection(Rectangle rectangle)
{
var horizontalDiffer = pointGenerator.CenterPoint.X - rectangle.Size.Width / 2 - rectangle.X;
var verticalDiffer = pointGenerator.CenterPoint.Y - rectangle.Size.Height / 2 - rectangle.Y;
var directions = new List<(int X, int Y)>();
if (horizontalDiffer != 0 && verticalDiffer != 0)
directions.Add((horizontalDiffer > 0 ? 1 : -1, verticalDiffer > 0 ? 1 : -1));
if (horizontalDiffer != 0)
directions.Add((horizontalDiffer > 0 ? 1 : -1, 0));
if (verticalDiffer != 0)
directions.Add((0, verticalDiffer > 0 ? 1 : -1));
return directions;
}

private static Rectangle GetMovedRectangle(Rectangle rectangle, int xDelta, int yDelta) =>
new(
new Point(
rectangle.X + xDelta,
rectangle.Y + yDelta
),
rectangle.Size
);
}
}
9 changes: 9 additions & 0 deletions TagCloudResult/Layouter/ILayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagCloudResult.Layouter
{
public interface ILayouter
{
public Result<Rectangle> PutNextRectangle(Size rectangleSize);
}
}
10 changes: 10 additions & 0 deletions TagCloudResult/Layouter/IPointGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagCloudResult.Layouter
{
public interface IPointGenerator
{
public Point GetNextPoint();
public Point CenterPoint { get; }
}
}
7 changes: 7 additions & 0 deletions TagCloudResult/Layouter/IRectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TagCloudResult.Layouter
{
public interface IRectanglesGenerator
{
public Result<IEnumerable<RectangleData>> GetRectanglesData();
}
}
18 changes: 18 additions & 0 deletions TagCloudResult/Layouter/RectangleData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Drawing;

namespace TagCloudResult.Layouter
{
public class RectangleData
{
public readonly Rectangle rectangle;
public readonly string word;
public readonly float fontSize;

public RectangleData(Rectangle rectangle, string word, float fontSize)
{
this.fontSize = fontSize;
this.word = word;
this.rectangle = rectangle;
}
}
}
44 changes: 44 additions & 0 deletions TagCloudResult/Layouter/RectanglesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Drawing;
using TagCloudResult.TextProcessing;

namespace TagCloudResult.Layouter
{
public class RectanglesGenerator(ITextProcessor textProcessor, Settings settings, ILayouter layouter)
: IRectanglesGenerator
{
public Result<IEnumerable<RectangleData>> GetRectanglesData()
{
var frequencies = textProcessor.GetWordsFrequency();
if (!frequencies.IsSuccess)
return frequencies.Fail<IEnumerable<RectangleData>>();

var fontResult = Result.Of(() => new Font(settings.FontName, settings.FontSize, FontStyle.Regular))
.ReplaceError(x => $"Font with name {settings.FontName} does not exist or not installed");
if (!fontResult.IsSuccess)
return fontResult.Fail<IEnumerable<RectangleData>>();

var totalAmount = frequencies.Value.Sum(x => x.Value);
var result = new List<RectangleData>();
foreach (var frequency in frequencies.Value.OrderByDescending(x => x.Value))
{
using var font = new Font(
settings.FontName, settings.FontSize * (frequency.Value * 100 / totalAmount), FontStyle.Regular
);
var rectangleResult = layouter.PutNextRectangle(GetTextSize(frequency.Key, font));
if (!rectangleResult.IsSuccess)
return rectangleResult.Fail<IEnumerable<RectangleData>>();

result.Add(new RectangleData(rectangleResult.Value, frequency.Key, font.Size));
}

return result;
}

private static Size GetTextSize(string text, Font font)
{
using var temporaryBitmap = new Bitmap(1, 1);
using var temporaryGraphics = Graphics.FromImage(temporaryBitmap);
return Size.Ceiling(temporaryGraphics.MeasureString(text, font));
}
}
}
22 changes: 22 additions & 0 deletions TagCloudResult/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Autofac;
using CommandLine;
using TagCloudResult.Applications;

namespace TagCloudResult
{
abstract class MainClass
{
public static void Main(string[] args)
{
var settingsResult = Parser.Default.ParseArguments<Settings>(args);
if (settingsResult.Errors.Any())
return;
var appResult = Result<IApplication>
.Of(() => Container.SetupContainer(settingsResult.Value).Resolve<IApplication>())
.RefineError("Impossible to build app")
.Then(x => x.Run());
if (!appResult.IsSuccess)
Console.WriteLine(appResult.Error);
}
}
}
Loading