Skip to content

Commit

Permalink
fix cpt-city svg parsing and display
Browse files Browse the repository at this point in the history
  • Loading branch information
etiennesky committed Aug 6, 2012
1 parent 3b3f674 commit 3391f42
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 72 deletions.
6 changes: 4 additions & 2 deletions src/core/symbology-ng/qgssymbollayerv2utils.cpp
Expand Up @@ -490,10 +490,12 @@ QIcon QgsSymbolLayerV2Utils::colorRampPreviewIcon( QgsVectorColorRampV2* ramp, Q
QPixmap QgsSymbolLayerV2Utils::colorRampPreviewPixmap( QgsVectorColorRampV2* ramp, QSize size )
{
QPixmap pixmap( size );
pixmap.fill( Qt::transparent );
// pixmap.fill( Qt::white ); // this makes the background white instead of transparent
QPainter painter;
painter.begin( &pixmap );
painter.setRenderHint( QPainter::Antialiasing );
painter.eraseRect( QRect( QPoint( 0, 0 ), size ) );
// antialising makes the colors duller, and no point in antialiasing a color ramp
// painter.setRenderHint( QPainter::Antialiasing );
for ( int i = 0; i < size.width(); i++ )
{
QPen pen( ramp->color(( double ) i / size.width() ) );
Expand Down
139 changes: 94 additions & 45 deletions src/core/symbology-ng/qgsvectorcolorrampv2.cpp
Expand Up @@ -60,8 +60,9 @@ static QColor _interpolate( QColor c1, QColor c2, double value )
int r = ( int )( c1.red() + value * ( c2.red() - c1.red() ) );
int g = ( int )( c1.green() + value * ( c2.green() - c1.green() ) );
int b = ( int )( c1.blue() + value * ( c2.blue() - c1.blue() ) );
int a = ( int )( c1.alpha() + value * ( c2.alpha() - c1.alpha() ) );

return QColor::fromRgb( r, g, b );
return QColor::fromRgb( r, g, b, a );
}

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

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



#if 0
QColor QgsCptCityColorRampV2::color( double value ) const
{
if ( mPalette.isEmpty() || value < 0 || value > 1 )
Expand Down Expand Up @@ -333,6 +334,45 @@ QColor QgsCptCityColorRampV2::color( double value ) const
return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
}
}
#endif

QColor QgsCptCityColorRampV2::color( double value ) const
{
if ( mPalette.isEmpty() || value < 0 || value > 1 )
return QColor( 255, 0, 0 ); // red color as a warning :)

int numStops = mPalette.count();
if ( numStops < 2 )
return QColor( 255, 0, 0 ); // red color as a warning :)

double lower = 0, upper = 0;
QColor c1, c2;
c1 = mPalette[0].second;
for ( int i = 0; i < numStops; i++ )
{
if ( mPalette[i].first >= value )
{
if ( mGradientType == Discrete )
return c1;

upper = mPalette[i].first;
c2 = mPalette[i].second;

return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
}

lower = mPalette[i].first;
c1 = mPalette[i].second;
}

if ( mGradientType == Discrete )
return c1;

upper = 1;
c2 = mPalette[ numStops - 1 ].second;

return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
}

QgsVectorColorRampV2* QgsCptCityColorRampV2::clone() const
{
Expand Down Expand Up @@ -390,23 +430,6 @@ QStringList QgsCptCityColorRampV2::listSchemeNames( QString collectionName )
return entries;
}

QList<int> QgsCptCityColorRampV2::listSchemeVariants( QString schemeName )
{
QList<int> variants;

QString palette( brewerString );
QStringList list = palette.split( QChar( '\n' ) );
foreach ( QString entry, list )
{
QStringList items = entry.split( QChar( '-' ) );
if ( items.count() != 3 || items[0] != schemeName )
continue;
variants << items[1].toInt();
}

return variants;
}

QString QgsCptCityColorRampV2::getBaseDir()
{
// currently hard-coded, but could be also in QGis install path and/or configurable
Expand Down Expand Up @@ -436,7 +459,6 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
// QgsDebugMsg("filename= "+filename);

mPalette.clear();
mPaletteStops.clear();

QString mErrorString = QString();

Expand Down Expand Up @@ -478,40 +500,38 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
return false;
}

// initialize self
mContinuous = true; // we will detect later if there are overlapping stops
mPalette.clear();
mPaletteStops.clear();

// loop for all stop tags
QDomElement e = rampsElement.firstChildElement();
// int i = 0;
QMap< double, QColor > map;
QMap< double, QPair<QColor, QColor> > map;

QColor prevColor;
while ( !e.isNull() )
{
// QgsDebugMsg("read "+e.tagName());
if ( e.tagName() == "stop" )
{
//todo integrate this into symbollayerutils, keep here for now...
double offset;
QString offsetStr = e.attribute( "offset" ); // offset="50.00%" | offset="0.5"
QString colorStr = e.attribute( "stop-color", "" ); // stop-color="rgb(222,235,247)"
QString opacityStr = e.attribute( "stop-opacity", "1.0" ); // stop-opacity="1.0000"
if ( offsetStr.endsWith( "%" ) )
offset = offsetStr.remove( offsetStr.size() - 1, 1 ).toDouble() / 100.0;
else
offset = offsetStr.toDouble();

QString colorStr = e.attribute( "stop-color", "" ); // stop-color="rgb(222,235,247)"
QString opacityStr = e.attribute( "stop-opacity", "1.0" ); // stop-opacity="1.0000"
// QColor color( 255, 0, 0 ); // red color as a warning :)
QColor color = QgsSymbolLayerV2Utils::parseColor( colorStr );
if ( color != QColor() )
{
int alpha = opacityStr.toDouble() * 255; // test
color.setAlpha( alpha );
if ( map.contains( offset ) )
mContinuous = false; // assume discrete if at least one stop is repeated
map[offset] = color;
map[offset].second = color;
else
map[offset] = qMakePair( color, color );
}
else
QgsDebugMsg( QString( "at offset=%1 invalid color" ).arg( offset ) );
}
else
{
Expand All @@ -521,18 +541,51 @@ bool QgsCptCityColorRampV2::loadFile( QString filename )
e = e.nextSiblingElement();
}

// if this is a discrete gradient, remove last stop
if ( ! mContinuous )
// add colors to palette
mPalette.clear();
QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
// first detect if file is gradient is continuous or dicrete
// discrete: stop contains 2 colors and first color is identical to previous second
// multi: stop contains 2 colors and no relation with previous stop
mGradientType = Continuous;
it = prev = map.constBegin();
while ( it != map.constEnd() )
{
if ( map.contains( 1 ) )
map.remove( 1 );
// look for stops that contain multiple values
if ( it != map.constBegin() && ( it.value().first != it.value().second ) )
{
if ( it.value().first == prev.value().second )
{
mGradientType = Discrete;
break;
}
else
{
mGradientType = ContinuousMulti;
break;
}
}
prev = it;
++it;
}
// add colors to palette
QMap<double, QColor>::const_iterator it = map.constBegin();

it = prev = map.constBegin();
while ( it != map.constEnd() )
{
mPaletteStops << it.key();
mPalette << it.value();
if ( mGradientType == Discrete )
{
mPalette << qMakePair( it.key(), it.value().second );
}
else
{
mPalette << qMakePair( it.key(), it.value().first );
if (( mGradientType == ContinuousMulti ) &&
( it.key() != 0.0 && it.key() != 1.0 ) )
{
mPalette << qMakePair( it.key(), it.value().second );
}
}
prev = it;
++it;
}

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

void QgsCptCityColorRampV2::loadPalette()
{
// TODO: IMPLEMENT ME
}
35 changes: 17 additions & 18 deletions src/core/symbology-ng/qgsvectorcolorrampv2.h
Expand Up @@ -168,6 +168,16 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
QgsCptCityColorRampV2( QString schemeName = DEFAULT_CPTCITY_SCHEMENAME,
QString variantName = DEFAULT_CPTCITY_VARIANTNAME );


enum GradientType
{
Discrete, //discrete stops, e.g. Color Brewer
Continuous, //continuous, e.g. QgsVectorColorRampV2
ContinuousMulti //continuous with 2 values in intermediate stops
};
typedef QList< QPair < double, QColor > > GradientList;


static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() );

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

/* void setSchemeName( QString schemeName ) { mSchemeName = schemeName; loadPalette(); } */
/* void setVariantName( QString variantName ) { mVariantName = variantName; loadPalette(); } */
/* lazy loading - have to call loadPalette() explicitly */
void setSchemeName( QString schemeName ) { mSchemeName = schemeName; }
void setVariantName( QString variantName ) { mVariantName = variantName; }
void setName( QString schemeName, QString variantName = "" )
{ mSchemeName = schemeName; mVariantName = variantName; loadPalette(); }

void loadPalette();
bool isContinuous() const { return mContinuous; }
void loadPalette() { loadFile(); }
/* bool isContinuous() const { return mContinuous; } */
GradientType gradientType() const { return mGradientType; }

QString getFilename() const;
bool loadFile( QString filename = "" );

/* static QList<QColor> listSchemeColors( QString schemeName, int colors ); */
static QList<int> listSchemeVariants( QString schemeName );

static QString getBaseDir();
static void setBaseDir( QString dirName ) { mBaseDir = dirName; }
static bool loadSchemes( QString rootDir = "", bool reset = false );
/** Is the minimal (free to distribute) set of schemes available? Currently returns hasAllSchemes, because we don't have a minimal set yet. */
/** Is the minimal (free to distribute) set of schemes available?
* Currently returns hasAllSchemes, because we don't have a minimal set yet. */
static bool hasBasicSchemes();
/** Is the entire archive available? Currently tests that there is at least one scheme. */
static bool hasAllSchemes();
Expand All @@ -213,27 +220,19 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorColorRampV2
static QgsCptCityColorRampV2* colorRampFromSVGString( QString svgString );

static const QMap< QString, QStringList > schemeMap() { return mSchemeMap; }
/* static const QMap< QString, int > schemeNumColors() { return mSchemeNumColors; } */
static const QMap< QString, QStringList > schemeVariants() { return mSchemeVariants; }
static const QMap< QString, QString > collectionNames() { return mCollectionNames; }
static const QMap< QString, QStringList > collectionSelections() { return mCollectionSelections; }

protected:

typedef QMap<double, QColor> StopsMap;

QString mSchemeName;
QString mVariantName;
bool mContinuous;
QList< QColor > mPalette;
QList< double > mPaletteStops;
/* QMap< double, QColor > mPalette; */

GradientType mGradientType;
GradientList mPalette;
static QString mBaseDir;
static QStringList mCollections;
static QMap< QString, QStringList > mSchemeMap; //key is collection, value is schemes
/* mSchemeNumColors removed, instead read on demand */
/* static QMap< QString, int > mSchemeNumColors; //key is scheme, value is # colors (if no variants) */
static QMap< QString, QStringList > mSchemeVariants; //key is scheme, value is variants
static QMap< QString, QString > mCollectionNames; //key is name, value is description
static QMap< QString, QStringList > mCollectionSelections;
Expand Down
28 changes: 24 additions & 4 deletions src/gui/symbology-ng/qgscptcitycolorrampv2dialog.cpp
Expand Up @@ -40,7 +40,6 @@ QgsCptCityColorRampV2Dialog::QgsCptCityColorRampV2Dialog( QgsCptCityColorRampV2*
setupUi( this );

QgsCptCityColorRampV2::loadSchemes( "" );
// QgsCptCityColorRampV2::loadSchemes( "cb" );

// show information on how to install cpt-city files if none are found
if ( ! QgsCptCityColorRampV2::hasAllSchemes() )
Expand All @@ -67,6 +66,7 @@ QgsCptCityColorRampV2Dialog::QgsCptCityColorRampV2Dialog( QgsCptCityColorRampV2*
populateVariants();
cboVariantName->setCurrentIndex( cboVariantName->findData( ramp->variantName(), Qt::UserRole ) );
connect( cboVariantName, SIGNAL( currentIndexChanged( int ) ), this, SLOT( setVariantName() ) );

updatePreview();
}

Expand Down Expand Up @@ -265,9 +265,12 @@ void QgsCptCityColorRampV2Dialog::on_treeWidget_itemExpanded( QTreeWidgetItem *
if ( ramp.loadFile() )
{
itemDesc = QString::number( ramp.count() ) + " " + tr( "colors" ) + " - ";
if ( ramp.isContinuous() )
QgsCptCityColorRampV2::GradientType type = ramp.gradientType();
if ( type == QgsCptCityColorRampV2::Continuous )
itemDesc += tr( "continuous" );
else
else if ( type == QgsCptCityColorRampV2::ContinuousMulti )
itemDesc += tr( "continuous (multi)" );
else if ( type == QgsCptCityColorRampV2::Discrete )
itemDesc += tr( "discrete" );
}
childItem->setText( 1, " " + itemDesc );
Expand Down Expand Up @@ -295,7 +298,24 @@ void QgsCptCityColorRampV2Dialog::updatePreview()
{
QSize size( 300, 40 );
mRamp->loadFile();
lblPreview->setPixmap( QgsSymbolLayerV2Utils::colorRampPreviewPixmap( mRamp, size ) );
// TODO draw checker-board/transparent background
// for transparent, add [ pixmap.fill( Qt::transparent ); ] to QgsSymbolLayerV2Utils::colorRampPreviewPixmap

QPixmap pixmap = QgsSymbolLayerV2Utils::colorRampPreviewPixmap( mRamp, size );
lblPreview->setPixmap( pixmap );

// this is for testing purposes only
// you need to install a mirror of cpt-city files in $HOME/.qgis/cpt-city-state with just the .png files
QString basefile = QgsApplication::qgisSettingsDirPath() + "/" + "cpt-city-site" + "/" + mRamp->schemeName() + mRamp->variantName() + ".png";
QFileInfo info( basefile );
QString pngfile = info.path() + "/tn/" + info.fileName();
if ( QFile::exists( pngfile ) )
{
QPixmap pixmap2( pngfile );
lblPreview2->setPixmap( pixmap2.scaled( size ) );
}
lblPreview2->setText( "" );

}

void QgsCptCityColorRampV2Dialog::setSchemeName()
Expand Down
1 change: 0 additions & 1 deletion src/gui/symbology-ng/qgscptcitycolorrampv2dialog.h
Expand Up @@ -44,7 +44,6 @@ class GUI_EXPORT QgsCptCityColorRampV2Dialog : public QDialog, private Ui::QgsCp
void updatePreview();
QTreeWidgetItem* findPath( QString path );
QTreeWidgetItem * makeCollectionItem( const QString& path );
// TODO rename Scheme to something else, maybe data
void makeSchemeItem( QTreeWidgetItem *item, const QString& path, const QString& schemeName );

QgsCptCityColorRampV2* mRamp;
Expand Down

0 comments on commit 3391f42

Please sign in to comment.