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