Showing with 201 additions and 11 deletions.
  1. +184 −10 src/core/dxf/qgsdxfpaintengine.cpp
  2. +17 −1 src/core/dxf/qgsdxfpaintengine.h
194 changes: 184 additions & 10 deletions src/core/dxf/qgsdxfpaintengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ void QgsDxfPaintEngine::updateState( const QPaintEngineState& state )
{
mPen = state.pen();
}
if ( state.state() & QPaintEngine::DirtyBrush )
{
mBrush = state.brush();
}
}

void QgsDxfPaintEngine::drawPolygon( const QPointF* points, int pointCount, PolygonDrawMode mode )
{
Q_UNUSED( mode );
if ( !mDxf || !mPaintDevice )
{
return;
Expand All @@ -77,7 +82,8 @@ void QgsDxfPaintEngine::drawPolygon( const QPointF* points, int pointCount, Poly
polyline[i] = toDxfCoordinates( points[i] );
}

mDxf->writePolyline( polyline, mLayer, "CONTINUOUS", currentPenColor(), currentWidth(), mode != QPaintEngine::PolylineMode );
bool closed = ( pointCount > 3 && points[0] == points[pointCount - 1] );
mDxf->writePolyline( polyline, mLayer, "CONTINUOUS", currentColor(), currentWidth(), closed );
}

void QgsDxfPaintEngine::drawRects( const QRectF* rects, int rectCount )
Expand All @@ -97,7 +103,7 @@ void QgsDxfPaintEngine::drawRects( const QRectF* rects, int rectCount )
QgsPoint pt2 = toDxfCoordinates( QPointF( right, bottom ) );
QgsPoint pt3 = toDxfCoordinates( QPointF( left, top ) );
QgsPoint pt4 = toDxfCoordinates( QPointF( right, top ) );
mDxf->writeSolid( mLayer, currentPenColor(), pt1, pt2, pt3, pt4 );
mDxf->writeSolid( mLayer, currentColor(), pt1, pt2, pt3, pt4 );
}
}

Expand All @@ -108,20 +114,98 @@ void QgsDxfPaintEngine::drawEllipse( const QRectF& rect )
//a circle
if ( qgsDoubleNear( rect.width(), rect.height() ) )
{
mDxf->writeCircle( mLayer, currentPenColor(), toDxfCoordinates( midPoint ), rect.width() / 2.0 );
mDxf->writeCircle( mLayer, currentColor(), toDxfCoordinates( midPoint ), rect.width() / 2.0 );
}

//todo: create polyline for real ellises
}

void QgsDxfPaintEngine::drawPath( const QPainterPath& path )
{
QList<QPolygonF> polygonList = path.toFillPolygons();
QList<QPolygonF>::const_iterator pIt = polygonList.constBegin();
for ( ; pIt != polygonList.constEnd(); ++pIt )
int pathLength = path.elementCount();
for ( int i = 0; i < pathLength; ++i )
{
drawPolygon( pIt->constData(), pIt->size(), pIt->isClosed() ? QPaintEngine::OddEvenMode : QPaintEngine::PolylineMode );
const QPainterPath::Element& pathElem = path.elementAt( i );
if ( pathElem.type == QPainterPath::MoveToElement )
{
moveTo( pathElem.x, pathElem.y );
}
else if ( pathElem.type == QPainterPath::LineToElement )
{
lineTo( pathElem.x, pathElem.y );
}
else if ( pathElem.type == QPainterPath::CurveToElement )
{
curveTo( pathElem.x, pathElem.y );
}
else if ( pathElem.type == QPainterPath::CurveToDataElement )
{
mCurrentCurve.append( QPointF( pathElem.x, pathElem.y ) );
}
}
endCurve();
endPolygon();
}

void QgsDxfPaintEngine::moveTo( double dx, double dy )
{
endCurve();
endPolygon();
mCurrentPolygon.append( QPointF( dx, dy ) );
}

void QgsDxfPaintEngine::lineTo( double dx, double dy )
{
endCurve();
mCurrentPolygon.append( QPointF( dx, dy ) );
}

void QgsDxfPaintEngine::curveTo( double dx, double dy )
{
endCurve();
if ( mCurrentPolygon.size() > 0 )
{
mCurrentCurve.append( mCurrentPolygon.last() );
}
mCurrentCurve.append( QPointF( dx, dy ) );
}

void QgsDxfPaintEngine::endPolygon()
{
if ( mCurrentPolygon.size() > 1 )
{
drawPolygon( mCurrentPolygon.constData(), mCurrentPolygon.size(), QPaintEngine::OddEvenMode );
}
mCurrentPolygon.clear();
}

