QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsclipper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsclipper.cpp - a class that clips line
3  segments and polygons
4  -------------------
5  begin : March 2004
6  copyright : (C) 2005 by Gavin Macaulay
7  email :
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "qgsclipper.h"
20 
21 // Where has all the code gone?
22 
23 // It's been inlined, so its in the qgsclipper.h file.
24 
25 // But the static members must be initialised outside the class! (or GCC 4 dies)
26 
27 // Qt also does clipping when the coordinates go over +/- 32767
28 // moreover from Qt 4.6, Qt clips also when the width/height of a painter path
29 // is more than 32767. Since we want to avoid clipping by Qt (because it is slow)
30 // we set coordinate limit to less than 32767 / 2
31 const double QgsClipper::MAX_X = 16000;
32 const double QgsClipper::MIN_X = -16000;
33 const double QgsClipper::MAX_Y = 16000;
34 const double QgsClipper::MIN_Y = -16000;
35 
36 const double QgsClipper::SMALL_NUM = 1e-12;
37 
38 const unsigned char* QgsClipper::clippedLineWKB( const unsigned char* wkb, const QgsRectangle& clipExtent, QPolygonF& line )
39 {
40  wkb++; // jump over endian info
41  unsigned int wkbType = *(( int* ) wkb );
42  wkb += sizeof( unsigned int );
43  unsigned int nPoints = *(( int* ) wkb );
44  wkb += sizeof( unsigned int );
45 
46  bool hasZValue = ( wkbType == QGis::WKBLineString25D );
47 
48  int sizeOfDoubleX = sizeof( double );
49  int sizeOfDoubleY = hasZValue ? 2 * sizeof( double ) : sizeof( double );
50 
51  double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
52  double p1x_c, p1y_c; //clipped end coordinates
53  double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
54 
55  line.clear();
56  line.reserve( nPoints + 1 );
57 
58  for ( unsigned int i = 0; i < nPoints; ++i )
59  {
60  if ( i == 0 )
61  {
62  memcpy( &p1x, wkb, sizeof( double ) ); wkb += sizeOfDoubleX;
63  memcpy( &p1y, wkb, sizeof( double ) ); wkb += sizeOfDoubleY;
64 
65  continue;
66  }
67  else
68  {
69  p0x = p1x;
70  p0y = p1y;
71 
72  memcpy( &p1x, wkb, sizeof( double ) ); wkb += sizeOfDoubleX;
73  memcpy( &p1y, wkb, sizeof( double ) ); wkb += sizeOfDoubleY;
74 
75  p1x_c = p1x; p1y_c = p1y;
76  if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
77  p0x, p0y, p1x_c, p1y_c ) )
78  {
79  bool newLine = line.size() > 0 && ( p0x != lastClipX || p0y != lastClipY );
80  if ( newLine )
81  {
82  //add edge points to connect old and new line
83  connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
84  }
85  if ( line.size() < 1 || newLine )
86  {
87  //add first point
88  line << QPointF( p0x, p0y );
89  }
90 
91  //add second point
92  lastClipX = p1x_c; lastClipY = p1y_c;
93  line << QPointF( p1x_c, p1y_c );
94  }
95  }
96  }
97  return wkb;
98 }
99 
100 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
101  const QgsRectangle& clipRect, QPolygonF& pts )
102 {
103  //test the different edge combinations...
104  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
105  {
106  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
107  {
108  return;
109  }
110  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
111  {
112  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
113  return;
114  }
115  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
116  {
117  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
118  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
119  return;
120  }
121  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
122  {
123  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
124  return;
125  }
126  }
127  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
128  {
129  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
130  {
131  return;
132  }
133  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
134  {
135  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
136  return;
137  }
138  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
139  {
140  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
141  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
142  return;
143  }
144  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
145  {
146  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
147  return;
148  }
149  }
150  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
151  {
152  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
153  {
154  return;
155  }
156  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
157  {
158  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
159  return;
160  }
161  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
162  {
163  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
164  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
165  return;
166  }
167  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
168  {
169  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
170  return;
171  }
172  }
173  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
174  {
175  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
176  {
177  return;
178  }
179  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
180  {
181  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
182  return;
183  }
184  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
185  {
186  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
187  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
188  return;
189  }
190  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
191  {
192  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
193  return;
194  }
195  }
196 }
static const double MAX_Y
Definition: qgsclipper.h:64
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static const double SMALL_NUM
Definition: qgsclipper.h:92
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:194
static const unsigned char * clippedLineWKB(const unsigned char *wkb, const QgsRectangle &clipExtent, QPolygonF &line)
Reads a polyline from WKB and clips it to clipExtent.
Definition: qgsclipper.cpp:38
static bool clipLineSegment(double xLeft, double xRight, double yBottom, double yTop, double &x0, double &y0, double &x1, double &y1)
Definition: qgsclipper.h:480
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
static const double MIN_X
Definition: qgsclipper.h:63
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:199
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:184
static void connectSeparatedLines(double x0, double y0, double x1, double y1, const QgsRectangle &clipRect, QPolygonF &pts)
Connects two lines split by the clip (by inserting points on the clip border)
Definition: qgsclipper.cpp:100
static const double MIN_Y
Definition: qgsclipper.h:65
static const double MAX_X
Definition: qgsclipper.h:62
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189