400 changes: 204 additions & 196 deletions src/app/nodetool/qgsmaptoolnodetool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,6 @@ QgsMapToolNodeTool::~QgsMapToolNodeTool()
removeRubberBands();
}

void QgsMapToolNodeTool::deactivate()
{
removeRubberBands();

delete mSelectedFeature;
mSelectedFeature = 0;

mRubberBand = 0;
mSelectAnother = false;
mCtrl = false;
mMoving = true;
mClicked = false;

QgsMapTool::deactivate();
}

void QgsMapToolNodeTool::createMovingRubberBands()
{
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
Expand Down Expand Up @@ -129,52 +113,6 @@ void QgsMapToolNodeTool::createMovingRubberBands()
}
}

QgsRubberBand* QgsMapToolNodeTool::createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer )
{
// create rubberband marker for moving points
QgsRubberBand* marker = new QgsRubberBand( mCanvas, true );
marker->setColor( Qt::red );
marker->setWidth( 2 );
double movement = 4;
double s = QgsTolerance::toleranceInMapUnits( movement, vlayer, mCanvas->mapRenderer(), QgsTolerance::Pixels );
QgsPoint pom = toMapCoordinates( vlayer, center );
pom.setX( pom.x() - s );
pom.setY( pom.y() - s );
marker->addPoint( pom );
pom.setX( pom.x() + 2*s );
marker->addPoint( pom );
pom.setY( pom.y() + 2*s );
marker->addPoint( pom );
pom.setX( pom.x() - 2*s );
marker->addPoint( pom );
pom.setY( pom.y() - 2*s );
marker->addPoint( pom );
return marker;
}

void QgsMapToolNodeTool::removeRubberBands()
{
// cleanup rubberbands and list
foreach( QgsRubberBand *rb, mRubberBands )
{
delete rb;
}
mRubberBands.clear();

foreach( QgsRubberBand *rb, mTopologyRubberBand )
{
delete rb;
}
mTopologyRubberBand.clear();

mTopologyMovingVertexes.clear();
mTopologyRubberBandVertexes.clear();

// remove all data from selected feature (no change to rubberbands itself)
if ( mSelectedFeature )
mSelectedFeature->cleanRubberBandsData();
}

void QgsMapToolNodeTool::createTopologyRubberBands( QgsVectorLayer* vlayer, const QList<QgsVertexEntry*> &vertexMap, int vertex )
{
QMultiMap<double, QgsSnappingResult> currentResultList;
Expand Down Expand Up @@ -281,10 +219,123 @@ void QgsMapToolNodeTool::createTopologyRubberBands( QgsVectorLayer* vlayer, cons
}
}

void QgsMapToolNodeTool::selectedFeatureDestroyed()
void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
{
QgsDebugMsg( "Entered." );
mSelectedFeature = 0;
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
if ( !mSelectedFeature || !vlayer || !mClicked )
return;

if ( !vlayer )
return;

mSelectAnother = false;
if ( mMoving )
{
// create rubberband if none exists
if ( mRubberBands.empty() )
{
if ( mIsPoint )
{
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( vertexMap[i]->isSelected() )
{
QgsRubberBand* rb = createRubberBandMarker( vertexMap[i]->point(), vlayer );
mRubberBands.append( rb );
}
}
}
createMovingRubberBands();
QList<QgsSnappingResult> snapResults;
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
mPosMapCoordBackup = posMapCoord;
}
else
{
// move rubberband
QList<QgsSnappingResult> snapResults;
QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
QList<QgsPoint> excludePoints;
excludePoints.append( mClosestVertex );
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, excludePoints );
// get correct coordinates to move
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
if ( snapResults.size() > 0 )
{
firstCoords = toMapCoordinates( vlayer, mClosestVertex );
}

// special handling of points
if ( mIsPoint )
{
double offsetX = posMapCoord.x() - firstCoords.x();
double offsetY = posMapCoord.y() - firstCoords.y();
for ( int i = 0; i < mRubberBands.size(); i++ )
{
mRubberBands[i]->setTranslationOffset( offsetX, offsetY );
}
return;
}

// move points
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{

if ( vertexMap[i]->isSelected() )
{
QgsPoint mapCoords = toMapCoordinates( vlayer, vertexMap[i]->point() );
double x = mapCoords.x() + posMapCoord.x() - firstCoords.x();
double y = mapCoords.y() + posMapCoord.y() - firstCoords.y();

mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), QgsPoint( x, y ) );
if ( vertexMap[i]->rubberBandIndex() == 0 )
{
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, QgsPoint( x, y ) );
}
}
}

