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

Козлов Двнил #196

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
12149fb
added file reader
SenyaPevko Jan 23, 2024
83d1aa6
added text parser
SenyaPevko Jan 23, 2024
ec0dca0
added tag builder
SenyaPevko Jan 23, 2024
29f1d22
added form pointer
SenyaPevko Jan 23, 2024
b15fdc1
added cloud layouter
SenyaPevko Jan 23, 2024
ee64719
added cloud drawer
SenyaPevko Jan 23, 2024
b0950ba
added tests
SenyaPevko Jan 23, 2024
ceb1207
added application
SenyaPevko Jan 23, 2024
45c5d7f
refactored code
SenyaPevko Jan 23, 2024
b385a92
TagsCloudSettings now can't have nullable fields
SenyaPevko Jan 26, 2024
afa5144
added laziness instead of initialization
SenyaPevko Jan 26, 2024
2c1e9fe
now every constructor throws null exception if null reference was passed
SenyaPevko Jan 26, 2024
b0c310a
now every constructor throws null exception if null reference was pas
SenyaPevko Jan 26, 2024
7193c85
refactored
SenyaPevko Jan 26, 2024
1d5b6eb
settings now loaded from settings file
SenyaPevko Jan 26, 2024
b74c843
refactored
SenyaPevko Jan 26, 2024
dad1000
settings added to config
SenyaPevko Jan 27, 2024
b743802
refactored
SenyaPevko Jan 27, 2024
af17557
added di tests
SenyaPevko Jan 27, 2024
6dd0cd7
refactored
SenyaPevko Jan 27, 2024
3a801dd
app settings now passed through container
SenyaPevko Jan 27, 2024
49959c5
refactored exceptions throwing
SenyaPevko Jan 28, 2024
74c891e
added app settings into di tests
SenyaPevko Jan 28, 2024
47ec8ee
now actions can be empty
SenyaPevko Jan 28, 2024
1b9fe40
refactored after feedback
SenyaPevko Jan 31, 2024
eae835c
files now copied to solution directory
SenyaPevko Feb 1, 2024
5a12d34
images are now saved with format
SenyaPevko Feb 1, 2024
52e1d87
cloud now stores list of tuples and layouter now doesn't have laziness
SenyaPevko Feb 1, 2024
6c8155c
cloud settings now use app settings
SenyaPevko Feb 1, 2024
f41c88d
changed file readers logic
SenyaPevko Feb 1, 2024
43d00cd
added interfaces for settings
SenyaPevko Feb 1, 2024
4f024d3
added interface for cloud drawer
SenyaPevko Feb 1, 2024
e463cc4
cleaned up
SenyaPevko Feb 1, 2024
944d472
added gif and bmp formats for image saving
SenyaPevko Feb 1, 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
55 changes: 55 additions & 0 deletions TagsCloudPainter/CloudDrawer/CloudDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using TagsCloudPainter.Settings;

namespace TagsCloudPainter.Drawer;

public class CloudDrawer
{
private readonly CloudSettings cloudSettings;
private readonly TagSettings tagSettings;

public CloudDrawer(TagSettings tagSettings, CloudSettings cloudSettings)
{
this.tagSettings = tagSettings ?? throw new ArgumentNullException(nameof(tagSettings));
this.cloudSettings = cloudSettings ?? throw new ArgumentNullException(nameof(cloudSettings));
}

public Bitmap DrawCloud(TagsCloud cloud, int imageWidth, int imageHeight)
{
if (cloud.Tags.Count == 0)
throw new ArgumentException("rectangles are empty");
if (imageWidth <= 0 || imageHeight <= 0)
throw new ArgumentException("either width or height of rectangle size is not positive");

var drawingScale = CalculateObjectDrawingScale(cloud.GetWidth(), cloud.GetHeight(), imageWidth, imageHeight);
var bitmap = new Bitmap(imageWidth, imageHeight);
var graphics = Graphics.FromImage(bitmap);
var pen = new Pen(tagSettings.TagColor);
LevShisterov marked this conversation as resolved.
Show resolved Hide resolved

graphics.TranslateTransform(-cloud.Center.X, -cloud.Center.Y);
graphics.ScaleTransform(drawingScale, drawingScale, MatrixOrder.Append);
graphics.TranslateTransform(cloud.Center.X, cloud.Center.Y, MatrixOrder.Append);
graphics.Clear(cloudSettings.BackgroundColor);
foreach (var tag in cloud.Tags)
{
var font = new Font(tagSettings.TagFontName, tag.Key.FontSize);
graphics.DrawString(tag.Key.Value, font, pen.Brush, tag.Value.Location);
}

return bitmap;
}

public static float CalculateObjectDrawingScale(float width, float height, float imageWidth, float imageHeight)
{
var scale = 1f;
var scaleAccuracy = 0.05f;
var widthScale = scale;
var heightScale = scale;
if (width * scale > imageWidth)
widthScale = imageWidth / width - scaleAccuracy;
if (height * scale > imageHeight)
heightScale = imageHeight / height - scaleAccuracy;
return Math.Min(widthScale, heightScale);
}
}
11 changes: 11 additions & 0 deletions TagsCloudPainter/CloudLayouter/ICloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Drawing;
using TagsCloudPainter.Tags;

