From 4b1e5b8a2b533cf3a04b26b9b90c1629db8feef1 Mon Sep 17 00:00:00 2001 From: Arnaut Date: Wed, 12 May 2021 19:13:17 +0200 Subject: [PATCH 1/2] Added Bresenham line algorithm for one octant --- Assets/Scripts/ServerShared/ItemData.cs | 26 ++++++++++++++++++ Assets/Scripts/Tests/BresenhamTest.cs | 31 ++++++++++++++++++++++ Assets/Scripts/Tests/BresenhamTest.cs.meta | 11 ++++++++ 3 files changed, 68 insertions(+) create mode 100644 Assets/Scripts/Tests/BresenhamTest.cs create mode 100644 Assets/Scripts/Tests/BresenhamTest.cs.meta diff --git a/Assets/Scripts/ServerShared/ItemData.cs b/Assets/Scripts/ServerShared/ItemData.cs index 9bb1521ba..687e1af7c 100644 --- a/Assets/Scripts/ServerShared/ItemData.cs +++ b/Assets/Scripts/ServerShared/ItemData.cs @@ -217,6 +217,32 @@ public class Shape position = int2.zero; return false; } + + // Set every cell on the line from a to b to true according to Bresenham's Line Algorithm + public void SetLine(float2 a, float2 b) + { + float dx = b.x - a.x; + float dy = b.y - a.y; + float derr = Math.Abs(dy / dx); // dx != 0 + float error = 0f; + int y = (int) Math.Round(a.y); + + for (int x = (int) Math.Round(a.x); x <= (int) Math.Round(b.x); x++) + { + if (x < Width && y < Height) + { + Cells[x, y] = true; + } + error += derr; + if (error >= 0.5f) + { + y += Math.Sign(dy); + error -= 1f; + } + } + + } + } [MessagePackObject, JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] diff --git a/Assets/Scripts/Tests/BresenhamTest.cs b/Assets/Scripts/Tests/BresenhamTest.cs new file mode 100644 index 000000000..b1b77ec5e --- /dev/null +++ b/Assets/Scripts/Tests/BresenhamTest.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Unity.Mathematics; + + + +class BresenhamTest +{ + + + + [Test] + public void ShapeTest() + { + Shape shape = new Shape(14, 6); + Console.WriteLine("test"); + shape.SetLine(new float2(0.6f, 0.6f), new float2(10.6f, 4.6f)); + + var coords = new[] { (1, 1), (2, 1), (3, 2), (4, 2), (5, 3), (6, 3), (7, 3), (8, 4), (9, 4), (10, 5), (11, 5)}; + foreach(var coord in coords) + { + Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); + } + } +} + + diff --git a/Assets/Scripts/Tests/BresenhamTest.cs.meta b/Assets/Scripts/Tests/BresenhamTest.cs.meta new file mode 100644 index 000000000..cf6e30a70 --- /dev/null +++ b/Assets/Scripts/Tests/BresenhamTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 108b8cc35b87da84c8671ee8f9386799 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From c2a3555f607d929c13952d4494a9746ebad3c66b Mon Sep 17 00:00:00 2001 From: Arnaut Date: Fri, 14 May 2021 11:41:30 +0200 Subject: [PATCH 2/2] Finished Bresenham algorithm for all cases --- Assets/Scripts/ServerShared/ItemData.cs | 31 ++++++++++-- Assets/Scripts/Tests/BresenhamTest.cs | 67 +++++++++++++++++++++---- 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/Assets/Scripts/ServerShared/ItemData.cs b/Assets/Scripts/ServerShared/ItemData.cs index 687e1af7c..a3085135a 100644 --- a/Assets/Scripts/ServerShared/ItemData.cs +++ b/Assets/Scripts/ServerShared/ItemData.cs @@ -221,17 +221,40 @@ public class Shape // Set every cell on the line from a to b to true according to Bresenham's Line Algorithm public void SetLine(float2 a, float2 b) { + if (a.Equals(b)) + { + return; + } + + // If line gradient is steep, swap x and y + bool steep = Math.Abs(b.y - a.y) > Math.Abs(b.x - a.x); + if (steep) + { + a = new float2(a.y, a.x); + b = new float2(b.y, b.x); + } + + // If b is closer to the origin than a, swap a and b. + if (a.x > b.x) + { + var temp = a; + a = b; + b = temp; + } + float dx = b.x - a.x; float dy = b.y - a.y; float derr = Math.Abs(dy / dx); // dx != 0 - float error = 0f; + int y = (int) Math.Round(a.y); + int xStart = (int) Math.Round(a.x); + float error = (a.y - y) + (xStart - a.x) * derr; - for (int x = (int) Math.Round(a.x); x <= (int) Math.Round(b.x); x++) + for (int x = xStart; x <= (int) Math.Round(b.x); x++) { - if (x < Width && y < Height) + if (x >= 0 && x < Width && y >= 0 && y < Height) { - Cells[x, y] = true; + Cells[steep ? y : x, steep ? x : y] = true; } error += derr; if (error >= 0.5f) diff --git a/Assets/Scripts/Tests/BresenhamTest.cs b/Assets/Scripts/Tests/BresenhamTest.cs index b1b77ec5e..a8d9f7216 100644 --- a/Assets/Scripts/Tests/BresenhamTest.cs +++ b/Assets/Scripts/Tests/BresenhamTest.cs @@ -9,23 +9,72 @@ using Unity.Mathematics; class BresenhamTest -{ - - - +{ [Test] - public void ShapeTest() + public void LowPositiveGradientTest() { - Shape shape = new Shape(14, 6); - Console.WriteLine("test"); - shape.SetLine(new float2(0.6f, 0.6f), new float2(10.6f, 4.6f)); + Shape shape = new Shape(7, 7); + shape.SetLine(new float2(1, 1f), new float2(6f, 3f)); - var coords = new[] { (1, 1), (2, 1), (3, 2), (4, 2), (5, 3), (6, 3), (7, 3), (8, 4), (9, 4), (10, 5), (11, 5)}; + var coords = new[] { (1, 1), (2, 1), (3, 2), (4, 2), (5, 3), (6, 3)}; foreach(var coord in coords) { Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); } } + + [Test] + public void LowNegativeGradientTest() + { + Shape shape = new Shape(5, 5); + shape.SetLine(new float2(-2f, 4f), new float2(3f, 2f)); + + var coords = new[] { (0, 3), (1, 3), (2, 2), (3, 2)}; + foreach (var coord in coords) + { + Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); + } + } + + [Test] + public void HighPositiveGradientTest() + { + Shape shape = new Shape(4, 4); + shape.SetLine(new float2(1f, 3f), new float2(0f, 0f)); + + var coords = new[] { (0, 0), (0, 1), (1, 2), (1, 3) }; + foreach (var coord in coords) + { + Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); + } + } + + [Test] + public void FloatingPointYTest() + { + Shape shape = new Shape(7, 7); + shape.SetLine(new float2(0.6f, 1.4f), new float2(6f, 2.6f)); + + var coords = new[] { (1, 1), (2, 2), (3, 2), (4, 2), (5, 2), (6, 3) }; + foreach (var coord in coords) + { + Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); + } + } + + + [Test] + public void FloatingPointXTest() + { + Shape shape = new Shape(7, 7); + shape.SetLine(new float2(0.6f, 1f), new float2(5.6f, 3f)); + + var coords = new[] { (1, 1), (2, 2), (3, 2), (4, 2), (5, 3), (6, 3) }; + foreach (var coord in coords) + { + Assert.True(shape.Cells[coord.Item1, coord.Item2], $"{coord.Item1}, {coord.Item2}"); + } + } }