1 /*
2 * Grace - Graphics for Exploratory Data Analysis
3 *
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5 *
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2001 Grace Development Team
8 *
9 * Maintained by Evgeny Stambulchik
10 *
11 *
12 * All Rights Reserved
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*
30 *
31 * routines to allocate, manipulate, and return
32 * information about regions.
33 *
34 */
35
36 #include <config.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include "globals.h"
42
43 #include "draw.h"
44 #include "graphs.h"
45 #include "utils.h"
46 #include "protos.h"
47
48 int regiontype = 0;
49
50 /*
51 * see if (x,y) lies inside the plot
52 */
inbounds(int gno,double x,double y)53 int inbounds(int gno, double x, double y)
54 {
55 WPoint wp;
56
57 wp.x = x;
58 wp.y = y;
59 return is_validWPoint(wp);
60 }
61
isactive_region(int regno)62 int isactive_region(int regno)
63 {
64 return (regno == MAXREGION || regno == MAXREGION + 1 || rg[regno].active == TRUE);
65 }
66
region_types(int it,int which)67 char *region_types(int it, int which)
68 {
69 char *s;
70
71 s = "UNDEFINED";
72 switch (it) {
73 case REGION_TOLEFT:
74 s = "REGION_TOLEFT";
75 break;
76 case REGION_TORIGHT:
77 s = "REGION_TORIGHT";
78 break;
79 case REGION_ABOVE:
80 s = "REGION_ABOVE";
81 break;
82 case REGION_BELOW:
83 s = "REGION_BELOW";
84 break;
85 case REGION_POLYI:
86 if (which) {
87 s = "REGION_POLYI";
88 } else {
89 s = "INSIDE POLY";
90 }
91 break;
92 case REGION_POLYO:
93 if (which) {
94 s = "REGION_POLYO";
95 } else {
96 s = "OUTSIDE POLY";
97 }
98 break;
99 case REGION_HORIZI:
100 s ="REGION_HORIZI";
101 break;
102 case REGION_VERTI:
103 s ="REGION_VERTI";
104 break;
105 case REGION_HORIZO:
106 s ="REGION_HORIZO";
107 break;
108 case REGION_VERTO:
109 s ="REGION_VERTO";
110 break;
111
112 }
113 return s;
114 }
115
kill_region(int r)116 void kill_region(int r)
117 {
118 if (rg[r].active) {
119 XCFREE(rg[r].x);
120 XCFREE(rg[r].y);
121 rg[r].active = FALSE;
122 rg[r].n = 0;
123 set_dirtystate();
124 }
125 }
126
kill_all_regions(void)127 void kill_all_regions(void)
128 {
129 int r;
130 for (r = 0; r < MAXREGION; r++) {
131 kill_region(r);
132 }
133 }
134
activate_region(int r,int type,int linkto)135 void activate_region(int r, int type, int linkto)
136 {
137 kill_region(r);
138 rg[r].active = TRUE;
139 rg[r].type = type;
140 rg[r].linkto = linkto;
141 set_dirtystate();
142 }
143
144
145 /*
146 * report on sets in a region
147 */
reporton_region(int gno,int rno,int type)148 void reporton_region(int gno, int rno, int type)
149 {
150 char buf[256];
151 int i, j, first, contained;
152 double *x, *y;
153 sprintf(buf, "\nRegion R%1d contains:\n", rno);
154 stufftext(buf);
155 for (j = 0; j < number_of_sets(gno); j++) {
156 if (is_set_active(gno, j)) {
157 x = getx(gno, j);
158 y = gety(gno, j);
159 first = 1;
160 contained = 0;
161 for (i = 0; i < getsetlength(gno, j); i++) {
162 if (inregion(rno, x[i], y[i])) {
163 contained = 1;
164 switch (type) {
165 case 0: /* report on sets */
166 if (first) {
167 first = 0;
168 sprintf(buf, " Set S%1d\n", j);
169 stufftext(buf);
170 }
171 break;
172 case 1: /* points */
173 if (first) {
174 first = 0;
175 sprintf(buf, " Set S%1d\n", j);
176 stufftext(buf);
177 }
178 sprintf(buf, " %d %f %f\n", i + 1, x[i], y[i]);
179 stufftext(buf);
180 break;
181 }
182 } else {
183 contained = 0;
184 }
185 }
186 }
187 }
188 stufftext("\n");
189 }
190
load_poly_region(int r,int gno,int n,WPoint * wps)191 void load_poly_region(int r, int gno, int n, WPoint *wps)
192 {
193 int i;
194
195 if (n > 2) {
196 activate_region(r, regiontype, gno);
197 rg[r].n = n;
198 rg[r].x = xcalloc(n, SIZEOF_DOUBLE);
199 rg[r].y = xcalloc(n, SIZEOF_DOUBLE);
200 for (i = 0; i < n; i++) {
201 rg[r].x[i] = wps[i].x;
202 rg[r].y[i] = wps[i].y;
203 }
204 }
205 }
206
207 /*
208 * routines to determine if a point lies in a polygon
209 */
intersect_to_left(double x,double y,double x1,double y1,double x2,double y2)210 int intersect_to_left(double x, double y, double x1, double y1, double x2, double y2)
211 {
212 double xtmp, m, b;
213
214 /* ignore horizontal lines */
215 if (y1 == y2) {
216 return 0;
217 }
218 /* not contained vertically */
219 if (((y < y1) && (y < y2)) || ((y > y1) && (y > y2))) {
220 return 0;
221 }
222 /* none of the above, compute the intersection */
223 if ((xtmp = x2 - x1) != 0.0) {
224 m = (y2 - y1) / xtmp;
225 b = y1 - m * x1;
226 xtmp = (y - b) / m;
227 } else {
228 xtmp = x1;
229 }
230 if (xtmp <= x) {
231 /* check for intersections at a vertex */
232 /* if this is the max ordinate then accept */
233 if (y == y1) {
234 if (y1 > y2) {
235 return 1;
236 } else {
237 return 0;
238 }
239 }
240 /* check for intersections at a vertex */
241 if (y == y2) {
242 if (y2 > y1) {
243 return 1;
244 } else {
245 return 0;
246 }
247 }
248 /* no vertices intersected */
249 return 1;
250 }
251 return 0;
252 }
253
254 /*
255 * determine if (x,y) is in the polygon xlist[], ylist[]
256 */
inbound(double x,double y,double * xlist,double * ylist,int n)257 int inbound(double x, double y, double *xlist, double *ylist, int n)
258 {
259 int i, l = 0;
260
261 for (i = 0; i < n; i++) {
262 l += intersect_to_left(x, y, xlist[i], ylist[i], xlist[(i + 1) % n], ylist[(i + 1) % n]);
263 }
264 return l % 2;
265 }
266
267 /*
268 * routines to determine if a point lies to the left of an infinite line
269 */
isleft(double x,double y,double x1,double y1,double x2,double y2)270 int isleft(double x, double y, double x1, double y1, double x2, double y2)
271 {
272 double xtmp, m, b;
273
274 /* horizontal lines */
275 if (y1 == y2) {
276 return 0;
277 }
278 /* none of the above, compute the intersection */
279 if ((xtmp = x2 - x1) != 0.0) {
280 m = (y2 - y1) / xtmp;
281 b = y1 - m * x1;
282 xtmp = (y - b) / m;
283 } else {
284 xtmp = x1;
285 }
286 if (xtmp >= x) {
287 return 1;
288 }
289 return 0;
290 }
291
292
293 /*
294 * routines to determine if a point lies to the left of an infinite line
295 */
isright(double x,double y,double x1,double y1,double x2,double y2)296 int isright(double x, double y, double x1, double y1, double x2, double y2)
297 {
298 double xtmp, m, b;
299
300 /* horizontal lines */
301 if (y1 == y2) {
302 return 0;
303 }
304 if ((xtmp = x2 - x1) != 0.0) {
305 m = (y2 - y1) / xtmp;
306 b = y1 - m * x1;
307 xtmp = (y - b) / m;
308 } else {
309 xtmp = x1;
310 }
311 if (xtmp <= x) {
312 return 1;
313 }
314 return 0;
315 }
316
317 /*
318 * routines to determine if a point lies above an infinite line
319 */
isabove(double x,double y,double x1,double y1,double x2,double y2)320 int isabove(double x, double y, double x1, double y1, double x2, double y2)
321 {
322 double ytmp, m, b;
323
324 /* vertical lines */
325 if (x1 == x2) {
326 return 0;
327 }
328 if ((ytmp = y2 - y1) != 0.0) {
329 m = ytmp / (x2 - x1);
330 b = y1 - m * x1;
331 ytmp = m * x + b;
332 } else {
333 ytmp = y1;
334 }
335 if (ytmp <= y) {
336 return 1;
337 }
338 return 0;
339 }
340
341 /*
342 * routines to determine if a point lies below an infinite line
343 */
isbelow(double x,double y,double x1,double y1,double x2,double y2)344 int isbelow(double x, double y, double x1, double y1, double x2, double y2)
345 {
346 double ytmp, m, b;
347
348 /* vertical lines */
349 if (x1 == x2) {
350 return 0;
351 }
352 if ((ytmp = y2 - y1) != 0.0) {
353 m = ytmp / (x2 - x1);
354 b = y1 - m * x1;
355 ytmp = m * x + b;
356 } else {
357 ytmp = y1;
358 }
359 if (ytmp >= y) {
360 return 1;
361 }
362 return 0;
363 }
364
inregion(int regno,double x,double y)365 int inregion(int regno, double x, double y)
366 {
367 if (regno == MAXREGION) {
368 return (inbounds(get_cg() , x, y));
369 }
370 if (regno == MAXREGION + 1) {
371 return (!inbounds(get_cg() , x, y));
372 }
373 if (rg[regno].active == TRUE) {
374 switch (rg[regno].type) {
375 case REGION_POLYI:
376 if (inbound(x, y, rg[regno].x, rg[regno].y, rg[regno].n)) {
377 return 1;
378 }
379 break;
380 case REGION_POLYO:
381 if (!inbound(x, y, rg[regno].x, rg[regno].y, rg[regno].n)) {
382 return 1;
383 }
384 break;
385 case REGION_TORIGHT:
386 if (isright(x, y, rg[regno].x1, rg[regno].y1, rg[regno].x2, rg[regno].y2)) {
387 return 1;
388 }
389 break;
390 case REGION_TOLEFT:
391 if (isleft(x, y, rg[regno].x1, rg[regno].y1, rg[regno].x2, rg[regno].y2)) {
392 return 1;
393 }
394 break;
395 case REGION_ABOVE:
396 if (isabove(x, y, rg[regno].x1, rg[regno].y1, rg[regno].x2, rg[regno].y2)) {
397 return 1;
398 }
399 break;
400 case REGION_BELOW:
401 if (isbelow(x, y, rg[regno].x1, rg[regno].y1, rg[regno].x2, rg[regno].y2)) {
402 return 1;
403 }
404 break;
405 case REGION_HORIZI:
406 return (x >= rg[regno].x1) && ( x <= rg[regno].x2);
407 break;
408 case REGION_VERTI:
409 return (y >= rg[regno].y1) && ( y <= rg[regno].y2);
410 break;
411 case REGION_HORIZO:
412 return !( (x >= rg[regno].x1) && ( x <= rg[regno].x2) );
413 break;
414 case REGION_VERTO:
415 return !( (y >= rg[regno].y1) && ( y <= rg[regno].y2) );
416 break;
417
418 }
419 }
420 return 0;
421 }
422