Skip to content

Commit

Permalink
[FEATURE] gradient color ramps now support multiple stops - for addin…
Browse files Browse the repository at this point in the history
…g intermediate colors

git-svn-id: http://svn.osgeo.org/qgis/trunk@13333 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder committed Apr 20, 2010
1 parent b24494c commit 63c295c
Show file tree
Hide file tree
Showing 7 changed files with 411 additions and 21 deletions.
102 changes: 102 additions & 0 deletions python/core/conversions.sip
Expand Up @@ -9,6 +9,7 @@ which are not wrapped by PyQt:
- QMap<int, QMap<int, TYPE> >
- QMap<QString, QVariant::Type>
- QMap<TYPE1, TYPE2*>
- QMap<double, TYPE>
- QMultiMap<double, TYPE2>
- QMap<int, QgsOverlayObject*>*
*/
Expand Down Expand Up @@ -730,6 +731,107 @@ template<TYPE1, TYPE2>
%End
};



template<double, TYPE>
%MappedType QMap<double, TYPE>
{
%TypeHeaderCode
#include <QMap>
%End

%ConvertFromTypeCode
// Create the dictionary.
PyObject *d = PyDict_New();

if (!d)
return NULL;

// Set the dictionary elements.
QMap<double, TYPE>::iterator i;

for (i = sipCpp->begin(); i != sipCpp->end(); ++i)
{
PyObject *t1obj = PyFloat_FromDouble(i.key());
TYPE* t2 = &i.value();
PyObject *t2obj = sipConvertFromInstance(t2, sipClass_TYPE, sipTransferObj);

if (t1obj == NULL || t2obj == NULL || PyDict_SetItem(d, t1obj, t2obj) < 0)
{
Py_DECREF(d);

if (t1obj)
Py_DECREF(t1obj);

if (t2obj)
Py_DECREF(t2obj);

return NULL;
}

Py_DECREF(t1obj);
Py_DECREF(t2obj);
}

return d;
%End

%ConvertToTypeCode
PyObject *t1obj, *t2obj;
#if PY_VERSION_HEX >= 0x02050000
Py_ssize_t i = 0;
#else
int i = 0;
#endif

// Check the type if that is all that is required.
if (sipIsErr == NULL)
{
if (!PyDict_Check(sipPy))
return 0;

while (PyDict_Next(sipPy, &i, &t1obj, &t2obj))
{
if (!PyFloat_Check(t1obj))
return 0;

if (!sipCanConvertToInstance(t2obj, sipClass_TYPE, SIP_NOT_NONE))
return 0;
}

return 1;
}

QMap<double, TYPE> *qm = new QMap<double, TYPE>;

while (PyDict_Next(sipPy, &i, &t1obj, &t2obj))
{
int state;

double k = PyFloat_AsDouble(t1obj);
TYPE *t2 = reinterpret_cast<TYPE *>(sipConvertToInstance(t2obj, sipClass_TYPE, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));

if (*sipIsErr)
{
sipReleaseInstance(t2, sipClass_TYPE, state);
delete qm;
return 0;
}

qm->insert(k, *t2);

sipReleaseInstance(t2, sipClass_TYPE, state);
}

*sipCppPtr = qm;

return sipGetState(sipTransferObj);
%End
};




template<double, TYPE2>
%MappedType QMultiMap<double, TYPE2>
{
Expand Down
44 changes: 43 additions & 1 deletion python/core/symbology-ng-core.sip
Expand Up @@ -762,19 +762,59 @@ class QgsVectorColorRampV2
#include <qgsvectorcolorrampv2.h>
%End

%ConvertToSubClassCode
if (sipCpp->type() == "gradient")
{
sipClass = sipClass_QgsVectorGradientColorRampV2;
}
else
sipClass = 0;
%End

public:
virtual ~QgsVectorColorRampV2();

virtual QColor color(double value) const = 0;

virtual QString type() const = 0;

virtual QgsVectorColorRampV2* clone() const = 0;
virtual QgsVectorColorRampV2* clone() const = 0 /Factory/;

virtual QgsStringMap properties() const = 0;

};

