Skip to content

Commit 3391f42

Browse files
committed
fix cpt-city svg parsing and display
1 parent 3b3f674 commit 3391f42

File tree

7 files changed

+151
-72
lines changed

7 files changed

+151
-72
lines changed

src/core/symbology-ng/qgssymbollayerv2utils.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,10 +490,12 @@ QIcon QgsSymbolLayerV2Utils::colorRampPreviewIcon( QgsVectorColorRampV2* ramp, Q
490490
QPixmap QgsSymbolLayerV2Utils::colorRampPreviewPixmap( QgsVectorColorRampV2* ramp, QSize size )
491491
{
492492
QPixmap pixmap( size );
493+
pixmap.fill( Qt::transparent );
494+
// pixmap.fill( Qt::white ); // this makes the background white instead of transparent
493495
QPainter painter;
494496
painter.begin( &pixmap );
495-
painter.setRenderHint( QPainter::Antialiasing );
496-
painter.eraseRect( QRect( QPoint( 0, 0 ), size ) );
497+
// antialising makes the colors duller, and no point in antialiasing a color ramp
498+
// painter.setRenderHint( QPainter::Antialiasing );
497499
for ( int i = 0; i < size.width(); i++ )
498500
{
499501
QPen pen( ramp->color(( double ) i / size.width() ) );

src/core/symbology-ng/qgsvectorcolorrampv2.cpp

Lines changed: 94 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ static QColor _interpolate( QColor c1, QColor c2, double value )
6060
int r = ( int )( c1.red() + value * ( c2.red() - c1.red() ) );
6161
int g = ( int )( c1.green() + value * ( c2.green() - c1.green() ) );
6262
int b = ( int )( c1.blue() + value * ( c2.blue() - c1.blue() ) );
63+
int a = ( int )( c1.alpha() + value * ( c2.alpha() - c1.alpha() ) );
6364

64-
return QColor::fromRgb( r, g, b );
65+
return QColor::fromRgb( r, g, b, a );
6566
}
6667

6768
QColor QgsVectorGradientColorRampV2::color( double value ) const
@@ -269,7 +270,7 @@ QMap< QString, QString > QgsCptCityColorRampV2::mCollectionNames;
269270
QMap< QString, QStringList > QgsCptCityColorRampV2::mCollectionSelections;
270271

271272
QgsCptCityColorRampV2::QgsCptCityColorRampV2( QString schemeName, QString variantName )
272-
: mSchemeName( schemeName ), mVariantName( variantName ), mContinuous( false )
273+
: mSchemeName( schemeName ), mVariantName( variantName ), mGradientType( Continuous )
273274
{
274275
// TODO replace this with hard-coded data in the default case
275276
loadFile();
@@ -289,7 +290,7 @@ QgsVectorColorRampV2* QgsCptCityColorRampV2::create( const QgsStringMap& props )
289290
}
290291

291292

292-
293+
#if 0
293294
QColor QgsCptCityColorRampV2::color( double value ) const
294295
{
295296
if ( mPalette.isEmpty() || value < 0 || value > 1 )
@@ -333,6 +334,45 @@ QColor QgsCptCityColorRampV2::color( double value ) const
333334
return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
334335
}
335336
}
337+
#endif
338+
339+
QColor QgsCptCityColorRampV2::color( double value ) const
340+
{
341+
if ( mPalette.isEmpty() || value < 0 || value > 1 )
342+
return QColor( 255, 0, 0 ); // red color as a warning :)
343+
344+
int numStops = mPalette.count();
345+
if ( numStops < 2 )
346+
return QColor( 255, 0, 0 ); // red color as a warning :)
347+
348+
double lower = 0, upper = 0;
349+
QColor c1, c2;
350+
c1 = mPalette[0].second;
351+
for ( int i = 0; i < numStops; i++ )
352+
{
353+
if ( mPalette[i].first >= value )
354+
{
355+
if ( mGradientType == Discrete )
356+
return c1;
357+
358+
upper = mPalette[i].first;
359+
c2 = mPalette[i].second;
360+
361+
return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
362+
}
363+
364+
lower = mPalette[i].first;
365+
c1 = mPalette[i].second;
366+
}
367+
368+
if ( mGradientType == Discrete )
369+
return c1;
370+
371+
upper = 1;
372+
c2 = mPalette[ numStops - 1 ].second;
373+
374+
return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
375+
}
336376

337377
QgsVectorColorRampV2* QgsCptCityColorRampV2::clone() const
338378
{
@@ -390,23 +430,6 @@ QStringList QgsCptCityColorRampV2::listSchemeNames( QString collectionName )
390430
return entries;
391431
}
392432

393-
QList<int> QgsCptCityColorRampV2::listSchemeVariants( QString schemeName )
394-
{
395-
QList<int> variants;
396-
397-
QString palette( brewerString );
398-
QStringList list = palette.split( QChar( '\n' ) );
399-
foreach ( QString entry, list )
400-
{
401-
QStringList items = entry.split( QChar( '-' ) );
402-
if ( items.count() != 3 || items[0] != schemeName )
403-
continue;
404-
variants << items[1].toInt();
405-
}
406-
407-
return variants;
408-
}
409-
410433
QString QgsCptCityColorRampV2::getBaseDir()
411434
{
412435
// currently hard-coded, but could be also in QGis install path and/or configurable
@@ -436,7 +459,6 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
436459
// QgsDebugMsg("filename= "+filename);
437460

438461
mPalette.clear();
439-
mPaletteStops.clear();
440462

441463
QString mErrorString = QString();
442464

@@ -478,40 +500,38 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
478500
return false;
479501
}
480502

481-
// initialize self
482-
mContinuous = true; // we will detect later if there are overlapping stops
483-
mPalette.clear();
484-
mPaletteStops.clear();
485-
486503
// loop for all stop tags
487504
QDomElement e = rampsElement.firstChildElement();
488-
// int i = 0;
489-
QMap< double, QColor > map;
505+
QMap< double, QPair<QColor, QColor> > map;
506+
507+
QColor prevColor;
490508
while ( !e.isNull() )
491509
{
492-
// QgsDebugMsg("read "+e.tagName());
493510
if ( e.tagName() == "stop" )
494511
{
495512
//todo integrate this into symbollayerutils, keep here for now...
496513
double offset;
497514
QString offsetStr = e.attribute( "offset" ); // offset="50.00%" | offset="0.5"
515+
QString colorStr = e.attribute( "stop-color", "" ); // stop-color="rgb(222,235,247)"
516+
QString opacityStr = e.attribute( "stop-opacity", "1.0" ); // stop-opacity="1.0000"
498517
if ( offsetStr.endsWith( "%" ) )
499518
offset = offsetStr.remove( offsetStr.size() - 1, 1 ).toDouble() / 100.0;
500519
else
501520
offset = offsetStr.toDouble();
502521

503-
QString colorStr = e.attribute( "stop-color", "" ); // stop-color="rgb(222,235,247)"
504-
QString opacityStr = e.attribute( "stop-opacity", "1.0" ); // stop-opacity="1.0000"
505522
// QColor color( 255, 0, 0 ); // red color as a warning :)
506523
QColor color = QgsSymbolLayerV2Utils::parseColor( colorStr );
507524
if ( color != QColor() )
508525
{
509526
int alpha = opacityStr.toDouble() * 255; // test
510527
color.setAlpha( alpha );
511528
if ( map.contains( offset ) )
512-
mContinuous = false; // assume discrete if at least one stop is repeated
513-
map[offset] = color;
529+
map[offset].second = color;
530+
else
531+
map[offset] = qMakePair( color, color );
514532
}
533+
else
534+
QgsDebugMsg( QString( "at offset=%1 invalid color" ).arg( offset ) );
515535
}
516536
else
517537
{
@@ -521,18 +541,51 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
521541
e = e.nextSiblingElement();
522542
}
523543

524-
// if this is a discrete gradient, remove last stop
525-
if ( ! mContinuous )
544+
// add colors to palette
545+
mPalette.clear();
546+
QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
547+
// first detect if file is gradient is continuous or dicrete
548+
// discrete: stop contains 2 colors and first color is identical to previous second
549+
// multi: stop contains 2 colors and no relation with previous stop
550+
mGradientType = Continuous;
551+
it = prev = map.constBegin();
552+
while ( it != map.constEnd() )
526553
{
527-
if ( map.contains( 1 ) )
528-
map.remove( 1 );
554+
// look for stops that contain multiple values
555+
if ( it != map.constBegin() && ( it.value().first != it.value().second ) )
556+
{
557+
if ( it.value().first == prev.value().second )
558+
{
559+
mGradientType = Discrete;
560+
break;
561+
}
562+
else
563+
{
564+
mGradientType = ContinuousMulti;
565+
break;
566+
}
567+
}
568+
prev = it;
569+
++it;
529570
}
530-
// add colors to palette
531-
QMap<double, QColor>::const_iterator it = map.constBegin();
571+
572+
it = prev = map.constBegin();
532573
while ( it != map.constEnd() )
533574
{
534-
mPaletteStops << it.key();
535-
mPalette << it.value();
575+
if ( mGradientType == Discrete )
576+
{
577+
mPalette << qMakePair( it.key(), it.value().second );
578+
}
579+
else
580+
{
581+
mPalette << qMakePair( it.key(), it.value().first );
582+
if (( mGradientType == ContinuousMulti ) &&
583+
( it.key() != 0.0 && it.key() != 1.0 ) )
584+
{
585+
mPalette << qMakePair( it.key(), it.value().second );
586+
}
587+
}
588+
prev = it;
536589
++it;
537590
}
538591

@@ -782,7 +835,3 @@ bool QgsCptCityColorRampV2::loadSchemes( QString rootDir, bool reset )
782835
return ( ! mCollections.isEmpty() );
783836
}
784837

785-
void QgsCptCityColorRampV2::loadPalette()
786-
{
787-
// TODO: IMPLEMENT ME
788-
}

src/core/symbology-ng/qgsvectorcolorrampv2.h

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
168168
QgsCptCityColorRampV2( QString schemeName = DEFAULT_CPTCITY_SCHEMENAME,
169169
QString variantName = DEFAULT_CPTCITY_VARIANTNAME );
170170

171+
172+
enum GradientType
173+
{
174+
Discrete, //discrete stops, e.g. Color Brewer
175+
Continuous, //continuous, e.g. QgsVectorColorRampV2
176+
ContinuousMulti //continuous with 2 values in intermediate stops
177+
};
178+
typedef QList< QPair < double, QColor > > GradientList;
179+
180+
171181
static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() );
172182

