Okular

area.h
1/*
2 SPDX-FileCopyrightText: 2004-05 Enrico Ros <eros.kde@email.it>
3 SPDX-FileCopyrightText: 2005 Piotr Szymanski <niedakh@gmail.com>
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
21class QPolygonF;
22class QRect;
23
24namespace Okular
25{
26class Annotation;
27class Action;
28class 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 */
116class OKULARCORE_EXPORT NormalizedPoint
117{
118public:
119 /**
120 * Creates a normalized point at (0, 0).
121 */
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 */
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.
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 */
188class OKULARCORE_EXPORT NormalizedRect
189{
190public:
191 /**
192 * Creates a null normalized rectangle.
193 * @see isNull()
194 */
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 */
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 {
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 {
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 *
454 *
455 * @see NormalizedPoint
456 */
457class OKULARCORE_EXPORT ObjectRect
458{
459public:
460 /**
461 * Describes the type of storable object.
462 */
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
545protected:
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 */
555class OKULARCORE_EXPORT AnnotationObjectRect : public ObjectRect
556{
557public:
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
591private:
592 Annotation *m_annotation;
593};
594
595/**
596 * This class describes the object rectangle for a source reference.
597 */
598class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect
599{
600 friend class ObjectRect;
601
602public:
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
623private:
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 */
631class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect
632{
633public:
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 */
641template<typename T> T *givePtr(T &t)
642{
643 return &t;
644}
645
646/** @internal */
647template<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.
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 */
670template<class NormalizedShape, class Shape> class RegularArea : public QList<NormalizedShape>
671{
672public:
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 */
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
730template<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
751template<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
767template<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
783template<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
802template<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
810template<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
866template<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
882template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(const NormalizedShape &shape) const
883{
884 if (this->isEmpty()) {
885 return false;
886 }
887
889}
890
891template<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
909template<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.
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 */
932class OKULARCORE_EXPORT RegularAreaRect : public RegularArea<NormalizedRect, QRect>
933{
934public:
938
939 RegularAreaRect &operator=(const RegularAreaRect &rar);
940
941private:
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{
952public:
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
970size_t qHash(const Okular::NormalizedRect &r, size_t seed = 0);
971}
972
973#ifndef QT_NO_DEBUG_STREAM
974/**
975 * Debug operator for normalized @p point.
976 */
977OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedPoint &point);
978
979/**
980 * Debug operator for normalized @p rect.
981 */
982OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedRect &rect);
983#endif
984
985#endif
This class describes the object rectangle for an annotation.
Definition area.h:556
Annotation struct holds properties shared by all annotations.
Definition annotations.h:99
This class stores the geometry of a highlighting area in normalized coordinates, together with highli...
Definition area.h:951
int s_id
The search ID of the highlight owner.
Definition area.h:962
HighlightAreaRect(const RegularAreaRect *area=nullptr)
Creates a new highlight area rect with the coordinates of the given area.
Definition area.cpp:299
QColor color
The color of the highlight.
Definition area.h:967
This class is an object rect that doesn't own the given pointer, i.e.
Definition area.h:632
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition area.h:117
NormalizedPoint & operator=(const NormalizedPoint &)
double x
The normalized x coordinate.
Definition area.h:166
double y
The normalized y coordinate.
Definition area.h:171
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition area.h:189
double bottom
The normalized bottom coordinate.
Definition area.h:435
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 right
The normalized right coordinate.
Definition area.h:430
NormalizedRect(const NormalizedRect &)
double height() const
Definition area.h:412
NormalizedRect & operator=(const NormalizedRect &other)
double left
The normalized left coordinate.
Definition area.h:420
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
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
bool isTop(const NormalizedPoint &pt) const
Returns true if the point pt is located above the top of the rectangle.
Definition area.h:340
bool isTopOrLevel(const NormalizedPoint &pt) const
Returns true if the point pt is located above the bottom of the rectangle.
Definition area.h:358
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 width() const
Definition area.h:406
double top
The normalized top coordinate.
Definition area.h:425
bool isBottom(const NormalizedPoint &pt) const
Returns true if the point pt is located below the bottom of the rectangle.
Definition area.h:331
An area with normalized coordinates that contains a reference to an object.
Definition area.h:458
ObjectType
Describes the type of storable object.
Definition area.h:463
@ Image
An image.
Definition area.h:465
@ Action
An action.
Definition area.h:464
@ OAnnotation
An annotation.
Definition area.h:466
This is a list of NormalizedRect, to describe an area consisting of multiple rectangles using normali...
Definition area.h:933
An area with normalized coordinates, consisting of NormalizedShape objects.
Definition area.h:671
void appendShape(const NormalizedShape &shape, MergeSide side=MergeAll)
Appends the given shape to this area.
Definition area.h:810
bool intersects(const NormalizedShape &shape) const
Returns whether the regular area intersects with the given shape.
Definition area.h:767
bool contains(const NormalizedShape &shape) const
Returns whether this area contains a NormalizedShape object that equals shape.
Definition area.h:882
void transform(const QTransform &matrix)
Transforms the regular area with the operations defined by matrix.
Definition area.h:909
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
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
bool contains(double x, double y) const
Returns whether this area contains the normalized point (x, y).
Definition area.h:866
void appendArea(const RegularArea< NormalizedShape, Shape > *area)
Appends the given area to this area.
Definition area.h:802
bool intersects(const RegularArea< NormalizedShape, Shape > *area) const
Returns whether this area intersects with the given area.
Definition area.h:783
This class describes the object rectangle for a source reference.
Definition area.h:599
global.h
Definition action.h:17
MergeSide
The side(s) to be considered when merging areas.
Definition global.h:64
@ MergeBottom
Merge only if the bottom side of the first area intersect.
Definition global.h:66
@ MergeAll
Merge if the areas intersects, no matter which side(s).
Definition global.h:69
@ MergeTop
Merge only if the top side of the first area intersect.
Definition global.h:68
@ MergeRight
Merge only if the right side of the first area intersect.
Definition global.h:65
@ MergeLeft
Merge only if the left side of the first area intersect.
Definition global.h:67
void append(QList< T > &&value)
iterator begin()
bool contains(const AT &value) const const
iterator end()
This file is part of the KDE documentation.