void QgsWFSProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const { const QList<QDomElement>& projectLayerElements = mProjectParser.projectLayerElements(); if ( projectLayerElements.size() < 1 ) { return; } QStringList wfsLayersId = mProjectParser.wfsLayers(); QStringList wfstUpdateLayersId = wfstUpdateLayers(); QStringList wfstInsertLayersId = wfstInsertLayers(); QStringList wfstDeleteLayersId = wfstDeleteLayers(); QMap<QString, QgsMapLayer *> layerMap; foreach ( const QDomElement &elem, projectLayerElements ) { QString type = elem.attribute( "type" ); if ( type == "vector" ) { QgsMapLayer *layer = mProjectParser.createLayerFromElement( elem ); if ( layer && wfsLayersId.contains( layer->id() ) ) { QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) ); layerMap.insert( layer->id(), layer ); QDomElement layerElem = doc.createElement( "FeatureType" ); QDomElement nameElem = doc.createElement( "Name" ); //We use the layer name even though it might not be unique. //Because the id sometimes contains user/pw information and the name is more descriptive QString typeName = layer->name(); typeName = typeName.replace( " ", "_" ); QDomText nameText = doc.createTextNode( typeName ); nameElem.appendChild( nameText ); layerElem.appendChild( nameElem ); QDomElement titleElem = doc.createElement( "Title" ); QString titleName = layer->title(); if ( titleName.isEmpty() ) { titleName = layer->name(); } QDomText titleText = doc.createTextNode( titleName ); titleElem.appendChild( titleText ); layerElem.appendChild( titleElem ); QDomElement abstractElem = doc.createElement( "Abstract" ); QString abstractName = layer->abstract(); if ( abstractName.isEmpty() ) { abstractName = ""; } QDomText abstractText = doc.createTextNode( abstractName ); abstractElem.appendChild( abstractText ); layerElem.appendChild( abstractElem ); //keyword list if ( !layer->keywordList().isEmpty() ) { QDomElement keywordsElem = doc.createElement( "Keywords" ); QDomText keywordsText = doc.createTextNode( layer->keywordList() ); keywordsElem.appendChild( keywordsText ); layerElem.appendChild( keywordsElem ); } //appendExGeographicBoundingBox( layerElem, doc, layer->extent(), layer->crs() ); QDomElement srsElem = doc.createElement( "SRS" ); QDomText srsText = doc.createTextNode( layer->crs().authid() ); srsElem.appendChild( srsText ); layerElem.appendChild( srsElem ); //wfs:Operations element QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ ); //wfs:Query element QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ ); operationsElement.appendChild( queryElement ); QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( layer ); QgsVectorDataProvider* provider = vlayer->dataProvider(); if (( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) ) { //wfs:Insert element QDomElement insertElement = doc.createElement( "Insert"/*wfs:Insert*/ ); operationsElement.appendChild( insertElement ); } if (( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) && ( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) && wfstUpdateLayersId.contains( layer->id() ) ) { //wfs:Update element QDomElement updateElement = doc.createElement( "Update"/*wfs:Update*/ ); operationsElement.appendChild( updateElement ); } if (( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) ) { //wfs:Delete element QDomElement deleteElement = doc.createElement( "Delete"/*wfs:Delete*/ ); operationsElement.appendChild( deleteElement ); } layerElem.appendChild( operationsElement ); QgsRectangle layerExtent = layer->extent(); QDomElement bBoxElement = doc.createElement( "LatLongBoundingBox" ); bBoxElement.setAttribute( "minx", QString::number( layerExtent.xMinimum() ) ); bBoxElement.setAttribute( "miny", QString::number( layerExtent.yMinimum() ) ); bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) ); bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) ); layerElem.appendChild( bBoxElement ); // layer metadata URL QString metadataUrl = layer->metadataUrl(); if ( !metadataUrl.isEmpty() ) { QDomElement metaUrlElem = doc.createElement( "MetadataURL" ); QString metadataUrlType = layer->metadataUrlType(); metaUrlElem.setAttribute( "type", metadataUrlType ); QString metadataUrlFormat = layer->metadataUrlFormat(); if ( metadataUrlFormat == "text/xml" ) { metaUrlElem.setAttribute( "format", "XML" ); } else { metaUrlElem.setAttribute( "format", "TXT" ); } QDomText metaUrlText = doc.createTextNode( metadataUrl ); metaUrlElem.appendChild( metaUrlText ); layerElem.appendChild( metaUrlElem ); } parentElement.appendChild( layerElem ); } } }
void QgsAlignRaster::setClipExtent( const QgsRectangle& extent ) { setClipExtent( extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ); }
void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool useIntersect ) { //apply selection rectangle resetSelection( 0 ); BOUND_BOX box; box.N = rect.yMaximum(); box.S = rect.yMinimum(); box.E = rect.xMaximum(); box.W = rect.xMinimum(); box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; if ( !useIntersect ) { // select by bounding boxes only if ( mSource->mLayerType == QgsGrassProvider::POINT || mSource->mLayerType == QgsGrassProvider::CENTROID || mSource->mLayerType == QgsGrassProvider::LINE || mSource->mLayerType == QgsGrassProvider::FACE || mSource->mLayerType == QgsGrassProvider::BOUNDARY || mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { Vect_select_lines_by_box( mSource->mMap, &box, mSource->mGrassType, mList ); } else if ( mSource->mLayerType == QgsGrassProvider::POLYGON ) { Vect_select_areas_by_box( mSource->mMap, &box, mList ); } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { Vect_select_nodes_by_box( mSource->mMap, &box, mList ); } } else { // check intersection struct line_pnts *Polygon; Polygon = Vect_new_line_struct(); // Using z coor -PORT_DOUBLE_MAX/PORT_DOUBLE_MAX we cover 3D, Vect_select_lines_by_polygon is // using dig_line_box to get the box, it is not perfect, Vect_select_lines_by_polygon // should clarify better how 2D/3D is treated Vect_append_point( Polygon, rect.xMinimum(), rect.yMinimum(), -PORT_DOUBLE_MAX ); Vect_append_point( Polygon, rect.xMaximum(), rect.yMinimum(), PORT_DOUBLE_MAX ); Vect_append_point( Polygon, rect.xMaximum(), rect.yMaximum(), 0 ); Vect_append_point( Polygon, rect.xMinimum(), rect.yMaximum(), 0 ); Vect_append_point( Polygon, rect.xMinimum(), rect.yMinimum(), 0 ); if ( mSource->mLayerType == QgsGrassProvider::POINT || mSource->mLayerType == QgsGrassProvider::CENTROID || mSource->mLayerType == QgsGrassProvider::LINE || mSource->mLayerType == QgsGrassProvider::FACE || mSource->mLayerType == QgsGrassProvider::BOUNDARY || mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { Vect_select_lines_by_polygon( mSource->mMap, Polygon, 0, NULL, mSource->mGrassType, mList ); } else if ( mSource->mLayerType == QgsGrassProvider::POLYGON ) { Vect_select_areas_by_polygon( mSource->mMap, Polygon, 0, NULL, mList ); } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { // There is no Vect_select_nodes_by_polygon but for nodes it is the same as by box Vect_select_nodes_by_box( mSource->mMap, &box, mList ); } Vect_destroy_line_struct( Polygon ); } for ( int i = 0; i < mList->n_values; i++ ) { if ( mList->value[i] <= mSelectionSize ) { mSelection[mList->value[i]] = 1; } else { QgsDebugMsg( "Selected element out of range" ); } } }
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureIterator features; const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection { features = L->selectedFeaturesIterator(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( L->crs().geographicFlag() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } QgsFeature feat; while ( features.nextFeature( feat ) ) { if ( !feat.constGeometry() ) { continue; } QList<QgsGeometry*> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry* newGeometry = 0; splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( feat.id(), feat.geometry() ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { newGeometry = newGeometries.at( i ); QgsFeature newFeature; newFeature.setGeometry( newGeometry ); //use default value where possible for primary key (e.g. autoincrement), //and use the value from the original (split) feature if not primary key QgsAttributes newAttributes = feat.attributes(); Q_FOREACH ( int pkIdx, L->dataProvider()->pkAttributeIndexes() ) { const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx ); if ( !defaultValue.isNull() ) { newAttributes[ pkIdx ] = defaultValue; } else //try with NULL { newAttributes[ pkIdx ] = QVariant(); } } newFeature.setAttributes( newAttributes ); newFeatures.append( newFeature ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback ) { QgsDebugMsgLevel( QString( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 ); QgsDebugMsgLevel( QString( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 ); QgsRasterBlock *block = new QgsRasterBlock( dataType( bandNo ), width, height ); if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) ) { block->setNoDataValue( sourceNoDataValue( bandNo ) ); } if ( block->isEmpty() ) { QgsDebugMsg( "Couldn't create raster block" ); return block; } // Read necessary extent only QgsRectangle tmpExtent = extent().intersect( &boundingBox ); if ( tmpExtent.isEmpty() ) { QgsDebugMsg( "Extent outside provider extent" ); block->setIsNoData(); return block; } double xRes = boundingBox.width() / width; double yRes = boundingBox.height() / height; double tmpXRes, tmpYRes; double providerXRes = 0; double providerYRes = 0; if ( capabilities() & Size ) { providerXRes = extent().width() / xSize(); providerYRes = extent().height() / ySize(); tmpXRes = std::max( providerXRes, xRes ); tmpYRes = std::max( providerYRes, yRes ); if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes; if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes; } else { tmpXRes = xRes; tmpYRes = yRes; } if ( tmpExtent != boundingBox || tmpXRes > xRes || tmpYRes > yRes ) { // Read smaller extent or lower resolution if ( !extent().contains( boundingBox ) ) { QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() ); block->setIsNoDataExcept( subRect ); } // Calculate row/col limits (before tmpExtent is aligned) int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes ); int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1; int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes ); int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1; QgsDebugMsgLevel( QString( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 ); if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height || fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width ) { // Should not happen QgsDebugMsg( "Row or column limits out of range" ); return block; } // If lower source resolution is used, the extent must beS aligned to original // resolution to avoid possible shift due to resampling if ( tmpXRes > xRes ) { int col = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes ); col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes ); } if ( tmpYRes > yRes ) { int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes ); tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes ); row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes ); tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes ); } int tmpWidth = std::round( tmpExtent.width() / tmpXRes ); int tmpHeight = std::round( tmpExtent.height() / tmpYRes ); tmpXRes = tmpExtent.width() / tmpWidth; tmpYRes = tmpExtent.height() / tmpHeight; QgsDebugMsgLevel( QString( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 ); QgsDebugMsgLevel( QString( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 ); QgsRasterBlock *tmpBlock = new QgsRasterBlock( dataType( bandNo ), tmpWidth, tmpHeight ); if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) ) { tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) ); } readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ); int pixelSize = dataTypeSize( bandNo ); double xMin = boundingBox.xMinimum(); double yMax = boundingBox.yMaximum(); double tmpXMin = tmpExtent.xMinimum(); double tmpYMax = tmpExtent.yMaximum(); for ( int row = fromRow; row <= toRow; row++ ) { double y = yMax - ( row + 0.5 ) * yRes; int tmpRow = std::floor( ( tmpYMax - y ) / tmpYRes ); for ( int col = fromCol; col <= toCol; col++ ) { double x = xMin + ( col + 0.5 ) * xRes; int tmpCol = std::floor( ( x - tmpXMin ) / tmpXRes ); if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth ) { QgsDebugMsg( "Source row or column limits out of range" ); block->setIsNoData(); // so that the problem becomes obvious and fixed delete tmpBlock; return block; } qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol; qgssize index = row * static_cast< qgssize >( width ) + col; char *tmpBits = tmpBlock->bits( tmpIndex ); char *bits = block->bits( index ); if ( !tmpBits ) { QgsDebugMsg( QString( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) ); continue; } if ( !bits ) { QgsDebugMsg( "Cannot set output block data." ); continue; } memcpy( bits, tmpBits, pixelSize ); } } delete tmpBlock; } else { readBlock( bandNo, boundingBox, width, height, block->bits(), feedback ); } // apply scale and offset block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) ); // apply user no data values block->applyNoDataValues( userNoDataValues( bandNo ) ); return block; }
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 ( !d->mIsValid || d->mShortCircuit ) return rect; if ( rect.isEmpty() ) { QgsPointXY 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 = std::sqrt( ( rect.width() * rect.height() ) / std::pow( std::sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) ); int nXPoints = static_cast< int >( std::ceil( rect.width() / d ) ) + 1; int nYPoints = static_cast< int >( std::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 ); QgsDebugMsgLevel( "Entering transformBoundingBox...", 4 ); // 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 ( !std::isfinite( x[i] ) || !std::isfinite( 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 ( bb_rect.isNull() ) { // something bad happened when reprojecting the filter rect... no finite points were left! throw QgsCsException( QObject::tr( "Could not transform bounding box to target CRS" ) ); } 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 ); } QgsDebugMsgLevel( "Projected extent: " + bb_rect.toString(), 4 ); if ( bb_rect.isEmpty() ) { QgsDebugMsgLevel( "Original extent: " + rect.toString(), 4 ); } return bb_rect; }
void QgsComposerMapWidget::updateGuiElements() { if ( mComposerMap ) { blockAllSignals( true ); //width, height, scale QRectF composerMapRect = mComposerMap->rect(); mWidthLineEdit->setText( QString::number( composerMapRect.width() ) ); mHeightLineEdit->setText( QString::number( composerMapRect.height() ) ); mScaleLineEdit->setText( QString::number( mComposerMap->scale(), 'f', 0 ) ); //preview mode QgsComposerMap::PreviewMode previewMode = mComposerMap->previewMode(); int index = -1; if ( previewMode == QgsComposerMap::Cache ) { index = mPreviewModeComboBox->findText( tr( "Cache" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Render ) { index = mPreviewModeComboBox->findText( tr( "Render" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Rectangle ) { index = mPreviewModeComboBox->findText( tr( "Rectangle" ) ); mUpdatePreviewButton->setEnabled( false ); } if ( index != -1 ) { mPreviewModeComboBox->setCurrentIndex( index ); } //composer map extent QgsRectangle composerMapExtent = mComposerMap->extent(); mXMinLineEdit->setText( QString::number( composerMapExtent.xMinimum(), 'f', 3 ) ); mXMaxLineEdit->setText( QString::number( composerMapExtent.xMaximum(), 'f', 3 ) ); mYMinLineEdit->setText( QString::number( composerMapExtent.yMinimum(), 'f', 3 ) ); mYMaxLineEdit->setText( QString::number( composerMapExtent.yMaximum(), 'f', 3 ) ); mRotationSpinBox->setValue( mComposerMap->rotation() ); //keep layer list check box if ( mComposerMap->keepLayerSet() ) { mKeepLayerListCheckBox->setCheckState( Qt::Checked ); } else { mKeepLayerListCheckBox->setCheckState( Qt::Unchecked ); } //draw canvas items if ( mComposerMap->drawCanvasItems() ) { mDrawCanvasItemsCheckBox->setCheckState( Qt::Checked ); } else { mDrawCanvasItemsCheckBox->setCheckState( Qt::Unchecked ); } //grid if ( mComposerMap->gridEnabled() ) { mGridCheckBox->setChecked( true ); } else { mGridCheckBox->setChecked( false ); } mIntervalXSpinBox->setValue( mComposerMap->gridIntervalX() ); mIntervalYSpinBox->setValue( mComposerMap->gridIntervalY() ); mOffsetXSpinBox->setValue( mComposerMap->gridOffsetX() ); mOffsetYSpinBox->setValue( mComposerMap->gridOffsetY() ); QgsComposerMap::GridStyle gridStyle = mComposerMap->gridStyle(); if ( gridStyle == QgsComposerMap::Cross ) { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Cross" ) ) ); } else { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Solid" ) ) ); } mCrossWidthSpinBox->setValue( mComposerMap->crossLength() ); QgsComposerMap::GridAnnotationPosition annotationPos = mComposerMap->gridAnnotationPosition(); if ( annotationPos == QgsComposerMap::InsideMapFrame ) { mAnnotationPositionComboBox->setCurrentIndex( mAnnotationPositionComboBox->findText( tr( "Inside frame" ) ) ); } else { mAnnotationPositionComboBox->setCurrentIndex( mAnnotationPositionComboBox->findText( tr( "Outside frame" ) ) ); } mDistanceToMapFrameSpinBox->setValue( mComposerMap->annotationFrameDistance() ); if ( mComposerMap->showGridAnnotation() ) { mDrawAnnotationCheckBox->setCheckState( Qt::Checked ); } else { mDrawAnnotationCheckBox->setCheckState( Qt::Unchecked ); } QgsComposerMap::GridAnnotationDirection dir = mComposerMap->gridAnnotationDirection(); if ( dir == QgsComposerMap::Horizontal ) { mAnnotationDirectionComboBox->setCurrentIndex( mAnnotationDirectionComboBox->findText( tr( "Horizontal" ) ) ); } else if ( dir == QgsComposerMap::Vertical ) { mAnnotationDirectionComboBox->setCurrentIndex( mAnnotationDirectionComboBox->findText( tr( "Vertical" ) ) ); } else if ( dir == QgsComposerMap::HorizontalAndVertical ) { mAnnotationDirectionComboBox->setCurrentIndex( mAnnotationDirectionComboBox->findText( tr( "Horizontal and Vertical" ) ) ); } else //BoundaryDirection { mAnnotationDirectionComboBox->setCurrentIndex( mAnnotationDirectionComboBox->findText( tr( "Boundary direction" ) ) ); } mCoordinatePrecisionSpinBox->setValue( mComposerMap->gridAnnotationPrecision() ); QPen gridPen = mComposerMap->gridPen(); mLineWidthSpinBox->setValue( gridPen.widthF() ); mLineColorButton->setColor( gridPen.color() ); blockAllSignals( false ); } }
bool QgsVectorLayerRenderer::render() { if ( mGeometryType == QgsWkbTypes::NullGeometry || mGeometryType == QgsWkbTypes::UnknownGeometry ) return true; if ( !mRenderer ) { mErrors.append( QObject::tr( "No renderer for drawing." ) ); return false; } bool usingEffect = false; if ( mRenderer->paintEffect() && mRenderer->paintEffect()->enabled() ) { usingEffect = true; mRenderer->paintEffect()->begin( mContext ); } // Per feature blending mode if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) { // set the painter to the feature blend mode, so that features drawn // on this layer will interact and blend with each other mContext.painter()->setCompositionMode( mFeatureBlendMode ); } mRenderer->startRender( mContext, mFields ); QString rendererFilter = mRenderer->filter( mFields ); QgsRectangle requestExtent = mContext.extent(); mRenderer->modifyRequestExtent( requestExtent, mContext ); QgsFeatureRequest featureRequest = QgsFeatureRequest() .setFilterRect( requestExtent ) .setSubsetOfAttributes( mAttrNames, mFields ) .setExpressionContext( mContext.expressionContext() ); if ( mRenderer->orderByEnabled() ) { featureRequest.setOrderBy( mRenderer->orderBy() ); } const QgsFeatureFilterProvider* featureFilterProvider = mContext.featureFilterProvider(); if ( featureFilterProvider ) { featureFilterProvider->filterFeatures( mLayer, featureRequest ); } if ( !rendererFilter.isEmpty() && rendererFilter != "TRUE" ) { featureRequest.combineFilterExpression( rendererFilter ); } // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine. if ( mSimplifyGeometry ) { double map2pixelTol = mSimplifyMethod.threshold(); bool validTransform = true; const QgsMapToPixel& mtp = mContext.mapToPixel(); map2pixelTol *= mtp.mapUnitsPerPixel(); QgsCoordinateTransform ct = mContext.coordinateTransform(); // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem if ( ct.isValid() && !ct.isShortCircuited() ) { try { QgsPoint center = mContext.extent().center(); double rectSize = ct.sourceCrs().isGeographic() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100; QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize ); QgsRectangle targetRect = ct.transform( sourceRect ); QgsDebugMsgLevel( QString( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ), 4 ); QgsDebugMsgLevel( QString( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ), 4 ); if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() ) { QgsPoint minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() ); QgsPoint maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() ); QgsPoint minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() ); QgsPoint maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() ); double sourceHypothenuse = sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) ); double targetHypothenuse = sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) ); QgsDebugMsgLevel( QString( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ), 4 ); QgsDebugMsgLevel( QString( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ), 4 ); if ( !qgsDoubleNear( targetHypothenuse, 0.0 ) ) map2pixelTol *= ( sourceHypothenuse / targetHypothenuse ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); validTransform = false; } } if ( validTransform ) { QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); simplifyMethod.setThreshold( mSimplifyMethod.threshold() ); simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod; vectorMethod.setTolerance( map2pixelTol ); mContext.setVectorSimplifyMethod( vectorMethod ); } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } QgsFeatureIterator fit = mSource->getFeatures( featureRequest ); // Attach an interruption checker so that iterators that have potentially // slow fetchFeature() implementations, such as in the WFS provider, can // check it, instead of relying on just the mContext.renderingStopped() check // in drawRenderer() fit.setInterruptionChecker( &mInterruptionChecker ); if (( mRenderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && mRenderer->usingSymbolLevels() ) drawRendererLevels( fit ); else drawRenderer( fit ); if ( usingEffect ) { mRenderer->paintEffect()->end( mContext ); } return true; }
// Slot called when the menu item is triggered // If you created more menu items / toolbar buttons in initiGui, you should // create a separate handler for each action - this single run() method will // not be enough void Heatmap::run() { HeatmapGui d( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags, &mSessionSettings ); if ( d.exec() == QDialog::Accepted ) { // everything runs here // Get the required data from the dialog QgsRectangle myBBox = d.bbox(); int columns = d.columns(); int rows = d.rows(); double cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value mDecay = d.decayRatio(); int kernelShape = d.kernelShape(); // Start working on the input vector QgsVectorLayer* inputLayer = d.inputVectorLayer(); // Getting the rasterdataset in place GDALAllRegister(); GDALDataset *emptyDataset; GDALDriver *myDriver; myDriver = GetGDALDriverManager()->GetDriverByName( d.outputFormat().toUtf8() ); if ( myDriver == NULL ) { QMessageBox::information( 0, tr( "GDAL driver error" ), tr( "Cannot open the driver for the specified format" ) ); return; } double geoTransform[6] = { myBBox.xMinimum(), cellsize, 0, myBBox.yMinimum(), 0, cellsize }; emptyDataset = myDriver->Create( d.outputFilename().toUtf8(), columns, rows, 1, GDT_Float32, NULL ); emptyDataset->SetGeoTransform( geoTransform ); // Set the projection on the raster destination to match the input layer emptyDataset->SetProjection( inputLayer->crs().toWkt().toLocal8Bit().data() ); GDALRasterBand *poBand; poBand = emptyDataset->GetRasterBand( 1 ); poBand->SetNoDataValue( NO_DATA ); float* line = ( float * ) CPLMalloc( sizeof( float ) * columns ); for ( int i = 0; i < columns ; i++ ) { line[i] = NO_DATA; } // Write the empty raster for ( int i = 0; i < rows ; i++ ) { poBand->RasterIO( GF_Write, 0, i, columns, 1, line, columns, 1, GDT_Float32, 0, 0 ); } CPLFree( line ); //close the dataset GDALClose(( GDALDatasetH ) emptyDataset ); // open the raster in GA_Update mode GDALDataset *heatmapDS; heatmapDS = ( GDALDataset * ) GDALOpen( d.outputFilename().toUtf8(), GA_Update ); if ( !heatmapDS ) { QMessageBox::information( 0, tr( "Raster update error" ), tr( "Could not open the created raster for updating. The heatmap was not generated." ) ); return; } poBand = heatmapDS->GetRasterBand( 1 ); QgsAttributeList myAttrList; int rField = 0; int wField = 0; // Handle different radius options double radius; double radiusToMapUnits = 1; int myBuffer = 0; if ( d.variableRadius() ) { rField = d.radiusField(); myAttrList.append( rField ); QgsDebugMsg( QString( "Radius Field index received: %1" ).arg( rField ) ); // If not using map units, then calculate a conversion factor to convert the radii to map units if ( d.radiusUnit() == HeatmapGui::Meters ) { radiusToMapUnits = mapUnitsOf( 1, inputLayer->crs() ); } } else { radius = d.radius(); // radius returned by d.radius() is already in map units myBuffer = bufferSize( radius, cellsize ); } if ( d.weighted() ) { wField = d.weightField(); myAttrList.append( wField ); } // This might have attributes or mightnot have attibutes at all // based on the variableRadius() and weighted() QgsFeatureIterator fit = inputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( myAttrList ) ); int totalFeatures = inputLayer->featureCount(); int counter = 0; QProgressDialog p( tr( "Creating heatmap" ), tr( "Abort" ), 0, totalFeatures, mQGisIface->mainWindow() ); p.setWindowModality( Qt::ApplicationModal ); p.show(); QgsFeature myFeature; while ( fit.nextFeature( myFeature ) ) { counter++; p.setValue( counter ); QApplication::processEvents(); if ( p.wasCanceled() ) { QMessageBox::information( 0, tr( "Heatmap generation aborted" ), tr( "QGIS will now load the partially-computed raster." ) ); break; } QgsGeometry* myPointGeometry; myPointGeometry = myFeature.geometry(); // convert the geometry to point QgsPoint myPoint; myPoint = myPointGeometry->asPoint(); // avoiding any empty points or out of extent points if (( myPoint.x() < myBBox.xMinimum() ) || ( myPoint.y() < myBBox.yMinimum() ) || ( myPoint.x() > myBBox.xMaximum() ) || ( myPoint.y() > myBBox.yMaximum() ) ) { continue; } // If radius is variable then fetch it and calculate new pixel buffer size if ( d.variableRadius() ) { radius = myFeature.attribute( rField ).toDouble() * radiusToMapUnits; myBuffer = bufferSize( radius, cellsize ); } int blockSize = 2 * myBuffer + 1; //Block SIDE would be more appropriate // calculate the pixel position unsigned int xPosition, yPosition; xPosition = (( myPoint.x() - myBBox.xMinimum() ) / cellsize ) - myBuffer; yPosition = (( myPoint.y() - myBBox.yMinimum() ) / cellsize ) - myBuffer; // get the data float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize ); poBand->RasterIO( GF_Read, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ); double weight = 1.0; if ( d.weighted() ) { weight = myFeature.attribute( wField ).toDouble(); } for ( int xp = 0; xp <= myBuffer; xp++ ) { for ( int yp = 0; yp <= myBuffer; yp++ ) { double distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) ); // is pixel outside search bandwidth of feature? if ( distance > myBuffer ) { continue; } double pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape ); // clearing anamolies along the axes if ( xp == 0 && yp == 0 ) { pixelValue /= 4; } else if ( xp == 0 || yp == 0 ) { pixelValue /= 2; } int pos[4]; pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp ); pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp ); pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp ); pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp ); for ( int p = 0; p < 4; p++ ) { if ( dataBuffer[ pos[p] ] == NO_DATA ) { dataBuffer[ pos[p] ] = 0; } dataBuffer[ pos[p] ] += pixelValue; } } } poBand->RasterIO( GF_Write, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ); CPLFree( dataBuffer ); } // Finally close the dataset GDALClose(( GDALDatasetH ) heatmapDS ); // Open the file in QGIS window mQGisIface->addRasterLayer( d.outputFilename(), QFileInfo( d.outputFilename() ).baseName() ); } }
SpatialIndex::Region QgsSpatialIndex::rectToRegion( const QgsRectangle &rect ) { double pt1[2] = { rect.xMinimum(), rect.yMinimum() }, pt2[2] = { rect.xMaximum(), rect.yMaximum() }; return SpatialIndex::Region( pt1, pt2, 2 ); }
QString QgsOSMDownload::queryFromRect( const QgsRectangle& rect ) { return QStringLiteral( "(node(%1,%2,%3,%4);<;);out;" ).arg( rect.yMinimum() ).arg( rect.xMinimum() ) .arg( rect.yMaximum() ).arg( rect.xMaximum() ); }
//! Simplify the WKB-geometry using the specified tolerance QgsGeometry QgsMapToPixelSimplifier::simplifyGeometry( int simplifyFlags, SimplifyAlgorithm simplifyAlgorithm, QgsWkbTypes::Type wkbType, const QgsAbstractGeometry& geometry, const QgsRectangle &envelope, double map2pixelTol, bool isaLinearRing ) { bool isGeneralizable = true; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { return generalizeWkbGeometryByBoundingBox( wkbType, geometry, envelope ); } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; const QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( wkbType ); // Write the geometry if ( flatType == QgsWkbTypes::LineString || flatType == QgsWkbTypes::CircularString ) { const QgsCurve& srcCurve = dynamic_cast<const QgsCurve&>( geometry ); QScopedPointer<QgsCurve> output( createEmptySameTypeGeom( srcCurve ) ); double x = 0.0, y = 0.0, lastX = 0.0, lastY = 0.0; QgsRectangle r; r.setMinimal(); const int numPoints = srcCurve.numPoints(); if ( numPoints <= ( isaLinearRing ? 4 : 2 ) ) isGeneralizable = false; bool isLongSegment; bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments. // Check whether the LinearRing is really closed. if ( isaLinearRing ) { isaLinearRing = qgsDoubleNear( srcCurve.xAt( 0 ), srcCurve.xAt( numPoints - 1 ) ) && qgsDoubleNear( srcCurve.yAt( 0 ), srcCurve.yAt( numPoints - 1 ) ); } // Process each vertex... switch ( simplifyAlgorithm ) { case SnapToGrid: { double gridOriginX = envelope.xMinimum(); double gridOriginY = envelope.yMinimum(); // Use a factor for the maximum displacement distance for simplification, similar as GeoServer does float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f; for ( int i = 0; i < numPoints; ++i ) { x = srcCurve.xAt( i ); y = srcCurve.yAt( i ); if ( i == 0 || !isGeneralizable || !equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) ); lastX = x; lastY = y; } r.combineExtentWith( x, y ); } break; } case Visvalingam: { map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'Area' calculations. EFFECTIVE_AREAS ea( srcCurve ); int set_area = 0; ptarray_calc_areas( &ea, isaLinearRing ? 4 : 2, set_area, map2pixelTol ); for ( int i = 0; i < numPoints; ++i ) { if ( ea.res_arealist[ i ] > map2pixelTol ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), ea.inpts.at( i ) ); } } break; } case Distance: { map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations. for ( int i = 0; i < numPoints; ++i ) { x = srcCurve.xAt( i ); y = srcCurve.yAt( i ); isLongSegment = false; if ( i == 0 || !isGeneralizable || ( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) ); lastX = x; lastY = y; hasLongSegments |= isLongSegment; } r.combineExtentWith( x, y ); } } } if ( output->numPoints() < ( isaLinearRing ? 4 : 2 ) ) { // we simplified the geometry too much! if ( !hasLongSegments ) { // approximate the geometry's shape by its bounding box // (rect for linear ring / one segment for line string) return generalizeWkbGeometryByBoundingBox( wkbType, geometry, r ); } else { // Bad luck! The simplified geometry is invalid and approximation by bounding box // would create artifacts due to long segments. // We will return the original geometry return QgsGeometry( geometry.clone() ); } } if ( isaLinearRing ) { // make sure we keep the linear ring closed if ( !qgsDoubleNear( lastX, output->xAt( 0 ) ) || !qgsDoubleNear( lastY, output->yAt( 0 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( output->xAt( 0 ), output->yAt( 0 ) ) ); } } return QgsGeometry( output.take() ); } else if ( flatType == QgsWkbTypes::Polygon ) { const QgsPolygonV2& srcPolygon = dynamic_cast<const QgsPolygonV2&>( geometry ); QScopedPointer<QgsPolygonV2> polygon( new QgsPolygonV2() ); polygon->setExteriorRing( dynamic_cast<QgsCurve*>( simplifyGeometry( simplifyFlags, simplifyAlgorithm, srcPolygon.exteriorRing()->wkbType(), *srcPolygon.exteriorRing(), envelope, map2pixelTol, true ).geometry()->clone() ) ); for ( int i = 0; i < srcPolygon.numInteriorRings(); ++i ) { const QgsCurve* sub = srcPolygon.interiorRing( i ); polygon->addInteriorRing( dynamic_cast<QgsCurve*>( simplifyGeometry( simplifyFlags, simplifyAlgorithm, sub->wkbType(), *sub, envelope, map2pixelTol, true ).geometry()->clone() ) ); } return QgsGeometry( polygon.take() ); } else if ( QgsWkbTypes::isMultiType( flatType ) ) { const QgsGeometryCollection& srcCollection = dynamic_cast<const QgsGeometryCollection&>( geometry ); QScopedPointer<QgsGeometryCollection> collection( createEmptySameTypeGeom( srcCollection ) ); const int numGeoms = srcCollection.numGeometries(); for ( int i = 0; i < numGeoms; ++i ) { const QgsAbstractGeometry* sub = srcCollection.geometryN( i ); collection->addGeometry( simplifyGeometry( simplifyFlags, simplifyAlgorithm, sub->wkbType(), *sub, envelope, map2pixelTol, false ).geometry()->clone() ); } return QgsGeometry( collection.take() ); } return QgsGeometry( geometry.clone() ); }
static SpatialIndex::Region rect2region( const QgsRectangle &rect ) { double pLow[2] = { rect.xMinimum(), rect.yMinimum() }; double pHigh[2] = { rect.xMaximum(), rect.yMaximum() }; return SpatialIndex::Region( pLow, pHigh, 2 ); }
bool isSegmentInRect( double x0, double y0, double x1, double y1 ) { // compute outcodes for P0, P1, and whatever point lies outside the clip rectangle OutCode outcode0 = computeOutCode( x0, y0 ); OutCode outcode1 = computeOutCode( x1, y1 ); bool accept = false; while ( true ) { if ( !( outcode0 | outcode1 ) ) { // Bitwise OR is 0. Trivially accept and get out of loop accept = true; break; } else if ( outcode0 & outcode1 ) { // Bitwise AND is not 0. Trivially reject and get out of loop break; } else { // failed both tests, so calculate the line segment to clip // from an outside point to an intersection with clip edge double x, y; // At least one endpoint is outside the clip rectangle; pick it. OutCode outcodeOut = outcode0 ? outcode0 : outcode1; // Now find the intersection point; // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0) if ( outcodeOut & TOP ) { // point is above the clip rectangle x = x0 + ( x1 - x0 ) * ( mRect.yMaximum() - y0 ) / ( y1 - y0 ); y = mRect.yMaximum(); } else if ( outcodeOut & BOTTOM ) { // point is below the clip rectangle x = x0 + ( x1 - x0 ) * ( mRect.yMinimum() - y0 ) / ( y1 - y0 ); y = mRect.yMinimum(); } else if ( outcodeOut & RIGHT ) { // point is to the right of clip rectangle y = y0 + ( y1 - y0 ) * ( mRect.xMaximum() - x0 ) / ( x1 - x0 ); x = mRect.xMaximum(); } else if ( outcodeOut & LEFT ) { // point is to the left of clip rectangle y = y0 + ( y1 - y0 ) * ( mRect.xMinimum() - x0 ) / ( x1 - x0 ); x = mRect.xMinimum(); } else break; // Now we move outside point to intersection point to clip // and get ready for next pass. if ( outcodeOut == outcode0 ) { x0 = x; y0 = y; outcode0 = computeOutCode( x0, y0 ); } else { x1 = x; y1 = y; outcode1 = computeOutCode( x1, y1 ); } } } return accept; }
void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffset, int yOffset, int nCols, int nRows, double* sourceTransform, GDALRasterBandH sourceBand, float* rasterBuffer ) { //If dataset transform is the same as the requested transform, do a normal GDAL raster io if ( transformationsEqual( targetGeotransform, sourceTransform ) ) { GDALRasterIO( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0, 0 ); return; } //pixel calculation needed because of different raster position / resolution int nodataSuccess; double nodataValue = GDALGetRasterNoDataValue( sourceBand, &nodataSuccess ); QgsRectangle targetRect( targetGeotransform[0] + targetGeotransform[1] * xOffset, targetGeotransform[3] + yOffset * targetGeotransform[5] + nRows * targetGeotransform[5] , targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] * nCols, targetGeotransform[3] + yOffset * targetGeotransform[5] ); QgsRectangle sourceRect( sourceTransform[0], sourceTransform[3] + GDALGetRasterBandYSize( sourceBand ) * sourceTransform[5], sourceTransform[0] + GDALGetRasterBandXSize( sourceBand )* sourceTransform[1], sourceTransform[3] ); QgsRectangle intersection = targetRect.intersect( &sourceRect ); //no intersection, fill all the pixels with nodata values if ( intersection.isEmpty() ) { int nPixels = nCols * nRows; for ( int i = 0; i < nPixels; ++i ) { rasterBuffer[i] = nodataValue; } return; } //do raster io in source resolution int sourcePixelOffsetXMin = floor(( intersection.xMinimum() - sourceTransform[0] ) / sourceTransform[1] ); int sourcePixelOffsetXMax = ceil(( intersection.xMaximum() - sourceTransform[0] ) / sourceTransform[1] ); int nSourcePixelsX = sourcePixelOffsetXMax - sourcePixelOffsetXMin; int sourcePixelOffsetYMax = floor(( intersection.yMaximum() - sourceTransform[3] ) / sourceTransform[5] ); int sourcePixelOffsetYMin = ceil(( intersection.yMinimum() - sourceTransform[3] ) / sourceTransform[5] ); int nSourcePixelsY = sourcePixelOffsetYMin - sourcePixelOffsetYMax; float* sourceRaster = ( float * ) CPLMalloc( sizeof( float ) * nSourcePixelsX * nSourcePixelsY ); double sourceRasterXMin = sourceRect.xMinimum() + sourcePixelOffsetXMin * sourceTransform[1]; double sourceRasterYMax = sourceRect.yMaximum() + sourcePixelOffsetYMax * sourceTransform[5]; GDALRasterIO( sourceBand, GF_Read, sourcePixelOffsetXMin, sourcePixelOffsetYMax, nSourcePixelsX, nSourcePixelsY, sourceRaster, nSourcePixelsX, nSourcePixelsY, GDT_Float32, 0, 0 ); double targetPixelX; double targetPixelXMin = targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] / 2.0; double targetPixelY = targetGeotransform[3] + targetGeotransform[5] * yOffset + targetGeotransform[5] / 2.0; //coordinates of current target pixel int sourceIndexX, sourceIndexY; //current raster index in source pixels double sx, sy; for ( int i = 0; i < nRows; ++i ) { targetPixelX = targetPixelXMin; for ( int j = 0; j < nCols; ++j ) { sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1]; sourceIndexX = sx > 0 ? sx : floor( sx ); sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5]; sourceIndexY = sy > 0 ? sy : floor( sy ); if ( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX && sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY ) { rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ]; } else { rasterBuffer[j + i*j] = nodataValue; } targetPixelX += targetGeotransform[1]; } targetPixelY += targetGeotransform[5]; } CPLFree( sourceRaster ); return; }
QgsRasterBandStats QgsRasterInterface::bandStatistics( int theBandNo, int theStats, const QgsRectangle & theExtent, int theSampleSize ) { QgsDebugMsg( QString( "theBandNo = %1 theStats = %2 theSampleSize = %3" ).arg( theBandNo ).arg( theStats ).arg( theSampleSize ) ); // TODO: null values set on raster layer!!! QgsRasterBandStats myRasterBandStats; initStatistics( myRasterBandStats, theBandNo, theStats, theExtent, theSampleSize ); foreach ( QgsRasterBandStats stats, mStatistics ) { if ( stats.contains( myRasterBandStats ) ) { QgsDebugMsg( "Using cached statistics." ); return stats; } } QgsRectangle myExtent = myRasterBandStats.extent; int myWidth = myRasterBandStats.width; int myHeight = myRasterBandStats.height; //int myDataType = dataType( theBandNo ); int myXBlockSize = xBlockSize(); int myYBlockSize = yBlockSize(); if ( myXBlockSize == 0 ) // should not happen, but happens { myXBlockSize = 500; } if ( myYBlockSize == 0 ) // should not happen, but happens { myYBlockSize = 500; } int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize; int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize; double myXRes = myExtent.width() / myWidth; double myYRes = myExtent.height() / myHeight; // TODO: progress signals // used by single pass stdev double myMean = 0; double mySumOfSquares = 0; bool myFirstIterationFlag = true; for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ ) { for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ ) { QgsDebugMsg( QString( "myYBlock = %1 myXBlock = %2" ).arg( myYBlock ).arg( myXBlock ) ); int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize ); int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize ); double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes; double xmax = xmin + myBlockWidth * myXRes; double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes; double ymax = ymin - myBlockHeight * myYRes; QgsRectangle myPartExtent( xmin, ymin, xmax, ymax ); QgsRasterBlock* blk = block( theBandNo, myPartExtent, myBlockWidth, myBlockHeight ); // Collect the histogram counts. for ( qgssize i = 0; i < (( qgssize ) myBlockHeight ) * myBlockWidth; i++ ) { if ( blk->isNoData( i ) ) continue; // NULL double myValue = blk->value( i ); myRasterBandStats.sum += myValue; myRasterBandStats.elementCount++; if ( myFirstIterationFlag ) { myFirstIterationFlag = false; myRasterBandStats.minimumValue = myValue; myRasterBandStats.maximumValue = myValue; } else { if ( myValue < myRasterBandStats.minimumValue ) { myRasterBandStats.minimumValue = myValue; } if ( myValue > myRasterBandStats.maximumValue ) { myRasterBandStats.maximumValue = myValue; } } // Single pass stdev double myDelta = myValue - myMean; myMean += myDelta / myRasterBandStats.elementCount; mySumOfSquares += myDelta * ( myValue - myMean ); } delete blk; } } myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue; myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount; myRasterBandStats.sumOfSquares = mySumOfSquares; // OK with single pass? // stdDev may differ from GDAL stats, because GDAL is using naive single pass // algorithm which is more error prone (because of rounding errors) // Divide result by sample size - 1 and get square root to get stdev myRasterBandStats.stdDev = sqrt( mySumOfSquares / ( myRasterBandStats.elementCount - 1 ) ); QgsDebugMsg( "************ STATS **************" ); QgsDebugMsg( QString( "MIN %1" ).arg( myRasterBandStats.minimumValue ) ); QgsDebugMsg( QString( "MAX %1" ).arg( myRasterBandStats.maximumValue ) ); QgsDebugMsg( QString( "RANGE %1" ).arg( myRasterBandStats.range ) ); QgsDebugMsg( QString( "MEAN %1" ).arg( myRasterBandStats.mean ) ); QgsDebugMsg( QString( "STDDEV %1" ).arg( myRasterBandStats.stdDev ) ); myRasterBandStats.statsGathered = QgsRasterBandStats::All; mStatistics.append( myRasterBandStats ); return myRasterBandStats; }
QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext ) : QgsMapLayerRenderer( layer->id() ) , mRasterViewPort( nullptr ) , mPipe( nullptr ) { mPainter = rendererContext.painter(); const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); mMapToPixel = &theQgsMapToPixel; QgsMapToPixel mapToPixel = theQgsMapToPixel; if ( mapToPixel.mapRotation() ) { // unset rotation for the sake of local computations. // Rotation will be handled by QPainter later // TODO: provide a method of QgsMapToPixel to fetch map center // in geographical units QgsPoint center = mapToPixel.toMapCoordinates( mapToPixel.mapWidth() / 2.0, mapToPixel.mapHeight() / 2.0 ); mapToPixel.setMapRotation( 0, center.x(), center.y() ); } QgsRectangle myProjectedViewExtent; QgsRectangle myProjectedLayerExtent; if ( rendererContext.coordinateTransform() ) { QgsDebugMsg( "coordinateTransform set -> project extents." ); try { myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedViewExtent.setMinimal(); } try { myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( layer->extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedLayerExtent.setMinimal(); } } else { QgsDebugMsg( "coordinateTransform not set" ); myProjectedViewExtent = rendererContext.extent(); myProjectedLayerExtent = layer->extent(); } // clip raster extent to view extent QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); if ( myRasterExtent.isEmpty() ) { QgsDebugMsg( "draw request outside view extent." ); // nothing to do return; } QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); // // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings // relating to the size (in pixels and coordinate system units) of the raster part that is // in view in the map window. It also stores the origin. // //this is not a class level member because every time the user pans or zooms //the contents of the rasterViewPort will change mRasterViewPort = new QgsRasterViewPort(); mRasterViewPort->mDrawnExtent = myRasterExtent; if ( rendererContext.coordinateTransform() ) { mRasterViewPort->mSrcCRS = layer->crs(); mRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); mRasterViewPort->mSrcDatumTransform = rendererContext.coordinateTransform()->sourceDatumTransform(); mRasterViewPort->mDestDatumTransform = rendererContext.coordinateTransform()->destinationDatumTransform(); } else { mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mSrcDatumTransform = -1; mRasterViewPort->mDestDatumTransform = -1; } // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) mRasterViewPort->mTopLeftPoint = mapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); mRasterViewPort->mBottomRightPoint = mapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); // align to output device grid, i.e. floor/ceil to integers // TODO: this should only be done if paint device is raster - screen, image // for other devices (pdf) it can have floating point origin // we could use floating point for raster devices as well, but respecting the // output device grid should make it more effective as the resampling is done in // the provider anyway mRasterViewPort->mTopLeftPoint.setX( floor( mRasterViewPort->mTopLeftPoint.x() ) ); mRasterViewPort->mTopLeftPoint.setY( floor( mRasterViewPort->mTopLeftPoint.y() ) ); mRasterViewPort->mBottomRightPoint.setX( ceil( mRasterViewPort->mBottomRightPoint.x() ) ); mRasterViewPort->mBottomRightPoint.setY( ceil( mRasterViewPort->mBottomRightPoint.y() ) ); // recalc myRasterExtent to aligned values myRasterExtent.set( mapToPixel.toMapCoordinatesF( mRasterViewPort->mTopLeftPoint.x(), mRasterViewPort->mBottomRightPoint.y() ), mapToPixel.toMapCoordinatesF( mRasterViewPort->mBottomRightPoint.x(), mRasterViewPort->mTopLeftPoint.y() ) ); //raster viewport top left / bottom right are already rounded to int mRasterViewPort->mWidth = static_cast<int>( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ); mRasterViewPort->mHeight = static_cast<int>( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ); //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue //mapToPixel.mapUnitsPerPixel() is less then 1, //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( layer->width() ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( layer->height() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 ); // /\/\/\ - added to handle zoomed-in rasters // TODO R->mLastViewPort = *mRasterViewPort; // TODO: is it necessary? Probably WMS only? layer->dataProvider()->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); // copy the whole raster pipe! mPipe = new QgsRasterPipe( *layer->pipe() ); }
QgsRasterHistogram QgsRasterInterface::histogram( int theBandNo, int theBinCount, double theMinimum, double theMaximum, const QgsRectangle & theExtent, int theSampleSize, bool theIncludeOutOfRange ) { QgsDebugMsg( QString( "theBandNo = %1 theBinCount = %2 theMinimum = %3 theMaximum = %4 theSampleSize = %5" ).arg( theBandNo ).arg( theBinCount ).arg( theMinimum ).arg( theMaximum ).arg( theSampleSize ) ); QgsRasterHistogram myHistogram; initHistogram( myHistogram, theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange ); // Find cached foreach ( QgsRasterHistogram histogram, mHistograms ) { if ( histogram == myHistogram ) { QgsDebugMsg( "Using cached histogram." ); return histogram; } } int myBinCount = myHistogram.binCount; int myWidth = myHistogram.width; int myHeight = myHistogram.height; QgsRectangle myExtent = myHistogram.extent; myHistogram.histogramVector.resize( myBinCount ); int myXBlockSize = xBlockSize(); int myYBlockSize = yBlockSize(); if ( myXBlockSize == 0 ) // should not happen, but happens { myXBlockSize = 500; } if ( myYBlockSize == 0 ) // should not happen, but happens { myYBlockSize = 500; } int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize; int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize; double myXRes = myExtent.width() / myWidth; double myYRes = myExtent.height() / myHeight; double myMinimum = myHistogram.minimum; double myMaximum = myHistogram.maximum; // To avoid rounding errors // TODO: check this double myerval = ( myMaximum - myMinimum ) / myHistogram.binCount; myMinimum -= 0.1 * myerval; myMaximum += 0.1 * myerval; QgsDebugMsg( QString( "binCount = %1 myMinimum = %2 myMaximum = %3" ).arg( myHistogram.binCount ).arg( myMinimum ).arg( myMaximum ) ); double myBinSize = ( myMaximum - myMinimum ) / myBinCount; // TODO: progress signals for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ ) { for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ ) { int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize ); int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize ); double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes; double xmax = xmin + myBlockWidth * myXRes; double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes; double ymax = ymin - myBlockHeight * myYRes; QgsRectangle myPartExtent( xmin, ymin, xmax, ymax ); QgsRasterBlock* blk = block( theBandNo, myPartExtent, myBlockWidth, myBlockHeight ); // Collect the histogram counts. for ( qgssize i = 0; i < (( qgssize ) myBlockHeight ) * myBlockWidth; i++ ) { if ( blk->isNoData( i ) ) { continue; // NULL } double myValue = blk->value( i ); int myBinIndex = static_cast <int>( qFloor(( myValue - myMinimum ) / myBinSize ) ) ; if (( myBinIndex < 0 || myBinIndex > ( myBinCount - 1 ) ) && !theIncludeOutOfRange ) { continue; } if ( myBinIndex < 0 ) myBinIndex = 0; if ( myBinIndex > ( myBinCount - 1 ) ) myBinIndex = myBinCount - 1; myHistogram.histogramVector[myBinIndex] += 1; myHistogram.nonNullCount++; } delete blk; } } myHistogram.valid = true; mHistograms.append( myHistogram ); #ifdef QGISDEBUG QString hist; for ( int i = 0; i < qMin( myHistogram.histogramVector.size(), 500 ); i++ ) { hist += QString::number( myHistogram.histogramVector.value( i ) ) + " "; } QgsDebugMsg( "Histogram (max first 500 bins): " + hist ); #endif return myHistogram; }
//! Simplify the WKB-geometry using the specified tolerance bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, SimplifyAlgorithm simplifyAlgorithm, QGis::WkbType wkbType, QgsConstWkbPtr sourceWkbPtr, QgsWkbPtr targetWkbPtr, int &targetWkbSize, const QgsRectangle &envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing ) { bool isGeneralizable = true; bool result = false; // Save initial WKB settings to use when the simplification creates invalid geometries QgsConstWkbPtr sourcePrevWkbPtr( sourceWkbPtr ); QgsWkbPtr targetPrevWkbPtr( targetWkbPtr ); int targetWkbPrevSize = targetWkbSize; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { isGeneralizable = generalizeWkbGeometryByBoundingBox( wkbType, sourceWkbPtr, targetWkbPtr, targetWkbSize, envelope, writeHeader ); if ( isGeneralizable ) return true; } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; // Write the main header of the geometry if ( writeHeader ) { QgsWKBTypes::Type geometryType = sourceWkbPtr.readHeader(); targetWkbPtr << ( char ) QgsApplication::endian() << QgsWKBTypes::flatType( geometryType ); targetWkbSize += targetWkbPtr - targetPrevWkbPtr; } unsigned int flatType = QGis::flatType( wkbType ); // Write the geometry if ( flatType == QGis::WKBLineString || isaLinearRing ) { QgsWkbPtr savedTargetWkbPtr( targetWkbPtr ); double x = 0.0, y = 0.0, lastX = 0, lastY = 0; QgsRectangle r; r.setMinimal(); int skipZM = ( QGis::wkbDimensions( wkbType ) - 2 ) * sizeof( double ); Q_ASSERT( skipZM >= 0 ); int numPoints; sourceWkbPtr >> numPoints; if ( numPoints <= ( isaLinearRing ? 5 : 2 ) ) isGeneralizable = false; QgsWkbPtr numPtr( targetWkbPtr ); int numTargetPoints = 0; targetWkbPtr << numTargetPoints; targetWkbSize += 4; bool isLongSegment; bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments. bool badLuck = false; // Check whether the LinearRing is really closed. if ( isaLinearRing ) { QgsConstWkbPtr checkPtr( sourceWkbPtr ); double x1, y1, x2, y2; checkPtr >> x1 >> y1; checkPtr += skipZM + ( numPoints - 2 ) * ( 2 * sizeof( double ) + skipZM ); checkPtr >> x2 >> y2; isaLinearRing = qgsDoubleNear( x1, x2 ) && qgsDoubleNear( y1, y2 ); } // Process each vertex... if ( simplifyAlgorithm == SnapToGrid ) { double gridOriginX = envelope.xMinimum(); double gridOriginY = envelope.yMinimum(); // Use a factor for the maximum displacement distance for simplification, similar as GeoServer does float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f; for ( int i = 0; i < numPoints; ++i ) { sourceWkbPtr >> x >> y; sourceWkbPtr += skipZM; if ( i == 0 || !isGeneralizable || !equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { targetWkbPtr << x << y; lastX = x; lastY = y; numTargetPoints++; } r.combineExtentWith( x, y ); } }
bool QgsVectorLayerRenderer::render() { if ( mGeometryType == QGis::NoGeometry || mGeometryType == QGis::UnknownGeometry ) return true; if ( !mRendererV2 ) { mErrors.append( "No renderer for drawing." ); return false; } // Per feature blending mode if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) { // set the painter to the feature blend mode, so that features drawn // on this layer will interact and blend with each other mContext.painter()->setCompositionMode( mFeatureBlendMode ); } mRendererV2->startRender( mContext, mFields ); QgsFeatureRequest featureRequest = QgsFeatureRequest() .setFilterRect( mContext.extent() ) .setSubsetOfAttributes( mAttrNames, mFields ); // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine. if ( mSimplifyGeometry ) { double map2pixelTol = mSimplifyMethod.threshold(); const QgsMapToPixel& mtp = mContext.mapToPixel(); map2pixelTol *= mtp.mapUnitsPerPixel(); const QgsCoordinateTransform* ct = mContext.coordinateTransform(); // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem if ( ct && !(( QgsCoordinateTransform* )ct )->isShortCircuited() ) { try { QgsPoint center = mContext.extent().center(); double rectSize = ct->sourceCrs().geographicFlag() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100; QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize ); QgsRectangle targetRect = ct->transform( sourceRect ); QgsDebugMsg( QString( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ) ); QgsDebugMsg( QString( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ) ); if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() ) { QgsPoint minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() ); QgsPoint maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() ); QgsPoint minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() ); QgsPoint maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() ); double sourceHypothenuse = sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) ); double targetHypothenuse = sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) ); QgsDebugMsg( QString( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ) ); QgsDebugMsg( QString( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ) ); if ( targetHypothenuse != 0 ) map2pixelTol *= ( sourceHypothenuse / targetHypothenuse ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); } } QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); } QgsFeatureIterator fit = mSource->getFeatures( featureRequest ); if (( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels ) && mRendererV2->usingSymbolLevels() ) drawRendererV2Levels( fit ); else drawRendererV2( fit ); //apply layer transparency for vector layers if ( mContext.useAdvancedEffects() && mLayerTransparency != 0 ) { // a layer transparency has been set, so update the alpha for the flattened layer // by combining it with the layer transparency QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * mLayerTransparency / 100 ) ); // use destination in composition mode to merge source's alpha with destination mContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn ); mContext.painter()->fillRect( 0, 0, mContext.painter()->device()->width(), mContext.painter()->device()->height(), transparentFillColor ); } return true; }
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; }
/**************************** REGION ********************************/ void QgsGrassNewMapset::setRegionPage() { QgsDebugMsg( "entered" ); // Set defaults if ( !mRegionModified ) { setGrassRegionDefaults(); } // Create new projection QgsCoordinateReferenceSystem newCrs; if ( mProjRadioButton->isChecked() ) { QgsDebugMsg( QString( "selectedCrsId() = %1" ).arg( mProjectionSelector->selectedCrsId() ) ); if ( mProjectionSelector->selectedCrsId() > 0 ) { newCrs.createFromSrsId( mProjectionSelector->selectedCrsId() ); if ( ! newCrs.isValid() ) { QgsGrass::warning( tr( "Cannot create projection." ) ); } } } // Reproject previous region if it was modified // and if previous and current projection is valid if ( mRegionModified && newCrs.isValid() && mCrs.isValid() && newCrs.srsid() != mCrs.srsid() ) { QgsCoordinateTransform trans( mCrs, newCrs ); double n = mNorthLineEdit->text().toDouble(); double s = mSouthLineEdit->text().toDouble(); double e = mEastLineEdit->text().toDouble(); double w = mWestLineEdit->text().toDouble(); std::vector<QgsPoint> points; // TODO: this is not perfect points.push_back( QgsPoint( w, s ) ); points.push_back( QgsPoint( e, n ) ); bool ok = true; for ( int i = 0; i < 2; i++ ) { try { points[i] = trans.transform( points[i] ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( "Cannot transform point" ); ok = false; break; } } if ( ok ) { int precision = newCrs.mapUnits() == QGis::Degrees ? 6 : 1; mNorthLineEdit->setText( qgsDoubleToString( points[1].y(), precision ) ); mSouthLineEdit->setText( qgsDoubleToString( points[0].y(), precision ) ); mEastLineEdit->setText( qgsDoubleToString( points[1].x(), precision ) ); mWestLineEdit->setText( qgsDoubleToString( points[0].x(), precision ) ); } else { QgsGrass::warning( tr( "Cannot reproject previously set region, default region set." ) ); setGrassRegionDefaults(); } } // Set current region projection mCrs = newCrs; // Enable / disable region selection widgets if ( mNoProjRadioButton->isChecked() ) { mRegionMap->hide(); mCurrentRegionButton->hide(); mRegionsComboBox->hide(); mRegionButton->hide(); mSetRegionFrame->hide(); } else { mRegionMap->show(); mCurrentRegionButton->show(); mRegionsComboBox->show(); mRegionButton->show(); mSetRegionFrame->show(); QgsRectangle ext = mIface->mapCanvas()->extent(); if ( ext.xMinimum() >= ext.xMaximum() || ext.yMinimum() >= ext.yMaximum() ) { mCurrentRegionButton->setEnabled( false ); } } checkRegion(); if ( !mNoProjRadioButton->isChecked() ) { drawRegion(); } }
// Default implementation for values QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ ) { QgsDebugMsgLevel( "Entered", 4 ); QMap<int, QVariant> results; if ( format != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) ) { QgsDebugMsg( "Format not supported" ); return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) ); } if ( !extent().contains( point ) ) { // Outside the raster for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ ) { results.insert( bandNo, QVariant() ); } return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results ); } QgsRectangle finalExtent = boundingBox; if ( finalExtent.isEmpty() ) finalExtent = extent(); if ( width == 0 ) { width = capabilities() & Size ? xSize() : 1000; } if ( height == 0 ) { height = capabilities() & Size ? ySize() : 1000; } // Calculate the row / column where the point falls double xres = ( finalExtent.width() ) / width; double yres = ( finalExtent.height() ) / height; int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) ); int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) ); double xMin = finalExtent.xMinimum() + col * xres; double xMax = xMin + xres; double yMax = finalExtent.yMaximum() - row * yres; double yMin = yMax - yres; QgsRectangle pixelExtent( xMin, yMin, xMax, yMax ); for ( int i = 1; i <= bandCount(); i++ ) { QgsRasterBlock *myBlock = block( i, pixelExtent, 1, 1 ); if ( myBlock ) { double value = myBlock->value( 0 ); results.insert( i, value ); delete myBlock; } else { results.insert( i, QVariant() ); } } return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results ); }
void QgsGrassFeatureIterator::setSelectionRect( const QgsRectangle& rect, bool useIntersect ) { QgsDebugMsg( QString( "useIntersect = %1 rect = %2" ).arg( useIntersect ).arg( rect.toString() ) ); // TODO: selection of edited lines // Lock because functions using static/global variables are used // (e.g. static LocList in Vect_select_lines_by_box, global BranchBuf in RTreeGetBranches) QgsGrass::lock(); mSelection.fill( false ); BOUND_BOX box; box.N = rect.yMaximum(); box.S = rect.yMinimum(); box.E = rect.xMaximum(); box.W = rect.xMinimum(); box.T = PORT_DOUBLE_MAX; box.B = -PORT_DOUBLE_MAX; // Init structures struct ilist * list = Vect_new_list(); if ( !useIntersect ) { // select by bounding boxes only if ( mSource->mLayerType == QgsGrassProvider::POINT || mSource->mLayerType == QgsGrassProvider::CENTROID || mSource->mLayerType == QgsGrassProvider::LINE || mSource->mLayerType == QgsGrassProvider::FACE || mSource->mLayerType == QgsGrassProvider::BOUNDARY || mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE || mSource->mEditing ) { QgsDebugMsg( "Vect_select_lines_by_box" ); int type = mSource->mGrassType; if ( mSource->mEditing ) { type = GV_POINTS | GV_LINES; } QgsDebugMsg( QString( "type = %1" ).arg( type ) ); Vect_select_lines_by_box( mSource->map(), &box, type, list ); } else if ( mSource->mLayerType == QgsGrassProvider::POLYGON ) { Vect_select_areas_by_box( mSource->map(), &box, list ); } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { Vect_select_nodes_by_box( mSource->map(), &box, list ); } } else { // check intersection struct line_pnts *polygon = Vect_new_line_struct(); // Using z coor -PORT_DOUBLE_MAX/PORT_DOUBLE_MAX we cover 3D, Vect_select_lines_by_polygon is // using dig_line_box to get the box, it is not perfect, Vect_select_lines_by_polygon // should clarify better how 2D/3D is treated Vect_append_point( polygon, rect.xMinimum(), rect.yMinimum(), -PORT_DOUBLE_MAX ); Vect_append_point( polygon, rect.xMaximum(), rect.yMinimum(), PORT_DOUBLE_MAX ); Vect_append_point( polygon, rect.xMaximum(), rect.yMaximum(), 0 ); Vect_append_point( polygon, rect.xMinimum(), rect.yMaximum(), 0 ); Vect_append_point( polygon, rect.xMinimum(), rect.yMinimum(), 0 ); if ( mSource->mLayerType == QgsGrassProvider::POINT || mSource->mLayerType == QgsGrassProvider::CENTROID || mSource->mLayerType == QgsGrassProvider::LINE || mSource->mLayerType == QgsGrassProvider::FACE || mSource->mLayerType == QgsGrassProvider::BOUNDARY || mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE || mSource->mEditing ) { QgsDebugMsg( "Vect_select_lines_by_polygon" ); int type = mSource->mGrassType; if ( mSource->mEditing ) { type = GV_POINTS | GV_LINES; } QgsDebugMsg( QString( "type = %1" ).arg( type ) ); Vect_select_lines_by_polygon( mSource->map(), polygon, 0, NULL, type, list ); } else if ( mSource->mLayerType == QgsGrassProvider::POLYGON ) { Vect_select_areas_by_polygon( mSource->map(), polygon, 0, NULL, list ); } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { // There is no Vect_select_nodes_by_polygon but for nodes it is the same as by box Vect_select_nodes_by_box( mSource->map(), &box, list ); } Vect_destroy_line_struct( polygon ); } for ( int i = 0; i < list->n_values; i++ ) { int lid = list->value[i]; if ( lid < 1 || lid >= mSelection.size() ) // should not happen { QgsDebugMsg( QString( "lid %1 out of range <1,%2>" ).arg( lid ).arg( mSelection.size() ) ); continue; } mSelection.setBit( lid ); } Vect_destroy_list( list ); QgsDebugMsg( QString( " %1 features selected" ).arg( list->n_values ) ); QgsGrass::unlock(); }
bool QgsRenderChecker::runTest( QString theTestName, unsigned int theMismatchCount ) { if ( mExpectedImageFile.isEmpty() ) { qDebug( "QgsRenderChecker::runTest failed - Expected Image File not set." ); mReport = "<table>" "<tr><td>Test Result:</td><td>Expected Result:</td></tr>\n" "<tr><td>Nothing rendered</td>\n<td>Failed because Expected " "Image File not set.</td></tr></table>\n"; return false; } // // Load the expected result pixmap // QImage myExpectedImage( mExpectedImageFile ); mMatchTarget = myExpectedImage.width() * myExpectedImage.height(); // // Now render our layers onto a pixmap // mMapSettings.setBackgroundColor( qRgb( 152, 219, 249 ) ); mMapSettings.setFlag( QgsMapSettings::Antialiasing ); mMapSettings.setOutputSize( QSize( myExpectedImage.width(), myExpectedImage.height() ) ); QTime myTime; myTime.start(); QgsMapRendererSequentialJob job( mMapSettings ); job.start(); job.waitForFinished(); mElapsedTime = myTime.elapsed(); QImage myImage = job.renderedImage(); // // Save the pixmap to disk so the user can make a // visual assessment if needed // mRenderedImageFile = QDir::tempPath() + QDir::separator() + theTestName + "_result.png"; myImage.setDotsPerMeterX( myExpectedImage.dotsPerMeterX() ); myImage.setDotsPerMeterY( myExpectedImage.dotsPerMeterY() ); myImage.save( mRenderedImageFile, "PNG", 100 ); //create a world file to go with the image... QFile wldFile( QDir::tempPath() + QDir::separator() + theTestName + "_result.wld" ); if ( wldFile.open( QIODevice::WriteOnly ) ) { QgsRectangle r = mMapSettings.extent(); QTextStream stream( &wldFile ); stream << QString( "%1\r\n0 \r\n0 \r\n%2\r\n%3\r\n%4\r\n" ) .arg( qgsDoubleToString( mMapSettings.mapUnitsPerPixel() ) ) .arg( qgsDoubleToString( -mMapSettings.mapUnitsPerPixel() ) ) .arg( qgsDoubleToString( r.xMinimum() + mMapSettings.mapUnitsPerPixel() / 2.0 ) ) .arg( qgsDoubleToString( r.yMaximum() - mMapSettings.mapUnitsPerPixel() / 2.0 ) ); } return compareImages( theTestName, theMismatchCount ); }
bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform &ct, QgsRectangle &extent, QgsRectangle &r2 ) { bool split = false; try { #ifdef QGISDEBUG // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__); #endif // Split the extent into two if the source CRS is // geographic and the extent crosses the split in // geographic coordinates (usually +/- 180 degrees, // and is assumed to be so here), and draw each // extent separately. static const double SPLIT_COORD = 180.0; if ( ml->crs().isGeographic() ) { if ( ml->type() == QgsMapLayer::VectorLayer && !ct.destinationCrs().isGeographic() ) { // if we transform from a projected coordinate system check // check if transforming back roughly returns the input // extend - otherwise render the world. QgsRectangle extent1 = ct.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform ); QgsRectangle extent2 = ct.transformBoundingBox( extent1, QgsCoordinateTransform::ForwardTransform ); QgsDebugMsgLevel( QString( "\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" ) .arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ) .arg( extent1.toString(), extent2.toString() ).arg( extent2.width() ).arg( extent2.height() ) .arg( std::fabs( 1.0 - extent2.width() / extent.width() ) ) .arg( std::fabs( 1.0 - extent2.height() / extent.height() ) ) , 3 ); if ( std::fabs( 1.0 - extent2.width() / extent.width() ) < 0.5 && std::fabs( 1.0 - extent2.height() / extent.height() ) < 0.5 ) { extent = extent1; } else { extent = QgsRectangle( -180.0, -90.0, 180.0, 90.0 ); } } else { // Note: ll = lower left point QgsPointXY ll = ct.transform( extent.xMinimum(), extent.yMinimum(), QgsCoordinateTransform::ReverseTransform ); // and ur = upper right point QgsPointXY ur = ct.transform( extent.xMaximum(), extent.yMaximum(), QgsCoordinateTransform::ReverseTransform ); QgsDebugMsgLevel( QString( "in:%1 (ll:%2 ur:%3)" ).arg( extent.toString(), ll.toString(), ur.toString() ), 4 ); extent = ct.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform ); QgsDebugMsgLevel( QString( "out:%1 (w:%2 h:%3)" ).arg( extent.toString() ).arg( extent.width() ).arg( extent.height() ), 4 ); if ( ll.x() > ur.x() ) { // the coordinates projected in reverse order than what one would expect. // we are probably looking at an area that includes longitude of 180 degrees. // we need to take into account coordinates from two intervals: (-180,x1) and (x2,180) // so let's use (-180,180). This hopefully does not add too much overhead. It is // more straightforward than rendering with two separate extents and more consistent // for rendering, labeling and caching as everything is rendered just in one go extent.setXMinimum( -SPLIT_COORD ); extent.setXMaximum( SPLIT_COORD ); } } // TODO: the above rule still does not help if using a projection that covers the whole // world. E.g. with EPSG:3857 the longitude spectrum -180 to +180 is mapped to approx. // -2e7 to +2e7. Converting extent from -5e7 to +5e7 is transformed as -90 to +90, // but in fact the extent should cover the whole world. } else // can't cross 180 { if ( ct.destinationCrs().isGeographic() && ( extent.xMinimum() <= -180 || extent.xMaximum() >= 180 || extent.yMinimum() <= -90 || extent.yMaximum() >= 90 ) ) // Use unlimited rectangle because otherwise we may end up transforming wrong coordinates. // E.g. longitude -200 to +160 would be understood as +40 to +160 due to periodicity. // We could try to clamp coords to (-180,180) for lon resp. (-90,90) for lat, // but this seems like a safer choice. extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX ); else extent = ct.transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform ); } } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( "Transform error caught" ); extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX ); r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX ); } return split; }
bool QgsAlignRaster::checkInputParameters() { mErrorMessage.clear(); if ( mCrsWkt == "_error_" ) { mErrorMessage = QObject::tr( "Unable to reproject." ); return false; } if ( mCellSizeX == 0 || mCellSizeY == 0 ) { mErrorMessage = QObject::tr( "Cell size must not be zero." ); return false; } mXSize = mYSize = 0; for ( int i = 0; i < 6; ++i ) mGeoTransform[i] = 0; double finalExtent[4] = { 0, 0, 0, 0 }; // for each raster: determine their extent in projected cfg for ( int i = 0; i < mRasters.count(); ++i ) { Item& r = mRasters[i]; RasterInfo info( r.inputFilename ); QSizeF cs; QgsRectangle extent; if ( !suggestedWarpOutput( info, mCrsWkt, &cs, 0, &extent ) ) { mErrorMessage = QString( "Failed to get suggested warp output.\n\n" "File:\n%1\n\n" "Source WKT:\n%2\n\nDestination WKT:\n%3" ) .arg( r.inputFilename ) .arg( info.mCrsWkt ) .arg( mCrsWkt ); return false; } r.srcCellSizeInDestCRS = cs.width() * cs.height(); if ( finalExtent[0] == 0 && finalExtent[1] == 0 && finalExtent[2] == 0 && finalExtent[3] == 0 ) { // initialize with the first layer finalExtent[0] = extent.xMinimum(); finalExtent[1] = extent.yMinimum(); finalExtent[2] = extent.xMaximum(); finalExtent[3] = extent.yMaximum(); } else { // use intersection of rects if ( extent.xMinimum() > finalExtent[0] ) finalExtent[0] = extent.xMinimum(); if ( extent.yMinimum() > finalExtent[1] ) finalExtent[1] = extent.yMinimum(); if ( extent.xMaximum() < finalExtent[2] ) finalExtent[2] = extent.xMaximum(); if ( extent.yMaximum() < finalExtent[3] ) finalExtent[3] = extent.yMaximum(); } } // count in extra clip extent (if present) // 1. align requested rect to the grid - extend the rect if necessary // 2. intersect with clip extent with final extent if ( !( mClipExtent[0] == 0 && mClipExtent[1] == 0 && mClipExtent[2] == 0 && mClipExtent[3] == 0 ) ) { // extend clip extent to grid double clipX0 = floor_with_tolerance(( mClipExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX; double clipY0 = floor_with_tolerance(( mClipExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY; double clipX1 = ceil_with_tolerance(( mClipExtent[2] - clipX0 ) / mCellSizeX ) * mCellSizeX + clipX0; double clipY1 = ceil_with_tolerance(( mClipExtent[3] - clipY0 ) / mCellSizeY ) * mCellSizeY + clipY0; if ( clipX0 > finalExtent[0] ) finalExtent[0] = clipX0; if ( clipY0 > finalExtent[1] ) finalExtent[1] = clipY0; if ( clipX1 < finalExtent[2] ) finalExtent[2] = clipX1; if ( clipY1 < finalExtent[3] ) finalExtent[3] = clipY1; } // align to grid - shrink the rect if necessary // output raster grid configuration (with no rotation/shear) // ... and raster width/height double originX = ceil_with_tolerance(( finalExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX;; double originY = ceil_with_tolerance(( finalExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY; int xSize = floor_with_tolerance(( finalExtent[2] - originX ) / mCellSizeX ); int ySize = floor_with_tolerance(( finalExtent[3] - originY ) / mCellSizeY ); if ( xSize <= 0 || ySize <= 0 ) { mErrorMessage = QObject::tr( "No common intersecting area." ); return false; } mXSize = xSize; mYSize = ySize; // build final geotransform... mGeoTransform[0] = originX; mGeoTransform[1] = mCellSizeX; mGeoTransform[2] = 0; mGeoTransform[3] = originY + ( mCellSizeY * ySize ); mGeoTransform[4] = 0; mGeoTransform[5] = -mCellSizeY; return true; }
void QgsComposerMapWidget::updateGuiElements() { if ( mComposerMap ) { blockAllSignals( true ); //width, height, scale QRectF composerMapRect = mComposerMap->rect(); mWidthLineEdit->setText( QString::number( composerMapRect.width() ) ); mHeightLineEdit->setText( QString::number( composerMapRect.height() ) ); mScaleLineEdit->setText( QString::number( mComposerMap->scale(), 'f', 0 ) ); //preview mode QgsComposerMap::PreviewMode previewMode = mComposerMap->previewMode(); int index = -1; if ( previewMode == QgsComposerMap::Cache ) { index = mPreviewModeComboBox->findText( tr( "Cache" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Render ) { index = mPreviewModeComboBox->findText( tr( "Render" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Rectangle ) { index = mPreviewModeComboBox->findText( tr( "Rectangle" ) ); mUpdatePreviewButton->setEnabled( false ); } if ( index != -1 ) { mPreviewModeComboBox->setCurrentIndex( index ); } //composer map extent QgsRectangle composerMapExtent = mComposerMap->extent(); mXMinLineEdit->setText( QString::number( composerMapExtent.xMinimum(), 'f', 3 ) ); mXMaxLineEdit->setText( QString::number( composerMapExtent.xMaximum(), 'f', 3 ) ); mYMinLineEdit->setText( QString::number( composerMapExtent.yMinimum(), 'f', 3 ) ); mYMaxLineEdit->setText( QString::number( composerMapExtent.yMaximum(), 'f', 3 ) ); mRotationSpinBox->setValue( mComposerMap->rotation() ); //keep layer list check box if ( mComposerMap->keepLayerSet() ) { mKeepLayerListCheckBox->setCheckState( Qt::Checked ); } else { mKeepLayerListCheckBox->setCheckState( Qt::Unchecked ); } //draw canvas items if ( mComposerMap->drawCanvasItems() ) { mDrawCanvasItemsCheckBox->setCheckState( Qt::Checked ); } else { mDrawCanvasItemsCheckBox->setCheckState( Qt::Unchecked ); } //overview frame int overviewMapFrameId = mComposerMap->overviewFrameMapId(); mOverviewFrameMapComboBox->setCurrentIndex( mOverviewFrameMapComboBox->findData( overviewMapFrameId ) ); //grid if ( mComposerMap->gridEnabled() ) { mGridCheckBox->setChecked( true ); } else { mGridCheckBox->setChecked( false ); } mIntervalXSpinBox->setValue( mComposerMap->gridIntervalX() ); mIntervalYSpinBox->setValue( mComposerMap->gridIntervalY() ); mOffsetXSpinBox->setValue( mComposerMap->gridOffsetX() ); mOffsetYSpinBox->setValue( mComposerMap->gridOffsetY() ); QgsComposerMap::GridStyle gridStyle = mComposerMap->gridStyle(); if ( gridStyle == QgsComposerMap::Cross ) { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Cross" ) ) ); } else { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Solid" ) ) ); } mCrossWidthSpinBox->setValue( mComposerMap->crossLength() ); //grid frame mFrameWidthSpinBox->setValue( mComposerMap->gridFrameWidth() ); QgsComposerMap::GridFrameStyle gridFrameStyle = mComposerMap->gridFrameStyle(); if ( gridFrameStyle == QgsComposerMap::Zebra ) { mFrameStyleComboBox->setCurrentIndex( mFrameStyleComboBox->findText( tr( "Zebra" ) ) ); } else //NoGridFrame { mFrameStyleComboBox->setCurrentIndex( mFrameStyleComboBox->findText( tr( "No frame" ) ) ); } //grid annotation position initAnnotationPositionBox( mAnnotationPositionLeftComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Left ) ); initAnnotationPositionBox( mAnnotationPositionRightComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Right ) ); initAnnotationPositionBox( mAnnotationPositionTopComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Top ) ); initAnnotationPositionBox( mAnnotationPositionBottomComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Bottom ) ); //grid annotation direction initAnnotationDirectionBox( mAnnotationDirectionComboBoxLeft, mComposerMap->gridAnnotationDirection( QgsComposerMap::Left ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxRight, mComposerMap->gridAnnotationDirection( QgsComposerMap::Right ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxTop, mComposerMap->gridAnnotationDirection( QgsComposerMap::Top ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxBottom, mComposerMap->gridAnnotationDirection( QgsComposerMap::Bottom ) ); mDistanceToMapFrameSpinBox->setValue( mComposerMap->annotationFrameDistance() ); if ( mComposerMap->showGridAnnotation() ) { mDrawAnnotationCheckBox->setCheckState( Qt::Checked ); } else { mDrawAnnotationCheckBox->setCheckState( Qt::Unchecked ); } mCoordinatePrecisionSpinBox->setValue( mComposerMap->gridAnnotationPrecision() ); QPen gridPen = mComposerMap->gridPen(); mLineWidthSpinBox->setValue( gridPen.widthF() ); mLineColorButton->setColor( gridPen.color() ); blockAllSignals( false ); } }
void QgsComposerMapWidget::updateGuiElements() { if ( mComposerMap ) { blockAllSignals( true ); //width, height, scale // QRectF composerMapRect = mComposerMap->rect(); mScaleLineEdit->setText( QString::number( mComposerMap->scale(), 'f', 0 ) ); //preview mode QgsComposerMap::PreviewMode previewMode = mComposerMap->previewMode(); int index = -1; if ( previewMode == QgsComposerMap::Cache ) { index = mPreviewModeComboBox->findText( tr( "Cache" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Render ) { index = mPreviewModeComboBox->findText( tr( "Render" ) ); mUpdatePreviewButton->setEnabled( true ); } else if ( previewMode == QgsComposerMap::Rectangle ) { index = mPreviewModeComboBox->findText( tr( "Rectangle" ) ); mUpdatePreviewButton->setEnabled( false ); } if ( index != -1 ) { mPreviewModeComboBox->setCurrentIndex( index ); } //composer map extent QgsRectangle composerMapExtent = *( mComposerMap->currentMapExtent() ); mXMinLineEdit->setText( QString::number( composerMapExtent.xMinimum(), 'f', 3 ) ); mXMaxLineEdit->setText( QString::number( composerMapExtent.xMaximum(), 'f', 3 ) ); mYMinLineEdit->setText( QString::number( composerMapExtent.yMinimum(), 'f', 3 ) ); mYMaxLineEdit->setText( QString::number( composerMapExtent.yMaximum(), 'f', 3 ) ); mMapRotationSpinBox->setValue( mComposerMap->mapRotation() ); //keep layer list check box if ( mComposerMap->keepLayerSet() ) { mKeepLayerListCheckBox->setCheckState( Qt::Checked ); } else { mKeepLayerListCheckBox->setCheckState( Qt::Unchecked ); } //draw canvas items if ( mComposerMap->drawCanvasItems() ) { mDrawCanvasItemsCheckBox->setCheckState( Qt::Checked ); } else { mDrawCanvasItemsCheckBox->setCheckState( Qt::Unchecked ); } //overview frame int overviewMapFrameId = mComposerMap->overviewFrameMapId(); mOverviewFrameMapComboBox->setCurrentIndex( mOverviewFrameMapComboBox->findData( overviewMapFrameId ) ); //overview frame blending mode mOverviewBlendModeComboBox->setBlendMode( mComposerMap->overviewBlendMode() ); //overview inverted mOverviewInvertCheckbox->setChecked( mComposerMap->overviewInverted() ); //center overview mOverviewCenterCheckbox->setChecked( mComposerMap->overviewCentered() ); //grid if ( mComposerMap->gridEnabled() ) { mGridCheckBox->setChecked( true ); } else { mGridCheckBox->setChecked( false ); } mIntervalXSpinBox->setValue( mComposerMap->gridIntervalX() ); mIntervalYSpinBox->setValue( mComposerMap->gridIntervalY() ); mOffsetXSpinBox->setValue( mComposerMap->gridOffsetX() ); mOffsetYSpinBox->setValue( mComposerMap->gridOffsetY() ); QgsComposerMap::GridStyle gridStyle = mComposerMap->gridStyle(); if ( gridStyle == QgsComposerMap::Cross ) { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Cross" ) ) ); } else { mGridTypeComboBox->setCurrentIndex( mGridTypeComboBox->findText( tr( "Solid" ) ) ); } mCrossWidthSpinBox->setValue( mComposerMap->crossLength() ); //grid frame mFrameWidthSpinBox->setValue( mComposerMap->gridFrameWidth() ); mGridFramePenSizeSpinBox->setValue( mComposerMap->gridFramePenSize() ); mGridFramePenColorButton->setColor( mComposerMap->gridFramePenColor() ); mGridFrameFill1ColorButton->setColor( mComposerMap->gridFrameFillColor1() ); mGridFrameFill2ColorButton->setColor( mComposerMap->gridFrameFillColor2() ); QgsComposerMap::GridFrameStyle gridFrameStyle = mComposerMap->gridFrameStyle(); if ( gridFrameStyle == QgsComposerMap::Zebra ) { mFrameStyleComboBox->setCurrentIndex( mFrameStyleComboBox->findText( tr( "Zebra" ) ) ); toggleFrameControls( true ); } else //NoGridFrame { mFrameStyleComboBox->setCurrentIndex( mFrameStyleComboBox->findText( tr( "No frame" ) ) ); toggleFrameControls( false ); } //grid blend mode mGridBlendComboBox->setBlendMode( mComposerMap->gridBlendMode() ); //grid annotation format QgsComposerMap::GridAnnotationFormat gf = mComposerMap->gridAnnotationFormat(); mAnnotationFormatComboBox->setCurrentIndex(( int )gf ); //grid annotation position initAnnotationPositionBox( mAnnotationPositionLeftComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Left ) ); initAnnotationPositionBox( mAnnotationPositionRightComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Right ) ); initAnnotationPositionBox( mAnnotationPositionTopComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Top ) ); initAnnotationPositionBox( mAnnotationPositionBottomComboBox, mComposerMap->gridAnnotationPosition( QgsComposerMap::Bottom ) ); //grid annotation direction initAnnotationDirectionBox( mAnnotationDirectionComboBoxLeft, mComposerMap->gridAnnotationDirection( QgsComposerMap::Left ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxRight, mComposerMap->gridAnnotationDirection( QgsComposerMap::Right ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxTop, mComposerMap->gridAnnotationDirection( QgsComposerMap::Top ) ); initAnnotationDirectionBox( mAnnotationDirectionComboBoxBottom, mComposerMap->gridAnnotationDirection( QgsComposerMap::Bottom ) ); mAnnotationFontColorButton->setColor( mComposerMap->annotationFontColor() ); mDistanceToMapFrameSpinBox->setValue( mComposerMap->annotationFrameDistance() ); if ( mComposerMap->showGridAnnotation() ) { mDrawAnnotationCheckableGroupBox->setChecked( true ); } else { mDrawAnnotationCheckableGroupBox->setChecked( false ); } mCoordinatePrecisionSpinBox->setValue( mComposerMap->gridAnnotationPrecision() ); //atlas controls mAtlasCheckBox->setChecked( mComposerMap->atlasDriven() ); mAtlasMarginSpinBox->setValue( static_cast<int>( mComposerMap->atlasMargin() * 100 ) ); if ( mComposerMap->atlasFixedScale() ) { mAtlasFixedScaleRadio->setChecked( true ); mAtlasMarginSpinBox->setEnabled( false ); } else { mAtlasMarginRadio->setChecked( true ); mAtlasMarginSpinBox->setEnabled( true ); } if ( !mComposerMap->atlasDriven() ) { mAtlasMarginSpinBox->setEnabled( false ); mAtlasMarginRadio->setEnabled( false ); mAtlasFixedScaleRadio->setEnabled( false ); } else { mAtlasFixedScaleRadio->setEnabled( true ); toggleAtlasMarginByLayerType(); } blockAllSignals( false ); } }
tileMatrixInfo calculateTileMatrixInfo( const QString &crsStr, const QgsProject *project ) { // Does the CRS have fixed tile matrices if ( fixedTileMatrixInfoMap.contains( crsStr ) ) return fixedTileMatrixInfoMap[crsStr]; // Does the CRS have already calculated tile matrices if ( calculatedTileMatrixInfoMap.contains( crsStr ) ) return calculatedTileMatrixInfoMap[crsStr]; tileMatrixInfo tmi; tmi.ref = crsStr; QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crsStr ); QgsCoordinateTransform crsTransform( wgs84, crs, project ); try { tmi.extent = crsTransform.transformBoundingBox( crs.bounds() ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ) } tmi.unit = crs.mapUnits(); tmi.hasAxisInverted = crs.hasAxisInverted(); // calculate tile matrix scale denominator double scaleDenominator = 0.0; int colRes = ( tmi.extent.xMaximum() - tmi.extent.xMinimum() ) / tileSize; int rowRes = ( tmi.extent.yMaximum() - tmi.extent.yMinimum() ) / tileSize; double UNIT_TO_M = QgsUnitTypes::fromUnitToUnitFactor( tmi.unit, QgsUnitTypes::DistanceMeters ); if ( colRes > rowRes ) scaleDenominator = std::ceil( colRes * UNIT_TO_M / POINTS_TO_M ); else scaleDenominator = std::ceil( rowRes * UNIT_TO_M / POINTS_TO_M ); // Update extent to get a square one QgsRectangle extent = tmi.extent; double res = POINTS_TO_M * scaleDenominator / UNIT_TO_M; int col = std::ceil( ( extent.xMaximum() - extent.xMinimum() ) / ( tileSize * res ) ); int row = std::ceil( ( extent.yMaximum() - extent.yMinimum() ) / ( tileSize * res ) ); if ( col > 1 || row > 1 ) { // Update scale if ( col > row ) { res = col * res; scaleDenominator = col * scaleDenominator; } else { res = row * res; scaleDenominator = row * scaleDenominator; } // set col and row to 1 for the square col = 1; row = 1; } // Calculate extent double left = ( extent.xMinimum() + ( extent.xMaximum() - extent.xMinimum() ) / 2.0 ) - ( col / 2.0 ) * ( tileSize * res ); double bottom = ( extent.yMinimum() + ( extent.yMaximum() - extent.yMinimum() ) / 2.0 ) - ( row / 2.0 ) * ( tileSize * res ); double right = ( extent.xMinimum() + ( extent.xMaximum() - extent.xMinimum() ) / 2.0 ) + ( col / 2.0 ) * ( tileSize * res ); double top = ( extent.yMinimum() + ( extent.yMaximum() - extent.yMinimum() ) / 2.0 ) + ( row / 2.0 ) * ( tileSize * res ); tmi.extent = QgsRectangle( left, bottom, right, top ); tmi.resolution = res; tmi.scaleDenominator = scaleDenominator; calculatedTileMatrixInfoMap[crsStr] = tmi; return tmi; }