QGIS API Documentation  2.17.0-Master (872e6d2)
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 #include "qgsgeometry.h"
21 #include "qgswkbptr.h"
22 #include "qgslogger.h"
23 
24 // Where has all the code gone?
25 
26 // It's been inlined, so its in the qgsclipper.h file.
27 
28 // But the static members must be initialized outside the class! (or GCC 4 dies)
29 
30 // Qt also does clipping when the coordinates go over +/- 32767
31 // moreover from Qt 4.6, Qt clips also when the width/height of a painter path
32 // is more than 32767. Since we want to avoid clipping by Qt (because it is slow)
33 // we set coordinate limit to less than 32767 / 2
34 const double QgsClipper::MAX_X = 16000;
35 const double QgsClipper::MIN_X = -16000;
36 const double QgsClipper::MAX_Y = 16000;
37 const double QgsClipper::MIN_Y = -16000;
38 
39 const double QgsClipper::SMALL_NUM = 1e-12;
40 
42 {
43  QgsWKBTypes::Type wkbType = wkbPtr.readHeader();
44 
45  int nPoints;
46  wkbPtr >> nPoints;
47 
48  int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double );
49 
50  if ( static_cast<int>( nPoints * ( 2 * sizeof( double ) + skipZM ) ) > wkbPtr.remaining() )
51  {
52  QgsDebugMsg( QString( "%1 points exceed wkb length (%2>%3)" ).arg( nPoints ).arg( nPoints * ( 2 * sizeof( double ) + skipZM ) ).arg( wkbPtr.remaining() ) );
53  return QgsConstWkbPtr( nullptr, 0 );
54  }
55 
56  double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
57  double p1x_c, p1y_c; //clipped end coordinates
58  double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
59 
60  QPolygonF pts;
61  wkbPtr -= sizeof( unsigned int );
62  wkbPtr >> pts;
63  nPoints = pts.size();
64 
65  line.clear();
66  line.reserve( nPoints + 1 );
67 
68  QPointF *ptr = pts.data();
69 
70  for ( int i = 0; i < nPoints; ++i, ++ptr )
71  {
72  if ( i == 0 )
73  {
74  p1x = ptr->rx();
75  p1y = ptr->ry();
76  continue;
77  }
78  else
79  {
80  p0x = p1x;
81  p0y = p1y;
82 
83  p1x = ptr->rx();
84  p1y = ptr->ry();
85 
86  p1x_c = p1x;
87  p1y_c = p1y;
88  if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
89  p0x, p0y, p1x_c, p1y_c ) )
90  {
91  bool newLine = !line.isEmpty() && ( !qgsDoubleNear( p0x, lastClipX ) || !qgsDoubleNear( p0y, lastClipY ) );
92  if ( newLine )
93  {
94  //add edge points to connect old and new line
95  connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
96  }
97  if ( line.size() < 1 || newLine )
98  {
99  //add first point
100  line << QPointF( p0x, p0y );
101  }
102 
103  //add second point
104  lastClipX = p1x_c;
105  lastClipY = p1y_c;
106  line << QPointF( p1x_c, p1y_c );
107  }
108  }
109  }
110  return wkbPtr;
111 }
112 
113 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
114  const QgsRectangle& clipRect, QPolygonF& pts )
115 {
116  //test the different edge combinations...
117  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
118  {
119  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
120  {
121  return;
122  }
123  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
124  {
125  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
126  return;
127  }
128  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
129  {
130  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
131  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
132  return;
133  }
134  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
135  {
136  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
137  return;
138  }
139  }
140  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
141  {
142  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
143  {
144  return;
145  }
146  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
147  {
148  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
149  return;
150  }
151  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
152  {
153  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
154  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
155  return;
156  }
157  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
158  {
159  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
160  return;
161  }
162  }
163  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
164  {
165  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
166  {
167  return;
168  }
169  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
170  {
171  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
172  return;
173  }
174  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
175  {
176  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
177  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
178  return;
179  }
180  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
181  {
182  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
183  return;
184  }
185  }
186  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
187  {
188  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
189  {
190  return;
191  }
192  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
193  {
194  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
195  return;
196  }
197  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
198  {
199  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
200  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
201  return;
202  }
203  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
204  {
205  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
206  return;
207  }
208  }
209 }
static int coordDimensions(Type type)
Returns the coordinate dimension of the geometry type as an integer.
Definition: qgswkbtypes.h:573
static const double MAX_Y
Definition: qgsclipper.h:65
A rectangle specified with double values.
Definition: qgsrectangle.h:35
int remaining() const
Definition: qgswkbptr.h:133
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:197
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
static QgsConstWkbPtr clippedLineWKB(QgsConstWkbPtr &wkb, const QgsRectangle &clipExtent, QPolygonF &line)
Reads a polyline from WKB and clips it to clipExtent.
Definition: qgsclipper.cpp:41
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:38
static const double MIN_X
Definition: qgsclipper.h:64
void clear()
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:202
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:187
void reserve(int size)
bool isEmpty() const
qreal & rx()
qreal & ry()
static const double MIN_Y
Definition: qgsclipper.h:66
static const double MAX_X
Definition: qgsclipper.h:63
int size() const
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:192