Esempio n. 1
0
bool SingleCellViewSimulationData::isModified() const
{
    // Check whether any of our constants or states has been modified
    // Note: we start with our states since they are more likely to be modified
    //       than our constants...

    iface::cellml_services::CellMLCompiledModel*
        compModel(isDAETypeSolver() ?
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->daeCompiledModel()) :
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->odeCompiledModel()));
    ObjRef<iface::cellml_services::CodeInformation> codeInfo
        (compModel->codeInformation());
    
    bool foundChange = false;
    for (int i = 0; i < mInitialConstants.size(); i++)
        if (!qIsFinite(mInitialConstants[i]) ||
            mInitialConstants[i] != mConstants[i])
            return true;
    if (!foundChange)
        for (int i = 0; i < mInitialStates.size(); i++)
            if (!qIsFinite(mInitialStates[i]) ||
                mInitialStates[i] != mStates[i])
                return true;

    return false;
}
Esempio n. 2
0
/*!
    Returns the number of representable floating-point numbers between \a a and \a b.

    This function serves the same purpose as \c{qFloatDistance(float, float)}, but
    returns the distance between two \c double numbers. Since the range is larger
    than for two \c float numbers (\c{[-DBL_MAX,DBL_MAX]}), the return type is quint64.


    \sa qFuzzyCompare()
    \since 5.2
    \relates <QtGlobal>
*/
Q_CORE_EXPORT quint64 qFloatDistance(double a, double b)
{
    static const quint64 smallestPositiveFloatAsBits = 0x1;  // denormalized, (SMALLEST)
    /* Assumes:
       * IEE754 format double precision
       * Integers and floats have the same endian
    */
    Q_STATIC_ASSERT(sizeof(quint64) == sizeof(double));
    Q_ASSERT(qIsFinite(a) && qIsFinite(b));
    if (a == b)
        return 0;
    if ((a < 0) != (b < 0)) {
        // if they have different signs
        if (a < 0)
            a = -a;
        else /*if (b < 0)*/
            b = -b;
        return qFloatDistance(0.0, a) + qFloatDistance(0.0, b);
    }
    if (a < 0) {
        a = -a;
        b = -b;
    }
    // at this point a and b should not be negative

    // 0 is special
    if (!a)
        return d2i(b) - smallestPositiveFloatAsBits + 1;
    if (!b)
        return d2i(a) - smallestPositiveFloatAsBits + 1;

    // finally do the common integer subtraction
    return a > b ? d2i(a) - d2i(b) : d2i(b) - d2i(a);
}
Esempio n. 3
0
/*!
    Returns the number of representable floating-point numbers between \a a and \a b.

    This function provides an alternative way of doing approximated comparisons of floating-point
    numbers similar to qFuzzyCompare(). However, it returns the distance between two numbers, which
    gives the caller a possibility to choose the accepted error. Errors are relative, so for
    instance the distance between 1.0E-5 and 1.00001E-5 will give 110, while the distance between
    1.0E36 and 1.00001E36 will give 127.

    This function is useful if a floating point comparison requires a certain precision.
    Therefore, if \a a and \a b are equal it will return 0. The maximum value it will return for 32-bit
    floating point numbers is 4,278,190,078. This is the distance between \c{-FLT_MAX} and
    \c{+FLT_MAX}.

    The function does not give meaningful results if any of the arguments are \c Infinite or \c NaN.
    You can check for this by calling qIsFinite().

    The return value can be considered as the "error", so if you for instance want to compare
    two 32-bit floating point numbers and all you need is an approximated 24-bit precision, you can
    use this function like this:

    \code
    if (qFloatDistance(a, b) < (1 << 7)) {   // The last 7 bits are not
                                            // significant
        // precise enough
    }
    \endcode

    \sa qFuzzyCompare()
    \since 5.2
    \relates <QtGlobal>
*/
Q_CORE_EXPORT quint32 qFloatDistance(float a, float b)
{
    static const quint32 smallestPositiveFloatAsBits = 0x00000001;  // denormalized, (SMALLEST), (1.4E-45)
    /* Assumes:
       * IEE754 format.
       * Integers and floats have the same endian
    */
    Q_STATIC_ASSERT(sizeof(quint32) == sizeof(float));
    Q_ASSERT(qIsFinite(a) && qIsFinite(b));
    if (a == b)
        return 0;
    if ((a < 0) != (b < 0)) {
        // if they have different signs
        if (a < 0)
            a = -a;
        else /*if (b < 0)*/
            b = -b;
        return qFloatDistance(0.0F, a) + qFloatDistance(0.0F, b);
    }
    if (a < 0) {
        a = -a;
        b = -b;
    }
    // at this point a and b should not be negative

    // 0 is special
    if (!a)
        return f2i(b) - smallestPositiveFloatAsBits + 1;
    if (!b)
        return f2i(a) - smallestPositiveFloatAsBits + 1;

    // finally do the common integer subtraction
    return a > b ? f2i(a) - f2i(b) : f2i(b) - f2i(a);
}
/*!
    \internal
*/
void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
                                                const QList<QGeoCoordinate> &path)
{
    if (!sourceDirty_)
        return;

    qreal minX = -1.0;

    // build the actual path
    QPointF origin;
    QPointF lastPoint;
    srcPath_ = QPainterPath();

    double unwrapBelowX = 0;
    if (preserveGeometry_ )
        unwrapBelowX = map.coordinateToScreenPosition(geoLeftBound_, false).x();

    for (int i = 0; i < path.size(); ++i) {
        const QGeoCoordinate &coord = path.at(i);

        if (!coord.isValid())
            continue;

        QPointF point = map.coordinateToScreenPosition(coord, false);

        // We can get NaN if the map isn't set up correctly, or the projection
        // is faulty -- probably best thing to do is abort
        if (!qIsFinite(point.x()) || !qIsFinite(point.y()))
            return;

        // unwrap x to preserve geometry if moved to border of map
        if (preserveGeometry_ && point.x() < unwrapBelowX && !qFuzzyCompare(point.x(), unwrapBelowX))
            point.setX(unwrapBelowX + geoDistanceToScreenWidth(map, geoLeftBound_, coord));

        if (i == 0) {
            origin = point;
            minX = point.x();
            srcOrigin_ = coord;
            srcPath_.moveTo(point - origin);
            lastPoint = point;
        } else {
            if (point.x() <= minX)
                minX = point.x();
            const QPointF diff = (point - lastPoint);
            if (diff.x() * diff.x() + diff.y() * diff.y() >= 3.0) {
                srcPath_.lineTo(point - origin);
                lastPoint = point;
            }
        }
    }

    srcPath_.closeSubpath();

    if (!assumeSimple_)
        srcPath_ = srcPath_.simplified();

    sourceBounds_ = srcPath_.boundingRect();
    geoLeftBound_ = map.screenPositionToCoordinate(QPointF(minX, 0), false);
}
void YAxis::autoscale(int64_t start, int64_t end)
{
    float minimum = INFINITY;
    float maximum = -INFINITY;
    float extralen;

    bool alldatadensity = true;

    for (auto i = this->streams.begin(); i != this->streams.end(); i++)
    {
        Stream* s = *i;
        QList<QSharedPointer<CacheEntry>>& entries = s->data;
        for (auto j = entries.begin(); j != entries.end(); j++)
        {
            QSharedPointer<CacheEntry> entry = *j;
            entry->getRange(start, end, s->dataDensity, minimum, maximum);
            if (s->dataDensity)
            {
                /*
                 * If we're plotting a data density stream, then we need to
                 * make sure that the minimum of the range contains zero.
                 */
                minimum = 0.0f;
            }
            else
            {
                alldatadensity = false;
            }
        }
    }

    extralen = (maximum - minimum) * 0.05;
    maximum += extralen;
    minimum -= extralen;

    if (qIsFinite(minimum) && qIsFinite(maximum))
    {
        if (minimum == maximum)
        {
            minimum -= 1.0f;
            maximum += 1.0f;
        }

        niceScale(&minimum, &maximum, this->minticks);
        if (alldatadensity)
        {
            /*
             * We set the minimum to a value slightly below zero, so that the
             * data density line doesn't get partially cut off if it goes to
             * zero.
             */
            minimum = -maximum / 100.0f;
        }
        this->setDomain(minimum, maximum);
    }
}
/*!
    \internal
*/
void QGeoMapRectangleGeometry::updatePoints(const QGeoMap &map,
                                            const QGeoCoordinate &topLeft,
                                            const QGeoCoordinate &bottomRight)
{
    if (!screenDirty_ && !sourceDirty_)
        return;

    QPointF tl = map.coordinateToScreenPosition(topLeft, false);
    QPointF br = map.coordinateToScreenPosition(bottomRight, false);

    // We can get NaN if the map isn't set up correctly, or the projection
    // is faulty -- probably best thing to do is abort
    if (!qIsFinite(tl.x()) || !qIsFinite(tl.y()))
        return;
    if (!qIsFinite(br.x()) || !qIsFinite(br.y()))
        return;

    if ( preserveGeometry_ ) {
        double unwrapBelowX = map.coordinateToScreenPosition(geoLeftBound_, false).x();
        if (br.x() < unwrapBelowX)
            br.setX(tl.x() + screenBounds_.width());
    }


    QRectF re(tl, br);
    re.translate(-1 * tl);

    clear();
    screenVertices_.reserve(6);

    screenVertices_ << re.topLeft();
    screenVertices_ << re.topRight();
    screenVertices_ << re.bottomLeft();

    screenVertices_ << re.topRight();
    screenVertices_ << re.bottomLeft();
    screenVertices_ << re.bottomRight();

    firstPointOffset_ = QPointF(0,0);
    srcOrigin_ = topLeft;
    screenBounds_ = re;

    screenOutline_ = QPainterPath();
    screenOutline_.addRect(re);

    geoLeftBound_ = topLeft;
}
bool SingleCellViewSimulationData::isModified() const
{
    if (!mRuntime)
        return false;

    // Check whether any of our constants or states has been modified
    // Note: we start with our states since they are more likely to be modified
    //       than our constants...

    for (int i = 0, iMax = mRuntime->statesCount(); i < iMax; ++i)
        if (!qIsFinite(mStates[i]) || !qFuzzyCompare(mStates[i], mInitialStates[i]))
            return true;

    for (int i = 0, iMax = mRuntime->constantsCount(); i < iMax; ++i)
        if (!qIsFinite(mConstants[i]) || !qFuzzyCompare(mConstants[i], mInitialConstants[i]))
            return true;

    return false;
}
void SingleCellViewGraphPanelPlotWidget::checkAnyAxesValues(double &pMinX,
                                                            double &pMaxX,
                                                            double &pMinY,
                                                            double &pMaxY)
{
    // Make sure that the minimum/maximum values of our (local) axes have finite
    // values

    if (!qIsFinite(pMinX))
        pMinX = -DBL_MAX;

    if (!qIsFinite(pMaxX))
        pMaxX = DBL_MAX;

    if (!qIsFinite(pMinY))
        pMinY = -DBL_MAX;

    if (!qIsFinite(pMaxY))
        pMaxY = DBL_MAX;
}
bool AcSensorBridge::toDBus(const QString &path, QVariant &value)
{
	if (path == "/Connected") {
		value = QVariant(value.value<ConnectionState>() == Connected ? 1 : 0);
	} else if (path == "/Position") {
		value = QVariant(static_cast<int>(value.value<Position>()));
	}
	if (value.type() == QVariant::Double && !qIsFinite(value.toDouble()))
		value = QVariant();
	return true;
}
Esempio n. 10
0
bool isDoubleEqual(double a, double b)
{
	if (!qIsFinite(a) || !qIsFinite(b)) return(false);
	double valmax = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
	if (valmax < 1e-10)
	{
		return(fabs(a - b) < 1e10);
	}
	else if (valmax < 1e-9)
	{
		return(fabs((a - b)/valmax) < 5e-2);
	}
	else if(valmax < 1e-8)
	{
		return (fabs((a-b)/valmax) < 1e-3);
	}
	else
	{
		return (fabs((a-b)/valmax) < 1e-4);
	}
}
void SingleCellViewGraphPanelPlotWidget::checkAxisValues(double &pMin,
                                                         double &pMax)
{
    // Make sure that our axis' values have finite values

    if (!qIsFinite(pMin))
        pMin = MinAxis;

    if (!qIsFinite(pMax))
        pMax = MaxAxis;

    // Make sure that our axis' values are valid

    double range = pMax-pMin;

    if (range > MaxAxisRange) {
        // The range is too big, so reset our values

        pMin = MinAxis;
        pMax = MaxAxis;
    } else if (range < MinAxisRange) {
        // The range is too small, so reset our values

        pMin = qMax(MinAxis, 0.5*(pMin+pMax-MinAxisRange));
        pMax = qMin(MaxAxis, pMin+MinAxisRange);
        pMin = pMax-MinAxisRange;
        // Note: the last statement is in case pMax was set to MaxAxis, in which
        //       case pMin has to be re-reset...
    } else if (pMin < MinAxis) {
        // The minimum value is too small, so reset it

        pMin = MinAxis;
        pMax = pMin+range;
    } else if (pMax > MaxAxis) {
        // The maximum value is too big, so reset it

        pMax = MaxAxis;
        pMin = pMax-range;
    }
}
bool YAxis::setDomain(float low, float high)
{
    if (low >= high || !qIsFinite(low) || !qIsFinite(high))
    {
        return false;
    }

    if (this->domainLo == low && this->domainHi == high) {
        return true;
    }

    // I used to have this code so that axes could be animated, but
    // it caused stack overflow problems once I added the notify signal
    /*this->setProperty("domainLo", low);
    this->setProperty("domainHi", high);*/

    this->domainLo = low;
    this->domainHi = high;

    for (auto j = this->axisareas.begin(); j != this->axisareas.end(); j++)
    {
        (*j)->update();
        if ((*j)->plotarea != nullptr) {
            (*j)->plotarea->update();
        }
    }
    for (auto i = this->streams.begin(); i != this->streams.end(); i++)
    {
        Stream* s = *i;
        if (s->plotarea != nullptr)
        {
            s->plotarea->update();
        }
    }

    emit this->domainChanged();

    return true;
}
Esempio n. 13
0
QString KSUtils::getDSSURL( const dms &ra, const dms &dec, float width, float height, const QString & type) {
    const QString URLprefix( "http://archive.stsci.edu/cgi-bin/dss_search?v=poss2ukstu_blue" );
    QString URLsuffix = QString( "&e=J2000&f=%1&c=none&fov=NONE" ).arg(type);
    const double dss_default_size = Options::defaultDSSImageSize();

    char decsgn = ( dec.Degrees() < 0.0 ) ? '-' : '+';
    int dd = abs( dec.degree() );
    int dm = abs( dec.arcmin() );
    int ds = abs( dec.arcsec() );

    // Infinite and NaN sizes are replaced by the default size
    if( !qIsFinite( height ) )
        height = dss_default_size;
    if( !qIsFinite( width ) )
        width = dss_default_size;

    // Negative / zero sizes are replaced by the default size
    if( height <= 0.0 )
        height = dss_default_size;
    if( width <= 0.0 )
        width = dss_default_size;

    // DSS accepts images that are no larger than 75 arcminutes
    if( height > 75.0 )
        height = 75.0;
    if( width > 75.0 )
        width = 75.0;

    QString RAString, DecString, SizeString;
    DecString = DecString.sprintf( "&d=%c%02d+%02d+%02d", decsgn, dd, dm, ds );
    RAString  = RAString.sprintf( "&r=%02d+%02d+%02d", ra.hour(), ra.minute(), ra.second() );
    SizeString = SizeString.sprintf( "&h=%02.1f&w=%02.1f", height, width );

    return ( URLprefix + RAString + DecString + SizeString + URLsuffix );

}
//-----------------------------------------------------------------------------
QWidget* qtDoubleSpinBoxDelegate::createEditor(
  QWidget* parent, const QStyleOptionViewItem&, const QModelIndex&) const
{
  QTE_D_CONST(qtDoubleSpinBoxDelegate);

  QDoubleSpinBox* editor = new QDoubleSpinBox(parent);

  if (qIsFinite(d->minimum))
    {
    editor->setMinimum(d->minimum);
    }
  if (qIsFinite(d->maximum))
    {
    editor->setMaximum(d->maximum);
    }

  if (d->precision >= 0)
    {
    editor->setDecimals(d->precision);
    editor->setSingleStep(1.0 / pow(1e1, d->precision));
    }

  return editor;
}
Esempio n. 15
0
QScriptValueImpl Math::method_atan2(QScriptContextPrivate *context,
                                    QScriptEnginePrivate *eng,
                                    QScriptClassInfo *)
{
    qsreal v1 = context->argument(0).toNumber();
    qsreal v2 = context->argument(1).toNumber();
#ifdef Q_OS_WINCE
    if (v1 == 0.0) {
        const bool v1MinusZero = _copysign(1.0, v1) < 0.0;
        const bool v2MinusZero = (v2 == 0 && _copysign(1.0, v2) < 0.0);
        if ((v1MinusZero && v2MinusZero) || (v1MinusZero && v2 == -1.0))
            return QScriptValueImpl(eng, -qt_PI);
        if (v2MinusZero)
            return QScriptValueImpl(eng, qt_PI);
        if (v1MinusZero && v2 == 1.0)
            return QScriptValueImpl(eng, -0.0);
#if defined(_X86_)
        if (v2 == 0.0 && (v1MinusZero || (!v1MinusZero && !v2MinusZero)))
            return QScriptValueImpl(eng, 0.0);
#endif
    }
#endif
#if defined(Q_OS_WINCE) && defined(_X86_)
    if (v1 == -1.0 && !_finite(v2) && _copysign(1.0, v2) > 0.0)
        return QScriptValueImpl(eng, -0.0);
#endif
    if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0))
        return QScriptValueImpl(eng, copySign(0, -1.0));
    if ((v1 == 0.0) && (v2 == 0.0)) {
        if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0))
            return QScriptValueImpl(eng, qt_PI);
        else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0))
            return QScriptValueImpl(eng, -qt_PI);
    }
    return (QScriptValueImpl(eng, ::atan2(v1, v2)));
}
Esempio n. 16
0
QString QgsPoint::toString( int thePrecision ) const
{
  QString x = qIsFinite( m_x ) ? QString::number( m_x, 'f', thePrecision ) : QObject::tr( "infinite" );
  QString y = qIsFinite( m_y ) ? QString::number( m_y, 'f', thePrecision ) : QObject::tr( "infinite" );
  return QStringLiteral( "%1,%2" ).arg( x, y );
}
void QgsDelimitedTextProvider::scanFile( bool buildIndexes )
{
  QStringList messages;

  // assume the layer is invalid until proven otherwise

  mLayerValid = false;
  mValid = false;
  mRescanRequired = false;

  clearInvalidLines();

  // Initiallize indexes

  resetIndexes();
  bool buildSpatialIndex = buildIndexes && mSpatialIndex != 0;

  // No point building a subset index if there is no geometry, as all
  // records will be included.

  bool buildSubsetIndex = buildIndexes && mBuildSubsetIndex && mGeomRep != GeomNone;

  if ( ! mFile->isValid() )
  {
    // uri is invalid so the layer must be too...

    messages.append( tr( "File cannot be opened or delimiter parameters are not valid" ) );
    reportErrors( messages );
    QgsDebugMsg( "Delimited text source invalid - filename or delimiter parameters" );
    return;
  }

  // Open the file and get number of rows, etc. We assume that the
  // file has a header row and process accordingly. Caller should make
  // sure that the delimited file is properly formed.

  if ( mGeomRep == GeomAsWkt )
  {
    mWktFieldIndex = mFile->fieldIndex( mWktFieldName );
    if ( mWktFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Wkt", mWktFieldName ) );
    }
  }
  else if ( mGeomRep == GeomAsXy )
  {
    mXFieldIndex = mFile->fieldIndex( mXFieldName );
    mYFieldIndex = mFile->fieldIndex( mYFieldName );
    if ( mXFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "X", mWktFieldName ) );
    }
    if ( mYFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Y", mWktFieldName ) );
    }
  }
  if ( messages.size() > 0 )
  {
    reportErrors( messages );
    QgsDebugMsg( "Delimited text source invalid - missing geometry fields" );
    return;
  }

  // Scan the entire file to determine
  // 1) the number of fields (this is handled by QgsDelimitedTextFile mFile
  // 2) the number of valid features.  Note that the selection of valid features
  //    should match the code in QgsDelimitedTextFeatureIterator
  // 3) the geometric extents of the layer
  // 4) the type of each field
  //
  // Also build subset and spatial indexes.

  QStringList parts;
  long nEmptyRecords = 0;
  long nBadFormatRecords = 0;
  long nIncompatibleGeometry = 0;
  long nInvalidGeometry = 0;
  long nEmptyGeometry = 0;
  mNumberFeatures = 0;
  mExtent = QgsRectangle();

  QList<bool> isEmpty;
  QList<bool> couldBeInt;
  QList<bool> couldBeLongLong;
  QList<bool> couldBeDouble;

  while ( true )
  {
    QgsDelimitedTextFile::Status status = mFile->nextRecord( parts );
    if ( status == QgsDelimitedTextFile::RecordEOF ) break;
    if ( status != QgsDelimitedTextFile::RecordOk )
    {
      nBadFormatRecords++;
      recordInvalidLine( tr( "Invalid record format at line %1" ) );
      continue;
    }
    // Skip over empty records
    if ( recordIsEmpty( parts ) )
    {
      nEmptyRecords++;
      continue;
    }

    // Check geometries are valid
    bool geomValid = true;

    if ( mGeomRep == GeomAsWkt )
    {
      if ( mWktFieldIndex >= parts.size() || parts[mWktFieldIndex].isEmpty() )
      {
        nEmptyGeometry++;
        mNumberFeatures++;
      }
      else
      {
        // Get the wkt - confirm it is valid, get the type, and
        // if compatible with the rest of file, add to the extents

        QString sWkt = parts[mWktFieldIndex];
        QgsGeometry *geom = 0;
        if ( !mWktHasPrefix && sWkt.indexOf( WktPrefixRegexp ) >= 0 )
          mWktHasPrefix = true;
        if ( !mWktHasZM && sWkt.indexOf( WktZMRegexp ) >= 0 )
          mWktHasZM = true;
        geom = geomFromWkt( sWkt, mWktHasPrefix, mWktHasZM );

        if ( geom )
        {
          QGis::WkbType type = geom->wkbType();
          if ( type != QGis::WKBNoGeometry )
          {
            if ( mGeometryType == QGis::UnknownGeometry || geom->type() == mGeometryType )
            {
              mGeometryType = geom->type();
              if ( mNumberFeatures == 0 )
              {
                mNumberFeatures++;
                mWkbType = type;
                mExtent = geom->boundingBox();
              }
              else
              {
                mNumberFeatures++;
                if ( geom->isMultipart() ) mWkbType = type;
                QgsRectangle bbox( geom->boundingBox() );
                mExtent.combineExtentWith( &bbox );
              }
              if ( buildSpatialIndex )
              {
                QgsFeature f;
                f.setFeatureId( mFile->recordId() );
                f.setGeometry( geom );
                mSpatialIndex->insertFeature( f );
                // Feature now has ownership of geometry, so set to null
                // here to avoid deleting twice.
                geom = 0;
              }
            }
            else
            {
              nIncompatibleGeometry++;
              geomValid = false;
            }
          }
          if ( geom ) delete geom;
        }
        else
        {
          geomValid = false;
          nInvalidGeometry++;
          recordInvalidLine( tr( "Invalid WKT at line %1" ) );
        }
      }
    }
    else if ( mGeomRep == GeomAsXy )
    {
      // Get the x and y values, first checking to make sure they
      // aren't null.

      QString sX = mXFieldIndex < parts.size() ? parts[mXFieldIndex] : QString();
      QString sY = mYFieldIndex < parts.size() ? parts[mYFieldIndex] : QString();
      if ( sX.isEmpty() && sY.isEmpty() )
      {
        nEmptyGeometry++;
        mNumberFeatures++;
      }
      else
      {
        QgsPoint pt;
        bool ok = pointFromXY( sX, sY, pt, mDecimalPoint, mXyDms );

        if ( ok )
        {
          if ( mNumberFeatures > 0 )
          {
            mExtent.combineExtentWith( pt.x(), pt.y() );
          }
          else
          {
            // Extent for the first point is just the first point
            mExtent.set( pt.x(), pt.y(), pt.x(), pt.y() );
            mWkbType = QGis::WKBPoint;
            mGeometryType = QGis::Point;
          }
          mNumberFeatures++;
          if ( buildSpatialIndex && qIsFinite( pt.x() ) && qIsFinite( pt.y() ) )
          {
            QgsFeature f;
            f.setFeatureId( mFile->recordId() );
            f.setGeometry( QgsGeometry::fromPoint( pt ) );
            mSpatialIndex->insertFeature( f );
          }
        }
        else
        {
          geomValid = false;
          nInvalidGeometry++;
          recordInvalidLine( tr( "Invalid X or Y fields at line %1" ) );
        }
      }
    }
    else
    {
      mWkbType = QGis::WKBNoGeometry;
      mNumberFeatures++;
    }

    if ( ! geomValid ) continue;

    if ( buildSubsetIndex ) mSubsetIndex.append( mFile->recordId() );


    // If we are going to use this record, then assess the potential types of each colum

    for ( int i = 0; i < parts.size(); i++ )
    {

      QString &value = parts[i];
      // Ignore empty fields - spreadsheet generated CSV files often
      // have random empty fields at the end of a row
      if ( value.isEmpty() )
        continue;

      // Expand the columns to include this non empty field if necessary

      while ( couldBeInt.size() <= i )
      {
        isEmpty.append( true );
        couldBeInt.append( false );
        couldBeLongLong.append( false );
        couldBeDouble.append( false );
      }

      // If this column has been empty so far then initiallize it
      // for possible types

      if ( isEmpty[i] )
      {
        isEmpty[i] = false;
        couldBeInt[i] = true;
        couldBeLongLong[i] = true;
        couldBeDouble[i] = true;
      }

      // Now test for still valid possible types for the field
      // Types are possible until first record which cannot be parsed

      if ( couldBeInt[i] )
      {
        value.toInt( &couldBeInt[i] );
      }

      if ( couldBeLongLong[i] && ! couldBeInt[i] )
      {
        value.toLongLong( &couldBeLongLong[i] );
      }

      if ( couldBeDouble[i] && ! couldBeLongLong[i] )
      {
        if ( ! mDecimalPoint.isEmpty() )
        {
          value.replace( mDecimalPoint, "." );
        }
        value.toDouble( &couldBeDouble[i] );
      }
    }
  }

  // Now create the attribute fields.  Field types are integer by preference,
  // failing that double, failing that text.

  QStringList fieldNames = mFile->fieldNames();
  mFieldCount = fieldNames.size();
  attributeColumns.clear();
  attributeFields.clear();

  QString csvtMessage;
  QStringList csvtTypes = readCsvtFieldTypes( mFile->fileName(), &csvtMessage );

  for ( int i = 0; i < fieldNames.size(); i++ )
  {
    // Skip over WKT field ... don't want to display in attribute table
    if ( i == mWktFieldIndex ) continue;

    // Add the field index lookup for the column
    attributeColumns.append( i );
    QVariant::Type fieldType = QVariant::String;
    QString typeName = "text";
    if ( i < csvtTypes.size() )
    {
      if ( csvtTypes[i] == "integer" )
      {
        fieldType = QVariant::Int;
        typeName = "integer";
      }
      else if ( csvtTypes[i] == "long" || csvtTypes[i] == "longlong" || csvtTypes[i] == "int8" )
      {
        fieldType = QVariant::LongLong; //QVariant doesn't support long
        typeName = "longlong";
      }
      else if ( csvtTypes[i] == "real" || csvtTypes[i] == "double" )
      {
        fieldType = QVariant::Double;
        typeName = "double";
      }
    }
    else if ( i < couldBeInt.size() )
    {
      if ( couldBeInt[i] )
      {
        fieldType = QVariant::Int;
        typeName = "integer";
      }
      else if ( couldBeLongLong[i] )
      {
        fieldType = QVariant::LongLong;
        typeName = "longlong";
      }
      else if ( couldBeDouble[i] )
      {
        fieldType = QVariant::Double;
        typeName = "double";
      }
    }
    attributeFields.append( QgsField( fieldNames[i], fieldType, typeName ) );
  }


  QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) );
  QgsDebugMsg( "geometry type is: " + QString::number( mWkbType ) );
  QgsDebugMsg( "feature count is: " + QString::number( mNumberFeatures ) );

  QStringList warnings;
  if ( ! csvtMessage.isEmpty() ) warnings.append( csvtMessage );
  if ( nBadFormatRecords > 0 )
    warnings.append( tr( "%1 records discarded due to invalid format" ).arg( nBadFormatRecords ) );
  if ( nEmptyGeometry > 0 )
    warnings.append( tr( "%1 records have missing geometry definitions" ).arg( nEmptyGeometry ) );
  if ( nInvalidGeometry > 0 )
    warnings.append( tr( "%1 records discarded due to invalid geometry definitions" ).arg( nInvalidGeometry ) );
  if ( nIncompatibleGeometry > 0 )
    warnings.append( tr( "%1 records discarded due to incompatible geometry types" ).arg( nIncompatibleGeometry ) );

  reportErrors( warnings );

  // Decide whether to use subset ids to index records rather than simple iteration through all
  // If more than 10% of records are being skipped, then use index.  (Not based on any experimentation,
  // could do with some analysis?)

  if ( buildSubsetIndex )
  {
    long recordCount = mFile->recordCount();
    recordCount -= recordCount / SUBSET_ID_THRESHOLD_FACTOR;
    mUseSubsetIndex = mSubsetIndex.size() < recordCount;
    if ( ! mUseSubsetIndex ) mSubsetIndex = QList<quintptr>();
  }

  mUseSpatialIndex = buildSpatialIndex;

  mValid = mGeometryType != QGis::UnknownGeometry;
  mLayerValid = mValid;

  // If it is valid, then watch for changes to the file
  connect( mFile, SIGNAL( fileUpdated() ), this, SLOT( onFileUpdated() ) );


}
Esempio n. 18
0
/*! \internal
  Stringifies \a variant.
 */
