-
Notifications
You must be signed in to change notification settings - Fork 303
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
base: master
Are you sure you want to change the base?
Ренат Зубакин #207
Changes from 5 commits
6a52d04
8b5d4f9
edcb92f
f74ba1c
ecd3b3d
7c92409
7c9ab4b
4b5972c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace TagsCloud.App; | ||
|
||
public interface IApp | ||
{ | ||
public void Run(); | ||
} |
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); | ||
} |
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)); | ||
} | ||
} |
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(); | ||
} | ||
} |
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; } | ||
} |
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(); | ||
} | ||
} |
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(); | ||
} |
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; | ||
|
||
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); | ||
} | ||
} |
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; | ||
} | ||
} |
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
var changes = 1; | ||
while (changes > 0) | ||
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Логика с rectangle = CompressByAxis(rectangle, true);
rectangle = CompressByAxis(rectangle, false); Условно - пожали по X, пожали по Y, вроде бы There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
} |
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(); | ||
} |
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()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Эти строчки кажутся тут лишними |
||
app.Run(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А почему часть значений сделана свойствами, а часть - полями?
Давай придерживаться практики, что полями должны быть только зависимости, прилетающие в конструкторе (и возможно некоторые приватные компоненты)