namespace TagsCloudPainter.CloudLayouter;

public interface ICloudLayouter : IResetable
{
Rectangle PutNextTag(Tag tag);
TagsCloud GetCloud();
void PutTags(List<Tag> tags);
}
61 changes: 61 additions & 0 deletions TagsCloudPainter/CloudLayouter/TagsCloudLayouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Drawing;
using TagsCloudPainter.FormPointer;
using TagsCloudPainter.Settings;
using TagsCloudPainter.Tags;

namespace TagsCloudPainter.CloudLayouter;

public class TagsCloudLayouter : ICloudLayouter
{
private readonly Lazy<CloudSettings> cloudSettings;
private readonly IFormPointer formPointer;
private readonly TagSettings tagSettings;
private TagsCloud cloud;

public TagsCloudLayouter(Lazy<CloudSettings> cloudSettings, IFormPointer formPointer, TagSettings tagSettings)
{
this.cloudSettings = cloudSettings ?? throw new ArgumentNullException(nameof(cloudSettings));
this.formPointer = formPointer ?? throw new ArgumentNullException(nameof(formPointer));
this.tagSettings = tagSettings ?? throw new ArgumentNullException(nameof(tagSettings));
}

private TagsCloud Cloud
{
get => cloud ??= new TagsCloud(cloudSettings.Value.CloudCenter, []);
set => cloud = value;
}
LevShisterov marked this conversation as resolved.
Show resolved Hide resolved

public Rectangle PutNextTag(Tag tag)
{
var rectangleSize = Utils.Utils.GetStringSize(tag.Value, tagSettings.TagFontName, tag.FontSize);
if (rectangleSize.Height <= 0 || rectangleSize.Width <= 0)
throw new ArgumentException("either width or height of rectangle size is not possitive");

var nextRectangle = Utils.Utils.GetRectangleFromCenter(formPointer.GetNextPoint(), rectangleSize);
while (Cloud.Tags.Values.Any(rectangle => rectangle.IntersectsWith(nextRectangle)))
nextRectangle = Utils.Utils.GetRectangleFromCenter(formPointer.GetNextPoint(), rectangleSize);

Cloud.AddTag(tag, nextRectangle);

return nextRectangle;
}

public void PutTags(List<Tag> tags)
{
if (tags.Count == 0)
throw new ArgumentException("пустые размеры");
foreach (var tag in tags)
PutNextTag(tag);
}

public TagsCloud GetCloud()
{
return new TagsCloud(Cloud.Center, Cloud.Tags);
}

public void Reset()
{
formPointer.Reset();
Cloud = new TagsCloud(cloudSettings.Value.CloudCenter, []);
}
}
6 changes: 6 additions & 0 deletions TagsCloudPainter/FileReader/IFileReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloudPainter.FileReader;

public interface IFileReader
{
public string ReadFile(string path);
}
34 changes: 34 additions & 0 deletions TagsCloudPainter/FileReader/TextFileReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Spire.Doc;

namespace TagsCloudPainter.FileReader;

public class TextFileReader : IFileReader
{
public string ReadFile(string path)
{
if (!File.Exists(path))
throw new FileNotFoundException();

return Path.GetExtension(path) switch
{
".txt" => ReadTxtFile(path),
".doc" => ReadDocFile(path),
".docx" => ReadDocFile(path),
_ => throw new ArgumentException("Incorrect file extension. Supported file extensions: txt, doc, docx")
};
}

private static string ReadTxtFile(string path)
{
return File.ReadAllText(path).Trim();
}

private static string ReadDocFile(string path)
{
var doc = new Document();
doc.LoadFromFile(path);
var text = doc.GetText();
var lastIndexOfSpirePart = text.IndexOf(Environment.NewLine);
return text.Substring(lastIndexOfSpirePart + 2).Trim();
}
LevShisterov marked this conversation as resolved.
Show resolved Hide resolved
}
40 changes: 40 additions & 0 deletions TagsCloudPainter/FormPointer/ArchimedeanSpiralPointer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Drawing;
using TagsCloudPainter.Settings;

namespace TagsCloudPainter.FormPointer;

public class ArchimedeanSpiralPointer : IFormPointer
{
private readonly CloudSettings cloudSettings;
private readonly SpiralPointerSettings spiralPointerSettings;
private double сurrentDifference;

public ArchimedeanSpiralPointer(CloudSettings cloudSettings, SpiralPointerSettings spiralPointerSettings)
{
if (spiralPointerSettings.Step <= 0
|| spiralPointerSettings.RadiusConst <= 0
|| spiralPointerSettings.AngleConst <= 0)
throw new ArgumentException("either step or radius or angle is not possitive");
this.cloudSettings = cloudSettings ?? throw new ArgumentNullException(nameof(cloudSettings));
this.spiralPointerSettings =
spiralPointerSettings ?? throw new ArgumentNullException(nameof(spiralPointerSettings));
сurrentDifference = 0;
}

private double Angle => сurrentDifference * spiralPointerSettings.AngleConst;
private double Radius => сurrentDifference * spiralPointerSettings.RadiusConst;

public Point GetNextPoint()
{
сurrentDifference += spiralPointerSettings.Step;
var x = cloudSettings.CloudCenter.X + (int)(Radius * Math.Cos(Angle));
var y = cloudSettings.CloudCenter.Y + (int)(Radius * Math.Sin(Angle));

return new Point(x, y);
}

public void Reset()
{
сurrentDifference = 0;
}
}
8 changes: 8 additions & 0 deletions TagsCloudPainter/FormPointer/IFormPointer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Drawing;

