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; }
/*! 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); }
/*! 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; }
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; }
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; }
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))); }
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() ) ); }
/*! \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"); } }
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; }
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); }
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; }
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; }