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

Fixes #132 - Implement ArcGen #210

Merged
merged 9 commits into from
Sep 13, 2023
Merged
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
11 changes: 11 additions & 0 deletions src/Compiler/Input/AbstractSectorDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ public bool IsBlankLine(string line)
return line.Trim() == "";
}

/*
* Returns whether or not the line is an arc gen line
*/
public bool IsArcGenLine(string line) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if there's an alternate way to express arcs that don't require them to be comments 🤔 I think if we start to make some comments "special", things could get confusing.

I think we could look at creating a macro expression (I hate macros, but they're great for this), that gets expanded. That way, we don't have this situation where some comments are special.

Perhaps something like @ARC(arc def here)?

For a first pass, we can just parse macros in the parser, but perhaps in the future we can implement something that expands all macros on a line, before we send things over to the parser?

LMK what you think :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I was also thinking the syntax of the arcs could be changed, I was just going off of what went into the ArcGen tool. Eventually yeah I could also write a macro expander - I had a look in the rest of the replacers but they were only for options in the file.

try {
return line.TrimStart().StartsWith("@ARC");
} catch (ArgumentOutOfRangeException) {
return false;
}
}

/*
* Returns whether or not the line is a comment line
*/
Expand Down
116 changes: 115 additions & 1 deletion src/Compiler/Input/SectorDataFile.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Compiler.Model;