173183
virtual QColor color( double value ) const;
@@ -183,27 +193,24 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
183193
QString schemeName() const { return mSchemeName; }
184194
QString variantName() const { return mVariantName; }
185195

186-
/* void setSchemeName( QString schemeName ) { mSchemeName = schemeName; loadPalette(); } */
187-
/* void setVariantName( QString variantName ) { mVariantName = variantName; loadPalette(); } */
188196
/* lazy loading - have to call loadPalette() explicitly */
189197
void setSchemeName( QString schemeName ) { mSchemeName = schemeName; }
190198
void setVariantName( QString variantName ) { mVariantName = variantName; }
191199
void setName( QString schemeName, QString variantName = "" )
192200
{ mSchemeName = schemeName; mVariantName = variantName; loadPalette(); }
193201

194-
void loadPalette();
195-
bool isContinuous() const { return mContinuous; }
202+
void loadPalette() { loadFile(); }
203+
/* bool isContinuous() const { return mContinuous; } */
204+
GradientType gradientType() const { return mGradientType; }
196205

197206
QString getFilename() const;
198207
bool loadFile( QString filename = "" );
199208

200-
/* static QList<QColor> listSchemeColors( QString schemeName, int colors ); */
201-
static QList<int> listSchemeVariants( QString schemeName );
202-
203209
static QString getBaseDir();
204210
static void setBaseDir( QString dirName ) { mBaseDir = dirName; }
205211
static bool loadSchemes( QString rootDir = "", bool reset = false );
206-
/** Is the minimal (free to distribute) set of schemes available? Currently returns hasAllSchemes, because we don't have a minimal set yet. */
212+
/** Is the minimal (free to distribute) set of schemes available?
213+
* Currently returns hasAllSchemes, because we don't have a minimal set yet. */
207214
static bool hasBasicSchemes();
208215
/** Is the entire archive available? Currently tests that there is at least one scheme. */
209216
static bool hasAllSchemes();
@@ -213,27 +220,19 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
213220
static QgsCptCityColorRampV2* colorRampFromSVGString( QString svgString );
214221

