Created
July 19, 2018 22:16
-
-
Save yzorg/1fda998f09dcec2e8b0add5f8ee3b645 to your computer and use it in GitHub Desktop.
programming coda: detect points on a line
This file contains hidden or 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
[ | |
{"x": 1, "y": 0 }, | |
{"x": 1, "y": 4 }, | |
{"x": 1, "y": 7 }, | |
{"x": 1.5, "y": 3 }, | |
{"x": 3, "y": 2 }, | |
{"x": 5, "y": 0 }, | |
{"x": 5, "y": 4 } | |
] |
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using Newtonsoft.Json; | |
//## Output | |
// starting PointsLines | |
//m:-1 b:5 has points: | |
// X:1.00 Y:04 | |
// X:3.00 Y:02 | |
// X:5.00 Y:00 | |
//m:1 b:-1 has points: | |
// X:1.00 Y:00 | |
// X:3.00 Y:02 | |
// X:5.00 Y:04 | |
//vertical line at x:1 has points: | |
// X:1.00 Y:00 | |
// X:1.00 Y:04 | |
// X:1.00 Y:07 | |
//Press any key to continue . . . | |
namespace PointsLines | |
{ | |
using static Console; | |
struct Point | |
{ | |
public float X { get; set; } | |
public float Y { get; set; } | |
public override string ToString() => | |
$"X:{X:0.00} Y:{Y:00}"; | |
} | |
class LineInfo : IComparable<LineInfo> | |
{ | |
/// <summary> | |
/// Per the spec document, the intersection with Y-axis is "+ b", but in .NET conventions members are capitalized. | |
/// </summary> | |
public float B { get; set; } | |
public float? Slope { get; set; } | |
/// <summary> | |
/// A vertical line has no Slope. | |
/// </summary> | |
public bool IsVertical => Slope == null; | |
/// <summary> | |
/// Vertical line has a fixed X. | |
/// </summary> | |
public float? VerticalX { get; set; } | |
public HashSet<int> PointIndexes { get; } = new HashSet<int>(); | |
public bool HasMultipleMatches => PointIndexes.Count > 2; | |
public int CompareTo(LineInfo other) | |
{ | |
if (other == null) | |
return 1; | |
if (IsVertical != other.IsVertical) | |
return Comparer<bool>.Default.Compare(IsVertical, other.IsVertical); | |
if (IsVertical && other.IsVertical) | |
return Comparer<float>.Default.Compare(VerticalX ?? float.MinValue, other.VerticalX ?? float.MinValue); | |
if (Slope.HasValue && other.Slope.HasValue && Slope != other.Slope) | |
return Comparer<float>.Default.Compare(Slope.Value, other.Slope.Value); | |
return Comparer<float>.Default.Compare(B, other.B); | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
WriteLine($"starting {nameof(PointsLines)}"); | |
var app = new Program(); | |
#if DEBUG | |
const string jsonFile = "../../../points.json"; // skip bin\Debug\netcoreapp2.0 when running from IDE (Visual Studio or Code) | |
#else | |
const string jsonFile = "points.json"; | |
#endif | |
app.ReadPoints(File.ReadAllText(jsonFile)); | |
app.BuildLinesFromAllCombinationOfPoints(); | |
app.OutputLinesWithThreeOrMorePoints(); | |
} | |
public List<Point> Points { get; set; } | |
public SortedSet<LineInfo> Lines { get; set; } = new SortedSet<LineInfo>(); | |
private void ReadPoints(string pointsJson) | |
{ | |
Points = JsonConvert.DeserializeObject<List<Point>>(pointsJson); | |
} | |
private void BuildLinesFromAllCombinationOfPoints() | |
{ | |
for (int i = 0; i < Points.Count; ++i) | |
{ | |
var p1 = Points[i]; | |
for (int j = i + 1; j < Points.Count; ++j) | |
{ | |
var p2 = Points[j]; | |
LineInfo line; | |
// we have a vertical line, no slope | |
if (p1.X == p2.X) // does not handle duplicate points | |
{ | |
line = new LineInfo() { VerticalX = p1.X }; | |
} | |
else | |
{ | |
line = new LineInfo() | |
{ | |
Slope = (p2.Y - p1.Y) / (p2.X - p1.X) | |
}; | |
line.B = p1.Y - (line.Slope.Value * p1.X); | |
} | |
if (Lines.TryGetValue(line, out var existingLine)) | |
{ | |
existingLine.PointIndexes.Add(j); // i is already in the set, from when the line was created | |
} | |
else | |
{ | |
line.PointIndexes.Add(i); | |
line.PointIndexes.Add(j); | |
Lines.Add(line); | |
} | |
} | |
} | |
} | |
private void OutputLinesWithThreeOrMorePoints() | |
{ | |
foreach (var line in Lines) | |
{ | |
if (line.HasMultipleMatches) | |
{ | |
if (line.IsVertical) | |
WriteLine($"vertical line at x:{line.VerticalX} has points:"); | |
else | |
WriteLine($"m:{line.Slope} b:{line.B} has points:"); | |
foreach (var pointIndex in line.PointIndexes) | |
{ | |
WriteLine($" {Points[pointIndex]}"); | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment