[planner: 6/32] libgnomecanvas: Restore various utility functions used by GnomeCanvasLine




commit 224f7c9ba56f4229ed1ff29643ee9bf011700a89
Author: Mart Raudsepp <leio gentoo org>
Date:   Sun Mar 21 16:14:35 2021 +0200

    libgnomecanvas: Restore various utility functions used by GnomeCanvasLine
    
    We'll need those temporarily for GnomeCanvasLine.
    This is essentially a partial revert of evolution
    commit 61900647523c854d322ed6a7f79922d7e03c33a0

 src/libgnomecanvas/gnome-canvas-util.c | 266 +++++++++++++++++++++++++++++++++
 src/libgnomecanvas/gnome-canvas-util.h |  36 +++++
 2 files changed, 302 insertions(+)
---
diff --git a/src/libgnomecanvas/gnome-canvas-util.c b/src/libgnomecanvas/gnome-canvas-util.c
index f8e33934..58697004 100644
--- a/src/libgnomecanvas/gnome-canvas-util.c
+++ b/src/libgnomecanvas/gnome-canvas-util.c
@@ -102,6 +102,272 @@ gnome_canvas_points_free (GnomeCanvasPoints *points)
        }
 }
 
+/**
+ * gnome_canvas_get_miter_points:
+ * @x1: X coordinate of the first point
+ * @y1: Y coordinate of the first point
+ * @x2: X coordinate of the second (angle) point
+ * @y2: Y coordinate of the second (angle) point
+ * @x3: X coordinate of the third point
+ * @y3: Y coordinate of the third point
+ * @width: Width of the line
+ * @mx1: The X coordinate of the first miter point is returned here.
+ * @my1: The Y coordinate of the first miter point is returned here.
+ * @mx2: The X coordinate of the second miter point is returned here.
+ * @my2: The Y coordinate of the second miter point is returned here.
+ *
+ * Given three points forming an angle, computes the coordinates of the inside
+ * and outside points of the mitered corner formed by a line of a given width at
+ * that angle.
+ *
+ * Return value: FALSE if the angle is less than 11 degrees (this is the same
+ * threshold as X uses.  If this occurs, the return points are not modified.
+ * Otherwise, returns TRUE.
+ **/
+gint
+gnome_canvas_get_miter_points (gdouble x1,
+                               gdouble y1,
+                               gdouble x2,
+                               gdouble y2,
+                               gdouble x3,
+                               gdouble y3,
+                               gdouble width,
+                               gdouble *mx1,
+                               gdouble *my1,
+                               gdouble *mx2,
+                               gdouble *my2)
+{
+       gdouble theta1;         /* angle of segment p2-p1 */
+       gdouble theta2;         /* angle of segment p2-p3 */
+       gdouble theta;          /* angle between line segments */
+       gdouble theta3;         /* angle that bisects theta1 and theta2 and points to p1 */
+       gdouble dist;           /* distance of miter points from p2 */
+       gdouble dx, dy;         /* x and y offsets corresponding to dist */
+
+#define ELEVEN_DEGREES (11.0 * G_PI / 180.0)
+
+       if (y2 == y1)
+               theta1 = (x2 < x1) ? 0.0 : G_PI;
+       else if (x2 == x1)
+               theta1 = (y2 < y1) ? G_PI_2 : -G_PI_2;
+       else
+               theta1 = atan2 (y1 - y2, x1 - x2);
+
+       if (y3 == y2)
+               theta2 = (x3 > x2) ? 0 : G_PI;
+       else if (x3 == x2)
+               theta2 = (y3 > y2) ? G_PI_2 : -G_PI_2;
+       else
+               theta2 = atan2 (y3 - y2, x3 - x2);
+
+       theta = theta1 - theta2;
+
+       if (theta > G_PI)
+               theta -= 2.0 * G_PI;
+       else if (theta < -G_PI)
+               theta += 2.0 * G_PI;
+
+       if ((theta < ELEVEN_DEGREES) && (theta > -ELEVEN_DEGREES))
+               return FALSE;
+
+       dist = 0.5 * width / sin (0.5 * theta);
+       if (dist < 0.0)
+               dist = -dist;
+
+       theta3 = (theta1 + theta2) / 2.0;
+       if (sin (theta3 - (theta1 + G_PI)) < 0.0)
+               theta3 += G_PI;
+
+       dx = dist * cos (theta3);
+       dy = dist * sin (theta3);
+
+       *mx1 = x2 + dx;
+       *mx2 = x2 - dx;
+       *my1 = y2 + dy;
+       *my2 = y2 - dy;
+
+       return TRUE;
+}
+
+/**
+ * gnome_canvas_get_butt_points:
+ * @x1: X coordinate of first point in the line
+ * @y1: Y cooordinate of first point in the line
+ * @x2: X coordinate of second point (endpoint) of the line
+ * @y2: Y coordinate of second point (endpoint) of the line
+ * @width: Width of the line
+ * @project: Whether the butt points should project out by width/2 distance
+ * @bx1: X coordinate of first butt point is returned here
+ * @by1: Y coordinate of first butt point is returned here
+ * @bx2: X coordinate of second butt point is returned here
+ * @by2: Y coordinate of second butt point is returned here
+ *
+ * Computes the butt points of a line segment.
+ **/
+void
+gnome_canvas_get_butt_points (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
+                             gdouble width, gint project,
+                             gdouble *bx1, gdouble *by1, gdouble *bx2, gdouble *by2)
+{
+       gdouble length;
+       gdouble dx, dy;
+
+       width *= 0.5;
+       dx = x2 - x1;
+       dy = y2 - y1;
+       length = sqrt (dx * dx + dy * dy);
+
+       if (length < GNOME_CANVAS_EPSILON) {
+               *bx1 = *bx2 = x2;
+               *by1 = *by2 = y2;
+       } else {
+               dx = -width * (y2 - y1) / length;
+               dy = width * (x2 - x1) / length;
+
+               *bx1 = x2 + dx;
+               *bx2 = x2 - dx;
+               *by1 = y2 + dy;
+               *by2 = y2 - dy;
+
+               if (project) {
+                       *bx1 += dy;
+                       *bx2 += dy;
+                       *by1 -= dx;
+                       *by2 -= dx;
+               }
+       }
+}
+
+/**
+ * gnome_canvas_polygon_to_point:
+ * @poly: Vertices of the polygon.  X coordinates are in the even indices, and Y
+ * coordinates are in the odd indices
+ * @num_points: Number of points in the polygon
+ * @x: X coordinate of the point
+ * @y: Y coordinate of the point
+ *
+ * Computes the distance between a point and a polygon.
+ *
+ * Return value: The distance from the point to the polygon, or zero if the
+ * point is inside the polygon.
+ **/
+gdouble
+gnome_canvas_polygon_to_point (gdouble *poly, gint num_points, gdouble x, gdouble y)
+{
+       gdouble best;
+       gint intersections;
+       gint i;
+       gdouble *p;
+       gdouble dx, dy;
+
+       /* Iterate through all the edges in the polygon, updating best and
+        * intersections.
+        *
+        * When computing intersections, include left X coordinate of line
+        * within its range, but not Y coordinate.  Otherwise if the point
+        * lies exactly below a vertex we'll count it as two intersections. */
+
+       best = 1.0e36;
+       intersections = 0;
+
+       for (i = num_points, p = poly; i > 1; i--, p += 2) {
+               gdouble px, py, dist;
+
+               /* Compute the point on the current edge closest to the
+                * point and update the intersection count.  This must be
+                * done separately for vertical edges, horizontal edges,
+                * and others. */
+
+               if (p[2] == p[0]) {
+                       /* Vertical edge */
+
+                       px = p[0];
+
+                       if (p[1] >= p[3]) {
+                               py = MIN (p[1], y);
+                               py = MAX (py, p[3]);
+                       } else {
+                               py = MIN (p[3], y);
+                               py = MAX (py, p[1]);
+                       }
+               } else if (p[3] == p[1]) {
+                       /* Horizontal edge */
+
+                       py = p[1];
+
+                       if (p[0] >= p[2]) {
+                               px = MIN (p[0], x);
+                               px = MAX (px, p[2]);
+
+                               if ((y < py) && (x < p[0]) && (x >= p[2]))
+                                       intersections++;
+                       } else {
+                               px = MIN (p[2], x);
+                               px = MAX (px, p[0]);
+
+                               if ((y < py) && (x < p[2]) && (x >= p[0]))
+                                       intersections++;
+                       }
+               } else {
+                       gdouble m1, b1, m2, b2;
+                       gint lower;
+
+                       /* Diagonal edge.  Convert the edge to a line equation (y = m1*x + b1), then
+                        * compute a line perpendicular to this edge but passing through the point,
+                        * (y = m2*x + b2).
+                        */
+
+                       m1 = (p[3] - p[1]) / (p[2] - p[0]);
+                       b1 = p[1] - m1 * p[0];
+
+                       m2 = -1.0 / m1;
+                       b2 = y - m2 * x;
+
+                       px = (b2 - b1) / (m1 - m2);
+                       py = m1 * px + b1;
+
+                       if (p[0] > p[2]) {
+                               if (px > p[0]) {
+                                       px = p[0];
+                                       py = p[1];
+                               } else if (px < p[2]) {
+                                       px = p[2];
+                                       py = p[3];
+                               }
+                       } else {
+                               if (px > p[2]) {
+                                       px = p[2];
+                                       py = p[3];
+                               } else if (px < p[0]) {
+                                       px = p[0];
+                                       py = p[1];
+                               }
+                       }
+
+                       lower = (m1 * x + b1) > y;
+
+                       if (lower && (x >= MIN (p[0], p[2])) && (x < MAX (p[0], p[2])))
+                               intersections++;
+               }
+
+               /* Compute the distance to the closest point, and see if that is the best so far */
+
+               dx = x - px;
+               dy = y - py;
+               dist = sqrt (dx * dx + dy * dy);
+               if (dist < best)
+                       best = dist;
+       }
+
+       /* We've processed all the points.  If the number of
+        * intersections is odd, the point is inside the polygon. */
+
+       if (intersections & 0x1)
+               return 0.0;
+       else
+               return best;
+}
+
 /* Here are some helper functions for aa rendering: */
 
 /**
diff --git a/src/libgnomecanvas/gnome-canvas-util.h b/src/libgnomecanvas/gnome-canvas-util.h
index ed491048..22d36efd 100644
--- a/src/libgnomecanvas/gnome-canvas-util.h
+++ b/src/libgnomecanvas/gnome-canvas-util.h
@@ -56,6 +56,42 @@ GnomeCanvasPoints *gnome_canvas_points_ref (GnomeCanvasPoints *points);
 /* Decrease ref count and free structure if it has reached zero */
 void gnome_canvas_points_free (GnomeCanvasPoints *points);
 
