Okular

area.h
1 /***************************************************************************
2  * Copyright (C) 2004-05 by Enrico Ros <[email protected]> *
3  * Copyright (C) 2005 by Piotr Szymanski <[email protected]> *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 2 of the License, or *
7  * (at your option) any later version. *
8  ***************************************************************************/
9 
10 #ifndef _OKULAR_AREA_H_
11 #define _OKULAR_AREA_H_
12 
13 #include <math.h>
14 
15 #include <QColor>
16 #include <QDebug>
17 #include <QList>
18 #include <QPainterPath>
19 #include <QTransform>
20 
21 #include "global.h"
22 #include "okularcore_export.h"
23 
24 class QPolygonF;
25 class QRect;
26 
27 namespace Okular
28 {
29 class Annotation;
30 class Action;
31 class NormalizedShape;
32 
33 /**
34  * NormalizedPoint is a helper class which stores the coordinates
35  * of a normalized point.
36  *
37  * @par Normalized Coordinate System
38  * @parblock
39  * Normalized means that the coordinates are always between 0 and 1,
40  * unless the point shall be outside of the reference area.
41  *
42  * The reference area is a rectangle, and all normalized points
43  * with coordinates of 0 or 1 describe its edges.
44  *
45  * This allows to locate things on a reference area without knowing its
46  * (current or future) actual size. When the reference area is resized,
47  * all things which are described in normalized coordinates keep their
48  * proportional position on the area.
49  * @endparblock
50  *
51  * @par Transformation to and from Normalized Coordinates
52  * @parblock
53  * To transform normalized coordinates to coordinates on the reference area,
54  * just multiply them with the size of the reference area.
55  *
56  * To get normalized coordinates from a point on the reference area,
57  * just divide its coordinates with the size of the reference area.
58  *
59  * Many methods have parameters @c xScale and @c yScale,
60  * these are equal to the size of the reference area.
61  * @endparblock
62  *
63  * @par Normalized Coordinate System Applied to Pages
64  * @parblock
65  * Okular uses a normalized coordinate system mainly to describe
66  * positions on pages.
67  * This is useful because pages can be shown in different sizes (zoom),
68  * but all objects shall keep their proportional position on the page.
69  *
70  * Okular maps from page to normalized coordinates as follows:
71  * * Left edge of the page: x = 0
72  * * Right edge of the page: x = 1
73  * * Top edge of the page: y = 0
74  * * Bottom edge of the page: y = 1
75  * @endparblock
76  *
77  * @par Example: Draw a Point on a Page
78  * @parblock
79  * The point is given in normalized coordinates (0.5, 0.3).
80  *
81  * If you want to draw it on a 800x600 page,
82  * just multiply the x coordinate (0.5) with the page width (800),
83  * and the y coordinate (0.3) with the page height (600).
84  * So, the point will be drawn on the page at (400, 180).
85  *
86  * That allows you to zoom the page by just multiplying the normalized points with the
87  * zoomed page size.
88  * @endparblock
89  *
90  * @par Example: Select Text on a Page using Mouse Events
91  * @parblock
92  * The position of all glyphs and words is stored in normalized coordinates.
93  * (This is what TextPage actually does.)
94  * Mouse press and release events are given in page coordinates (400, 180) and (600, 450),
95  * while the page has a size of 800x600.
96  *
97  * If you want to search all text between the mouse click and release event,
98  * you need their normalized coordinates.
99  * Just divide the x coordinates (400 and 600) by the page width (800),
100  * and the y coordinates (180 and 450) by the page height (600).
101  * So, you have to search for all glyphs between (0.5, 0.3) and (0.75, 0.75).
102  *
103  * That allows you to process all glyphs and words without
104  * having to keep any of their positions in sync with the page.
105  * @endparblock
106  *
107  * @par Geometric operations
108  * @parblock
109  * NormalizedPoint supports basic geometric operations.
110  * * You can transform it with a QTransform matrix.
111  * * With the size of the reference area, you can calculate the squared
112  * absolute distance to another NormalizedPoint or a line of two NormalizedPoints.
113  *
114  * NormalizedRect provides additional geometric operations for rectangles.
115  * @endparblock
116  *
117  * @see NormalizedRect
118  */
119 class OKULARCORE_EXPORT NormalizedPoint
120 {
121 public:
122  /**
123  * Creates a normalized point at (0, 0).
124  */
125  NormalizedPoint();
126 
127  /**
128  * Creates a new normalized point with the normalized coordinates (@p x, @p y ).
129  */
130  NormalizedPoint(double x, double y);
131 
132  /**
133  * Creates a new normalized point from an absolute point (@p x, @p y)
134  * on a reference area of size @p xScale x @p yScale.
135  */
136  NormalizedPoint(int x, int y, int xScale, int yScale);
137 
138  /**
139  * @internal
140  */
141  NormalizedPoint &operator=(const NormalizedPoint &);
142 
144  // TODO next ABI break, move the = default to here
145  ~NormalizedPoint(); // NOLINT(performance-trivially-destructible)
146 
147  /**
148  * Transforms the normalized point with the operations defined by @p matrix.
149  */
150  void transform(const QTransform &matrix);
151 
152  /**
153  * Returns squared distance to normalized point (@p x, @p y)
154  * on a reference area of size @p xScale x @p yScale.
155  * @since 0.17 (KDE 4.11)
156  */
157  double distanceSqr(double x, double y, double xScale, double yScale) const;
158 
159  /**
160  * Returns squared distance of the normalized point (@p x, @p y)
161  * to the line segment from @p start to @p end
162  * on a reference area of size @p xScale x @p yScale.
163  * @since 0.17 (KDE 4.11)
164  */
165  static double distanceSqr(double x, double y, double xScale, double yScale, const NormalizedPoint &start, const NormalizedPoint &end);
166 
167  /**
168  * The normalized x coordinate.
169  */
170  double x;
171 
172  /**
173  * The normalized y coordinate.
174  */
175  double y;
176 };
177 
178 /**
179  * A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
180  *
181  * It describes a rectangular area on a reference area of undefined size.
182  * For more information about the normalized coordinate system, see NormalizedPoint.
183  *
184  * In Okular, NormalizedRect can be used e. g. to describe bounding boxes of TextEntity objects,
185  * and the highlight area of text selections.
186  *
187  * If you need to describe an area which consists of multiple rectangles,
188  * you can use RegularAreaRect instead.
189  *
190  * @see NormalizedPoint, RegularAreaRect, TextEntity
191  */
192 class OKULARCORE_EXPORT NormalizedRect
193 {
194 public:
195  /**
196  * Creates a null normalized rectangle.
197  * @see isNull()
198  */
199  NormalizedRect();
200 
201  /**
202  * Creates a normalized rectangle with the normalized coordinates
203  * @p left, @p top, @p right, @p bottom.
204  *
205  * If you need the x, y, width and height coordinates use the
206  * following formulas:
207  *
208  * @li x = left
209  * @li y = top
210  * @li width = right - left
211  * @li height = bottom - top
212  *
213  * @note
214  * The coordinates for @p left and @p top should be lower than
215  * @p right and @p bottom, respectively.
216  * At negative width or height the behaviour of some operations is undefined.
217  */
218  NormalizedRect(double left, double top, double right, double bottom);
219 
220  /**
221  * Creates a normalized rectangle from the given @p rectangle
222  * on a reference area of size @p xScale x @p yScale.
223  *
224  * @note
225  * The rectangle should have positive width and height.
226  * You can use e. g. QRect::normalize() to ensure this.
227  * At negative width or height the behaviour of some operations is undefined.
228  */
229  NormalizedRect(const QRect &rectangle, double xScale, double yScale);
230 
231  /**
232  * @internal
233  */
235 
236  /**
237  * @internal
238  */
239  NormalizedRect &operator=(const NormalizedRect &other);
240 
241  // TODO next ABI break, move the = default to here
242  ~NormalizedRect(); // NOLINT(performance-trivially-destructible)
243 
244  /**
245  * Build a normalized rect from a QRectF, which already has normalized coordinates.
246  */
247  static NormalizedRect fromQRectF(const QRectF &rect);
248 
249  /**
250  * Returns whether this normalized rectangle is a null normalized rect.
251  */
252  bool isNull() const;
253 
254  /**
255  * Returns whether the normalized rectangle contains the normalized point
256  * (@p x, @p y).
257  */
258  bool contains(double x, double y) const;
259 
260  /**
261  * Returns whether the normalized rectangle intersects the @p other normalized
262  * rectangle.
263  */
264  bool intersects(const NormalizedRect &other) const;
265 
266  /**
267  * This is an overloaded member function, provided for convenience. It behaves essentially
268  * like the above function.
269  */
270  bool intersects(const NormalizedRect *other) const;
271 
272  /**
273  * Returns whether the normalized rectangle intersects an other normalized
274  * rectangle, which is defined by @p left, @p top, @p right and @p bottom.
275  */
276  bool intersects(double left, double top, double right, double bottom) const;
277 
278  /**
279  * Returns the rectangle mapped to a reference area of @p xScale x @p yScale.
280  */
281  QRect geometry(int xScale, int yScale) const;
282 
283  /**
284  * Same functionality as geometry, but the output is now rounded before typecasting to int
285  *
286  * @since 0.14 (KDE 4.8)
287  */
288  QRect roundedGeometry(int xScale, int yScale) const;
289 
290  /**
291  * Returns the normalized bounding rectangle of the normalized rectangle
292  * combined with the @p other normalized rectangle.
293  */
294  NormalizedRect operator|(const NormalizedRect &other) const;
295 
296  /**
297  * Sets the normalized rectangle to the normalized bounding rectangle
298  * of itself combined with the @p other normalized rectangle.
299  */
300  NormalizedRect &operator|=(const NormalizedRect &other);
301 
302  /**
303  * Returns the intersection of this normalized rectangle with the specified
304  * @p other. If the rects do not intersect then the result is a null rectangle.
305  *
306  * @since 0.7 (KDE 4.1)
307  */
308  NormalizedRect operator&(const NormalizedRect &other) const;
309 
310  /**
311  * Returns whether the normalized rectangle is equal to the @p other
312  * normalized rectangle.
313  */
314  bool operator==(const NormalizedRect &other) const;
315 
316  /**
317  * Returns the center of the rectangle
318  * @since 0.10 (KDE 4.4)
319  */
320  NormalizedPoint center() const;
321 
322  /**
323  * Transforms the normalized rectangle with the operations defined by @p matrix.
324  */
325  void transform(const QTransform &matrix);
326 
327  /**
328  * Returns true if the point @p pt is located below the bottom of the rectangle
329  * @since 0.14 (KDE 4.8)
330  */
331  bool isBottom(const NormalizedPoint &pt) const
332  {
333  return bottom < pt.y;
334  }
335 
336  /**
337  * Returns true if the point @p pt is located above the top of the rectangle
338  * @since 0.14 (KDE 4.8)
339  */
340  bool isTop(const NormalizedPoint &pt) const
341  {
342  return top > pt.y;
343  }
344 
345  /**
346  * Returns true if the point @p pt is located below the top of the rectangle
347  * @since 0.14 (KDE 4.8)
348  */
349  bool isBottomOrLevel(const NormalizedPoint &pt) const
350  {
351  return top < pt.y;
352  }
353 
354  /**
355  * Returns true if the point @p pt is located above the bottom of the rectangle
356  * @since 0.14 (KDE 4.8)
357  */
358  bool isTopOrLevel(const NormalizedPoint &pt) const
359  {
360  return bottom > pt.y;
361  }
362 
363  /**
364  * Returns true if the point @p pt is located to the right of the left edge of the rectangle
365  * @since 0.14 (KDE 4.8)
366  */
367  bool isLeft(const NormalizedPoint &pt) const
368  {
369  return left < pt.x;
370  }
371 
372  /**
373  * Returns true if the point @p pt is located to the left of the right edge of the rectangle
374  * @since 0.14 (KDE 4.8)
375  */
376  bool isRight(const NormalizedPoint &pt) const
377  {
378  return right > pt.x;
379  }
380 
381  /**
382  * Returns the squared distance of the normalized point (@p x, @p y)
383  * to the closest edge, or 0 if the point is within the rectangle;
384  * using a reference area of size @p xScale x @p yScale
385  * @since 0.17 (KDE 4.11)
386  */
387  double distanceSqr(double x, double y, double xScale, double yScale) const
388  {
389  double distX = 0;
390  if (x < left)
391  distX = left - x;
392  else if (x > right)
393  distX = x - right;
394 
395  double distY = 0;
396  if (top > y)
397  distY = top - y;
398  else if (bottom < y)
399  distY = y - bottom;
400  return pow(distX * xScale, 2) + pow(distY * yScale, 2);
401  }
402 
403  /// @since 1.4
404  double width() const
405  {
406  return right - left;
407  }
408 
409  /// @since 1.4
410  double height() const
411  {
412  return bottom - top;
413  }
414 
415  /**
416  * The normalized left coordinate.
417  */
418  double left;
419 
420  /**
421  * The normalized top coordinate.
422  */
423  double top;
424 
425  /**
426  * The normalized right coordinate.
427  */
428  double right;
429 
430  /**
431  * The normalized bottom coordinate.
432  */
433  double bottom;
434 };
435 // KDE_DUMMY_QHASH_FUNCTION(NormalizedRect)
436 
437 /**
438  * @short An area with normalized coordinates that contains a reference to an object.
439  *
440  * These areas ("rects") contain a pointer to a document object
441  * (such as a hyperlink, an action, or something like that).
442  * The pointer is read and stored as 'void pointer' so cast is
443  * performed by accessors based on the value returned by objectType(). Objects
444  * are reparented to this class.
445  *
446  * Type / Class correspondence tab:
447  * - Action : class Action: description of an action
448  * - Image : class Image : description of an image (n/a)
449  * - Annotation: class Annotation: description of an annotation
450  *
451  * For more information about the normalized coordinate system, see NormalizedPoint.
452  *
453  * @see NormalizedPoint
454  */
455 class OKULARCORE_EXPORT ObjectRect
456 {
457 public:
458  /**
459  * Describes the type of storable object.
460  */
461  enum ObjectType {
462  Action, ///< An action
463  Image, ///< An image
464  OAnnotation, ///< An annotation
465  SourceRef ///< A source reference
466  };
467 
468  /**
469  * Creates a new object rectangle.
470  *
471  * @param left The left coordinate of the rectangle.
472  * @param top The top coordinate of the rectangle.
473  * @param right The right coordinate of the rectangle.
474  * @param bottom The bottom coordinate of the rectangle.
475  * @param ellipse If true the rectangle describes an ellipse.
476  * @param type The type of the storable object @see ObjectType.
477  * @param object The pointer to the storable object.
478  */
479  ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
480 
481  /**
482  * This is an overloaded member function, provided for convenience.
483  */
484  ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object);
485 
486  /**
487  * This is an overloaded member function, provided for convenience.
488  */
489  ObjectRect(const QPolygonF &poly, ObjectType type, void *object);
490 
491  /**
492  * Destroys the object rectangle.
493  */
494  virtual ~ObjectRect();
495 
496  ObjectRect(const ObjectRect &o) = delete;
497  ObjectRect &operator=(const ObjectRect &o) = delete;
498 
499  /**
500  * Returns the object type of the object rectangle.
501  * @see ObjectType
502  */
503  ObjectType objectType() const;
504 
505  /**
506  * Returns the storable object of the object rectangle.
507  */
508  const void *object() const;
509 
510  /**
511  * Returns the region that is covered by the object rectangle.
512  */
513  const QPainterPath &region() const;
514 
515  /**
516  * Returns the bounding rect of the object rectangle for the
517  * scaling factor @p xScale and @p yScale.
518  */
519  virtual QRect boundingRect(double xScale, double yScale) const;
520 
521  /**
522  * Returns whether the object rectangle contains the point with absolute coordinates
523  * (@p x, @p y) at a page size of @p xScale x @p yScale.
524  */
525  virtual bool contains(double x, double y, double xScale, double yScale) const;
526 
527  /**
528  * Transforms the object rectangle with the operations defined by @p matrix.
529  */
530  virtual void transform(const QTransform &matrix);
531 
532  /**
533  * Returns the squared distance between the object
534  * and the point with
535  * normalized coordinates (@p x, @p y)
536  * at a page size of @p xScale x @p yScale.
537  *
538  * @since 0.8.2 (KDE 4.2.2)
539  */
540  // FIXME this should most probably be a virtual method
541  double distanceSqr(double x, double y, double xScale, double yScale) const;
542 
543 protected:
544  ObjectType m_objectType;
545  void *m_object;
546  QPainterPath m_path;
547  QPainterPath m_transformedPath;
548 };
549 
550 /**
551  * This class describes the object rectangle for an annotation.
552  */
553 class OKULARCORE_EXPORT AnnotationObjectRect : public ObjectRect
554 {
555 public:
556  /**
557  * Creates a new annotation object rectangle with the
558  * given @p annotation.
559  */
560  explicit AnnotationObjectRect(Annotation *annotation);
561 
562  /**
563  * Destroys the annotation object rectangle.
564  */
565  ~AnnotationObjectRect() override;
566 
567  /**
568  * Returns the annotation object of the annotation object rectangle.
569  */
570  Annotation *annotation() const;
571 
572  /**
573  * Returns the bounding rect of the annotation object rectangle for the
574  * scaling factor @p xScale and @p yScale.
575  */
576  QRect boundingRect(double xScale, double yScale) const override;
577 
578  /**
579  * Returns whether the annotation object rectangle contains the point @p x, @p y for the
580  * scaling factor @p xScale and @p yScale.
581  */
582  bool contains(double x, double y, double xScale, double yScale) const override;
583 
584  /**
585  * Transforms the annotation object rectangle with the operations defined by @p matrix.
586  */
587  void transform(const QTransform &matrix) override;
588 
589 private:
590  Annotation *m_annotation;
591 };
592 
593 /**
594  * This class describes the object rectangle for a source reference.
595  */
596 class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect
597 {
598  friend class ObjectRect;
599 
600 public:
601  /**
602  * Creates a new source reference object rectangle.
603  *
604  * @param point The point of the source reference.
605  * @param srcRef The storable source reference object.
606  */
607  SourceRefObjectRect(const NormalizedPoint &point, void *srcRef);
608 
609  /**
610  * Returns the bounding rect of the source reference object rectangle for the
611  * scaling factor @p xScale and @p yScale.
612  */
613  QRect boundingRect(double xScale, double yScale) const override;
614 
615  /**
616  * Returns whether the source reference object rectangle contains the point @p x, @p y for the
617  * scaling factor @p xScale and @p yScale.
618  */
619  bool contains(double x, double y, double xScale, double yScale) const override;
620 
621 private:
622  NormalizedPoint m_point;
623 };
624 
625 /**
626  * This class is an object rect that doesn't own the given pointer, i.e. won't delete it on destruction
627  * @since 1.7
628  */
629 class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect
630 {
631 public:
632  NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
633  ~NonOwningObjectRect() override;
634 };
635 
636 /// @cond PRIVATE
637 /** @internal */
638 /** @internal */
639 template<typename T> T *givePtr(T &t)
640 {
641  return &t;
642 }
643 
644 /** @internal */
645 template<typename T> T &deref(T &t)
646 {
647  return t;
648 }
649 /// @endcond
650 
651 /**
652  * @short An area with normalized coordinates, consisting of NormalizedShape objects.
653  *
654  * This is a template class to describe an area which consists of
655  * multiple shapes of the same type, intersecting or non-intersecting.
656  * The coordinates are normalized, and can be mapped to a reference area of defined size.
657  * For more information about the normalized coordinate system, see NormalizedPoint.
658  *
659  * Class NormalizedShape \b must have the following functions/operators defined:
660  * - bool contains( double, double ), whether it contains the given NormalizedPoint
661  * - bool intersects( NormalizedShape )
662  * - bool isNull()
663  * - Shape geometry( int, int ), which maps to the reference area
664  * - operator|=( NormalizedShape ), which unites two NormalizedShape's
665  *
666  * @see RegularAreaRect, NormalizedPoint
667  */
668 template<class NormalizedShape, class Shape> class RegularArea : public QList<NormalizedShape>
669 {
670 public:
671  /**
672  * Returns whether this area contains the normalized point (@p x, @p y).
673  */
674  bool contains(double x, double y) const;
675 
676  /**
677  * Returns whether this area contains a NormalizedShape object that equals @p shape.
678  *
679  * @note
680  * The original NormalizedShape objects can be lost if simplify() was called.
681  */
682  bool contains(const NormalizedShape &shape) const;
683 
684  /**
685  * Returns whether this area intersects with the given @p area.
686  */
687  bool intersects(const RegularArea<NormalizedShape, Shape> *area) const;
688 
689  /**
690  * Returns whether the regular area intersects with the given @p shape.
691  */
692  bool intersects(const NormalizedShape &shape) const;
693 
694  /**
695  * Appends the given @p area to this area.
696  */
697  void appendArea(const RegularArea<NormalizedShape, Shape> *area);
698 
699  /**
700  * Appends the given @p shape to this area.
701  */
702  void appendShape(const NormalizedShape &shape, MergeSide side = MergeAll);
703 
704  /**
705  * Simplifies this regular area by merging its intersecting subareas.
706  * This might change the effective geometry of this area.
707  */
708  void simplify();
709 
710  /**
711  * Returns whether the regular area is a null area.
712  */
713  bool isNull() const;
714 
715  /**
716  * Returns the subareas of this regular area
717  * mapped to a reference area of size @p xScale x @p yScale,
718  * then translated by @p dx and @p dy.
719  */
720  QList<Shape> geometry(int xScale, int yScale, int dx = 0, int dy = 0) const;
721 
722  /**
723  * Transforms the regular area with the operations defined by @p matrix.
724  */
725  void transform(const QTransform &matrix);
726 };
727 
728 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::simplify()
729 {
730 #ifdef DEBUG_REGULARAREA
731  int prev_end = this->count();
732 #endif
733  int end = this->count() - 1, x = 0;
734  for (int i = 0; i < end; ++i) {
735  if (givePtr((*this)[x])->intersects(deref((*this)[i + 1]))) {
736  deref((*this)[x]) |= deref((*this)[i + 1]);
737  this->removeAt(i + 1);
738  --end;
739  --i;
740  } else {
741  x = i + 1;
742  }
743  }
744 #ifdef DEBUG_REGULARAREA
745  qCDebug(OkularCoreDebug) << "from" << prev_end << "to" << this->count();
746 #endif
747 }
748 
749 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::isNull() const
750 {
751  if (this->isEmpty())
752  return true;
753 
754  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
755  for (; it != itEnd; ++it)
756  if (!givePtr(*it)->isNull())
757  return false;
758 
759  return true;
760 }
761 
762 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const NormalizedShape &shape) const
763 {
764  if (this->isEmpty())
765  return false;
766 
767  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
768  for (; it != itEnd; ++it)
769  if (!givePtr(*it)->isNull() && givePtr(*it)->intersects(shape))
770  return true;
771 
772  return false;
773 }
774 
775 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const RegularArea<NormalizedShape, Shape> *area) const
776 {
777  if (this->isEmpty())
778  return false;
779 
780  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
781  for (; it != itEnd; ++it) {
782  typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
783  for (; areaIt != areaItEnd; ++areaIt) {
784  if (!(*it).isNull() && (*it).intersects(*areaIt))
785  return true;
786  }
787  }
788 
789  return false;
790 }
791 
792 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendArea(const RegularArea<NormalizedShape, Shape> *area)
793 {
794  typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
795  for (; areaIt != areaItEnd; ++areaIt)
796  this->append(*areaIt);
797 }
798 
799 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendShape(const NormalizedShape &shape, MergeSide side)
800 {
801  int size = this->count();
802  // if the list is empty, adds the shape normally
803  if (size == 0) {
804  this->append(shape);
805  } else {
806  bool intersection = false;
807  NormalizedShape &last = (*this)[size - 1];
808 #define O_LAST givePtr(last)
809 #define O_LAST_R O_LAST->right
810 #define O_LAST_L O_LAST->left
811 #define O_LAST_T O_LAST->top
812 #define O_LAST_B O_LAST->bottom
813 #define O_NEW givePtr(shape)
814 #define O_NEW_R O_NEW->right
815 #define O_NEW_L O_NEW->left
816 #define O_NEW_T O_NEW->top
817 #define O_NEW_B O_NEW->bottom
818  switch (side) {
819  case MergeRight:
820  intersection = (O_LAST_R >= O_NEW_L) && (O_LAST_L <= O_NEW_R) && ((O_LAST_T <= O_NEW_T && O_LAST_B >= O_NEW_B) || (O_LAST_T >= O_NEW_T && O_LAST_B <= O_NEW_B));
821  break;
822  case MergeBottom:
823  intersection = (O_LAST_B >= O_NEW_T) && (O_LAST_T <= O_NEW_B) && ((O_LAST_R <= O_NEW_R && O_LAST_L >= O_NEW_L) || (O_LAST_R >= O_NEW_R && O_LAST_L <= O_NEW_L));
824  break;
825  case MergeLeft:
826  intersection = (O_LAST_L <= O_NEW_R) && (O_LAST_R >= O_NEW_L) && ((O_LAST_T <= O_NEW_T && O_LAST_B >= O_NEW_B) || (O_LAST_T >= O_NEW_T && O_LAST_B <= O_NEW_B));
827  break;
828  case MergeTop:
829  intersection = (O_LAST_T <= O_NEW_B) && (O_LAST_B >= O_NEW_T) && ((O_LAST_R <= O_NEW_R && O_LAST_L >= O_NEW_L) || (O_LAST_R >= O_NEW_R && O_LAST_L <= O_NEW_L));
830  break;
831  case MergeAll:
832  intersection = O_LAST->intersects(shape);
833  break;
834  }
835 #undef O_LAST
836 #undef O_LAST_R
837 #undef O_LAST_L
838 #undef O_LAST_T
839 #undef O_LAST_B
840 #undef O_NEW
841 #undef O_NEW_R
842 #undef O_NEW_L
843 #undef O_NEW_T
844 #undef O_NEW_B
845  // if the new shape intersects with the last shape in the list, then
846  // merge it with that and delete the shape
847  if (intersection) {
848  deref((*this)[size - 1]) |= deref(shape);
849  } else
850  this->append(shape);
851  }
852 }
853 
854 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(double x, double y) const
855 {
856  if (this->isEmpty())
857  return false;
858 
859  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
860  for (; it != itEnd; ++it)
861  if ((*it).contains(x, y))
862  return true;
863 
864  return false;
865 }
866 
867 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(const NormalizedShape &shape) const
868 {
869  if (this->isEmpty())
870  return false;
871 
872  return QList<NormalizedShape>::contains(shape);
873 }
874 
875 template<class NormalizedShape, class Shape> QList<Shape> RegularArea<NormalizedShape, Shape>::geometry(int xScale, int yScale, int dx, int dy) const
876 {
877  if (this->isEmpty())
878  return QList<Shape>();
879 
880  QList<Shape> ret;
881  Shape t;
882  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
883  for (; it != itEnd; ++it) {
884  t = givePtr(*it)->geometry(xScale, yScale);
885  t.translate(dx, dy);
886  ret.append(t);
887  }
888 
889  return ret;
890 }
891 
892 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::transform(const QTransform &matrix)
893 {
894  if (this->isEmpty())
895  return;
896 
897  for (int i = 0; i < this->count(); ++i)
898  givePtr((*this)[i])->transform(matrix);
899 }
900 
901 /**
902  * This is a list of NormalizedRect, to describe an area consisting of
903  * multiple rectangles using normalized coordinates.
904  *
905  * This area can be mapped to a reference area, resulting in a list of QRects.
906  * For more information about the normalized coordinate system, see NormalizedPoint.
907  *
908  * Okular uses this area e. g. to describe a text highlight area,
909  * which consists of multiple, intersecting or non-intersecting rectangles.
910  *
911  * @see NormalizedRect, NormalizedPoint
912  */
913 class OKULARCORE_EXPORT RegularAreaRect : public RegularArea<NormalizedRect, QRect>
914 {
915 public:
916  RegularAreaRect();
917  RegularAreaRect(const RegularAreaRect &rar);
918  ~RegularAreaRect();
919 
920  RegularAreaRect &operator=(const RegularAreaRect &rar);
921 
922 private:
923  class Private;
924  Private *const d;
925 };
926 
927 /**
928  * This class stores the geometry of a highlighting area in normalized coordinates,
929  * together with highlighting specific information.
930  */
932 {
933 public:
934  /**
935  * Creates a new highlight area rect with the coordinates of
936  * the given @p area.
937  */
938  explicit HighlightAreaRect(const RegularAreaRect *area = nullptr);
939 
940  /**
941  * The search ID of the highlight owner.
942  */
943  int s_id;
944 
945  /**
946  * The color of the highlight.
947  */
949 };
950 
951 uint qHash(const Okular::NormalizedRect &r, uint seed = 0);
952 }
953 
954 #ifndef QT_NO_DEBUG_STREAM
955 /**
956  * Debug operator for normalized @p point.
957  */
958 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedPoint &point);
959 
960 /**
961  * Debug operator for normalized @p rect.
962  */
963 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedRect &rect);
964 #endif
965 
966 #endif
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:119
Merge only if the bottom side of the first area intersect.
Definition: global.h:68
Merge only if the left side of the first area intersect.
Definition: global.h:69
void appendArea(const RegularArea< NormalizedShape, Shape > *area)
Appends the given area to this area.
Definition: area.h:792
QList< Shape > geometry(int xScale, int yScale, int dx=0, int dy=0) const
Returns the subareas of this regular area mapped to a reference area of size xScale x yScale...
Definition: area.h:875
bool isRight(const NormalizedPoint &pt) const
Returns true if the point pt is located to the left of the right edge of the rectangle.
Definition: area.h:376
MergeSide
The side(s) to be considered when merging areas.
Definition: global.h:66
This class describes the object rectangle for a source reference.
Definition: area.h:596
bool contains(double x, double y) const
Returns whether this area contains the normalized point (x, y).
Definition: area.h:854
Merge only if the top side of the first area intersect.
Definition: global.h:70
double left
The normalized left coordinate.
Definition: area.h:418
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition: area.h:192
void appendShape(const NormalizedShape &shape, MergeSide side=MergeAll)
Appends the given shape to this area.
Definition: area.h:799
This is a list of NormalizedRect, to describe an area consisting of multiple rectangles using normali...
Definition: area.h:913
Merge only if the right side of the first area intersect.
Definition: global.h:67
double y
The normalized y coordinate.
Definition: area.h:175
double width() const
Definition: area.h:404
bool intersects(const RegularArea< NormalizedShape, Shape > *area) const
Returns whether this area intersects with the given area.
Definition: area.h:775
global.h
Definition: action.h:19
This class describes the object rectangle for an annotation.
Definition: area.h:553
double right
The normalized right coordinate.
Definition: area.h:428
bool isNull() const
Returns whether the regular area is a null area.
Definition: area.h:749
void append(const T &value)
QColor color
The color of the highlight.
Definition: area.h:948
double height() const
Definition: area.h:410
An area with normalized coordinates that contains a reference to an object.
Definition: area.h:455
int s_id
The search ID of the highlight owner.
Definition: area.h:943
bool isTopOrLevel(const NormalizedPoint &pt) const
Returns true if the point pt is located above the bottom of the rectangle.
Definition: area.h:358
double distanceSqr(double x, double y, double xScale, double yScale) const
Returns the squared distance of the normalized point (x, y) to the closest edge, or 0 if the point is...
Definition: area.h:387
An area with normalized coordinates, consisting of NormalizedShape objects.
Definition: area.h:668
This class is an object rect that doesn&#39;t own the given pointer, i.e.
Definition: area.h:629
bool isBottom(const NormalizedPoint &pt) const
Returns true if the point pt is located below the bottom of the rectangle.
Definition: area.h:331
Merge if the areas intersects, no matter which side(s).
Definition: global.h:71
QList::iterator end()
KCALENDARCORE_EXPORT uint qHash(const KCalendarCore::Period &key)
void transform(const QTransform &matrix)
Transforms the regular area with the operations defined by matrix.
Definition: area.h:892
bool contains(const T &value) const const
bool isBottomOrLevel(const NormalizedPoint &pt) const
Returns true if the point pt is located below the top of the rectangle.
Definition: area.h:349
double top
The normalized top coordinate.
Definition: area.h:423
ObjectType
Describes the type of storable object.
Definition: area.h:461
QDataStream & operator<<(QDataStream &out, const KDateTime::Spec &spec)
double x
The normalized x coordinate.
Definition: area.h:170
bool isTop(const NormalizedPoint &pt) const
Returns true if the point pt is located above the top of the rectangle.
Definition: area.h:340
Annotation struct holds properties shared by all annotations.
Definition: annotations.h:88
void simplify()
Simplifies this regular area by merging its intersecting subareas.
Definition: area.h:728
double bottom
The normalized bottom coordinate.
Definition: area.h:433
bool isLeft(const NormalizedPoint &pt) const
Returns true if the point pt is located to the right of the left edge of the rectangle.
Definition: area.h:367
This class stores the geometry of a highlighting area in normalized coordinates, together with highli...
Definition: area.h:931
QList::iterator begin()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Mar 7 2021 22:35:31 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.