void JsonWriter::stringify(const QVariant &variant, int depth)
{
    if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) {
        m_result += QLatin1Char('[');
        QVariantList list = variant.toList();
        for (int i = 0; i < list.count(); i++) {
            if (i != 0) {
                m_result += QLatin1Char(',');
                if (m_autoFormatting)
                    m_result += QLatin1Char(' ');
            }
            stringify(list[i], depth+1);
        }
        m_result += QLatin1Char(']');
    } else if (variant.type() == QVariant::Map) {
        QString indent = m_autoFormattingIndent.repeated(depth);
        QVariantMap map = variant.toMap();
        if (m_autoFormatting && depth != 0) {
            m_result += QLatin1Char('\n');
            m_result += indent;
            m_result += QLatin1String("{\n");
        } else {
            m_result += QLatin1Char('{');
        }
        for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) {
            if (it != map.constBegin()) {
                m_result += QLatin1Char(',');
                if (m_autoFormatting)
                    m_result += QLatin1Char('\n');
            }
            if (m_autoFormatting)
                m_result += indent + QLatin1Char(' ');
            m_result += QLatin1Char('\"') + escape(it.key()) + QLatin1String("\":");
            stringify(it.value(), depth+1);
        }
        if (m_autoFormatting) {
            m_result += QLatin1Char('\n');
            m_result += indent;
        }
        m_result += QLatin1Char('}');
    } else if (variant.type() == QVariant::String || variant.type() == QVariant::ByteArray) {
        m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"');
    } else if (variant.type() == QVariant::Double || (int)variant.type() == (int)QMetaType::Float) {
        double d = variant.toDouble();
        if (qIsFinite(d))
            m_result += QString::number(variant.toDouble(), 'g', 15);
        else
            m_result += QLatin1String("null");
    } else if (variant.type() == QVariant::Bool) {
        m_result += variant.toBool() ? QLatin1String("true") : QLatin1String("false");
    } else if (variant.type() == QVariant::Invalid) {
        m_result += QLatin1String("null");
    } else if (variant.type() == QVariant::ULongLong) {
        m_result += QString::number(variant.toULongLong());
    } else if (variant.type() == QVariant::LongLong) {
        m_result += QString::number(variant.toLongLong());
    } else if (variant.type() == QVariant::Int) {
        m_result += QString::number(variant.toInt());
    } else if (variant.type() == QVariant::UInt) {
        m_result += QString::number(variant.toUInt());
    } else if (variant.type() == QVariant::Char) {
        QChar c = variant.toChar();
        if (c.unicode() > 127)
            m_result += QLatin1String("\"\\u") + QString::number(c.unicode(), 16).rightJustified(4, QLatin1Char('0')) + QLatin1Char('\"');
        else
            m_result += QLatin1Char('\"') + c + QLatin1Char('\"');
    } else if (variant.canConvert<qlonglong>()) {
        m_result += QString::number(variant.toLongLong());
    } else if (variant.canConvert<QString>()) {
        m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"');
    } else {
        if (!m_errorString.isEmpty())
            m_errorString.append(QLatin1Char('\n'));
        QString msg = QString::fromLatin1("Unsupported type %1 (id: %2)").arg(QString::fromUtf8(variant.typeName())).arg(variant.userType());
        m_errorString.append(msg);
        qWarning() << "JsonWriter::stringify - " << msg;
        m_result += QLatin1String("null");
    }
}
Esempio n. 19
0
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle rect, TransformDirection direction, const bool handle180Crossover ) const
{
    // Calculate the bounding box of a QgsRectangle in the source CRS
    // when projected to the destination CRS (or the inverse).
    // This is done by looking at a number of points spread evenly
    // across the rectangle

    if ( mShortCircuit || !mInitialisedFlag )
        return rect;

    if ( rect.isEmpty() )
    {
        QgsPoint p = transform( rect.xMinimum(), rect.yMinimum(), direction );
        return QgsRectangle( p, p );
    }

    static const int numP = 8;

    QgsRectangle bb_rect;
    bb_rect.setMinimal();

    // We're interfacing with C-style vectors in the
    // end, so let's do C-style vectors here too.

    double x[numP * numP];
    double y[numP * numP];
    double z[numP * numP];

    QgsDebugMsg( "Entering transformBoundingBox..." );

    // Populate the vectors

    double dx = rect.width()  / ( double )( numP - 1 );
    double dy = rect.height() / ( double )( numP - 1 );

    double pointY = rect.yMinimum();

    for ( int i = 0; i < numP ; i++ )
    {

        // Start at right edge
        double pointX = rect.xMinimum();

        for ( int j = 0; j < numP; j++ )
        {
            x[( i*numP ) + j] = pointX;
            y[( i*numP ) + j] = pointY;
            // and the height...
            z[( i*numP ) + j] = 0.0;
            // QgsDebugMsg(QString("BBox coord: (%1, %2)").arg(x[(i*numP) + j]).arg(y[(i*numP) + j]));
            pointX += dx;
        }
        pointY += dy;
    }

    // Do transformation. Any exception generated must
    // be handled in above layers.
    try
    {
        transformCoords( numP * numP, x, y, z, direction );
    }
    catch ( const QgsCsException & )
    {
        // rethrow the exception
        QgsDebugMsg( "rethrowing exception" );
        throw;
    }

    // Calculate the bounding box and use that for the extent

    for ( int i = 0; i < numP * numP; i++ )
    {
        if ( !qIsFinite( x[i] ) || !qIsFinite( y[i] ) )
        {
            continue;
        }

        if ( handle180Crossover )
        {
            //if crossing the date line, temporarily add 360 degrees to -ve longitudes
            bb_rect.combineExtentWith( x[i] >= 0.0 ? x[i] : x[i] + 360.0, y[i] );
        }
        else
        {
            bb_rect.combineExtentWith( x[i], y[i] );
        }
    }

    if ( handle180Crossover )
    {
        //subtract temporary addition of 360 degrees from longitudes
        if ( bb_rect.xMinimum() > 180.0 )
            bb_rect.setXMinimum( bb_rect.xMinimum() - 360.0 );
        if ( bb_rect.xMaximum() > 180.0 )
            bb_rect.setXMaximum( bb_rect.xMaximum() - 360.0 );
    }

    QgsDebugMsg( "Projected extent: " + bb_rect.toString() );

    if ( bb_rect.isEmpty() )
    {
        QgsDebugMsg( "Original extent: " + rect.toString() );
    }

    return bb_rect;
}
Esempio n. 20
0
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle &rect, TransformDirection direction, const bool handle180Crossover ) const
{
  // Calculate the bounding box of a QgsRectangle in the source CRS
  // when projected to the destination CRS (or the inverse).
  // This is done by looking at a number of points spread evenly
  // across the rectangle

  if ( mShortCircuit || !mInitialisedFlag )
    return rect;

  if ( rect.isEmpty() )
  {
    QgsPoint p = transform( rect.xMinimum(), rect.yMinimum(), direction );
    return QgsRectangle( p, p );
  }

  // 64 points (<=2.12) is not enough, see #13665, for EPSG:4326 -> EPSG:3574 (say that it is a hard one),
  // are decent result from about 500 points and more. This method is called quite often, but
  // even with 1000 points it takes < 1ms
  // TODO: how to effectively and precisely reproject bounding box?
  const int nPoints = 1000;
  double d = sqrt(( rect.width() * rect.height() ) / pow( sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) );
  int nXPoints = static_cast< int >( ceil( rect.width() / d ) ) + 1;
  int nYPoints = static_cast< int >( ceil( rect.height() / d ) ) + 1;

  QgsRectangle bb_rect;
  bb_rect.setMinimal();

  // We're interfacing with C-style vectors in the
  // end, so let's do C-style vectors here too.

  QVector<double> x( nXPoints * nYPoints );
  QVector<double> y( nXPoints * nYPoints );
  QVector<double> z( nXPoints * nYPoints );

  QgsDebugMsg( "Entering transformBoundingBox..." );

  // Populate the vectors

  double dx = rect.width()  / static_cast< double >( nXPoints - 1 );
  double dy = rect.height() / static_cast< double >( nYPoints - 1 );

  double pointY = rect.yMinimum();

  for ( int i = 0; i < nYPoints ; i++ )
  {

    // Start at right edge
    double pointX = rect.xMinimum();

    for ( int j = 0; j < nXPoints; j++ )
    {
      x[( i*nXPoints ) + j] = pointX;
      y[( i*nXPoints ) + j] = pointY;
      // and the height...
      z[( i*nXPoints ) + j] = 0.0;
      // QgsDebugMsg(QString("BBox coord: (%1, %2)").arg(x[(i*numP) + j]).arg(y[(i*numP) + j]));
      pointX += dx;
    }
    pointY += dy;
  }

  // Do transformation. Any exception generated must
  // be handled in above layers.
  try
  {
    transformCoords( nXPoints * nYPoints, x.data(), y.data(), z.data(), direction );
  }
  catch ( const QgsCsException & )
  {
    // rethrow the exception
    QgsDebugMsg( "rethrowing exception" );
    throw;
  }

  // Calculate the bounding box and use that for the extent

  for ( int i = 0; i < nXPoints * nYPoints; i++ )
  {
    if ( !qIsFinite( x[i] ) || !qIsFinite( y[i] ) )
    {
      continue;
    }

    if ( handle180Crossover )
    {
      //if crossing the date line, temporarily add 360 degrees to -ve longitudes
      bb_rect.combineExtentWith( x[i] >= 0.0 ? x[i] : x[i] + 360.0, y[i] );
    }
    else
    {
      bb_rect.combineExtentWith( x[i], y[i] );
    }
  }

  if ( handle180Crossover )
  {
    //subtract temporary addition of 360 degrees from longitudes
    if ( bb_rect.xMinimum() > 180.0 )
      bb_rect.setXMinimum( bb_rect.xMinimum() - 360.0 );
    if ( bb_rect.xMaximum() > 180.0 )
      bb_rect.setXMaximum( bb_rect.xMaximum() - 360.0 );
  }

  QgsDebugMsg( "Projected extent: " + bb_rect.toString() );

  if ( bb_rect.isEmpty() )
  {
    QgsDebugMsg( "Original extent: " + rect.toString() );
  }

  return bb_rect;
}
/*!
    \internal
*/
void QGeoMapPolylineGeometry::updateScreenPoints(const QGeoMap &map,
                                                 qreal strokeWidth)
{
    if (!screenDirty_)
        return;

    QPointF origin = map.coordinateToScreenPosition(srcOrigin_, false).toPointF();

    if (!qIsFinite(origin.x()) || !qIsFinite(origin.y())) {
        clear();
        return;
    }

    // Create the viewport rect in the same coordinate system
    // as the actual points
    QRectF viewport(0, 0, map.width(), map.height());
    viewport.adjust(-strokeWidth, -strokeWidth, strokeWidth, strokeWidth);
    viewport.translate(-1 * origin);

    // Perform clipping to the viewport limits
    QVector<qreal> points;
    QVector<QPainterPath::ElementType> types;

    if (clipToViewport_) {
        clipPathToRect(srcPoints_, srcPointTypes_, viewport, points, types);
    } else {
        points = srcPoints_;
        types = srcPointTypes_;
    }

    QVectorPath vp(points.data(), types.size(), types.data());
    QTriangulatingStroker ts;
    ts.process(vp, QPen(QBrush(Qt::black), strokeWidth), viewport, QPainter::Qt4CompatiblePainting);

    clear();

    // Nothing is on the screen
    if (ts.vertexCount() == 0)
        return;

    // QTriangulatingStroker#vertexCount is actually the length of the array,
    // not the number of vertices
    screenVertices_.reserve(ts.vertexCount());

    screenOutline_ = QPainterPath();

    QPolygonF tri;
    const float *vs = ts.vertices();
    for (int i = 0; i < (ts.vertexCount()/2*2); i += 2) {
        screenVertices_ << QPointF(vs[i], vs[i + 1]);

        if (!qIsFinite(vs[i]) || !qIsFinite(vs[i + 1]))
            break;

        tri << QPointF(vs[i], vs[i + 1]);
        if (tri.size() == 4) {
            tri.remove(0);
            screenOutline_.addPolygon(tri);
        }
    }

    QRectF bb = screenOutline_.boundingRect();
    screenBounds_ = bb;
    this->translate( -1 * sourceBounds_.topLeft());
}
/*!
    \internal
*/
void QGeoMapPolylineGeometry::updateSourcePoints(const QGeoMap &map,
                                                 const QList<QGeoCoordinate> &path)
{
    bool foundValid = false;
    double minX = -1.0;
    double minY = -1.0;
    double maxX = -1.0;
    double maxY = -1.0;

    if (!sourceDirty_)
        return;

    // clear the old data and reserve enough memory
    srcPoints_.clear();
    srcPoints_.reserve(path.size() * 2);
    srcPointTypes_.clear();
    srcPointTypes_.reserve(path.size());

    QDoubleVector2D origin, lastPoint, lastAddedPoint;

    double unwrapBelowX = 0;
    if (preserveGeometry_)
        unwrapBelowX = map.coordinateToScreenPosition(geoLeftBound_, false).x();

    for (int i = 0; i < path.size(); ++i) {
        const QGeoCoordinate &coord = path.at(i);

        if (!coord.isValid())
            continue;

        QDoubleVector2D point = map.coordinateToScreenPosition(coord, false);

        // We can get NaN if the map isn't set up correctly, or the projection
        // is faulty -- probably best thing to do is abort
        if (!qIsFinite(point.x()) || !qIsFinite(point.y()))
            return;

        // unwrap x to preserve geometry if moved to border of map
        if (preserveGeometry_ && point.x() < unwrapBelowX && !qFuzzyCompare(point.x(), unwrapBelowX))
            point.setX(unwrapBelowX + geoDistanceToScreenWidth(map, geoLeftBound_, coord));

        if (!foundValid) {
            foundValid = true;
            srcOrigin_ = coord;
            origin = point;
            point = QDoubleVector2D(0,0);

            minX = point.x();
            maxX = minX;
            minY = point.y();
            maxY = minY;

            srcPoints_ << point.x() << point.y();
            srcPointTypes_ << QPainterPath::MoveToElement;
            lastAddedPoint = point;
        } else {
            point -= origin;

            minX = qMin(point.x(), minX);
            minY = qMin(point.y(), minY);
            maxX = qMax(point.x(), maxX);
            maxY = qMax(point.y(), maxY);

            if ((point - lastAddedPoint).manhattanLength() > 3 ||
                    i == path.size() - 1) {
                srcPoints_ << point.x() << point.y();
                srcPointTypes_ << QPainterPath::LineToElement;
                lastAddedPoint = point;
            }
        }

        lastPoint = point;
    }

    sourceBounds_ = QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
    geoLeftBound_ = map.screenPositionToCoordinate(
                                    QDoubleVector2D(minX + origin.x(), minY + origin.y()), false);
}
Esempio n. 23
0
QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    Q_D(QQuickImage);

    QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());

    // Copy over the current texture state into the texture provider...
    if (d->provider) {
        d->provider->m_smooth = d->smooth;
        d->provider->m_mipmap = d->mipmap;
        d->provider->updateTexture(texture);
    }

    if (!texture || width() <= 0 || height() <= 0) {
        delete oldNode;
        return 0;
    }

    QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
    if (!node) {
        d->pixmapChanged = true;
        node = d->sceneGraphContext()->createImageNode();
    }

    QRectF targetRect;
    QRectF sourceRect;
    QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
    QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;

    qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
    qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight :  d->pix.height() / d->devicePixelRatio;

    int xOffset = 0;
    if (d->hAlign == QQuickImage::AlignHCenter)
        xOffset = qCeil((width() - pixWidth) / 2.);
    else if (d->hAlign == QQuickImage::AlignRight)
        xOffset = qCeil(width() - pixWidth);

    int yOffset = 0;
    if (d->vAlign == QQuickImage::AlignVCenter)
        yOffset = qCeil((height() - pixHeight) / 2.);
    else if (d->vAlign == QQuickImage::AlignBottom)
        yOffset = qCeil(height() - pixHeight);

    switch (d->fillMode) {
    default:
    case Stretch:
        targetRect = QRectF(0, 0, width(), height());
        sourceRect = d->pix.rect();
        break;

    case PreserveAspectFit:
        targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
        sourceRect = d->pix.rect();
        break;

    case PreserveAspectCrop: {
        targetRect = QRect(0, 0, width(), height());
        qreal wscale = width() / qreal(d->pix.width());
        qreal hscale = height() / qreal(d->pix.height());

        if (wscale > hscale) {
            int src = (hscale / wscale) * qreal(d->pix.height());
            int y = 0;
            if (d->vAlign == QQuickImage::AlignVCenter)
                y = qCeil((d->pix.height() - src) / 2.);
            else if (d->vAlign == QQuickImage::AlignBottom)
                y = qCeil(d->pix.height() - src);
            sourceRect = QRectF(0, y, d->pix.width(), src);

        } else {
            int src = (wscale / hscale) * qreal(d->pix.width());
            int x = 0;
            if (d->hAlign == QQuickImage::AlignHCenter)
                x = qCeil((d->pix.width() - src) / 2.);
            else if (d->hAlign == QQuickImage::AlignRight)
                x = qCeil(d->pix.width() - src);
            sourceRect = QRectF(x, 0, src, d->pix.height());
        }
        }
        break;

    case Tile:
        targetRect = QRectF(0, 0, width(), height());
        sourceRect = QRectF(-xOffset, -yOffset, width(), height());
        hWrap = QSGTexture::Repeat;
        vWrap = QSGTexture::Repeat;
        break;

    case TileHorizontally:
        targetRect = QRectF(0, 0, width(), height());
        sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
        hWrap = QSGTexture::Repeat;
        break;

    case TileVertically:
        targetRect = QRectF(0, 0, width(), height());
        sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
        vWrap = QSGTexture::Repeat;
        break;

    case Pad:
        qreal w = qMin(qreal(d->pix.width()), width());
        qreal h = qMin(qreal(d->pix.height()), height());
        qreal x = (d->pix.width() > width()) ? -xOffset : 0;
        qreal y = (d->pix.height() > height()) ? -yOffset : 0;
        targetRect = QRectF(x + xOffset, y + yOffset, w, h);
        sourceRect = QRectF(x, y, w, h);
        break;
    };

    qreal nsWidth = (hWrap == QSGTexture::Repeat) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
    qreal nsHeight = (vWrap == QSGTexture::Repeat) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
    QRectF nsrect(sourceRect.x() / nsWidth,
                  sourceRect.y() / nsHeight,
                  sourceRect.width() / nsWidth,
                  sourceRect.height() / nsHeight);

    if (targetRect.isEmpty()
        || !qIsFinite(targetRect.width()) || !qIsFinite(targetRect.height())
        || nsrect.isEmpty()
        || !qIsFinite(nsrect.width()) || !qIsFinite(nsrect.height())) {
        delete node;
        return 0;
    }

    if (d->pixmapChanged) {
        // force update the texture in the node to trigger reconstruction of
        // geometry and the likes when a atlas segment has changed.
        if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat || d->mipmap))
            node->setTexture(texture->removedFromAtlas());
        else
            node->setTexture(texture);
        d->pixmapChanged = false;
    }

    node->setMipmapFiltering(d->mipmap ? QSGTexture::Linear : QSGTexture::None);
    node->setHorizontalWrapMode(hWrap);
    node->setVerticalWrapMode(vWrap);
    node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);

    node->setTargetRect(targetRect);
    node->setInnerTargetRect(targetRect);
    node->setSubSourceRect(nsrect);
    node->setMirror(d->mirror);
    node->setAntialiasing(d->antialiasing);
    node->update();

    return node;
}
Esempio n. 24
0
void old_tesselate_polygon(QVector<XTrapezoid> *traps, const QPointF *pg, int pgSize,
                           bool winding)
{
    QVector<QEdge> edges;
    edges.reserve(128);
    qreal ymin(INT_MAX/256);
    qreal ymax(INT_MIN/256);

    //painter.begin(pg, pgSize);
    if (pg[0] != pg[pgSize-1])
        qWarning() << Q_FUNC_INFO << "Malformed polygon (first and last points must be identical)";
    // generate edge table
//     qDebug() << "POINTS:";
    for (int x = 0; x < pgSize-1; ++x) {
	QEdge edge;
        QPointF p1(Q27Dot5ToDouble(FloatToQ27Dot5(pg[x].x())),
                   Q27Dot5ToDouble(FloatToQ27Dot5(pg[x].y())));
        QPointF p2(Q27Dot5ToDouble(FloatToQ27Dot5(pg[x+1].x())),
                   Q27Dot5ToDouble(FloatToQ27Dot5(pg[x+1].y())));

//         qDebug() << "    "
//                  << p1;
	edge.winding = p1.y() > p2.y() ? 1 : -1;
	if (edge.winding > 0)
            qSwap(p1, p2);
        edge.p1.x = XDoubleToFixed(p1.x());
        edge.p1.y = XDoubleToFixed(p1.y());
        edge.p2.x = XDoubleToFixed(p2.x());
        edge.p2.y = XDoubleToFixed(p2.y());

	edge.m = (p1.y() - p2.y()) / (p1.x() - p2.x()); // line derivative
	edge.b = p1.y() - edge.m * p1.x(); // intersection with y axis
	edge.m = edge.m != 0.0 ? 1.0 / edge.m : 0.0; // inverted derivative
	edges.append(edge);
        ymin = qMin(ymin, qreal(XFixedToDouble(edge.p1.y)));
        ymax = qMax(ymax, qreal(XFixedToDouble(edge.p2.y)));
    }

    QList<const QEdge *> et; 	    // edge list
    for (int i = 0; i < edges.size(); ++i)
        et.append(&edges.at(i));

    // sort edge table by min y value
    qSort(et.begin(), et.end(), compareEdges);

    // eliminate shared edges
    for (int i = 0; i < et.size(); ++i) {
	for (int k = i+1; k < et.size(); ++k) {
            const QEdge *edgeI = et.at(i);
            const QEdge *edgeK = et.at(k);
            if (edgeK->p1.y > edgeI->p1.y)
                break;
   	    if (edgeI->winding != edgeK->winding &&
                isEqual(edgeI->p1, edgeK->p1) && isEqual(edgeI->p2, edgeK->p2)
		) {
 		et.removeAt(k);
		et.removeAt(i);
		--i;
		break;
	    }
	}
    }

    if (ymax <= ymin)
	return;
    QList<const QEdge *> aet; 	    // edges that intersects the current scanline

//     if (ymin < 0)
// 	ymin = 0;
//     if (paintEventClipRegion) // don't scan more lines than we have to
// 	ymax = paintEventClipRegion->boundingRect().height();

#ifdef QT_DEBUG_TESSELATOR
    qDebug("==> ymin = %f, ymax = %f", ymin, ymax);
#endif // QT_DEBUG_TESSELATOR

    currentY = ymin; // used by the less than op
    for (qreal y = ymin; y < ymax;) {
	// fill active edge table with edges that intersect the current line
	for (int i = 0; i < et.size(); ++i) {
            const QEdge *edge = et.at(i);
            if (edge->p1.y > XDoubleToFixed(y))
                break;
            aet.append(edge);
            et.removeAt(i);
            --i;
	}

	// remove processed edges from active edge table
	for (int i = 0; i < aet.size(); ++i) {
	    if (aet.at(i)->p2.y <= XDoubleToFixed(y)) {
		aet.removeAt(i);
 		--i;
	    }
	}
        if (aet.size()%2 != 0) {
#ifndef QT_NO_DEBUG
            qWarning("QX11PaintEngine: aet out of sync - this should not happen.");
#endif
            return;
        }

	// done?
	if (!aet.size()) {
            if (!et.size()) {
                break;
	    } else {
 		y = currentY = XFixedToDouble(et.at(0)->p1.y);
                continue;
	    }
        }

        // calculate the next y where we have to start a new set of trapezoids
	qreal next_y(INT_MAX/256);
 	for (int i = 0; i < aet.size(); ++i) {
            const QEdge *edge = aet.at(i);
 	    if (XFixedToDouble(edge->p2.y) < next_y)
 		next_y = XFixedToDouble(edge->p2.y);
        }

	if (et.size() && next_y > XFixedToDouble(et.at(0)->p1.y))
	    next_y = XFixedToDouble(et.at(0)->p1.y);

        int aetSize = aet.size();
	for (int i = 0; i < aetSize; ++i) {
	    for (int k = i+1; k < aetSize; ++k) {
                const QEdge *edgeI = aet.at(i);
                const QEdge *edgeK = aet.at(k);
		qreal m1 = edgeI->m;
		qreal b1 = edgeI->b;
		qreal m2 = edgeK->m;
		qreal b2 = edgeK->b;

		if (qAbs(m1 - m2) < 0.001)
                    continue;

                // ### intersect is not calculated correctly when optimized with -O2 (gcc)
                volatile qreal intersect = 0;
                if (!qIsFinite(b1))
                    intersect = (1.f / m2) * XFixedToDouble(edgeI->p1.x) + b2;
                else if (!qIsFinite(b2))
                    intersect = (1.f / m1) * XFixedToDouble(edgeK->p1.x) + b1;
                else
                    intersect = (b1*m1 - b2*m2) / (m1 - m2);

 		if (intersect > y && intersect < next_y)
		    next_y = intersect;
	    }
	}

        XFixed yf, next_yf;
        yf = qrealToXFixed(y);
        next_yf = qrealToXFixed(next_y);

        if (yf == next_yf) {
            y = currentY = next_y;
            continue;
        }

#ifdef QT_DEBUG_TESSELATOR
        qDebug("###> y = %f, next_y = %f, %d active edges", y, next_y, aet.size());
        qDebug("===> edges");
        dump_edges(et);
        qDebug("===> active edges");
        dump_edges(aet);
#endif
	// calc intersection points
 	QVarLengthArray<QIntersectionPoint> isects(aet.size()+1);
 	for (int i = 0; i < isects.size()-1; ++i) {
            const QEdge *edge = aet.at(i);
 	    isects[i].x = (edge->p1.x != edge->p2.x) ?
			  ((y - edge->b)*edge->m) : XFixedToDouble(edge->p1.x);
	    isects[i].edge = edge;
	}

	if (isects.size()%2 != 1)
	    qFatal("%s: number of intersection points must be odd", Q_FUNC_INFO);

	// sort intersection points
 	qSort(&isects[0], &isects[isects.size()-1], compareIntersections);
//         qDebug() << "INTERSECTION_POINTS:";
//  	for (int i = 0; i < isects.size(); ++i)
//             qDebug() << isects[i].edge << isects[i].x;

        if (winding) {
            // winding fill rule
            for (int i = 0; i < isects.size()-1;) {
                int winding = 0;
                const QEdge *left = isects[i].edge;
                const QEdge *right = 0;
                winding += isects[i].edge->winding;
                for (++i; i < isects.size()-1 && winding != 0; ++i) {
                    winding += isects[i].edge->winding;
                    right = isects[i].edge;
                }
                if (!left || !right)
                    break;
                //painter.addTrapezoid(&toXTrapezoid(yf, next_yf, *left, *right));
                traps->append(toXTrapezoid(yf, next_yf, *left, *right));
            }
        } else {
            // odd-even fill rule
            for (int i = 0; i < isects.size()-2; i += 2) {
                //painter.addTrapezoid(&toXTrapezoid(yf, next_yf, *isects[i].edge, *isects[i+1].edge));
                traps->append(toXTrapezoid(yf, next_yf, *isects[i].edge, *isects[i+1].edge));
            }
        }
	y = currentY = next_y;
    }

#ifdef QT_DEBUG_TESSELATOR
    qDebug("==> number of trapezoids: %d - edge table size: %d\n", traps->size(), et.size());

    for (int i = 0; i < traps->size(); ++i)
        dump_trap(traps->at(i));
#endif

    // optimize by unifying trapezoids that share left/right lines
    // and have a common top/bottom edge
//     for (int i = 0; i < tps.size(); ++i) {
// 	for (int k = i+1; k < tps.size(); ++k) {
// 	    if (i != k && tps.at(i).right == tps.at(k).right
// 		&& tps.at(i).left == tps.at(k).left
// 		&& (tps.at(i).top == tps.at(k).bottom
// 		    || tps.at(i).bottom == tps.at(k).top))
// 	    {
// 		tps[i].bottom = tps.at(k).bottom;
// 		tps.removeAt(k);
//                 i = 0;
// 		break;
// 	    }
// 	}
//     }
    //static int i = 0;
    //QImage img = painter.end();
    //img.save(QString("res%1.png").arg(i++), "PNG");
}
double UnaryFunc::operator()(double x)
{
    double res = _f(x);
    _validity_flag = qIsFinite(res);
    return res;
}
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle rect, TransformDirection direction ) const
{
  // Calculate the bounding box of a QgsRectangle in the source CRS
  // when projected to the destination CRS (or the inverse).
  // This is done by looking at a number of points spread evenly
  // across the rectangle

  if ( mShortCircuit || !mInitialisedFlag || rect.isEmpty() )
    return rect;

  static const int numP = 8;

  QgsRectangle bb_rect;
  bb_rect.setMinimal();

  // We're interfacing with C-style vectors in the
  // end, so let's do C-style vectors here too.

  double x[numP * numP];
  double y[numP * numP];
  double z[numP * numP];

  QgsDebugMsg( "Entering transformBoundingBox..." );

  // Populate the vectors

  double dx = rect.width()  / ( double )( numP - 1 );
  double dy = rect.height() / ( double )( numP - 1 );

  double pointY = rect.yMinimum();

  for ( int i = 0; i < numP ; i++ )
  {

    // Start at right edge
    double pointX = rect.xMinimum();

    for ( int j = 0; j < numP; j++ )
    {
      x[( i*numP ) + j] = pointX;
      y[( i*numP ) + j] = pointY;
      // and the height...
      z[( i*numP ) + j] = 0.0;
      // QgsDebugMsg(QString("BBox coord: (%1, %2)").arg(x[(i*numP) + j]).arg(y[(i*numP) + j]));
      pointX += dx;
    }
    pointY += dy;
  }

  // Do transformation. Any exception generated must
  // be handled in above layers.
  try
  {
    transformCoords( numP * numP, x, y, z, direction );
  }
  catch ( QgsCsException &cse )
  {
    // rethrow the exception
    QgsDebugMsg( "rethrowing exception" );
    throw cse;
  }

  // Calculate the bounding box and use that for the extent

  for ( int i = 0; i < numP * numP; i++ )
  {
    if ( qIsFinite( x[i] ) && qIsFinite( y[i] ) )
      bb_rect.combineExtentWith( x[i], y[i] );
  }

  QgsDebugMsg( "Projected extent: " + QString(( bb_rect.toString() ).toLocal8Bit().data() ) );

  return bb_rect;
}