// topological editing
double offsetX = posMapCoord.x() - mPosMapCoordBackup.x();
double offsetY = posMapCoord.y() - mPosMapCoordBackup.y();
for ( int i = 0; i < mTopologyRubberBand.size(); i++ )
{
for ( int pointIndex = 0; pointIndex < mTopologyRubberBand[i]->numberOfVertices() - 1; pointIndex++ )
{
if ( mTopologyRubberBandVertexes[i]->contains( pointIndex ) )
{
const QgsPoint* point = mTopologyRubberBand[i]->getPoint( 0, pointIndex );
if ( point == 0 )
{
break;
}
mTopologyRubberBand[i]->movePoint( pointIndex, QgsPoint( point->x() + offsetX, point->y() + offsetY ) );
if ( pointIndex == 0 )
{
mTopologyRubberBand[i]->movePoint( pointIndex , QgsPoint( point->x() + offsetX, point->y() + offsetY ) );
}
}
}
}
mPosMapCoordBackup = posMapCoord;
}
}
else
{
if ( !mSelectionRectangle )
{
mSelectionRectangle = true;
mRubberBand = new QRubberBand( QRubberBand::Rectangle, mCanvas );
mRect = new QRect();
mRect->setTopLeft( QPoint( mLastCoordinates->x(), mLastCoordinates->y() ) );
}
mRect->setBottomRight( e->pos() );
QRect normalizedRect = mRect->normalized();
mRubberBand->setGeometry( normalizedRect );
mRubberBand->show();
}
}

void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
Expand All @@ -293,8 +344,7 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

mClicked = true;
mLastCoordinates = QgsPoint( e->pos().x(), e->pos().y() );

mLastCoordinates = new QgsPoint( e->pos().x(), e->pos().y() );
QList<QgsSnappingResult> snapResults;
if ( !mSelectedFeature )
{
Expand All @@ -314,14 +364,13 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
else
{
// some feature already selected
QgsPoint mapPoint = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
QgsPoint layerPoint = toLayerCoordinates( vlayer, mapPoint );
QgsPoint mapCoordPoint = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
double tol = QgsTolerance::vertexSearchRadius( vlayer, mCanvas->mapRenderer() );

// get geometry and find if snapping is near it
int atVertex, beforeVertex, afterVertex;
double dist;
QgsPoint closestPoint = mSelectedFeature->geometry()->closestVertex( layerPoint, atVertex, beforeVertex, afterVertex, dist );
mSelectedFeature->geometry()->closestVertex( toLayerCoordinates( vlayer, mapCoordPoint ), atVertex, beforeVertex, afterVertex, dist );
dist = sqrt( dist );

mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex, tol );
Expand All @@ -330,9 +379,7 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
// for points only selecting another feature
// no vertexes found (selecting or inverting selection) if move
// or select another feature if clicked there
if( !mIsPoint )
mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToSegment, tol );

