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

Ренат Зубакин #207

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
25 changes: 25 additions & 0 deletions TagsCloud/App/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using TagsCloud.Layouters;
using TagsCloud.TagsCloudPainters;
using TagsCloud.TextReaders;

namespace TagsCloud.App;

public class App : IApp
{
private readonly IWordsProvider wordsProvider;
private readonly ILayouter layouter;
private readonly IPainter painter;

public App(IWordsProvider wordsProvider, ILayouter layouter, IPainter painter)
{
this.wordsProvider = wordsProvider;
this.layouter = layouter;
this.painter = painter;
}

public void Run()
{
layouter.CreateTagCloud(wordsProvider.GetWords());
painter.DrawCloud(layouter);
}
}
6 changes: 6 additions & 0 deletions TagsCloud/App/IApp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloud.App;

public interface IApp
{
public void Run();
}
9 changes: 9 additions & 0 deletions TagsCloud/ColorGenerators/IColorGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;
using TagsCloud.Entities;

namespace TagsCloud.ColorGenerators;

public interface IColorGenerator
{
Color GetTagColor(Tag tag);
}
14 changes: 14 additions & 0 deletions TagsCloud/ColorGenerators/RandomColorGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Drawing;
using TagsCloud.Entities;

namespace TagsCloud.ColorGenerators;

public class RandomColorGenerator : IColorGenerator
{
private static readonly Random Random = new Random();

public Color GetTagColor(Tag tag)
{
return Color.FromArgb(Random.Next(256), Random.Next(256), Random.Next(256));
}
}
30 changes: 30 additions & 0 deletions TagsCloud/ConsoleCommands/Conventers/SizeTypeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel;
using System.Drawing;

namespace TagsCloud.ConsoleCommands.Conventers;

public class SizeTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}

public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture,
object value)
{
if (value is string stringValue)
{
string[] sizeValues = stringValue.Split(',');

if (sizeValues.Length == 2 &&
int.TryParse(sizeValues[0], out int width) &&
int.TryParse(sizeValues[1], out int height))
{
return new Size(width, height);
}
}

throw new ArgumentException();
}
}
30 changes: 30 additions & 0 deletions TagsCloud/ConsoleCommands/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel;
using System.Drawing;
using CommandLine;
using TagsCloud.ConsoleCommands.Conventers;

namespace TagsCloud.ConsoleCommands;

public class Options
{
[Option('i', "inputFile", Default = "C:\\Users\\hellw\\Desktop\\C#\\di\\TagsCloud\\source\\input.txt",
HelpText = "Set input file name.")]
public string InputFile { get; set; }

[Option('o', "outputFile", Default = "C:\\Users\\hellw\\Desktop\\C#\\di\\TagsCloud\\source\\output.png",
HelpText = "Set output file name.")]
public string OutputFile { get; set; }

[Option('f', "font", Default = "Arial", HelpText = "Set tagsCloud word Font")]
public string TagsFont { get; set; }

[Option('s', "imagesize", Default = null, HelpText = "Set output image size")]
[TypeConverter(typeof(SizeTypeConverter))]
public Size ImageSize { get; set; }

[Option('b', "background", Default = "Empty", HelpText = "Set tagsCloud output background color")]
public string Background { get; set; }

[Option('t', "parts", Default = new string[] { "sdsd", "sfdfd" }, HelpText = "Word available parts of speech.")]
public IEnumerable<string> PartsOfSpeech { get; set; }
}
31 changes: 31 additions & 0 deletions TagsCloud/ContainerConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Autofac;
using TagsCloud.App;
using TagsCloud.ColorGenerators;
using TagsCloud.ConsoleCommands;
using TagsCloud.Distributors;
using TagsCloud.Layouters;
using TagsCloud.TagsCloudPainters;
using TagsCloud.TextReaders;
using TagsCloud.WordSizeCalculators;
using TagsCloud.WordValidators;


namespace TagsCloud;

