Skip to content
Permalink
Browse files

New property for simple line and marker line: offset!

git-svn-id: http://svn.osgeo.org/qgis/branches/symbology-ng-branch@10806 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder
wonder committed May 17, 2009
1 parent 333842b commit 9bd511351e8bf7b1eaa958861024332fa27b734e
@@ -9,7 +9,7 @@
#include <cmath>

QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2(QColor color, int width, Qt::PenStyle penStyle)
: mPenStyle(penStyle)
: mPenStyle(penStyle), mOffset(0)
{
mColor = color;
mWidth = width;
@@ -29,7 +29,10 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::create(const QgsStringMap& props)
if (props.contains("penstyle"))
penStyle = QgsSymbolLayerV2Utils::decodePenStyle(props["penstyle"]);

return new QgsSimpleLineSymbolLayerV2(color, width, penStyle);
QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2(color, width, penStyle);
if (props.contains("offset"))
l->setOffset( props["offset"].toDouble() );
return l;
}


@@ -53,7 +56,14 @@ void QgsSimpleLineSymbolLayerV2::stopRender(QgsRenderContext& context)
void QgsSimpleLineSymbolLayerV2::renderPolyline(const QPolygonF& points, QgsRenderContext& context)
{
context.painter()->setPen(mPen);
context.painter()->drawPolyline(points);
if (mOffset == 0)
{
context.painter()->drawPolyline(points);
}
else
{
context.painter()->drawPolyline( ::offsetLine(points, mOffset) );
}
}

QgsStringMap QgsSimpleLineSymbolLayerV2::properties() const
@@ -62,12 +72,15 @@ QgsStringMap QgsSimpleLineSymbolLayerV2::properties() const
map["color"] = QgsSymbolLayerV2Utils::encodeColor(mColor);
map["width"] = QString::number(mWidth);
map["penstyle"] = QgsSymbolLayerV2Utils::encodePenStyle(mPenStyle);
map["offset"] = QString::number(mOffset);
return map;
}

QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::clone() const
{
return new QgsSimpleLineSymbolLayerV2(mColor, mWidth, mPenStyle);
QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2(mColor, mWidth, mPenStyle);
l->setOffset(mOffset);
return l;
}


@@ -138,6 +151,7 @@ QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2(bool rotateMarker, double
mRotateMarker = rotateMarker;
mInterval = interval;
mMarker = NULL;
mOffset = 0;

setSubSymbol(new QgsMarkerSymbolV2());
}
@@ -158,6 +172,8 @@ QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::create(const QgsStringMap& props)
rotate = (props["rotate"] == "1");

QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2(rotate, interval);
if (props.contains("offset"))
x->setOffset(props["offset"].toDouble());
return x;
}

@@ -186,6 +202,19 @@ void QgsMarkerLineSymbolLayerV2::stopRender(QgsRenderContext& context)
}

void QgsMarkerLineSymbolLayerV2::renderPolyline(const QPolygonF& points, QgsRenderContext& context)
{
if (mOffset == 0)
{
renderPolylineNoOffset(points, context);
}
else
{
QPolygonF points2 = ::offsetLine( points, mOffset );
renderPolylineNoOffset( points2, context );
}
}

void QgsMarkerLineSymbolLayerV2::renderPolylineNoOffset(const QPolygonF& points, QgsRenderContext& context)
{
QPointF lastPt = points[0];
double lengthLeft = 0; // how much is left until next marker
@@ -245,6 +274,7 @@ QgsStringMap QgsMarkerLineSymbolLayerV2::properties() const
QgsStringMap map;
map["rotate"] = (mRotateMarker ? "1" : "0");
map["interval"] = QString::number(mInterval);
map["offset"] = QString::number(mOffset);
return map;
}

@@ -271,6 +301,7 @@ QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::clone() const
{
QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2(mRotateMarker, mInterval);
x->setSubSymbol(mMarker->clone());
x->setOffset(mOffset);
return x;
}

