[evince/BUG_markup_annots_check_quadrilaterals] markup annotations: check quadrilaterals region



commit 595cc58fcde19bdb3314d962287d0675314fd1e8
Author: Nelson Benítez León <nbenitezl gmail com>
Date:   Sat Dec 28 20:31:54 2019 -0400

    markup annotations: check quadrilaterals region
    
    when determining if the mouse pointer is over
    a markup annotation (used by evince to change
    the pointer type).
    
    Quadrilaterals represent a more precise shape
    of the annotation than just the annotation area
    (which is currently used) so by checking the
    quads region we avoid false positives when
    hovering over blank space.
    
    Implemented as a new libdocument method interface
    that we pass it the 'annotation' and 'x,y' coords
    and returns us whether that annotation has any
    quadrilateral under that location.
    
    The "point over a quadrilateral" code is based on:
    Algorithm: https://math.stackexchange.com/a/190203
    Implementation: https://stackoverflow.com/a/37865332
    
    Fixes issue #1275

 backend/pdf/ev-poppler.cc             | 83 +++++++++++++++++++++++++++++++++++
 libdocument/ev-document-annotations.c | 14 ++++++
 libdocument/ev-document-annotations.h | 15 +++++++
 libview/ev-view.c                     | 14 ++++++
 4 files changed, 126 insertions(+)
---
diff --git a/backend/pdf/ev-poppler.cc b/backend/pdf/ev-poppler.cc
index a6383a15..2e54456a 100644
--- a/backend/pdf/ev-poppler.cc
+++ b/backend/pdf/ev-poppler.cc
@@ -3921,6 +3921,88 @@ pdf_document_annotations_save_annotation (EvDocumentAnnotations *document_annota
        ev_document_set_modified (EV_DOCUMENT (document_annotations), TRUE);
 }
 
+/* Creates a vector from points @p1 and @p2 and stores it on @vector */
+static inline void
+set_vector (PopplerPoint *p1,
+           PopplerPoint *p2,
+           PopplerPoint *vector)
+{
+       vector->x = p2->x - p1->x;
+       vector->y = p2->y - p1->y;
+}
+
+/* Returns the dot product of the passed vectors @v1 and @v2 */
+static inline gdouble
+dot_product (PopplerPoint *v1,
+            PopplerPoint *v2)
+{
+       return v1->x * v2->x + v1->y * v2->y;
+}
+
+/* Algorithm: https://math.stackexchange.com/a/190203
+   Implementation: https://stackoverflow.com/a/37865332 */
+static gboolean
+point_over_poppler_quadrilateral (PopplerQuadrilateral *quad,
+                                 PopplerPoint         *M)
+{
+       PopplerPoint AB, AM, BC, BM;
+       gdouble dotABAM, dotABAB, dotBCBM, dotBCBC;
+
+       /* We interchange p3 and p4 because algorithm expects clockwise eg. p1 -> p2
+          while pdf quadpoints are defined as p1 -> p2                     p4 <- p3
+                                              p3 -> p4 (https://stackoverflow.com/q/9855814) */
+       set_vector (&quad->p1, &quad->p2, &AB);
+       set_vector (&quad->p1, M, &AM);
+       set_vector (&quad->p2, &quad->p4, &BC);
+       set_vector (&quad->p2, M, &BM);
+
+       dotABAM = dot_product (&AB, &AM);
+       dotABAB = dot_product (&AB, &AB);
+       dotBCBM = dot_product (&BC, &BM);
+       dotBCBC = dot_product (&BC, &BC);
+
+       return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
+}
+
+static EvAnnotationsQuadsOver
+pdf_document_annotations_over_quads_xy (EvDocumentAnnotations *document_annotations,
+                                       EvAnnotation          *annot,
+                                       gdouble                x,
+                                       gdouble                y)
+{
+       EvPage       *page;
+       PopplerAnnot *poppler_annot;
+       GArray       *quads;
+       PopplerPoint  M;
+       guint         quads_len;
+       gdouble       height;
+
+       poppler_annot = POPPLER_ANNOT (g_object_get_data (G_OBJECT (annot), "poppler-annot"));
+
+       if (!poppler_annot || !POPPLER_IS_ANNOT_TEXT_MARKUP (poppler_annot))
+               return EV_ANNOTATION_QUADS_OVER_UNKNOWN;
+
+       quads = poppler_annot_text_markup_get_quadrilaterals (POPPLER_ANNOT_TEXT_MARKUP (poppler_annot));
+       quads_len = quads->len;
+
+       page = ev_annotation_get_page (annot);
+       poppler_page_get_size (POPPLER_PAGE (page->backend_page), NULL, &height);
+       M.x = x;
+       M.y = height - y;
+
+       for (guint i = 0; i < quads_len; ++i) {
+               PopplerQuadrilateral *quadrilateral = &g_array_index (quads, PopplerQuadrilateral, i);
+
+               if (point_over_poppler_quadrilateral (quadrilateral, &M)) {
+                       g_array_unref (quads);
+                       return EV_ANNOTATION_QUADS_OVER_YES;
+               }
+       }
+       g_array_unref (quads);
+
+       return EV_ANNOTATION_QUADS_OVER_NOT;
+}
+
 static void
 pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface)
 {
@@ -3929,6 +4011,7 @@ pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *if
        iface->add_annotation = pdf_document_annotations_add_annotation;
        iface->save_annotation = pdf_document_annotations_save_annotation;
        iface->remove_annotation = pdf_document_annotations_remove_annotation;
+       iface->over_quads_xy = pdf_document_annotations_over_quads_xy;
 }
 
 /* Media */