namespace Compiler.Input
Expand Down Expand Up @@ -39,6 +41,118 @@ public override IEnumerator<SectorData> GetEnumerator()
{
docblock.AddLine(reader.GetCommentSegment(line));
}
else if (reader.IsArcGenLine(line)) {
// Return new SectorData for each new region

const int DELTA_THETA = 5;
const double R = 6372.795477598;

Regex rx = new Regex(@"@ARC\(region (.*) centre ([NS]\d{3}\.\d{2}\.\d{2}\.\d{3}) ([EW]\d{3}\.\d{2}\.\d{2}\.\d{3}) radius (\d*(?:\.\d*){0,1})(?: from ([NS]\d{3}\.\d{2}\.\d{2}\.\d{3}) ([EW]\d{3}\.\d{2}\.\d{2}\.\d{3}) to ([NS]\d{3}\.\d{2}\.\d{2}\.\d{3}) ([EW]\d{3}\.\d{2}\.\d{2}\.\d{3})){0,1}\)", RegexOptions.None);
GroupCollection groups = rx.Match(line).Groups; // error catching!

string regionName = groups[1].Value;

double lat = Coordinate.DegreeMinSecToDecimalDegree(groups[2].Value);
double lon = Coordinate.DegreeMinSecToDecimalDegree(groups[3].Value);

float radius = float.Parse(groups[4].Value);

int initialTheta = 0;
int finalTheta = 360;

string prevLat = "";
string prevLon = "";

bool includesFromTo = false;

if (groups.Count > 5) { // includes a from / to as
if (groups[5].Value.Length > 0) {
includesFromTo = true;
prevLat = groups[5].Value;
prevLon = groups[6].Value;

double fromLat = Coordinate.DegreeMinSecToDecimalDegree(groups[5].Value);
double fromLon = Coordinate.DegreeMinSecToDecimalDegree(groups[6].Value);

double toLat = Coordinate.DegreeMinSecToDecimalDegree(groups[7].Value);
double toLon = Coordinate.DegreeMinSecToDecimalDegree(groups[8].Value);

// Calculate angle to from / to coordinate

double fromTheta = Math.Atan2(Math.Cos(fromLat * Math.PI / 180) * Math.Sin((fromLon - lon) * Math.PI / 180),
Math.Cos(lat * Math.PI / 180) * Math.Sin(fromLat * Math.PI / 180) - Math.Sin(lat * Math.PI / 180) * Math.Cos(fromLat * Math.PI / 180) * Math.Cos((fromLon - lon) * Math.PI / 180)
);
fromTheta = (180 * fromTheta / Math.PI + 360) % 360;

double toTheta = Math.Atan2(Math.Cos(toLat * Math.PI / 180) * Math.Sin((toLon - lon) * Math.PI / 180),
Math.Cos(lat * Math.PI / 180) * Math.Sin(toLat * Math.PI / 180) - Math.Sin(lat * Math.PI / 180) * Math.Cos(toLat * Math.PI / 180) * Math.Cos((toLon - lon) * Math.PI / 180)
);
toTheta = (180 * toTheta / Math.PI + 360) % 360;

initialTheta = (int)Math.Min(fromTheta, toTheta);
finalTheta = (int)Math.Max(fromTheta, toTheta);

initialTheta += 1; // padding
finalTheta -= DELTA_THETA;

// calculate actual radius

double fromDist = R * Math.Acos(Math.Sin(lat * Math.PI / 180) * Math.Sin(fromLat * Math.PI / 180) + Math.Cos(lat * Math.PI / 180) * Math.Cos(fromLat * Math.PI / 180) * Math.Cos((lon - fromLon) * Math.PI / 180));
fromDist = fromDist / 1.852;
double toDist = R * Math.Acos(Math.Sin(lat * Math.PI / 180) * Math.Sin(toLat * Math.PI / 180) + Math.Cos(lat * Math.PI / 180) * Math.Cos(toLat * Math.PI / 180) * Math.Cos((lon - toLon) * Math.PI / 180));
toDist = toDist / 1.852;

float meanRadius = (float)Math.Round((fromDist + toDist) / 2, 2);

if (meanRadius != radius) {
radius = meanRadius; // AIP radius was wrong
}
}
}

for (int theta = initialTheta; theta <= finalTheta; theta += DELTA_THETA) {
double deltaLat = (radius * Math.Cos(theta * Math.PI / 180)) / 60.0d;
double deltaLon = (radius * Math.Sin(theta * Math.PI / 180)) / 60.0d;
deltaLon /= Math.Cos((lat) * Math.PI / 180); // account for length of nautical mile changing with latitude

string newLat = Coordinate.DecimalDegreeToDegreeMinSec(lat + deltaLat, true);
string newLon = Coordinate.DecimalDegreeToDegreeMinSec(lon + deltaLon, false);

if (theta == initialTheta && !includesFromTo) {
prevLat = newLat;
prevLon = newLon;
continue;
}

string outLine = $"{regionName} {prevLat} {prevLon} {newLat} {newLon}";

prevLat = newLat;
prevLon = newLon;

// For each new coordinate, yield return it.

yield return new SectorData(
docblock,
reader.GetCommentSegment(outLine),
reader.GetDataSegments(outLine),
reader.GetRawData(outLine),
new Definition(this.FullPath, this.CurrentLineNumber) // sus
);
docblock = new Docblock();
}

if (includesFromTo) {
string outLine = $"{regionName} {prevLat} {prevLon} {groups[7].Value} {groups[8].Value}";
yield return new SectorData(
docblock,
reader.GetCommentSegment(outLine),
reader.GetDataSegments(outLine),
reader.GetRawData(outLine),
new Definition(this.FullPath, this.CurrentLineNumber) // sus
);
docblock = new Docblock();
}
}
else
{
yield return new SectorData(
Expand Down
43 changes: 42 additions & 1 deletion src/Compiler/Model/Coordinate.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Compiler.Model
using System;

namespace Compiler.Model
{
public struct Coordinate
{
Expand All @@ -11,6 +13,45 @@ public Coordinate(string latitude, string longitude)
this.longitude = longitude;
}

public static double DegreeMinSecToDecimalDegree(string latOrLong) {
double output = 0;
string[] sections = latOrLong.Split('.');
output += int.Parse(sections[0].Substring(1));
output += int.Parse(sections[1]) / 60.0d;
output += int.Parse(sections[2]) / 3600.0d;
output += int.Parse(sections[3]) / 3600000.0d;
if (sections[0].StartsWith("S") || sections[0].StartsWith("W")) {
output = -output;
}
return output;
}

public static string DecimalDegreeToDegreeMinSec(double decimalDegree, bool isLat) {
string output = "";
if (decimalDegree > 0) {
if (isLat) output += "N";
else output += "E";
} else {
decimalDegree = -decimalDegree;
if (isLat) output += "S";
else output += "W";
}

output += ((int)decimalDegree).ToString().PadLeft(3, '0') + ".";
decimalDegree -= (int)decimalDegree;
decimalDegree *= 60;
output += ((int)decimalDegree).ToString().PadLeft(2, '0') + ".";
decimalDegree -= (int)decimalDegree;
decimalDegree *= 60;
output += ((int)decimalDegree).ToString().PadLeft(2, '0') + ".";
decimalDegree -= (int)decimalDegree;
decimalDegree *= 1000;
if (Math.Round(decimalDegree) > 999) output += "999";
else output += Math.Round(decimalDegree).ToString().PadLeft(3, '0');

return output;
}

public override bool Equals(object obj)
{
return (obj is Coordinate) &&
Expand Down
1 change: 1 addition & 0 deletions tests/CompilerTest/CompilerTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<Content Include="_TestData\FolderFileListGenerator\Foo.txt" />
<Content Include="_TestData\FolderFileListGenerator\Nested\Bar.txt" />
<Content Include="_TestData\IgnoreWhenFileExists\Foo.txt" />
<Content Include="_TestData\SectorDataFile\ArcGenTest.txt" />
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
Expand Down
11 changes: 11 additions & 0 deletions tests/CompilerTest/Input/EseSectorDataReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,22 @@ public void ItDetectsABlankLine(string line, bool expected)
[InlineData("", false)]
[InlineData("// comment", false)]
[InlineData("/* comment */", false)]
[InlineData("@ARC", false)]
public void ItDetectsACommentLine(string line, bool expected)
{
Assert.Equal(expected, this.reader.IsCommentLine(line));
}

[Fact]
public void ItIgnoresShortComments() {
Assert.False(this.reader.IsArcGenLine("@AR"));
}

[Fact]
public void ItRecognisesArcGenLines() {
Assert.True(this.reader.IsArcGenLine("@ARC(xxx)"));
}

[Theory]
[InlineData("abc ;", "")]
[InlineData("abc ;comment", "comment")]
Expand Down
14 changes: 12 additions & 2 deletions tests/CompilerTest/Input/SctSectorDataReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,21 @@ public void ItDetectsABlankLine(string line, bool expected)
[InlineData("", false)]
[InlineData("// comment", false)]
[InlineData("/* comment */", false)]
public void ItDetectsACommentLine(string line, bool expected)
{
[InlineData("@ARC", false)]
public void ItDetectsACommentLine(string line, bool expected) {
Assert.Equal(expected, this.reader.IsCommentLine(line));
}

[Fact]
public void ItIgnoresShortComments() {
Assert.False(this.reader.IsArcGenLine("@AR"));
}

[Fact]
public void ItRecognisesArcGenLines() {
Assert.True(this.reader.IsArcGenLine("@ARC(xxx)"));
}

[Theory]
[InlineData("abc ;", "")]
[InlineData("abc ;comment", "comment")]
Expand Down
26 changes: 25 additions & 1 deletion tests/CompilerTest/Input/SectorDataFileTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Compiler.Input;
using Compiler.Model;
using Xunit;
Expand All @@ -8,6 +9,7 @@ namespace CompilerTest.Input
public class SectorDataFileTest
{
private readonly SectorDataFile file;
private readonly SectorDataFile arcGenFile;

public SectorDataFileTest()
{
Expand All @@ -17,6 +19,13 @@ public SectorDataFileTest()
InputDataType.ESE_AGREEMENTS,
new EseSectorDataReader()
);

arcGenFile = new SectorDataFile(
"_TestData/SectorDataFile/ArcGenTest.txt",
new InputFileStreamFactory(),
InputDataType.ESE_AGREEMENTS,
new EseSectorDataReader()
);
}

[Fact]
Expand Down Expand Up @@ -85,6 +94,21 @@ public void TestItIteratesTheInputFile()

Assert.Equal(33, file.CurrentLineNumber);
}

[Fact]
public void TestItIteratesArcGen() {
string[] lines = { "Test Region N051.31.15.000 W000.07.30.000 N051.31.14.715 W000.07.19.500", "Test Region N051.31.14.715 W000.07.19.500 N051.31.13.861 W000.07.09.079", "Test Region N051.31.13.861 W000.07.09.079 N051.31.12.444 W000.06.58.818", "Test Region N051.31.12.444 W000.06.58.818 N051.31.10.477 W000.06.48.794", "Test Region N051.31.10.477 W000.06.48.794 N051.31.07.973 W000.06.39.083", "Test Region N051.31.07.973 W000.06.39.083 N051.31.04.952 W000.06.29.760", "Test Region N051.31.04.952 W000.06.29.760 N051.31.01.436 W000.06.20.896", "Test Region N051.31.01.436 W000.06.20.896 N051.30.57.453 W000.06.12.558", "Test Region N051.30.57.453 W000.06.12.558 N051.30.53.033 W000.06.04.808", "Test Region N051.30.53.033 W000.06.04.808 N051.30.48.209 W000.05.57.708", "Test Region N051.30.48.209 W000.05.57.708 N051.30.43.018 W000.05.51.309", "Test Region N051.30.43.018 W000.05.51.309 N051.30.37.500 W000.05.45.662", "Test Region N051.30.37.500 W000.05.45.662 N051.30.31.696 W000.05.40.809", "Test Region N051.30.31.696 W000.05.40.809 N051.30.25.652 W000.05.36.787", "Test Region N051.30.25.652 W000.05.36.787 N051.30.19.411 W000.05.33.626", "Test Region N051.30.19.411 W000.05.33.626 N051.30.13.024 W000.05.31.351", "Test Region N051.30.13.024 W000.05.31.351 N051.30.06.537 W000.05.29.979", "Test Region N051.30.06.537 W000.05.29.979 N051.30.00.000 W000.05.29.521", "Test Region N051.30.00.000 W000.05.29.521 N051.29.53.463 W000.05.29.979", "Test Region N051.29.53.463 W000.05.29.979 N051.29.46.976 W000.05.31.351", "Test Region N051.29.46.976 W000.05.31.351 N051.29.40.589 W000.05.33.626", "Test Region N051.29.40.589 W000.05.33.626 N051.29.34.348 W000.05.36.787", "Test Region N051.29.34.348 W000.05.36.787 N051.29.28.304 W000.05.40.809", "Test Region N051.29.28.304 W000.05.40.809 N051.29.22.500 W000.05.45.662", "Test Region N051.29.22.500 W000.05.45.662 N051.29.16.982 W000.05.51.309", "Test Region N051.29.16.982 W000.05.51.309 N051.29.11.791 W000.05.57.708", "Test Region N051.29.11.791 W000.05.57.708 N051.29.06.967 W000.06.04.808", "Test Region N051.29.06.967 W000.06.04.808 N051.29.02.547 W000.06.12.558", "Test Region N051.29.02.547 W000.06.12.558 N051.28.58.564 W000.06.20.896", "Test Region N051.28.58.564 W000.06.20.896 N051.28.55.048 W000.06.29.760", "Test Region N051.28.55.048 W000.06.29.760 N051.28.52.027 W000.06.39.083", "Test Region N051.28.52.027 W000.06.39.083 N051.28.49.523 W000.06.48.794", "Test Region N051.28.49.523 W000.06.48.794 N051.28.47.556 W000.06.58.818", "Test Region N051.28.47.556 W000.06.58.818 N051.28.46.139 W000.07.09.079", "Test Region N051.28.46.139 W000.07.09.079 N051.28.45.285 W000.07.19.500", "Test Region N051.28.45.285 W000.07.19.500 N051.28.44.999 W000.07.30.000", "Test Region N051.28.44.999 W000.07.30.000 N051.28.45.285 W000.07.40.500", "Test Region N051.28.45.285 W000.07.40.500 N051.28.46.139 W000.07.50.921", "Test Region N051.28.46.139 W000.07.50.921 N051.28.47.556 W000.08.01.182", "Test Region N051.28.47.556 W000.08.01.182 N051.28.49.523 W000.08.11.206", "Test Region N051.28.49.523 W000.08.11.206 N051.28.52.027 W000.08.20.917", "Test Region N051.28.52.027 W000.08.20.917 N051.28.55.048 W000.08.30.240", "Test Region N051.28.55.048 W000.08.30.240 N051.28.58.564 W000.08.39.104", "Test Region N051.28.58.564 W000.08.39.104 N051.29.02.547 W000.08.47.442", "Test Region N051.29.02.547 W000.08.47.442 N051.29.06.967 W000.08.55.192", "Test Region N051.29.06.967 W000.08.55.192 N051.29.11.791 W000.09.02.292", "Test Region N051.29.11.791 W000.09.02.292 N051.29.16.982 W000.09.08.691", "Test Region N051.29.16.982 W000.09.08.691 N051.29.22.500 W000.09.14.338", "Test Region N051.29.22.500 W000.09.14.338 N051.29.28.304 W000.09.19.191", "Test Region N051.29.28.304 W000.09.19.191 N051.29.34.348 W000.09.23.213", "Test Region N051.29.34.348 W000.09.23.213 N051.29.40.589 W000.09.26.374", "Test Region N051.29.40.589 W000.09.26.374 N051.29.46.976 W000.09.28.649", "Test Region N051.29.46.976 W000.09.28.649 N051.29.53.463 W000.09.30.021", "Test Region N051.29.53.463 W000.09.30.021 N051.30.00.000 W000.09.30.479", "Test Region N051.30.00.000 W000.09.30.479 N051.30.06.537 W000.09.30.021", "Test Region N051.30.06.537 W000.09.30.021 N051.30.13.024 W000.09.28.649", "Test Region N051.30.13.024 W000.09.28.649 N051.30.19.411 W000.09.26.374", "Test Region N051.30.19.411 W000.09.26.374 N051.30.25.652 W000.09.23.213", "Test Region N051.30.25.652 W000.09.23.213 N051.30.31.696 W000.09.19.191", "Test Region N051.30.31.696 W000.09.19.191 N051.30.37.500 W000.09.14.338", "Test Region N051.30.37.500 W000.09.14.338 N051.30.43.018 W000.09.08.691", "Test Region N051.30.43.018 W000.09.08.691 N051.30.48.209 W000.09.02.292", "Test Region N051.30.48.209 W000.09.02.292 N051.30.53.033 W000.08.55.192", "Test Region N051.30.53.033 W000.08.55.192 N051.30.57.453 W000.08.47.442", "Test Region N051.30.57.453 W000.08.47.442 N051.31.01.436 W000.08.39.104", "Test Region N051.31.01.436 W000.08.39.104 N051.31.04.952 W000.08.30.240", "Test Region N051.31.04.952 W000.08.30.240 N051.31.07.973 W000.08.20.917", "Test Region N051.31.07.973 W000.08.20.917 N051.31.10.477 W000.08.11.206", "Test Region N051.31.10.477 W000.08.11.206 N051.31.12.444 W000.08.01.182", "Test Region N051.31.12.444 W000.08.01.182 N051.31.13.861 W000.07.50.921", "Test Region N051.31.13.861 W000.07.50.921 N051.31.14.715 W000.07.40.500", "Test Region N051.31.14.715 W000.07.40.500 N051.31.15.000 W000.07.30.000" };
string[] lines2 = { "Test Region N051.29.17.000 W000.06.34.000 N051.29.16.696 W000.06.34.039", "Test Region N051.29.16.696 W000.06.34.039 N051.29.13.869 W000.06.33.999", "Test Region N051.29.13.869 W000.06.33.999 N051.29.11.051 W000.06.34.355", "Test Region N051.29.11.051 W000.06.34.355 N051.29.08.264 W000.06.35.104", "Test Region N051.29.08.264 W000.06.35.104 N051.29.05.527 W000.06.36.241", "Test Region N051.29.05.527 W000.06.36.241 N051.29.02.863 W000.06.37.756", "Test Region N051.29.02.863 W000.06.37.756 N051.29.00.291 W000.06.39.639", "Test Region N051.29.00.291 W000.06.39.639 N051.28.57.831 W000.06.41.874", "Test Region N051.28.57.831 W000.06.41.874 N051.28.55.501 W000.06.44.445", "Test Region N051.28.55.501 W000.06.44.445 N051.28.52.000 W000.06.49.000" };
int i = 0;
foreach (SectorData dataLine in arcGenFile) {
if (i < lines.Length) {
Assert.Equal(lines[i], dataLine.rawData);
} else {
Assert.Equal(lines2[i - lines.Length], dataLine.rawData);
}
i += 1;
}
}

[Fact]
public void ItsEqualIfPathTheSame()
Expand Down
Loading
Loading