Okular

area.cpp
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 #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 
18 using namespace Okular;
19 
20 /** class NormalizedPoint **/
22  : x(0.0)
23  , y(0.0)
24 {
25 }
26 
27 NormalizedPoint::NormalizedPoint(double dX, double dY)
28  : x(dX)
29  , y(dY)
30 {
31 }
32 
33 NormalizedPoint::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 
51 double 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  */
60 NormalizedPoint 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  */
68 double 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 
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 
125 NormalizedRect::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 
134 NormalizedRect::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 
142 NormalizedRect::NormalizedRect(const NormalizedRect &rect) = default;
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 
160 bool 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 
175 bool 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 /*
226 QDebug operator << (QDebug str , const NormalizedRect &r)
227 {
228  str << "[" <<r.left() << "," << r.top() << "] x "<< "[" <<r.right() << "," << r.bottom() << "]";
229  return str;
230 }*/
231 
232 QRect 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 
239 QRect 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 
247 {
248  QRectF rect(left, top, right - left, bottom - top);
249  rect = matrix.mapRect(rect);
250 
251  left = rect.left();
252  top = rect.top();
253  right = rect.right();
254  bottom = rect.bottom();
255 }
256 
257 uint Okular::qHash(const NormalizedRect &r, uint seed)
258 {
259  return ::qHash(r.bottom, ::qHash(r.right, ::qHash(r.top, ::qHash(r.left, seed))));
260 }
261 
263 {
264  str.nospace() << "NormRect(" << r.left << "," << r.top << " x " << (r.right - r.left) << "+" << (r.bottom - r.top) << ")";
265  return str.space();
266 }
267 
268 RegularAreaRect::RegularAreaRect()
270  , d(nullptr)
271 {
272 }
273 
274 RegularAreaRect::RegularAreaRect(const RegularAreaRect &rar)
276  , d(nullptr)
277 {
278 }
279 
280 RegularAreaRect::~RegularAreaRect()
281 {
282 }
283 
284 RegularAreaRect &RegularAreaRect::operator=(const RegularAreaRect &rar)
285 {
286  if (this != &rar) {
288  }
289  return *this;
290 }
291 
293  : RegularAreaRect()
294  , s_id(-1)
295 {
296  if (area) {
298  RegularAreaRect::ConstIterator itEnd = area->end();
299  for (; it != itEnd; ++it) {
300  append(NormalizedRect(*it));
301  }
302  }
303 }
304 
305 /** class ObjectRect **/
306 
307 ObjectRect::ObjectRect(double l, double t, double r, double b, bool ellipse, ObjectType type, void *object)
308  : m_objectType(type)
309  , m_object(object)
310 {
311  // assign coordinates swapping them if negative width or height
312  QRectF rect(r > l ? l : r, b > t ? t : b, fabs(r - l), fabs(b - t));
313  if (ellipse) {
314  m_path.addEllipse(rect);
315  } else {
316  m_path.addRect(rect);
317  }
318 
319  m_transformedPath = m_path;
320 }
321 
322 ObjectRect::ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object)
323  : m_objectType(type)
324  , m_object(object)
325 {
326  QRectF rect(r.left, r.top, fabs(r.right - r.left), fabs(r.bottom - r.top));
327  if (ellipse) {
328  m_path.addEllipse(rect);
329  } else {
330  m_path.addRect(rect);
331  }
332 
333  m_transformedPath = m_path;
334 }
335 
336 ObjectRect::ObjectRect(const QPolygonF &poly, ObjectType type, void *object)
337  : m_objectType(type)
338  , m_object(object)
339 {
340  m_path.addPolygon(poly);
341 
342  m_transformedPath = m_path;
343 }
344 
346 {
347  return m_objectType;
348 }
349 
350 const void *ObjectRect::object() const
351 {
352  return m_object;
353 }
354 
356 {
357  return m_transformedPath;
358 }
359 
360 QRect ObjectRect::boundingRect(double xScale, double yScale) const
361 {
362  const QRectF &br = m_transformedPath.boundingRect();
363 
364  return QRect((int)(br.left() * xScale), (int)(br.top() * yScale), (int)(br.width() * xScale), (int)(br.height() * yScale));
365 }
366 
367 bool ObjectRect::contains(double x, double y, double, double) const
368 {
369  return m_transformedPath.contains(QPointF(x, y));
370 }
371 
373 {
374  m_transformedPath = matrix.map(m_path);
375 }
376 
377 double ObjectRect::distanceSqr(double x, double y, double xScale, double yScale) const
378 {
379  switch (m_objectType) {
380  case Action:
381  case Image: {
382  const QRectF &rect(m_transformedPath.boundingRect());
383  return NormalizedRect(rect.x(), rect.y(), rect.right(), rect.bottom()).distanceSqr(x, y, xScale, yScale);
384  }
385  case OAnnotation: {
386  return static_cast<Annotation *>(m_object)->d_func()->distanceSqr(x, y, xScale, yScale);
387  }
388  case SourceRef: {
389  const SourceRefObjectRect *sr = static_cast<const SourceRefObjectRect *>(this);
390  const NormalizedPoint &point = sr->m_point;
391  if (point.x == -1.0) {
392  return pow((y - point.y) * yScale, 2);
393  } else if (point.y == -1.0) {
394  return pow((x - point.x) * xScale, 2);
395  } else {
396  return pow((x - point.x) * xScale, 2) + pow((y - point.y) * yScale, 2);
397  }
398  }
399  }
400  return 0.0;
401 }
402 
404 {
405  if (!m_object) {
406  return;
407  }
408 
409  if (m_objectType == Action) {
410  delete static_cast<Okular::Action *>(m_object);
411  } else if (m_objectType == SourceRef) {
412  delete static_cast<Okular::SourceReference *>(m_object);
413  } else {
414  qCDebug(OkularCoreDebug).nospace() << "Object deletion not implemented for type '" << m_objectType << "'.";
415  }
416 }
417 
418 /** class AnnotationObjectRect **/
419 
421  : ObjectRect(QPolygonF(), OAnnotation, annotation)
422  , m_annotation(annotation)
423 {
424 }
425 
427 {
428  return m_annotation;
429 }
430 
431 QRect AnnotationObjectRect::boundingRect(double xScale, double yScale) const
432 {
433  const QRect annotRect = AnnotationUtils::annotationGeometry(m_annotation, xScale, yScale);
434  const QPoint center = annotRect.center();
435 
436  // Make sure that the rectangle has a minimum size, so that it's possible
437  // to click on it
438  const int minSize = 14;
439  const QRect minRect(center.x() - minSize / 2, center.y() - minSize / 2, minSize, minSize);
440 
441  return annotRect | minRect;
442 }
443 
444 bool AnnotationObjectRect::contains(double x, double y, double xScale, double yScale) const
445 {
446  return boundingRect(xScale, yScale).contains((int)(x * xScale), (int)(y * yScale), false);
447 }
448 
450 {
451  // the annotation pointer is kept elsewehere (in Page, most probably),
452  // so just release its pointer
453  m_object = nullptr;
454 }
455 
457 {
458  m_annotation->d_func()->annotationTransform(matrix);
459 }
460 
461 /** class SourceRefObjectRect **/
462 
464  : ObjectRect(point.x, point.y, .0, .0, false, SourceRef, srcRef)
465  , m_point(point)
466 {
467  const double x = m_point.x < 0.0 ? 0.5 : m_point.x;
468  const double y = m_point.y < 0.0 ? 0.5 : m_point.y;
469  const QRectF rect(x - 2, y - 2, 5, 5);
470  m_path.addRect(rect);
471 
472  m_transformedPath = m_path;
473 }
474 
475 QRect SourceRefObjectRect::boundingRect(double xScale, double yScale) const
476 {
477  const double x = m_point.x < 0.0 ? 0.5 : m_point.x;
478  const double y = m_point.y < 0.0 ? 0.5 : m_point.y;
479 
480  return QRect(x * xScale, y * yScale, 1, 1);
481 }
482 
483 bool SourceRefObjectRect::contains(double x, double y, double xScale, double yScale) const
484 {
485  return distanceSqr(x, y, xScale, yScale) < (pow(7.0 / xScale, 2) + pow(7.0 / yScale, 2));
486 }
487 
488 /** class NonOwningObjectRect **/
489 
490 NonOwningObjectRect::NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
491  : ObjectRect(left, top, right, bottom, ellipse, type, object)
492 {
493 }
494 
495 NonOwningObjectRect::~NonOwningObjectRect()
496 {
497  // Set m_object so that ~ObjectRect() doesn't delete it
498  m_object = nullptr;
499 }
void append(const T &value)
NormalizedPoint()
Creates a normalized point at (0, 0).
Definition: area.cpp:21
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
This class describes the object rectangle for a source reference.
Definition: area.h:593
QPoint map(const QPoint &point) const const
qreal left() const const
ObjectType objectType() const
Returns the object type of the object rectangle.
Definition: area.cpp:345
An area with normalized coordinates, consisting of NormalizedShape objects.
Definition: area.h:665
void addPolygon(const QPolygonF &polygon)
double y
The normalized y coordinate.
Definition: area.h:171
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
NormalizedRect operator&(const NormalizedRect &other) const
Returns the intersection of this normalized rectangle with the specified other.
Definition: area.cpp:199
@ Image
An image.
Definition: area.h:460
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:360
The documentation to the global Okular namespace.
Definition: action.h:16
Annotation struct holds properties shared by all annotations.
Definition: annotations.h:95
Encapsulates data that describes an action.
Definition: action.h:40
virtual void transform(const QTransform &matrix)
Transforms the object rectangle with the operations defined by matrix.
Definition: area.cpp:372
qreal x() const const
qreal y() const const
HighlightAreaRect(const RegularAreaRect *area=nullptr)
Creates a new highlight area rect with the coordinates of the given area.
Definition: area.cpp:292
QDebug & nospace()
Q_SCRIPTABLE Q_NOREPLY void start()
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
Definition: area.h:116
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:475
QDebug & space()
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:367
bool contains(const QRect &rectangle, bool proper) const const
ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
Creates a new object rectangle.
Definition: area.cpp:307
bool isNull() const
Returns whether this normalized rectangle is a null normalized rect.
Definition: area.cpp:155
void addEllipse(const QRectF &boundingRectangle)
NormalizedRect operator|(const NormalizedRect &other) const
Returns the normalized bounding rectangle of the normalized rectangle combined with the other normali...
Definition: area.cpp:180
Annotation * annotation() const
Returns the annotation object of the annotation object rectangle.
Definition: area.cpp:426
QRect geometry(int xScale, int yScale) const
Returns the rectangle mapped to a reference area of xScale x yScale.
Definition: area.cpp:232
SourceRefObjectRect(const NormalizedPoint &point, void *srcRef)
Creates a new source reference object rectangle.
Definition: area.cpp:463
bool contains(const QPointF &point) const const
~AnnotationObjectRect() override
Destroys the annotation object rectangle.
Definition: area.cpp:449
This is a list of NormalizedRect, to describe an area consisting of multiple rectangles using normali...
Definition: area.h:927
QRectF boundingRect() const const
@ Action
An action.
Definition: area.h:459
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:431
const void * object() const
Returns the storable object of the object rectangle.
Definition: area.cpp:350
static NormalizedRect fromQRectF(const QRectF &rect)
Build a normalized rect from a QRectF, which already has normalized coordinates.
Definition: area.cpp:144
const QPainterPath & region() const
Returns the region that is covered by the object rectangle.
Definition: area.cpp:355
qreal bottom() const const
KCALENDARCORE_EXPORT uint qHash(const KCalendarCore::Period &key)
NormalizedPoint & operator=(const NormalizedPoint &)
QPoint center() const const
void addRect(const QRectF &rectangle)
QList< T > & operator=(const QList< T > &other)
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
Definition: area.h:188
static QRect annotationGeometry(const Annotation *annotation, double scaleX, double scaleY)
Returns the geometry of the given annotation scaled by scaleX and scaleY.
double left
The normalized left coordinate.
Definition: area.h:415
@ OAnnotation
An annotation.
Definition: area.h:461
qreal top() const const
qreal right() const const
NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object)
class NonOwningObjectRect
Definition: area.cpp:490
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
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 right
The normalized right coordinate.
Definition: area.h:425
void transform(const QTransform &matrix)
Transforms the normalized rectangle with the operations defined by matrix.
Definition: area.cpp:246
NormalizedPoint center() const
Returns the center of the rectangle.
Definition: area.cpp:220
qreal width() const const
ObjectType
Describes the type of storable object.
Definition: area.h:458
Defines a source reference.
NormalizedRect & operator|=(const NormalizedRect &other)
Sets the normalized rectangle to the normalized bounding rectangle of itself combined with the other ...
Definition: area.cpp:190
NormalizedRect()
Creates a null normalized rectangle.
Definition: area.cpp:117
QList::iterator begin()
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:377
bool intersects(const NormalizedRect &other) const
Returns whether the normalized rectangle intersects the other normalized rectangle.
Definition: area.cpp:165
bool contains(double x, double y) const
Returns whether the normalized rectangle contains the normalized point (x, y).
Definition: area.cpp:160
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:483
QRectF normalized() const const
@ SourceRef
A source reference.
Definition: area.h:462
QRect mapRect(const QRect &rectangle) const const
AnnotationObjectRect(Annotation *annotation)
Creates a new annotation object rectangle with the given annotation.
Definition: area.cpp:420
QList::iterator end()
NormalizedRect & operator=(const NormalizedRect &other)
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
void transform(const QTransform &matrix) override
Transforms the annotation object rectangle with the operations defined by matrix.
Definition: area.cpp:456
An area with normalized coordinates that contains a reference to an object.
Definition: area.h:452
virtual ~ObjectRect()
Destroys the object rectangle.
Definition: area.cpp:403
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:444
bool operator==(const NormalizedRect &other) const
Returns whether the normalized rectangle is equal to the other normalized rectangle.
Definition: area.cpp:215
double top
The normalized top coordinate.
Definition: area.h:420
double bottom
The normalized bottom coordinate.
Definition: area.h:430
qreal height() const const
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.