215222
static const QMap< QString, QStringList > schemeMap() { return mSchemeMap; }
216-
/* static const QMap< QString, int > schemeNumColors() { return mSchemeNumColors; } */
217223
static const QMap< QString, QStringList > schemeVariants() { return mSchemeVariants; }
218224
static const QMap< QString, QString > collectionNames() { return mCollectionNames; }
219225
static const QMap< QString, QStringList > collectionSelections() { return mCollectionSelections; }
220226

221227
protected:
222228

223-
typedef QMap<double, QColor> StopsMap;
224-
225229
QString mSchemeName;
226230
QString mVariantName;
227-
bool mContinuous;
228-
QList< QColor > mPalette;
229-
QList< double > mPaletteStops;
230-
/* QMap< double, QColor > mPalette; */
231-
231+
GradientType mGradientType;
232+
GradientList mPalette;
232233
static QString mBaseDir;
233234
static QStringList mCollections;
234235
static QMap< QString, QStringList > mSchemeMap; //key is collection, value is schemes
235-
/* mSchemeNumColors removed, instead read on demand */
236-
/* static QMap< QString, int > mSchemeNumColors; //key is scheme, value is # colors (if no variants) */
237236
static QMap< QString, QStringList > mSchemeVariants; //key is scheme, value is variants
238237
static QMap< QString, QString > mCollectionNames; //key is name, value is description
239238
static QMap< QString, QStringList > mCollectionSelections;