diff --git a/libdocument/ev-document-annotations.c b/libdocument/ev-document-annotations.c
index 96ce4f6c..88d1c6f7 100644
--- a/libdocument/ev-document-annotations.c
+++ b/libdocument/ev-document-annotations.c
@@ -91,3 +91,17 @@ ev_document_annotations_can_remove_annotation (EvDocumentAnnotations *document_a
 
        return iface->remove_annotation != NULL;
 }
+
+EvAnnotationsQuadsOver
+ev_document_annotations_over_quads_xy (EvDocumentAnnotations *document_annots,
+                                      EvAnnotation          *annot,
+                                      gdouble                x,
+                                      gdouble                y)
+{
+       EvDocumentAnnotationsInterface *iface = EV_DOCUMENT_ANNOTATIONS_GET_IFACE (document_annots);
+
+       if (iface->over_quads_xy)
+               return iface->over_quads_xy (document_annots, annot, x, y);
+
+       return EV_ANNOTATION_QUADS_OVER_NOT_IMPLEMENTED;
+}
diff --git a/libdocument/ev-document-annotations.h b/libdocument/ev-document-annotations.h
index 36ec65ab..d05430dc 100644
--- a/libdocument/ev-document-annotations.h
+++ b/libdocument/ev-document-annotations.h
@@ -66,6 +66,13 @@ typedef enum {
        EV_ANNOTATIONS_SAVE_ALL              = (1 << 11) - 1
 } EvAnnotationsSaveMask;
 
+typedef enum {
+       EV_ANNOTATION_QUADS_OVER_NOT_IMPLEMENTED = 0,
+       EV_ANNOTATION_QUADS_OVER_UNKNOWN,
+       EV_ANNOTATION_QUADS_OVER_YES,
+       EV_ANNOTATION_QUADS_OVER_NOT
+} EvAnnotationsQuadsOver;
+
 typedef struct _EvDocumentAnnotations          EvDocumentAnnotations;
 typedef struct _EvDocumentAnnotationsInterface EvDocumentAnnotationsInterface;
 
@@ -85,6 +92,10 @@ struct _EvDocumentAnnotationsInterface
                                                 EvAnnotationsSaveMask  mask);
        void           (* remove_annotation)    (EvDocumentAnnotations *document_annots,
                                                 EvAnnotation          *annot);
+       EvAnnotationsQuadsOver (* over_quads_xy)(EvDocumentAnnotations *document_annots,
+                                                EvAnnotation          *annot,
+                                                gdouble                 x,
+                                                gdouble                 y);
 };
 
 GType          ev_document_annotations_get_type             (void) G_GNUC_CONST;
@@ -102,6 +113,10 @@ void           ev_document_annotations_save_annotation      (EvDocumentAnnotatio
                                                             EvAnnotationsSaveMask  mask);
 gboolean       ev_document_annotations_can_add_annotation    (EvDocumentAnnotations *document_annots);
 gboolean       ev_document_annotations_can_remove_annotation (EvDocumentAnnotations *document_annots);
+EvAnnotationsQuadsOver ev_document_annotations_over_quads_xy (EvDocumentAnnotations *document_annots,
+                                                             EvAnnotation          *annot,
+                                                             gdouble                x,
+                                                             gdouble                y);
 
 G_END_DECLS
 
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 802ca493..14f9f0c5 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -3332,11 +3332,25 @@ ev_view_get_annotation_at_location (EvView  *view,
                                    gdouble  x,
                                    gdouble  y)
 {
+       EvDocumentAnnotations *document_annots;
+       EvAnnotation *annot;
        EvMapping *annotation_mapping;
        gint page;
+       gint doc_x, doc_y;
 
        annotation_mapping = get_annotation_mapping_at_location (view, x, y, &page);
 
+       if (annotation_mapping) {
+               document_annots = EV_DOCUMENT_ANNOTATIONS (view->document);
+               annot = EV_ANNOTATION (annotation_mapping->data);
+
+               if (get_doc_point_from_location (view, x, y, &page, &doc_x, &doc_y) &&
+                   ev_document_annotations_over_quads_xy (document_annots, annot,
+                                                           (gdouble) doc_x, (gdouble) doc_y)
+                                                       == EV_ANNOTATION_QUADS_OVER_NOT)
+                       annotation_mapping = NULL;
+       }
+
        return annotation_mapping ? annotation_mapping->data : NULL;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]