mSnapper.snapToCurrentLayer( e->pos(), snapResults, mIsPoint ? QgsSnapper::SnapToVertex : QgsSnapper::SnapToSegment, tol );
if ( snapResults.size() > 0 )
{
// need to check all if there is a point in my selected feature
Expand All @@ -354,7 +401,8 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
if ( !mSelectAnother )
{
mMoving = true;
mClosestVertex = closestPoint;
QgsPoint point = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
mClosestVertex = closestVertex( toLayerCoordinates( vlayer, point ) );

if ( mIsPoint )
{
Expand All @@ -368,7 +416,8 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
mSelectedFeature->invertVertexSelection( snapResult.snappedVertexNr );
}
}
else
else if ( !mSelectedFeature->isSelected( snapResult.beforeVertexNr ) ||
!mSelectedFeature->isSelected( snapResult.afterVertexNr ) )
{
if ( !mCtrl )
{
Expand All @@ -393,7 +442,8 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
{
// some vertex selected
mMoving = true;
mClosestVertex = closestPoint;
QgsPoint point = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
mClosestVertex = closestVertex( toLayerCoordinates( vlayer, point ) );
if ( mMoving )
{
if ( mCtrl )
Expand All @@ -417,124 +467,10 @@ void QgsMapToolNodeTool::canvasPressEvent( QMouseEvent * e )
QgsDebugMsg( "Leaving." );
}

void QgsMapToolNodeTool::canvasMoveEvent( QMouseEvent * e )
void QgsMapToolNodeTool::selectedFeatureDestroyed()
{
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
if ( !mSelectedFeature || !vlayer || !mClicked )
return;

if ( !vlayer )
return;

mSelectAnother = false;
if ( mMoving )
{
// create rubberband if none exists
if ( mRubberBands.empty() )
{
if ( mIsPoint )
{
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{
if ( vertexMap[i]->isSelected() )
{
QgsRubberBand* rb = createRubberBandMarker( vertexMap[i]->point(), vlayer );
mRubberBands.append( rb );
}
}
}
createMovingRubberBands();
QList<QgsSnappingResult> snapResults;
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
mPosMapCoordBackup = posMapCoord;
}
else
{
// move rubberband
QList<QgsSnappingResult> snapResults;
QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates.x(), mLastCoordinates.y() );

QList<QgsPoint> excludePoints;
excludePoints.append( mClosestVertex );

mSnapper.snapToBackgroundLayers( e->pos(), snapResults, excludePoints );

// get correct coordinates to move
QgsPoint posMapCoord = snapPointFromResults( snapResults, e->pos() );
if ( snapResults.size() > 0 )
{
firstCoords = toMapCoordinates( vlayer, mClosestVertex );
}

QgsVector offset = posMapCoord - firstCoords;

// special handling of points
if ( mIsPoint )
{
for ( int i = 0; i < mRubberBands.size(); i++ )
{
mRubberBands[i]->setTranslationOffset( offset.x(), offset.y() );
}
return;
}

// move points
QList<QgsVertexEntry*> &vertexMap = mSelectedFeature->vertexMap();
for ( int i = 0; i < vertexMap.size(); i++ )
{

if ( vertexMap[i]->isSelected() )
{
QgsPoint mapCoord = toMapCoordinates( vlayer, vertexMap[i]->point() ) + offset;

mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( vertexMap[i]->rubberBandIndex(), mapCoord );
if ( vertexMap[i]->rubberBandIndex() == 0 )
{
mRubberBands[vertexMap[i]->rubberBandNr()]->movePoint( 0, mapCoord );
}
}
}

// topological editing
offset = posMapCoord - mPosMapCoordBackup;

for ( int i = 0; i < mTopologyRubberBand.size(); i++ )
{
for ( int pointIndex = 0; pointIndex < mTopologyRubberBand[i]->numberOfVertices() - 1; pointIndex++ )
{
if ( mTopologyRubberBandVertexes[i]->contains( pointIndex ) )
{
const QgsPoint* point = mTopologyRubberBand[i]->getPoint( 0, pointIndex );
if ( point == 0 )
{
break;
}
mTopologyRubberBand[i]->movePoint( pointIndex, *point + offset );
if ( pointIndex == 0 )
{
mTopologyRubberBand[i]->movePoint( pointIndex , *point + offset );
}
}
}
}
mPosMapCoordBackup = posMapCoord;
}
}
else
{
if ( !mSelectionRectangle )
{
mSelectionRectangle = true;
mRubberBand = new QRubberBand( QRubberBand::Rectangle, mCanvas );
mRect = new QRect();
mRect->setTopLeft( QPoint( mLastCoordinates.x(), mLastCoordinates.y() ) );
}
mRect->setBottomRight( e->pos() );
QRect normalizedRect = mRect->normalized();
mRubberBand->setGeometry( normalizedRect );
mRubberBand->show();
}
QgsDebugMsg( "Entered." );
mSelectedFeature = 0;
}

void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
Expand All @@ -553,15 +489,15 @@ void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
mSelectionRectangle = false;
QgsPoint coords = toMapCoordinates( e->pos() );

QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates.x(), mLastCoordinates.y() );
QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
if ( mRubberBand )
{
mRubberBand->close();
delete mRubberBand;
mRubberBand = 0;
}

if ( mLastCoordinates.x() == e->pos().x() && mLastCoordinates.y() == e->pos().y() )
if ( mLastCoordinates->x() == e->pos().x() && mLastCoordinates->y() == e->pos().y() )
{
if ( mSelectAnother )
{
Expand Down Expand Up @@ -606,7 +542,7 @@ void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
{
mMoving = false;
QList<QgsSnappingResult> snapResults;
QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates.x(), mLastCoordinates.y() );
QgsPoint firstCoords = mCanvas->getCoordinateTransform()->toMapPoint( mLastCoordinates->x(), mLastCoordinates->y() );
QList<QgsPoint> excludePoints;
excludePoints.append( mClosestVertex );
mSnapper.snapToBackgroundLayers( e->pos(), snapResults, excludePoints );
Expand Down Expand Up @@ -659,6 +595,46 @@ void QgsMapToolNodeTool::canvasReleaseEvent( QMouseEvent * e )
mExcludePoint.clear();
}

void QgsMapToolNodeTool::deactivate()
{
removeRubberBands();

delete mSelectedFeature;
mSelectedFeature = 0;

mRubberBand = 0;
mSelectAnother = false;
mCtrl = false;
mMoving = true;
mClicked = false;

QgsMapTool::deactivate();
}

void QgsMapToolNodeTool::removeRubberBands()
{
// cleanup rubberbands and list
foreach( QgsRubberBand *rb, mRubberBands )
{
delete rb;
}
mRubberBands.clear();

foreach( QgsRubberBand *rb, mTopologyRubberBand )
{
delete rb;
}
mTopologyRubberBand.clear();

mTopologyMovingVertexes.clear();
mTopologyRubberBandVertexes.clear();

// remove all data from selected feature (no change to rubberbands itself)
if ( mSelectedFeature )
mSelectedFeature->cleanRubberBandsData();
}


void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
Expand Down Expand Up @@ -710,6 +686,15 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
mCanvas->refresh();
}

QgsPoint QgsMapToolNodeTool::closestVertex( QgsPoint point )
{
int at;
int before;
int after;
double dist;
return mSelectedFeature->geometry()->closestVertex( point, at, before, after, dist );
}

void QgsMapToolNodeTool::keyPressEvent( QKeyEvent* e )
{
if ( e->key() == Qt::Key_Control )
Expand All @@ -732,3 +717,26 @@ void QgsMapToolNodeTool::keyReleaseEvent( QKeyEvent* e )
mCanvas->refresh();
}
}

QgsRubberBand* QgsMapToolNodeTool::createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer )
{
// create rubberband marker for moving points
QgsRubberBand* marker = new QgsRubberBand( mCanvas, true );
marker->setColor( Qt::red );
marker->setWidth( 2 );
double movement = 4;
double s = QgsTolerance::toleranceInMapUnits( movement, vlayer, mCanvas->mapRenderer(), QgsTolerance::Pixels );
QgsPoint pom = toMapCoordinates( vlayer, center );
pom.setX( pom.x() - s );
pom.setY( pom.y() - s );
marker->addPoint( pom );
pom.setX( pom.x() + 2*s );
marker->addPoint( pom );
pom.setY( pom.y() + 2*s );
marker->addPoint( pom );
pom.setX( pom.x() - 2*s );
marker->addPoint( pom );
pom.setY( pom.y() - 2*s );
marker->addPoint( pom );
return marker;
}
7 changes: 6 additions & 1 deletion src/app/nodetool/qgsmaptoolnodetool.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ class QgsMapToolNodeTool: public QgsMapToolVertexEdit
//! called when map tool is being deactivated
void deactivate();

