-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
emper
authored and
emper
committed
Sep 20, 2024
1 parent
3eb694e
commit 87f56fb
Showing
3 changed files
with
286 additions
and
0 deletions.
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,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.10.34928.147 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diastavrosis", "Diastavrosis\Diastavrosis.csproj", "{4A2F91E5-4681-4C61-961C-BD821E239450}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{4A2F91E5-4681-4C61-961C-BD821E239450}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{4A2F91E5-4681-4C61-961C-BD821E239450}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{4A2F91E5-4681-4C61-961C-BD821E239450}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{4A2F91E5-4681-4C61-961C-BD821E239450}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {6C80AD41-6407-4C6C-8CF7-87F927A708FF} | ||
EndGlobalSection | ||
EndGlobal |
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,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
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,251 @@ | ||
using System; | ||
using System.Globalization; | ||
using System.Text.RegularExpressions; | ||
|
||
class Program | ||
{ | ||
static void Main() | ||
{ | ||
while (true) | ||
{ // User Input Prompt | ||
string lineA = GetValidInput("Enter coordinates for Line Segment A:"); | ||
string lineB = GetValidInput("Enter coordinates for Line Segment B:"); | ||
|
||
// Print inputs for verification | ||
Console.WriteLine($"Line Segment A: {lineA}"); | ||
Console.WriteLine($"Line Segment B: {lineB}"); | ||
|
||
// Parse User Input | ||
var lineACoords = ParseCoordinates(lineA); | ||
var lineBCoords = ParseCoordinates(lineB); | ||
|
||
// Intersection Calculation | ||
var result = CalculateIntersection(lineACoords, lineBCoords); | ||
|
||
// Output Result | ||
Console.WriteLine(result); | ||
|
||
// Ask user if they want to reset or exit | ||
Console.WriteLine("Press 'R' to reset and input new lines. Press any other key to exit."); | ||
var key = Console.ReadKey().Key; | ||
if (key != ConsoleKey.R) | ||
{ | ||
break; | ||
} | ||
// Clear the console for new input | ||
Console.Clear(); | ||
} | ||
} | ||
|
||
static string GetValidInput(string prompt) | ||
{ | ||
while (true) | ||
{ | ||
Console.WriteLine(prompt); | ||
string input = Console.ReadLine(); | ||
if (IsValidInputFormat(input)) | ||
{ | ||
return input; | ||
} | ||
Console.WriteLine("Invalid input format. Please try again."); | ||
} | ||
} | ||
|
||
static bool IsValidInputFormat(string input) | ||
{ | ||
// Regex to match the expected format | ||
string pattern = @"^[NS]\d{3}\.\d{2}\.\d{2}\.\d{3}:[EW]\d{3}\.\d{2}\.\d{2}\.\d{3}:[NS]\d{3}\.\d{2}\.\d{2}\.\d{3}:[EW]\d{3}\.\d{2}\.\d{2}\.\d{3}$"; | ||
return Regex.IsMatch(input, pattern); | ||
} | ||
|
||
static (double lat, double lon)[] ParseCoordinates(string input) | ||
{ | ||
var parts = input.Split(':'); | ||
if (parts.Length != 4) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Expected 4 parts."); | ||
} | ||
|
||
// Ensure latitude parts have 'N' or 'S' and longitude parts have 'E' or 'W' | ||
if (!parts[0].Contains('N') && !parts[0].Contains('S')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing latitude hemisphere in part 1."); | ||
} | ||
if (!parts[1].Contains('E') && !parts[1].Contains('W')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing longitude hemisphere in part 2."); | ||
} | ||
if (!parts[2].Contains('N') && !parts[2].Contains('S')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing latitude hemisphere in part 3."); | ||
} | ||
if (!parts[3].Contains('E') && !parts[3].Contains('W')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing longitude hemisphere in part 4."); | ||
} | ||
|
||
return new (double lat, double lon)[] | ||
{ | ||
ParseCoordinate(parts[0], parts[1]), | ||
ParseCoordinate(parts[2], parts[3]) | ||
}; | ||
} | ||
|
||
static (double lat, double lon) ParseCoordinate(string latCoord, string lonCoord) | ||
{ | ||
try | ||
{ | ||
|
||
if (string.IsNullOrEmpty(latCoord) || string.IsNullOrEmpty(lonCoord)) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Coordinate string is empty."); | ||
} | ||
|
||
if (!latCoord.Contains('N') && !latCoord.Contains('S')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing latitude hemisphere indicator."); | ||
} | ||
|
||
if (!lonCoord.Contains('E') && !lonCoord.Contains('W')) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Missing longitude hemisphere indicator."); | ||
} | ||
|
||
char latHemisphere = latCoord[0]; | ||
char lonHemisphere = lonCoord[0]; | ||
|
||
var latParts = latCoord.Substring(1).Split('.'); | ||
var lonParts = lonCoord.Substring(1).Split('.'); | ||
|
||
if (latParts.Length != 4 || lonParts.Length != 4) | ||
{ | ||
throw new FormatException("Invalid coordinate format: Incomplete coordinate parts."); | ||
} | ||
|
||
double lat = ConvertToDecimalDegrees(latParts); | ||
double lon = ConvertToDecimalDegrees(lonParts); | ||
|
||
if (latHemisphere == 'S') lat = -lat; | ||
if (lonHemisphere == 'W') lon = -lon; | ||
|
||
return (lat, lon); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine($"Exception: {ex.Message}"); | ||
throw new FormatException("Invalid coordinate format.", ex); | ||
} | ||
} | ||
static double ConvertToDecimalDegrees(string[] dmsParts) | ||
{ | ||
try | ||
{ | ||
|
||
double degrees = double.Parse(dmsParts[0], CultureInfo.InvariantCulture); | ||
double minutes = double.Parse(dmsParts[1], CultureInfo.InvariantCulture); | ||
double seconds = double.Parse(dmsParts[2], CultureInfo.InvariantCulture); | ||
double milliseconds = double.Parse(dmsParts[3], CultureInfo.InvariantCulture); | ||
|
||
return degrees + (minutes / 60) + (seconds / 3600) + (milliseconds / 3600000); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine($"Exception in ConvertToDecimalDegrees: {ex.Message}"); | ||
throw new FormatException("Invalid DMS format.", ex); | ||
} | ||
} | ||
|
||
static string FormatCoordinates((double lat, double lon) coord) | ||
{ | ||
string latHemisphere = coord.lat >= 0 ? "N" : "S"; | ||
string lonHemisphere = coord.lon >= 0 ? "E" : "W"; | ||
return $"{latHemisphere}{ConvertToDMS(Math.Abs(coord.lat))}:{lonHemisphere}{ConvertToDMS(Math.Abs(coord.lon))}"; | ||
} | ||
|
||
static string ConvertToDMS(double decimalDegrees) | ||
{ | ||
int degrees = (int)decimalDegrees; | ||
double fractional = Math.Abs(decimalDegrees - degrees); | ||
int minutes = (int)(fractional * 60); | ||
double secondsFractional = (fractional * 60 - minutes) * 60; | ||
int seconds = (int)secondsFractional; | ||
double millisecondsFractional = (secondsFractional - seconds) * 1000; | ||
int milliseconds = (int)Math.Round(millisecondsFractional); | ||
|
||
// Ensure milliseconds are within the valid range | ||
if (milliseconds == 1000) | ||
{ | ||
milliseconds = 0; | ||
seconds++; | ||
} | ||
|
||
if (seconds == 60) | ||
{ | ||
seconds = 0; | ||
minutes++; | ||
} | ||
|
||
if (minutes == 60) | ||
{ | ||
minutes = 0; | ||
degrees++; | ||
} | ||
|
||
return $"{degrees:D3}.{minutes:D2}.{seconds:D2}.{milliseconds:D3}"; | ||
} | ||
|
||
static string CalculateIntersection((double lat, double lon)[] lineA, (double lat, double lon)[] lineB) | ||
{ | ||
// Extract points | ||
var (x1, y1) = lineA[0]; | ||
var (x2, y2) = lineA[1]; | ||
var (x3, y3) = lineB[0]; | ||
var (x4, y4) = lineB[1]; | ||
|
||
// Calculate the denominators | ||
double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); | ||
if (denom == 0) | ||
{ | ||
// Lines are parallel, check for coincidence | ||
if (AreLinesCoincident(lineA, lineB)) | ||
{ | ||
return "The lines are coincident."; | ||
} | ||
return "The lines are parallel."; | ||
} | ||
|
||
// Calculate the intersection point of the infinite lines | ||
double intersectX = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom; | ||
double intersectY = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom; | ||
|
||
// Check if the intersection point is within the bounds of both segments | ||
if (IsWithinBounds(intersectX, intersectY, x1, y1, x2, y2) && IsWithinBounds(intersectX, intersectY, x3, y3, x4, y4)) | ||
{ | ||
return $"Intersection at: {FormatCoordinates((intersectX, intersectY))}"; | ||
} | ||
|
||
// If not within bounds, return the intersection point of the infinite lines | ||
return $"The segments do not intersect, but the lines intersect at: {FormatCoordinates((intersectX, intersectY))}"; | ||
} | ||
|
||
static bool AreLinesCoincident((double lat, double lon)[] lineA, (double lat, double lon)[] lineB) | ||
{ | ||
// Check if any point of lineB lies on lineA | ||
return IsPointOnLine(lineA, lineB[0]) || IsPointOnLine(lineA, lineB[1]); | ||
} | ||
|
||
static bool IsPointOnLine((double lat, double lon)[] line, (double lat, double lon) point) | ||
{ | ||
var (x1, y1) = line[0]; | ||
var (x2, y2) = line[1]; | ||
var (px, py) = point; | ||
|
||
// Check if the point satisfies the line equation | ||
return (x2 - x1) * (py - y1) == (y2 - y1) * (px - x1); | ||
} | ||
|
||
static bool IsWithinBounds(double x, double y, double x1, double y1, double x2, double y2) | ||
{ | ||
return (Math.Min(x1, x2) <= x && x <= Math.Max(x1, x2)) && (Math.Min(y1, y2) <= y && y <= Math.Max(y1, y2)); | ||
} | ||
} |