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  * Returns the normalized bounding rectangle of the normalized rectangle
287  * combined with the @p other normalized rectangle.
288  */
289  NormalizedRect operator|(const NormalizedRect &other) const;
290 
291  /**
292  * Sets the normalized rectangle to the normalized bounding rectangle
293  * of itself combined with the @p other normalized rectangle.
294  */
295  NormalizedRect &operator|=(const NormalizedRect &other);
296 
297  /**
298  * Returns the intersection of this normalized rectangle with the specified
299  * @p other. If the rects do not intersect then the result is a null rectangle.
300  *
301  * @since 0.7 (KDE 4.1)
302  */
303  NormalizedRect operator&(const NormalizedRect &other) const;
304 
305  /**
306  * Returns whether the normalized rectangle is equal to the @p other
307  * normalized rectangle.
308  */
309  bool operator==(const NormalizedRect &other) const;
310 
311  /**
312  * Returns the center of the rectangle
313  * @since 0.10 (KDE 4.4)
314  */
315  NormalizedPoint center() const;
316 
317  /**
318  * Transforms the normalized rectangle with the operations defined by @p matrix.
319  */
320  void transform(const QTransform &matrix);
321 
322  /**
323  * Returns true if the point @p pt is located below the bottom of the rectangle
324  * @since 0.14 (KDE 4.8)
325  */
326  bool isBottom(const NormalizedPoint &pt) const
327  {
328  return bottom < pt.y;
329  }
330 
331  /**
332  * Returns true if the point @p pt is located above the top of the rectangle
333  * @since 0.14 (KDE 4.8)
334  */
335  bool isTop(const NormalizedPoint &pt) const
336  {
337  return top > pt.y;
338  }
339 
340  /**
341  * Returns true if the point @p pt is located below the top of the rectangle
342  * @since 0.14 (KDE 4.8)
343  */
344  bool isBottomOrLevel(const NormalizedPoint &pt) const
345  {
346  return top < pt.y;
347  }
348 
349  /**
350  * Returns true if the point @p pt is located above the bottom of the rectangle
351  * @since 0.14 (KDE 4.8)
352  */
353  bool isTopOrLevel(const NormalizedPoint &pt) const
354  {
355  return bottom > pt.y;
356  }
357 
358  /**
359  * Returns true if the point @p pt is located to the right of the left edge of the rectangle
360  * @since 0.14 (KDE 4.8)
361  */
362  bool isLeft(const NormalizedPoint &pt) const
363  {
364  return left < pt.x;
365  }
366 
367  /**
368  * Returns true if the point @p pt is located to the left of the right edge of the rectangle
369  * @since 0.14 (KDE 4.8)
370  */
371  bool isRight(const NormalizedPoint &pt) const
372  {
373  return right > pt.x;
374  }
375 
376  /**
377  * Returns the squared distance of the normalized point (@p x, @p y)
378  * to the closest edge, or 0 if the point is within the rectangle;
379  * using a reference area of size @p xScale x @p yScale
380  * @since 0.17 (KDE 4.11)
381  */
382  double distanceSqr(double x, double y, double xScale, double yScale) const
383  {
384  double distX = 0;
385  if (x < left) {
386  distX = left - x;
387  } else if (x > right) {
388  distX = x - right;
389  }
390 
391  double distY = 0;
392  if (top > y) {
393  distY = top - y;
394  } else if (bottom < y) {
395  distY = y - bottom;
396  }
397  return pow(distX * xScale, 2) + pow(distY * yScale, 2);
398  }
399 
400  /// @since 1.4
401  double width() const
402  {
403  return right - left;
404  }
405 
406  /// @since 1.4
407  double height() const
408  {
409  return bottom - top;
410  }
411 
412  /**
413  * The normalized left coordinate.
414  */
415  double left;
416 
417  /**
418  * The normalized top coordinate.
419  */
420  double top;
421 
422  /**
423  * The normalized right coordinate.
424  */
425  double right;
426 
427  /**
428  * The normalized bottom coordinate.
429  */
430  double bottom;
431 };
432 // KDE_DUMMY_QHASH_FUNCTION(NormalizedRect)
433 
434 /**
435  * @short An area with normalized coordinates that contains a reference to an object.
436  *
437  * These areas ("rects") contain a pointer to a document object
438  * (such as a hyperlink, an action, or something like that).
439  * The pointer is read and stored as 'void pointer' so cast is
440  * performed by accessors based on the value returned by objectType(). Objects
441  * are reparented to this class.
442  *
443  * Type / Class correspondence tab:
444  * - Action : class Action: description of an action
445  * - Image : class Image : description of an image (n/a)
446  * - Annotation: class Annotation: description of an annotation
447  *
448  * For more information about the normalized coordinate system, see NormalizedPoint.
449  *
450  * @see NormalizedPoint
451  */
452 class OKULARCORE_EXPORT ObjectRect
453 {
454 public:
455  /**
456  * Describes the type of storable object.
457  */
458  enum ObjectType {
459  Action, ///< An action
460  Image, ///< An image
461  OAnnotation, ///< An annotation
462  SourceRef ///< A source reference
463  };
464 
465  /**
466  * Creates a new object rectangle.
467  *
468  * @param left The left coordinate of the rectangle.
469  * @param top The top coordinate of the rectangle.
470  * @param right The right coordinate of the rectangle.
471  * @param bottom The bottom coordinate of the rectangle.
472  * @param ellipse If true the rectangle describes an ellipse.
473  * @param type The type of the storable object @see ObjectType.
474  * @param object The pointer to the storable object.
475  */
476  ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
477 
478  /**
479  * This is an overloaded member function, provided for convenience.
480  */
481  ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object);
482 
483  /**
484  * This is an overloaded member function, provided for convenience.
485  */
486  ObjectRect(const QPolygonF &poly, ObjectType type, void *object);
487 
488  /**
489  * Destroys the object rectangle.
490  */
491  virtual ~ObjectRect();
492 
493  ObjectRect(const ObjectRect &o) = delete;
494  ObjectRect &operator=(const ObjectRect &o) = delete;
495 
496  /**
497  * Returns the object type of the object rectangle.
498  * @see ObjectType
499  */
500  ObjectType objectType() const;
501 
502  /**
503  * Returns the storable object of the object rectangle.
504  */
505  const void *object() const;
506 
507  /**
508  * Returns the region that is covered by the object rectangle.
509  */
510  const QPainterPath &region() const;
511 
512  /**
513  * Returns the bounding rect of the object rectangle for the
514  * scaling factor @p xScale and @p yScale.
515  */
516  virtual QRect boundingRect(double xScale, double yScale) const;
517 
518  /**
519  * Returns whether the object rectangle contains the point with absolute coordinates
520  * (@p x, @p y) at a page size of @p xScale x @p yScale.
521  */
522  virtual bool contains(double x, double y, double xScale, double yScale) const;
523 
524  /**
525  * Transforms the object rectangle with the operations defined by @p matrix.
526  */
527  virtual void transform(const QTransform &matrix);
528 
529  /**
530  * Returns the squared distance between the object
531  * and the point with
532  * normalized coordinates (@p x, @p y)
533  * at a page size of @p xScale x @p yScale.
534  *
535  * @since 0.8.2 (KDE 4.2.2)
536  */
537  // FIXME this should most probably be a virtual method
538  double distanceSqr(double x, double y, double xScale, double yScale) const;
539 
540 protected:
541  ObjectType m_objectType;
542  void *m_object;
543  QPainterPath m_path;
544  QPainterPath m_transformedPath;
545 };
546 
547 /**
548  * This class describes the object rectangle for an annotation.
549  */
550 class OKULARCORE_EXPORT AnnotationObjectRect : public ObjectRect
551 {
552 public:
553  /**
554  * Creates a new annotation object rectangle with the
555  * given @p annotation.
556  */
557  explicit AnnotationObjectRect(Annotation *annotation);
558 
559  /**
560  * Destroys the annotation object rectangle.
561  */
562  ~AnnotationObjectRect() override;
563 
564  /**
565  * Returns the annotation object of the annotation object rectangle.
566  */
567  Annotation *annotation() const;
568 
569  /**
570  * Returns the bounding rect of the annotation object rectangle for the
571  * scaling factor @p xScale and @p yScale.
572  */
573  QRect boundingRect(double xScale, double yScale) const override;
574 
575  /**
576  * Returns whether the annotation object rectangle contains the point @p x, @p y for the
577  * scaling factor @p xScale and @p yScale.
578  */
579  bool contains(double x, double y, double xScale, double yScale) const override;
580 
581  /**
582  * Transforms the annotation object rectangle with the operations defined by @p matrix.
583  */
584  void transform(const QTransform &matrix) override;
585 
586 private:
587  Annotation *m_annotation;
588 };
589 
590 /**
591  * This class describes the object rectangle for a source reference.
592  */
593 class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect
594 {
595  friend class ObjectRect;
596 
597 public:
598  /**
599  * Creates a new source reference object rectangle.
600  *
601  * @param point The point of the source reference.
602  * @param srcRef The storable source reference object.
603  */
604  SourceRefObjectRect(const NormalizedPoint &point, void *srcRef);
605 
606  /**
607  * Returns the bounding rect of the source reference object rectangle for the
608  * scaling factor @p xScale and @p yScale.
609  */
610  QRect boundingRect(double xScale, double yScale) const override;
611 
612  /**
613  * Returns whether the source reference object rectangle contains the point @p x, @p y for the
614  * scaling factor @p xScale and @p yScale.
615  */
616  bool contains(double x, double y, double xScale, double yScale) const override;
617 
618 private:
619  NormalizedPoint m_point;
620 };
621 
622 /**
623  * This class is an object rect that doesn't own the given pointer, i.e. won't delete it on destruction
624  * @since 1.7
625  */
626 class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect
627 {
628 public:
629  NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
630  ~NonOwningObjectRect() override;
631 };
632 
633 /// @cond PRIVATE
634 /** @internal */
635 /** @internal */
636 template<typename T> T *givePtr(T &t)
637 {
638  return &t;
639 }
640 
641 /** @internal */
642 template<typename T> T &deref(T &t)
643 {
644  return t;
645 }
646 /// @endcond
647 
648 /**
649  * @short An area with normalized coordinates, consisting of NormalizedShape objects.
650  *
651  * This is a template class to describe an area which consists of
652  * multiple shapes of the same type, intersecting or non-intersecting.
653  * The coordinates are normalized, and can be mapped to a reference area of defined size.
654  * For more information about the normalized coordinate system, see NormalizedPoint.
655  *
656  * Class NormalizedShape \b must have the following functions/operators defined:
657  * - bool contains( double, double ), whether it contains the given NormalizedPoint
658  * - bool intersects( NormalizedShape )
659  * - bool isNull()
660  * - Shape geometry( int, int ), which maps to the reference area
661  * - operator|=( NormalizedShape ), which unites two NormalizedShape's
662  *
663  * @see RegularAreaRect, NormalizedPoint
664  */
665 template<class NormalizedShape, class Shape> class RegularArea : public QList<NormalizedShape>
666 {
667 public:
668  /**
669  * Returns whether this area contains the normalized point (@p x, @p y).
670  */
671  bool contains(double x, double y) const;
672 
673  /**
674  * Returns whether this area contains a NormalizedShape object that equals @p shape.
675  *
676  * @note
677  * The original NormalizedShape objects can be lost if simplify() was called.
678  */
679  bool contains(const NormalizedShape &shape) const;
680 
681  /**
682  * Returns whether this area intersects with the given @p area.
683  */
684  bool intersects(const RegularArea<NormalizedShape, Shape> *area) const;
685 
686  /**
687  * Returns whether the regular area intersects with the given @p shape.
688  */
689  bool intersects(const NormalizedShape &shape) const;
690 
691  /**
692  * Appends the given @p area to this area.
693  */
695 
696  /**
697  * Appends the given @p shape to this area.
698  */
699  void appendShape(const NormalizedShape &shape, MergeSide side = MergeAll);
700 
701  /**
702  * Simplifies this regular area by merging its intersecting subareas.
703  * This might change the effective geometry of this area.
704  */
705  void simplify();
706 
707  /**
708  * Returns whether the regular area is a null area.
709  */
710  bool isNull() const;
711 
712  /**
713  * Returns the subareas of this regular area
714  * mapped to a reference area of size @p xScale x @p yScale,
715  * then translated by @p dx and @p dy.
716  */
717  QList<Shape> geometry(int xScale, int yScale, int dx = 0, int dy = 0) const;
718 
719  /**
720  * Transforms the regular area with the operations defined by @p matrix.
721  */
722  void transform(const QTransform &matrix);
723 };
724 
725 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::simplify()
726 {
727 #ifdef DEBUG_REGULARAREA
728  int prev_end = this->count();
729 #endif
730  int end = this->count() - 1, x = 0;
731  for (int i = 0; i < end; ++i) {
732  if (givePtr((*this)[x])->intersects(deref((*this)[i + 1]))) {
733  deref((*this)[x]) |= deref((*this)[i + 1]);
734  this->removeAt(i + 1);
735  --end;
736  --i;
737  } else {
738  x = i + 1;
739  }
740  }
741 #ifdef DEBUG_REGULARAREA
742  qCDebug(OkularCoreDebug) << "from" << prev_end << "to" << this->count();
743 #endif
744 }
745 
746 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::isNull() const
747 {
748  if (this->isEmpty()) {
749  return true;
750  }
751 
752  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
753  for (; it != itEnd; ++it) {
754  if (!givePtr(*it)->isNull()) {
755  return false;
756  }
757  }
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 
768  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
769  for (; it != itEnd; ++it) {
770  if (!givePtr(*it)->isNull() && givePtr(*it)->intersects(shape)) {
771  return true;
772  }
773  }
774 
775  return false;
776 }
777 
778 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const RegularArea<NormalizedShape, Shape> *area) const
779 {
780  if (this->isEmpty()) {
781  return false;
782  }
783 
784  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
785  for (; it != itEnd; ++it) {
786  typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
787  for (; areaIt != areaItEnd; ++areaIt) {
788  if (!(*it).isNull() && (*it).intersects(*areaIt)) {
789  return true;
790  }
791  }
792  }
793 
794  return false;
795 }
796 
797 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendArea(const RegularArea<NormalizedShape, Shape> *area)
798 {
799  typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
800  for (; areaIt != areaItEnd; ++areaIt) {
801  this->append(*areaIt);
802  }
803 }
804 
805 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendShape(const NormalizedShape &shape, MergeSide side)
806 {
807  int size = this->count();
808  // if the list is empty, adds the shape normally
809  if (size == 0) {
810  this->append(shape);
811  } else {
812  bool intersection = false;
813  NormalizedShape &last = (*this)[size - 1];
814 #define O_LAST givePtr(last)
815 #define O_LAST_R O_LAST->right
816 #define O_LAST_L O_LAST->left
817 #define O_LAST_T O_LAST->top
818 #define O_LAST_B O_LAST->bottom
819 #define O_NEW givePtr(shape)
820 #define O_NEW_R O_NEW->right
821 #define O_NEW_L O_NEW->left
822 #define O_NEW_T O_NEW->top
823 #define O_NEW_B O_NEW->bottom
824  switch (side) {
825  case MergeRight:
826  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));
827  break;
828  case MergeBottom:
829  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));
830  break;
831  case MergeLeft:
832  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));
833  break;
834  case MergeTop:
835  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));
836  break;
837  case MergeAll:
838  intersection = O_LAST->intersects(shape);
839  break;
840  }
841 #undef O_LAST
842 #undef O_LAST_R
843 #undef O_LAST_L
844 #undef O_LAST_T
845 #undef O_LAST_B
846 #undef O_NEW
847 #undef O_NEW_R
848 #undef O_NEW_L
849 #undef O_NEW_T
850 #undef O_NEW_B
851  // if the new shape intersects with the last shape in the list, then
852  // merge it with that and delete the shape
853  if (intersection) {
854  deref((*this)[size - 1]) |= deref(shape);
855  } else {
856  this->append(shape);
857  }
858  }
859 }
860 
861 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(double x, double y) const
862 {
863  if (this->isEmpty()) {
864  return false;
865  }
866 
867  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
868  for (; it != itEnd; ++it) {
869  if ((*it).contains(x, y)) {
870  return true;
871  }
872  }
873 
874  return false;
875 }
876 
877 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(const NormalizedShape &shape) const
878 {
879  if (this->isEmpty()) {
880  return false;
881  }
882 
883  return QList<NormalizedShape>::contains(shape);
884 }
885 
886 template<class NormalizedShape, class Shape> QList<Shape> RegularArea<NormalizedShape, Shape>::geometry(int xScale, int yScale, int dx, int dy) const
887 {
888  if (this->isEmpty()) {
889  return QList<Shape>();
890  }
891 
892  QList<Shape> ret;
893  Shape t;
894  typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
895  for (; it != itEnd; ++it) {
896  t = givePtr(*it)->geometry(xScale, yScale);
897  t.translate(dx, dy);
898  ret.append(t);
899  }
900 
901  return ret;
902 }
903 
904 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::transform(const QTransform &matrix)
905 {
906  if (this->isEmpty()) {
907  return;
908  }
909 
910  for (int i = 0; i < this->count(); ++i) {
911  givePtr((*this)[i])->transform(matrix);
912  }
913 }
914 
915 /**
916  * This is a list of NormalizedRect, to describe an area consisting of
917  * multiple rectangles using normalized coordinates.
918  *
919  * This area can be mapped to a reference area, resulting in a list of QRects.
920  * For more information about the normalized coordinate system, see NormalizedPoint.
921  *
922  * Okular uses this area e. g. to describe a text highlight area,
923  * which consists of multiple, intersecting or non-intersecting rectangles.
924  *
925  * @see NormalizedRect, NormalizedPoint
926  */
927 class OKULARCORE_EXPORT RegularAreaRect : public RegularArea<NormalizedRect, QRect>
928 {
929 public:
930  RegularAreaRect();
931  RegularAreaRect(const RegularAreaRect &rar);
932  ~RegularAreaRect();
933 
934  RegularAreaRect &operator=(const RegularAreaRect &rar);
935 
936 private:
937  class Private;
938  Private *const d;
939 };
940 
941 /**
942  * This class stores the geometry of a highlighting area in normalized coordinates,
943  * together with highlighting specific information.
944  */
946 {
947 public:
948  /**
949  * Creates a new highlight area rect with the coordinates of
950  * the given @p area.
951  */
952  explicit HighlightAreaRect(const RegularAreaRect *area = nullptr);
953 
954  /**
955  * The search ID of the highlight owner.
956  */
957  int s_id;
958 
959  /**
960  * The color of the highlight.
961  */
963 };
964 
965 uint qHash(const Okular::NormalizedRect &r, uint seed = 0);
966 }
967 
968 #ifndef QT_NO_DEBUG_STREAM
969 /**
970  * Debug operator for normalized @p point.
971  */
972 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedPoint &point);
973 
974 /**
975  * Debug operator for normalized @p rect.
976  */
977 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedRect &rect);
978 #endif
979 
980 #endif
void append(const T &value)
This class describes the object rectangle for a source reference.
Definition: area.h:593
bool contains(double x, double y) const
Returns whether this area contains the normalized point (x, y).
Definition: area.h:861
double width() const
Definition: area.h:401
An area with normalized coordinates, consisting of NormalizedShape objects.
Definition: area.h:665
double y
The normalized y coordinate.
Definition: area.h:171
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
@ Image
An image.
Definition: area.h:460
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:292
void appendArea(const RegularArea< NormalizedShape, Shape > *area)
Appends the given area to this area.
Definition: area.h:797
Q_SCRIPTABLE Q_NOREPLY void start()
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:116
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:371
This class describes the object rectangle for an annotation.
Definition: area.h:550
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:326
bool intersects(const RegularArea< NormalizedShape, Shape > *area) const
Returns whether this area intersects with the given area.
Definition: area.h:778
QColor color
The color of the highlight.
Definition: area.h:962
@ 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:927
@ Action
An action.
Definition: area.h:459
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:945
ObjectType
int s_id
The search ID of the highlight owner.
Definition: area.h:957
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:344
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:353
This class is an object rect that doesn't own the given pointer, i.e.
Definition: area.h:626
@ 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:415
@ OAnnotation
An annotation.
Definition: area.h:461
@ 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:382
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:904
double right
The normalized right coordinate.
Definition: area.h:425
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:886
ObjectType
Describes the type of storable object.
Definition: area.h:458
bool isTop(const NormalizedPoint &pt) const
Returns true if the point pt is located above the top of the rectangle.
Definition: area.h:335
QList::iterator begin()
bool isNull() const
Returns whether the regular area is a null area.
Definition: area.h:746
void simplify()
Simplifies this regular area by merging its intersecting subareas.
Definition: area.h:725
void appendShape(const NormalizedShape &shape, MergeSide side=MergeAll)
Appends the given shape to this area.
Definition: area.h:805
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:452
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:362
double height() const
Definition: area.h:407
double top
The normalized top coordinate.
Definition: area.h:420
double bottom
The normalized bottom coordinate.
Definition: area.h:430
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue Sep 27 2022 03:58:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.