fix for bug 1166086 plus consider not commited features in 'zoom to selection'

git-svn-id: http://svn.osgeo.org/qgis/trunk@3018 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
mhugent 2005-03-24 22:28:56 +00:00
parent 0910cdcd8a
commit 7c29714923
6 changed files with 277 additions and 227 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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:

View File

@ -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

View File

@ -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()<xmin)
{
xmin=r.xMin();
}
if(r.yMin()<ymin)
{
ymin=r.yMin();
}
if(r.xMax()>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<QgsFeature*>::iterator iter=mAddedFeatures.begin();iter!=mAddedFeatures.end();++iter)
{
if(mSelected.find((*iter)->featureId())!=mSelected.end())
{
r=(*iter)->boundingBox();
if(r.xMin()<xmin)
{
xmin=r.xMin();
}
if(r.yMin()<ymin)
{
ymin=r.yMin();
}
if(r.xMax()>xmax)
{
xmax=r.xMax();
}
if(r.yMax()>ymax)
{
ymax=r.yMax();
}
}
}
return QgsRect(xmin,ymin,xmax,ymax);
}
void QgsVectorLayer::setLayerProperties(QgsDlgVectorLayerProperties * properties)

View File

@ -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();