namespace TagsCloudPainter.FormPointer;

public interface IFormPointer : IResetable
{
Point GetNextPoint();
}
6 changes: 6 additions & 0 deletions TagsCloudPainter/IResetable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloudPainter;

public interface IResetable
{
void Reset();
}
32 changes: 32 additions & 0 deletions TagsCloudPainter/Parser/BoringTextParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using TagsCloudPainter.Settings;

namespace TagsCloudPainter.Parser;

public class BoringTextParser : ITextParser
{
private static readonly string[] _separators = [" ", ". ", ", ", "; ", "-", "—", Environment.NewLine];
private readonly TextSettings textSettings;

public BoringTextParser(TextSettings textSettings)
{
this.textSettings = textSettings ?? throw new ArgumentNullException(nameof(textSettings));
}

public List<string> ParseText(string text)
{
var boringWords = GetBoringWords(textSettings.BoringText);
var words = text.Split(_separators, StringSplitOptions.RemoveEmptyEntries);
return words.Select(word => word.ToLower()).Where(word => !boringWords.Contains(word)).ToList();
}

public HashSet<string> GetBoringWords(string text)
{
var words = text.Split(Environment.NewLine);
var boringWords = new HashSet<string>();

foreach (var word in words)
boringWords.Add(word.ToLower());

return boringWords;
}
}
6 changes: 6 additions & 0 deletions TagsCloudPainter/Parser/ITextParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloudPainter.Parser;

public interface ITextParser
{
List<string> ParseText(string text);
}
9 changes: 9 additions & 0 deletions TagsCloudPainter/Settings/CloudSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Drawing;

namespace TagsCloudPainter.Settings;

public class CloudSettings
{
public Point CloudCenter { get; set; }
public Color BackgroundColor { get; set; }
}
8 changes: 8 additions & 0 deletions TagsCloudPainter/Settings/SpiralPointerSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TagsCloudPainter.Settings;

public class SpiralPointerSettings
{
public double Step { get; set; } = 1;
public double RadiusConst { get; set; } = 1;
public double AngleConst { get; set; } = 1;
}
10 changes: 10 additions & 0 deletions TagsCloudPainter/Settings/TagSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Drawing;

namespace TagsCloudPainter.Settings;

public class TagSettings
{
public int TagFontSize { get; set; }
public string TagFontName { get; set; } = "Arial";
public Color TagColor { get; set; }
}
6 changes: 6 additions & 0 deletions TagsCloudPainter/Settings/TextSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloudPainter.Settings;

public class TextSettings
{
public string BoringText { get; set; } = string.Empty;
}
6 changes: 6 additions & 0 deletions TagsCloudPainter/Tags/ITagsBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TagsCloudPainter.Tags;

public interface ITagsBuilder
{
public List<Tag> GetTags(List<string> words);
}
15 changes: 15 additions & 0 deletions TagsCloudPainter/Tags/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace TagsCloudPainter.Tags;

public class Tag
{
public Tag(string value, float fontSize, int count)
{
Value = value ?? "";
LevShisterov marked this conversation as resolved.
Show resolved Hide resolved
FontSize = fontSize;
Count = count;
}

public string Value { get; private set; }
public float FontSize { get; private set; }
public int Count { get; private set; }
}
44 changes: 44 additions & 0 deletions TagsCloudPainter/Tags/TagsBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using TagsCloudPainter.Settings;

namespace TagsCloudPainter.Tags;

public class TagsBuilder : ITagsBuilder
{
private readonly TagSettings _settings;

public TagsBuilder(TagSettings settings)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
}

public List<Tag> GetTags(List<string> words)
{
var countedWords = CountWords(words);
var tags = new List<Tag>();

foreach (var wordWithCount in countedWords)
{
var tagFontSize = GetTagFontSize(_settings.TagFontSize, wordWithCount.Value, countedWords.Count);
var tag = new Tag(wordWithCount.Key, tagFontSize, wordWithCount.Value);
tags.Add(tag);
}

return tags;
}

private static Dictionary<string, int> CountWords(List<string> words)
{
var countedWords = new Dictionary<string, int>();

foreach (var word in words)
if (!countedWords.TryAdd(word, 1))
countedWords[word] += 1;

return countedWords;
}

private static float GetTagFontSize(int fontSize, int tagCount, int wordsAmount)
{
return (float)tagCount / wordsAmount * fontSize * 100;
}
}
Loading