QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 "qgscurve.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 
41 QPolygonF QgsClipper::clippedLine( const QgsCurve &curve, const QgsRectangle &clipExtent )
42 {
43  const int nPoints = curve.numPoints();
44 
45  double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
46  double p1x_c, p1y_c; //clipped end coordinates
47  double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
48 
49  QPolygonF line;
50  line.reserve( nPoints + 1 );
51 
52  for ( int i = 0; i < nPoints; ++i )
53  {
54  if ( i == 0 )
55  {
56  p1x = curve.xAt( i );
57  p1y = curve.yAt( i );
58  continue;
59  }
60  else
61  {
62  p0x = p1x;
63  p0y = p1y;
64 
65  p1x = curve.xAt( i );
66  p1y = curve.yAt( i );
67 
68  p1x_c = p1x;
69  p1y_c = p1y;
70  if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
71  p0x, p0y, p1x_c, p1y_c ) )
72  {
73  bool newLine = !line.isEmpty() && ( !qgsDoubleNear( p0x, lastClipX ) || !qgsDoubleNear( p0y, lastClipY ) );
74  if ( newLine )
75  {
76  //add edge points to connect old and new line
77  connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
78  }
79  if ( line.empty() || newLine )
80  {
81  //add first point
82  line << QPointF( p0x, p0y );
83  }
84 
85  //add second point
86  lastClipX = p1x_c;
87  lastClipY = p1y_c;
88  line << QPointF( p1x_c, p1y_c );
89  }
90  }
91  }
92  return line;
93 }
94 
95 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
96  const QgsRectangle &clipRect, QPolygonF &pts )
97 {
98  //test the different edge combinations...
99  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
100  {
101  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
102  {
103  return;
104  }
105  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
106  {
107  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
108  return;
109  }
110  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
111  {
112  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
113  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
114  return;
115  }
116  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
117  {
118  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
119  return;
120  }
121  }
122  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
123  {
124  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
125  {
126  return;
127  }
128  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
129  {
130  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
131  return;
132  }
133  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
134  {
135  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
136  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
137  return;
138  }
139  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
140  {
141  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
142  return;
143  }
144  }
145  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
146  {
147  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
148  {
149  return;
150  }
151  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
152  {
153  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
154  return;
155  }
156  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
157  {
158  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
159  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
160  return;
161  }
162  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
163  {
164  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
165  return;
166  }
167  }
168  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
169  {
170  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
171  {
172  return;
173  }
174  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
175  {
176  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
177  return;
178  }
179  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
180  {
181  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
182  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
183  return;
184  }
185  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
186  {
187  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
188  return;
189  }
190  }
191 }
static const double MAX_Y
Maximum Y-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:71
A rectangle specified with double values.
Definition: qgsrectangle.h:41
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
static const double MIN_X
Minimum X-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:69
virtual double xAt(int index) const =0
Returns the x-coordinate of the specified node in the line string.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
static QPolygonF clippedLine(const QgsCurve &curve, const QgsRectangle &clipExtent)
Takes a linestring and clips it to clipExtent.
Definition: qgsclipper.cpp:41
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
static const double MIN_Y
Minimum Y-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:73
static const double MAX_X
Maximum X-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:67
virtual int numPoints() const =0
Returns the number of points in the curve.