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 MainWindow::labelItemAnchors(QCPAbstractItem *item, double fontSize, bool circle, bool labelBelow)
{
	QList<QCPItemAnchor*> anchors = item->anchors();
	for (int i=0; i<anchors.size(); ++i)
	{
		if (circle)
		{
			QCPItemEllipse *circ = new QCPItemEllipse(item->parentPlot());
			item->parentPlot()->addItem(circ);
			circ->topLeft->setParentAnchor(anchors.at(i));
			circ->bottomRight->setParentAnchor(anchors.at(i));
			circ->topLeft->setCoords(-4, -4);
			circ->bottomRight->setCoords(4, 4);
			QPen p(Qt::blue, 0, Qt::CustomDashLine);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) // Qt 4.8 changed the meaning of this completely...
			p.setDashPattern(QVector<qreal>()<<2<<1);
#else
			p.setDashPattern(QVector<qreal>()<<1<<3);
#endif
			circ->setPen(p);
			if (dynamic_cast<QCPItemPosition*>(anchors.at(i)))
			{
				QCPItemEllipse *circ2 = new QCPItemEllipse(item->parentPlot());
				item->parentPlot()->addItem(circ2);
				circ2->topLeft->setParentAnchor(anchors.at(i));
				circ2->bottomRight->setParentAnchor(anchors.at(i));
				circ2->topLeft->setCoords(-2.5, -2.5);
				circ2->bottomRight->setCoords(2.5, 2.5);
				circ2->setPen(Qt::NoPen);
				circ2->setBrush(Qt::blue);
			}
		}
		if (fontSize > 0)
		{
			QCPItemText *label = new QCPItemText(item->parentPlot());
			item->parentPlot()->addItem(label);
			label->setFont(QFont(font().family(), fontSize));
			label->setColor(Qt::blue);
			label->setText(QString("%2 (%1)").arg(i).arg(anchors.at(i)->name()));
			label->position->setParentAnchor(anchors.at(i));
			if (circle)
				label->position->setCoords(0, fontSize*2*(labelBelow?1:-1));
			else
				label->position->setCoords(0, 0);
			label->setTextAlignment(Qt::AlignCenter);
		}
	}
}
void LiftDragPlot::updatePlot()
{
    clearPlottables();
    clearItems();

    xAxis->setLabel(tr("Drag Coefficient"));
    yAxis->setLabel(tr("Lift Coefficient"));

    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);

    double s10 = 0, s01 = 0, s20 = 0, s11 = 0;
    double s21 = 0, s30 = 0, s40 = 0;

    bool first = true;
    for (int i = start; i < end; ++i)
    {
        const DataPoint &dp = mMainWindow->dataPoint(i);

        t.append(dp.t);
        x.append(dp.drag);
        y.append(dp.lift);

        if (first)
        {
            xMax = x.back();
            yMax = y.back();

            first = false;
        }
        else
        {
            if (x.back() > xMax) xMax = x.back();
            if (y.back() > yMax) yMax = y.back();
        }

        s10 += dp.lift;
        s01 += dp.drag;
        s20 += dp.lift * dp.lift;
        s11 += dp.lift * dp.drag;
        s21 += dp.lift * dp.lift * dp.drag;
        s30 += dp.lift * dp.lift * dp.lift;
        s40 += dp.lift * dp.lift * dp.lift * dp.lift;
    }

    QCPCurve *curve = new QCPCurve(xAxis, yAxis);
    curve->setData(t, x, y);
    curve->setPen(QPen(Qt::lightGray, mMainWindow->lineThickness()));
    curve->setLineStyle(QCPCurve::lsNone);
    curve->setScatterStyle(QCPScatterStyle::ssDisc);
    addPlottable(curve);

    setViewRange(xMax, yMax);

    // Update plot limits
    xMin = xAxis->range().lower;
    xMax = xAxis->range().upper;

    yMin = yAxis->range().lower;
    yMax = yAxis->range().upper;

    if (mMainWindow->markActive())
    {
        int i1 = mMainWindow->findIndexBelowT(mMainWindow->markEnd()) + 1;
        int i2 = mMainWindow->findIndexAboveT(mMainWindow->markEnd()) - 1;

        const DataPoint &dp1 = mMainWindow->dataPoint(i1);
        const DataPoint &dp2 = mMainWindow->dataPoint(i2);

        QVector< double > xMark, yMark;

        if (mMainWindow->markEnd() - dp1.t < dp2.t - mMainWindow->markEnd())
        {
            xMark.append(dp1.drag);
            yMark.append(dp1.lift);
        }
        else
        {
            xMark.append(dp2.drag);
            yMark.append(dp2.lift);
        }

        QCPGraph *graph = addGraph();
        graph->setData(xMark, yMark);
        graph->setPen(QPen(Qt::black, mMainWindow->lineThickness()));
        graph->setLineStyle(QCPGraph::lsNone);
        graph->setScatterStyle(QCPScatterStyle::ssDisc);
    }

    // x = ay^2 + c
    const double m = 1 / mMainWindow->maxLD();
    const double c = mMainWindow->minDrag();
    const double a = m * m / (4 * c);

    // Draw tangent line
    const double yt = sqrt(c / a);

    if (a != 0)
    {
        x.clear();
        y.clear();

        x << m * yMin << m * yMax;
        y << yMin << yMax;

        QCPGraph *graph = addGraph();
        graph->setData(x, y);
        graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine));
    }

    // Draw minimum drag
    x.clear();
    y.clear();

    x << mMainWindow->minDrag() << mMainWindow->minDrag();
    y << yMin << yMax;

    QCPGraph *graph = addGraph();
    graph->setData(x, y);
    graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine));

    // Draw maximum lift
    x.clear();
    y.clear();

    x << xMin << xMax;
    y << mMainWindow->maxLift() << mMainWindow->maxLift();

    graph = addGraph();
    graph->setData(x, y);
    graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine));

    // Draw saved curve
    t.clear();
    x.clear();
    y.clear();

    for (int i = 0; i <= 100; ++i)
    {
        const double yy = yMin + (yMax - yMin) / 100 * i;

        t.append(yy);
        x.append(a * yy * yy + c);
        y.append(yy);
    }

    curve = new QCPCurve(xAxis, yAxis);
    curve->setData(t, x, y);
    curve->setPen(QPen(Qt::red, mMainWindow->lineThickness()));
    addPlottable(curve);

    // Draw dot at maximum L/D
    x.clear();
    y.clear();

    x << a * yt * yt + c;
    y << yt;

    graph = addGraph();
    graph->setData(x, y);
    graph->setPen(QPen(Qt::red, mMainWindow->lineThickness()));
    graph->setLineStyle(QCPGraph::lsNone);
    graph->setScatterStyle(QCPScatterStyle::ssDisc);

    // Add label to show equation for saved curve
    QCPItemText *textLabel = new QCPItemText(this);
    addItem(textLabel);

    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("Minimum drag = %1\nMaximum lift = %2\nMaximum L/D = %3")
                    .arg(fabs(c))
                    .arg(mMainWindow->maxLift())
                    .arg(1/ m));

    replot();
}