Okular

area.cpp
1/*
2 SPDX-FileCopyrightText: 2004-05 Enrico Ros <eros.kde@email.it>
3 SPDX-FileCopyrightText: 2005 Piotr Szymanski <niedakh@gmail.com>
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "area.h"
8
9#include <QPolygonF>
10#include <QRect>
11
12#include "action.h"
13#include "annotations.h"
14#include "annotations_p.h"
15#include "debug_p.h"
16#include "sourcereference.h"
17
18using namespace Okular;
19
20/** class NormalizedPoint **/
22 : x(0.0)
23 , y(0.0)
24{
25}
26
28 : x(dX)
29 , y(dY)
30{
31}
32
33NormalizedPoint::NormalizedPoint(int iX, int iY, int xScale, int yScale)
34 : x((double)iX / (double)xScale)
35 , y((double)iY / (double)yScale)
36{
37}
38
41
43{
44 qreal tmp_x = (qreal)x;
45 qreal tmp_y = (qreal)y;
46 matrix.map(tmp_x, tmp_y, &tmp_x, &tmp_y);
47 x = tmp_x;
48 y = tmp_y;
49}
50
51double NormalizedPoint::distanceSqr(double x, double y, double xScale, double yScale) const
52{
53 return pow((this->x - x) * xScale, 2) + pow((this->y - y) * yScale, 2);
54}
55
56/**
57 * Returns a vector from the given points @p a and @p b
58 * @internal
59 */
60NormalizedPoint operator-(const NormalizedPoint &a, const NormalizedPoint &b)
61{
62 return NormalizedPoint(a.x - b.x, a.y - b.y);
63}
64
65/**
66 * @brief Calculates distance of the point @p x @p y @p xScale @p yScale to the line segment from @p start to @p end
67 */
68double NormalizedPoint::distanceSqr(double x, double y, double xScale, double yScale, const NormalizedPoint &start, const NormalizedPoint &end)
69{
70 NormalizedPoint point(x, y);
71 double thisDistance;
72 NormalizedPoint lineSegment(end - start);
73 const double lengthSqr = pow(lineSegment.x, 2) + pow(lineSegment.y, 2);
74
75 // if the length of the current segment is null, we can just
76 // measure the distance to either end point
77 if (lengthSqr == 0.0) {
78 thisDistance = end.distanceSqr(x, y, xScale, yScale);
79 } else {
80 // vector from the start point of the current line segment to the measurement point
81 NormalizedPoint a = point - start;
82 // vector from the same start point to the end point of the current line segment
83 NormalizedPoint b = end - start;
84
85 // we're using a * b (dot product) := |a| * |b| * cos(phi) and the knowledge
86 // that cos(phi) is adjacent side / hypotenuse (hypotenuse = |b|)
87 // therefore, t becomes the length of the vector that represents the projection of
88 // the point p onto the current line segment
89 //(hint: if this is still unclear, draw it!)
90 float t = (a.x * b.x + a.y * b.y) / lengthSqr;
91
92 if (t < 0) {
93 // projection falls outside the line segment on the side of "start"
94 thisDistance = point.distanceSqr(start.x, start.y, xScale, yScale);
95 } else if (t > 1) {
96 // projection falls outside the line segment on the side of the current point
97 thisDistance = point.distanceSqr(end.x, end.y, xScale, yScale);
98 } else {
99 // projection is within [start, *i];
100 // determine the length of the perpendicular distance from the projection to the actual point
101 NormalizedPoint direction = end - start;
102 NormalizedPoint projection = start - NormalizedPoint(-t * direction.x, -t * direction.y);
103 thisDistance = projection.distanceSqr(x, y, xScale, yScale);
104 }
105 }
106 return thisDistance;
107}
108
109QDebug operator<<(QDebug str, const Okular::NormalizedPoint &p)
110{
111 str.nospace() << "NormPt(" << p.x << "," << p.y << ")";
112 return str.space();
113}
114
115/** class NormalizedRect **/
116
118 : left(0.0)
119 , top(0.0)
120 , right(0.0)
121 , bottom(0.0)
122{
123}
124
125NormalizedRect::NormalizedRect(double l, double t, double r, double b)
126 // note: check for swapping coords?
127 : left(l)
128 , top(t)
129 , right(r)
130 , bottom(b)
131{
132}
133
134NormalizedRect::NormalizedRect(const QRect r, double xScale, double yScale)
135 : left((double)r.left() / xScale)
136 , top((double)r.top() / yScale)
137 , right((double)r.right() / xScale)
138 , bottom((double)r.bottom() / yScale)
139{
140}
141
143
145{
146 QRectF nrect = rect.normalized();
147 NormalizedRect ret;
148 ret.left = nrect.left();
149 ret.top = nrect.top();
150 ret.right = nrect.right();
151 ret.bottom = nrect.bottom();
152 return ret;
153}
154
156{
157 return left == 0 && top == 0 && right == 0 && bottom == 0;
158}
159
160bool NormalizedRect::contains(double x, double y) const
161{
162 return x >= left && x <= right && y >= top && y <= bottom;
163}
164
166{
167 return (r.left <= right) && (r.right >= left) && (r.top <= bottom) && (r.bottom >= top);
168}
169
171{
172 return (r->left <= right) && (r->right >= left) && (r->top <= bottom) && (r->bottom >= top);
173}
174
175bool NormalizedRect::intersects(double l, double t, double r, double b) const
176{
177 return (l <= right) && (r >= left) && (t <= bottom) && (b >= top);
178}
179
181{
182 NormalizedRect ret;
183 ret.left = qMin(left, r.left);
184 ret.top = qMin(top, r.top);
185 ret.bottom = qMax(bottom, r.bottom);
186 ret.right = qMax(right, r.right);
187 return ret;
188}
189
191{
192 left = qMin(left, r.left);
193 top = qMin(top, r.top);
194 bottom = qMax(bottom, r.bottom);
195 right = qMax(right, r.right);
196 return *this;
197}
198
200{
201 if (isNull() || r.isNull()) {
202 return NormalizedRect();
203 }
204
205 NormalizedRect ret;
206 ret.left = qMax(left, r.left);
207 ret.top = qMax(top, r.top);
208 ret.bottom = qMin(bottom, r.bottom);
209 ret.right = qMin(right, r.right);
210 return ret;
211}
212
214
216{
217 return (isNull() && r.isNull()) || (fabs(left - r.left) < 1e-4 && fabs(right - r.right) < 1e-4 && fabs(top - r.top) < 1e-4 && fabs(bottom - r.bottom) < 1e-4);
218}
219
221{
222 return NormalizedPoint((left + right) / 2.0, (top + bottom) / 2.0);
223}
224
225/*
226QDebug operator << (QDebug str , const NormalizedRect &r)
227{
228 str << "[" <<r.left() << "," << r.top() << "] x "<< "[" <<r.right() << "," << r.bottom() << "]";
229 return str;
230}*/
231
232QRect NormalizedRect::geometry(int xScale, int yScale) const
233{
234 int l = (int)(left * xScale), t = (int)(top * yScale), r = (int)(right * xScale), b = (int)(bottom * yScale);
235
236 return QRect(l, t, r - l + 1, b - t + 1);
237}
238
239QRect NormalizedRect::roundedGeometry(int xScale, int yScale) const
240{
241 int l = (int)(left * xScale + 0.5), t = (int)(top * yScale + 0.5), r = (int)(right * xScale + 0.5), b = (int)(bottom * yScale + 0.5);
242
243 return QRect(l, t, r - l + 1, b - t + 1);
244}
245
246QRectF NormalizedRect::geometryF(float xScale, float yScale) const
247{
248 float l = (left * xScale), t = (top * yScale), r = (right * xScale), b = (bottom * yScale);
249
250 return QRectF(l, t, r - l, b - t);
251}
252
254{
255 QRectF rect(left, top, right - left, bottom - top);
256 rect = matrix.mapRect(rect);
257
258 left = rect.left();
259 top = rect.top();
260 right = rect.right();
261 bottom = rect.bottom();
262}
263
264size_t Okular::qHash(const NormalizedRect &r, size_t seed)
265{
266 return ::qHashMulti(seed, r.bottom, r.right, r.top, r.left);
267}
268
269QDebug operator<<(QDebug str, const Okular::NormalizedRect &r)
270{
271 str.nospace() << "NormRect(" << r.left << "," << r.top << " x " << (r.right - r.left) << "+" << (r.bottom - r.top) << ")";
272 return str.space();
273}
274
275RegularAreaRect::RegularAreaRect()
277 , d(nullptr)
278{
279}
280
281RegularAreaRect::RegularAreaRect(const RegularAreaRect &rar)
283 , d(nullptr)
284{
285}
286
287RegularAreaRect::~RegularAreaRect()
288{
289}
290
291RegularAreaRect &RegularAreaRect::operator=(const RegularAreaRect &rar)
292{
293 if (this != &rar) {
295 }
296 return *this;
297}
298
301 , s_id(-1)
302{
303 if (area) {
305 RegularAreaRect::ConstIterator itEnd = area->end();
306 for (; it != itEnd; ++it) {
308 }
309 }
310}
311
312/** class ObjectRect **/
313
314ObjectRect::ObjectRect(double l, double t, double r, double b, bool ellipse, ObjectType type, void *object)
315 : m_objectType(type)
316 , m_object(object)
317{
318 // assign coordinates swapping them if negative width or height
319 QRectF rect(r > l ? l : r, b > t ? t : b, fabs(r - l), fabs(b - t));
320 if (ellipse) {
321 m_path.addEllipse(rect);
322 } else {
323 m_path.addRect(rect);
324 }
325
326 m_transformedPath = m_path;
327}
328
329ObjectRect::ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object)
330 : m_objectType(type)
331 , m_object(object)
332{
333 QRectF rect(r.left, r.top, fabs(r.right - r.left), fabs(r.bottom - r.top));
334 if (ellipse) {
335 m_path.addEllipse(rect);
336 } else {
337 m_path.addRect(rect);
338 }
339
340 m_transformedPath = m_path;
341}
342
343ObjectRect::ObjectRect(const QPolygonF &poly, ObjectType type, void *object)
344 : m_objectType(type)
345 , m_object(object)
346{
347 m_path.addPolygon(poly);
348
349 m_transformedPath = m_path;
350}
351
353{
354 return m_objectType;
355}
356
357const void *ObjectRect::object() const
358{
359 return m_object;
360}
361
363{
364 return m_transformedPath;
365}
366
367QRect ObjectRect::boundingRect(double xScale, double yScale) const
368{
369 const QRectF &br = m_transformedPath.boundingRect();
370
371 return QRect((int)(br.left() * xScale), (int)(br.top() * yScale), (int)(br.width() * xScale), (int)(br.height() * yScale));
372}
373
374bool ObjectRect::contains(double x, double y, double, double) const
375{
376 return m_transformedPath.contains(QPointF(x, y));
377}
378
380{
381 m_transformedPath = matrix.map(m_path);
382}
383
384double ObjectRect::distanceSqr(double x, double y, double xScale, double yScale) const
385{
386 switch (m_objectType) {
387 case Action:
388 case Image: {
389 const QRectF &rect(m_transformedPath.boundingRect());
390 return NormalizedRect(rect.x(), rect.y(), rect.right(), rect.bottom()).distanceSqr(x, y, xScale, yScale);
391 }
392 case OAnnotation: {
393 return static_cast<Annotation *>(m_object)->d_func()->distanceSqr(x, y, xScale, yScale);
394 }
395 case SourceRef: {
396 const SourceRefObjectRect *sr = static_cast<const SourceRefObjectRect *>(this);
397 const NormalizedPoint &point = sr->m_point;
398 if (point.x == -1.0) {
399 return pow((y - point.y) * yScale, 2);
400 } else if (point.y == -1.0) {
401 return pow((x - point.x) * xScale, 2);
402 } else {
403 return pow((x - point.x) * xScale, 2) + pow((y - point.y) * yScale, 2);
404 }
405 }
406 }
407 return 0.0;
408}
409
411{
412 if (!m_object) {
413 return;
414 }
415
416 if (m_objectType == Action) {
417 delete static_cast<Okular::Action *>(m_object);
418 } else if (m_objectType == SourceRef) {
419 delete static_cast<Okular::SourceReference *>(m_object);
420 } else {
421 qCDebug(OkularCoreDebug).nospace() << "Object deletion not implemented for type '" << m_objectType << "'.";
422 }
423}
424
425/** class AnnotationObjectRect **/
426
428 : ObjectRect(QPolygonF(), OAnnotation, annotation)
429 , m_annotation(annotation)
430{
431}
432
434{
435 return m_annotation;
436}
437
438QRect AnnotationObjectRect::boundingRect(double xScale, double yScale) const
439{
440 const QRect annotRect = AnnotationUtils::annotationGeometry(m_annotation, xScale, yScale);
441 const QPoint center = annotRect.center();
442
443 // Make sure that the rectangle has a minimum size, so that it's possible
444 // to click on it
445 const int minSize = 14;
446 const QRect minRect(center.x() - minSize / 2, center.y() - minSize / 2, minSize, minSize);
447
448 return annotRect | minRect;
449}
450
451bool AnnotationObjectRect::contains(double x, double y, double xScale, double yScale) const
452{
453 return boundingRect(xScale, yScale).contains((int)(x * xScale), (int)(y * yScale), false);
454}
455
457{
458 // the annotation pointer is kept elsewehere (in Page, most probably),
459 // so just release its pointer
460 m_object = nullptr;
461}
462
464{
465 m_annotation->d_func()->annotationTransform(matrix);
466}
467
468/** class SourceRefObjectRect **/
469
471 : ObjectRect(point.x, point.y, .0, .0, false, SourceRef, srcRef)
472 , m_point(point)
473{
474 const double x = m_point.x < 0.0 ? 0.5 : m_point.x;
475 const double y = m_point.y < 0.0 ? 0.5 : m_point.y;
476 const QRectF rect(x - 2, y - 2, 5, 5);
477 m_path.addRect(rect);
478
479 m_transformedPath = m_path;
480}
481
482QRect SourceRefObjectRect::boundingRect(double xScale, double yScale) const
483{
484 const double x = m_point.x < 0.0 ? 0.5 : m_point.x;
485 const double y = m_point.y < 0.0 ? 0.5 : m_point.y;
486
487 return QRect(x * xScale, y * yScale, 1, 1);
488}
489
490bool SourceRefObjectRect::contains(double x, double y, double xScale, double yScale) const
491{
492 return distanceSqr(x, y, xScale, yScale) < (pow(7.0 / xScale, 2) + pow(7.0 / yScale, 2));
493}
494
495/** class NonOwningObjectRect **/
496
497NonOwningObjectRect::NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
498 : ObjectRect(left, top, right, bottom, ellipse, type, object)
499{
500}
501
502NonOwningObjectRect::~NonOwningObjectRect()
503{
504 // Set m_object so that ~ObjectRect() doesn't delete it
505 m_object = nullptr;
506}
Encapsulates data that describes an action.
Definition action.h:41
bool contains(double x, double y, double xScale, double yScale) const override
Returns whether the annotation object rectangle contains the point x, y for the scaling factor xScale...
Definition area.cpp:451
AnnotationObjectRect(Annotation *annotation)
Creates a new annotation object rectangle with the given annotation.
Definition area.cpp:427
Annotation * annotation() const
Returns the annotation object of the annotation object rectangle.
Definition area.cpp:433
~AnnotationObjectRect() override
Destroys the annotation object rectangle.
Definition area.cpp:456
QRect boundingRect(double xScale, double yScale) const override
Returns the bounding rect of the annotation object rectangle for the scaling factor xScale and yScale...
Definition area.cpp:438
void transform(const QTransform &matrix) override
Transforms the annotation object rectangle with the operations defined by matrix.
Definition area.cpp:463
static QRect annotationGeometry(const Annotation *annotation, double scaleX, double scaleY)
Returns the geometry of the given annotation scaled by scaleX and scaleY.
Annotation struct holds properties shared by all annotations.
Definition annotations.h:99
HighlightAreaRect(const RegularAreaRect *area=nullptr)
Creates a new highlight area rect with the coordinates of the given area.
Definition area.cpp:299
NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
class NonOwningObjectRect
Definition area.cpp:497
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition area.h:117
double distanceSqr(double x, double y, double xScale, double yScale) const
Returns squared distance to normalized point (x, y) on a reference area of size xScale x yScale.
Definition area.cpp:51
NormalizedPoint & operator=(const NormalizedPoint &)
NormalizedPoint()
Creates a normalized point at (0, 0).
Definition area.cpp:21
void transform(const QTransform &matrix)
Transforms the normalized point with the operations defined by matrix.
Definition area.cpp:42
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
bool operator==(const NormalizedRect &other) const
Returns whether the normalized rectangle is equal to the other normalized rectangle.
Definition area.cpp:215
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 & operator=(const NormalizedRect &other)
NormalizedPoint center() const
Returns the center of the rectangle.
Definition area.cpp:220
NormalizedRect operator&(const NormalizedRect &other) const
Returns the intersection of this normalized rectangle with the specified other.
Definition area.cpp:199
NormalizedRect & operator|=(const NormalizedRect &other)
Sets the normalized rectangle to the normalized bounding rectangle of itself combined with the other ...
Definition area.cpp:190
double left
The normalized left coordinate.
Definition area.h:420
NormalizedRect()
Creates a null normalized rectangle.
Definition area.cpp:117
bool contains(double x, double y) const
Returns whether the normalized rectangle contains the normalized point (x, y).
Definition area.cpp:160
static NormalizedRect fromQRectF(const QRectF &rect)
Build a normalized rect from a QRectF, which already has normalized coordinates.
Definition area.cpp:144
bool intersects(const NormalizedRect &other) const
Returns whether the normalized rectangle intersects the other normalized rectangle.
Definition area.cpp:165
QRectF geometryF(float xScale, float yScale) const
Same functionality as geometry, but nothing is converted into int.
Definition area.cpp:246
QRect geometry(int xScale, int yScale) const
Returns the rectangle mapped to a reference area of xScale x yScale.
Definition area.cpp:232
double top
The normalized top coordinate.
Definition area.h:425
QRect roundedGeometry(int xScale, int yScale) const
Same functionality as geometry, but the output is now rounded before typecasting to int.
Definition area.cpp:239
NormalizedRect operator|(const NormalizedRect &other) const
Returns the normalized bounding rectangle of the normalized rectangle combined with the other normali...
Definition area.cpp:180
void transform(const QTransform &matrix)
Transforms the normalized rectangle with the operations defined by matrix.
Definition area.cpp:253
bool isNull() const
Returns whether this normalized rectangle is a null normalized rect.
Definition area.cpp:155
An area with normalized coordinates that contains a reference to an object.
Definition area.h:458
ObjectType objectType() const
Returns the object type of the object rectangle.
Definition area.cpp:352
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
@ SourceRef
A source reference.
Definition area.h:467
virtual QRect boundingRect(double xScale, double yScale) const
Returns the bounding rect of the object rectangle for the scaling factor xScale and yScale.
Definition area.cpp:367
ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
Creates a new object rectangle.
Definition area.cpp:314
virtual ~ObjectRect()
Destroys the object rectangle.
Definition area.cpp:410
const void * object() const
Returns the storable object of the object rectangle.
Definition area.cpp:357
const QPainterPath & region() const
Returns the region that is covered by the object rectangle.
Definition area.cpp:362
virtual bool contains(double x, double y, double xScale, double yScale) const
Returns whether the object rectangle contains the point with absolute coordinates (x,...
Definition area.cpp:374
double distanceSqr(double x, double y, double xScale, double yScale) const
Returns the squared distance between the object and the point with normalized coordinates (x,...
Definition area.cpp:384
virtual void transform(const QTransform &matrix)
Transforms the object rectangle with the operations defined by matrix.
Definition area.cpp:379
This is a list of NormalizedRect, to describe an area consisting of multiple rectangles using normali...
Definition area.h:927
An area with normalized coordinates, consisting of NormalizedShape objects.
Definition area.h:665
This class describes the object rectangle for a source reference.
Definition area.h:599
SourceRefObjectRect(const NormalizedPoint &point, void *srcRef)
Creates a new source reference object rectangle.
Definition area.cpp:470
bool contains(double x, double y, double xScale, double yScale) const override
Returns whether the source reference object rectangle contains the point x, y for the scaling factor ...
Definition area.cpp:490
QRect boundingRect(double xScale, double yScale) const override
Returns the bounding rect of the source reference object rectangle for the scaling factor xScale and ...
Definition area.cpp:482
Defines a source reference.
Q_SCRIPTABLE Q_NOREPLY void start()
global.h
Definition action.h:17
QDebug & nospace()
QDebug & space()
void append(QList< T > &&value)
iterator begin()
iterator end()
QList< T > & operator=(QList< T > &&other)
void addEllipse(const QPointF &center, qreal rx, qreal ry)
void addPolygon(const QPolygonF &polygon)
void addRect(const QRectF &rectangle)
QRectF boundingRect() const const
bool contains(const QPainterPath &p) const const
QPoint center() const const
bool contains(const QPoint &point, bool proper) const const
qreal bottom() const const
qreal height() const const
qreal left() const const
QRectF normalized() const const
qreal right() const const
qreal top() const const
qreal width() const const
qreal x() const const
qreal y() const const
QLine map(const QLine &l) const const
QRect mapRect(const QRect &rectangle) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:33 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.