Skip to content
qwt_plot_curve.cpp 34.8 KiB
Newer Older
pixhawk's avatar
pixhawk committed
    }

    polyline = ::clipPolygon(painter, d_data->paintAttributes, polyline);

    QwtPainter::drawPolyline(painter, polyline);

    if ( d_data->brush.style() != Qt::NoBrush )
        fillCurve(painter, xMap, yMap, polyline);
}


/*!
  \brief Specify an attribute for drawing the curve

  The attributes can be used to modify the drawing style.
  The following attributes are defined:<dl>
  <dt>Fitted</dt>
  <dd>For Lines only. A QwtCurveFitter tries to
      interpolate/smooth the curve, before it is painted.
      Note that curve fitting requires temorary memory
      for calculating coefficients and additional points.
pixhawk's avatar
pixhawk committed
      If painting in Fitted mode is slow it might be better
      to fit the points, before they are passed to QwtPlotCurve.
  </dd>
  <dt>Inverted</dt>
  <dd>For Steps only. Draws a step function
      from the right to the left.</dd></dl>

  \param attribute Curve attribute
  \param on On/Off

  /sa testCurveAttribute(), setCurveFitter()
*/
void QwtPlotCurve::setCurveAttribute(CurveAttribute attribute, bool on)
{
    if ( bool(d_data->attributes & attribute) == on )
        return;

    if ( on )
        d_data->attributes |= attribute;
    else
        d_data->attributes &= ~attribute;

    itemChanged();
}

/*!
    \return true, if attribute is enabled
    \sa setCurveAttribute()
*/
bool QwtPlotCurve::testCurveAttribute(CurveAttribute attribute) const
{
pixhawk's avatar
pixhawk committed
    return d_data->attributes & attribute;
}

/*!
  Assign the curve type

  <dt>QwtPlotCurve::Yfx
  <dd>Draws y as a function of x (the default). The
      baseline is interpreted as a horizontal line
      with y = baseline().</dd>
  <dt>QwtPlotCurve::Xfy
  <dd>Draws x as a function of y. The baseline is
      interpreted as a vertical line with x = baseline().</dd>

  The baseline is used for aligning the sticks, or
  filling the curve with a brush.

  \sa curveType()
*/
void QwtPlotCurve::setCurveType(CurveType curveType)
{
    if ( d_data->curveType != curveType ) {
pixhawk's avatar
pixhawk committed
        d_data->curveType = curveType;
        itemChanged();
    }
}

/*!
   Return the curve type
   \sa setCurveType()
*/
QwtPlotCurve::CurveType QwtPlotCurve::curveType() const
{
    return d_data->curveType;
}

void QwtPlotCurve::setCurveFitter(QwtCurveFitter *curveFitter)
{
    delete d_data->curveFitter;
    d_data->curveFitter = curveFitter;

    itemChanged();
}

QwtCurveFitter *QwtPlotCurve::curveFitter() const
{
    return d_data->curveFitter;
}

/*!
  Fill the area between the curve and the baseline with
pixhawk's avatar
pixhawk committed
  the curve brush

  \param painter Painter
  \param xMap x map
  \param yMap y map
  \param pa Polygon

  \sa setBrush(), setBaseline(), setCurveType()
*/

void QwtPlotCurve::fillCurve(QPainter *painter,
                             const QwtScaleMap &xMap, const QwtScaleMap &yMap,
                             QwtPolygon &pa) const
pixhawk's avatar
pixhawk committed
{
    if ( d_data->brush.style() == Qt::NoBrush )
        return;

    closePolyline(xMap, yMap, pa);
    if ( pa.count() <= 2 ) // a line can't be filled
        return;

    QBrush b = d_data->brush;
    if ( !b.color().isValid() )
        b.setColor(d_data->pen.color());

    painter->save();

    painter->setPen(QPen(Qt::NoPen));
    painter->setBrush(b);

    QwtPainter::drawPolygon(painter, pa);

    painter->restore();
}

/*!
  \brief Complete a polygon to be a closed polygon
pixhawk's avatar
pixhawk committed
         including the area between the original polygon
         and the baseline.
  \param xMap X map
  \param yMap Y map
  \param pa Polygon to be completed
*/

void QwtPlotCurve::closePolyline(
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    QwtPolygon &pa) const
{
    const int sz = pa.size();
    if ( sz < 2 )
        return;

    pa.resize(sz + 2);

    if ( d_data->curveType == QwtPlotCurve::Xfy ) {
pixhawk's avatar
pixhawk committed
        pa.setPoint(sz,
                    xMap.transform(d_data->reference), pa.point(sz - 1).y());
pixhawk's avatar
pixhawk committed
        pa.setPoint(sz + 1,
                    xMap.transform(d_data->reference), pa.point(0).y());
    } else {
pixhawk's avatar
pixhawk committed
        pa.setPoint(sz,
                    pa.point(sz - 1).x(), yMap.transform(d_data->reference));
pixhawk's avatar
pixhawk committed
        pa.setPoint(pa.size() - 1,
                    pa.point(0).x(), yMap.transform(d_data->reference));
pixhawk's avatar
pixhawk committed
    }
}

/*!
  \brief Draw symbols
  \param painter Painter
  \param symbol Curve symbol
  \param xMap x map
  \param yMap y map
  \param from index of the first point to be painted
  \param to index of the last point to be painted

  \sa setSymbol(), draw(), drawCurve()
*/
void QwtPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
                               const QwtScaleMap &xMap, const QwtScaleMap &yMap,
                               int from, int to) const
