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
98 changes: 98 additions & 0 deletions TagCloudConsoleClient/ConsoleClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using CommandLine;
using System.Drawing;
using System.Drawing.Imaging;
using TagCloudGenerator.Core.Interfaces;
using TagCloudGenerator.Core.Models;
using TagCloudGenerator.Infrastructure;

namespace TagCloudConsoleClient
{
public class ConsoleClient : IClient
{
private readonly ITagCloudGenerator _generator;
private readonly ICollection<IFilter> _filters;
private readonly IReaderRepository _readersRepository;
private readonly INormalizer _normalizer;
private readonly IRenderer _renderer;

public ConsoleClient(ITagCloudGenerator generator, ICollection<IFilter> filters, IReaderRepository readers, INormalizer normalizer, IRenderer renderer)
{
_generator = generator;
_filters = filters;
_readersRepository = readers;
_normalizer = normalizer;
_renderer = renderer;
}

public void Run(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed(RunWithOptions)
.WithNotParsed(errors => { });
}

private void RunWithOptions(Options opts)
{
if (!File.Exists(opts.InputFile))
{
Console.WriteLine($"Error: input file '{opts.InputFile}' does not exist.");
return;
}

var canvasSettings = new CanvasSettings()
.SetSize(opts.Width, opts.Height)
.SetBackgroundColor(TryParseColor(opts.BackgroundColor))
.WithShowRectangles()
.SetPadding(opts.Padding);

var textSettings = new TextSettings()
.SetFontFamily(opts.FontFamily)
.SetFontSizeRange(opts.MinFontSize, opts.MaxFontSize)
.SetTextColor(TryParseColor(opts.TextColor));

var inputFile = opts.InputFile;
var outputFile = opts.OutputFile;

Console.WriteLine("Starting tag cloud generation...");
Console.WriteLine($"Input file: {inputFile}");
Console.WriteLine($"Output file: {outputFile}");


_readersRepository.TryGetReader(inputFile)
.Then(reader => reader.TryRead(inputFile))
.Then(words => _normalizer.Normalize(words))
.Then(words => _generator.Generate(words, canvasSettings, textSettings, _filters))
.Then(items => _renderer.Render(items, canvasSettings, textSettings))
.Then(image => Result.OfAction(() =>
{
image.Save(outputFile, ImageFormat.Png);
image.Dispose();
}, "Failed to save output image"))
.OnFail(error =>
{
Console.WriteLine("Error during generation:");
Console.WriteLine(error);
});
}

private static Color? TryParseColor(string colorStr)
{
if (string.IsNullOrWhiteSpace(colorStr))
return null;

try
{
var known = Color.FromName(colorStr);
if (known.IsKnownColor)
return known;

return ColorTranslator.FromHtml(colorStr);
}
catch
{
Console.WriteLine($"Color '{colorStr}' could not be parsed. Default color will be used.");
return null;
}
}
}
}
41 changes: 41 additions & 0 deletions TagCloudConsoleClient/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using CommandLine;

namespace TagCloudConsoleClient
{
public class Options
{
[Value(0, MetaName = "input",
HelpText = "Path to the input file containing text.",
Required = true)]
public string InputFile { get; set; }

[Value(1, MetaName = "output",
HelpText = "Path for the output image (e.g., out.png).",
Required = true)]
public string OutputFile { get; set; }

[Option("width", HelpText = "Canvas width (default is 1000).")]
public int? Width { get; set; }

[Option("height", HelpText = "Canvas height (default is 1000).")]
public int? Height { get; set; }

[Option("padding", HelpText = "Canvas padding (default if 50).")]
public int? Padding { get; set; }

[Option("bgcolor", HelpText = "Background color (name or #RRGGBB).")]
public string BackgroundColor { get; set; }

[Option("textcolor", HelpText = "Text color (name or #RRGGBB).")]
public string TextColor { get; set; }

[Option("font", HelpText = "Font family name (e.g., Arial).")]
public string FontFamily { get; set; }

[Option("minsize", HelpText = "Minimum font size.")]
public float? MinFontSize { get; set; }

[Option("maxsize", HelpText = "Maximum font size.")]
public float? MaxFontSize { get; set; }
}
}
26 changes: 26 additions & 0 deletions TagCloudConsoleClient/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Autofac;
using TagCloudGenerator.Core.Interfaces;
using TagCloudGenerator.DI;
using TagCloudGenerator.Infrastructure.Filters;

namespace TagCloudConsoleClient
{
public class Program
{
public static void Main(string[] args)
{
var builder = new ContainerBuilder();

builder.RegisterModule<TagCloudModule>();
builder.RegisterType<NullWordsFilter>().As<IFilter>();
builder.RegisterType<BoringWordsFilter>().As<IFilter>();
builder.RegisterType<ConsoleClient>().As<IClient>();

var container = builder.Build();

using var scope = container.BeginLifetimeScope();
var client = scope.Resolve<IClient>();
client.Run(args);
}
}
}
14 changes: 14 additions & 0 deletions TagCloudConsoleClient/TagCloudConsoleClient.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\TagCloudGenerator\TagCloudGenerator.csproj" />
</ItemGroup>

