From 4a676722037d9d6d7152c112fbaff1b6e85959d4 Mon Sep 17 00:00:00 2001
From: Edward Hennessy <[EMAIL PROTECTED]>
Date: Thu, 6 Nov 2008 03:16:39 -0800
Subject: [PATCH] Implemented distance selection mechaism for path objects

This patch implements the distance calculation to path objects that may
include both line segments and Bezier curves.  Also, the distance from
a point to a line (o_line_shortest_distance()) is enhanced to handle the
case where both endpoints are equal.
---
 libgeda/include/prototype_priv.h |    2 +-
 libgeda/src/m_polygon.c          |   46 ++++++++++++++++++++++++++++++-----
 libgeda/src/o_line_basic.c       |   36 +++++++++++++++++----------
 libgeda/src/o_path_basic.c       |   49 +++++++++++--------------------------
 4 files changed, 78 insertions(+), 55 deletions(-)

diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 060c507..e23b0c6 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -62,7 +62,7 @@ void m_hatch_polygon(GArray *points, gint angle, gint pitch, 
GArray *lines);
 
 /* m_polygon.c */
 gboolean m_polygon_interior_point(GArray *points, gint x, gint y);
-gdouble m_polygon_shortest_distance(GArray *points, gint x, gint y, gboolean 
solid);
+gdouble m_polygon_shortest_distance(GArray *points, gint x, gint y, gboolean 
closed);
 
 /* m_transform.c */
 void m_transform_combine(TRANSFORM *result, TRANSFORM *a, TRANSFORM *b );
diff --git a/libgeda/src/m_polygon.c b/libgeda/src/m_polygon.c
index 1618861..ffacd24 100644
--- a/libgeda/src/m_polygon.c
+++ b/libgeda/src/m_polygon.c
@@ -142,18 +142,50 @@ gboolean m_polygon_interior_point(GArray *points, gint x, 
gint y)
 }
 
 /*! \brief Calculates the distance between the given point and the closest
- * point on the interior or perimeter of the polygon.
+ *  point on the perimeter of the polygon.
  *
- *  \param [in] points The polygon, where polygon != NULL.
- *  \param [in] x The x coordinate of the given point.
- *  \param [in] y The y coordinate of the given point.
+ *  \param points [in] The polygon, where polygon != NULL.
+ *  \param x [in] The x coordinate of the given point.
+ *  \param y [in] The y coordinate of the given point.
+ *  \param closed [in] If TRUE, the function treats the polygon as a closed
+ *  shape, creating a line between the first and last points, if needed.  If
+ *  the first and last points are equal, or inherintly closed, this parameter
+ *  does not matter.
  *  \return The shortest distance from the polygon to the point.  With an
  *  invalid parameter, this function returns G_MAXDOUBLE.
  */
-gdouble m_polygon_shortest_distance(GArray *points, gint x, gint y, gboolean 
solid)
+gdouble m_polygon_shortest_distance(GArray *points, gint x, gint y, gboolean 
closed)
 {
-  /* TODO Implement */
+  gdouble shortest = G_MAXDOUBLE;
+
+  if (points->len > 0) {
+    gint   index = 0;
+    sPOINT point;
+
+    if (closed) {
+      point = g_array_index(points, sPOINT, points->len-1);
+    } else {
+      point = g_array_index(points, sPOINT, index++);
+    }
+
+    while (index < points->len) {
+      gdouble distance;
+      LINE line;
+
+      line.x[0] = point.x;
+      line.y[0] = point.y;
+
+      point = g_array_index(points, sPOINT, index++);
+
+      line.x[1] = point.x;
+      line.y[1] = point.y;
+
+      distance = o_line_shortest_distance(&line, x, y);
+
+      shortest = min(shortest, distance);
+    }
+  }
 
-  return G_MAXDOUBLE;
+  return shortest;
 }
 
diff --git a/libgeda/src/o_line_basic.c b/libgeda/src/o_line_basic.c
index c0fab50..86652da 100644
--- a/libgeda/src/o_line_basic.c
+++ b/libgeda/src/o_line_basic.c
@@ -1225,6 +1225,9 @@ double o_line_length(OBJECT *object)
  *  end point, this function returns the distance from the given point to the
  *  closest end point.
  *
+ *  If the line represents a single point (the endpoints are the same), this
+ *  function calcualtes the distance to that point.
+ *
  *  \param [in] line  The line of an OBJECT
  *  \param [in] x The x coordinate of the given point.
  *  \param [in] y The y coordinate of the given point.
