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