void RouteMapOverlay::DrawLine(Position *p1, wxColour &color1, Position *p2, wxColour &color2,
                               wrDC &dc, PlugIn_ViewPort &vp)
{
#if 0
    double p1plon, p2plon;
    if(fabs(vp.clon) > 90)
        p1plon = positive_degrees(p1->lon), p2plon = positive_degrees(p2->lon);
    else
        p1plon = heading_resolve(p1->lon), p2plon = heading_resolve(p2->lon);

    if((p1plon+180 < vp.clon && p2plon+180 > vp.clon) ||
       (p1plon+180 > vp.clon && p2plon+180 < vp.clon) ||
       (p1plon-180 < vp.clon && p2plon-180 > vp.clon) ||
       (p1plon-180 > vp.clon && p2plon-180 < vp.clon))
        return;
#endif

    wxPoint p1p, p2p;
    GetCanvasPixLL(&vp, &p1p, p1->lat, p1->lon);
    GetCanvasPixLL(&vp, &p2p, p2->lat, p2->lon);

    SetColor(dc, color1);
    if(dc.GetDC())
        dc.DrawLine(p1p.x, p1p.y, p2p.x, p2p.y);
    else {
        glVertex2d(p1p.x, p1p.y);
        SetColor(dc, color2);
        glVertex2d(p2p.x, p2p.y);
    }
}
Esempio n. 2
0
/* compute boat speed from given power level, true wind angle and true wind speed */
double BoatPlan::Speed(double W, double VW)
{
    W = positive_degrees(W);
    if(VW < 0 || VW > MAX_KNOTS)
        return NAN;

    double W1 = floor(W/DEGREE_STEP)*DEGREE_STEP;
    double W2 = ceil(W/DEGREE_STEP)*DEGREE_STEP;

    /* get headings nearby each other */
    while(W1 - W2 > 180)
        W2 += 360;
    while(W2 - W1 > 180)
        W1 += 360;

    int W1i = positive_degrees(W1)/DEGREE_STEP;
    int W2i = positive_degrees(W2)/DEGREE_STEP;

    int VW1i = ClosestVWi(VW), VW2i = VW1i+1;
    double VW1 = wind_speeds[VW1i], VW2 = wind_speeds[VW2i];

    double VB11 = speed[VW1i][W1i].VB;
    double VB12 = speed[VW1i][W2i].VB;
    double VB21 = speed[VW2i][W1i].VB;
    double VB22 = speed[VW2i][W2i].VB;

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB = interp_value(W, W1, W2, VB1, VB2);
    return VB;
}
Esempio n. 3
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double BoatPlan::TrueWindSpeed(double VB, double W, double maxVW)
{
    W = positive_degrees(W);
    unsigned int W1i = degree_step_index[(int)floor(W)], W2i;
    if(W1i == degree_steps.size()-1)
        W2i = 0;
    else
        W2i = W1i++;
    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++) {
        if(wind_speeds[VWi].VW > maxVW)
            break;

        SailingWindSpeed &ws = wind_speeds[VWi];
        double VB1 = ws.speeds[W1i].VB;
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = ws.VW;
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = ws.VW;

        double VB2 = ws.speeds[W2i].VB;
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = ws.VW;
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = ws.VW;
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Esempio n. 4
0
double Polar::SpeedAtApparentWind(double A, double VA, double *pW)
{
    int iters = 0;
    double VW = VA, W = A, VB = 0; // initial guess
    double lp = 1;
    for(;;) {
        double cVB = Speed(W, VW);
        VB -= (VB - cVB) * lp;

        double cVA = VelocityApparentWind(VB, W, VW);
        double cA = positive_degrees(DirectionApparentWind(cVA, VB, W, VW));

        if(isnan(cVA) || isnan(cA) || iters++ > 256) {
            if(pW) *pW = NAN;
            return NAN;
        }

        if(fabsf(cVA - VA) < 2e-2 && fabsf(cA - A) < 2e-2) {
            if(pW) *pW = W;
            return cVB;
        }

        VW -= (cVA - VA) * lp;
        W -= (cA - A) * lp;
        lp *= .97;
    }
}
Esempio n. 5
0
wxString BoatDialog::FormatVMG(double W, double VW)
{
    long index = SelectedPolar();
    Polar &polar = m_Boat.Polars[index];
    double A = isnan(W) ? NAN :
        positive_degrees(Polar::DirectionApparentWind(polar.Speed(W, VW), W, VW));
    return wxString::Format(_T("%.1f True %.1f Apparent"), W, A);
}
RouteMapConfiguration ConfigurationDialog::Configuration()
{
    RouteMapConfiguration configuration;

    configuration.Start = m_cStart->GetValue();

    configuration.StartTime = m_dpStartDate->GetValue();
    double hour;
    m_tStartHour->GetValue().ToDouble(&hour);
    configuration.StartTime.SetHour((int)hour);
    configuration.StartTime.SetMinute((int)(60*hour)%60);

    configuration.boatFileName = m_fpBoat->GetPath();

    configuration.dt = 60*(60*m_sTimeStepHours->GetValue()
                     + m_sTimeStepMinutes->GetValue())
        + m_sTimeStepSeconds->GetValue();
    if(configuration.dt == 0) {
        wxMessageDialog mdlg(this, _("Zero Time Step invalid"),
                             _("Weather Routing"), wxOK | wxICON_WARNING);
        mdlg.ShowModal();
    }

    configuration.End = m_cEnd->GetValue();

    if(m_lDegreeSteps->GetCount() < 4) {
        wxMessageDialog mdlg(this, _("Warning: less than 4 different degree steps specified\n"),
                             wxString(_("Weather Routing"), wxOK | wxICON_WARNING));
        mdlg.ShowModal();
    }

    configuration.DegreeSteps.clear();
    for(unsigned int i=0; i<m_lDegreeSteps->GetCount(); i++) {
        double step;
        m_lDegreeSteps->GetString(i).ToDouble(&step);
        configuration.DegreeSteps.push_back(positive_degrees(step));
    }
    configuration.DegreeSteps.sort();

    configuration.MaxDivertedCourse = m_sMaxDivertedCourse->GetValue();
    configuration.MaxWindKnots = m_sMaxWindKnots->GetValue();
    configuration.MaxSwellMeters = m_sMaxSwellMeters->GetValue();
    configuration.MaxLatitude = m_sMaxLatitude->GetValue();
    configuration.MaxTacks = m_sMaxTacks->GetValue();
    configuration.TackingTime = m_sTackingTime->GetValue();

    configuration.DetectLand = m_cbDetectLand->GetValue();
    configuration.Currents = m_cbCurrents->GetValue();
    configuration.InvertedRegions = m_cbInvertedRegions->GetValue();
    configuration.Anchoring = m_cbAnchoring->GetValue();

    configuration.AllowDataDeficient = m_cbAllowDataDeficient->GetValue();

    configuration.UseGrib = m_cbUseGrib->GetValue();
    configuration.UseClimatology = m_cbUseClimatology->GetValue();

    return configuration;
}
Esempio n. 7
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double BoatPlan::TrueWindSpeed(double VB, double W, double maxVW)
{
    int W1 = floor(W/DEGREE_STEP)*DEGREE_STEP;
    int W2 = ceil(W/DEGREE_STEP)*DEGREE_STEP;

    /* get headings nearby */
    while(W1 - W2 > 180)
        W2 += 360;
    while(W2 - W1 > 180)
        W1 += 360;

    W1 = positive_degrees(W1);
    W2 = positive_degrees(W2);

    int W1i = W1/DEGREE_STEP, W2i = W2/DEGREE_STEP;

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(int VWi = 0; VWi < num_wind_speeds; VWi++) {
        if(wind_speeds[VWi] > maxVW)
            break;

        double VB1 = speed[VWi][W1i].VB;
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = wind_speeds[VWi];
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = wind_speeds[VWi];

        double VB2 = speed[VWi][W2i].VB;
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = wind_speeds[VWi];
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = wind_speeds[VWi];
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Esempio n. 8
0
/* compute boat speed from true wind angle and true wind speed
 */
double Polar::Speed(double W, double VW, bool bound)
{
    if(VW < 0)
        return NAN;

    if(!degree_steps.size() || !wind_speeds.size())
        return NAN;

    W = positive_degrees(W);

    // assume symmetric
    if(W > 180)
        W = 360 - W;

    if(W < degree_steps[0] || W > degree_steps[degree_steps.size()-1])
        return NAN;

    if(bound)
        if(VW < wind_speeds[0].VW || VW > wind_speeds[wind_speeds.size()-1].VW)
            return NAN;

    unsigned int W1i = degree_step_index[(int)floor(W)];
    unsigned int W2i = degree_steps.size() == 1 ? 0 : W1i+1;

    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    int VW1i, VW2i;
    ClosestVWi(VW, VW1i, VW2i);
    if(VW1i == (int)wind_speeds.size() - 1)
        VW2i = VW1i;
    else
        VW2i = VW1i + 1;

    SailingWindSpeed &ws1 = wind_speeds[VW1i], &ws2 = wind_speeds[VW2i];
    double VW1 = ws1.VW, VW2 = ws2.VW;

    double VB11 = ws1.speeds[W1i], VB12 = ws1.speeds[W2i];
    double VB21 = ws2.speeds[W1i], VB22 = ws2.speeds[W2i];

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB  = interp_value(W, W1, W2, VB1, VB2);

    if(VB < 0) // with faulty polars, extrapolation, sometimes results in negative boat speed
        return 0;

    return VB;
}
Esempio n. 9
0
/* compute boat speed from true wind angle and true wind speed

   Maybe this should use rectangular coordinate interpolation when the speed
   is outside the VMG zone.
 */
double BoatPlan::Speed(double W, double VW)
{
    if(VW < 0)
        return NAN;

    W = positive_degrees(W);
    unsigned int W1i = degree_step_index[(int)floor(W)], W2i;
    double W1 = degree_steps[W1i], W2;
    if(W1i == degree_steps.size()-1) {
        W2i = 0;
        W2 = 360 + degree_steps[0];
    } else {
        W2i = W1i+1;
        W2 = degree_steps[W2i];
    }

    int VW1i, VW2i;
    ClosestVWi(VW, VW1i, VW2i);
    if(VW1i == wind_speeds.size() - 1)
        VW2i = VW1i;
    else
        VW2i = VW1i + 1;

    SailingWindSpeed &ws1 = wind_speeds[VW1i], &ws2 = wind_speeds[VW2i];
    double VW1 = ws1.VW, VW2 = ws2.VW;

    double VB11 = ws1.speeds[W1i].VB, VB12 = ws1.speeds[W2i].VB;
    double VB21 = ws2.speeds[W1i].VB, VB22 = ws2.speeds[W2i].VB;

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB  = interp_value(W, W1, W2, VB1, VB2);

    if(VB < 0) // with faulty polars, extrapolation, sometimes results in negative boat speed
        return 0;

    return VB;
}
Esempio n. 10
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double Polar::TrueWindSpeed(double VB, double W, double maxVW)
{
    if(!degree_steps.size())
        return NAN;

    W = positive_degrees(W);
    // assume symmetric
    if(W > 180)
        W = 360 - W;

    unsigned int W1i = degree_step_index[(int)floor(W)];
    unsigned int W2i = degree_steps.size() == 1 ? 0 : W1i+1;

    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++) {
        if(wind_speeds[VWi].VW > maxVW)
            break;

        SailingWindSpeed &ws = wind_speeds[VWi];
        double VB1 = ws.speeds[W1i];
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = ws.VW;
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = ws.VW;

        double VB2 = ws.speeds[W2i];
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = ws.VW;
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = ws.VW;
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Esempio n. 11
0
void BoatDialog::OnMouseEventsPolarPlot( wxMouseEvent& event )
{
#if 0
    if(event.Leaving()) {
        m_stTrueWindAngle->SetLabel(_("N/A"));
        m_stTrueWindKnots->SetLabel(_("N/A"));
        m_stApparentWindAngle->SetLabel(_("N/A"));
        m_stApparentWindKnots->SetLabel(_("N/A"));
        m_stBoatAngle->SetLabel(_("N/A"));
        m_stBoatKnots->SetLabel(_("N/A"));
        return;
    }

    wxPoint p = event.GetPosition();
    int w, h;
    m_PlotWindow->GetSize( &w, &h);

    /* range + to - */
    double W, VW, B, VB, A, VA;
    double windspeed;

    switch(m_lPlotType->GetSelection()) {
    case 0:
        if(m_cPlotType->GetSelection() == 0) { // polar
            if(!m_PlotScale)
                return;
            
            double x = (double)p.x - w/2;
            double y = (double)p.y - h/2;
            
            /* range +- */
            x /= m_PlotScale;
            y /= m_PlotScale;
            
            B = rad2posdeg(atan2(x, -y));
        } else
            B = (double)p.x/w*360;
        
        windspeed = m_sWindSpeed->GetValue();
        break;
    case 1:
    {
        B = m_sWindDirection->GetValue();
        double i = (double)p.x/w*num_wind_speeds;
        int i0 = floor(i), i1 = ceil(i);
        double d = i - i0;
        windspeed = (1-d)*wind_speeds[i0] + d*wind_speeds[i1];
    } break;
    }

    switch(m_cPlotVariable->GetSelection()) {
    case 0: // true wind
        W = B;
        VW = windspeed;
        VB = m_Boat.Plans[m_SelectedSailPlan].Speed(W, VW);

        VA = BoatPlan::VelocityApparentWind(VB, W, VW);
        A = rad2posdeg(BoatPlan::DirectionApparentWind(VA, VB, W, VW));
        break;
    case 1:
        A = heading_resolve(B);
        VW = windspeed;
        VB = m_Boat.Plans[m_SelectedSailPlan].SpeedAtApparentWindDirection(A, VW, &W);
        W = positive_degrees(W);

        VA = BoatPlan::VelocityApparentWind(VB, W, VW);
        break;
    case 2:
        W = B;
        VA = windspeed;
        VB = m_Boat.Plans[m_SelectedSailPlan].SpeedAtApparentWindSpeed(W, VA);
        VW = BoatPlan::VelocityTrueWind(VA, VB, W);
        A = rad2posdeg(BoatPlan::DirectionApparentWind(VA, VB, W, VW));
        break;
    case 3:
        A = heading_resolve(B);
        VA = windspeed;
        VB = m_Boat.Plans[m_SelectedSailPlan].SpeedAtApparentWind(A, VA, &W);
        W = positive_degrees(W);
        VW = BoatPlan::VelocityTrueWind(VA, VB, W);
    }

    m_stBoatAngle->SetLabel(wxString::Format(_T("%03.0f"), B));
    m_stBoatKnots->SetLabel(wxString::Format(_T("%.1f"), VB));

    int newmousew = round(B);
    if(newmousew != m_MouseW) {
        m_MouseW = newmousew;
        RefreshPlots();
    }
    
    m_stTrueWindAngle->SetLabel(wxString::Format(_T("%03.0f"), W));
    m_stTrueWindKnots->SetLabel(wxString::Format(_T("%.1f"), VW));

    m_stApparentWindAngle->SetLabel(wxString::Format(_T("%03.0f"), A));

    m_stApparentWindKnots->SetLabel(wxString::Format(_T("%.1f"), VA));
#endif
}
Esempio n. 12
0
double rad2posdeg(double radians)
{
    return positive_degrees(rad2deg(radians));
}