[gimp] app: add various handle and vectors hit tests to gimpcanvasitems-utils.[ch]



commit c4d5693903fc9ee6dd5c2224676ca5f5dcf68d6d
Author: Michael Natterer <mitch gimp org>
Date:   Wed Jun 21 23:21:26 2017 +0200

    app: add various handle and vectors hit tests to gimpcanvasitems-utils.[ch]
    
    1:1 copies of the same functions in gimpdrawtool.[ch].

 app/display/gimpcanvasitem-utils.c |  321 ++++++++++++++++++++++++++++++++++++
 app/display/gimpcanvasitem-utils.h |   68 ++++++--
 2 files changed, 375 insertions(+), 14 deletions(-)
---
diff --git a/app/display/gimpcanvasitem-utils.c b/app/display/gimpcanvasitem-utils.c
index 73dbd54..e72c194 100644
--- a/app/display/gimpcanvasitem-utils.c
+++ b/app/display/gimpcanvasitem-utils.c
@@ -23,10 +23,331 @@
 #include <gegl.h>
 #include <gtk/gtk.h>
 
+#include "libgimpmath/gimpmath.h"
+
 #include "display-types.h"
 
+#include "core/gimpimage.h"
+
+#include "vectors/gimpanchor.h"
+#include "vectors/gimpbezierstroke.h"
+#include "vectors/gimpvectors.h"
+
+#include "gimpcanvasitem.h"
 #include "gimpcanvasitem-utils.h"
