Branch data Line data Source code
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 : 0 : QPolygonF QgsClipper::clippedLine( const QgsCurve &curve, const QgsRectangle &clipExtent )
42 : : {
43 : 0 : return clippedLine( curve.asQPolygonF(), clipExtent );
44 : 0 : }
45 : :
46 : 0 : QPolygonF QgsClipper::clippedLine( const QPolygonF &curve, const QgsRectangle &clipExtent )
47 : : {
48 : 0 : const int nPoints = curve.size();
49 : :
50 : 0 : double p0x, p0y, p1x = 0.0, p1y = 0.0; //original coordinates
51 : : double p1x_c, p1y_c; //clipped end coordinates
52 : 0 : double lastClipX = 0.0, lastClipY = 0.0; //last successfully clipped coords
53 : :
54 : 0 : QPolygonF line;
55 : 0 : line.reserve( nPoints + 1 );
56 : :
57 : 0 : const QPointF *curveData = curve.data();
58 : :
59 : 0 : for ( int i = 0; i < nPoints; ++i )
60 : : {
61 : 0 : if ( i == 0 )
62 : : {
63 : 0 : p1x = curveData->x();
64 : 0 : p1y = curveData->y();
65 : 0 : }
66 : : else
67 : : {
68 : 0 : p0x = p1x;
69 : 0 : p0y = p1y;
70 : :
71 : 0 : p1x = curveData->x();
72 : 0 : p1y = curveData->y();
73 : :
74 : 0 : p1x_c = p1x;
75 : 0 : p1y_c = p1y;
76 : 0 : if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
77 : : p0x, p0y, p1x_c, p1y_c ) )
78 : : {
79 : 0 : bool newLine = !line.isEmpty() && ( !qgsDoubleNear( p0x, lastClipX ) || !qgsDoubleNear( p0y, lastClipY ) );
80 : 0 : if ( newLine )
81 : : {
82 : : //add edge points to connect old and new line
83 : 0 : connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
84 : 0 : }
85 : 0 : if ( line.empty() || newLine )
86 : : {
87 : : //add first point
88 : 0 : line << QPointF( p0x, p0y );
89 : 0 : }
90 : :
91 : : //add second point
92 : 0 : lastClipX = p1x_c;
93 : 0 : lastClipY = p1y_c;
94 : 0 : line << QPointF( p1x_c, p1y_c );
95 : 0 : }
96 : : }
97 : 0 : curveData++;
98 : 0 : }
99 : 0 : return line;
100 : 0 : }
101 : :
102 : 0 : 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 : 0 : if ( qgsDoubleNear( x0, clipRect.xMinimum() ) )
107 : : {
108 : 0 : if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
109 : : {
110 : 0 : return;
111 : : }
112 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
113 : : {
114 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
115 : 0 : return;
116 : : }
117 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
118 : : {
119 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
120 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
121 : 0 : return;
122 : : }
123 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
124 : : {
125 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
126 : 0 : return;
127 : : }
128 : 0 : }
129 : 0 : else if ( qgsDoubleNear( y0, clipRect.yMaximum() ) )
130 : : {
131 : 0 : if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
132 : : {
133 : 0 : return;
134 : : }
135 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
136 : : {
137 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
138 : 0 : return;
139 : : }
140 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
141 : : {
142 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
143 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
144 : 0 : return;
145 : : }
146 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
147 : : {
148 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
149 : 0 : return;
150 : : }
151 : 0 : }
152 : 0 : else if ( qgsDoubleNear( x0, clipRect.xMaximum() ) )
153 : : {
154 : 0 : if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
155 : : {
156 : 0 : return;
157 : : }
158 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
159 : : {
160 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
161 : 0 : return;
162 : : }
163 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
164 : : {
165 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
166 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
167 : 0 : return;
168 : : }
169 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
170 : : {
171 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
172 : 0 : return;
173 : : }
174 : 0 : }
175 : 0 : else if ( qgsDoubleNear( y0, clipRect.yMinimum() ) )
176 : : {
177 : 0 : if ( qgsDoubleNear( y1, clipRect.yMinimum() ) )
178 : : {
179 : 0 : return;
180 : : }
181 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMinimum() ) )
182 : : {
183 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
184 : 0 : return;
185 : : }
186 : 0 : else if ( qgsDoubleNear( y1, clipRect.yMaximum() ) )
187 : : {
188 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
189 : 0 : pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
190 : 0 : return;
191 : : }
192 : 0 : else if ( qgsDoubleNear( x1, clipRect.xMaximum() ) )
193 : : {
194 : 0 : pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
195 : 0 : return;
196 : : }
197 : 0 : }
198 : 0 : }
|