Index: python/core/qgsvectorlayer.sip =================================================================== --- python/core/qgsvectorlayer.sip (revision 9474) +++ python/core/qgsvectorlayer.sip (working copy) @@ -301,7 +301,7 @@ /** \brief Draws the layer labels using coordinate transformation * \param scale size scale, applied to all values in pixels */ - void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale); + void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale, double rendererScale ); /** returns list of attributes */ QList pendingAllAttributesList(); Index: src/app/qgslabeldialog.cpp =================================================================== --- src/app/qgslabeldialog.cpp (revision 9475) +++ src/app/qgslabeldialog.cpp (working copy) @@ -54,6 +54,7 @@ void QgsLabelDialog::init( ) { QgsDebugMsg( "entering." ); + QgsLabelAttributes * myLabelAttributes = mLabel->layerAttributes(); //populate a string list with all the field names which will be used to set up the //data bound combos @@ -133,6 +134,10 @@ cboAngleField->addItems( myFieldStringList ); cboAngleField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Angle ), myFieldStringList ) ); + // set up the scale based layer visibility stuff.... + chkUseScaleDependentRendering->setChecked( mLabel->scaleBasedVisibility() ); + spinMinimumScale->setValue(( int )mLabel->minScale() ); + spinMaximumScale->setValue(( int )mLabel->maxScale() ); // //set the non-databound fields up now @@ -197,7 +202,16 @@ spinXOffset->setValue( 0 ); spinYOffset->setValue( 0 ); } - spinAngle->setValue( static_cast( myLabelAttributes->angle() ) ); + spinAngle->setRange( -1, 360 ); + spinAngle->setSpecialValueText( tr("Auto") ); + if( myLabelAttributes->angleIsAuto() ) + { + spinAngle->setValue( -1 ); + } + else + { + spinAngle->setValue( static_cast( myLabelAttributes->angle() ) ); + } //the values here may seem a bit counterintuitive - basically everything //is the reverse of the way you think it should be... @@ -242,6 +256,7 @@ spinBufferSize->setValue( static_cast( myLabelAttributes->bufferSize() ) ); //TODO - transparency attributes for buffers + listWidget->setItemSelected( listWidget->item(0), true); } @@ -335,8 +350,9 @@ myTypeInt = QgsLabelAttributes::MapUnits; } myLabelAttributes->setOffset( spinXOffset->value(), spinYOffset->value(), myTypeInt ); + myLabelAttributes->setAutoAngle( spinAngle->value() == -1 ); myLabelAttributes->setAngle( spinAngle->value() ); - + //the values here may seem a bit counterintuitive - basically everything //is the reverse of the way you think it should be... //TODO investigate in QgsLabel why this needs to be the case @@ -382,6 +398,10 @@ mLabel->setLabelField( QgsLabel::Alignment, fieldIndexFromName( cboAlignmentField->currentText() ) ); mLabel->setLabelField( QgsLabel::Angle, fieldIndexFromName( cboAngleField->currentText() ) ); + // set up the scale based layer visibility stuff.... + mLabel->setScaleBasedVisibility( chkUseScaleDependentRendering->isChecked() ); + mLabel->setMinScale( spinMinimumScale->value() ); + mLabel->setMaxScale( spinMaximumScale->value() ); } int QgsLabelDialog::fieldIndexFromName( QString name ) Index: src/core/qgslabelattributes.cpp =================================================================== --- src/core/qgslabelattributes.cpp (revision 9475) +++ src/core/qgslabelattributes.cpp (working copy) @@ -41,6 +41,7 @@ mOffsetIsSet( false ), mAngle( 0.0 ), mAngleIsSet( false ), + mAngleIsAuto( false ), mAlignment( 0 ), mAlignmentIsSet( false ), mBufferEnabledFlag( false ), @@ -69,6 +70,7 @@ setOffset( 0, 0, PointUnits ); setAngle( 0 ); + setAutoAngle(false); setAlignment( Qt::AlignCenter ); setColor( QColor( 0, 0, 0 ) ); @@ -150,6 +152,16 @@ return mAngle; } +bool QgsLabelAttributes::angleIsAuto() const +{ + return mAngleIsAuto; +} + +void QgsLabelAttributes::setAutoAngle ( bool state ) +{ + mAngleIsAuto = state; +} + /* Alignment */ void QgsLabelAttributes::setAlignment( int alignment ) { Index: src/core/qgsvectorlayer.cpp =================================================================== --- src/core/qgsvectorlayer.cpp (revision 9475) +++ src/core/qgsvectorlayer.cpp (working copy) @@ -286,17 +286,19 @@ { return; } - drawLabels( thePainter, rendererContext.extent(), &( rendererContext.mapToPixel() ), rendererContext.coordinateTransform(), rendererContext.scaleFactor() ); + drawLabels( thePainter, rendererContext.extent(), &( rendererContext.mapToPixel() ), rendererContext.coordinateTransform(), rendererContext.scaleFactor(), rendererContext.rendererScale() ); } // NOTE this is a temporary method added by Tim to prevent label clipping // which was occurring when labeller was called in the main draw loop // This method will probably be removed again in the near future! -void QgsVectorLayer::drawLabels( QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* theMapToPixelTransform, const QgsCoordinateTransform* ct, double scale ) +void QgsVectorLayer::drawLabels( QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* theMapToPixelTransform, const QgsCoordinateTransform* ct, double scale, double rendererScale ) { QgsDebugMsg( "Starting draw of labels" ); - if ( mRenderer && mLabelOn ) + if ( mRenderer && mLabelOn && + (!label()->scaleBasedVisibility() || + (label()->minScale()<=rendererScale && rendererScale<=label()->maxScale())) ) { QgsAttributeList attributes = mRenderer->classificationAttributes(); @@ -1967,8 +1969,6 @@ return mLabelOn; } - - bool QgsVectorLayer::startEditing() { if ( !mDataProvider ) @@ -2057,6 +2057,12 @@ setDisplayField( e.text() ); } + // use scale dependent visibility flag + QDomElement e = layer_node.toElement(); + label()->setScaleBasedVisibility( e.attribute( "scaleBasedLabelVisibilityFlag", "0") == "1" ); + label()->setMinScale( e.attribute( "minLabelScale", "1" ).toFloat() ); + label()->setMaxScale( e.attribute( "maxLabelScale", "100000000" ).toFloat() ); + QDomNode editTypesNode = layer_node.namedItem( "edittypes" ); if ( !editTypesNode.isNull() ) { @@ -2224,7 +2230,7 @@ if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) ) { - qDebug( "QgsVectorLayer::writeXML() can't find " ); + QgsDebugMsg( "can't find " ); return false; } @@ -2233,6 +2239,11 @@ // set the geometry type mapLayerNode.setAttribute( "geometry", QGis::qgisVectorGeometryType[type()] ); + // use scale dependent visibility flag + mapLayerNode.setAttribute( "scaleBasedLabelVisibilityFlag", label()->scaleBasedVisibility() ? 1 : 0 ); + mapLayerNode.setAttribute( "minLabelScale", label()->minScale() ); + mapLayerNode.setAttribute( "maxLabelScale", label()->maxScale() ); + // add provider node QDomElement provider = document.createElement( "provider" ); @@ -2353,54 +2364,7 @@ layer_node.appendChild( dField ); } - std::stringstream labelXML; - - myLabel->writeXML( labelXML ); - - QDomDocument labelDom; - - std::string rawXML; - std::string temp_str; - QString errorMsg; - int errorLine; - int errorColumn; - - // start with bogus XML header - rawXML = "\n"; - - temp_str = labelXML.str(); - - rawXML += temp_str; - -#ifdef QGISDEBUG - std::cout << rawXML << std::endl << std::flush; // OK - -#endif - const char * s = rawXML.c_str(); // debugger probe - // Use the const char * form of the xml to make non-stl qt happy - if ( ! labelDom.setContent( QString::fromUtf8( s ), &errorMsg, &errorLine, &errorColumn ) ) - { - qDebug(( "XML import error at line %d column %d " + errorMsg ).toLocal8Bit().data(), errorLine, errorColumn ); - - return false; - } - - // lastChild() because the first two nodes are the and - // nodes; the label node follows that, and is (hopefully) - // the last node. - QDomNode labelDomNode = document.importNode( labelDom.lastChild(), true ); - - if ( ! labelDomNode.isNull() ) - { - layer_node.appendChild( labelDomNode ); - } - else - { - qDebug( "not able to import label Dom node" ); - - // XXX return false? - } - + myLabel->writeXML( layer_node, document ); } return true; @@ -3533,3 +3497,4 @@ return mRanges[ fields[idx].name()]; } + Index: src/core/qgsrendercontext.h =================================================================== --- src/core/qgsrendercontext.h (revision 9475) +++ src/core/qgsrendercontext.h (working copy) @@ -56,6 +56,8 @@ bool drawEditingInformation() const {return mDrawEditingInformation;} + double rendererScale() const {return mRendererScale;} + //setters /**Sets coordinate transformation. QgsRenderContext takes ownership and deletes if necessary*/ @@ -66,6 +68,7 @@ void setRenderingStopped( bool stopped ) {mRenderingStopped = stopped;} void setScaleFactor( double factor ) {mScaleFactor = factor;} void setRasterScaleFactor( double factor ) {mRasterScaleFactor = factor;} + void setRendererScale( double scale ) {mRendererScale = scale;} void setPainter( QPainter* p ) {mPainter = p;} private: @@ -94,6 +97,9 @@ /**Factor to scale rasters*/ double mRasterScaleFactor; + + /** renderer scale */ + double mRendererScale; }; #endif Index: src/core/qgsvectorlayer.h =================================================================== --- src/core/qgsvectorlayer.h (revision 9475) +++ src/core/qgsvectorlayer.h (working copy) @@ -363,7 +363,8 @@ void drawLabels( QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, - double scale ); + double scale, + double rendererScale ); /** returns field list in the to-be-committed state */ const QgsFieldMap &pendingFields(); Index: src/core/qgsmaprenderer.cpp =================================================================== --- src/core/qgsmaprenderer.cpp (revision 9475) +++ src/core/qgsmaprenderer.cpp (working copy) @@ -69,7 +69,6 @@ void QgsMapRenderer::updateScale() { - mScale = mScaleCalculator->calculate( mExtent, mSize.width() ); } @@ -248,6 +247,7 @@ double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi; mRenderContext.setScaleFactor( scaleFactor ); mRenderContext.setRasterScaleFactor( rasterScaleFactor ); + mRenderContext.setRendererScale( mScale ); // render all layers in the stack, starting at the base QListIterator li( mLayerSet ); @@ -289,8 +289,7 @@ QgsDebugMsg( " Scale dep. visibility enabled? " + QString( "%1" ).arg( ml->scaleBasedVisibility() ) ); QgsDebugMsg( " Input extent: " + ml->extent().toString() ); - if (( ml->scaleBasedVisibility() && ml->minScale() < mScale && ml->maxScale() > mScale ) - || ( !ml->scaleBasedVisibility() ) ) + if ( !ml->scaleBasedVisibility() || (ml->minScale() < mScale && mScale < ml->maxScale() ) ) { connect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) ); @@ -390,8 +389,7 @@ { // only make labels if the layer is visible // after scale dep viewing settings are checked - if (( ml->scaleBasedVisibility() && ml->minScale() < mScale && ml->maxScale() > mScale ) - || ( !ml->scaleBasedVisibility() ) ) + if ( !ml->scaleBasedVisibility() || (ml->minScale() < mScale && mScale < ml->maxScale() )) { bool split = false; Index: src/core/qgslabel.cpp =================================================================== --- src/core/qgslabel.cpp (revision 9475) +++ src/core/qgslabel.cpp (working copy) @@ -47,6 +47,9 @@ "$Id$"; QgsLabel::QgsLabel( const QgsFieldMap & fields ) +: mMinScale(0 ), + mMaxScale(100000000), + mScaleBasedVisibility(false) { mField = fields; mLabelFieldIdx.resize( LabelFieldCount ); @@ -353,13 +356,13 @@ } else { - std::vector points; + std::vector points; labelPoint( points, feature ); for ( uint i = 0; i < points.size(); ++i ) { - renderLabel( painter, points[i], coordinateTransform, + renderLabel( painter, points[i].p, coordinateTransform, transform, text, font, pen, dx, dy, - xoffset, yoffset, ang, width, height, alignment, sizeScale ); + xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment, sizeScale ); } } } @@ -393,7 +396,7 @@ double x = point.x(); double y = point.y(); - static const double rad = ang * M_PI / 180; + double rad = ang * M_PI / 180; x = x + xoffset * cos( rad ) - yoffset * sin( rad ); y = y - xoffset * sin( rad ) - yoffset * cos( rad ); @@ -504,13 +507,13 @@ return mLabelAttributes; } -void QgsLabel::labelPoint( std::vector& points, QgsFeature & feature ) +void QgsLabel::labelPoint( std::vector& points, QgsFeature & feature ) { QgsGeometry *geometry = feature.geometry(); unsigned char *geom = geometry->wkbBuffer(); size_t geomlen = geometry->wkbSize(); QGis::WkbType wkbType = geometry->wkbType(); - QgsPoint point; + labelpoint point; switch ( wkbType ) { @@ -552,7 +555,7 @@ } } -unsigned char* QgsLabel::labelPoint( QgsPoint& point, unsigned char *geom, size_t geomlen ) +unsigned char* QgsLabel::labelPoint( labelpoint& point, unsigned char *geom, size_t geomlen ) { // verify that local types match sizes as WKB spec Q_ASSERT( sizeof( int ) == 4 ); @@ -584,7 +587,8 @@ { Q_ASSERT( geom + 2*sizeof( double ) <= geomend ); double *pts = ( double * )geom; - point.set( pts[0], pts[1] ); + point.p.set( pts[0], pts[1] ); + point.angle = 0.0; geom += 2 * sizeof( double ); } break; @@ -622,8 +626,9 @@ { double k = ( tl - l ) / dl; - point.set( pts[dims*( i-1 )] + k * dx, - pts[dims*( i-1 )+1] + k * dy ); + point.p.set( pts[dims*( i-1 )] + k * dx, + pts[dims*( i-1 )+1] + k * dy ); + point.angle = atan2(dy,dx)*180.0*M_1_PI; break; } @@ -659,8 +664,9 @@ sx += pts[dims*j]; sy += pts[dims*j+1]; } - point.set( sx / ( nPoints - 1 ), - sy / ( nPoints - 1 ) ); + point.p.set( sx / ( nPoints - 1 ), + sy / ( nPoints - 1 ) ); + point.angle = 0.0; } geom += nPoints * sizeof( double ) * dims; @@ -871,6 +877,7 @@ el = scratchNode.toElement(); mLabelAttributes->setAngle( el.attribute( "value", "0.0" ).toDouble() ); setLabelField( Angle, _elementFieldIndex( el ) ); + mLabelAttributes->setAutoAngle( el.attribute( "auto", "0" )=="1" ); } /* Alignment */ @@ -954,298 +961,351 @@ -void QgsLabel::writeXML( std::ostream& xml ) +void QgsLabel::writeXML( QDomNode & layer_node, + QDomDocument & document ) { + QDomElement labelattributes = document.createElement( "labelattributes" ); - xml << "\t\t\n"; - // Text - if ( mLabelAttributes->textIsSet() ) + QDomElement label = document.createElement( "label" ); + label.setAttribute("text", mLabelAttributes->text() ); + if ( mLabelAttributes->textIsSet() && mLabelFieldIdx[Text] != -1 ) { - if ( mLabelFieldIdx[Text] != -1 ) - { - xml << "\t\t\t\n"; + layer_node.appendChild(labelattributes); } +void QgsLabel::setScaleBasedVisibility( bool theVisibilityFlag ) +{ + mScaleBasedVisibility = theVisibilityFlag; +} + +bool QgsLabel::scaleBasedVisibility() +{ + return mScaleBasedVisibility; +} + +void QgsLabel::setMinScale( float theMinScale ) +{ + mMinScale = theMinScale; +} + +float QgsLabel::minScale() +{ + return mMinScale; +} + +void QgsLabel::setMaxScale( float theMaxScale ) +{ + mMaxScale = theMaxScale; +} + +float QgsLabel::maxScale() +{ + return mMaxScale; +} Index: src/core/qgslabel.h =================================================================== --- src/core/qgslabel.h (revision 9475) +++ src/core/qgslabel.h (working copy) @@ -23,12 +23,14 @@ #include #include +#include "qgspoint.h" + class QDomNode; +class QDomDocument; class QString; class QPainter; class QPaintDevice; -class QgsPoint; class QgsFeature; class QgsField; class QgsLabelAttributes; @@ -82,6 +84,11 @@ LabelFieldCount }; + struct labelpoint { + QgsPoint p; + double angle; + }; + /** \brief render label * \param sizeScale global scale factor for size in pixels, labels in map units are not scaled */ @@ -96,7 +103,7 @@ void readXML( const QDomNode& node ); /** Writes the contents of the renderer to a configuration file */ - void writeXML( std::ostream& xml ); + void writeXML( QDomNode & label_node, QDomDocument & document ); //! add vector of required fields to existing list of fields void addRequiredFields( QgsAttributeList& fields ); @@ -123,6 +130,18 @@ */ QString fieldValue( int attr, QgsFeature& feature ); + /** Accessor and mutator for the minimum scale member */ + void setMinScale( float theMinScale ); + float minScale(); + + /** Accessor and mutator for the maximum scale member */ + void setMaxScale( float theMaxScale ); + float maxScale(); + + /** Accessor and mutator for the scale based visilibility flag */ + void setScaleBasedVisibility( bool theVisibilityFlag ); + bool scaleBasedVisibility(); + private: /** Does the actual rendering of a label at the given point * @@ -137,10 +156,10 @@ int width, int height, int alignment, double sizeScale = 1.0 ); /** Get label point for simple feature in map units */ - void labelPoint( std::vector&, QgsFeature &feature ); + void labelPoint( std::vector&, QgsFeature &feature ); /** Get label point for the given feature in wkb format. */ - unsigned char* labelPoint( QgsPoint& point, unsigned char* wkb, size_t wkblen ); + unsigned char* labelPoint( labelpoint& point, unsigned char* wkb, size_t wkblen ); /** Color to draw selected features */ QColor mSelectionColor; @@ -156,6 +175,13 @@ //! Label field indexes std::vector mLabelFieldIdx; + + /** Minimum scale at which this label should be displayed */ + float mMinScale; + /** Maximum scale at which this label should be displayed */ + float mMaxScale; + /** A flag that tells us whether to use the above vars to restrict the label's visibility */ + bool mScaleBasedVisibility; }; #endif Index: src/core/qgslabelattributes.h =================================================================== --- src/core/qgslabelattributes.h (revision 9475) +++ src/core/qgslabelattributes.h (working copy) @@ -140,6 +140,9 @@ bool angleIsSet( void ) const; double angle( void ) const; + bool angleIsAuto( void ) const; + void setAutoAngle(bool state); + /* Alignment */ void setAlignment( int alignment ); bool alignmentIsSet( void ) const; @@ -207,6 +210,7 @@ /** Angle (degrees) */ double mAngle; bool mAngleIsSet; + bool mAngleIsAuto; /** Alignment */ int mAlignment; Index: src/ui/qgslabeldialogbase.ui =================================================================== --- src/ui/qgslabeldialogbase.ui (revision 9475) +++ src/ui/qgslabeldialogbase.ui (working copy) @@ -6,7 +6,7 @@ 0 0 516 - 447 + 487 @@ -19,18 +19,9 @@ Form1 - + 0 - - 0 - - - 0 - - - 0 - @@ -91,7 +82,7 @@ - Font + General @@ -135,9 +126,17 @@ - 1 + 0 + + + 0 + 0 + 309 + 394 + + @@ -236,18 +235,9 @@ Placement - + 11 - - 11 - - - 11 - - - 11 - @@ -345,7 +335,7 @@ Qt::Vertical - + 20 40 @@ -353,9 +343,88 @@ + + + + Use scale dependent rendering + + + true + + + + 11 + + + + + Maximum + + + spinMaximumScale + + + + + + + Minimum + + + spinMinimumScale + + + + + + + Minimum scale at which this layer will be displayed. + + + 1 + + + 100000000 + + + + + + + Maximum scale at which this layer will be displayed. + + + 1 + + + 100000000 + + + + + + + + + + Multiline labels? + + + true + + + + + + 0 + 0 + 309 + 394 + + @@ -449,21 +518,11 @@ - - - Multiline labels? - - - true - - - - Qt::Vertical - + 20 40 @@ -474,6 +533,14 @@ + + + 0 + 0 + 100 + 30 + + @@ -531,7 +598,7 @@ Qt::Vertical - + 20 181 @@ -542,6 +609,14 @@ + + + 0 + 0 + 100 + 30 + + @@ -728,6 +803,14 @@ + + + 0 + 0 + 100 + 30 + + @@ -764,6 +847,14 @@ + + + 0 + 0 + 100 + 30 + + @@ -819,6 +910,14 @@ + + + 0 + 0 + 100 + 30 + + @@ -900,18 +999,9 @@ Preview: - + 11 - - 11 - - - 11 - - - 11 -