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 
40 const unsigned char* QgsClipper::clippedLineWKB( const unsigned char* wkb, const QgsRectangle& clipExtent, QPolygonF& line )
41 {
42  QgsConstWkbPtr wkbPtr( wkb + 1 );
43 
44  unsigned int wkbType, nPoints;
45 
46  wkbPtr >> wkbType >> nPoints;
47 
48  bool hasZValue = QgsWKBTypes::hasZ( static_cast< QgsWKBTypes::Type >( wkbType ) );
49  bool hasMValue = QgsWKBTypes::hasM( static_cast< QgsWKBTypes::Type >( wkbType ) );
50 
51 
52  double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
53  double p1x_c, p1y_c; //clipped end coordinates
54  double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
55 
56  line.clear();
57  line.reserve( nPoints + 1 );
58 
59  for ( unsigned int i = 0; i < nPoints; ++i )
60  {
61  if ( i == 0 )
62  {
63  wkbPtr >> p1x >> p1y;
64  if ( hasZValue )
65  wkbPtr += sizeof( double );
66  if ( hasMValue )
67  wkbPtr += sizeof( double );
68 
69  continue;
70  }
71  else
72  {
73  p0x = p1x;
74  p0y = p1y;
75 
76  wkbPtr >> p1x >> p1y;
77  if ( hasZValue )
78  wkbPtr += sizeof( double );
79  if ( hasMValue )
80  wkbPtr += sizeof( double );
81 
82  p1x_c = p1x;
83  p1y_c = p1y;
84  if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
85  p0x, p0y, p1x_c, p1y_c ) )
86  {
87  bool newLine = !line.isEmpty() && ( !qgsDoubleNear( p0x, lastClipX ) || !qgsDoubleNear( p0y, lastClipY ) );
88  if ( newLine )
89  {
90  //add edge points to connect old and new line
91  connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
92  }
93  if ( line.size() < 1 || newLine )
94  {
95  //add first point
96  line << QPointF( p0x, p0y );
97  }
98 
99  //add second point
100  lastClipX = p1x_c;
101  lastClipY = p1y_c;
102  line << QPointF( p1x_c, p1y_c );
103  }
104  }
105  }
106  return wkbPtr;
107 }
108 
109 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
110  const QgsRectangle& clipRect, QPolygonF& pts )
111 {
112  //test the different edge combinations...
113  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
114  {
115  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
116  {
117  return;
118  }
119  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
120  {
121  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
122  return;
123  }
124  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
125  {
126  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
127  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
128  return;
129  }
130  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
131  {
132  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
133  return;
134  }
135  }
136  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
137  {
138  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
139  {
140  return;
141  }
142  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
143  {
144  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
145  return;
146  }
147  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
148  {
149  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
150  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
151  return;
152  }
153  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
154  {
155  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
156  return;
157  }
158  }
159  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
160  {
161  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
162  {
163  return;
164  }
165  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
166  {
167  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
168  return;
169  }
170  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
171  {
172  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
173  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
174  return;
175  }
176  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
177  {
178  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
179  return;
180  }
181  }
182  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
183  {
184  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
185  {
186  return;
187  }
188  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
189  {
190  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
191  return;
192  }
193  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
194  {
195  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
196  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
197  return;
198  }
199  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
200  {
201  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
202  return;
203  }
204  }
205 }
static const double MAX_Y
Definition: qgsclipper.h:64
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:703
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:196
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:40
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:656
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
static const double MIN_X
Definition: qgsclipper.h:63
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:65
static const double MAX_X
Definition: qgsclipper.h:62
int size() const
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:191