File indexing completed on 2024-04-28 04:32:37
0001 /* 0002 SPDX-FileCopyrightText: 2004-05 Enrico Ros <eros.kde@email.it> 0003 SPDX-FileCopyrightText: 2005 Piotr Szymanski <niedakh@gmail.com> 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef _OKULAR_AREA_H_ 0008 #define _OKULAR_AREA_H_ 0009 0010 #include <math.h> 0011 0012 #include <QColor> 0013 #include <QDebug> 0014 #include <QList> 0015 #include <QPainterPath> 0016 #include <QTransform> 0017 0018 #include "global.h" 0019 #include "okularcore_export.h" 0020 0021 class QPolygonF; 0022 class QRect; 0023 0024 namespace Okular 0025 { 0026 class Annotation; 0027 class Action; 0028 class NormalizedShape; 0029 0030 /** 0031 * NormalizedPoint is a helper class which stores the coordinates 0032 * of a normalized point. 0033 * 0034 * @par Normalized Coordinate System 0035 * @parblock 0036 * Normalized means that the coordinates are always between 0 and 1, 0037 * unless the point shall be outside of the reference area. 0038 * 0039 * The reference area is a rectangle, and all normalized points 0040 * with coordinates of 0 or 1 describe its edges. 0041 * 0042 * This allows to locate things on a reference area without knowing its 0043 * (current or future) actual size. When the reference area is resized, 0044 * all things which are described in normalized coordinates keep their 0045 * proportional position on the area. 0046 * @endparblock 0047 * 0048 * @par Transformation to and from Normalized Coordinates 0049 * @parblock 0050 * To transform normalized coordinates to coordinates on the reference area, 0051 * just multiply them with the size of the reference area. 0052 * 0053 * To get normalized coordinates from a point on the reference area, 0054 * just divide its coordinates with the size of the reference area. 0055 * 0056 * Many methods have parameters @c xScale and @c yScale, 0057 * these are equal to the size of the reference area. 0058 * @endparblock 0059 * 0060 * @par Normalized Coordinate System Applied to Pages 0061 * @parblock 0062 * Okular uses a normalized coordinate system mainly to describe 0063 * positions on pages. 0064 * This is useful because pages can be shown in different sizes (zoom), 0065 * but all objects shall keep their proportional position on the page. 0066 * 0067 * Okular maps from page to normalized coordinates as follows: 0068 * * Left edge of the page: x = 0 0069 * * Right edge of the page: x = 1 0070 * * Top edge of the page: y = 0 0071 * * Bottom edge of the page: y = 1 0072 * @endparblock 0073 * 0074 * @par Example: Draw a Point on a Page 0075 * @parblock 0076 * The point is given in normalized coordinates (0.5, 0.3). 0077 * 0078 * If you want to draw it on a 800x600 page, 0079 * just multiply the x coordinate (0.5) with the page width (800), 0080 * and the y coordinate (0.3) with the page height (600). 0081 * So, the point will be drawn on the page at (400, 180). 0082 * 0083 * That allows you to zoom the page by just multiplying the normalized points with the 0084 * zoomed page size. 0085 * @endparblock 0086 * 0087 * @par Example: Select Text on a Page using Mouse Events 0088 * @parblock 0089 * The position of all glyphs and words is stored in normalized coordinates. 0090 * (This is what TextPage actually does.) 0091 * Mouse press and release events are given in page coordinates (400, 180) and (600, 450), 0092 * while the page has a size of 800x600. 0093 * 0094 * If you want to search all text between the mouse click and release event, 0095 * you need their normalized coordinates. 0096 * Just divide the x coordinates (400 and 600) by the page width (800), 0097 * and the y coordinates (180 and 450) by the page height (600). 0098 * So, you have to search for all glyphs between (0.5, 0.3) and (0.75, 0.75). 0099 * 0100 * That allows you to process all glyphs and words without 0101 * having to keep any of their positions in sync with the page. 0102 * @endparblock 0103 * 0104 * @par Geometric operations 0105 * @parblock 0106 * NormalizedPoint supports basic geometric operations. 0107 * * You can transform it with a QTransform matrix. 0108 * * With the size of the reference area, you can calculate the squared 0109 * absolute distance to another NormalizedPoint or a line of two NormalizedPoints. 0110 * 0111 * NormalizedRect provides additional geometric operations for rectangles. 0112 * @endparblock 0113 * 0114 * @see NormalizedRect 0115 */ 0116 class OKULARCORE_EXPORT NormalizedPoint 0117 { 0118 public: 0119 /** 0120 * Creates a normalized point at (0, 0). 0121 */ 0122 NormalizedPoint(); 0123 0124 /** 0125 * Creates a new normalized point with the normalized coordinates (@p x, @p y ). 0126 */ 0127 NormalizedPoint(double x, double y); 0128 0129 /** 0130 * Creates a new normalized point from an absolute point (@p x, @p y) 0131 * on a reference area of size @p xScale x @p yScale. 0132 */ 0133 NormalizedPoint(int x, int y, int xScale, int yScale); 0134 0135 /** 0136 * @internal 0137 */ 0138 NormalizedPoint &operator=(const NormalizedPoint &); 0139 0140 NormalizedPoint(const NormalizedPoint &); 0141 ~NormalizedPoint() = default; 0142 0143 /** 0144 * Transforms the normalized point with the operations defined by @p matrix. 0145 */ 0146 void transform(const QTransform &matrix); 0147 0148 /** 0149 * Returns squared distance to normalized point (@p x, @p y) 0150 * on a reference area of size @p xScale x @p yScale. 0151 * @since 0.17 (KDE 4.11) 0152 */ 0153 double distanceSqr(double x, double y, double xScale, double yScale) const; 0154 0155 /** 0156 * Returns squared distance of the normalized point (@p x, @p y) 0157 * to the line segment from @p start to @p end 0158 * on a reference area of size @p xScale x @p yScale. 0159 * @since 0.17 (KDE 4.11) 0160 */ 0161 static double distanceSqr(double x, double y, double xScale, double yScale, const NormalizedPoint &start, const NormalizedPoint &end); 0162 0163 /** 0164 * The normalized x coordinate. 0165 */ 0166 double x; 0167 0168 /** 0169 * The normalized y coordinate. 0170 */ 0171 double y; 0172 }; 0173 0174 /** 0175 * A NormalizedRect is a rectangle which can be defined by two NormalizedPoints. 0176 * 0177 * It describes a rectangular area on a reference area of undefined size. 0178 * For more information about the normalized coordinate system, see NormalizedPoint. 0179 * 0180 * In Okular, NormalizedRect can be used e. g. to describe bounding boxes of TextEntity objects, 0181 * and the highlight area of text selections. 0182 * 0183 * If you need to describe an area which consists of multiple rectangles, 0184 * you can use RegularAreaRect instead. 0185 * 0186 * @see NormalizedPoint, RegularAreaRect, TextEntity 0187 */ 0188 class OKULARCORE_EXPORT NormalizedRect 0189 { 0190 public: 0191 /** 0192 * Creates a null normalized rectangle. 0193 * @see isNull() 0194 */ 0195 NormalizedRect(); 0196 0197 /** 0198 * Creates a normalized rectangle with the normalized coordinates 0199 * @p left, @p top, @p right, @p bottom. 0200 * 0201 * If you need the x, y, width and height coordinates use the 0202 * following formulas: 0203 * 0204 * @li x = left 0205 * @li y = top 0206 * @li width = right - left 0207 * @li height = bottom - top 0208 * 0209 * @note 0210 * The coordinates for @p left and @p top should be lower than 0211 * @p right and @p bottom, respectively. 0212 * At negative width or height the behaviour of some operations is undefined. 0213 */ 0214 NormalizedRect(double left, double top, double right, double bottom); 0215 0216 /** 0217 * Creates a normalized rectangle from the given @p rectangle 0218 * on a reference area of size @p xScale x @p yScale. 0219 * 0220 * @note 0221 * The rectangle should have positive width and height. 0222 * You can use e. g. QRect::normalize() to ensure this. 0223 * At negative width or height the behaviour of some operations is undefined. 0224 */ 0225 NormalizedRect(const QRect rectangle, double xScale, double yScale); 0226 0227 /** 0228 * @internal 0229 */ 0230 NormalizedRect(const NormalizedRect &); 0231 0232 /** 0233 * @internal 0234 */ 0235 NormalizedRect &operator=(const NormalizedRect &other); 0236 0237 ~NormalizedRect() = default; 0238 0239 /** 0240 * Build a normalized rect from a QRectF, which already has normalized coordinates. 0241 */ 0242 static NormalizedRect fromQRectF(const QRectF &rect); 0243 0244 /** 0245 * Returns whether this normalized rectangle is a null normalized rect. 0246 */ 0247 bool isNull() const; 0248 0249 /** 0250 * Returns whether the normalized rectangle contains the normalized point 0251 * (@p x, @p y). 0252 */ 0253 bool contains(double x, double y) const; 0254 0255 /** 0256 * Returns whether the normalized rectangle intersects the @p other normalized 0257 * rectangle. 0258 */ 0259 bool intersects(const NormalizedRect &other) const; 0260 0261 /** 0262 * This is an overloaded member function, provided for convenience. It behaves essentially 0263 * like the above function. 0264 */ 0265 bool intersects(const NormalizedRect *other) const; 0266 0267 /** 0268 * Returns whether the normalized rectangle intersects an other normalized 0269 * rectangle, which is defined by @p left, @p top, @p right and @p bottom. 0270 */ 0271 bool intersects(double left, double top, double right, double bottom) const; 0272 0273 /** 0274 * Returns the rectangle mapped to a reference area of @p xScale x @p yScale. 0275 */ 0276 QRect geometry(int xScale, int yScale) const; 0277 0278 /** 0279 * Same functionality as geometry, but the output is now rounded before typecasting to int 0280 * 0281 * @since 0.14 (KDE 4.8) 0282 */ 0283 QRect roundedGeometry(int xScale, int yScale) const; 0284 0285 /** 0286 * Same functionality as geometry, but nothing is converted into int. 0287 */ 0288 QRectF geometryF(float xScale, float yScale) const; 0289 0290 /** 0291 * Returns the normalized bounding rectangle of the normalized rectangle 0292 * combined with the @p other normalized rectangle. 0293 */ 0294 NormalizedRect operator|(const NormalizedRect &other) const; 0295 0296 /** 0297 * Sets the normalized rectangle to the normalized bounding rectangle 0298 * of itself combined with the @p other normalized rectangle. 0299 */ 0300 NormalizedRect &operator|=(const NormalizedRect &other); 0301 0302 /** 0303 * Returns the intersection of this normalized rectangle with the specified 0304 * @p other. If the rects do not intersect then the result is a null rectangle. 0305 * 0306 * @since 0.7 (KDE 4.1) 0307 */ 0308 NormalizedRect operator&(const NormalizedRect &other) const; 0309 0310 /** 0311 * Returns whether the normalized rectangle is equal to the @p other 0312 * normalized rectangle. 0313 */ 0314 bool operator==(const NormalizedRect &other) const; 0315 0316 /** 0317 * Returns the center of the rectangle 0318 * @since 0.10 (KDE 4.4) 0319 */ 0320 NormalizedPoint center() const; 0321 0322 /** 0323 * Transforms the normalized rectangle with the operations defined by @p matrix. 0324 */ 0325 void transform(const QTransform &matrix); 0326 0327 /** 0328 * Returns true if the point @p pt is located below the bottom of the rectangle 0329 * @since 0.14 (KDE 4.8) 0330 */ 0331 bool isBottom(const NormalizedPoint &pt) const 0332 { 0333 return bottom < pt.y; 0334 } 0335 0336 /** 0337 * Returns true if the point @p pt is located above the top of the rectangle 0338 * @since 0.14 (KDE 4.8) 0339 */ 0340 bool isTop(const NormalizedPoint &pt) const 0341 { 0342 return top > pt.y; 0343 } 0344 0345 /** 0346 * Returns true if the point @p pt is located below the top of the rectangle 0347 * @since 0.14 (KDE 4.8) 0348 */ 0349 bool isBottomOrLevel(const NormalizedPoint &pt) const 0350 { 0351 return top < pt.y; 0352 } 0353 0354 /** 0355 * Returns true if the point @p pt is located above the bottom of the rectangle 0356 * @since 0.14 (KDE 4.8) 0357 */ 0358 bool isTopOrLevel(const NormalizedPoint &pt) const 0359 { 0360 return bottom > pt.y; 0361 } 0362 0363 /** 0364 * Returns true if the point @p pt is located to the right of the left edge of the rectangle 0365 * @since 0.14 (KDE 4.8) 0366 */ 0367 bool isLeft(const NormalizedPoint &pt) const 0368 { 0369 return left < pt.x; 0370 } 0371 0372 /** 0373 * Returns true if the point @p pt is located to the left of the right edge of the rectangle 0374 * @since 0.14 (KDE 4.8) 0375 */ 0376 bool isRight(const NormalizedPoint &pt) const 0377 { 0378 return right > pt.x; 0379 } 0380 0381 /** 0382 * Returns the squared distance of the normalized point (@p x, @p y) 0383 * to the closest edge, or 0 if the point is within the rectangle; 0384 * using a reference area of size @p xScale x @p yScale 0385 * @since 0.17 (KDE 4.11) 0386 */ 0387 double distanceSqr(double x, double y, double xScale, double yScale) const 0388 { 0389 double distX = 0; 0390 if (x < left) { 0391 distX = left - x; 0392 } else if (x > right) { 0393 distX = x - right; 0394 } 0395 0396 double distY = 0; 0397 if (top > y) { 0398 distY = top - y; 0399 } else if (bottom < y) { 0400 distY = y - bottom; 0401 } 0402 return pow(distX * xScale, 2) + pow(distY * yScale, 2); 0403 } 0404 0405 /// @since 1.4 0406 double width() const 0407 { 0408 return right - left; 0409 } 0410 0411 /// @since 1.4 0412 double height() const 0413 { 0414 return bottom - top; 0415 } 0416 0417 /** 0418 * The normalized left coordinate. 0419 */ 0420 double left; 0421 0422 /** 0423 * The normalized top coordinate. 0424 */ 0425 double top; 0426 0427 /** 0428 * The normalized right coordinate. 0429 */ 0430 double right; 0431 0432 /** 0433 * The normalized bottom coordinate. 0434 */ 0435 double bottom; 0436 }; 0437 // KDE_DUMMY_QHASH_FUNCTION(NormalizedRect) 0438 0439 /** 0440 * @short An area with normalized coordinates that contains a reference to an object. 0441 * 0442 * These areas ("rects") contain a pointer to a document object 0443 * (such as a hyperlink, an action, or something like that). 0444 * The pointer is read and stored as 'void pointer' so cast is 0445 * performed by accessors based on the value returned by objectType(). Objects 0446 * are reparented to this class. 0447 * 0448 * Type / Class correspondence tab: 0449 * - Action : class Action: description of an action 0450 * - Image : class Image : description of an image (n/a) 0451 * - Annotation: class Annotation: description of an annotation 0452 * 0453 * For more information about the normalized coordinate system, see NormalizedPoint. 0454 * 0455 * @see NormalizedPoint 0456 */ 0457 class OKULARCORE_EXPORT ObjectRect 0458 { 0459 public: 0460 /** 0461 * Describes the type of storable object. 0462 */ 0463 enum ObjectType { 0464 Action, ///< An action 0465 Image, ///< An image 0466 OAnnotation, ///< An annotation 0467 SourceRef ///< A source reference 0468 }; 0469 0470 /** 0471 * Creates a new object rectangle. 0472 * 0473 * @param left The left coordinate of the rectangle. 0474 * @param top The top coordinate of the rectangle. 0475 * @param right The right coordinate of the rectangle. 0476 * @param bottom The bottom coordinate of the rectangle. 0477 * @param ellipse If true the rectangle describes an ellipse. 0478 * @param type The type of the storable object @see ObjectType. 0479 * @param object The pointer to the storable object. 0480 */ 0481 ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object); 0482 0483 /** 0484 * This is an overloaded member function, provided for convenience. 0485 */ 0486 ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object); 0487 0488 /** 0489 * This is an overloaded member function, provided for convenience. 0490 */ 0491 ObjectRect(const QPolygonF &poly, ObjectType type, void *object); 0492 0493 /** 0494 * Destroys the object rectangle. 0495 */ 0496 virtual ~ObjectRect(); 0497 0498 ObjectRect(const ObjectRect &o) = delete; 0499 ObjectRect &operator=(const ObjectRect &o) = delete; 0500 0501 /** 0502 * Returns the object type of the object rectangle. 0503 * @see ObjectType 0504 */ 0505 ObjectType objectType() const; 0506 0507 /** 0508 * Returns the storable object of the object rectangle. 0509 */ 0510 const void *object() const; 0511 0512 /** 0513 * Returns the region that is covered by the object rectangle. 0514 */ 0515 const QPainterPath ®ion() const; 0516 0517 /** 0518 * Returns the bounding rect of the object rectangle for the 0519 * scaling factor @p xScale and @p yScale. 0520 */ 0521 virtual QRect boundingRect(double xScale, double yScale) const; 0522 0523 /** 0524 * Returns whether the object rectangle contains the point with absolute coordinates 0525 * (@p x, @p y) at a page size of @p xScale x @p yScale. 0526 */ 0527 virtual bool contains(double x, double y, double xScale, double yScale) const; 0528 0529 /** 0530 * Transforms the object rectangle with the operations defined by @p matrix. 0531 */ 0532 virtual void transform(const QTransform &matrix); 0533 0534 /** 0535 * Returns the squared distance between the object 0536 * and the point with 0537 * normalized coordinates (@p x, @p y) 0538 * at a page size of @p xScale x @p yScale. 0539 * 0540 * @since 0.8.2 (KDE 4.2.2) 0541 */ 0542 // FIXME this should most probably be a virtual method 0543 double distanceSqr(double x, double y, double xScale, double yScale) const; 0544 0545 protected: 0546 ObjectType m_objectType; 0547 void *m_object; 0548 QPainterPath m_path; 0549 QPainterPath m_transformedPath; 0550 }; 0551 0552 /** 0553 * This class describes the object rectangle for an annotation. 0554 */ 0555 class OKULARCORE_EXPORT AnnotationObjectRect : public ObjectRect 0556 { 0557 public: 0558 /** 0559 * Creates a new annotation object rectangle with the 0560 * given @p annotation. 0561 */ 0562 explicit AnnotationObjectRect(Annotation *annotation); 0563 0564 /** 0565 * Destroys the annotation object rectangle. 0566 */ 0567 ~AnnotationObjectRect() override; 0568 0569 /** 0570 * Returns the annotation object of the annotation object rectangle. 0571 */ 0572 Annotation *annotation() const; 0573 0574 /** 0575 * Returns the bounding rect of the annotation object rectangle for the 0576 * scaling factor @p xScale and @p yScale. 0577 */ 0578 QRect boundingRect(double xScale, double yScale) const override; 0579 0580 /** 0581 * Returns whether the annotation object rectangle contains the point @p x, @p y for the 0582 * scaling factor @p xScale and @p yScale. 0583 */ 0584 bool contains(double x, double y, double xScale, double yScale) const override; 0585 0586 /** 0587 * Transforms the annotation object rectangle with the operations defined by @p matrix. 0588 */ 0589 void transform(const QTransform &matrix) override; 0590 0591 private: 0592 Annotation *m_annotation; 0593 }; 0594 0595 /** 0596 * This class describes the object rectangle for a source reference. 0597 */ 0598 class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect 0599 { 0600 friend class ObjectRect; 0601 0602 public: 0603 /** 0604 * Creates a new source reference object rectangle. 0605 * 0606 * @param point The point of the source reference. 0607 * @param srcRef The storable source reference object. 0608 */ 0609 SourceRefObjectRect(const NormalizedPoint &point, void *srcRef); 0610 0611 /** 0612 * Returns the bounding rect of the source reference object rectangle for the 0613 * scaling factor @p xScale and @p yScale. 0614 */ 0615 QRect boundingRect(double xScale, double yScale) const override; 0616 0617 /** 0618 * Returns whether the source reference object rectangle contains the point @p x, @p y for the 0619 * scaling factor @p xScale and @p yScale. 0620 */ 0621 bool contains(double x, double y, double xScale, double yScale) const override; 0622 0623 private: 0624 NormalizedPoint m_point; 0625 }; 0626 0627 /** 0628 * This class is an object rect that doesn't own the given pointer, i.e. won't delete it on destruction 0629 * @since 1.7 0630 */ 0631 class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect 0632 { 0633 public: 0634 NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object); 0635 ~NonOwningObjectRect() override; 0636 }; 0637 0638 /// @cond PRIVATE 0639 /** @internal */ 0640 /** @internal */ 0641 template<typename T> T *givePtr(T &t) 0642 { 0643 return &t; 0644 } 0645 0646 /** @internal */ 0647 template<typename T> T &deref(T &t) 0648 { 0649 return t; 0650 } 0651 /// @endcond 0652 0653 /** 0654 * @short An area with normalized coordinates, consisting of NormalizedShape objects. 0655 * 0656 * This is a template class to describe an area which consists of 0657 * multiple shapes of the same type, intersecting or non-intersecting. 0658 * The coordinates are normalized, and can be mapped to a reference area of defined size. 0659 * For more information about the normalized coordinate system, see NormalizedPoint. 0660 * 0661 * Class NormalizedShape \b must have the following functions/operators defined: 0662 * - bool contains( double, double ), whether it contains the given NormalizedPoint 0663 * - bool intersects( NormalizedShape ) 0664 * - bool isNull() 0665 * - Shape geometry( int, int ), which maps to the reference area 0666 * - operator|=( NormalizedShape ), which unites two NormalizedShape's 0667 * 0668 * @see RegularAreaRect, NormalizedPoint 0669 */ 0670 template<class NormalizedShape, class Shape> class RegularArea : public QList<NormalizedShape> 0671 { 0672 public: 0673 /** 0674 * Returns whether this area contains the normalized point (@p x, @p y). 0675 */ 0676 bool contains(double x, double y) const; 0677 0678 /** 0679 * Returns whether this area contains a NormalizedShape object that equals @p shape. 0680 * 0681 * @note 0682 * The original NormalizedShape objects can be lost if simplify() was called. 0683 */ 0684 bool contains(const NormalizedShape &shape) const; 0685 0686 /** 0687 * Returns whether this area intersects with the given @p area. 0688 */ 0689 bool intersects(const RegularArea<NormalizedShape, Shape> *area) const; 0690 0691 /** 0692 * Returns whether the regular area intersects with the given @p shape. 0693 */ 0694 bool intersects(const NormalizedShape &shape) const; 0695 0696 /** 0697 * Appends the given @p area to this area. 0698 */ 0699 void appendArea(const RegularArea<NormalizedShape, Shape> *area); 0700 0701 /** 0702 * Appends the given @p shape to this area. 0703 */ 0704 void appendShape(const NormalizedShape &shape, MergeSide side = MergeAll); 0705 0706 /** 0707 * Simplifies this regular area by merging its intersecting subareas. 0708 * This might change the effective geometry of this area. 0709 */ 0710 void simplify(); 0711 0712 /** 0713 * Returns whether the regular area is a null area. 0714 */ 0715 bool isNull() const; 0716 0717 /** 0718 * Returns the subareas of this regular area 0719 * mapped to a reference area of size @p xScale x @p yScale, 0720 * then translated by @p dx and @p dy. 0721 */ 0722 QList<Shape> geometry(int xScale, int yScale, int dx = 0, int dy = 0) const; 0723 0724 /** 0725 * Transforms the regular area with the operations defined by @p matrix. 0726 */ 0727 void transform(const QTransform &matrix); 0728 }; 0729 0730 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::simplify() 0731 { 0732 #ifdef DEBUG_REGULARAREA 0733 int prev_end = this->count(); 0734 #endif 0735 int end = this->count() - 1, x = 0; 0736 for (int i = 0; i < end; ++i) { 0737 if (givePtr((*this)[x])->intersects(deref((*this)[i + 1]))) { 0738 deref((*this)[x]) |= deref((*this)[i + 1]); 0739 this->removeAt(i + 1); 0740 --end; 0741 --i; 0742 } else { 0743 x = i + 1; 0744 } 0745 } 0746 #ifdef DEBUG_REGULARAREA 0747 qCDebug(OkularCoreDebug) << "from" << prev_end << "to" << this->count(); 0748 #endif 0749 } 0750 0751 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::isNull() const 0752 { 0753 if (this->isEmpty()) { 0754 return true; 0755 } 0756 0757 typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end(); 0758 for (; it != itEnd; ++it) { 0759 if (!givePtr(*it)->isNull()) { 0760 return false; 0761 } 0762 } 0763 0764 return true; 0765 } 0766 0767 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const NormalizedShape &shape) const 0768 { 0769 if (this->isEmpty()) { 0770 return false; 0771 } 0772 0773 typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end(); 0774 for (; it != itEnd; ++it) { 0775 if (!givePtr(*it)->isNull() && givePtr(*it)->intersects(shape)) { 0776 return true; 0777 } 0778 } 0779 0780 return false; 0781 } 0782 0783 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const RegularArea<NormalizedShape, Shape> *area) const 0784 { 0785 if (this->isEmpty()) { 0786 return false; 0787 } 0788 0789 typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end(); 0790 for (; it != itEnd; ++it) { 0791 typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end(); 0792 for (; areaIt != areaItEnd; ++areaIt) { 0793 if (!(*it).isNull() && (*it).intersects(*areaIt)) { 0794 return true; 0795 } 0796 } 0797 } 0798 0799 return false; 0800 } 0801 0802 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendArea(const RegularArea<NormalizedShape, Shape> *area) 0803 { 0804 typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end(); 0805 for (; areaIt != areaItEnd; ++areaIt) { 0806 this->append(*areaIt); 0807 } 0808 } 0809 0810 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendShape(const NormalizedShape &shape, MergeSide side) 0811 { 0812 int size = this->count(); 0813 // if the list is empty, adds the shape normally 0814 if (size == 0) { 0815 this->append(shape); 0816 } else { 0817 bool intersection = false; 0818 NormalizedShape &last = (*this)[size - 1]; 0819 #define O_LAST givePtr(last) 0820 #define O_LAST_R O_LAST->right 0821 #define O_LAST_L O_LAST->left 0822 #define O_LAST_T O_LAST->top 0823 #define O_LAST_B O_LAST->bottom 0824 #define O_NEW givePtr(shape) 0825 #define O_NEW_R O_NEW->right 0826 #define O_NEW_L O_NEW->left 0827 #define O_NEW_T O_NEW->top 0828 #define O_NEW_B O_NEW->bottom 0829 switch (side) { 0830 case MergeRight: 0831 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)); 0832 break; 0833 case MergeBottom: 0834 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)); 0835 break; 0836 case MergeLeft: 0837 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)); 0838 break; 0839 case MergeTop: 0840 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)); 0841 break; 0842 case MergeAll: 0843 intersection = O_LAST->intersects(shape); 0844 break; 0845 } 0846 #undef O_LAST 0847 #undef O_LAST_R 0848 #undef O_LAST_L 0849 #undef O_LAST_T 0850 #undef O_LAST_B 0851 #undef O_NEW 0852 #undef O_NEW_R 0853 #undef O_NEW_L 0854 #undef O_NEW_T 0855 #undef O_NEW_B 0856 // if the new shape intersects with the last shape in the list, then 0857 // merge it with that and delete the shape 0858 if (intersection) { 0859 deref((*this)[size - 1]) |= deref(shape); 0860 } else { 0861 this->append(shape); 0862 } 0863 } 0864 } 0865 0866 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(double x, double y) const 0867 { 0868 if (this->isEmpty()) { 0869 return false; 0870 } 0871 0872 typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end(); 0873 for (; it != itEnd; ++it) { 0874 if ((*it).contains(x, y)) { 0875 return true; 0876 } 0877 } 0878 0879 return false; 0880 } 0881 0882 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(const NormalizedShape &shape) const 0883 { 0884 if (this->isEmpty()) { 0885 return false; 0886 } 0887 0888 return QList<NormalizedShape>::contains(shape); 0889 } 0890 0891 template<class NormalizedShape, class Shape> QList<Shape> RegularArea<NormalizedShape, Shape>::geometry(int xScale, int yScale, int dx, int dy) const 0892 { 0893 if (this->isEmpty()) { 0894 return QList<Shape>(); 0895 } 0896 0897 QList<Shape> ret; 0898 Shape t; 0899 typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end(); 0900 for (; it != itEnd; ++it) { 0901 t = givePtr(*it)->geometry(xScale, yScale); 0902 t.translate(dx, dy); 0903 ret.append(t); 0904 } 0905 0906 return ret; 0907 } 0908 0909 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::transform(const QTransform &matrix) 0910 { 0911 if (this->isEmpty()) { 0912 return; 0913 } 0914 0915 for (int i = 0; i < this->count(); ++i) { 0916 givePtr((*this)[i])->transform(matrix); 0917 } 0918 } 0919 0920 /** 0921 * This is a list of NormalizedRect, to describe an area consisting of 0922 * multiple rectangles using normalized coordinates. 0923 * 0924 * This area can be mapped to a reference area, resulting in a list of QRects. 0925 * For more information about the normalized coordinate system, see NormalizedPoint. 0926 * 0927 * Okular uses this area e. g. to describe a text highlight area, 0928 * which consists of multiple, intersecting or non-intersecting rectangles. 0929 * 0930 * @see NormalizedRect, NormalizedPoint 0931 */ 0932 class OKULARCORE_EXPORT RegularAreaRect : public RegularArea<NormalizedRect, QRect> 0933 { 0934 public: 0935 RegularAreaRect(); 0936 RegularAreaRect(const RegularAreaRect &rar); 0937 ~RegularAreaRect(); 0938 0939 RegularAreaRect &operator=(const RegularAreaRect &rar); 0940 0941 private: 0942 class Private; 0943 Private *const d; 0944 }; 0945 0946 /** 0947 * This class stores the geometry of a highlighting area in normalized coordinates, 0948 * together with highlighting specific information. 0949 */ 0950 class HighlightAreaRect : public RegularAreaRect 0951 { 0952 public: 0953 /** 0954 * Creates a new highlight area rect with the coordinates of 0955 * the given @p area. 0956 */ 0957 explicit HighlightAreaRect(const RegularAreaRect *area = nullptr); 0958 0959 /** 0960 * The search ID of the highlight owner. 0961 */ 0962 int s_id; 0963 0964 /** 0965 * The color of the highlight. 0966 */ 0967 QColor color; 0968 }; 0969 0970 size_t qHash(const Okular::NormalizedRect &r, size_t seed = 0); 0971 } 0972 0973 #ifndef QT_NO_DEBUG_STREAM 0974 /** 0975 * Debug operator for normalized @p point. 0976 */ 0977 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedPoint &point); 0978 0979 /** 0980 * Debug operator for normalized @p rect. 0981 */ 0982 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedRect &rect); 0983 #endif 0984 0985 #endif