/* start out with the boat stopped, and over time, iterate accelerating boat until it reaches steady state. The speed of the boat is known already from apparent wind, this function finds it for true wind */ void BoatPlan::BoatSteadyState(double W, double VW, double &B, double &VB, double &A, double &VA, Boat &boat) { /* starting out not moving */ VB = 0, A = W, VA = VW; double lp = .1; const int count = 128; double bucket = 0; int bcount = 0; for(;;) { double v = VelocityBoat(A, VA); if(v == 0) { // we cannot sail this way B = 0; VB = 0; return; } double a = v - VB; double drag = boat.FrictionDrag(VB) + boat.WakeDrag(VB); if(isnan(drag)) { VB = 0; return; } a -= drag; if(bcount == count) { VB = bucket / count; a = 0; } if(fabs(a) < 1e-2 || lp < 1e-2) { if(VB < 0) // not allowing backwards sailing VB = 0; B = AngleofAttackBoat(A, VA); return; /* reached steady state */ } if(a < 0) { bucket += VB; bcount++; // lp *= .97; } VB = (1-lp)*VB + lp*(VB+a); /* lowpass to get a smooth update */ VA = VelocityApparentWind(VB, W, VW); A = DirectionApparentWind(VA, VB, W, VW); } }
Boat* Boat ::boatWithFile(const char *spName) { Boat *pobSprite = new Boat (); if (pobSprite && pobSprite->initWithFile(spName))//±¸×¢1 { pobSprite->myInit(); pobSprite->autorelease(); return pobSprite; } CC_SAFE_DELETE(pobSprite); return NULL; }
/* start out with the boat stopped, and over time, iterate accelerating boat until it reaches steady state. The speed of the boat is known already from apparent wind, this function finds it for true wind */ void BoatPlan::BoatSteadyState(double W, double VW, double &B, double &VB, double &A, double &VA, Boat &boat) { /* starting out not moving */ VB = 0, A = W, VA = VW; double lp = .03; for(;;) { double v = VelocityBoat(A, VA); double a = v - VB; double drag = boat.FrictionDrag(VB) + boat.WakeDrag(VB); a -= drag; if(fabs(a) < 1e-2 || a < 0) { B = AngleofAttackBoat(A, VA); return; /* reached steady state */ } VB = (1-lp)*VB + lp*(VB+a); /* lowpass to get a smooth update */ VA = VelocityApparentWind(VB, W, VW); A = DirectionApparentWind(VA, VB, W, VW); } }
/* 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; }