public static class ContainerConfig
{
public static IContainer Configure(Options options)
{
var builder = new ContainerBuilder();
builder.RegisterInstance(options).AsSelf();
builder.RegisterType<RandomColorGenerator>().As<IColorGenerator>().SingleInstance();
builder.RegisterType<SpiralDistributor>().As<IDistributor>();
builder.RegisterType<SimplePainter>().As<IPainter>();
builder.RegisterType<WordsProvider>().As<IWordsProvider>();
builder.RegisterType<SimpleWordFontCalculator>().As<IWordFontCalculator>();
builder.RegisterType<SimpleWordValidator>().As<IWordValidator>();
builder.RegisterType<CircularCloudLayouter>().As<ILayouter>();
builder.RegisterType<App.App>().As<IApp>();
return builder.Build();
}
}
8 changes: 8 additions & 0 deletions TagsCloud/Distributors/IDistributor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagsCloud.Distributors;

public interface IDistributor
{
Point GetNextPosition();
}
39 changes: 39 additions & 0 deletions TagsCloud/Distributors/SpiralDistributor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Drawing;

namespace TagsCloud.Distributors;

public class SpiralDistributor : IDistributor
{
public double Angle { get; private set; }
public double Radius { get; private set; }
public readonly double AngleStep;
public readonly double RadiusStep;
public readonly Point Center;
Copy link

Choose a reason for hiding this comment

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

А почему часть значений сделана свойствами, а часть - полями?

Давай придерживаться практики, что полями должны быть только зависимости, прилетающие в конструкторе (и возможно некоторые приватные компоненты)


public SpiralDistributor(Point center = new Point(), double angleStep = 0.1, double radiusStep = 0.1)
{
if (radiusStep <= 0 || angleStep == 0) throw new ArgumentException();
this.Center = center;
Radius = 0;
Angle = 0;
this.AngleStep = angleStep - 2 * Math.PI * (int)(angleStep / 2 * Math.PI);
this.RadiusStep = radiusStep;
}


public Point GetNextPosition()
{
var x = Radius * Math.Cos(Angle) + Center.X;
var y = Radius * Math.Sin(Angle) + Center.Y;

Angle += AngleStep;

if (Angle >= Math.PI * 2)
{
Angle -= 2 * Math.PI;
Radius += RadiusStep;
}

return new Point((int)x, (int)y);
}
}
17 changes: 17 additions & 0 deletions TagsCloud/Entities/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Drawing;

namespace TagsCloud.Entities;

public class Tag
{
public Rectangle TagRectangle;
public string Content;
public Font Font;

public Tag(Rectangle tagRectangle, Font font, string content)
{
this.Content = content;
this.TagRectangle = tagRectangle;
this.Font = font;
}
}
120 changes: 120 additions & 0 deletions TagsCloud/Layouters/CircularCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.Drawing;
using TagsCloud.Distributors;
using TagsCloud.Entities;
using TagsCloud.WordSizeCalculators;

namespace TagsCloud.Layouters;

public class CircularCloudLayouter : ILayouter
{
private readonly List<Tag> tags;
private IDistributor distributor;
private IWordFontCalculator fontCalculator;
public Point Center { get; private set; }
private int leftBorder;
private int rightBorder;
private int topBorder;
private int bottomBorder;

public CircularCloudLayouter(IDistributor distributor,
IWordFontCalculator fontCalculator,
Point center = new Point())
{
this.distributor = distributor;
this.fontCalculator = fontCalculator;
this.Center = center;
tags = new();
}

public void CreateTagCloud(Dictionary<string, int> tagsDictionary)
{
foreach (var tag in tagsDictionary)
{
var tagFont = fontCalculator.GetWordFont(tag.Key, tag.Value);
var rectangle = new Rectangle();
rectangle.Location = distributor.GetNextPosition();

using (Graphics g = Graphics.FromImage(new Bitmap(1, 1)))
{
var sizeF = g.MeasureString(tag.Key, tagFont);
rectangle.Size = new Size((int)Math.Ceiling(sizeF.Width), (int)Math.Ceiling(sizeF.Height));
}

while (CheckIntersection(rectangle))
{
rectangle.Location = distributor.GetNextPosition();
}

rectangle = ComperessRectangle(rectangle);
UpdateImageSize(rectangle);
var newtag = new Tag(rectangle, tagFont, tag.Key);
tags.Add(newtag);
}
}

public IEnumerable<Tag> GetTagsCollection()
{
return tags;
}

public Size GetImageSize()
{
return new Size(Math.Abs(rightBorder - leftBorder), Math.Abs(topBorder - bottomBorder));
}

private void UpdateImageSize(Rectangle rec)
{
var right = rec.X + rec.Width / 2;
var left = rec.X - rec.Width / 2;
var top = rec.Y + rec.Height / 2;
var bottom = rec.Y - rec.Height / 2;

rightBorder = right > rightBorder ? right : rightBorder;
leftBorder = left < leftBorder ? left : leftBorder;
topBorder = top > topBorder ? top : topBorder;
bottomBorder = bottom < bottomBorder ? bottom : bottomBorder;
}

private bool CheckIntersection(Rectangle currRectangle)
Copy link

Choose a reason for hiding this comment

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

От сокращения мы тут даже немного проиграли, чем выиграли, давай полностью пропишем, за читаемость никто по рукам не ударит))