/**
* Returns closest vertex to given point from selected feature
*/
QgsPoint closestVertex( QgsPoint point );

public slots:
void selectedFeatureDestroyed();

Expand Down Expand Up @@ -127,7 +132,7 @@ class QgsMapToolNodeTool: public QgsMapToolVertexEdit
QgsFeatureId mAnother;

/** stored position of last press down action to count how much vertexes should be moved */
QgsPoint mLastCoordinates;
QgsPoint* mLastCoordinates;

/** closest vertex to click */
QgsPoint mClosestVertex;
Expand Down
108 changes: 28 additions & 80 deletions src/core/qgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,12 +578,12 @@ void QgsGeometry::fromWkb( unsigned char * wkb, size_t length )
mDirtyGeos = true;
}

unsigned char * QgsGeometry::asWkb( QGis::GeometryType requestedType )
unsigned char * QgsGeometry::asWkb()
{
if ( mDirtyWkb || (requestedType!=QGis::UnknownGeometry && requestedType!=type()) )
if ( mDirtyWkb )
{
// convert from GEOS
exportGeosToWkb( requestedType );
exportGeosToWkb();
}

return mGeometry;
Expand Down Expand Up @@ -4725,7 +4725,7 @@ bool QgsGeometry::exportWkbToGeos()
return true;
}

bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
bool QgsGeometry::exportGeosToWkb()
{
//QgsDebugMsg("entered.");
if ( !mDirtyWkb )
Expand All @@ -4751,27 +4751,7 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
// set up byteOrder
char byteOrder = QgsApplication::endian();

int type = GEOSGeomTypeId( mGeos );

if( type == GEOS_GEOMETRYCOLLECTION )
{
switch( geomType )
{
case QGis::Point:
type = GEOS_MULTIPOINT;
break;
case QGis::Line:
type = GEOS_MULTILINESTRING;
break;
case QGis::Polygon:
type = GEOS_MULTIPOLYGON;
break;
default:
break;
}
}

switch ( type )
switch ( GEOSGeomTypeId( mGeos ) )
{
case GEOS_POINT: // a point
{
Expand Down Expand Up @@ -4943,25 +4923,13 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )

case GEOS_MULTIPOINT: // a collection of points
{
QList<const GEOSGeometry *> points;

// determine size of geometry
int geometrySize = 1 + 2 * sizeof( int );
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
const GEOSGeometry *point = GEOSGetGeometryN( mGeos, i );
if( GEOSGeomTypeId( point ) != GEOS_POINT )
continue;
points << point;
geometrySize += 1 + sizeof( int ) + 2 * sizeof( double );
}

if ( points.size() == 0 )
{
QgsMessageLog::logMessage( "Empty multipolygon skipped." );
return false;
}

mGeometry = new unsigned char[geometrySize];
mGeometrySize = geometrySize;
int wkbPosition = 0; //current position in the byte array
Expand All @@ -4971,21 +4939,24 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
int wkbtype = QGis::WKBMultiPoint;
memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) );
wkbPosition += sizeof( int );
int numPoints = points.size();
int numPoints = GEOSGetNumGeometries( mGeos );
memcpy( &mGeometry[wkbPosition], &numPoints, sizeof( int ) );
wkbPosition += sizeof( int );

int pointType = QGis::WKBPoint;
const GEOSGeometry *currentPoint = 0;

foreach( const GEOSGeometry *point, points )
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
//copy endian and point type
memcpy( &mGeometry[wkbPosition], &byteOrder, 1 );
wkbPosition += 1;
memcpy( &mGeometry[wkbPosition], &pointType, sizeof( int ) );
wkbPosition += sizeof( int );

const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( point );
currentPoint = GEOSGetGeometryN( mGeos, i );

const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( currentPoint );

GEOSCoordSeq_getX( cs, 0, ( double* )&mGeometry[wkbPosition] );
wkbPosition += sizeof( double );
Expand All @@ -4998,25 +4969,12 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )

case GEOS_MULTILINESTRING: // a collection of linestrings
{
QList<const GEOSGeometry *> linestrings;

// determine size of geometry
int geometrySize = 1 + 2 * sizeof( int );
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
const GEOSGeometry *linestring = GEOSGetGeometryN( mGeos, i );
if( GEOSGeomTypeId( linestring ) != GEOS_LINESTRING )
continue;

linestrings << linestring;
geometrySize += 1 + 2 * sizeof( int );
geometrySize += getNumGeosPoints( linestring ) * 2 * sizeof( double );
}

if ( linestrings.size() == 0 )
{
QgsMessageLog::logMessage( "Empty multilinestring skipped." );
return false;
geometrySize += getNumGeosPoints( GEOSGetGeometryN( mGeos, i ) ) * 2 * sizeof( double );
}

mGeometry = new unsigned char[geometrySize];
Expand All @@ -5028,7 +4986,7 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
int wkbtype = QGis::WKBMultiLineString;
memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) );
wkbPosition += sizeof( int );
int numLines = linestrings.size();
int numLines = GEOSGetNumGeometries( mGeos );
memcpy( &mGeometry[wkbPosition], &numLines, sizeof( int ) );
wkbPosition += sizeof( int );

Expand All @@ -5037,15 +4995,15 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
const GEOSCoordSequence *cs = 0;
unsigned int lineSize;

foreach( const GEOSGeometry *linestring, linestrings )
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
//endian and type WKBLineString
memcpy( &mGeometry[wkbPosition], &byteOrder, 1 );
wkbPosition += 1;
memcpy( &mGeometry[wkbPosition], &lineType, sizeof( int ) );
wkbPosition += sizeof( int );

cs = GEOSGeom_getCoordSeq( linestring );
cs = GEOSGeom_getCoordSeq( GEOSGetGeometryN( mGeos, i ) );

//line size
GEOSCoordSeq_getSize( cs, &lineSize );
Expand All @@ -5067,38 +5025,26 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )

case GEOS_MULTIPOLYGON: // a collection of polygons
{
QList<const GEOSGeometry *> polygons;

//first determine size of geometry
int geometrySize = 1 + ( 2 * sizeof( int ) ); //endian, type, number of polygons
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
const GEOSGeometry *poly = GEOSGetGeometryN( mGeos, i );
if( GEOSGeomTypeId( poly ) != GEOS_POLYGON )
continue;

polygons << poly;
const GEOSGeometry *thePoly = GEOSGetGeometryN( mGeos, i );
geometrySize += 1 + 2 * sizeof( int ); //endian, type, number of rings
//exterior ring
geometrySize += sizeof( int ); //number of points in exterior ring
const GEOSGeometry *exRing = GEOSGetExteriorRing( poly );
const GEOSGeometry *exRing = GEOSGetExteriorRing( thePoly );
geometrySize += 2 * sizeof( double ) * getNumGeosPoints( exRing );

const GEOSGeometry *intRing = 0;
for ( int j = 0; j < GEOSGetNumInteriorRings( poly ); j++ )
for ( int j = 0; j < GEOSGetNumInteriorRings( thePoly ); j++ )
{
geometrySize += sizeof( int ); //number of points in ring
intRing = GEOSGetInteriorRingN( poly, j );
intRing = GEOSGetInteriorRingN( thePoly, j );
geometrySize += 2 * sizeof( double ) * getNumGeosPoints( intRing );
}
}

if ( polygons.size() == 0 )
{
QgsMessageLog::logMessage( "Empty multipolyon skipped." );
return false;
}

mGeometry = new unsigned char[geometrySize];
mGeometrySize = geometrySize;
int wkbPosition = 0; //current position in the byte array
Expand All @@ -5108,24 +5054,25 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
int wkbtype = QGis::WKBMultiPolygon;
memcpy( &mGeometry[wkbPosition], &wkbtype, sizeof( int ) );
wkbPosition += sizeof( int );
int numPolygons = polygons.size();
int numPolygons = GEOSGetNumGeometries( mGeos );
memcpy( &mGeometry[wkbPosition], &numPolygons, sizeof( int ) );
wkbPosition += sizeof( int );

