-
Notifications
You must be signed in to change notification settings - Fork 307
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
Рушкова Ольга #254
Open
SomEnaMeforme
wants to merge
25
commits into
kontur-courses:master
Choose a base branch
from
SomEnaMeforme:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Рушкова Ольга #254
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
8cae611
AddNearestFinder
09cf278
Add CircularLayer
9bbe39a
Add CircularCloudLayoter
dfbc811
Add Direction
9f88c15
Fix calculation radius
ce6db8c
Add move to next sector when find position without intersection
517ccb0
Add intersections and small fix
3761068
Refactoring: replace validation in layoter, fix tests
4ec2ddc
Remove usless saving
fe8c9fe
Refactoring: add RectangleStorage
d661efd
Refactoring: add using storage
e4ca17d
Fix: changing rectangle should change rectangle in storage
8dff187
Add move closer to center
6f70c9d
Fix radius recalculate and intersection multiplier, add visualisation
a4217c3
Small fix
051cb3a
Refactoring: remove dublicate tests
9879db0
Refactoring And Fix infinite cicle when find position for new rectangle
badf496
Add results for random generated data
23112ec
fix filepath
80508bb
Add third task
3eb403a
Fix visualizer and add .csproj
cb4cb27
Fix naming
9d33c50
Replace DrawGrid to extensions
d4550a0
Remove storage
067800a
Fix intelisense and add compressor
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Drawing; | ||
using System.Linq; | ||
using System.Runtime.InteropServices.ComTypes; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace TagsCloudVisualization | ||
{ | ||
public class BruteForceNearestFinder | ||
{ | ||
private List<Rectangle> rectangles = new(); | ||
|
||
public void Insert(Rectangle r) | ||
{ | ||
if (RectangleHasInсorrectSize(r)) | ||
throw new ArgumentException($"Rectangle has incorrect size: width = {r.Width}, height = {r.Height}"); | ||
rectangles.Add(r); | ||
} | ||
|
||
public Rectangle? FindNearestByDirection(Rectangle r, Direction direction) | ||
{ | ||
if (RectangleHasInсorrectSize(r)) | ||
throw new ArgumentException($"Rectangle has incorrect size: width= {r.Width}, height={r.Height}"); | ||
if (rectangles.Count == 0) | ||
return null; | ||
var calculator = GetMinDistanceCalculatorBy(direction); | ||
return rectangles.Select(currentRectangle => (distance: calculator(currentRectangle, r), CurrentEl: currentRectangle)) | ||
.Where(el => el.distance > 0) | ||
.MinBy(el => el.distance).CurrentEl; | ||
} | ||
|
||
private Func<Rectangle, Rectangle, int> GetMinDistanceCalculatorBy(Direction direction) | ||
{ | ||
switch (direction) | ||
{ | ||
case Direction.Left: return (possibleNearest, rectangleForFind) => rectangleForFind.X - possibleNearest.X; | ||
case Direction.Right: return (possibleNearest, rectangleForFind) => possibleNearest.X - rectangleForFind.X; | ||
case Direction.Top: return (possibleNearest, rectangleForFind) => rectangleForFind.Y - possibleNearest.Y; | ||
default: return (possibleNearest, rectangleForFind) => possibleNearest.Y - rectangleForFind.Y; | ||
} | ||
} | ||
|
||
private bool RectangleHasInсorrectSize(Rectangle r) | ||
{ | ||
return r.Width <= 0 || r.Height <= 0; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
using System.Drawing; | ||
|
||
namespace TagsCloudVisualization; | ||
|
||
public class CircleLayer | ||
{ | ||
public enum Sector | ||
{ | ||
Top_Right, | ||
Bottom_Right, | ||
Bottom_Left, | ||
Top_Left | ||
} | ||
|
||
public Point Center { get; } | ||
public int Radius { get; } | ||
|
||
|
||
private Sector currentSector; | ||
private readonly List<Rectangle> layerRectangles; | ||
private CircleLayer prevLayer; | ||
|
||
public CircleLayer(Point center, int radius) | ||
{ | ||
Center = center; | ||
Radius = radius; | ||
currentSector = Sector.Top_Right; | ||
layerRectangles = new List<Rectangle>(); | ||
} | ||
|
||
public CircleLayer OnSuccessInsertRectangle(Rectangle inserted) | ||
{ | ||
currentSector = currentSector == Sector.Top_Left ? Sector.Top_Right : currentSector + 1; | ||
layerRectangles.Add(inserted); | ||
if (currentSector == Sector.Top_Right) | ||
return CreateNextLayer(); | ||
return this; | ||
} | ||
|
||
private CircleLayer CreateNextLayer() | ||
{ | ||
var nextLayer = new CircleLayer(Center, CalculateRadiusForNextLayer()); | ||
nextLayer.prevLayer = this; | ||
return nextLayer; | ||
} | ||
|
||
private int CalculateRadiusForNextLayer() | ||
{ | ||
var prevSector = Sector.Top_Right - 1; | ||
return layerRectangles.Select(r => CalculateDistanceBetweenCenterAndRectangleBySector(r, prevSector + 1)).Max(); | ||
} | ||
|
||
private int CalculateDistanceBetweenCenterAndRectangleBySector(Rectangle r, Sector s) | ||
{ | ||
switch (s) | ||
{ | ||
case Sector.Top_Right: | ||
return CalculateDistanceBetweenPoints(Center, new Point(r.X + r.Width, r.Y)); | ||
case Sector.Bottom_Right: | ||
return CalculateDistanceBetweenPoints(Center, new Point(r.X + r.Width, r.Y + r.Height)); | ||
case Sector.Bottom_Left: | ||
return CalculateDistanceBetweenPoints(Center, new Point(r.X - r.Width, r.Y + r.Height)); | ||
default: | ||
return CalculateDistanceBetweenPoints(Center, new Point(r.X - r.Width, r.Y)); | ||
} | ||
} | ||
|
||
private int CalculateDistanceBetweenPoints(Point p1, Point p2) | ||
{ | ||
return (int)Math.Ceiling(Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y))); | ||
} | ||
|
||
public Point CalculateTopLeftRectangleCornerPosition(Size rectangleSize) | ||
{ | ||
var relevantForSectorPosition = GetPositionRelevantForSector(); | ||
switch (currentSector) | ||
{ | ||
case Sector.Top_Right: | ||
return new Point(relevantForSectorPosition.X, relevantForSectorPosition.Y - rectangleSize.Height); | ||
case Sector.Bottom_Right: | ||
return relevantForSectorPosition; | ||
case Sector.Bottom_Left: | ||
return new Point(relevantForSectorPosition.X - rectangleSize.Width, relevantForSectorPosition.Y); | ||
default: | ||
return new Point(relevantForSectorPosition.X - rectangleSize.Width, | ||
relevantForSectorPosition.Y - rectangleSize.Height); | ||
} | ||
} | ||
|
||
private Point GetPositionRelevantForSector() | ||
{ | ||
switch (currentSector) | ||
{ | ||
case Sector.Top_Right: | ||
return new Point(Center.X, Center.Y - Radius); | ||
case Sector.Bottom_Right: | ||
return new Point(Center.X + Radius, Center.Y); | ||
case Sector.Bottom_Left: | ||
return new Point(Center.X, Center.Y + Radius); | ||
default: | ||
return new Point(Center.X - Radius, Center.Y); | ||
} | ||
} | ||
|
||
public Point GetRectanglePositionWithoutIntersection(Rectangle forInsertion, Rectangle intersected) | ||
{ | ||
return CalculateNewPositionWithoutIntersectionBySector(currentSector, forInsertion, intersected); | ||
} | ||
|
||
private Point CalculateNewPositionWithoutIntersectionBySector(Sector s, Rectangle forInsertion, Rectangle intersected) | ||
{ | ||
var distanceForMoving = CalculateDistanceForMovingBySector(s, forInsertion, intersected); | ||
var isMovingAxisIsX = IsMovingAxisIsXBySector(s); | ||
var nearestForCenterCorner = | ||
CalculateCornerNearestForCenterAfterMove(s, distanceForMoving, forInsertion); | ||
var distanceForBringBackOnCircle = | ||
CalculateDeltaForBringRectangleBackOnCircle(nearestForCenterCorner, isMovingAxisIsX); | ||
distanceForMoving *= CalculateMoveMultiplierForMoveClockwise(isMovingAxisIsX, forInsertion); | ||
distanceForBringBackOnCircle *= CalculateMoveMultiplierForMoveFromCenter(!isMovingAxisIsX, forInsertion); | ||
return isMovingAxisIsX | ||
? new Point(forInsertion.X + distanceForMoving, forInsertion.Y + distanceForBringBackOnCircle) | ||
: new Point(forInsertion.X + distanceForBringBackOnCircle, forInsertion.Y + distanceForMoving); | ||
} | ||
|
||
private int CalculateDeltaForBringRectangleBackOnCircle(Point nearestForCenterCorner, bool isMovingAxisIsX) | ||
{ | ||
Func<Point, int> getAxisForBringBackOnCircle = isMovingAxisIsX ? p => p.Y : p => p.X; | ||
Func<Point, int> getStaticAxis = isMovingAxisIsX ? p => p.X : p => p.Y; | ||
|
||
var distanceOnStaticAxis = Math.Abs(getStaticAxis(nearestForCenterCorner) - getStaticAxis(Center)); | ||
var distanceOnAxisForBringBackOnCircle = Math.Abs(getAxisForBringBackOnCircle(nearestForCenterCorner) - getAxisForBringBackOnCircle(Center)); | ||
return (int)Math.Ceiling(Math.Sqrt(Radius * Radius - distanceOnStaticAxis * distanceOnStaticAxis)) - distanceOnAxisForBringBackOnCircle; | ||
} | ||
|
||
private Point CalculateCornerNearestForCenterAfterMove(Sector s, int distanceForMoving, Rectangle r) | ||
{ | ||
var isAxisForMoveIsX = IsMovingAxisIsXBySector(s); | ||
var moveMultiplier = CalculateMoveMultiplierForMoveClockwise(isAxisForMoveIsX, r); | ||
distanceForMoving *= moveMultiplier; | ||
var nearestCorner = GetCornerNearestForCenterBySector(s, r); | ||
return isAxisForMoveIsX | ||
? new Point(nearestCorner.X + distanceForMoving, nearestCorner.Y) | ||
: new Point(nearestCorner.X, nearestCorner.Y + distanceForMoving); | ||
} | ||
|
||
private int CalculateMoveMultiplierForMoveFromCenter(bool isAxisForMoveIsX, Rectangle r) | ||
{ | ||
return isAxisForMoveIsX | ||
? r.Right < Center.X ? -1 : 1 | ||
: r.Bottom < Center.Y ? -1 : 1; | ||
} | ||
private int CalculateMoveMultiplierForMoveClockwise(bool isAxisForMoveIsX, Rectangle r) | ||
{ | ||
return isAxisForMoveIsX | ||
? r.Left > Center.X ? -1 : 1 | ||
: r.Bottom > Center.Y ? -1 : 1; | ||
} | ||
|
||
private int CalculateDistanceForMovingBySector (Sector s, Rectangle forInsertion, Rectangle intersected) | ||
{ | ||
switch (s) | ||
{ | ||
case Sector.Top_Right: | ||
return Math.Abs(forInsertion.Top - intersected.Bottom); | ||
case Sector.Bottom_Right: | ||
return Math.Abs(forInsertion.Right - intersected.Left); | ||
case Sector.Bottom_Left: | ||
return Math.Abs(forInsertion.Bottom - intersected.Top); | ||
default: | ||
return Math.Abs(forInsertion.Left - intersected.Right); | ||
} | ||
} | ||
|
||
private Point GetCornerNearestForCenterBySector(Sector s, Rectangle r) | ||
{ | ||
switch (s) | ||
{ | ||
case Sector.Top_Right: | ||
return new Point(r.Left, r.Bottom); | ||
case Sector.Bottom_Right: | ||
return new Point(r.Left, r.Top); | ||
case Sector.Bottom_Left: | ||
return new Point(r.Right, r.Top); | ||
default: | ||
return new Point(r.Right, r.Bottom); | ||
} | ||
} | ||
|
||
private bool IsMovingAxisIsXBySector(Sector s) | ||
{ | ||
return s == Sector.Bottom_Right || s == Sector.Top_Left; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Drawing; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace TagsCloudVisualization | ||
{ | ||
public class CircularCloudLayouter | ||
{ | ||
private List<Rectangle> rectanglesLocation = new (); | ||
private readonly Point center; | ||
private BruteForceNearestFinder nearestFinder; | ||
|
||
public CircleLayer CurrentLayer { get; private set; } | ||
|
||
public CircularCloudLayouter(Point center) | ||
{ | ||
this.center = center; | ||
nearestFinder = new BruteForceNearestFinder(); | ||
} | ||
public Rectangle PutNextRectangle(Size rectangleSize) | ||
{ | ||
Rectangle resultRectangle; | ||
if (IsFirstRectangle()) | ||
{ | ||
CreateFirstLayer(rectangleSize); | ||
resultRectangle = PutRectangleToCenter(rectangleSize); | ||
} | ||
else | ||
{ | ||
var possiblePosition = CurrentLayer.CalculateTopLeftRectangleCornerPosition(rectangleSize); | ||
resultRectangle = new Rectangle(possiblePosition, rectangleSize); | ||
} | ||
OnSuccessInsertion(resultRectangle); | ||
return resultRectangle; | ||
} | ||
|
||
private void OnSuccessInsertion(Rectangle r) | ||
{ | ||
rectanglesLocation.Add(r); | ||
nearestFinder.Insert(r); | ||
if (IsNotFirstInsertion()) | ||
CurrentLayer.OnSuccessInsertRectangle(r); | ||
} | ||
|
||
private void CreateFirstLayer(Size firstRectangle) | ||
{ | ||
var radius = Math.Ceiling(Math.Max(firstRectangle.Width, firstRectangle.Height) / 2.0); | ||
CurrentLayer = new CircleLayer(center, (int)radius); | ||
} | ||
|
||
private Rectangle PutRectangleToCenter(Size rectangleSize) | ||
{ | ||
var rectangleX = center.X - rectangleSize.Width / 2; | ||
var rectangleY = center.Y - rectangleSize.Height / 2; | ||
|
||
return new Rectangle(new Point(rectangleX, rectangleY), rectangleSize); | ||
} | ||
|
||
private bool IsFirstRectangle() | ||
{ | ||
return rectanglesLocation.Count == 0; | ||
} | ||
|
||
private bool IsNotFirstInsertion() | ||
{ | ||
return rectanglesLocation.Count > 1; | ||
} | ||
|
||
public IEnumerable<Rectangle> GetRectangles() | ||
{ | ||
foreach (var rectangle in rectanglesLocation) | ||
{ | ||
yield return rectangle; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace TagsCloudVisualization | ||
{ | ||
public enum Direction | ||
{ | ||
Left, | ||
Right, | ||
Top, | ||
Bottom | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Что с неймингом