mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
copy/paste: try to convert geometries
This commit is contained in:
parent
3a317a061e
commit
643e59a23d
@ -356,6 +356,14 @@ class QgsGeometry
|
||||
*/
|
||||
QString exportToGeoJSON() const;
|
||||
|
||||
/** try to convert the geometry to the requested type
|
||||
* @param destType the geometry type to be converted to
|
||||
* @param destMultipart determines if the output geometry will be multipart or not
|
||||
* @return the converted geometry or NULL pointer if the conversion fails.
|
||||
* @note added in 2.2
|
||||
*/
|
||||
QgsGeometry* convertToType( QGis::GeometryType destType, bool destMultipart = false ) /Factory/;
|
||||
|
||||
/* Accessor functions for getting geometry data */
|
||||
|
||||
/** return contents of the geometry as a point
|
||||
|
@ -5580,6 +5580,7 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
|
||||
{
|
||||
features = clipboard()->copyOf( pasteVectorLayer->pendingFields() );
|
||||
}
|
||||
int nTotalFeatures = features.count();
|
||||
|
||||
QHash<int, int> remap;
|
||||
const QgsFields &fields = clipboard()->fields();
|
||||
@ -5594,10 +5595,11 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
|
||||
}
|
||||
|
||||
int dstAttrCount = pasteVectorLayer->pendingFields().count();
|
||||
for ( int i = 0; i < features.size(); i++ )
|
||||
|
||||
QgsFeatureList::iterator featureIt = features.begin();
|
||||
while ( featureIt != features.end() )
|
||||
{
|
||||
QgsFeature &f = features[i];
|
||||
const QgsAttributes &srcAttr = f.attributes();
|
||||
const QgsAttributes &srcAttr = featureIt->attributes();
|
||||
QgsAttributes dstAttr( dstAttrCount );
|
||||
|
||||
for ( int src = 0; src < srcAttr.count(); ++src )
|
||||
@ -5617,17 +5619,54 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
|
||||
dstAttr[ dst ] = srcAttr[ src ];
|
||||
}
|
||||
|
||||
f.setAttributes( dstAttr );
|
||||
featureIt->setAttributes( dstAttr );
|
||||
|
||||
//avoid intersection if enabled in digitize settings
|
||||
if ( f.geometry() )
|
||||
if ( featureIt->geometry() )
|
||||
{
|
||||
f.geometry()->avoidIntersections();
|
||||
// convert geometry to match destination layer
|
||||
QgsGeometry* newGeometry = featureIt->geometry()->convertToType( pasteVectorLayer->geometryType(), QGis::isMultiType( pasteVectorLayer->wkbType() ) );
|
||||
if ( newGeometry )
|
||||
{
|
||||
// avoid intersection if enabled in digitize settings
|
||||
featureIt->setGeometry( newGeometry );
|
||||
featureIt->geometry()->avoidIntersections();
|
||||
++featureIt;
|
||||
}
|
||||
else
|
||||
{
|
||||
featureIt = features.erase( featureIt );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++featureIt;
|
||||
}
|
||||
}
|
||||
|
||||
pasteVectorLayer->addFeatures( features );
|
||||
pasteVectorLayer->endEditCommand();
|
||||
|
||||
int nCopiedFeatures = features.count();
|
||||
if ( nCopiedFeatures == 0 )
|
||||
{
|
||||
messageBar()->pushMessage( tr( "Paste features" ),
|
||||
tr( "no features could be successfully pasted." ),
|
||||
QgsMessageBar::WARNING , messageTimeout() );
|
||||
|
||||
}
|
||||
else if ( nCopiedFeatures == nTotalFeatures )
|
||||
{
|
||||
messageBar()->pushMessage( tr( "Paste features" ),
|
||||
tr( "%1 features were successfully pasted." ).arg( nCopiedFeatures ),
|
||||
QgsMessageBar::INFO , messageTimeout() );
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBar()->pushMessage( tr( "Paste features" ),
|
||||
tr( "%1 of %2 features could be successfully pasted." ).arg( nCopiedFeatures ).arg( nTotalFeatures ),
|
||||
QgsMessageBar::WARNING , messageTimeout() );
|
||||
}
|
||||
|
||||
mMapCanvas->refresh();
|
||||
}
|
||||
|
||||
|
@ -4423,6 +4423,24 @@ bool QgsGeometry::exportGeosToWkb() const
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsGeometry* QgsGeometry::convertToType( QGis::GeometryType destType, bool destMultipart )
|
||||
{
|
||||
switch ( destType )
|
||||
{
|
||||
case QGis::Point:
|
||||
return convertToPoint( destMultipart );
|
||||
|
||||
case QGis::Line:
|
||||
return convertToLine( destMultipart );
|
||||
|
||||
case QGis::Polygon:
|
||||
return convertToPolygon( destMultipart );
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsGeometry::convertToMultiType()
|
||||
{
|
||||
// TODO: implement with GEOS
|
||||
@ -5976,3 +5994,318 @@ double QgsGeometry::leftOf( double x, double y, double& x1, double& y1, double&
|
||||
double f4 = x2 - x1;
|
||||
return f1*f2 - f3*f4;
|
||||
}
|
||||
|
||||
QgsGeometry* QgsGeometry::convertToPoint( bool destMultipart )
|
||||
{
|
||||
switch ( type() )
|
||||
{
|
||||
case QGis::Point:
|
||||
{
|
||||
bool srcIsMultipart = isMultipart();
|
||||
|
||||
if (( destMultipart && srcIsMultipart ) ||
|
||||
( !destMultipart && !srcIsMultipart ) )
|
||||
{
|
||||
// return a copy of the same geom
|
||||
return new QgsGeometry( *this );
|
||||
}
|
||||
if ( destMultipart )
|
||||
{
|
||||
// layer is multipart => make a multipoint with a single point
|
||||
return fromMultiPoint( QgsMultiPoint() << asPoint() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// destination is singlepart => make a single part if possible
|
||||
QgsMultiPoint multiPoint = asMultiPoint();
|
||||
if ( multiPoint.count() == 1 )
|
||||
{
|
||||
return fromPoint( multiPoint[0] );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case QGis::Line:
|
||||
{
|
||||
// only possible if destination is multipart
|
||||
if ( !destMultipart )
|
||||
return 0;
|
||||
|
||||
// input geometry is multipart
|
||||
if ( isMultipart() )
|
||||
{
|
||||
QgsMultiPolyline multiLine = asMultiPolyline();
|
||||
QgsMultiPoint multiPoint;
|
||||
for ( QgsMultiPolyline::const_iterator multiLineIt = multiLine.constBegin(); multiLineIt != multiLine.constEnd(); ++multiLineIt )
|
||||
for ( QgsPolyline::const_iterator lineIt = ( *multiLineIt ).constBegin(); lineIt != ( *multiLineIt ).constEnd(); ++lineIt )
|
||||
multiPoint << *lineIt;
|
||||
return fromMultiPoint( multiPoint );
|
||||
}
|
||||
// input geometry is not multipart: copy directly the line into a multipoint
|
||||
else
|
||||
{
|
||||
QgsPolyline line = asPolyline();
|
||||
if ( !line.isEmpty() )
|
||||
return fromMultiPoint( line );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case QGis::Polygon:
|
||||
{
|
||||
// can only transfrom if destination is multipoint
|
||||
if ( !destMultipart )
|
||||
return 0;
|
||||
|
||||
// input geometry is multipart: make a multipoint from multipolygon
|
||||
if ( isMultipart() )
|
||||
{
|
||||
QgsMultiPolygon multiPolygon = asMultiPolygon();
|
||||
QgsMultiPoint multiPoint;
|
||||
for ( QgsMultiPolygon::const_iterator polygonIt = multiPolygon.constBegin(); polygonIt != multiPolygon.constEnd(); ++polygonIt )
|
||||
for ( QgsMultiPolyline::const_iterator multiLineIt = ( *polygonIt ).constBegin(); multiLineIt != ( *polygonIt ).constEnd(); ++multiLineIt )
|
||||
for ( QgsPolyline::const_iterator lineIt = ( *multiLineIt ).constBegin(); lineIt != ( *multiLineIt ).constEnd(); ++lineIt )
|
||||
multiPoint << *lineIt;
|
||||
return fromMultiPoint( multiPoint );
|
||||
}
|
||||
// input geometry is not multipart: make a multipoint from polygon
|
||||
else
|
||||
{
|
||||
QgsPolygon polygon = asPolygon();
|
||||
QgsMultiPoint multiPoint;
|
||||
for ( QgsMultiPolyline::const_iterator multiLineIt = polygon.constBegin(); multiLineIt != polygon.constEnd(); ++multiLineIt )
|
||||
for ( QgsPolyline::const_iterator lineIt = ( *multiLineIt ).constBegin(); lineIt != ( *multiLineIt ).constEnd(); ++lineIt )
|
||||
multiPoint << *lineIt;
|
||||
return fromMultiPoint( multiPoint );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QgsGeometry* QgsGeometry::convertToLine( bool destMultipart )
|
||||
{
|
||||
switch ( type() )
|
||||
{
|
||||
case QGis::Point:
|
||||
{
|
||||
if ( !isMultipart() )
|
||||
return 0;
|
||||
|
||||
QgsMultiPoint multiPoint = asMultiPoint();
|
||||
if ( multiPoint.count() < 2 )
|
||||
return 0;
|
||||
|
||||
if ( destMultipart )
|
||||
return fromMultiPolyline( QgsMultiPolyline() << multiPoint );
|
||||
else
|
||||
return fromPolyline( multiPoint );
|
||||
}
|
||||
|
||||
case QGis::Line:
|
||||
{
|
||||
bool srcIsMultipart = isMultipart();
|
||||
|
||||
if (( destMultipart && srcIsMultipart ) ||
|
||||
( !destMultipart && ! srcIsMultipart ) )
|
||||
{
|
||||
// return a copy of the same geom
|
||||
return new QgsGeometry( *this );
|
||||
}
|
||||
if ( destMultipart )
|
||||
{
|
||||
// destination is multipart => makes a multipoint with a single line
|
||||
QgsPolyline line = asPolyline();
|
||||
if ( !line.isEmpty() )
|
||||
return fromMultiPolyline( QgsMultiPolyline() << line );
|
||||
}
|
||||
else
|
||||
{
|
||||
// destination is singlepart => make a single part if possible
|
||||
QgsMultiPolyline multiLine = asMultiPolyline();
|
||||
if ( multiLine.count() == 1 )
|
||||
return fromPolyline( multiLine[0] );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case QGis::Polygon:
|
||||
{
|
||||
// input geometry is multipolygon
|
||||
if ( isMultipart() )
|
||||
{
|
||||
QgsMultiPolygon multiPolygon = asMultiPolygon();
|
||||
QgsMultiPolyline multiLine;
|
||||
for ( QgsMultiPolygon::const_iterator polygonIt = multiPolygon.constBegin(); polygonIt != multiPolygon.constEnd(); ++polygonIt )
|
||||
for ( QgsMultiPolyline::const_iterator multiLineIt = ( *polygonIt ).constBegin(); multiLineIt != ( *polygonIt ).constEnd(); ++multiLineIt )
|
||||
multiLine << *multiLineIt;
|
||||
|
||||
if ( destMultipart )
|
||||
{
|
||||
// destination is multipart
|
||||
return fromMultiPolyline( multiLine );
|
||||
}
|
||||
else if ( multiLine.count() == 1 )
|
||||
{
|
||||
// destination is singlepart => make a single part if possible
|
||||
return fromPolyline( multiLine[0] );
|
||||
}
|
||||
}
|
||||
// input geometry is single polygon
|
||||
else
|
||||
{
|
||||
QgsPolygon polygon = asPolygon();
|
||||
// if polygon has rings
|
||||
if ( polygon.count() > 1 )
|
||||
{
|
||||
// cannot fit a polygon with rings in a single line layer
|
||||
// TODO: would it be better to remove rings?
|
||||
if ( destMultipart )
|
||||
{
|
||||
QgsPolygon polygon = asPolygon();
|
||||
QgsMultiPolyline multiLine;
|
||||
for ( QgsMultiPolyline::const_iterator multiLineIt = polygon.constBegin(); multiLineIt != polygon.constEnd(); ++multiLineIt )
|
||||
multiLine << *multiLineIt;
|
||||
return fromMultiPolyline( multiLine );
|
||||
}
|
||||
}
|
||||
// no rings
|
||||
else if ( polygon.count() == 1 )
|
||||
{
|
||||
if ( destMultipart )
|
||||
{
|
||||
return fromMultiPolyline( polygon );
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromPolyline( polygon[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QgsGeometry* QgsGeometry::convertToPolygon( bool destMultipart )
|
||||
{
|
||||
switch ( type() )
|
||||
{
|
||||
case QGis::Point:
|
||||
{
|
||||
if ( !isMultipart() )
|
||||
return 0;
|
||||
|
||||
QgsMultiPoint multiPoint = asMultiPoint();
|
||||
if ( multiPoint.count() < 3 )
|
||||
return 0;
|
||||
|
||||
if ( multiPoint.last() != multiPoint.first() )
|
||||
multiPoint << multiPoint.first();
|
||||
|
||||
QgsPolygon polygon = QgsPolygon() << multiPoint;
|
||||
if ( destMultipart )
|
||||
return fromMultiPolygon( QgsMultiPolygon() << polygon );
|
||||
else
|
||||
return fromPolygon( polygon );
|
||||
}
|
||||
|
||||
case QGis::Line:
|
||||
{
|
||||
// input geometry is multiline
|
||||
if ( isMultipart() )
|
||||
{
|
||||
QgsMultiPolyline multiLine = asMultiPolyline();
|
||||
QgsMultiPolygon multiPolygon;
|
||||
for ( QgsMultiPolyline::iterator multiLineIt = multiLine.begin(); multiLineIt != multiLine.end(); ++multiLineIt )
|
||||
{
|
||||
// do not create polygon for a 1 segment line
|
||||
// this does not consider the special case where line has 2 segments with first and last node identical
|
||||
if (( *multiLineIt ).count() < 3 )
|
||||
continue;
|
||||
|
||||
// add closing node
|
||||
if (( *multiLineIt ).first() != ( *multiLineIt ).last() )
|
||||
*multiLineIt << ( *multiLineIt ).first();
|
||||
multiPolygon << ( QgsPolygon() << *multiLineIt );
|
||||
}
|
||||
// check that polygons were inserted
|
||||
if ( !multiPolygon.isEmpty() )
|
||||
{
|
||||
if ( destMultipart )
|
||||
{
|
||||
return fromMultiPolygon( multiPolygon );
|
||||
}
|
||||
else if ( multiPolygon.count() == 1 )
|
||||
{
|
||||
// destination is singlepart => make a single part if possible
|
||||
return fromPolygon( multiPolygon[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
// input geometry is single line
|
||||
else
|
||||
{
|
||||
QgsPolyline line = asPolyline();
|
||||
|
||||
// do not create polygon for a 1 segment line
|
||||
if ( line.count() >= 3 )
|
||||
{
|
||||
// add closing node
|
||||
if ( line.first() != line.last() )
|
||||
line << line.first();
|
||||
|
||||
// destination is multipart
|
||||
if ( destMultipart )
|
||||
{
|
||||
return fromMultiPolygon( QgsMultiPolygon() << ( QgsPolygon() << line ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromPolygon( QgsPolygon() << line );
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case QGis::Polygon:
|
||||
{
|
||||
bool srcIsMultipart = isMultipart();
|
||||
|
||||
if (( destMultipart && srcIsMultipart ) ||
|
||||
( !destMultipart && ! srcIsMultipart ) )
|
||||
{
|
||||
// return a copy of the same geom
|
||||
return new QgsGeometry( *this );
|
||||
}
|
||||
if ( destMultipart )
|
||||
{
|
||||
// destination is multipart => makes a multipoint with a single polygon
|
||||
QgsPolygon polygon = asPolygon();
|
||||
if ( !polygon.isEmpty() )
|
||||
return fromMultiPolygon( QgsMultiPolygon() << polygon );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMultiPolygon multiPolygon = asMultiPolygon();
|
||||
if ( multiPolygon.count() == 1 )
|
||||
{
|
||||
// destination is singlepart => make a single part if possible
|
||||
return fromPolygon( multiPolygon[0] );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -397,6 +397,15 @@ class CORE_EXPORT QgsGeometry
|
||||
*/
|
||||
QString exportToGeoJSON() const;
|
||||
|
||||
/** try to convert the geometry to the requested type
|
||||
* @param destType the geometry type to be converted to
|
||||
* @param destMultipart determines if the output geometry will be multipart or not
|
||||
* @return the converted geometry or NULL pointer if the conversion fails.
|
||||
* @note added in 2.2
|
||||
*/
|
||||
QgsGeometry* convertToType( QGis::GeometryType destType, bool destMultipart = false );
|
||||
|
||||
|
||||
/* Accessor functions for getting geometry data */
|
||||
|
||||
/** return contents of the geometry as a point
|
||||
@ -611,6 +620,13 @@ class CORE_EXPORT QgsGeometry
|
||||
static inline bool moveVertex( QgsWkbPtr &wkbPtr, const double &x, const double &y, int atVertex, bool hasZValue, int &pointIndex, bool isRing );
|
||||
static inline bool deleteVertex( QgsConstWkbPtr &srcPtr, QgsWkbPtr &dstPtr, int atVertex, bool hasZValue, int &pointIndex, bool isRing, bool lastItem );
|
||||
static inline bool insertVertex( QgsConstWkbPtr &srcPtr, QgsWkbPtr &dstPtr, int beforeVertex, const double &x, const double &y, bool hasZValue, int &pointIndex, bool isRing );
|
||||
|
||||
/** try to convert the geometry to a point */
|
||||
QgsGeometry* convertToPoint( bool destMultipart );
|
||||
/** try to convert the geometry to a line */
|
||||
QgsGeometry* convertToLine( bool destMultipart );
|
||||
/** try to convert the geometry to a polygon */
|
||||
QgsGeometry* convertToPolygon( bool destMultipart );
|
||||
}; // class QgsGeometry
|
||||
|
||||
Q_DECLARE_METATYPE( QgsGeometry );
|
||||
|
Loading…
x
Reference in New Issue
Block a user