class QgsVectorGradientColorRampV2 : QgsVectorColorRampV2
{
public:
QgsVectorGradientColorRampV2( QColor color1 = QColor(0,0,255),
QColor color2 = QColor(0,255,0) );

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

virtual QColor color( double value ) const;

virtual QString type() const;

virtual QgsVectorColorRampV2* clone() const /Factory/;

virtual QgsStringMap properties() const;

QColor color1() const;
QColor color2() const;

void setColor1( QColor color );
void setColor2( QColor color );

typedef QMultiMap<double, QColor> StopsMap;

void setStops(const StopsMap& stops);
const StopsMap& stops() const;

};



//////////

class QgsSymbologyV2Conversion
Expand Down Expand Up @@ -858,3 +898,5 @@ class QgsRendererV2Registry
QgsRendererV2Registry();
~QgsRendererV2Registry();
};

///////////////
68 changes: 62 additions & 6 deletions src/core/symbology-ng/qgsvectorcolorrampv2.cpp
Expand Up @@ -18,28 +18,84 @@ QgsVectorColorRampV2* QgsVectorGradientColorRampV2::create( const QgsStringMap&
color1 = QgsSymbolLayerV2Utils::decodeColor( props["color1"] );
if ( props.contains( "color2" ) )
color2 = QgsSymbolLayerV2Utils::decodeColor( props["color2"] );
return new QgsVectorGradientColorRampV2( color1, color2 );

StopsMap stops;
if ( props.contains( "stops" ) )
{
foreach( QString stop, props["stops"].split( ':' ) )
{
int i = stop.indexOf( ';' );
if ( i == -1 ) continue;

QColor c = QgsSymbolLayerV2Utils::decodeColor( stop.mid( i + 1 ) );
stops.insert( stop.left( i ).toDouble(), c );
}
}

QgsVectorGradientColorRampV2* r = new QgsVectorGradientColorRampV2( color1, color2 );
r->setStops( stops );
return r;
}

QColor QgsVectorGradientColorRampV2::color( double value ) const
static QColor _interpolate( QColor c1, QColor c2, double value )
{
int r = ( int )( mColor1.red() + value * ( mColor2.red() - mColor1.red() ) );
int g = ( int )( mColor1.green() + value * ( mColor2.green() - mColor1.green() ) );
int b = ( int )( mColor1.blue() + value * ( mColor2.blue() - mColor1.blue() ) );
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() ) );

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

QColor QgsVectorGradientColorRampV2::color( double value ) const
{
if ( mStops.isEmpty() )
{
return _interpolate( mColor1, mColor2, value );
}
else
{
double lower = 0, upper;
QColor c1 = mColor1, c2;
for ( StopsMap::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
{
if ( it.key() >= value )
{
upper = it.key();
c2 = it.value();

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

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

QgsVectorColorRampV2* QgsVectorGradientColorRampV2::clone() const
{
return new QgsVectorGradientColorRampV2( mColor1, mColor2 );
QgsVectorGradientColorRampV2* r = new QgsVectorGradientColorRampV2( mColor1, mColor2 );
r->setStops( mStops );
return r;
}

QgsStringMap QgsVectorGradientColorRampV2::properties() const
{
QgsStringMap map;
map["color1"] = QgsSymbolLayerV2Utils::encodeColor( mColor1 );
map["color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
if ( !mStops.isEmpty() )
{
QStringList lst;
for ( StopsMap::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
{
lst.append( QString( "%1;%2" ).arg( it.key() ).arg( QgsSymbolLayerV2Utils::encodeColor( it.value() ) ) );
}
map["stops"] = lst.join( ":" );
}
return map;
}

Expand Down
6 changes: 6 additions & 0 deletions src/core/symbology-ng/qgsvectorcolorrampv2.h
Expand Up @@ -46,8 +46,14 @@ class CORE_EXPORT QgsVectorGradientColorRampV2 : public QgsVectorColorRampV2
void setColor1( QColor color ) { mColor1 = color; }
void setColor2( QColor color ) { mColor2 = color; }

typedef QMap<double, QColor> StopsMap;

void setStops( const StopsMap& stops ) { mStops = stops; }
const StopsMap& stops() const { return mStops; }

protected:
QColor mColor1, mColor2;
StopsMap mStops;
};

#define DEFAULT_RANDOM_COUNT 10
Expand Down

0 comments on commit 63c295c

Please sign in to comment.