{
return tags.Any(rec => currRectangle.IntersectsWith(rec.TagRectangle));
}

private Rectangle ComperessRectangle(Rectangle rectangle)
Copy link

Choose a reason for hiding this comment

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

CompressRectangle - это как будто "сжать прямоугольник", давай для чуть большей конкретики сделаем CompressRectangleToCenter

{
var changes = 1;
while (changes > 0)
Comment on lines +85 to +86
Copy link

Choose a reason for hiding this comment

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

Логика с changes тут выглядить немного лишней, так как вызов CompressByAxis по идее должен выглядеть как-то так:

rectangle = CompressByAxis(rectangle, true);
rectangle = CompressByAxis(rectangle, false);

Условно - пожали по X, пожали по Y, вроде бы changes тут даже и не нужно

Copy link
Author

Choose a reason for hiding this comment

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

это сделано для того чтобы если мы не можем допустим сдвинуть по X, но можем по Y, проверить можем ли мы после сдвига все таки еще подвинуть по X. Например такая вообразимая ситуация: у нас есть свободное пространство в виде лесенки, где мы можем сместить объект по Х затем по Y, потом опять по X и только если мы будем делать это по очереди, с этой штукой я максимально как бы убеждаюсь, что я максимально возможно сдвинул все к центру. Возможно это немного лишнее, но вот просто в голове возник такой кейс и я решил немного логику усложнить

{
rectangle = CompressByAxis(rectangle, true, out changes);
rectangle = CompressByAxis(rectangle, false, out changes);
}

return rectangle;
}

private Rectangle CompressByAxis(Rectangle rectangle, bool isByX, out int changes)
{
changes = 0;
var stepX = rectangle.X < Center.X ? 1 : -1;
var stepY = rectangle.Y < Center.Y ? 1 : -1;

while ((isByX && Math.Abs(rectangle.X - Center.X) > 0) ||
(!isByX && Math.Abs(rectangle.Y - Center.Y) > 0))
{
var newRectangle = isByX
? new Rectangle(new Point(rectangle.X + stepX, rectangle.Y), rectangle.Size)
: new Rectangle(new Point(rectangle.X, rectangle.Y + stepY), rectangle.Size);

if (!CheckIntersection(newRectangle))
{
rectangle = newRectangle;
changes++;
continue;
}

break;
}

return rectangle;
}
}
12 changes: 12 additions & 0 deletions TagsCloud/Layouters/ILayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Drawing;
using TagsCloud.Entities;

namespace TagsCloud.Layouters;

public interface ILayouter
{
public IEnumerable<Tag> GetTagsCollection();
public void CreateTagCloud(Dictionary<string, int> tagsDictionary);

public Size GetImageSize();
}
23 changes: 23 additions & 0 deletions TagsCloud/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Autofac;
using CommandLine;
using TagsCloud.App;
using TagsCloud.ConsoleCommands;

namespace TagsCloud;

public class Program
{
static void Main(string[] args)
{
var options = CommandLine.Parser.Default.ParseArguments<Options>(args).Value;
var container = ContainerConfig.Configure(options);

using (var scope = container.BeginLifetimeScope())
Copy link

Choose a reason for hiding this comment

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

Можно подсыпать сахарку немного и написать так:

using var scope = container.BeginLifetimeScope();

Тогда можно будет убрать лишнюю вложенность в фигурных скобках

{
var app = scope.Resolve<IApp>();
var o = scope.Resolve<Options>().PartsOfSpeech.Count();
Console.WriteLine(o);
Copy link

Choose a reason for hiding this comment

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

Эти строчки кажутся тут лишними

app.Run();
}
}
}
Loading