|
Quantum GIS API Documentation
master-2bfffaa
|
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 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 fieldScale = sqrt( qAbs( f.attribute( symbol->scaleClassificationField() ).toDouble() ) ); 00125 } 00126 if ( symbol->rotationClassificationField() >= 0 ) 00127 { 00128 rotation = f.attribute( symbol->rotationClassificationField() ).toDouble(); 00129 } 00130 00131 QString oldName; 00132 00133 if ( symbol->symbolField() >= 0 ) 00134 { 00135 QString name = f.attribute( symbol->symbolField() ).toString(); 00136 oldName = symbol->pointSymbolName(); 00137 symbol->setNamedPointSymbol( name ); 00138 } 00139 00140 double scale = renderContext.scaleFactor(); 00141 00142 if ( symbol->pointSizeUnits() ) 00143 { 00144 scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); 00145 } 00146 00147 *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor, 00148 fieldScale, rotation, renderContext.rasterScaleFactor(), 00149 opacity ); 00150 if ( !oldName.isNull() ) 00151 { 00152 symbol->setNamedPointSymbol( oldName ); 00153 } 00154 } 00155 // Line, polygon 00156 else if ( mGeometryType != QGis::Point ) 00157 { 00158 if ( !selected ) 00159 { 00160 QPen pen = symbol->pen(); 00161 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00162 p->setPen( pen ); 00163 if ( mGeometryType == QGis::Polygon ) 00164 { 00165 QBrush brush = symbol->brush(); 00166 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00167 p->setBrush( brush ); 00168 } 00169 } 00170 else 00171 { 00172 QPen pen = symbol->pen(); 00173 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00174 if ( mGeometryType == QGis::Polygon ) 00175 { 00176 QBrush brush = symbol->brush(); 00177 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00178 brush.setColor( mSelectionColor ); 00179 p->setBrush( brush ); 00180 } 00181 else //don't draw outlines of polygons in selection color otherwise they appear merged 00182 { 00183 pen.setColor( mSelectionColor ); 00184 } 00185 p->setPen( pen ); 00186 } 00187 } 00188 } 00189 00190 QgsSymbol *QgsUniqueValueRenderer::symbolForFeature( const QgsFeature *f ) 00191 { 00192 //first find out the value 00193 QString value = f->attribute( mClassificationField ).toString(); 00194 00195 QMap<QString, QgsSymbol*>::iterator it = mSymbols.find( value ); 00196 if ( it == mSymbols.end() ) 00197 { 00198 it = mSymbols.find( QString::null ); 00199 } 00200 00201 if ( it == mSymbols.end() ) 00202 { 00203 return 0; 00204 } 00205 else 00206 { 00207 return it.value(); 00208 } 00209 } 00210 00211 int QgsUniqueValueRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl ) 00212 { 00213 mGeometryType = vl.geometryType(); 00214 QDomNode classnode = rnode.namedItem( "classificationfield" ); 00215 QString classificationField = classnode.toElement().text(); 00216 00217 QgsVectorDataProvider* theProvider = vl.dataProvider(); 00218 if ( !theProvider ) 00219 { 00220 return 1; 00221 } 00222 00223 int classificationId = vl.fieldNameIndex( classificationField ); 00224 if ( classificationId == -1 ) 00225 { 00226 //go on. Because with joins, it might be the joined layer is not loaded yet 00227 } 00228 setClassificationField( classificationId ); 00229 00230 QDomNode symbolnode = rnode.namedItem( "symbol" ); 00231 while ( !symbolnode.isNull() ) 00232 { 00233 QgsSymbol* msy = new QgsSymbol( mGeometryType ); 00234 msy->readXML( symbolnode, &vl ); 00235 insertValue( msy->lowerValue(), msy ); 00236 symbolnode = symbolnode.nextSibling(); 00237 } 00238 updateSymbolAttributes(); 00239 vl.setRenderer( this ); 00240 return 0; 00241 } 00242 00243 void QgsUniqueValueRenderer::clearValues() 00244 { 00245 for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00246 { 00247 delete it.value(); 00248 } 00249 mSymbols.clear(); 00250 updateSymbolAttributes(); 00251 } 00252 00253 void QgsUniqueValueRenderer::updateSymbolAttributes() 00254 { 00255 mSymbolAttributesDirty = false; 00256 00257 mSymbolAttributes.clear(); 00258 00259 QMap<QString, QgsSymbol*>::iterator it; 00260 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00261 { 00262 int rotationField = ( *it )->rotationClassificationField(); 00263 if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) ) 00264 { 00265 mSymbolAttributes.append( rotationField ); 00266 } 00267 int scaleField = ( *it )->scaleClassificationField(); 00268 if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) ) 00269 { 00270 mSymbolAttributes.append( scaleField ); 00271 } 00272 int symbolField = ( *it )->symbolField(); 00273 if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) ) 00274 { 00275 mSymbolAttributes.append( symbolField ); 00276 } 00277 } 00278 } 00279 00280 QString QgsUniqueValueRenderer::name() const 00281 { 00282 return "Unique Value"; 00283 } 00284 00285 QgsAttributeList QgsUniqueValueRenderer::classificationAttributes() const 00286 { 00287 QgsAttributeList list( mSymbolAttributes ); 00288 if ( ! list.contains( mClassificationField ) ) 00289 { 00290 list.append( mClassificationField ); 00291 } 00292 return list; 00293 } 00294 00295 bool QgsUniqueValueRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const 00296 { 00297 const QgsVectorDataProvider* theProvider = vl.dataProvider(); 00298 if ( !theProvider ) 00299 { 00300 return false; 00301 } 00302 00303 QString classificationFieldName; 00304 const QgsFields& fields = vl.pendingFields(); 00305 if ( mClassificationField >= 0 && mClassificationField < fields.count() ) 00306 { 00307 classificationFieldName = fields[ mClassificationField ].name(); 00308 } 00309 00310 bool returnval = true; 00311 QDomElement uniquevalue = document.createElement( "uniquevalue" ); 00312 layer_node.appendChild( uniquevalue ); 00313 QDomElement classificationfield = document.createElement( "classificationfield" ); 00314 QDomText classificationfieldtxt = document.createTextNode( classificationFieldName ); 00315 classificationfield.appendChild( classificationfieldtxt ); 00316 uniquevalue.appendChild( classificationfield ); 00317 for ( QMap<QString, QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00318 { 00319 if ( !( it.value()->writeXML( uniquevalue, document, &vl ) ) ) 00320 { 00321 returnval = false; 00322 } 00323 } 00324 return returnval; 00325 } 00326 00327 QgsRenderer* QgsUniqueValueRenderer::clone() const 00328 { 00329 QgsUniqueValueRenderer* r = new QgsUniqueValueRenderer( *this ); 00330 return r; 00331 }