pixhawk's avatar
pixhawk committed
{
    painter->setBrush(symbol.brush());

    const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();

    QPen pen = symbol.pen();

#if SCALE_PEN
    if ( pen.width() > 0 )
        pen.setWidth(metricsMap.screenToLayoutX(pen.width()));
#endif

    painter->setPen(pen);

    QRect rect;
    rect.setSize(metricsMap.screenToLayout(symbol.size()));

    if ( to > from && d_data->paintAttributes & PaintFiltered ) {
pixhawk's avatar
pixhawk committed
        const QRect window = painter->window();
        if ( window.isEmpty() )
            return;

        PrivateData::PixelMatrix pixelMatrix(window);

        for (int i = from; i <= to; i++) {
pixhawk's avatar
pixhawk committed
            const QPoint pi( xMap.transform(x(i)),
                             yMap.transform(y(i)) );
pixhawk's avatar
pixhawk committed

            if ( pixelMatrix.testPixel(pi) ) {
pixhawk's avatar
pixhawk committed
                rect.moveCenter(pi);
                symbol.draw(painter, rect);
            }
        }
    } else {
        for (int i = from; i <= to; i++) {
pixhawk's avatar
pixhawk committed
            const int xi = xMap.transform(x(i));
            const int yi = yMap.transform(y(i));

            rect.moveCenter(QPoint(xi, yi));
            symbol.draw(painter, rect);
        }
    }
}

/*!
  \brief Set the value of the baseline

  The baseline is needed for filling the curve with a brush or
  the Sticks drawing style.
pixhawk's avatar
pixhawk committed
  The default value is 0.0. The interpretation
  of the baseline depends on the CurveType. With QwtPlotCurve::Yfx,
  the baseline is interpreted as a horizontal line at y = baseline(),
  with QwtPlotCurve::Yfy, it is interpreted as a vertical line at
  x = baseline().
  \param reference baseline
  \sa baseline(), setBrush(), setStyle(), setCurveType()
*/
void QwtPlotCurve::setBaseline(double reference)
{
    if ( d_data->reference != reference ) {
pixhawk's avatar
pixhawk committed
        d_data->reference = reference;
        itemChanged();
    }
}

/*!
    Return the value of the baseline
    \sa setBaseline
*/
double QwtPlotCurve::baseline() const
{
    return d_data->reference;
pixhawk's avatar
pixhawk committed
}

/*!
  Return the size of the data arrays
  \sa setData()
*/
int QwtPlotCurve::dataSize() const
{
    return d_xy->size();
}

int QwtPlotCurve::closestPoint(const QPoint &pos, double *dist) const
{
    if ( plot() == NULL || dataSize() <= 0 )
        return -1;

    const QwtScaleMap xMap = plot()->canvasMap(xAxis());
    const QwtScaleMap yMap = plot()->canvasMap(yAxis());

    int index = -1;
    double dmin = 1.0e10;

    for (int i=0; i < dataSize(); i++) {
pixhawk's avatar
pixhawk committed
        const double cx = xMap.xTransform(x(i)) - pos.x();
        const double cy = yMap.xTransform(y(i)) - pos.y();

        const double f = qwtSqr(cx) + qwtSqr(cy);
        if (f < dmin) {
pixhawk's avatar
pixhawk committed
            index = i;
            dmin = f;
        }
    }
    if ( dist )
        *dist = sqrt(dmin);

    return index;
}

//!  Update the widget that represents the curve on the legend
void QwtPlotCurve::updateLegend(QwtLegend *legend) const
{
    if ( !legend )
        return;

    QwtPlotItem::updateLegend(legend);

    QWidget *widget = legend->find(this);
    if ( !widget || !widget->inherits("QwtLegendItem") )
        return;

    QwtLegendItem *legendItem = (QwtLegendItem *)widget;

#if QT_VERSION < 0x040000
    const bool doUpdate = legendItem->isUpdatesEnabled();
#else
    const bool doUpdate = legendItem->updatesEnabled();
#endif
    legendItem->setUpdatesEnabled(false);

    const int policy = legend->displayPolicy();

    if (policy == QwtLegend::FixedIdentifier) {
pixhawk's avatar
pixhawk committed
        int mode = legend->identifierMode();

        if (mode & QwtLegendItem::ShowLine)
            legendItem->setCurvePen(pen());

        if (mode & QwtLegendItem::ShowSymbol)
            legendItem->setSymbol(symbol());

        if (mode & QwtLegendItem::ShowText)
            legendItem->setText(title());
        else
            legendItem->setText(QwtText());

        legendItem->setIdentifierMode(mode);
    } else if (policy == QwtLegend::AutoIdentifier) {
pixhawk's avatar
pixhawk committed
        int mode = 0;

        if (QwtPlotCurve::NoCurve != style()) {
pixhawk's avatar
pixhawk committed
            legendItem->setCurvePen(pen());
            mode |= QwtLegendItem::ShowLine;
        }
        if (QwtSymbol::NoSymbol != symbol().style()) {
pixhawk's avatar
pixhawk committed
            legendItem->setSymbol(symbol());
            mode |= QwtLegendItem::ShowSymbol;
        }
        if ( !title().isEmpty() ) {
pixhawk's avatar
pixhawk committed
            legendItem->setText(title());
            mode |= QwtLegendItem::ShowText;
pixhawk's avatar
pixhawk committed
            legendItem->setText(QwtText());
        }
        legendItem->setIdentifierMode(mode);
    }

    legendItem->setUpdatesEnabled(doUpdate);
    legendItem->update();
}