+/* Given three points forming an angle, compute the coordinates of the inside and outside points of
+ * the mitered corner formed by a line of a given width at that angle.
+ *
+ * If the angle is less than 11 degrees, then FALSE is returned and the return points are not
+ * modified.  Otherwise, TRUE is returned.
+ */
+gint gnome_canvas_get_miter_points (gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3,
+                                  gdouble width,
+                                  gdouble *mx1, gdouble *my1, gdouble *mx2, gdouble *my2);
+
+/* Compute the butt points of a line segment.  If project is FALSE, then the results are as follows:
+ *
+ *            -------------------* (bx1, by1)
+ *                               |
+ *   (x1, y1) *------------------* (x2, y2)
+ *                               |
+ *            -------------------* (bx2, by2)
+ *
+ * that is, the line is not projected beyond (x2, y2).  If project is TRUE, then the results are as
+ * follows:
+ *
+ *            -------------------* (bx1, by1)
+ *                      (x2, y2) |
+ *   (x1, y1) *-------------*    |
+ *                               |
+ *            -------------------* (bx2, by2)
+ */
+void gnome_canvas_get_butt_points (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
+                                  gdouble width, gint project,
+                                  gdouble *bx1, gdouble *by1, gdouble *bx2, gdouble *by2);
+
+/* Calculate the distance from a polygon to a point.  The polygon's X coordinates are in the even
+ * indices of the poly array, and the Y coordinates are in the odd indices.
+ */
+gdouble gnome_canvas_polygon_to_point (gdouble *poly, gint num_points, gdouble x, gdouble y);
+
 /* Sets the svp to the new value, requesting repaint on what's changed. This
  * function takes responsibility for freeing new_svp. This routine also adds the
  * svp's bbox to the item's.


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