QGIS API Documentation  2.12.0-Lyon
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(( QgsWKBTypes::Type )wkbType );
49  bool hasMValue = QgsWKBTypes::hasM(( 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; p1y_c = p1y;
83  if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
84  p0x, p0y, p1x_c, p1y_c ) )
85  {
86  bool newLine = line.size() > 0 && ( p0x != lastClipX || p0y != lastClipY );
87  if ( newLine )
88  {
89  //add edge points to connect old and new line
90  connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
91  }
92  if ( line.size() < 1 || newLine )
93  {
94  //add first point
95  line << QPointF( p0x, p0y );
96  }
97 
98  //add second point
99  lastClipX = p1x_c; lastClipY = p1y_c;
100  line << QPointF( p1x_c, p1y_c );
101  }
102  }
103  }
104  return wkbPtr;
105 }
106 
107 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
108  const QgsRectangle& clipRect, QPolygonF& pts )
109 {
110  //test the different edge combinations...
111  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
112  {
113  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
114  {
115  return;
116  }
117  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
118  {
119  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
120  return;
121  }
122  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
123  {
124  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
125  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
126  return;
127  }
128  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
129  {
130  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
131  return;
132  }
133  }
134  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
135  {
136  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
137  {
138  return;
139  }
140  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
141  {
142  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
143  return;
144  }
145  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
146  {
147  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
148  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
149  return;
150  }
151  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
152  {
153  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
154  return;
155  }
156  }
157  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
158  {
159  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
160  {
161  return;
162  }
163  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
164  {
165  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
166  return;
167  }
168  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
169  {
170  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
171  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
172  return;
173  }
174  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
175  {
176  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
177  return;
178  }
179  }
180  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
181  {
182  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
183  {
184  return;
185  }
186  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
187  {
188  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
189  return;
190  }
191  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
192  {
193  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
194  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
195  return;
196  }
197  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
198  {
199  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
200  return;
201  }
202  }
203 }
static const double MAX_Y
Definition: qgsclipper.h:64
A rectangle specified with double values.
Definition: qgsrectangle.h:35
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:268
static const double MIN_X
Definition: qgsclipper.h:63
void clear()
static bool hasM(Type type)
Tests whether a WKB type contains m values.
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
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
void reserve(int size)
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