src/gui/symbology-ng/qgscptcitycolorrampv2dialog.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ QgsCptCityColorRampV2Dialog::QgsCptCityColorRampV2Dialog( QgsCptCityColorRampV2*
4040
setupUi( this );
4141

4242
QgsCptCityColorRampV2::loadSchemes( "" );
43-
// QgsCptCityColorRampV2::loadSchemes( "cb" );
4443

4544
// show information on how to install cpt-city files if none are found
4645
if ( ! QgsCptCityColorRampV2::hasAllSchemes() )
@@ -67,6 +66,7 @@ QgsCptCityColorRampV2Dialog::QgsCptCityColorRampV2Dialog( QgsCptCityColorRampV2*
6766
populateVariants();
6867
cboVariantName->setCurrentIndex( cboVariantName->findData( ramp->variantName(), Qt::UserRole ) );
6968
connect( cboVariantName, SIGNAL( currentIndexChanged( int ) ), this, SLOT( setVariantName() ) );
69+
7070
updatePreview();
7171
}
7272

@@ -265,9 +265,12 @@ void QgsCptCityColorRampV2Dialog::on_treeWidget_itemExpanded( QTreeWidgetItem *
265265
if ( ramp.loadFile() )
266266
{
267267
itemDesc = QString::number( ramp.count() ) + " " + tr( "colors" ) + " - ";
268-
if ( ramp.isContinuous() )
268+
QgsCptCityColorRampV2::GradientType type = ramp.gradientType();
269+
if ( type == QgsCptCityColorRampV2::Continuous )
269270
itemDesc += tr( "continuous" );
270-
else
271+
else if ( type == QgsCptCityColorRampV2::ContinuousMulti )
272+
itemDesc += tr( "continuous (multi)" );
273+
else if ( type == QgsCptCityColorRampV2::Discrete )
271274
itemDesc += tr( "discrete" );
272275
}
273276
childItem->setText( 1, " " + itemDesc );
@@ -295,7 +298,24 @@ void QgsCptCityColorRampV2Dialog::updatePreview()
295298
{
296299
QSize size( 300, 40 );
297300
mRamp->loadFile();
298-
lblPreview->setPixmap( QgsSymbolLayerV2Utils::colorRampPreviewPixmap( mRamp, size ) );
301+
// TODO draw checker-board/transparent background
302+
// for transparent, add [ pixmap.fill( Qt::transparent ); ] to QgsSymbolLayerV2Utils::colorRampPreviewPixmap
303+
304+
QPixmap pixmap = QgsSymbolLayerV2Utils::colorRampPreviewPixmap( mRamp, size );
305+
lblPreview->setPixmap( pixmap );
306+
307+
// this is for testing purposes only
308+
// you need to install a mirror of cpt-city files in $HOME/.qgis/cpt-city-state with just the .png files
309+
QString basefile = QgsApplication::qgisSettingsDirPath() + "/" + "cpt-city-site" + "/" + mRamp->schemeName() + mRamp->variantName() + ".png";
310+
QFileInfo info( basefile );
311+
QString pngfile = info.path() + "/tn/" + info.fileName();
312+
if ( QFile::exists( pngfile ) )
313+
{
314+
QPixmap pixmap2( pngfile );
315+
lblPreview2->setPixmap( pixmap2.scaled( size ) );
316+
}
317+
lblPreview2->setText( "" );
318+
299319
}
300320

301321
void QgsCptCityColorRampV2Dialog::setSchemeName()

src/gui/symbology-ng/qgscptcitycolorrampv2dialog.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ class GUI_EXPORT QgsCptCityColorRampV2Dialog : public QDialog, private Ui::QgsCp
4444
void updatePreview();
4545
QTreeWidgetItem* findPath( QString path );
4646
QTreeWidgetItem * makeCollectionItem( const QString& path );
47-
// TODO rename Scheme to something else, maybe data
4847
void makeSchemeItem( QTreeWidgetItem *item, const QString& path, const QString& schemeName );
4948

5049
QgsCptCityColorRampV2* mRamp;

0 commit comments

Comments
 (0)