Okular

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

KDE's Doxygen guidelines are available online.