diff --git a/src/qgsattributetabledisplay.cpp b/src/qgsattributetabledisplay.cpp index 23513f1528b..f1782d0576b 100644 --- a/src/qgsattributetabledisplay.cpp +++ b/src/qgsattributetabledisplay.cpp @@ -42,7 +42,7 @@ QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer):QgsAtt edit->insertItem(tr("&Add Attribute..."), this, SLOT(addAttribute()), CTRL+Key_A,0); edit->insertItem(tr("&Delete Attributes..."), this, SLOT(deleteAttributes()), CTRL+Key_D,1); - selection->insertItem(tr("&Bring selected to top"), this, SLOT(selectedToTop()), CTRL+Key_T); + selection->insertItem(tr("&Bring selection to top"), this, SLOT(selectedToTop()), CTRL+Key_T); selection->insertItem(tr("&Invert selection"), this, SLOT(invertSelection()), CTRL+Key_I); mMenuBar->insertItem(tr("&Edit"), edit); mMenuBar->insertItem(tr("&Selection"),selection); diff --git a/src/qgsfeature.cpp b/src/qgsfeature.cpp index 3217ec451b7..a258c2f9292 100644 --- a/src/qgsfeature.cpp +++ b/src/qgsfeature.cpp @@ -255,7 +255,7 @@ void QgsFeature::attributeDialog() } } -bool QgsFeature::intersects(QgsRect* r) +bool QgsFeature::intersects(QgsRect* r) const { bool returnval=false; @@ -532,7 +532,7 @@ bool QgsFeature::exportToWKT() const } -QgsPoint QgsFeature::closestVertex(const QgsPoint& point) +QgsPoint QgsFeature::closestVertex(const QgsPoint& point) const { if(geometry) { @@ -682,3 +682,213 @@ QgsPoint QgsFeature::closestVertex(const QgsPoint& point) } return QgsPoint(0,0); } + +QgsRect QgsFeature::boundingBox() const +{ + double xmin=DBL_MAX; + double ymin=DBL_MAX; + double xmax=-DBL_MAX; + double ymax=-DBL_MAX; + + double *x; + double *y; + int *nPoints; + int *numRings; + int *numPolygons; + int numPoints; + int numLineStrings; + int idx, jdx, kdx; + unsigned char *ptr; + char lsb; + QgsPoint pt; + QPointArray *pa; + int wkbType; + unsigned char *feature; + + feature = this->getGeometry(); + if(feature) + { + wkbType=(int) feature[1]; + switch (wkbType) + { + case QGis::WKBPoint: + x = (double *) (feature + 5); + y = (double *) (feature + 5 + sizeof(double)); + if (*x < xmin) + { + xmin=*x; + } + if (*x > xmax) + { + xmax=*x; + } + if (*y < ymin) + { + ymin=*y; + } + if (*y > ymax) + { + ymax=*y; + } + break; + + case QGis::WKBLineString: + // get number of points in the line + ptr = feature + 5; + nPoints = (int *) ptr; + ptr = feature + 1 + 2 * sizeof(int); + for (idx = 0; idx < *nPoints; idx++) + { + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + if (*x < xmin) + { + xmin=*x; + } + if (*x > xmax) + { + xmax=*x; + } + if (*y < ymin) + { + ymin=*y; + } + if (*y > ymax) + { + ymax=*y; + } + } + break; + + case QGis::WKBMultiLineString: + numLineStrings = (int) (feature[5]); + ptr = feature + 9; + for (jdx = 0; jdx < numLineStrings; jdx++) + { + // each of these is a wbklinestring so must handle as such + lsb = *ptr; + ptr += 5; // skip type since we know its 2 + nPoints = (int *) ptr; + ptr += sizeof(int); + for (idx = 0; idx < *nPoints; idx++) + { + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + if (*x < xmin) + { + xmin=*x; + } + if (*x > xmax) + { + xmax=*x; + } + if (*y < ymin) + { + ymin=*y; + } + if (*y > ymax) + { + ymax=*y; + } + } + } + break; + + case QGis::WKBPolygon: + // get number of rings in the polygon + numRings = (int *) (feature + 1 + sizeof(int)); + ptr = feature + 1 + 2 * sizeof(int); + for (idx = 0; idx < *numRings; idx++) + { + // get number of points in the ring + nPoints = (int *) ptr; + ptr += 4; + for (jdx = 0; jdx < *nPoints; jdx++) + { + // add points to a point array for drawing the polygon + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + if (*x < xmin) + { + xmin=*x; + } + if (*x > xmax) + { + xmax=*x; + } + if (*y < ymin) + { + ymin=*y; + } + if (*y > ymax) + { + ymax=*y; + } + } + } + break; + + case QGis::WKBMultiPolygon: + // get the number of polygons + ptr = feature + 5; + numPolygons = (int *) ptr; + for (kdx = 0; kdx < *numPolygons; kdx++) + { + //skip the endian and feature type info and + // get number of rings in the polygon + ptr = feature + 14; + numRings = (int *) ptr; + ptr += 4; + for (idx = 0; idx < *numRings; idx++) + { + // get number of points in the ring + nPoints = (int *) ptr; + ptr += 4; + for (jdx = 0; jdx < *nPoints; jdx++) + { + // add points to a point array for drawing the polygon + x = (double *) ptr; + ptr += sizeof(double); + y = (double *) ptr; + ptr += sizeof(double); + if (*x < xmin) + { + xmin=*x; + } + if (*x > xmax) + { + xmax=*x; + } + if (*y < ymin) + { + ymin=*y; + } + if (*y > ymax) + { + ymax=*y; + } + } + } + } + break; + + default: + #ifdef QGISDEBUG + std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n"; +#endif + break; + + } + return QgsRect(xmin,ymin,xmax,ymax); + } + else + { + return QgsRect(0,0,0,0); + } +} diff --git a/src/qgsfeature.h b/src/qgsfeature.h index b9cfde33965..16caa3c5fdc 100644 --- a/src/qgsfeature.h +++ b/src/qgsfeature.h @@ -122,10 +122,13 @@ class QgsFeature { void attributeDialog(); /**Test for intersection with a rectangle (uses GEOS)*/ - bool intersects(QgsRect* r); + bool intersects(QgsRect* r) const; /**Returns the Vertex closest to a given point*/ - QgsPoint closestVertex(const QgsPoint& point); + QgsPoint closestVertex(const QgsPoint& point) const; + + /**Returns the bounding box of this feature*/ + QgsRect boundingBox() const; private: diff --git a/src/qgsmapcanvas.cpp b/src/qgsmapcanvas.cpp index 7d25eabb929..bb62319f742 100644 --- a/src/qgsmapcanvas.cpp +++ b/src/qgsmapcanvas.cpp @@ -1076,28 +1076,11 @@ void QgsMapCanvas::zoomToSelected() rect = lyr->bBoxOfSelected(); } - // no selected features - // XXX where is rectange set to "empty"? Shouldn't we use QgsRect::isEmpty()? - if (rect.xMin() == DBL_MAX && - rect.yMin() == DBL_MAX && - rect.xMax() == -DBL_MAX && - rect.yMax() == -DBL_MAX) + // no selected features, only one selected point feature + //or two point features with the same x- or y-coordinates + if(rect.isEmpty()) { - return; - } - //zoom to one single point - else if (rect.xMin() == rect.xMax() && - rect.yMin() == rect.yMax()) - { - mCanvasProperties->previousExtent = mCanvasProperties->currentExtent; - mCanvasProperties->currentExtent.setXmin(rect.xMin() - 25); - mCanvasProperties->currentExtent.setYmin(rect.yMin() - 25); - mCanvasProperties->currentExtent.setXmax(rect.xMax() + 25); - mCanvasProperties->currentExtent.setYmax(rect.yMax() + 25); - emit extentsChanged(mCanvasProperties->currentExtent); - clear(); - render(); - return; + return; } //zoom to an area else diff --git a/src/qgsvectorlayer.cpp b/src/qgsvectorlayer.cpp index e096e080f6f..8acd1aefe41 100644 --- a/src/qgsvectorlayer.cpp +++ b/src/qgsvectorlayer.cpp @@ -1033,214 +1033,68 @@ QPopupMenu *QgsVectorLayer::contextMenu() QgsRect QgsVectorLayer::bBoxOfSelected() { - QgsRect rect(DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX); + if(mSelected.size()==0)//no selected features + { + return QgsRect(0,0,0,0); + } + + double xmin=DBL_MAX; + double ymin=DBL_MAX; + double xmax=-DBL_MAX; + double ymax=-DBL_MAX; + QgsRect r; + QgsFeature* fet; dataProvider->reset(); - QgsFeature *fet; - unsigned char *feature; - - double *x; - double *y; - int *nPoints; - int *numRings; - int *numPolygons; - int numPoints; - int numLineStrings; - int idx, jdx, kdx; - unsigned char *ptr; - char lsb; - QgsPoint pt; - QPointArray *pa; - int wkbType; - while ((fet = dataProvider->getNextFeature(false))) { if (mSelected.find(fet->featureId()) != mSelected.end()) { - feature = fet->getGeometry(); - wkbType = (int) feature[1]; - - - switch (wkbType) - { - case WKBPoint: - x = (double *) (feature + 5); - y = (double *) (feature + 5 + sizeof(double)); - if (*x < rect.xMin()) - { - rect.setXmin(*x); - } - if (*x > rect.xMax()) - { - rect.setXmax(*x); - } - if (*y < rect.yMin()) - { - rect.setYmin(*y); - } - if (*y > rect.yMax()) - { - rect.setYmax(*y); - } - break; - - case WKBLineString: - // get number of points in the line - ptr = feature + 5; - nPoints = (int *) ptr; - ptr = feature + 1 + 2 * sizeof(int); - for (idx = 0; idx < *nPoints; idx++) - { - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - if (*x < rect.xMin()) - { - rect.setXmin(*x); - } - if (*x > rect.xMax()) - { - rect.setXmax(*x); - } - if (*y < rect.yMin()) - { - rect.setYmin(*y); - } - if (*y > rect.yMax()) - { - rect.setYmax(*y); - } - } - break; - - case WKBMultiLineString: - numLineStrings = (int) (feature[5]); - ptr = feature + 9; - for (jdx = 0; jdx < numLineStrings; jdx++) - { - // each of these is a wbklinestring so must handle as such - lsb = *ptr; - ptr += 5; // skip type since we know its 2 - nPoints = (int *) ptr; - ptr += sizeof(int); - for (idx = 0; idx < *nPoints; idx++) - { - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - if (*x < rect.xMin()) - { - rect.setXmin(*x); - } - if (*x > rect.xMax()) - { - rect.setXmax(*x); - } - if (*y < rect.yMin()) - { - rect.setYmin(*y); - } - if (*y > rect.yMax()) - { - rect.setYmax(*y); - } - } - } - break; - - case WKBPolygon: - // get number of rings in the polygon - numRings = (int *) (feature + 1 + sizeof(int)); - ptr = feature + 1 + 2 * sizeof(int); - for (idx = 0; idx < *numRings; idx++) - { - // get number of points in the ring - nPoints = (int *) ptr; - ptr += 4; - for (jdx = 0; jdx < *nPoints; jdx++) - { - // add points to a point array for drawing the polygon - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - if (*x < rect.xMin()) - { - rect.setXmin(*x); - } - if (*x > rect.xMax()) - { - rect.setXmax(*x); - } - if (*y < rect.yMin()) - { - rect.setYmin(*y); - } - if (*y > rect.yMax()) - { - rect.setYmax(*y); - } - } - } - break; - - case WKBMultiPolygon: - // get the number of polygons - ptr = feature + 5; - numPolygons = (int *) ptr; - for (kdx = 0; kdx < *numPolygons; kdx++) - { - //skip the endian and feature type info and - // get number of rings in the polygon - ptr = feature + 14; - numRings = (int *) ptr; - ptr += 4; - for (idx = 0; idx < *numRings; idx++) - { - // get number of points in the ring - nPoints = (int *) ptr; - ptr += 4; - for (jdx = 0; jdx < *nPoints; jdx++) - { - // add points to a point array for drawing the polygon - x = (double *) ptr; - ptr += sizeof(double); - y = (double *) ptr; - ptr += sizeof(double); - if (*x < rect.xMin()) - { - rect.setXmin(*x); - } - if (*x > rect.xMax()) - { - rect.setXmax(*x); - } - if (*y < rect.yMin()) - { - rect.setYmin(*y); - } - if (*y > rect.yMax()) - { - rect.setYmax(*y); - } - } - } - } - break; - - default: -#ifdef QGISDEBUG - std::cout << "UNKNOWN WKBTYPE ENCOUNTERED\n"; -#endif - break; - - } - delete[]feature; + r=fet->boundingBox(); + if(r.xMin()xmax) + { + xmax=r.xMax(); + } + if(r.yMax()>ymax) + { + ymax=r.yMax(); + } } + delete fet; } - return rect; + //also go through the not commited features + for(std::list::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter) + { + if(mSelected.find((*iter)->featureId())!=mSelected.end()) + { + r=(*iter)->boundingBox(); + if(r.xMin()xmax) + { + xmax=r.xMax(); + } + if(r.yMax()>ymax) + { + ymax=r.yMax(); + } + } + } + return QgsRect(xmin,ymin,xmax,ymax); } void QgsVectorLayer::setLayerProperties(QgsDlgVectorLayerProperties * properties) diff --git a/src/qgsvectorlayer.h b/src/qgsvectorlayer.h index 995a892a86b..14f41d3f777 100644 --- a/src/qgsvectorlayer.h +++ b/src/qgsvectorlayer.h @@ -133,7 +133,7 @@ public slots: QgsDlgVectorLayerProperties *propertiesDialog(); /** Return the context menu for the layer */ QPopupMenu *contextMenu(); - /**Returns the bounding box of the selected features. If there is no selection, the lower bounds are DBL_MAX and the upper bounds -DBL_MAX*/ + /**Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned*/ virtual QgsRect bBoxOfSelected(); //! Return the provider type for this layer QString providerType();