</Project>
90 changes: 90 additions & 0 deletions TagCloudGenerator/Algorithms/BasicTagCloudAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System.Drawing;
using TagCloudGenerator.Core.Interfaces;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Algorithms
{
public class BasicTagCloudAlgorithm : ITagCloudAlgorithm
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 нужен

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Обновил

{
private Point center;

private readonly List<Rectangle> rectangles = new List<Rectangle>();

private double currentAngle = 0;
private double currentRadius = 0;

private double angleStep = 0.1;
private double radiusStep = 0.5;

public BasicTagCloudAlgorithm(Point center)
{
if (center.X < 0 || center.Y < 0)
center = new Point(0, 0);

this.center = center;
}

public BasicTagCloudAlgorithm()
{
center = new Point(0, 0);
}

public Result<Rectangle> PutNextRectangle(Size rectangleSize)
{
if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0)
return Result.Fail<Rectangle>("Rectangle sizes must be positives");

if (rectangles.Count == 0)
{
return Result.Ok(PutFirstRectangle(rectangleSize));
}

return Result.Ok(PlaceNextRectangle(rectangleSize));
}

private Rectangle PlaceNextRectangle(Size rectangleSize)
{
while (true)
{
double x = center.X + currentRadius * Math.Cos(currentAngle);
double y = center.Y + currentRadius * Math.Sin(currentAngle);

var potentialCenter = new Point((int)(x - rectangleSize.Width / 2), (int)(y - rectangleSize.Height / 2));
var potentialRectangle = new Rectangle(potentialCenter, rectangleSize);

if (!IntersectWithAny(potentialRectangle))
{
rectangles.Add(potentialRectangle);
return potentialRectangle;
}

currentAngle += angleStep;
if (currentAngle >= 2 * Math.PI)
{
currentAngle = 0;
currentRadius += radiusStep;
}
}
}

private bool IntersectWithAny(Rectangle potentialRectangle)
{
return rectangles.Any(rect => rect.IntersectsWith(potentialRectangle));
}

private Rectangle PutFirstRectangle(Size rectangleSize)
{
var firstCenter = new Point((int)(center.X - rectangleSize.Width / 2), (int)(center.Y - rectangleSize.Width / 2));
var first = new Rectangle(firstCenter, rectangleSize);
currentRadius = rectangleSize.Height / 2;
rectangles.Add(first);
return first;
}

public ITagCloudAlgorithm Reset()
{
rectangles.Clear();
return this;
}
}
}
10 changes: 10 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using TagCloudGenerator.Core.Models;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface IAnalyzer
{
Result<WordsWithFrequency> Analyze(List<string> words);
}
}
8 changes: 8 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

namespace TagCloudGenerator.Core.Interfaces
{
public interface IClient
{
void Run(string[] args);
}
}
11 changes: 11 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface IFilter
{
Result<List<string>> Filter(List<string> words);

bool ShouldInclude(string word);
}
}
8 changes: 8 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IFontSizeCalculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

namespace TagCloudGenerator.Core.Interfaces
{
public interface IFontSizeCalculator
{
float Calculate(int wordFrequency, int minFrequency, int maxFrequency, float minFontSize, float maxFontSize);
}
}
10 changes: 10 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IFormatReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface IFormatReader
{
bool CanRead(string filePath);
Result<List<string>> TryRead(string filePath);
}
}
9 changes: 9 additions & 0 deletions TagCloudGenerator/Core/Interfaces/INormalizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface INormalizer
{
public Result<List<string>> Normalize(List<string> words);
}
}
9 changes: 9 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IReaderRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface IReaderRepository
{
public Result<IFormatReader> TryGetReader(string filePath);
}
}
11 changes: 11 additions & 0 deletions TagCloudGenerator/Core/Interfaces/IRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Drawing;
using TagCloudGenerator.Core.Models;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface IRenderer
{
public Result<Bitmap> Render(IEnumerable<CloudItem> items, CanvasSettings canvasSettings, TextSettings textSettings);
}
}
10 changes: 10 additions & 0 deletions TagCloudGenerator/Core/Interfaces/ISorter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using TagCloudGenerator.Core.Models;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface ISorter
{
public Result<WordsWithFrequency> Sort(WordsWithFrequency wordsWithFreqs);
}
}
12 changes: 12 additions & 0 deletions TagCloudGenerator/Core/Interfaces/ITagCloudAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Drawing;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface ITagCloudAlgorithm
{
Result<Rectangle> PutNextRectangle(Size rectangleSize);

public ITagCloudAlgorithm Reset();
}
}
11 changes: 11 additions & 0 deletions TagCloudGenerator/Core/Interfaces/ITagCloudGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Drawing;
using TagCloudGenerator.Core.Models;
using TagCloudGenerator.Infrastructure;

namespace TagCloudGenerator.Core.Interfaces
{
public interface ITagCloudGenerator
{
public Result<List<CloudItem>> Generate(List<string> words, CanvasSettings canvasSettings, TextSettings textSettings, ICollection<IFilter> filters);
}
}
Loading