//loop over polygons
foreach ( const GEOSGeometry *poly, polygons )
for ( int i = 0; i < GEOSGetNumGeometries( mGeos ); i++ )
{
const GEOSGeometry *thePoly = GEOSGetGeometryN( mGeos, i );
memcpy( &mGeometry[wkbPosition], &byteOrder, 1 );
wkbPosition += 1;
int polygonType = QGis::WKBPolygon;
memcpy( &mGeometry[wkbPosition], &polygonType, sizeof( int ) );
wkbPosition += sizeof( int );
int numRings = GEOSGetNumInteriorRings( poly ) + 1;
int numRings = GEOSGetNumInteriorRings( thePoly ) + 1;
memcpy( &mGeometry[wkbPosition], &numRings, sizeof( int ) );
wkbPosition += sizeof( int );

//exterior ring
const GEOSGeometry *theRing = GEOSGetExteriorRing( poly );
const GEOSGeometry *theRing = GEOSGetExteriorRing( thePoly );
int nPointsInRing = getNumGeosPoints( theRing );
memcpy( &mGeometry[wkbPosition], &nPointsInRing, sizeof( int ) );
wkbPosition += sizeof( int );
Expand All @@ -5140,9 +5087,9 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )
}

//interior rings
for ( int j = 0; j < GEOSGetNumInteriorRings( poly ); j++ )
for ( int j = 0; j < GEOSGetNumInteriorRings( thePoly ); j++ )
{
theRing = GEOSGetInteriorRingN( poly, j );
theRing = GEOSGetInteriorRingN( thePoly, j );
nPointsInRing = getNumGeosPoints( theRing );
memcpy( &mGeometry[wkbPosition], &nPointsInRing, sizeof( int ) );
wkbPosition += sizeof( int );
Expand All @@ -5163,7 +5110,8 @@ bool QgsGeometry::exportGeosToWkb( QGis::GeometryType geomType )

case GEOS_GEOMETRYCOLLECTION: // a collection of heterogeneus geometries
{
QgsMessageLog::logMessage( "Geometry collection skipped." );
// TODO
QgsDebugMsg( "geometry collection - not supported" );
break;
} // case GEOS_GEOM::GEOS_GEOMETRYCOLLECTION

Expand Down
6 changes: 3 additions & 3 deletions src/core/qgsgeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class CORE_EXPORT QgsGeometry
Returns the buffer containing this geometry in WKB format.
You may wish to use in conjunction with wkbSize().
*/
unsigned char *asWkb( QGis::GeometryType requestedType = QGis::UnknownGeometry );
unsigned char * asWkb();

/**
Returns the size of the WKB in asWkb().
Expand All @@ -119,7 +119,7 @@ class CORE_EXPORT QgsGeometry

/**Returns a geos geomtry. QgsGeometry keeps ownership, don't delete the returned object!
@note this method was added in version 1.1*/
GEOSGeometry *asGeos();
GEOSGeometry* asGeos();

/** Returns type of wkb (point / linestring / polygon etc.) */
QGis::WkbType wkbType();
Expand Down Expand Up @@ -477,7 +477,7 @@ class CORE_EXPORT QgsGeometry
/** Converts from the GEOS geometry to the WKB geometry.
@return true in case of success and false else
*/
bool exportGeosToWkb( QGis::GeometryType type = QGis::UnknownGeometry );
bool exportGeosToWkb();

/** Insert a new vertex before the given vertex index (first number is index 0)
* in the given GEOS Coordinate Sequence.
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsvectorfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ bool QgsVectorFileWriter::addFeature( QgsFeature& feature )
return false;
}

OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb( QGis::Polygon ), geom->wkbSize() );
OGRErr err = OGR_G_ImportFromWkb( mGeom2, geom->asWkb(), geom->wkbSize() );
if ( err != OGRERR_NONE )
{
QgsDebugMsg( QString( "Failed to import geometry from WKB: %1 (OGR error: %2)" ).arg( err ).arg( CPLGetLastErrorMsg() ) );
Expand Down