Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsuniquevaluerenderer.cpp - description 00003 ------------------- 00004 begin : July 2004 00005 copyright : (C) 2004 by Marco Hugentobler 00006 email : [email protected] 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgsuniquevaluerenderer.h" 00019 #include "qgsfeature.h" 00020 #include "qgsvectordataprovider.h" 00021 #include "qgsvectorlayer.h" 00022 #include "qgsrendercontext.h" 00023 #include "qgssymbol.h" 00024 #include "qgssymbologyutils.h" 00025 #include "qgslogger.h" 00026 #include <cmath> 00027 #include <QDomNode> 00028 #include <QPainter> 00029 #include <QImage> 00030 #include <vector> 00031 00032 QgsUniqueValueRenderer::QgsUniqueValueRenderer( QGis::GeometryType type ): mClassificationField( 0 ) 00033 { 00034 mGeometryType = type; 00035 mSymbolAttributesDirty = false; 00036 } 00037 00038 QgsUniqueValueRenderer::QgsUniqueValueRenderer( const QgsUniqueValueRenderer& other ) 00039 { 00040 mGeometryType = other.mGeometryType; 00041 mClassificationField = other.mClassificationField; 00042 QMap<QString, QgsSymbol*> s = other.mSymbols; 00043 for ( QMap<QString, QgsSymbol*>::iterator it = s.begin(); it != s.end(); ++it ) 00044 { 00045 QgsSymbol* s = new QgsSymbol( * it.value() ); 00046 insertValue( it.key(), s ); 00047 } 00048 updateSymbolAttributes(); 00049 } 00050 00051 QgsUniqueValueRenderer& QgsUniqueValueRenderer::operator=( const QgsUniqueValueRenderer & other ) 00052 { 00053 if ( this != &other ) 00054 { 00055 mGeometryType = other.mGeometryType; 00056 mClassificationField = other.mClassificationField; 00057 clearValues(); 00058 for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00059 { 00060 QgsSymbol* s = new QgsSymbol( *it.value() ); 00061 insertValue( it.key(), s ); 00062 } 00063 updateSymbolAttributes(); 00064 } 00065 return *this; 00066 } 00067 00068 QgsUniqueValueRenderer::~QgsUniqueValueRenderer() 00069 { 00070 for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00071 { 00072 delete it.value(); 00073 } 00074 } 00075 00076 void QgsUniqueValueRenderer::insertValue( QString name, QgsSymbol* symbol ) 00077 { 00078 mSymbols.insert( name, symbol ); 00079 mSymbolAttributesDirty = true; 00080 } 00081 00082 void QgsUniqueValueRenderer::setClassificationField( int field ) 00083 { 00084 mClassificationField = field; 00085 } 00086 00087 int QgsUniqueValueRenderer::classificationField() const 00088 { 00089 return mClassificationField; 00090 } 00091 00092 bool QgsUniqueValueRenderer::willRenderFeature( QgsFeature *f ) 00093 { 00094 return ( symbolForFeature( f ) != 0 ); 00095 } 00096 00097 void QgsUniqueValueRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* img, bool selected, double opacity ) 00098 { 00099 QPainter *p = renderContext.painter(); 00100 QgsSymbol* symbol = symbolForFeature( &f ); 00101 if ( !symbol ) //no matching symbol 00102 { 00103 if ( img && mGeometryType == QGis::Point ) 00104 { 00105 img->fill( 0 ); 00106 } 00107 else if ( mGeometryType != QGis::Point ) 00108 { 00109 p->setPen( Qt::NoPen ); 00110 p->setBrush( Qt::NoBrush ); 00111 } 00112 return; 00113 } 00114 00115 // Point 00116 if ( img && mGeometryType == QGis::Point ) 00117 { 00118 double fieldScale = 1.0; 00119 double rotation = 0.0; 00120 00121 if ( symbol->scaleClassificationField() >= 0 ) 00122 { 00123 //first find out the value for the scale classification attribute 00124 const QgsAttributeMap& attrs = f.attributeMap(); 00125 fieldScale = sqrt( qAbs( attrs[symbol->scaleClassificationField()].toDouble() ) ); 00126 } 00127 if ( symbol->rotationClassificationField() >= 0 ) 00128 { 00129 const QgsAttributeMap& attrs = f.attributeMap(); 00130 rotation = attrs[symbol->rotationClassificationField()].toDouble(); 00131 } 00132 00133 QString oldName; 00134 00135 if ( symbol->symbolField() >= 0 ) 00136 { 00137 const QgsAttributeMap& attrs = f.attributeMap(); 00138 QString name = attrs[symbol->symbolField()].toString(); 00139 oldName = symbol->pointSymbolName(); 00140 symbol->setNamedPointSymbol( name ); 00141 } 00142 00143 double scale = renderContext.scaleFactor(); 00144 00145 if ( symbol->pointSizeUnits() ) 00146 { 00147 scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); 00148 } 00149 00150 *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor, 00151 fieldScale, rotation, renderContext.rasterScaleFactor(), 00152 opacity ); 00153 if ( !oldName.isNull() ) 00154 { 00155 symbol->setNamedPointSymbol( oldName ); 00156 } 00157 } 00158 // Line, polygon 00159 else if ( mGeometryType != QGis::Point ) 00160 { 00161 if ( !selected ) 00162 { 00163 QPen pen = symbol->pen(); 00164 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00165 p->setPen( pen ); 00166 if ( mGeometryType == QGis::Polygon ) 00167 { 00168 QBrush brush = symbol->brush(); 00169 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00170 p->setBrush( brush ); 00171 } 00172 } 00173 else 00174 { 00175 QPen pen = symbol->pen(); 00176 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00177 if ( mGeometryType == QGis::Polygon ) 00178 { 00179 QBrush brush = symbol->brush(); 00180 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00181 brush.setColor( mSelectionColor ); 00182 p->setBrush( brush ); 00183 } 00184 else //don't draw outlines of polygons in selection color otherwise they appear merged 00185 { 00186 pen.setColor( mSelectionColor ); 00187 } 00188 p->setPen( pen ); 00189 } 00190 } 00191 } 00192 00193 QgsSymbol *QgsUniqueValueRenderer::symbolForFeature( const QgsFeature *f ) 00194 { 00195 //first find out the value 00196 const QgsAttributeMap& attrs = f->attributeMap(); 00197 QString value = attrs[mClassificationField].toString(); 00198 00199 QMap<QString, QgsSymbol*>::iterator it = mSymbols.find( value ); 00200 if ( it == mSymbols.end() ) 00201 { 00202 it = mSymbols.find( QString::null ); 00203 } 00204 00205 if ( it == mSymbols.end() ) 00206 { 00207 return 0; 00208 } 00209 else 00210 { 00211 return it.value(); 00212 } 00213 } 00214 00215 int QgsUniqueValueRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl ) 00216 { 00217 mGeometryType = vl.geometryType(); 00218 QDomNode classnode = rnode.namedItem( "classificationfield" ); 00219 QString classificationField = classnode.toElement().text(); 00220 00221 QgsVectorDataProvider* theProvider = vl.dataProvider(); 00222 if ( !theProvider ) 00223 { 00224 return 1; 00225 } 00226 00227 int classificationId = theProvider->fieldNameIndex( classificationField ); 00228 if ( classificationId == -1 ) 00229 { 00230 //go on. Because with joins, it might be the joined layer is not loaded yet 00231 } 00232 setClassificationField( classificationId ); 00233 00234 QDomNode symbolnode = rnode.namedItem( "symbol" ); 00235 while ( !symbolnode.isNull() ) 00236 { 00237 QgsSymbol* msy = new QgsSymbol( mGeometryType ); 00238 msy->readXML( symbolnode, &vl ); 00239 insertValue( msy->lowerValue(), msy ); 00240 symbolnode = symbolnode.nextSibling(); 00241 } 00242 updateSymbolAttributes(); 00243 vl.setRenderer( this ); 00244 return 0; 00245 } 00246 00247 void QgsUniqueValueRenderer::clearValues() 00248 { 00249 for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00250 { 00251 delete it.value(); 00252 } 00253 mSymbols.clear(); 00254 updateSymbolAttributes(); 00255 } 00256 00257 void QgsUniqueValueRenderer::updateSymbolAttributes() 00258 { 00259 mSymbolAttributesDirty = false; 00260 00261 mSymbolAttributes.clear(); 00262 00263 QMap<QString, QgsSymbol*>::iterator it; 00264 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00265 { 00266 int rotationField = ( *it )->rotationClassificationField(); 00267 if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) ) 00268 { 00269 mSymbolAttributes.append( rotationField ); 00270 } 00271 int scaleField = ( *it )->scaleClassificationField(); 00272 if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) ) 00273 { 00274 mSymbolAttributes.append( scaleField ); 00275 } 00276 int symbolField = ( *it )->symbolField(); 00277 if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) ) 00278 { 00279 mSymbolAttributes.append( symbolField ); 00280 } 00281 } 00282 } 00283 00284 QString QgsUniqueValueRenderer::name() const 00285 { 00286 return "Unique Value"; 00287 } 00288 00289 QgsAttributeList QgsUniqueValueRenderer::classificationAttributes() const 00290 { 00291 QgsAttributeList list( mSymbolAttributes ); 00292 if ( ! list.contains( mClassificationField ) ) 00293 { 00294 list.append( mClassificationField ); 00295 } 00296 return list; 00297 } 00298 00299 bool QgsUniqueValueRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const 00300 { 00301 const QgsVectorDataProvider* theProvider = vl.dataProvider(); 00302 if ( !theProvider ) 00303 { 00304 return false; 00305 } 00306 00307 QString classificationFieldName; 00308 QgsFieldMap::const_iterator field_it = theProvider->fields().find( mClassificationField ); 00309 if ( field_it != theProvider->fields().constEnd() ) 00310 { 00311 classificationFieldName = field_it.value().name(); 00312 } 00313 00314 bool returnval = true; 00315 QDomElement uniquevalue = document.createElement( "uniquevalue" ); 00316 layer_node.appendChild( uniquevalue ); 00317 QDomElement classificationfield = document.createElement( "classificationfield" ); 00318 QDomText classificationfieldtxt = document.createTextNode( classificationFieldName ); 00319 classificationfield.appendChild( classificationfieldtxt ); 00320 uniquevalue.appendChild( classificationfield ); 00321 for ( QMap<QString, QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00322 { 00323 if ( !( it.value()->writeXML( uniquevalue, document, &vl ) ) ) 00324 { 00325 returnval = false; 00326 } 00327 } 00328 return returnval; 00329 } 00330 00331 QgsRenderer* QgsUniqueValueRenderer::clone() const 00332 { 00333 QgsUniqueValueRenderer* r = new QgsUniqueValueRenderer( *this ); 00334 return r; 00335 }