Skip to content

Commit

Permalink
Merge pull request #296 from sebastien-rosset/code_comments
Browse files Browse the repository at this point in the history
Add code comments
  • Loading branch information
seandepagnier authored Jul 2, 2024
2 parents 9a9f57e + ba8e931 commit 97f2a08
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 22 deletions.
4 changes: 4 additions & 0 deletions include/Boat.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

#include "Polar.h"

/*
* This class is responsible for loading and saving the polars of a given boat to disk.
* and for finding the fastest polar for a given wind and heading.
*/
class Boat
{
public:
Expand Down
121 changes: 101 additions & 20 deletions include/RouteMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class IsoRoute;
typedef std::list<IsoRoute*> IsoRouteList;

class PlotData;

class RoutePoint {
public:
RoutePoint(double latitude = 0., double longitude = 0., int sp = -1, int t=0, bool d = false) :
Expand All @@ -53,21 +54,39 @@ class RoutePoint {
bool grib_is_data_deficient;

bool GetPlotData(RoutePoint *next, double dt, RouteMapConfiguration &configuration, PlotData &data);
// @brief Return the wind data at the route point.
bool GetWindData(RouteMapConfiguration &configuration, double &W, double &VW, int &data_mask);
// @brief Return the current data at the route point.
bool GetCurrentData(RouteMapConfiguration &configuration, double &C, double &VC, int &data_mask);

// @brief Return true if the route point crosses land.
bool CrossesLand(double dlat, double dlon);
// @brief Return true if the route point enters a boundary.
bool EntersBoundary(double dlat, double dlon);
// @brief Propagate the route point to a specific point.
double PropagateToPoint(double dlat, double dlon, RouteMapConfiguration &cf, double &H, int &data_mask, bool end = true);
};

/*
* A RoutePoint that has a time associated with it, along with navigation and weather data.
*/
class PlotData : public RoutePoint
{
public:
wxDateTime time;
double delta;
double VBG, BG, VB, B, VW, W, VWG, WG, VC, C, WVHT;
double VW_GUST;
wxDateTime time; // The time when the boat reaches this position, based on the route calculation.
double delta; // The time in seconds from the previous position to this position.
double VBG; // Velocity of boat over ground, in knots.
double BG; // Boat direction over ground.
double VB; // Velocity of boat over water, in knots.
double B; // Boat direction over water.
double VW; // Velocity of wind over water, in knots.
double W; // Wind direction over water.
double VWG; // Velocity of wind over ground, in knots.
double WG; // Wind direction over ground.
double VC; // Velocity of current over ground, in knots.
double C; // Sea current direction over ground.
double WVHT; // Swell height, in meters.
double VW_GUST; // Gust wind speed, in knots.
};

class SkipPosition;
Expand Down Expand Up @@ -121,7 +140,7 @@ class SkipPosition
int quadrant;
};

/* a closed loop of positions */
/* A closed loop of isochrone positions */
class IsoRoute
{
public:
Expand Down Expand Up @@ -305,57 +324,119 @@ struct RouteMapPosition {
};


/* Configuration parameters for a route between two points. */
struct RouteMapConfiguration {
RouteMapConfiguration () : StartLon(0), EndLon(0),
grib(nullptr), grib_is_data_deficient(false) {} /* avoid waiting forever in update longitudes */
bool Update();

wxString RouteGUID; /* Route GUID if any */
wxString Start;
wxString Start; /* The name of starting position, which is resolved to StartLat/StartLon. */
wxString StartGUID;

wxString End;
wxString End; /* The name of the destination position, which is resolved to EndLat/EndLon. */
wxString EndGUID;

wxDateTime StartTime;
wxDateTime StartTime; /* The time when the boat leaves the starting position. */

double DeltaTime; /* default time in seconds between propagations */
double UsedDeltaTime; /* time in seconds between propagations */

Boat boat;
wxString boatFileName;
Boat boat; /* The polars of the boat, used for the route calculation. */
wxString boatFileName; /* The name of the boat XML file referencing polars. */

enum IntegratorType { NEWTON, RUNGE_KUTTA } Integrator;

double MaxDivertedCourse, MaxCourseAngle, MaxSearchAngle, MaxTrueWindKnots, MaxApparentWindKnots;
double MaxSwellMeters, MaxLatitude, TackingTime, WindVSCurrent;
// The maximum angle the boat can be diverted from the bearing to the destination,
// at each step of the route calculation, in degrees.
// This represents the angle away from Start to End bearing (StartEndBearing).
// The normal setting is 100 degrees, which speeds up calculations.
// If the route needs to go around land, islands or peninsulas, the user can increase the value.
// E.g. the boat may have to go in the opposite direction then back to the destination bearing.
double MaxDivertedCourse;
// The maximum deviation away from the direct route.
double MaxCourseAngle;
// The maximum angle at each step of the route calculation.
double MaxSearchAngle;
// The calculated route will avoid a path where the true wind is above this value in knots.
double MaxTrueWindKnots;
// The calculated route will avoid a path where the gust wind is above this value in knots.
double MaxApparentWindKnots;

// The calculated route will avoid swells larger than this value in meters.
// If the grib data does not contain swell information, the maximum swell value is ignored.
// If there is no route within the maximum swell value, the route calculation will fail.
double MaxSwellMeters;
// The calculated route will not go beyond this latitude, as an absolute value.
// If the starting or destination position is beyond this latitude, the route calculation will fail.
double MaxLatitude;
// The penalty time to tack the boat, in seconds.
// The penalty time is added to the route calculation for each tack.
double TackingTime;
// Balance the influence of the wind and the ocean current on the route calculation.
double WindVSCurrent;
// The minimum safety distance to land, in nautical miles.
// The calculated route will avoid land within this distance.
double SafetyMarginLand;

bool AvoidCycloneTracks;
int CycloneMonths, CycloneDays;
// Avoid cyclone tracks within ( 30*CycloneMonths + CycloneDays ) days of climatology data.
int CycloneMonths;
int CycloneDays;

bool UseGrib;
enum ClimatologyDataType {DISABLED, CURRENTS_ONLY, CUMULATIVE_MAP, CUMULATIVE_MINUS_CALMS, MOST_LIKELY, AVERAGE};
enum ClimatologyDataType ClimatologyType;
bool AllowDataDeficient;
double WindStrength; // wind speed multiplier
double WindStrength; // wind speed multiplier. 1.0 is 100% of the wind speed in the grib.

// If true, the route calculation will avoid land, outside the SafetyMarginLand.
bool DetectLand;
// If true, the route calculation will avoid exclusion boundaries.
bool DetectBoundary;
// If true and grib data contains ocean currents, the route calculation will use ocean current data.
bool Currents;
// If true, avoid polar dead zones.
// If false, avoid upwind course (polar angle too low) or downwind no-go zone (polar angle too high).
bool OptimizeTacking;
bool InvertedRegions;
bool Anchoring;

// Do not go below this minimum True Wind angle at each step of the route calculation.
// The default value is 0 degrees.
double FromDegree;
// Do not go above this maximum True Wind angle at each step of the route calculation.
// The default value is 180 degrees.
double ToDegree;
// The angular resolution at each step of the route calculation, in degrees.
// Lower values provide finer resolution but increase computation time.
// Higher values provide coarser resolution, but faster computation time.
// The allowed range of resolution is from 0.1 to 60 degrees.
// The default value is 5 degrees.
double ByDegrees;

bool DetectLand, DetectBoundary, Currents, OptimizeTacking, InvertedRegions, Anchoring;

double FromDegree, ToDegree, ByDegrees;

/* computed values */
std::list<double> DegreeSteps;
double StartLat, StartLon, EndLat, EndLon;

double StartEndBearing; /* calculated from start and end */
double StartLat, StartLon; // The latitude and longitude of the starting position.
double EndLat, EndLon; // The latitude and longitude of the destination position.

/*
* The initial bearing from Start position to End position, following the Great Circle
* route and taking into consideration the ellipsoidal shape of the Earth.
* Note: a boat sailing the great circle route will gradually change the bearing to the destination.
*/
double StartEndBearing;
bool positive_longitudes; /* longitudes are either 0 to 360 or -180 to 180,
this means the map cannot cross both 0 and 180 longitude.
To fully support this requires a lot more logic and would probably slow the algorithm
by about 8%. Is it even useful? */

// parameters
WR_GribRecordSet *grib;
// The time of the current isochrone step in the route calculation.
// The time starts at StartTime and is incremented for each step until the destination is reached,
// or the route calculation fails.
wxDateTime time;
bool grib_is_data_deficient, polar_failed, wind_data_failed;
bool land_crossing, boundary_crossing;
Expand Down
13 changes: 12 additions & 1 deletion src/Polar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,17 @@ bool Polar::VMGAngle(SailingWindSpeed &ws1, SailingWindSpeed &ws2, float VW, flo
return true;
}

/* compute boat speed from true wind angle and true wind speed
/**
* Calculate the boat speed (VB) based on the wind angle (W) and wind speed (VW) using the polar data.
*
* @param W The wind angle in degrees.
* @param VW The wind speed in knots.
* @param bound If true, the wind speed must be within the bounds of the polar data.
* For example, if the wind speed is 25 knots and the polar data only goes up to 20 knots,
* the function will return NAN.
* If false, the wind speed is extrapolated if outside the bounds.
* @param optimize_tacking Flag indicating whether to optimize for tacking angles.
* @return The boat speed (VB) in knots.
*/
double Polar::Speed(double W, double VW, bool bound, bool optimize_tacking)
{
Expand All @@ -498,6 +508,7 @@ double Polar::Speed(double W, double VW, bool bound, bool optimize_tacking)
W = 360 - W;

if(!optimize_tacking && (W < degree_steps[0] || W > degree_steps[degree_steps.size()-1]))
// Avoid upwind course (polar angle too low) or downwind no-go zone (polar angle too high).
return NAN;

if(bound && (VW < wind_speeds[0].VW || VW > wind_speeds[wind_speeds.size()-1].VW))
Expand Down
7 changes: 6 additions & 1 deletion src/RouteMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ static Json::Value RequestGRIB(const wxDateTime &t, const wxString &what, double
return error;
}

// Return the swell height at the specified lat/long location.
// @return the swell height in meters. 0 if no data is available.
static double Swell(RouteMapConfiguration &configuration, double lat, double lon)
{
WR_GribRecordSet *grib = configuration.grib;
Expand Down Expand Up @@ -144,6 +146,7 @@ static double Swell(RouteMapConfiguration &configuration, double lat, double lon
return height;
}

// Return the wind gust speed for the specified lat/long location, in knots.
static double Gust(RouteMapConfiguration &configuration, double lat, double lon)
{
WR_GribRecordSet *grib = configuration.grib;
Expand Down Expand Up @@ -171,6 +174,7 @@ static double Gust(RouteMapConfiguration &configuration, double lat, double lon)
}


// Return the wind speed from the grib at the specified lat/long location, in knots.
static bool GribWind(RouteMapConfiguration &configuration, double lat, double lon,
double &WG, double &VWG)
{
Expand Down Expand Up @@ -752,6 +756,7 @@ bool Position::Propagate(IsoRouteList &routelist, RouteMapConfiguration &configu
return false;

if(configuration.WindVSCurrent) {
/* Calculate the wind vector (Wx, Wy) and ocean current vector (Cx, Cy). */
/* these are already computed in OverWater.. could optimize by reusing them */
double Wx = VW*cos(deg2rad(W)), Wy = VW*sin(deg2rad(W));
double Cx = VC*cos(deg2rad(C) + M_PI), Cy = VC*sin(deg2rad(C) + M_PI);
Expand Down Expand Up @@ -929,7 +934,7 @@ bool Position::Propagate(IsoRouteList &routelist, RouteMapConfiguration &configu
double latBorderDown1, lonBorderDown1, latBorderDown2, lonBorderDown2;

// Test if land is found within a rectangle with
// dimensiosn (dist, distSecure). Tests borders, plus diag,
// dimensions (dist, distSecure). Tests borders, plus diag,
// and middle of each side...
// <- dist ->
// |-------------------------------|
Expand Down

0 comments on commit 97f2a08

Please sign in to comment.