void QgsDxfPaintEngine::endCurve()
{
if ( mCurrentCurve.size() < 1 )
{
return;
}
if ( mCurrentPolygon.size() < 1 )
{
mCurrentCurve.clear();
return;
}
//mCurrentCurve.prepend( mCurrentPolygon.last() );

if ( mCurrentCurve.size() >= 3 )
{
double t = 0.05;
for ( int i = 1; i < 20; ++i ) //approximate curve with 20 segments
{
mCurrentPolygon.append( bezierPoint( mCurrentCurve, t ) );
t += 0.05;
}
}
else if ( mCurrentCurve.size() == 2 )
{
mCurrentPolygon.append( mCurrentCurve.at( 1 ) );
}
mCurrentCurve.clear();
}

void QgsDxfPaintEngine::drawLines( const QLineF* lines, int lineCount )
Expand All @@ -135,7 +219,7 @@ void QgsDxfPaintEngine::drawLines( const QLineF* lines, int lineCount )
{
QgsPoint pt1 = toDxfCoordinates( lines[i].p1() );
QgsPoint pt2 = toDxfCoordinates( lines[i].p2() );
mDxf->writeLine( pt1, pt2, mLayer, "CONTINUOUS", currentPenColor(), currentWidth() );
mDxf->writeLine( pt1, pt2, mLayer, "CONTINUOUS", currentColor(), currentWidth() );
}
}

Expand All @@ -150,14 +234,19 @@ QgsPoint QgsDxfPaintEngine::toDxfCoordinates( const QPointF& pt ) const
return QgsPoint( dxfPt.x(), dxfPt.y() );
}

int QgsDxfPaintEngine::currentPenColor() const
int QgsDxfPaintEngine::currentColor() const
{
if ( !mDxf )
{
return 0;
}

return mDxf->closestColorMatch( mPen.color().rgb() );
QColor c = mPen.color();
if ( mPen.style() == Qt::NoPen )
{
c = mBrush.color();
}
return mDxf->closestColorMatch( c.rgb() );
}

double QgsDxfPaintEngine::currentWidth() const
Expand All @@ -169,3 +258,88 @@ double QgsDxfPaintEngine::currentWidth() const

return mPen.widthF() * mPaintDevice->widthScaleFactor();
}

QPointF QgsDxfPaintEngine::bezierPoint( const QList<QPointF>& controlPolygon, double t )
{
double x = 0;
double y = 0;
int cPolySize = controlPolygon.size();
double bPoly = 0;

QList<QPointF>::const_iterator it = controlPolygon.constBegin();
int i = 0;
for ( ; it != controlPolygon.constEnd(); ++it )
{
bPoly = bernsteinPoly( cPolySize - 1, i, t );
x += ( it->x() * bPoly );
y += ( it->y() * bPoly );
++i;
}

return QPointF( x, y );
}

double QgsDxfPaintEngine::bernsteinPoly( int n, int i, double t )
{
if ( i < 0 )
{
return 0;
}

return lower( n, i )*power( t, i )*power(( 1 - t ), ( n - i ) );
}

int QgsDxfPaintEngine::lower( int n, int i )
{
if ( i >= 0 && i <= n )
{
return faculty( n ) / ( faculty( i )*faculty( n - i ) );
}
else
{
return 0;
}
}

double QgsDxfPaintEngine::power( double a, int b )
{
if ( b == 0 )
{
return 1;
}
double tmp = a;
for ( int i = 2; i <= qAbs(( double )b ); i++ )
{

a *= tmp;
}
if ( b > 0 )
{
return a;
}
else
{
return ( 1.0 / a );
}
}

int QgsDxfPaintEngine::faculty( int n )
{
if ( n < 0 )//Is faculty also defined for negative integers?
{
return 0;
}
int i;
int result = n;

if ( n == 0 || n == 1 )
{
return 1;
}//faculty of 0 is 1!

for ( i = n - 1; i >= 2; i-- )
{
result *= i;
}
return result;
}
18 changes: 17 additions & 1 deletion src/core/dxf/qgsdxfpaintengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,28 @@ class CORE_EXPORT QgsDxfPaintEngine: public QPaintEngine
//painter state information
QTransform mTransform;
QPen mPen;
QBrush mBrush;
QString mLayer;
QPointF mShift;
QPolygonF mCurrentPolygon;
QList<QPointF> mCurrentCurve;

QgsPoint toDxfCoordinates( const QPointF& pt ) const;
int currentPenColor() const;
int currentColor() const;
double currentWidth() const;

void moveTo( double dx, double dy );
void lineTo( double dx, double dy );
void curveTo( double dx, double dy );
void endPolygon();
void endCurve();

//utils for bezier curve calculation
static QPointF bezierPoint( const QList<QPointF>& controlPolygon, double t );
static double bernsteinPoly( int n, int i, double t );
static int lower( int n, int i );
static double power( double a, int b );
static int faculty( int n );
};

#endif // QGSDXFPAINTENGINE_H