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