@@ -40,10 +40,14 @@ class QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2

Qt::PenStyle penStyle() const { return mPenStyle; }
void setPenStyle(Qt::PenStyle style) { mPenStyle = style; }

double offset() const { return mOffset; }
void setOffset(double offset) { mOffset = offset; }

protected:
Qt::PenStyle mPenStyle;
QPen mPen;
double mOffset;
};

/////////
@@ -89,11 +93,18 @@ class QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2

double interval() const { return mInterval; }
void setInterval(double interval) { mInterval = interval; }

double offset() const { return mOffset; }
void setOffset(double offset) { mOffset = offset; }

protected:

void renderPolylineNoOffset(const QPolygonF& points, QgsRenderContext& context);

bool mRotateMarker;
double mInterval;
QgsMarkerSymbolV2* mMarker;
double mOffset;
};

/////////
@@ -133,3 +133,109 @@ QPixmap QgsSymbolLayerV2Utils::colorRampPreviewPixmap(QgsVectorColorRampV2* ramp
painter.end();
return pixmap;
}


#include <QPolygonF>

#include <cmath>
#include <cfloat>


// calculate line's angle and tangent
static bool lineInfo(QPointF p1, QPointF p2, double& angle, double& t)
{
double x1 = p1.x(), y1 = p1.y(), x2 = p2.x(), y2 = p2.y();

if (x1 == x2 && y1 == y2)
return false;

// tangent
t = ( x1 == x2 ? t = DBL_MAX : (y2-y1)/(x2-x1) );

// angle
if (t == DBL_MAX)
angle = ( y2 >= y1 ? M_PI/2 : M_PI*3/2 ); // angle is 90 or 270
else if (t >= 0)
angle = ( y2 >= y1 ? atan(t) : M_PI + atan(t) );
else // t < 0
angle = ( y2 >= y1 ? M_PI + atan(t) : M_PI*2 + atan(t) );

return true;
}

// offset a point with an angle and distance
static QPointF offsetPoint(QPointF pt, double angle, double dist)
{
return QPointF(pt.x() + dist * cos(angle), pt.y() + dist * sin(angle));
}

// calc intersection of two (infinite) lines defined by one point and tangent
static QPointF linesIntersection(QPointF p1, double t1, QPointF p2, double t2)
{
// parallel lines?
if ( (t1 == DBL_MAX && t2 == DBL_MAX) || t1 == t2)
return QPointF();

double x,y;
if (t1 == DBL_MAX || t2 == DBL_MAX)
{
// in case one line is with angle 90 resp. 270 degrees (tangent undefined)
// swap them so that line 2 is with undefined tangent
if (t1 == DBL_MAX)
{
QPointF pSwp = p1; p1 = p2; p2 = pSwp;
double tSwp = t1; t1 = t2; t2 = tSwp;
}

x = p2.x();
}
else
{
// usual case
x = ( (p1.y() - p2.y()) + t2*p2.x() - t1*p1.x() ) / (t2 - t1);
}

y = p1.y() + t1 * (x - p1.x());
return QPointF(x,y);
}


QPolygonF offsetLine(QPolygonF polyline, double dist)
{
QPolygonF newLine;

if (polyline.count() < 2)
return newLine;

double angle, t_new, t_old=0;
QPointF pt_old, pt_new;
QPointF p1 = polyline[0], p2;

for (int i = 1; i < polyline.count(); i++)
{
p2 = polyline[i];

if ( !lineInfo(p1, p2, angle, t_new) )
continue; // not a line...

pt_new = offsetPoint(p1, angle + M_PI/2, dist);

if (i != 1)
{
// if it's not the first line segment
// calc intersection with last line (with offset)
pt_new = linesIntersection(pt_old, t_old, pt_new, t_new);
}

newLine.append(pt_new);

pt_old = pt_new;
t_old = t_new;
p1 = p2;
}

// last line segment:
pt_new = offsetPoint(p2, angle + M_PI/2, dist);
newLine.append(pt_new);
return newLine;
}
@@ -37,4 +37,10 @@ class QgsSymbolLayerV2Utils
static QPixmap colorRampPreviewPixmap(QgsVectorColorRampV2* ramp, QSize size);
};

