QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 
21 // Where has all the code gone?
22 
23 // It's been inlined, so its in the qgsclipper.h file.
24 
25 // But the static members must be initialised outside the class! (or GCC 4 dies)
26 
27 // Qt also does clipping when the coordinates go over +/- 32767
28 // moreover from Qt 4.6, Qt clips also when the width/height of a painter path
29 // is more than 32767. Since we want to avoid clipping by Qt (because it is slow)
30 // we set coordinate limit to less than 32767 / 2
31 const double QgsClipper::MAX_X = 16000;
32 const double QgsClipper::MIN_X = -16000;
33 const double QgsClipper::MAX_Y = 16000;
34 const double QgsClipper::MIN_Y = -16000;
35 
36 const double QgsClipper::SMALL_NUM = 1e-12;
37 
38 const unsigned char* QgsClipper::clippedLineWKB( const unsigned char* wkb, const QgsRectangle& clipExtent, QPolygonF& line )
39 {
40  wkb++; // jump over endian info
41  unsigned int wkbType = *(( int* ) wkb );
42  wkb += sizeof( unsigned int );
43  unsigned int nPoints = *(( int* ) wkb );
44  wkb += sizeof( unsigned int );
45 
46  bool hasZValue = ( wkbType == QGis::WKBLineString25D );
47 
48  double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
49  double p1x_c, p1y_c; //clipped end coordinates
50  double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
51 
52  line.reserve( nPoints + 1 );
53  line.clear();
54 
55  for ( unsigned int i = 0; i < nPoints; ++i )
56  {
57  if ( i == 0 )
58  {
59  memcpy( &p1x, wkb, sizeof( double ) );
60  wkb += sizeof( double );
61  memcpy( &p1y, wkb, sizeof( double ) );
62  wkb += sizeof( double );
63  if ( hasZValue ) // ignore Z value
64  {
65  wkb += sizeof( double );
66  }
67  continue;
68  }
69  else
70  {
71  p0x = p1x;
72  p0y = p1y;
73 
74  memcpy( &p1x, wkb, sizeof( double ) );
75  wkb += sizeof( double );
76  memcpy( &p1y, wkb, sizeof( double ) );
77  wkb += sizeof( double );
78  if ( hasZValue ) // ignore Z value
79  {
80  wkb += sizeof( double );
81  }
82 
83  p1x_c = p1x; 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.size() > 0 && ( p0x != lastClipX || 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; lastClipY = p1y_c;
101  line << QPointF( p1x_c, p1y_c );
102  }
103  }
104  }
105  return wkb;
106 }
107 
108 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
109  const QgsRectangle& clipRect, QPolygonF& pts )
110 {
111  //test the different edge combinations...
112  if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
113  {
114  if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
115  {
116  return;
117  }
118  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
119  {
120  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
121  return;
122  }
123  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
124  {
125  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
126  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
127  return;
128  }
129  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
130  {
131  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
132  return;
133  }
134  }
135  else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
136  {
137  if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
138  {
139  return;
140  }
141  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
142  {
143  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
144  return;
145  }
146  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
147  {
148  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
149  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
150  return;
151  }
152  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
153  {
154  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
155  return;
156  }
157  }
158  else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
159  {
160  if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
161  {
162  return;
163  }
164  else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
165  {
166  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
167  return;
168  }
169  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
170  {
171  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
172  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
173  return;
174  }
175  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
176  {
177  pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
178  return;
179  }
180  }
181  else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
182  {
183  if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
184  {
185  return;
186  }
187  else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
188  {
189  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
190  return;
191  }
192  else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
193  {
194  pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
195  pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
196  return;
197  }
198  else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
199  {
200  pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
201  return;
202  }
203  }
204 }