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