qwt_clipper.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_clipper.h"
11 #include "qwt_point_polar.h"
12 #include <qrect.h>
13 #include <string.h>
14 #include <stdlib.h>
15 
16 #if QT_VERSION < 0x040601
17 #define qAtan(x) ::atan(x)
18 #endif
19 
20 namespace QwtClip
21 {
22  // some templates used for inlining
23  template <class Point, typename T> class LeftEdge;
24  template <class Point, typename T> class RightEdge;
25  template <class Point, typename T> class TopEdge;
26  template <class Point, typename T> class BottomEdge;
27 }
28 
29 template <class Point, typename Value>
31 {
32 public:
33  inline LeftEdge( Value x1, Value, Value, Value ):
34  d_x1( x1 )
35  {
36  }
37 
38  inline bool isInside( const Point &p ) const
39  {
40  return p.x() >= d_x1;
41  }
42 
43  inline Point intersection( const Point &p1, const Point &p2 ) const
44  {
45  double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
46  return Point( d_x1, static_cast< Value >( p2.y() + ( d_x1 - p2.x() ) * dy ) );
47  }
48 private:
49  const Value d_x1;
50 };
51 
52 template <class Point, typename Value>
54 {
55 public:
56  inline RightEdge( Value, Value x2, Value, Value ):
57  d_x2( x2 )
58  {
59  }
60 
61  inline bool isInside( const Point &p ) const
62  {
63  return p.x() <= d_x2;
64  }
65 
66  inline Point intersection( const Point &p1, const Point &p2 ) const
67  {
68  double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
69  return Point( d_x2, static_cast<Value>( p2.y() + ( d_x2 - p2.x() ) * dy ) );
70  }
71 
72 private:
73  const Value d_x2;
74 };
75 
76 template <class Point, typename Value>
77 class QwtClip::TopEdge
78 {
79 public:
80  inline TopEdge( Value, Value, Value y1, Value ):
81  d_y1( y1 )
82  {
83  }
84 
85  inline bool isInside( const Point &p ) const
86  {
87  return p.y() >= d_y1;
88  }
89 
90  inline Point intersection( const Point &p1, const Point &p2 ) const
91  {
92  double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
93  return Point( static_cast<Value>( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 );
94  }
95 
96 private:
97  const Value d_y1;
98 };
99 
100 template <class Point, typename Value>
102 {
103 public:
104  inline BottomEdge( Value, Value, Value, Value y2 ):
105  d_y2( y2 )
106  {
107  }
108 
109  inline bool isInside( const Point &p ) const
110  {
111  return p.y() <= d_y2;
112  }
113 
114  inline Point intersection( const Point &p1, const Point &p2 ) const
115  {
116  double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
117  return Point( static_cast<Value>( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 );
118  }
119 
120 private:
121  const Value d_y2;
122 };
123 
124 using namespace QwtClip;
125 
126 template <class Polygon, class Rect, typename T>
128 {
129  typedef typename Polygon::value_type Point;
130 public:
131  explicit QwtPolygonClipper( const Rect &clipRect ):
132  d_clipRect( clipRect )
133  {
134  }
135 
136  void clipPolygon( Polygon &points1, bool closePolygon ) const
137  {
138 #if 0
139  if ( d_clipRect.contains( points1.boundingRect() ) )
140  return polygon;
141 #endif
142 
143  Polygon points2;
144  points2.reserve( qMin( 256, points1.size() ) );
145 
146  clipEdge< LeftEdge<Point, T> >( closePolygon, points1, points2 );
147  clipEdge< RightEdge<Point, T> >( closePolygon, points2, points1 );
148  clipEdge< TopEdge<Point, T> >( closePolygon, points1, points2 );
149  clipEdge< BottomEdge<Point, T> >( closePolygon, points2, points1 );
150  }
151 
152 private:
153  template <class Edge>
154  inline void clipEdge( bool closePolygon,
155  const Polygon &points, Polygon &clippedPoints ) const
156  {
157  clippedPoints.clear();
158 
159  if ( points.size() < 2 )
160  {
161  if ( points.size() == 1 )
162  clippedPoints += points[0];
163 
164  return;
165  }
166 
167  const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(),
168  d_clipRect.y(), d_clipRect.y() + d_clipRect.height() );
169 
170  if ( !closePolygon )
171  {
172  const Point &p1 = points.first();
173 
174  if ( edge.isInside( p1 ) )
175  clippedPoints += p1;
176  }
177  else
178  {
179  const Point &p1 = points.first();
180  const Point &p2 = points.last();
181 
182  if ( edge.isInside( p1 ) )
183  {
184  if ( !edge.isInside( p2 ) )
185  clippedPoints += edge.intersection( p1, p2 );
186 
187  clippedPoints += p1;
188  }
189  else if ( edge.isInside( p2 ) )
190  {
191  clippedPoints += edge.intersection( p1, p2 );
192  }
193  }
194 
195  const uint nPoints = points.size();
196  const Point* p = points.constData();
197 
198  for ( uint i = 1; i < nPoints; i++ )
199  {
200  const Point &p1 = p[i];
201  const Point &p2 = p[i - 1];
202 
203  if ( edge.isInside( p1 ) )
204  {
205  if ( !edge.isInside( p2 ) )
206  clippedPoints += edge.intersection( p1, p2 );
207 
208  clippedPoints += p1;
209  }
210  else if ( edge.isInside( p2 ) )
211  {
212  clippedPoints += edge.intersection( p1, p2 );
213  }
214  }
215  }
216 
217  const Rect d_clipRect;
218 };
219 
221 {
222 public:
223  explicit QwtCircleClipper( const QRectF &r );
224  QVector<QwtInterval> clipCircle( const QPointF &, double radius ) const;
225 
226 private:
227  enum Edge
228  {
233 
234  NEdges
235  };
236 
237  QVector<QPointF> cuttingPoints(
238  Edge, const QPointF &pos, double radius ) const;
239 
240  double toAngle( const QPointF &, const QPointF & ) const;
241 
242  const QRectF d_rect;
243 };
244 
245 
247  d_rect( r )
248 {
249 }
250 
251 QVector<QwtInterval> QwtCircleClipper::clipCircle(
252  const QPointF &pos, double radius ) const
253 {
254  QVector<QPointF> points;
255  for ( int edge = 0; edge < NEdges; edge++ )
256  points += cuttingPoints( static_cast<Edge>(edge), pos, radius );
257 
258  QVector<QwtInterval> intv;
259  if ( points.size() <= 0 )
260  {
261  QRectF cRect( 0, 0, 2 * radius, 2 * radius );
262  cRect.moveCenter( pos );
263  if ( d_rect.contains( cRect ) )
264  intv += QwtInterval( 0.0, 2 * M_PI );
265  }
266  else
267  {
268  QList<double> angles;
269 #if QT_VERSION >= 0x040700
270  angles.reserve( points.size() );
271 #endif
272 
273  for ( int i = 0; i < points.size(); i++ )
274  angles += toAngle( pos, points[i] );
275 
276  qSort( angles );
277 
278  const int in = d_rect.contains( qwtPolar2Pos( pos, radius,
279  angles[0] + ( angles[1] - angles[0] ) / 2 ) );
280 
281  intv.reserve( angles.size() / 2 );
282  if ( in )
283  {
284  for ( int i = 0; i < angles.size() - 1; i += 2 )
285  intv += QwtInterval( angles[i], angles[i+1] );
286  }
287  else
288  {
289  for ( int i = 1; i < angles.size() - 1; i += 2 )
290  intv += QwtInterval( angles[i], angles[i+1] );
291 
292  intv += QwtInterval( angles.last(), angles.first() );
293  }
294  }
295 
296  return intv;
297 }
298 
300  const QPointF &from, const QPointF &to ) const
301 {
302  if ( from.x() == to.x() )
303  return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0;
304 
305  const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) );
306 
307  double angle = qAtan( m );
308  if ( to.x() > from.x() )
309  {
310  if ( to.y() > from.y() )
311  angle = 2 * M_PI - angle;
312  }
313  else
314  {
315  if ( to.y() > from.y() )
316  angle = M_PI + angle;
317  else
318  angle = M_PI - angle;
319  }
320 
321  return angle;
322 }
323 
325  Edge edge, const QPointF &pos, double radius ) const
326 {
327  QVector<QPointF> points;
328 
329  if ( edge == Left || edge == Right )
330  {
331  const double x = ( edge == Left ) ? d_rect.left() : d_rect.right();
332  if ( qAbs( pos.x() - x ) < radius )
333  {
334  const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) );
335  const double m_y1 = pos.y() + off;
336  if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() )
337  points += QPointF( x, m_y1 );
338 
339  const double m_y2 = pos.y() - off;
340  if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() )
341  points += QPointF( x, m_y2 );
342  }
343  }
344  else
345  {
346  const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom();
347  if ( qAbs( pos.y() - y ) < radius )
348  {
349  const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) );
350  const double x1 = pos.x() + off;
351  if ( x1 >= d_rect.left() && x1 <= d_rect.right() )
352  points += QPointF( x1, y );
353 
354  const double m_x2 = pos.x() - off;
355  if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() )
356  points += QPointF( m_x2, y );
357  }
358  }
359  return points;
360 }
361 
370  const QRectF &clipRect, QPolygon &polygon, bool closePolygon )
371 {
372  const int minX = qCeil( clipRect.left() );
373  const int maxX = qFloor( clipRect.right() );
374  const int minY = qCeil( clipRect.top() );
375  const int maxY = qFloor( clipRect.bottom() );
376 
377  const QRect r( minX, minY, maxX - minX, maxY - minY );
378 
380  clipper.clipPolygon( polygon, closePolygon );
381 }
382 
391  const QRect &clipRect, QPolygon &polygon, bool closePolygon )
392 {
393  QwtPolygonClipper<QPolygon, QRect, int> clipper( clipRect );
394  clipper.clipPolygon( polygon, closePolygon );
395 }
396 
405  const QRectF &clipRect, QPolygonF &polygon, bool closePolygon )
406 {
408  clipper.clipPolygon( polygon, closePolygon );
409 }
410 
421  const QRectF &clipRect, const QPolygon &polygon, bool closePolygon )
422 {
423  QPolygon points( polygon );
424  clipPolygon( clipRect, points, closePolygon );
425 
426  return points;
427 }
438  const QRect &clipRect, const QPolygon &polygon, bool closePolygon )
439 {
440  QPolygon points( polygon );
441  clipPolygon( clipRect, points, closePolygon );
442 
443  return points;
444 }
445 
456  const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon )
457 {
458  QPolygonF points( polygon );
459  clipPolygonF( clipRect, points, closePolygon );
460 
461  return points;
462 }
463 
477 QVector<QwtInterval> QwtClipper::clipCircle( const QRectF &clipRect,
478  const QPointF &center, double radius )
479 {
480  QwtCircleClipper clipper( clipRect );
481  return clipper.clipCircle( center, radius );
482 }
Polygon::value_type Point
QwtCircleClipper(const QRectF &r)
A class representing an interval.
Definition: qwt_interval.h:26
Point intersection(const Point &p1, const Point &p2) const
Definition: qwt_clipper.cpp:43
QPoint qwtPolar2Pos(const QPoint &pole, double radius, double angle)
bool isInside(const Point &p) const
Definition: qwt_clipper.cpp:61
bool isInside(const Point &p) const
bool isInside(const Point &p) const
Definition: qwt_clipper.cpp:38
bool isInside(const Point &p) const
Definition: qwt_clipper.cpp:85
const Value d_x2
Definition: qwt_clipper.cpp:73
TFSIMD_FORCE_INLINE const tfScalar & y() const
static QPolygonF clippedPolygonF(const QRectF &, const QPolygonF &, bool closePolygon=false)
void clipEdge(bool closePolygon, const Polygon &points, Polygon &clippedPoints) const
Point intersection(const Point &p1, const Point &p2) const
Definition: qwt_clipper.cpp:66
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
static QPolygon clippedPolygon(const QRect &, const QPolygon &, bool closePolygon=false)
TFSIMD_FORCE_INLINE const tfScalar & x() const
QVector< QwtInterval > clipCircle(const QPointF &, double radius) const
BottomEdge(Value, Value, Value, Value y2)
const Rect d_clipRect
Point intersection(const Point &p1, const Point &p2) const
Definition: qwt_clipper.cpp:90
static void clipPolygonF(const QRectF &, QPolygonF &, bool closePolygon=false)
TopEdge(Value, Value, Value y1, Value)
Definition: qwt_clipper.cpp:80
TFSIMD_FORCE_INLINE const tfScalar & y() const
RightEdge(Value, Value x2, Value, Value)
Definition: qwt_clipper.cpp:56
TFSIMD_FORCE_INLINE const tfScalar & x() const
NodeSet in
QwtPolygonClipper(const Rect &clipRect)
#define qAtan(x)
Definition: qwt_clipper.cpp:17
void clipPolygon(Polygon &points1, bool closePolygon) const
double toAngle(const QPointF &, const QPointF &) const
static QVector< QwtInterval > clipCircle(const QRectF &, const QPointF &, double radius)
const QRectF d_rect
double qwtSqr(double x)
Return the square of a number.
Definition: qwt_math.h:88
int i
QVector< QPointF > cuttingPoints(Edge, const QPointF &pos, double radius) const
Point intersection(const Point &p1, const Point &p2) const
const Value d_y1
Definition: qwt_clipper.cpp:97
static void clipPolygon(const QRect &, QPolygon &, bool closePolygon=false)
const Value d_x1
Definition: qwt_clipper.cpp:49
LeftEdge(Value x1, Value, Value, Value)
Definition: qwt_clipper.cpp:33


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17