@@ -1256,23 +1259,30 @@ gdouble o_line_shortest_distance(LINE *line, gint x, 
gint y)
   ldx = ((double) line->x[1]) - ((double) line->x[0]);
   ldy = ((double) line->y[1]) - ((double) line->y[0]);
 
-  /* calculate parametric value of perpendicular intersection */
-  dx0 = ldx * ( x - lx0 );
-  dy0 = ldy * ( y - ly0 );
+  if ( ldx == 0 && ldy == 0 ) {
+    /* if line is a point, just calculate distance to the point */
+    dx = x-lx0;
+    dy = y-ly0;
+
+  } else {
+    /* calculate parametric value of perpendicular intersection */
+    dx0 = ldx * ( x - lx0 );
+    dy0 = ldy * ( y - ly0 );
 
-  t = (dx0 + dy0) / ((ldx*ldx) + (ldy*ldy));
+    t = (dx0 + dy0) / ((ldx*ldx) + (ldy*ldy));
 
-  /* constrain the parametric value to a point on the line */
-  t = max(t, 0);
-  t = min(t, 1);
+    /* constrain the parametric value to a point on the line */
+    t = max(t, 0);
+    t = min(t, 1);
 
-  /* calculate closest point on the line */
-  cx = t * ldx + lx0;
-  cy = t * ldy + ly0;
+    /* calculate closest point on the line */
+    cx = t * ldx + lx0;
+    cy = t * ldy + ly0;
 
-  /* calculate distance to closest point */
-  dx = x-cx;
-  dy = y-cy;
+    /* calculate distance to closest point */
+    dx = x-cx;
+    dy = y-cy;
+  }
 
   shortest_distance = sqrt( (dx*dx) + (dy*dy) );
 
diff --git a/libgeda/src/o_path_basic.c b/libgeda/src/o_path_basic.c
index 08b00b9..c6f6a41 100644
--- a/libgeda/src/o_path_basic.c
+++ b/libgeda/src/o_path_basic.c
@@ -1045,8 +1045,6 @@ void o_path_print(TOPLEVEL *toplevel, FILE *fp, OBJECT 
*o_current,
 /*! \brief Calculates the distance between the given point and the closest
  *  point on the given path segment.
  *
- *  \todo Support for bezier path segments.
- *
  *  \param [in] object The path OBJECT
  *  \param [in] x The x coordinate of the given point.
  *  \param [in] y The y coordinate of the given point.
@@ -1055,45 +1053,28 @@ void o_path_print(TOPLEVEL *toplevel, FILE *fp, OBJECT 
*o_current,
  */
 gdouble o_path_shortest_distance (OBJECT *object, gint x, gint y)
 {
-  PATH_SECTION *section;
-  LINE line;
+  GArray *points;
   gdouble shortest = G_MAXDOUBLE;
-  int last_x = 0, last_y = 0;
-  int i;
+  gboolean solid;
 
-  for (i = 0; i < object->path->num_sections; i++) {
-    section = &object->path->sections[i];
-    switch (section->code) {
+  points = g_array_new(FALSE, FALSE, sizeof(sPOINT));
 
-      case PATH_CURVETO:
-        /* TODO: Shortest distance to a besier section of the path.
-         *       For now, pretend it is a straight line. */
-        /* Fall through */
-      case PATH_LINETO:
-        line.x[0] = last_x;
-        line.y[0] = last_y;
-        line.x[1] = last_x = section->x3;
-        line.y[1] = last_y = section->y3;
-        shortest = MIN (shortest, o_line_shortest_distance (&line, x, y));
-        break;
+  s_path_to_polygon(object->path, points);
 
-      case PATH_MOVETO:
-      case PATH_MOVETO_OPEN:
-        last_x = section->x3;
-        last_y = section->y3;
-        break;
+  solid = object->fill_type != FILLING_HOLLOW;    /* FIXME */
 
-      case PATH_END:
-        /* Need to consider the line back to the first point in the path */
-        line.x[0] = last_x;
-        line.y[0] = last_y;
-        line.x[1] = last_x = object->path->sections[0].x3;
-        line.y[1] = last_y = object->path->sections[0].y3;
-        shortest = MIN (shortest, o_line_shortest_distance (&line, x, y));
-        break;
-    }
+  if (!solid) {
+    shortest = m_polygon_shortest_distance(points, x, y, FALSE);
+
+  } else if (m_polygon_interior_point(points, x, y)) {
+    shortest = 0;
+
+  } else {
+    shortest = m_polygon_shortest_distance(points, x, y, TRUE);
   }
 
+  g_array_free(points, TRUE);
+
   return shortest;
 }
 
-- 
1.5.4.3


_______________________________________________
geda-dev mailing list
geda-dev@moria.seul.org
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev

Reply via email to