Skip to content
Permalink
Browse files
Fix for X11 zoom bug. Only fixes lines (not polygons), and if you
zoom in enough things will still behave oddly (due to over/underflow of
doubles rather than 16 bit ints). Work in progress. Polygons next.


git-svn-id: http://svn.osgeo.org/qgis/trunk@3000 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
g_j_m committed Mar 22, 2005
1 parent fcde577 commit 6f2828c083d3ebacbc7242a6227f9b28ee0bfb48
Showing with 258 additions and 28 deletions.
  1. +202 −0 src/qgsmaptopixel.cpp
  2. +7 −1 src/qgsmaptopixel.h
  3. +49 −27 src/qgsvectorlayer.cpp
@@ -75,3 +75,205 @@ QString QgsMapToPixel::showParameters()
return rep;

}

void QgsMapToPixel::trimLine(const QgsPoint& from, const QgsPoint& to,
QgsPoint& tFrom, QgsPoint& tTo)
{
// The limits for X11 screen coordinates. Actual value is 32767, but
// we allow a little bit if space of rounding errors in the
// calculations below.
static const int minX = -32760;
static const int maxX = 32760;
static const int minY = -32760;
static const int maxY = 32760;
static const double SMALL_NUM = 1e-6;

// One thing in our favour is that if this function is called we
// already know that the line intersects the region that is visible
// on the screen, so there's no need to check for that intersection.

// To determine the intersection between a line given by the points
// A and B, and the line given by the points C and D, calculate
//
// (Ay - Cy)(Dx - Cx) - (Ax - Cx)(Dy - Cy)
// r = -----------------------------------------
// (Bx - Ax)(Dy - Cy) - (By - Ay)(Dx - Cx)
//
// (Ay - Cy)(Bx - Ax) - (Ax - Cx)(By - Ay)
// s = -----------------------------------------
// (Bx - Ax)(Dy - Cy) - (By - Ay)(Dx - Cx)
//
// If the demoninator is 0, the lines are parallel, and don't
// intersect, and can be left untrimmed
// If the numerator is 0 too, the lines are collinear and can be
// left untrimmed.
//
// Note that the demoninator is the same for r and s.
//
// If the two points that define the line segment are actually at
// the same place, the denominator will be zero and the points will
// be left alone as per parallel lines. This shouldn't happen anyway
// because if the line is just a point, and it's within the visible
// window on screen, the coordinates will be within the limits and
// the first if() test below will fail and not attempt any trimming.
//
// If 0 >= r <= 1 and 0 >= s <= 1 then the line segments intersect,
// and the intersection point P is given by:
//
// P = A + r*(B-A)
//

// Once we have adjusted both the to and from points, there is no
// point in doing further checks, so return from the function
// if that occurs.
bool toDone = false, fromDone = false;

// Check for the need to trim first
if (from.x() < minX || from.x() > maxX || to.x() < minX || to.x() > maxX ||
from.y() < minY || from.y() > maxY || to.y() < minY || to.y() > maxY)
{
tFrom = from;
tTo = to;

// Check the top boundary
double r_n = (from.y() - minY) * (maxX - minX);
double d = - (to.y() - from.y()) * (maxX - minX);
double s_n = (from.y() - minY) * (to.x() - from.x())
- (from.x() - minX) * (to.y() - from.y());

if (fabs(d) > SMALL_NUM && fabs(r_n) > SMALL_NUM != 0.0)
{
double r_nOverd = r_n / d;
double s_nOverd = s_n / d;
if (r_nOverd >= 0.0 && r_nOverd <= 1.0 &&
s_nOverd >= 0.0 && s_nOverd <= 1.0)
{
// intersects the top line. Trim back.
// work out which end to trim
if (from.y() <= minY) // trim from
{
fromDone = true;
tFrom.setX(from.x() + r_nOverd*(to.x() - from.x()));
tFrom.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
else // trim to
{
toDone = true;
tTo.setX(from.x() + r_nOverd*(to.x() - from.x()));
tTo.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
}
}

// the right border
r_n = -(from.x() - maxX) * (maxY - minY);
d = (to.x() - from.x()) * (maxY - minY);
s_n = (from.y() - minY) * (to.x() - from.x())
- (from.x() - maxX) * (to.y() - from.y());

if (fabs(d) > SMALL_NUM && fabs(r_n) > SMALL_NUM != 0.0)
{
double r_nOverd = r_n / d;
double s_nOverd = s_n / d;
if (r_nOverd >= 0.0 && r_nOverd <= 1.0 &&
s_nOverd >= 0.0 && s_nOverd <= 1.0)
{
// intersects the bottom line. Trim back.
// work out which end to trim
if (from.x() >= maxX) // trim from
{
fromDone = true;
tFrom.setX(from.x() + r_nOverd*(to.x() - from.x()));
tFrom.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
else // trim to
{
toDone = true;
tTo.setX(from.x() + r_nOverd*(to.x() - from.x()));
tTo.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
}
}

// Done both ends of the line, so leave.
if (toDone && fromDone)
return;

// the left border
r_n = - (from.x() - minX) * (maxY - minY);
d = (to.x() - from.x()) * (maxY - minY);
s_n = (from.y() - minY) * (to.x() - from.x())
- (from.x() - minX) * (to.y() - from.y());

if (fabs(d) > SMALL_NUM && fabs(r_n) > SMALL_NUM != 0.0)
{
double r_nOverd = r_n / d;
double s_nOverd = s_n / d;
if (r_nOverd >= 0.0 && r_nOverd <= 1.0 &&
s_nOverd >= 0.0 && s_nOverd <= 1.0)
{
// intersects the left line. Trim back.
// work out which end to trim
if (from.x() <= minX) // trim from
{
fromDone = true;
tFrom.setX(from.x() + r_nOverd*(to.x() - from.x()));
tFrom.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
else // trim to
{
toDone = true;
tTo.setX(from.x() + r_nOverd*(to.x() - from.x()));
tTo.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
}
}

// Done both ends of the line, so leave.
if (toDone && fromDone)
return;

// the bottom border
r_n = (from.y() - maxY) * (maxX - minX);
d = - (to.y() - from.y()) * (maxX - minX);
s_n = (from.y() - maxY) * (to.x() - from.x())
- (from.x() - minX) * (to.y() - from.y());

if (fabs(d) > SMALL_NUM && fabs(r_n) > SMALL_NUM != 0.0)
{
double r_nOverd = r_n/d;
double s_nOverd = s_n/d;
if (r_nOverd >= 0.0 && r_nOverd <= 1.0 &&
s_nOverd >= 0.0 && s_nOverd <= 1.0)
{
// intersects the bottom line. Trim back.
// work out which end to trim
if (from.y() >= maxY) // trim from
{
fromDone = true;
tFrom.setX(from.x() + r_nOverd*(to.x() - from.x()));
tFrom.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
else // trim to
{
toDone = true;
tTo.setX(from.x() + r_nOverd*(to.x() - from.x()));
tTo.setY(from.y() + r_nOverd*(to.y() - from.y()));
}
}
}
}
else
{
// The entire line is visible on screen, so do nothing.
tFrom = from;
tTo = to;
}
/*
// Too verbose for QGISDEBUG, but handy sometimes.
std::cerr << "Point 1 trimmed from " << from.x() << ", " << from.y()
<< " to " << tFrom.x() << ", " << tFrom.y() << '\n'
<< "Point 2 trimmed from " << to.x() << ", " << to.y()
<< " to " << tTo.x() << ", " << tTo.y() << "\n\n";
*/
}
@@ -84,6 +84,9 @@ class QgsMapToPixel{
void setParameters(double mupp, double xmin, double ymin, double ymax);
//! String representation of the parameters used in the transform
QString showParameters();

static void trimLine(const QgsPoint& from, const QgsPoint& to,
QgsPoint& tFrom, QgsPoint& tTo);
private:
double mapUnitsPerPixel;
double yMax;
@@ -119,6 +122,7 @@ inline QgsPoint QgsMapToPixel::transform(QgsPoint p)
double dx = (p.x() - xMin) / mapUnitsPerPixel;
double dy = yMax - ((p.y() - yMin)) / mapUnitsPerPixel;
// double dy = (yMax - (p.y() - yMin))/mapUnitsPerPixel;
//std::cerr << "Point to pixel...X : " << p.x() << "-->" << dx << ", Y: " << p.y() << " -->" << dy << std::endl;
return QgsPoint(dx, dy);
}

@@ -127,11 +131,13 @@ inline void QgsMapToPixel::transform(QgsPoint* p)
float x = ((p->x()-xMin)/mapUnitsPerPixel);
float y = (yMax-((p->y() - yMin)) / mapUnitsPerPixel);
#ifdef QGISDEBUG
//std::cout << "Point to pixel...X : " << p->x() << "-->" << x << ", Y: " << p->y() << " -->" << y << std::endl;
//std::cerr << "Point to pixel...X : " << p->x() << "-->" << x << ", Y: " << p->y() << " -->" << y << std::endl;
#endif
p->setX(x);
p->setY(y);

}



#endif // QGSMAPTOPIXEL
@@ -2206,6 +2206,8 @@ void QgsVectorLayer::drawFeature(QPainter* p, QgsFeature* fet, QgsMapToPixel * t
double *y;
int wkbType;
QgsPoint pt,myProjectedPoint;
QgsPoint ptFrom, ptTo;
QgsPoint trimmedFrom, trimmedTo;

QPen pen;

@@ -2283,24 +2285,34 @@ void QgsVectorLayer::drawFeature(QPainter* p, QgsFeature* fet, QgsMapToPixel * t
if (projectionsEnabledFlag)
{
//reproject the point to the map coordinate system
try {
myProjectedPoint=mCoordinateTransform->transform(pt);
}
catch (QgsCsException &e)
{
qDebug( "Transform error caught in %s line %d:\n%s", __FILE__, __LINE__, e.what());
}
//transform from projected coordinate system to pixel position on map canvas
theMapToPixelTransform->transform(&myProjectedPoint);
try
{
ptTo=mCoordinateTransform->transform(pt);
}
catch (QgsCsException &e)
{
qDebug( "Transform error caught in %s line %d:\n%s",
__FILE__, __LINE__, e.what());
}
//transform from projected coordinate system to pixel
// position on map canvas
theMapToPixelTransform->transform(&ptTo);
}
else
{
myProjectedPoint=theMapToPixelTransform->transform(pt);
ptTo=theMapToPixelTransform->transform(pt);
}
if (idx == 0)
p->moveTo(static_cast<int>(myProjectedPoint.x()), static_cast<int>(myProjectedPoint.y()));
else
p->lineTo(static_cast<int>(myProjectedPoint.x()), static_cast<int>(myProjectedPoint.y()));
ptFrom = ptTo;
else
{
QgsMapToPixel::trimLine(ptFrom, ptTo, trimmedFrom, trimmedTo);
p->drawLine(static_cast<int>(trimmedFrom.x()),
static_cast<int>(trimmedFrom.y()),
static_cast<int>(trimmedTo.x()),
static_cast<int>(trimmedTo.y()));
ptFrom = ptTo;
}
}
break;
}
@@ -2332,24 +2344,34 @@ void QgsVectorLayer::drawFeature(QPainter* p, QgsFeature* fet, QgsMapToPixel * t
if (projectionsEnabledFlag)
{
//reproject the point to the map coordinate system
try {
myProjectedPoint=mCoordinateTransform->transform(pt);
}
catch (QgsCsException &e)
{
qDebug( "Transform error caught in %s line %d:\n%s", __FILE__, __LINE__, e.what());
}
//transform from projected coordinate system to pixel position on map canvas
theMapToPixelTransform->transform(&myProjectedPoint);
try
{
ptTo=mCoordinateTransform->transform(pt);
}
catch (QgsCsException &e)
{
qDebug( "Transform error caught in %s line %d:\n%s",
__FILE__, __LINE__, e.what());
}
//transform from projected coordinate system to pixel
// position on map canvas
theMapToPixelTransform->transform(&ptTo);
}
else
{
myProjectedPoint=theMapToPixelTransform->transform(pt);
ptTo=theMapToPixelTransform->transform(pt);
}
if (idx == 0)
p->moveTo(static_cast<int>(myProjectedPoint.x()), static_cast<int>(myProjectedPoint.y()));
else
p->lineTo(static_cast<int>(myProjectedPoint.x()), static_cast<int>(myProjectedPoint.y()));
if (idx == 0)
ptFrom = ptTo;
else
{
QgsMapToPixel::trimLine(ptFrom, ptTo, trimmedFrom, trimmedTo);
p->drawLine(static_cast<int>(trimmedFrom.x()),
static_cast<int>(trimmedFrom.y()),
static_cast<int>(trimmedTo.x()),
static_cast<int>(trimmedTo.y()));
ptFrom = ptTo;
}
}
}
break;

0 comments on commit 6f2828c

Please sign in to comment.