28 #include <QProgressDialog>
33 bool onlySelectedFeatures,
54 if ( onlySelectedFeatures )
63 int processedFeatures = 0;
65 for ( ; it != selection.
constEnd(); ++it )
80 simplifyFeature( currentFeature, &vWriter, tolerance );
99 int processedFeatures = 0;
111 simplifyFeature( currentFeature, &vWriter, tolerance );
134 tmpGeometry = featureGeometry->
simplify( tolerance );
159 QgsDebugMsg(
"No data provider for layer passed to centroids" );
170 if ( onlySelectedFeatures )
179 int processedFeatures = 0;
181 for ( ; it != selection.
constEnd(); ++it )
196 centroidFeature( currentFeature, &vWriter );
215 int processedFeatures = 0;
227 centroidFeature( currentFeature, &vWriter );
250 tmpGeometry = featureGeometry->
centroid();
265 bool onlySelectedFeatures,
297 if ( onlySelectedFeatures )
307 double miny = rect.yMinimum();
308 double maxx = rect.xMaximum();
309 double maxy = rect.yMaximum();
310 double height = rect.height();
311 double width = rect.width();
312 double cntx = minx + ( width / 2.0 );
313 double cnty = miny + ( height / 2.0 );
314 double area = width * height;
315 double perim = ( 2 * width ) + ( 2 * height );
331 vWriter.addFeature( feat );
351 perim = perimeterMeasure( mpGeometry, measure );
375 bool useField =
false;
376 if ( uniqueIdField == -1 )
397 if ( onlySelectedFeatures )
402 for ( ; it != selection.
constEnd(); ++it )
419 map.
insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
438 map.
insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
446 int processedFeatures = 0;
448 if ( onlySelectedFeatures )
456 processedFeatures = 0;
457 while ( jt != map.
constEnd() && ( jt.
key() == currentKey || !useField ) )
473 convexFeature( currentFeature, processedFeatures, &dissolveGeometry );
479 if ( !dissolveGeometry )
481 QgsDebugMsg(
"no dissolved geometry - should not happen" );
484 dissolveGeometry = dissolveGeometry->
convexHull();
485 values = simpleMeasure( dissolveGeometry );
487 attributes[0] =
QVariant( currentKey );
488 attributes[1] = values.
at( 0 );
489 attributes[2] = values.
at( 1 );
493 vWriter.addFeature( dissolveFeature );
503 processedFeatures = 0;
504 while ( jt != map.
constEnd() && ( jt.
key() == currentKey || !useField ) )
519 convexFeature( currentFeature, processedFeatures, &dissolveGeometry );
525 if ( !dissolveGeometry )
527 QgsDebugMsg(
"no dissolved geometry - should not happen" );
530 dissolveGeometry = dissolveGeometry->
convexHull();
532 values = simpleMeasure( dissolveGeometry );
534 attributes[0] =
QVariant( currentKey );
535 attributes[1] =
QVariant( values[ 0 ] );
536 attributes[2] =
QVariant( values[ 1 ] );
540 vWriter.addFeature( dissolveFeature );
547 void QgsGeometryAnalyzer::convexFeature(
QgsFeature& f,
int nProcessedFeatures,
QgsGeometry** dissolveGeometry )
558 convexGeometry = featureGeometry->
convexHull();
560 if ( nProcessedFeatures == 0 )
562 *dissolveGeometry = convexGeometry;
566 tmpGeometry = *dissolveGeometry;
567 *dissolveGeometry = ( *dissolveGeometry )->
combine( convexGeometry );
569 delete convexGeometry;
585 bool useField =
false;
586 if ( uniqueIdField == -1 )
602 if ( onlySelectedFeatures )
607 for ( ; it != selection.
constEnd(); ++it )
613 map.
insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
621 map.
insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
631 int processedFeatures = 0;
634 if ( onlySelectedFeatures )
642 while ( jt != map.
constEnd() && ( jt.
key() == currentKey || !useField ) )
663 dissolveFeature( currentFeature, processedFeatures, &dissolveGeometry );
677 while ( jt != map.
constEnd() && ( jt.
key() == currentKey || !useField ) )
696 dissolveFeature( currentFeature, processedFeatures, &dissolveGeometry );
702 vWriter.addFeature( outputFeature );
707 void QgsGeometryAnalyzer::dissolveFeature(
QgsFeature& f,
int nProcessedFeatures,
QgsGeometry** dissolveGeometry )
716 if ( nProcessedFeatures == 0 )
718 size_t geomSize = featureGeometry->
wkbSize();
720 unsigned char* wkb =
new unsigned char[geomSize];
721 memcpy( wkb, featureGeometry->
asWkb(), geomSize );
722 ( *dissolveGeometry )->fromWkb( wkb, geomSize );
726 *dissolveGeometry = ( *dissolveGeometry )->
combine( featureGeometry );
731 bool onlySelectedFeatures,
bool dissolve,
int bufferDistanceField,
QProgressDialog* p )
756 if ( onlySelectedFeatures )
765 int processedFeatures = 0;
767 for ( ; it != selection.
constEnd(); ++it )
782 bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, &dissolveGeometry, bufferDistance, bufferDistanceField );
801 int processedFeatures = 0;
813 bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, &dissolveGeometry, bufferDistance, bufferDistanceField );
825 if ( !dissolveGeometry )
827 QgsDebugMsg(
"no dissolved geometry - should not happen" );
831 vWriter.addFeature( dissolveFeature );
837 QgsGeometry** dissolveGeometry,
double bufferDistance,
int bufferDistanceField )
844 double currentBufferDistance;
850 if ( bufferDistanceField == -1 )
852 currentBufferDistance = bufferDistance;
858 bufferGeometry = featureGeometry->
buffer( currentBufferDistance, 5 );
862 if ( nProcessedFeatures == 0 )
864 *dissolveGeometry = bufferGeometry;
868 tmpGeometry = *dissolveGeometry;
869 *dissolveGeometry = ( *dissolveGeometry )->
combine( bufferGeometry );
871 delete bufferGeometry;
889 const QString& outputFormat,
int locationField1,
int locationField2,
int offsetField,
double offsetScale,
892 if ( !lineLayer || !eventLayer || !lineLayer->
isValid() || !eventLayer->
isValid() )
909 if ( !memoryProvider )
912 if ( locationField2 == -1 )
924 &( lineLayer->
crs() ),
935 double measure1, measure2 = 0.0;
938 int featureCounter = 0;
939 int nOutputFeatures = 0;
964 if ( locationField2 != -1 )
975 for ( ; featureIdIt != featureIdList.
end(); ++featureIdIt )
977 if ( locationField2 == -1 )
989 addEventLayerFeature( fet, lrsGeom, featureIdIt->geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry );
992 if ( nOutputFeatures < 1 )
994 unlocatedFeatureIds.
insert( fet.
id() );
1003 if ( memoryProvider )
1005 memoryProvider->
addFeatures( memoryProviderFeatures );
1012 int offsetField,
double offsetScale,
bool forceSingleType )
1020 if ( forceSingleType )
1030 for ( ; geomIt != geomList.
end(); ++geomIt )
1033 if ( offsetField >= 0 )
1036 offsetVal *= offsetScale;
1037 if ( !createOffsetGeometry( *geomIt, lineGeom, offsetVal ) )
1051 memoryFeatures << feature;
1055 if ( forceSingleType )
1061 bool QgsGeometryAnalyzer::createOffsetGeometry(
QgsGeometry* geom,
QgsGeometry* lineGeom,
double offset )
1063 if ( !geom || !lineGeom )
1082 for ( ; inputGeomIt != inputGeomList.
constEnd(); ++inputGeomIt )
1087 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && \
1088 ((GEOS_VERSION_MAJOR>3) || ((GEOS_VERSION_MAJOR==3) && (GEOS_VERSION_MINOR>=3)))
1089 GEOSGeometry* offsetGeom = GEOSOffsetCurve_r( geosctxt, ( *inputGeomIt )->asGeos(), -offset, 8 , 0 , 5.0 );
1090 if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) )
1094 if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 )
1096 GEOSGeom_destroy_r( geosctxt, offsetGeom );
1101 outputGeomList.
push_back( GEOSGeom_clone_r( geosctxt, ( *inputGeomIt )->asGeos() ) );
1106 QgsPoint p = ( *inputGeomIt )->asPoint();
1107 p = createPointOffset( p.
x(), p.
y(), offset, lineGeom );
1108 GEOSCoordSequence* ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
1109 GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.
x() );
1110 GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.
y() );
1111 GEOSGeometry* geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq );
1118 GEOSGeometry* outputGeom = outputGeomList.
at( 0 );
1126 GEOSGeometry** geomArray =
new GEOSGeometry*[outputGeomList.
size()];
1127 for (
int i = 0; i < outputGeomList.
size(); ++i )
1129 geomArray[i] = outputGeomList.
at( i );
1131 GEOSGeometry* collection = 0;
1134 collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.
size() );
1138 collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.
size() );
1146 QgsPoint QgsGeometryAnalyzer::createPointOffset(
double x,
double y,
double dist,
QgsGeometry* lineGeom )
const
1153 int beforeVertexNr = afterVertexNr - 1;
1158 double dx = afterVertex.
x() - beforeVertex.
x();
1159 double dy = afterVertex.
y() - beforeVertex.
y();
1160 double normalX = -dy;
1161 double normalY = dx;
1162 double normalLength = sqrt( normalX * normalX + normalY * normalY );
1163 normalX *= ( dist / normalLength );
1164 normalY *= ( dist / normalLength );
1166 double debugLength = sqrt( normalX * normalX + normalY * normalY );
1167 Q_UNUSED( debugLength );
1168 return QgsPoint( x - normalX, y - normalY );
1181 const unsigned char* lineWkb = lineGeom->
asWkb();
1183 const unsigned char* ptr = lineWkb + 1;
1185 memcpy( &wkbType, ptr,
sizeof( wkbType ) );
1186 ptr +=
sizeof( wkbType );
1195 locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1199 int* nLines = (
int* )ptr;
1200 ptr +=
sizeof( int );
1201 for (
int i = 0; i < *nLines; ++i )
1203 ptr += ( 1 +
sizeof( wkbType ) );
1204 ptr = locateBetweenWkbString( ptr, resultGeom, fromMeasure, toMeasure );
1208 if ( resultGeom.
size() < 1 )
1225 const unsigned char* lineWkb = lineGeom->
asWkb();
1227 const unsigned char* ptr = lineWkb + 1;
1229 memcpy( &wkbType, ptr,
sizeof( wkbType ) );
1230 ptr +=
sizeof( wkbType );
1239 locateAlongWkbString( ptr, resultGeom, measure );
1243 int* nLines = (
int* )ptr;
1244 ptr +=
sizeof( int );
1245 for (
int i = 0; i < *nLines; ++i )
1247 ptr += ( 1 +
sizeof( wkbType ) );
1248 ptr = locateAlongWkbString( ptr, resultGeom, measure );
1252 if ( resultGeom.
size() < 1 )
1259 const unsigned char* QgsGeometryAnalyzer::locateBetweenWkbString(
const unsigned char* ptr,
QgsMultiPolyline& result,
double fromMeasure,
double toMeasure )
1261 int* nPoints = (
int* ) ptr;
1262 ptr +=
sizeof( int );
1263 double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1268 bool measureInSegment;
1269 bool secondPointClipped;
1272 for (
int i = 0; i < *nPoints; ++i )
1275 ptr +=
sizeof( double );
1277 ptr +=
sizeof( double );
1278 z = (
double* ) ptr;
1279 ptr +=
sizeof( double );
1283 measureInSegment = clipSegmentByRange( prevx, prevy, prevz, *x, *y, *z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
1284 if ( measureInSegment )
1286 if ( currentLine.
size() < 1 )
1288 currentLine.
append( pt1 );
1293 currentLine.
append( pt2 );
1296 if ( secondPointClipped || i == *nPoints - 1 )
1298 if ( currentLine.
size() > 1 )
1300 result.
append( currentLine );
1302 currentLine.
clear();
1306 prevx = *x; prevy = *y; prevz = *z;
1311 const unsigned char* QgsGeometryAnalyzer::locateAlongWkbString(
const unsigned char* ptr,
QgsMultiPoint& result,
double measure )
1313 int* nPoints = (
int* ) ptr;
1314 ptr +=
sizeof( int );
1315 double prevx = 0.0, prevy = 0.0, prevz = 0.0;
1321 for (
int i = 0; i < *nPoints; ++i )
1324 ptr +=
sizeof( double );
1326 ptr +=
sizeof( double );
1327 z = (
double* ) ptr;
1328 ptr +=
sizeof( double );
1332 locateAlongSegment( prevx, prevy, prevz, *x, *y, *z, measure, pt1Ok, pt1, pt2Ok, pt2 );
1337 if ( pt2Ok && ( i == ( *nPoints - 1 ) ) )
1342 prevx = *x; prevy = *y; prevz = *z;
1347 bool QgsGeometryAnalyzer::clipSegmentByRange(
double x1,
double y1,
double m1,
double x2,
double y2,
double m2,
double range1,
double range2,
QgsPoint& pt1,
1348 QgsPoint& pt2,
bool& secondPointClipped )
1350 bool reversed = m1 > m2;
1370 if ( range1 > range2 )
1378 if ( m2 < range1 || m1 > range2 )
1384 if ( m2 <= range2 && m1 >= range1 )
1396 secondPointClipped =
false;
1401 if ( m1 >= range1 && m1 <= range2 )
1404 double dist = ( range2 - m1 ) / ( m2 - m1 );
1405 pt2.
setX( x1 + ( x2 - x1 ) * dist );
1406 pt2.
setY( y1 + ( y2 - y1 ) * dist );
1407 secondPointClipped = !reversed;
1411 if ( m2 >= range1 && m2 <= range2 )
1414 double dist = ( m2 - range1 ) / ( m2 - m1 );
1415 pt1.
setX( x2 - ( x2 - x1 ) * dist );
1416 pt1.
setY( y2 - ( y2 - y1 ) * dist );
1417 secondPointClipped = reversed;
1421 if ( range1 >= m1 && range2 <= m2 )
1423 double dist1 = ( range1 - m1 ) / ( m2 - m1 );
1424 double dist2 = ( range2 - m1 ) / ( m2 - m1 );
1425 pt1.
setX( x1 + ( x2 - x1 ) * dist1 );
1426 pt1.
setY( y1 + ( y2 - y1 ) * dist1 );
1427 pt2.
setX( x1 + ( x2 - x1 ) * dist2 );
1428 pt2.
setY( y1 + ( y2 - y1 ) * dist2 );
1429 secondPointClipped =
true;
1442 void QgsGeometryAnalyzer::locateAlongSegment(
double x1,
double y1,
double m1,
double x2,
double y2,
double m2,
double measure,
bool& pt1Ok,
QgsPoint& pt1,
bool& pt2Ok,
QgsPoint& pt2 )
1444 bool reversed =
false;
1447 double tolerance = 0.000001;
1458 if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance )
1496 if ( pt1Ok || pt2Ok )
1509 double dist = ( measure - m1 ) / ( m2 - m1 );
1515 pt1.
setX( x1 + dist * ( x2 - x1 ) );
1516 pt1.
setY( y1 + dist * ( y2 - y1 ) );
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
QgsFeatureId id() const
Get the feature ID for this feature.
QgsGeometry * simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
Wrapper for iterator of features from vector data provider or vector layer.
bool eventLayer(QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString &outputLayer, const QString &outputFormat, int locationField1, int locationField2=-1, int offsetField=-1, double offsetScale=1.0, bool forceSingleGeometry=false, QgsVectorDataProvider *memoryProvider=0, QProgressDialog *p=0)
Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event tabl...
A rectangle specified with double values.
QgsGeometry * locateBetweenMeasures(double fromMeasure, double toMeasure, const QgsGeometry *lineGeom)
Returns linear reference geometry as a multiline (or 0 if no match).
QgsGeometry * convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes.
void append(const T &value)
void setMaximum(int maximum)
void push_back(const T &value)
bool dissolve(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, int uniqueIdField=-1, QProgressDialog *p=0)
Dissolve a vector layer and write it to a new shape file.
size_t wkbSize() const
Returns the size of the WKB in asWkb().
QgsFields fields() const
Returns the list of fields of this layer.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
bool extent(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, QProgressDialog *p=0)
Create a polygon based on the extent of all (selected) features and write it to a new shape file...
const_iterator constBegin() const
QList< QgsGeometry * > asGeometryCollection() const
Return contents of the geometry as a list of geometries.
const T & at(int i) const
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
WkbType
Used for symbology operations.
A convenience class for writing vector files to disk.
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
virtual bool addFeatures(QgsFeatureList &flist)
Adds a list of features.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
double x() const
Get the x value of the point.
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
QString encoding() const
Get encoding which is used for accessing data.
void setValue(int progress)
void setGeometry(const QgsGeometry &geom)
Set this feature's geometry from another QgsGeometry object.
void append(const T &value)
QgsRectangle extent() override
Return the extent of the layer.
const QgsFeatureIds & selectedFeaturesIds() const
Return reference to identifiers of selected features.
bool buffer(QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, bool onlySelectedFeatures=false, bool dissolve=false, int bufferDistanceField=-1, QProgressDialog *p=0)
Create buffers for a vector layer and write it to a new shape file.
QgsAttributes attributes() const
Returns the feature's attributes.
const_iterator constEnd() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
bool addFeature(QgsFeature &feature, QgsFeatureRendererV2 *renderer=0, QGis::UnitType outputUnit=QGis::Meters)
Add feature to the currently opened shapefile.
double measurePerimeter(const QgsGeometry *geometry) const
measures perimeter of polygon
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
QMap< Key, T >::iterator insert(const Key &key, const T &value)
const_iterator constEnd() const
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
double closestSegmentWithContext(const QgsPoint &point, QgsPoint &minDistPoint, int &afterVertex, double *leftOf=0, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Searches for the closest segment of geometry to the given point.
Encapsulate a field in an attribute table or data source.
QgsGeometry * centroid() const
Returns the center of mass of a geometry.
QHash< Key, T >::iterator insert(const Key &key, const T &value)
virtual QGis::WkbType geometryType() const =0
Get feature type.
bool isValid()
Return the status of the layer.
QgsGeometry * buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
A class to represent a point.
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
void setX(double x)
Sets the x value of the point.
void setY(double y)
Sets the y value of the point.
const_iterator constBegin() const
bool contains(const T &value) const
static QgsGeometry * fromMultiPolyline(const QgsMultiPolyline &multiline)
Creates a new geometry from a QgsMultiPolyline object.
General purpose distance and area calculator.
QgsGeometry * combine(const QgsGeometry *geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
bool centroids(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, QProgressDialog *p=0)
Calculate the true centroids, or 'center of mass' for a vector layer and write it to a new shape file...
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
Class for storing a coordinate reference system (CRS)
bool simplify(QgsVectorLayer *layer, const QString &shapefileName, double tolerance, bool onlySelectedFeatures=false, QProgressDialog *p=0)
Simplify vector layer using (a modified) Douglas-Peucker algorithm and write it to a new shape file...
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
QList< T > values() const
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsGeometry * locateAlongMeasure(double measure, const QgsGeometry *lineGeom)
Returns linear reference geometry.
static QgsGeometry * fromMultiPoint(const QgsMultiPoint &multipoint)
Creates a new geometry from a QgsMultiPoint object.
double y() const
Get the y value of the point.
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
double toDouble(bool *ok) const
void setMinimum(int minimum)
QgsVectorDataProvider * dataProvider()
Returns the data provider.
const_iterator constEnd() const
bool nextFeature(QgsFeature &f)
const_iterator constBegin() const
This is the base class for vector data providers.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
Represents a vector layer which manages a vector based data sets.
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
double xMinimum() const
Get the x minimum value (left side of rectangle)
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
bool convexHull(QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures=false, int uniqueIdField=-1, QProgressDialog *p=0)
Create convex hull(s) of a vector layer and write it to a new shape file.
QgsRectangle boundingBoxOfSelected()
Returns the bounding box of the selected features.