Began working on distance from location code

This commit is contained in:
AdenKoperczak 2024-06-30 16:20:38 -04:00
parent 60aed45450
commit 9f47e0ad72
7 changed files with 198 additions and 4 deletions

View file

@ -85,7 +85,8 @@ common::Coordinate AlertManager::Impl::CurrentCoordinate(
settings::AudioSettings& audioSettings = settings::AudioSettings::Instance();
common::Coordinate coordinate {};
if (locationMethod == types::LocationMethod::Fixed)
if (locationMethod == types::LocationMethod::Fixed ||
locationMethod == types::LocationMethod::Radius)
{
coordinate.latitude_ = audioSettings.alert_latitude().GetValue();
coordinate.longitude_ = audioSettings.alert_longitude().GetValue();
@ -153,6 +154,15 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
activeAtLocation = util::GeographicLib::AreaContainsPoint(
alertCoordinates, currentCoordinate);
}
else if (locationMethod == types::LocationMethod::Radius)
{
auto alertCoordinates = segment->codedLocation_->coordinates();
activeAtLocation = util::GeographicLib::AreaInRangeOfPoint(
alertCoordinates,
currentCoordinate,
units::length::meters<double>(1e6));
}
else if (locationMethod == types::LocationMethod::County)
{
// Determine if the alert contains the current county

View file

@ -14,6 +14,7 @@ namespace types
static const std::unordered_map<LocationMethod, std::string>
locationMethodName_ {{LocationMethod::Fixed, "Fixed"},
{LocationMethod::Radius, "Radius"},
{LocationMethod::Track, "Track"},
{LocationMethod::County, "County"},
{LocationMethod::All, "All"},

View file

@ -14,6 +14,7 @@ namespace types
enum class LocationMethod
{
Fixed,
Radius,
Track,
County,
All,

View file

@ -5,14 +5,16 @@
#include <GeographicLib/Gnomonic.hpp>
#include <geos/algorithm/PointLocation.h>
#include <geos/algorithm/distance/PointPairDistance.h>
#include <geos/algorithm/distance/DistanceToPoint.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/GeometryFactory.h>
namespace scwx
{
namespace qt
{
namespace util
{
namespace util {
namespace GeographicLib
{
@ -82,6 +84,12 @@ bool AreaContainsPoint(const std::vector<common::Coordinate>& area,
return areaContainsPoint;
}
units::angle::degrees<double>
GetAngle(double lat1, double lon1, double lat2, double lon2)
{
@ -137,6 +145,93 @@ GetDistance(double lat1, double lon1, double lat2, double lon2)
return units::length::meters<double> {distance};
}
bool AreaInRangeOfPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point,
const units::length::meters<double> distance)
{
// Cannot have an area with just two points
if (area.size() <= 2 || (area.size() == 3 && area.front() == area.back()))
{
return false;
}
::GeographicLib::Gnomonic gnomonic =
::GeographicLib::Gnomonic(DefaultGeodesic());
geos::geom::CoordinateSequence sequence {};
double x;
double y;
// Using a gnomonic projection with the test point as the center
// latitude/longitude, the projected test point will be at (0, 0)
geos::geom::CoordinateXY zero {};
// Create the area coordinate sequence using a gnomonic projection
for (auto& areaCoordinate : area)
{
gnomonic.Forward(point.latitude_,
point.longitude_,
areaCoordinate.latitude_,
areaCoordinate.longitude_,
x,
y);
sequence.add(x, y);
}
// get a point on the circle with the radius of the range in lat lon.
units::angle::degrees<double> angle = units::angle::degrees<double>(0);
common::Coordinate radiusPoint = GetCoordinate(point, angle, distance);
// get the radius in gnomonic projection
gnomonic.Forward(point.latitude_,
point.longitude_,
radiusPoint.latitude_,
radiusPoint.longitude_,
x,
y);
double gnomonicRadius = sqrt(x * x + y * y);
// If the sequence is not a ring, add the first point again for closure
if (!sequence.isRing())
{
sequence.add(sequence.front(), false);
}
// The sequence should be a ring at this point, but make sure
if (sequence.isRing())
{
try
{
if (geos::algorithm::PointLocation::isInRing(zero, &sequence))
{
return true;
}
// Calculate the distance the point is from the output
geos::algorithm::distance::PointPairDistance distancePair;
auto geometryFactory =
geos::geom::GeometryFactory::getDefaultInstance();
auto linearRing = geometryFactory->createLinearRing(sequence);
auto polygon =
geometryFactory->createPolygon(std::move(linearRing));
geos::algorithm::distance::DistanceToPoint::computeDistance(*polygon,
zero,
distancePair);
if (gnomonicRadius > distancePair.getDistance())
{
return true;
}
}
catch (const std::exception&)
{
logger_->trace("Invalid area sequence");
}
}
return false;
}
} // namespace GeographicLib
} // namespace util
} // namespace qt

View file

@ -90,6 +90,23 @@ common::Coordinate GetCoordinate(const common::Coordinate& center,
units::length::meters<double>
GetDistance(double lat1, double lon1, double lat2, double lon2);
/**
* Determine if an area/ring, oriented in either direction, is within a
* distance of a point. A point lying on the area boundary is considered to be
* inside the area, and thus always in range. Any part of the area being inside
* the radius counts as inside.
*
* @param [in] area A vector of Coordinates representing the area
* @param [in] point The point to check against the area
* @param [in] distance The max distance in meters
*
* @return true if area is inside the radius of the point
*/
bool AreaInRangeOfPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point,
const units::length::meters<double> distance);
} // namespace GeographicLib
} // namespace util
} // namespace qt