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

Triangulation algorithms to find your location #488

Closed
Closed
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
66 changes: 66 additions & 0 deletions Algorithms.Tests/Other/GeofenceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Algorithms.Other;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms.Tests.Other
{
[TestFixture]
public class GeofenceTests
{
private Geofence? geofence;

[SetUp]
public void Setup()
{
geofence = new Geofence(10.8231, 106.6297, 500);
}

[Test]
public void IsInside_ShouldReturnTrue_WhenUserIsInsideGeofence()
{
double userLat = 10.8221;
double userLon = 106.6289;

bool? result = geofence?.IsInside(userLat, userLon);

Assert.That(result, Is.True);
}

[Test]
public void IsInside_ShouldReturnFalse_WhenUserIsOutsideGeofence()
{
double userLat = 10.8300;
double userLon = 106.6400;

bool? result = geofence?.IsInside(userLat, userLon);

Assert.That(result, Is.False);
}

[Test]
public void IsInside_ShouldReturnTrue_WhenUserIsExactlyOnGeofenceBoundary()
{
double userLat = 10.8231;
double userLon = 106.6297;

bool? result = geofence?.IsInside(userLat, userLon);

Assert.That(result, Is.True);
}

[Test]
public void IsInside_ShouldReturnFalse_WhenUserIsFarFromGeofence()
{
double userLat = 20.0000;
double userLon = 100.0000;

bool? result = geofence?.IsInside(userLat, userLon);

Assert.That(result, Is.False);
}
}
}
62 changes: 62 additions & 0 deletions Algorithms.Tests/Other/TriangulatorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using Algorithms.Other;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms.Tests.Other
{
[TestFixture]
public class TriangulatorTests
{
[Test]
public void CalculatePosition_ValidCoordinatesAndDistances_ReturnsExpectedPosition()
{
var triangulator = new Triangulator();
var baseLocations = new List<(double Latitude, double Longitude)>
{
(16.054407, 108.202167),
(16.049807, 108.218991),
(16.063597, 108.215553)
};

var distances = new List<double> { 0.5, 0.7, 0.6 };

var expectedPosition = (Latitude: 16.054, Longitude: 108.210);
var result = triangulator.CalculatePosition(baseLocations, distances);

Assert.That(result.Latitude, Is.EqualTo(expectedPosition.Latitude).Within(0.01));
Assert.That(result.Longitude, Is.EqualTo(expectedPosition.Longitude).Within(0.01));
}

[Test]
public void CalculatePosition_InvalidBaseLocations_ThrowsArgumentException()
{
var triangulator = new Triangulator();
var baseLocations = new List<(double Latitude, double Longitude)>
{
(10.762622, 106.660172)
};
var distances = new List<double> { 1.0 };

Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException);
}

[Test]
public void CalculatePosition_InvalidDistances_ThrowsArgumentException()
{
var triangulator = new Triangulator();
var baseLocations = new List<(double Latitude, double Longitude)>
{
(10.762622, 106.660172),
(10.774981, 106.665504),
(10.771817, 106.681179)
};
var distances = new List<double> { 1.0 };

Assert.That(() => triangulator.CalculatePosition(baseLocations, distances), Throws.ArgumentException);
}
}
}
37 changes: 37 additions & 0 deletions Algorithms/Other/Geofence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms.Other
{
public class Geofence
{
public double Latitude { get; set; }

public double Longitude { get; set; }

public double RadiusInMeters { get; set; }

public Geofence(double latitude, double longitude, double radiusInMeters)
{
Latitude = latitude;
Longitude = longitude;
RadiusInMeters = radiusInMeters;
}

/// <summary>
/// Checks whether the provided user location (latitude and longitude) is within the geofence boundary.
/// The geofence is defined by a center point (latitude, longitude) and a radius in meters.
/// </summary>
/// <param name="userLatitude">The latitude of the user's current location.</param>
/// <param name="userLongitude">The longitude of the user's current location.</param>
/// <returns>Returns true if the user is inside the geofence, otherwise returns false.</returns>
public bool IsInside(double userLatitude, double userLongitude)
{
double distance = GeoLocation.CalculateDistanceFromLatLng(Latitude, Longitude, userLatitude, userLongitude);
return distance <= RadiusInMeters;
}
}
}
60 changes: 60 additions & 0 deletions Algorithms/Other/Triangulator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Algorithms.Other
{
public class Triangulator
{
public (double Latitude, double Longitude) CalculatePosition(List<(double Latitude, double Longitude)> baseLocations, List<double> distances)
{
if (baseLocations.Count < 3 || distances.Count < 3)
{
throw new ArgumentException("At least three points and corresponding distances are required.");
}

// Convert distances from kilometers to degrees (approximately)
// 1 degree is approximately 111.32 km at the equator
const double kmPerDegree = 111.32;
var distancesInDegrees = distances.Select(d => d / kmPerDegree).ToList();

Check notice on line 21 in Algorithms/Other/Triangulator.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

Algorithms/Other/Triangulator.cs#L21

Remove the unused local variable 'distancesInDegrees'.

// Get the coordinates of the three base stations
double lat1 = baseLocations[0].Latitude;
double lon1 = baseLocations[0].Longitude;
double lat2 = baseLocations[1].Latitude;
double lon2 = baseLocations[1].Longitude;
double lat3 = baseLocations[2].Latitude;
double lon3 = baseLocations[2].Longitude;

// Convert coordinates to radians
lat1 = ToRadians(lat1);
lon1 = ToRadians(lon1);
lat2 = ToRadians(lat2);
lon2 = ToRadians(lon2);
lat3 = ToRadians(lat3);
lon3 = ToRadians(lon3);

// Calculate the center point
double centerLat = (lat1 + lat2 + lat3) / 3;
double centerLon = (lon1 + lon2 + lon3) / 3;

// Convert back to degrees
centerLat = ToDegrees(centerLat);
centerLon = ToDegrees(centerLon);

return (centerLat, centerLon);
}

private double ToRadians(double degrees)
{
return degrees * Math.PI / 180;
}

private double ToDegrees(double radians)
{
return radians * 180 / Math.PI;
}
}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ find more than one implementation for the same objective but using different alg
* [Julian Easter](./Algorithms/Other/JulianEaster.cs)
* [Pollard's Rho](./Algorithms/Other/PollardsRhoFactorizing.cs)
* [GeoLocation Hash](./Algorithms/Other/Geohash.cs)
* [Geofencing](./Algorithms/Other/Geofence.cs)
* [Triangulation Algorithm](./Algorithms/Other/Triangulator.cs)
* [Problems](./Algorithms/Problems)
* [Stable Marriage](./Algorithms/Problems/StableMarriage)
* [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs)
Expand Down
Loading