+#include "gimpdisplay.h"
+#include "gimpdisplayshell.h"
+#include "gimpdisplayshell-transform.h"
+
+
+gboolean
+gimp_canvas_item_on_handle (GimpCanvasItem  *item,
+                            gdouble           x,
+                            gdouble           y,
+                            GimpHandleType    type,
+                            gdouble           handle_x,
+                            gdouble           handle_y,
+                            gint              width,
+                            gint              height,
+                            GimpHandleAnchor  anchor)
+{
+  GimpDisplayShell *shell;
+  gdouble           tx, ty;
+  gdouble           handle_tx, handle_ty;
+
+  g_return_val_if_fail (GIMP_IS_CANVAS_ITEM (item), FALSE);
+
+  shell = gimp_canvas_item_get_shell (item);
+
+  gimp_display_shell_zoom_xy_f (shell,
+                                x, y,
+                                &tx, &ty);
+  gimp_display_shell_zoom_xy_f (shell,
+                                handle_x, handle_y,
+                                &handle_tx, &handle_ty);
+
+  switch (type)
+    {
+    case GIMP_HANDLE_SQUARE:
+    case GIMP_HANDLE_FILLED_SQUARE:
+    case GIMP_HANDLE_CROSS:
+    case GIMP_HANDLE_CROSSHAIR:
+      gimp_canvas_item_shift_to_north_west (anchor,
+                                            handle_tx, handle_ty,
+                                            width, height,
+                                            &handle_tx, &handle_ty);
+
+      return (tx == CLAMP (tx, handle_tx, handle_tx + width) &&
+              ty == CLAMP (ty, handle_ty, handle_ty + height));
+
+    case GIMP_HANDLE_CIRCLE:
+    case GIMP_HANDLE_FILLED_CIRCLE:
+      gimp_canvas_item_shift_to_center (anchor,
+                                        handle_tx, handle_ty,
+                                        width, height,
+                                        &handle_tx, &handle_ty);
+
+      /* FIXME */
+      if (width != height)
+        width = (width + height) / 2;
+
+      width /= 2;
+
+      return ((SQR (handle_tx - tx) + SQR (handle_ty - ty)) < SQR (width));
+
+    default:
+      g_warning ("%s: invalid handle type %d", G_STRFUNC, type);
+      break;
+    }
 
+  return FALSE;
+}
+
+gboolean
+gimp_canvas_item_on_vectors_handle (GimpCanvasItem    *item,
+                                    GimpVectors       *vectors,
+                                    const GimpCoords  *coord,
+                                    gint               width,
+                                    gint               height,
+                                    GimpAnchorType     preferred,
+                                    gboolean           exclusive,
+                                    GimpAnchor       **ret_anchor,
+                                    GimpStroke       **ret_stroke)
+{
+  GimpStroke *stroke       = NULL;
+  GimpStroke *pref_stroke  = NULL;
+  GimpAnchor *anchor       = NULL;
+  GimpAnchor *pref_anchor  = NULL;
+  gdouble     dx, dy;
+  gdouble     pref_mindist = -1;
+  gdouble     mindist      = -1;
+
+  g_return_val_if_fail (GIMP_IS_CANVAS_ITEM (item), FALSE);
+  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
+  g_return_val_if_fail (coord != NULL, FALSE);
+
+  if (ret_anchor) *ret_anchor = NULL;
+  if (ret_stroke) *ret_stroke = NULL;
+
+  while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
+    {
+      GList *anchor_list;
+      GList *list;
+
+      anchor_list = g_list_concat (gimp_stroke_get_draw_anchors (stroke),
+                                   gimp_stroke_get_draw_controls (stroke));
+
+      for (list = anchor_list; list; list = g_list_next (list))
+        {
+          dx = coord->x - GIMP_ANCHOR (list->data)->position.x;
+          dy = coord->y - GIMP_ANCHOR (list->data)->position.y;
+
+          if (mindist < 0 || mindist > dx * dx + dy * dy)
+            {
+              mindist = dx * dx + dy * dy;
+              anchor = GIMP_ANCHOR (list->data);
+
+              if (ret_stroke)
+                *ret_stroke = stroke;
+            }
+
+          if ((pref_mindist < 0 || pref_mindist > dx * dx + dy * dy) &&
+              GIMP_ANCHOR (list->data)->type == preferred)
+            {
+              pref_mindist = dx * dx + dy * dy;
+              pref_anchor = GIMP_ANCHOR (list->data);
+              pref_stroke = stroke;
+            }
+        }
+
+      g_list_free (anchor_list);
+    }
+
+  /* If the data passed into ret_anchor is a preferred anchor, return it. */
+  if (ret_anchor && *ret_anchor &&
+      gimp_canvas_item_on_handle (item,
+                                  coord->x,
+                                  coord->y,
+                                  GIMP_HANDLE_CIRCLE,
+                                  (*ret_anchor)->position.x,
+                                  (*ret_anchor)->position.y,
+                                  width, height,
+                                  GIMP_HANDLE_ANCHOR_CENTER) &&
+      (*ret_anchor)->type == preferred)
+    {
+      if (ret_stroke) *ret_stroke = pref_stroke;
+
+      return TRUE;
+    }
+
+  if (pref_anchor && gimp_canvas_item_on_handle (item,
+                                                 coord->x,
+                                                 coord->y,
+                                                 GIMP_HANDLE_CIRCLE,
+                                                 pref_anchor->position.x,
+                                                 pref_anchor->position.y,
+                                                 width, height,
+                                                 GIMP_HANDLE_ANCHOR_CENTER))
+    {
+      if (ret_anchor) *ret_anchor = pref_anchor;
+      if (ret_stroke) *ret_stroke = pref_stroke;
+
+      return TRUE;
+    }
+  else if (!exclusive && anchor &&
+           gimp_canvas_item_on_handle (item,
+                                       coord->x,
+                                       coord->y,
+                                       GIMP_HANDLE_CIRCLE,
+                                       anchor->position.x,
+                                       anchor->position.y,
+                                       width, height,
+                                       GIMP_HANDLE_ANCHOR_CENTER))
+    {
+      if (ret_anchor)
+        *ret_anchor = anchor;
+
+      /* *ret_stroke already set correctly. */
+      return TRUE;
+    }
+
+  if (ret_anchor)
+    *ret_anchor = NULL;
+  if (ret_stroke)
+    *ret_stroke = NULL;
+
+  return FALSE;
+}
+
+gboolean
+gimp_canvas_item_on_vectors_curve (GimpCanvasItem    *item,
+                                   GimpVectors       *vectors,
+                                   const GimpCoords  *coord,
+                                   gint               width,
+                                   gint               height,
+                                   GimpCoords        *ret_coords,
+                                   gdouble           *ret_pos,
+                                   GimpAnchor       **ret_segment_start,
+                                   GimpAnchor       **ret_segment_end,
+                                   GimpStroke       **ret_stroke)
+{
+  GimpStroke *stroke = NULL;
+  GimpAnchor *segment_start;
+  GimpAnchor *segment_end;
+  GimpCoords  min_coords = GIMP_COORDS_DEFAULT_VALUES;
+  GimpCoords  cur_coords;
+  gdouble     min_dist, cur_dist, cur_pos;
+
+  g_return_val_if_fail (GIMP_IS_CANVAS_ITEM (item), FALSE);
+  g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
+  g_return_val_if_fail (coord != NULL, FALSE);
+
+  if (ret_coords)        *ret_coords        = *coord;
+  if (ret_pos)           *ret_pos           = -1.0;
+  if (ret_segment_start) *ret_segment_start = NULL;
+  if (ret_segment_end)   *ret_segment_end   = NULL;
+  if (ret_stroke)        *ret_stroke        = NULL;
+
+  min_dist = -1.0;
+
+  while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
+    {
+      cur_dist = gimp_stroke_nearest_point_get (stroke, coord, 1.0,
+                                                &cur_coords,
+                                                &segment_start,
+                                                &segment_end,
+                                                &cur_pos);
+
+      if (cur_dist >= 0 && (min_dist < 0 || cur_dist < min_dist))
+        {
+          min_dist   = cur_dist;
+          min_coords = cur_coords;
+
+          if (ret_coords)        *ret_coords        = cur_coords;
+          if (ret_pos)           *ret_pos           = cur_pos;
+          if (ret_segment_start) *ret_segment_start = segment_start;
+          if (ret_segment_end)   *ret_segment_end   = segment_end;
+          if (ret_stroke)        *ret_stroke        = stroke;
+        }
+    }
+
+  if (min_dist >= 0 &&
+      gimp_canvas_item_on_handle (item,
+                                  coord->x,
+                                  coord->y,
+                                  GIMP_HANDLE_CIRCLE,
+                                  min_coords.x,
+                                  min_coords.y,
+                                  width, height,
+                                  GIMP_HANDLE_ANCHOR_CENTER))
+    {
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+gboolean
+gimp_canvas_item_on_vectors (GimpCanvasItem    *item,
+                             const GimpCoords  *coords,
+                             gint               width,
+                             gint               height,
+                             GimpCoords        *ret_coords,
+                             gdouble           *ret_pos,
+                             GimpAnchor       **ret_segment_start,
+                             GimpAnchor       **ret_segment_end,
+                             GimpStroke       **ret_stroke,
+                             GimpVectors      **ret_vectors)
+{
+  GimpDisplayShell *shell;
+  GimpImage        *image;
+  GList            *all_vectors;
+  GList            *list;
+
+  g_return_val_if_fail (GIMP_IS_CANVAS_ITEM (item), FALSE);
+  g_return_val_if_fail (coords != NULL, FALSE);
+
+  shell = gimp_canvas_item_get_shell (item);
+  image = gimp_display_get_image (shell->display);
+
+  if (ret_coords)        *ret_coords         = *coords;
+  if (ret_pos)           *ret_pos            = -1.0;
+  if (ret_segment_start) *ret_segment_start  = NULL;
+  if (ret_segment_end)   *ret_segment_end    = NULL;
+  if (ret_stroke)        *ret_stroke         = NULL;
+  if (ret_vectors)       *ret_vectors        = NULL;
+
+  all_vectors = gimp_image_get_vectors_list (image);
+
+  for (list = all_vectors; list; list = g_list_next (list))
+    {
+      GimpVectors *vectors = list->data;
+
+      if (! gimp_item_get_visible (GIMP_ITEM (vectors)))
+        continue;
+
+      if (gimp_canvas_item_on_vectors_curve (item,
+                                             vectors, coords,
+                                             width, height,
+                                             ret_coords,
+                                             ret_pos,
+                                             ret_segment_start,
+                                             ret_segment_end,
+                                             ret_stroke))
+        {
+          if (ret_vectors)
+            *ret_vectors = vectors;
+
+          g_list_free (all_vectors);
+
+          return TRUE;
+        }
+    }
+
+  g_list_free (all_vectors);
+
+  return FALSE;
+}
 
 void
 gimp_canvas_item_shift_to_north_west (GimpHandleAnchor  anchor,
diff --git a/app/display/gimpcanvasitem-utils.h b/app/display/gimpcanvasitem-utils.h
index 7271877..bca9b3f 100644
--- a/app/display/gimpcanvasitem-utils.h
+++ b/app/display/gimpcanvasitem-utils.h
@@ -22,20 +22,60 @@
 #define __GIMP_CANVAS_ITEM_UTILS_H__
 
 
-void   gimp_canvas_item_shift_to_north_west (GimpHandleAnchor  anchor,
-                                             gdouble           x,
-                                             gdouble           y,
-                                             gint              width,
-                                             gint              height,
-                                             gdouble          *shifted_x,
-                                             gdouble          *shifted_y);
-void   gimp_canvas_item_shift_to_center     (GimpHandleAnchor  anchor,
-                                             gdouble           x,
-                                             gdouble           y,
-                                             gint              width,
-                                             gint              height,
-                                             gdouble          *shifted_x,
-                                             gdouble          *shifted_y);
+gboolean   gimp_canvas_item_on_handle           (GimpCanvasItem    *item,
+                                                 gdouble            x,
+                                                 gdouble            y,
+                                                 GimpHandleType     type,
+                                                 gdouble            handle_x,
+                                                 gdouble            handle_y,
+                                                 gint               width,
+                                                 gint               height,
+                                                 GimpHandleAnchor   anchor);
+
+gboolean   gimp_canvas_item_on_vectors_handle   (GimpCanvasItem    *item,
+                                                 GimpVectors       *vectors,
+                                                 const GimpCoords  *coord,
+                                                 gint               width,
+                                                 gint               height,
+                                                 GimpAnchorType     preferred,
+                                                 gboolean           exclusive,
+                                                 GimpAnchor       **ret_anchor,
+                                                 GimpStroke       **ret_stroke);
+gboolean   gimp_canvas_item_on_vectors_curve    (GimpCanvasItem    *item,
+                                                 GimpVectors       *vectors,
+                                                 const GimpCoords  *coord,
+                                                 gint               width,
+                                                 gint               height,
+                                                 GimpCoords        *ret_coords,
+                                                 gdouble           *ret_pos,
+                                                 GimpAnchor       **ret_segment_start,
+                                                 GimpAnchor       **ret_segment_end,
+                                                 GimpStroke       **ret_stroke);
+gboolean   gimp_canvas_item_on_vectors          (GimpCanvasItem    *item,
+                                                 const GimpCoords  *coords,
+                                                 gint               width,
+                                                 gint               height,
+                                                 GimpCoords        *ret_coords,
+                                                 gdouble           *ret_pos,
+                                                 GimpAnchor       **ret_segment_start,
+                                                 GimpAnchor       **ret_segment_end,
+                                                 GimpStroke       **ret_stroke,
+                                                 GimpVectors      **ret_vectors);
+
+void       gimp_canvas_item_shift_to_north_west (GimpHandleAnchor   anchor,
+                                                 gdouble            x,
+                                                 gdouble            y,
+                                                 gint               width,
+                                                 gint               height,
+                                                 gdouble           *shifted_x,
+                                                 gdouble           *shifted_y);
+void       gimp_canvas_item_shift_to_center     (GimpHandleAnchor   anchor,
+                                                 gdouble            x,
+                                                 gdouble            y,
+                                                 gint               width,
+                                                 gint               height,
+                                                 gdouble           *shifted_x,
+                                                 gdouble           *shifted_y);
 
 
 #endif /* __GIMP_CANVAS_ITEM_UTILS_H__ */


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