void WindPlot::updatePlot() { clearPlottables(); clearItems(); // Return now if plot empty if (mMainWindow->dataSize() == 0) return; double lower = mMainWindow->rangeLower(); double upper = mMainWindow->rangeUpper(); QVector< double > t, x, y; double xMin, xMax; double yMin, yMax; int start = mMainWindow->findIndexBelowT(lower) + 1; int end = mMainWindow->findIndexAboveT(upper); bool first = true; for (int i = start; i < end; ++i) { const DataPoint &dp = mMainWindow->dataPoint(i); t.append(dp.t); if (mMainWindow->units() == PlotValue::Metric) { x.append(dp.velE * MPS_TO_KMH); y.append(dp.velN * MPS_TO_KMH); } else { x.append(dp.velE * MPS_TO_MPH); y.append(dp.velN * MPS_TO_MPH); } if (first) { xMin = xMax = x.back(); yMin = yMax = y.back(); first = false; } else { if (x.back() < xMin) xMin = x.back(); if (x.back() > xMax) xMax = x.back(); if (y.back() < yMin) yMin = y.back(); if (y.back() > yMax) yMax = y.back(); } } QCPCurve *curve = new QCPCurve(xAxis, yAxis); curve->setData(t, x, y); curve->setPen(QPen(Qt::lightGray, mMainWindow->lineThickness())); setViewRange(xMin, xMax, yMin, yMax); if (mMainWindow->markActive()) { const DataPoint &dpEnd = mMainWindow->interpolateDataT(mMainWindow->markEnd()); t.clear(); x.clear(); y.clear(); QVector< double > xMark, yMark; if (mMainWindow->units() == PlotValue::Metric) { xMark.append(dpEnd.velE * MPS_TO_KMH); yMark.append(dpEnd.velN * MPS_TO_KMH); } else { xMark.append(dpEnd.velE * MPS_TO_MPH); yMark.append(dpEnd.velN * MPS_TO_MPH); } QCPGraph *graph = addGraph(); graph->setData(xMark, yMark); graph->setPen(QPen(Qt::black, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); } updateWind(start, end); QVector< double > xMark, yMark; if (mMainWindow->units() == PlotValue::Metric) { xMark.append(mWindE * MPS_TO_KMH); yMark.append(mWindN * MPS_TO_KMH); } else { xMark.append(mWindE * MPS_TO_MPH); yMark.append(mWindN * MPS_TO_MPH); } QCPGraph *graph = addGraph(); graph->setData(xMark, yMark); graph->setPen(QPen(Qt::red, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); const double x0 = mWindE; const double y0 = mWindN; const double r = mVelAircraft; QVector< double > tCircle, xCircle, yCircle; for (int i = 0; i <= 100; ++i) { tCircle.append(i); const double x = x0 + r * cos((double) i / 100 * 2 * M_PI); const double y = y0 + r * sin((double) i / 100 * 2 * M_PI); if (mMainWindow->units() == PlotValue::Metric) { xCircle.append(x * MPS_TO_KMH); yCircle.append(y * MPS_TO_KMH); } else { xCircle.append(x * MPS_TO_MPH); yCircle.append(y * MPS_TO_MPH); } } curve = new QCPCurve(xAxis, yAxis); curve->setData(tCircle, xCircle, yCircle); curve->setPen(QPen(Qt::red, mMainWindow->lineThickness())); // Add label to show best fit QCPItemText *textLabel = new QCPItemText(this); const double factor = (mMainWindow->units() == PlotValue::Metric) ? MPS_TO_KMH : MPS_TO_MPH; const QString units = (mMainWindow->units() == PlotValue::Metric) ? "km/h" : "mph"; double direction = atan2(-mWindE, -mWindN) / M_PI * 180.0; if (direction < 0) direction += 360.0; QPainter painter(this); double mmPerPix = (double) painter.device()->widthMM() / painter.device()->width(); double xRatioPerPix = 1.0 / axisRect()->width(); double xRatioPerMM = xRatioPerPix / mmPerPix; double yRatioPerPix = 1.0 / axisRect()->height(); double yRatioPerMM = yRatioPerPix / mmPerPix; textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignRight); textLabel->setTextAlignment(Qt::AlignRight); textLabel->position->setType(QCPItemPosition::ptAxisRectRatio); textLabel->position->setCoords(1 - 5 * xRatioPerMM, 1 - 5 * yRatioPerMM); textLabel->setText( QString("Wind speed = %1 %2\nWind direction = %3 deg\nAircraft speed = %4 %5") .arg(sqrt(mWindE * mWindE + mWindN * mWindN) * factor) .arg(units) .arg(direction) .arg(mVelAircraft * factor) .arg(units)); replot(); }
void ForestWindAccumulator::presimulate( const VectorF &windVector, U32 ticks ) { PROFILE_SCOPE( ForestWindAccumulator_Presimulate ); for ( U32 i = 0; i < ticks; i++ ) updateWind( windVector, TickSec ); }
void ForestWindMgr::processTick() { const F32 timeDelta = 0.032f; if ( mEmitters.empty() ) return; PROFILE_SCOPE(ForestWindMgr_AdvanceTime); // Advance all ForestWinds. { PROFILE_SCOPE(ForestWindMgr_AdvanceTime_ForestWind_ProcessTick); ForestWindEmitterList::iterator iter = mEmitters.begin(); for ( ; iter != mEmitters.end(); iter++ ) { if ( (*iter)->getWind() && (*iter)->isEnabled() ) { (*iter)->updateMountPosition(); ForestWind *wind = (*iter)->getWind(); if ( wind ) wind->processTick(); } } } // Assign the new global wind value used by the particle system. { ForestWindEmitter *pWindEmitter = getGlobalWind(); if ( pWindEmitter == NULL ) ParticleEmitter::setWindVelocity( Point3F::Zero ); else { ForestWind *pWind = pWindEmitter->getWind(); ParticleEmitter::setWindVelocity( pWind->getDirection() * pWind->getStrength() ); } } // Get the game connection and camera object // in order to retrieve the camera position. GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; GameBase *cam = conn->getCameraObject(); if ( !cam ) return; const Point3F &camPos = cam->getPosition(); // Gather TreePlacementInfo for trees near the camera. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_GatherTreePlacementInfo ); smAdvanceSignal.trigger( camPos, smWindEffectRadius, &mPlacementInfo ); } // Prepare to build a new local source map. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_SwapSources ); AssertFatal( mPrevSources->isEmpty(), "prev sources not empty!" ); swap( mSources, mPrevSources ); AssertFatal( mSources->isEmpty(), "swap failed!" ); } // Update wind for each TreePlacementInfo { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_UpdateWind ); for( S32 i = 0; i < mPlacementInfo.size(); i++ ) { const TreePlacementInfo &info = mPlacementInfo[i]; updateWind( camPos, info, timeDelta ); } mPlacementInfo.clear(); } // Clean up any accumulators in the // previous local source map. { PROFILE_SCOPE( ForestWindMgr_AdvanceTime_Cleanup ); IdToWindMap::Iterator sourceIter = mPrevSources->begin(); for( ; sourceIter != mPrevSources->end(); sourceIter++ ) { ForestWindAccumulator *accum = (*sourceIter).value; AssertFatal( accum, "Got null accumulator!" ); delete accum; } mPrevSources->clear(); } }