Пример #1
0
void Polar::RemoveDegreeStep(int index)
{
    degree_steps.erase(degree_steps.begin()+index);
    for(unsigned int VWi = 0; VWi<wind_speeds.size(); VWi++)
        wind_speeds[VWi].speeds.erase(wind_speeds[VWi].speeds.begin()+index);

    UpdateDegreeStepLookup();
}
Пример #2
0
void Polar::AddDegreeStep(double twa)
{
    unsigned int Wi;
    for(Wi = 0; Wi < degree_steps.size(); Wi++)
        if(twa < degree_steps[Wi])
            break;

    degree_steps.insert(degree_steps.begin()+Wi, twa);
    for(unsigned int VWi = 0; VWi<wind_speeds.size(); VWi++)
        wind_speeds[VWi].speeds.insert(wind_speeds[VWi].speeds.begin()+Wi, 0);

    UpdateDegreeStepLookup();
}
Пример #3
0
/* eta is a measure of efficiency of the boat, from .01 for racing boats to .5 for
   heavy cruisers */
void BoatPlan::ComputeBoatSpeeds(Boat &boat, PolarMethod method, int speed)
{
//    fileFileName = _T("");
    if(/*polarmethod == FROM_FILE ||*/
       wind_speeds.size() != num_computed_wind_speeds ||
       degree_steps.size() != computed_degree_count) {
        wind_speeds.clear();
        degree_steps.clear();

        for(unsigned int Wi = 0; Wi < computed_degree_count; Wi++)
            degree_steps.push_back(computed_degree_step*Wi);
        UpdateDegreeStepLookup();

        for(unsigned int VWi = 0; VWi < num_computed_wind_speeds; VWi++) {
            wind_speeds.push_back(SailingWindSpeed(computed_wind_speeds[VWi]));

            wind_speeds[VWi].speeds.clear();
            for(unsigned int Wi = 0; Wi < computed_degree_count; Wi++)
                wind_speeds[VWi].speeds.push_back(SailingWindSpeed::SailingSpeed(0, degree_steps[Wi]));
        }
    }

    // for IMF computation
    double SADR = boat.SailAreaDisplacementRatio();
    double lwl_ft = boat.lwl_ft;
    double hull_speed = boat.HullSpeed();

    int VW1i, VW2i;
    if(speed == -1) // all speeds
        VW1i = 0, VW2i = wind_speeds.size() - 1;
    else
        ClosestVWi(speed, VW1i, VW2i);

    for(int VWi = VW1i; VWi <= VW2i; VWi++) {
        for(unsigned int Wi = 0; Wi <= computed_degree_count/2; Wi++) {
            double VW = wind_speeds[VWi].VW;
            double W = Wi * computed_degree_step;

            double B, VB, A, VA;
            switch(method) {
            case TRANSFORM:
                BoatSteadyState(deg2rad(W), VW, B, VB, A, VA, boat);
                break;
            case IMF:
            {
                if(fabsf(W) < 30)
                    VB = 0;
                else {
                    double base_speed  = 2.62 + .066*SADR + .051*lwl_ft;
                    double b = 1 / sqrt(VW + 3);
                    VB = base_speed*(sin(deg2rad(W)/2) + b*cos(deg2rad(W))) * sqrt(20*VW) / 8;
                    if(VB > hull_speed)
                        VB = hull_speed;
                }
            }
            default:
                printf("BoatPlan::ComputeBoatSpeeds called with invalid method: %d\n", method);
                return;
            }

            Set(Wi, VWi, VB, W);
            if(W != 0) // assume symmetric performance
                Set(computed_degree_count-Wi, VWi, VB, DEGREES-W);
        }

        CalculateVMG(VWi);
    }

    polarmethod = method;
}
Пример #4
0
bool BoatPlan::Open(const char *filename, wxString &message)
{
    wind_speeds.clear();
    degree_steps.clear();

    if(filename[0] == 0)
        return false;
    
    int linenum = 0;
    ZUFILE *f = zu_open(filename, "r");
    char line[1024];
    double lastentryW = -1;
    char *token, *saveptr;
    const char delim[] = ";, \t\r\n";

    if(!f)
        PARSE_ERROR(_("Failed to open."));

    // polar file has optional first line which is description
    for(;;) {
        if(!zu_gets(f, line, sizeof line))
            PARSE_ERROR(_("Failed to read."));

        token = strtok_r(line, delim, &saveptr);
        linenum++;

        /* chomp invisible bytes */
        while(*token < 0) token++;

        if(!strcasecmp(token, "twa/tws") ||
           !strcasecmp(token, "twa\\tws") ||
           !strcasecmp(token, "twa"))
            break;

        if(linenum == 2)
            PARSE_ERROR(_("Unrecognized format."));
    }
    
    while((token = strtok_r(NULL, delim, &saveptr))) {
        wind_speeds.push_back(SailingWindSpeed(strtod(token, 0)));
        if(wind_speeds.size() > MAX_WINDSPEEDS_IN_TABLE)
            PARSE_ERROR(_("Too many wind speeds."));
    }

    wind_speed_step = (int)round(wind_speeds.back().VW / wind_speeds.size());

    while(zu_gets(f, line, sizeof line)) {
        linenum++;

#if 0
        /* strip newline/linefeed */
        for(unsigned int i=0; i<strlen(line); i++)
            if(line[i] == '\r' || line[i] == '\n')
                line[i] = '\0';
#endif

        if(!(token = strtok_r(line, delim, &saveptr)))
            break;

        double W = strtod(token, 0);

        if(W < 0 || W > 180) {
            PARSE_WARNING(_("Wind direction out of range."));
            continue;
        }

        if(W <= lastentryW) {
            PARSE_WARNING(_("Wind direction out of order."));
            continue;
        }

        // add zero speed for all wind speeds going against wind if not specified
        if(degree_steps.empty() && W > 0)
        {
            degree_steps.push_back(0);

            for(int VWi = 0; VWi < (int)wind_speeds.size(); VWi++)
                wind_speeds[VWi].speeds.push_back(SailingWindSpeed::SailingSpeed(0, 0));
        }

        degree_steps.push_back(W);
        lastentryW = W;

        {
            for(int VWi = 0; VWi < (int)wind_speeds.size(); VWi++) {
                double s = 0;
                if((token = strtok_r(NULL, delim, &saveptr)))
                    s = strtod(token, 0);
                else
                    PARSE_WARNING(_("Too few tokens."));

                wind_speeds[VWi].speeds.push_back
                    (SailingWindSpeed::SailingSpeed(s, W));
            }

            if(strtok_r(NULL, delim, &saveptr))
                PARSE_WARNING(_("Too many tokens."));
        }
    }

    zu_close(f);

    /* fill in port tack assuming symmetric */
    {
        int Win = degree_steps.size()-1;
        if(degree_steps[Win] == 180) Win--;
        for(; Win >= 0; Win--) {
            if(degree_steps[Win] == 0)
                break;
            
            degree_steps.push_back(DEGREES - degree_steps[Win]);
            
            for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++)
                wind_speeds[VWi].speeds.push_back(wind_speeds[VWi].speeds[Win]);
        }
    }
        
    UpdateDegreeStepLookup();
    wind_degree_step = degree_steps.size() ? 360 / degree_steps.size() : 0;

    for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++)
        CalculateVMG(VWi);

    fileFileName = wxString::FromUTF8(filename);
    polarmethod = FROM_FILE;
    return true;
    
failed:
    wind_speeds.clear();
    degree_steps.clear();

    zu_close(f);
    return false;
}