The BIG graph update
[rrdtool.git] / libraries / libart_lgpl-2.3.7 / art_svp_point.c
1 /* Libart_LGPL - library of basic graphic primitives
2  * Copyright (C) 1999 Raph Levien
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <math.h>
21 #include "art_misc.h"
22
23 #include "art_svp.h"
24 #include "art_svp_point.h"
25
26 /* Determine whether a point is inside, or near, an svp. */
27
28 /* return winding number of point wrt svp */
29 /**
30  * art_svp_point_wind: Determine winding number of a point with respect to svp.
31  * @svp: The svp.
32  * @x: The X coordinate of the point.
33  * @y: The Y coordinate of the point.
34  *
35  * Determine the winding number of the point @x, @y with respect to @svp.
36  *
37  * Return value: the winding number.
38  **/
39 int
40 art_svp_point_wind (ArtSVP *svp, double x, double y)
41 {
42   int i, j;
43   int wind = 0;
44
45   for (i = 0; i < svp->n_segs; i++)
46     {
47       ArtSVPSeg *seg = &svp->segs[i];
48
49       if (seg->bbox.y0 > y)
50         break;
51
52       if (seg->bbox.y1 > y)
53         {
54           if (seg->bbox.x1 < x)
55             wind += seg->dir ? 1 : -1;
56           else if (seg->bbox.x0 <= x)
57             {
58               double x0, y0, x1, y1, dx, dy;
59
60               for (j = 0; j < seg->n_points - 1; j++)
61                 {
62                   if (seg->points[j + 1].y > y)
63                     break;
64                 }
65               x0 = seg->points[j].x;
66               y0 = seg->points[j].y;
67               x1 = seg->points[j + 1].x;
68               y1 = seg->points[j + 1].y;
69
70               dx = x1 - x0;
71               dy = y1 - y0;
72               if ((x - x0) * dy > (y - y0) * dx)
73                 wind += seg->dir ? 1 : -1;
74             }
75         }
76     }
77
78   return wind;
79 }
80
81 /**
82  * art_svp_point_dist: Determine distance between point and svp.
83  * @svp: The svp.
84  * @x: The X coordinate of the point.
85  * @y: The Y coordinate of the point.
86  *
87  * Determines the distance of the point @x, @y to the closest edge in
88  * @svp. A large number is returned if @svp is empty.
89  *
90  * Return value: the distance.
91  **/
92 double
93 art_svp_point_dist (ArtSVP *svp, double x, double y)
94 {
95   int i, j;
96   double dist_sq;
97   double best_sq = -1;
98
99   for (i = 0; i < svp->n_segs; i++)
100     {
101       ArtSVPSeg *seg = &svp->segs[i];
102       for (j = 0; j < seg->n_points - 1; j++)
103         {
104           double x0 = seg->points[j].x;
105           double y0 = seg->points[j].y;
106           double x1 = seg->points[j + 1].x;
107           double y1 = seg->points[j + 1].y;
108
109           double dx = x1 - x0;
110           double dy = y1 - y0;
111
112           double dxx0 = x - x0;
113           double dyy0 = y - y0;
114
115           double dot = dxx0 * dx + dyy0 * dy;
116
117           if (dot < 0)
118             dist_sq = dxx0 * dxx0 + dyy0 * dyy0;
119           else
120             {
121               double rr = dx * dx + dy * dy;
122
123               if (dot > rr)
124                 dist_sq = (x - x1) * (x - x1) + (y - y1) * (y - y1);
125               else
126                 {
127                   double perp = (y - y0) * dx - (x - x0) * dy;
128
129                   dist_sq = perp * perp / rr;
130                 }
131             }
132           if (best_sq < 0 || dist_sq < best_sq)
133             best_sq = dist_sq;
134         }
135     }
136
137   if (best_sq >= 0)
138     return sqrt (best_sq);
139   else
140     return 1e12;
141 }
142