class QPolygonF;

//! calculate line shifted by a specified distance
QPolygonF offsetLine(QPolygonF polyline, double dist);


#endif
@@ -35,6 +35,7 @@ QgsSimpleLineSymbolLayerV2Widget::QgsSimpleLineSymbolLayerV2Widget(QWidget* pare
connect(spinWidth, SIGNAL(valueChanged(int)), this, SLOT(penWidthChanged()));
connect(btnChangeColor, SIGNAL(clicked()), this, SLOT(colorChanged()));
connect(cboPenStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(penStyleChanged()));
connect(spinOffset, SIGNAL(valueChanged(double)), this, SLOT(offsetChanged()));
}

void QgsSimpleLineSymbolLayerV2Widget::setSymbolLayer(QgsSymbolLayerV2* layer)
@@ -49,6 +50,7 @@ void QgsSimpleLineSymbolLayerV2Widget::setSymbolLayer(QgsSymbolLayerV2* layer)
spinWidth->setValue(mLayer->width());
updateColorButton(btnChangeColor, mLayer->color());
cboPenStyle->setPenStyle(mLayer->penStyle());
spinOffset->setValue(mLayer->offset());
}

QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2Widget::symbolLayer()
@@ -78,6 +80,12 @@ void QgsSimpleLineSymbolLayerV2Widget::penStyleChanged()
emit changed();
}

void QgsSimpleLineSymbolLayerV2Widget::offsetChanged()
{
mLayer->setOffset(spinOffset->value());
emit changed();
}


///////////

@@ -249,6 +257,7 @@ QgsMarkerLineSymbolLayerV2Widget::QgsMarkerLineSymbolLayerV2Widget(QWidget* pare
connect(spinInterval, SIGNAL(valueChanged(int)), this, SLOT(setInterval(int)));
connect(btnChangeMarker, SIGNAL(clicked()), this, SLOT(setMarker()));
connect(chkRotateMarker, SIGNAL(clicked()), this, SLOT(setRotate()));
connect(spinOffset, SIGNAL(valueChanged(double)), this, SLOT(setOffset()));
}

void QgsMarkerLineSymbolLayerV2Widget::setSymbolLayer(QgsSymbolLayerV2* layer)
@@ -262,6 +271,7 @@ void QgsMarkerLineSymbolLayerV2Widget::setSymbolLayer(QgsSymbolLayerV2* layer)
// set values
spinInterval->setValue( (int) mLayer->interval());
chkRotateMarker->setChecked(mLayer->rotateMarker());
spinOffset->setValue(mLayer->offset());
updateMarker();
}

@@ -292,6 +302,13 @@ void QgsMarkerLineSymbolLayerV2Widget::setRotate()
emit changed();
}

void QgsMarkerLineSymbolLayerV2Widget::setOffset()
{
mLayer->setOffset(spinOffset->value());
emit changed();
}


void QgsMarkerLineSymbolLayerV2Widget::updateMarker()
{
QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon(mLayer->subSymbol(), btnChangeMarker->iconSize());
@@ -44,6 +44,7 @@ class QgsSimpleLineSymbolLayerV2Widget : public QgsSymbolLayerV2Widget, private
void penWidthChanged();
void colorChanged();
void penStyleChanged();
void offsetChanged();

protected:
QgsSimpleLineSymbolLayerV2* mLayer;
@@ -132,6 +133,7 @@ class QgsMarkerLineSymbolLayerV2Widget : public QgsSymbolLayerV2Widget, private
void setInterval(int val);
void setMarker();
void setRotate();
void setOffset();

protected:

0 comments on commit 9bd5113

Please sign in to comment.
You can’t perform that action at this time.