1 /*
2  *   GRacer
3  *
4  *   Copyright (C) 1999 Takashi Matsuda <matsu@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  */
21 
22 #include <assert.h>
23 #include <string.h>
24 #include "gr_course.h"
25 #include "gr_memory.h"
26 #include "gr_vertex.h"
27 
28 enum {
29   TOKEN_NUM_GRID,
30   TOKEN_GRID,
31   TOKEN_NUM_CLINE,
32   TOKEN_CLINE,
33   TOKEN_NUM_MAT,
34   TOKEN_MAT,
35   TOKEN_NUM_SEG,
36   TOKEN_SEG,
37   TOKEN_NUM_VERT,
38   TOKEN_NUM_SURF,
39   TOKEN_TITLE,
40   TOKEN_DESC,
41   TOKEN_MODEL,
42   TOKEN_TIMESTAMP,
43 
44   TOKEN_INVALID = -1,
45 };
46 
47 static struct {
48   int type;
49   char *str;
50   int len;
51 } tokens[] = {
52   {TOKEN_NUM_GRID,	"NUM_GRID",	8},
53   {TOKEN_GRID,		"GRID",		4},
54   {TOKEN_NUM_CLINE,	"NUM_CLINE",	9},
55   {TOKEN_CLINE,		"CLINE",	5},
56   {TOKEN_NUM_MAT,	"NUM_MAT",	7},
57   {TOKEN_MAT,		"MAT",		3},
58   {TOKEN_NUM_SEG,	"NUM_SEG",	7},
59   {TOKEN_SEG,		"SEG",		3},
60   {TOKEN_NUM_VERT,	"NUM_VERT",	8},
61   {TOKEN_NUM_SURF,	"NUM_SURF",	8},
62   {TOKEN_TITLE,		"TITLE",	5},
63   {TOKEN_DESC,		"DESC",		4},
64   {TOKEN_MODEL,		"MODEL",	5},
65   {TOKEN_TIMESTAMP,	"TIMESTAMP",	9},
66   {TOKEN_INVALID,	NULL,	-1},
67 };
68 
69 
70 static int		next_line		(char *data, int *index);
71 static int		find_token		(char *data, int *index);
72 static int		next_word		(char *data, int *index);
73 static char*		get_name		(char *data, int *index);
74 static void		put_name		(char *str, FILE *file);
75 static GrCSegment*	read_segment		(GrCourse *course,
76     						 char *data,
77 						 int *index);
78 static void		create_boundary		(GrCSegment *seg);
79 static void		initialize_surface	(GrCSegment *seg);
80 
81 
82 static void
gr_csegment_free(GrCSegment * seg)83 gr_csegment_free (GrCSegment *seg)
84 {
85   gr_boundary_free (seg->boundary);
86   free (seg->verts);
87   free (seg->surfs);
88 }
89 
90 static void
gr_course_free(GrCourse * course)91 gr_course_free (GrCourse *course)
92 {
93   int i;
94 
95   free (course->title);
96   free (course->desc);
97   free (course->model);
98   free (course->timestamp);
99   free (course->grids);
100   free (course->clines);
101   free (course->mats);
102 
103   for (i=0; i<course->num_segs; i++) {
104     free (course->segs[i]);
105   }
106   free (course->segs);
107 
108   free (course);
109 }
110 
111 GrCourse*
gr_course_new_from_file(FILE * file)112 gr_course_new_from_file (FILE *file)
113 {
114   size_t pos;
115   size_t len;
116   char *buf;
117   GrCourse *course;
118 
119   pos = ftell (file);
120   fseek (file, 0, SEEK_END);
121   len = ftell (file) - pos;
122   fseek (file, pos, SEEK_SET);
123 
124   buf = gr_new (char, len+1);
125   if (!buf) {
126     return NULL;
127   }
128   fread (buf, 1, len, file);
129   buf[len] = '\0';
130 
131   course = gr_course_new_from_data (buf);
132   free (buf);
133 
134   return course;
135 }
136 
137 GrCourse*
gr_course_new_from_data(char * data)138 gr_course_new_from_data (char *data)
139 {
140   GrCourse *course = NULL;
141   GrControlLine *cline;
142   int i = 0, j, k;
143   int token;
144   float x[6];
145   float y[6];
146   float f;
147 
148   if (strncmp (data, "GRACER COURSE/1.0\n", 18))
149     goto ERROR;
150 
151   course = gr_new0 (GrCourse, 1);
152   if (!course)
153     return NULL;
154   gr_FREE_FUNC (course, gr_course_free);
155 
156   next_line (data, &i);
157   while (data[i] != '\0') {
158     token = find_token (data, &i);
159     switch (token) {
160     case TOKEN_TITLE:
161       next_word (data, &i);
162       course->title = get_name (data, &i);
163       break;
164 
165     case TOKEN_DESC:
166       next_word (data, &i);
167       course->desc = get_name (data, &i);
168       break;
169 
170     case TOKEN_MODEL:
171       next_word (data, &i);
172       course->model = get_name (data, &i);
173       break;
174 
175     case TOKEN_TIMESTAMP:
176       next_word (data, &i);
177       course->timestamp = get_name (data, &i);
178       break;
179 
180     case TOKEN_NUM_GRID:
181       next_word (data, &i);
182       sscanf (data+i, "%d", &course->num_grids);
183       course->grids = gr_new (GrGrid, course->num_grids);
184       next_line (data, &i);
185       for (j=0; j<course->num_grids; j++) {
186 	sscanf (data+i, "GRID %d %d %f %f %f",
187 	    	&course->grids[j].flag,
188 	    	&course->grids[j].segment,
189 	    	&course->grids[j].x,
190 	    	&course->grids[j].y,
191 	    	&course->grids[j].dir);
192 	next_line (data, &i);
193       }
194       break;
195 
196     case TOKEN_NUM_CLINE:
197       next_word (data, &i);
198       sscanf (data+i, "%d", &course->num_clines);
199       course->clines = gr_new (GrControlLine, course->num_clines);
200       next_line (data, &i);
201       for (j=0; j<course->num_clines; j++) {
202 	cline = course->clines + j;
203 
204 	sscanf (data+i, "CLINE %d %d",
205 	    	&cline->segment,
206 	    	&cline->flag);
207 	next_line (data, &i);
208 	for (k=0; k<6; k++) {
209 	  sscanf (data+i, "%f %f", &x[k], &y[k]);
210 	  next_line (data, &i);
211 	}
212 	cline->region_a[0].c.x = x[0];
213 	cline->region_a[0].c.y = y[0];
214 	cline->region_a[1].c.x = x[1];
215 	cline->region_a[1].c.y = y[1];
216 	cline->region_a[2].c.x = x[3];
217 	cline->region_a[2].c.y = y[3];
218 	cline->region_a[3].c.x = x[2];
219 	cline->region_a[3].c.y = y[2];
220 
221 	cline->region_b[0].c.x = x[2];
222 	cline->region_b[0].c.y = y[2];
223 	cline->region_b[1].c.x = x[3];
224 	cline->region_b[1].c.y = y[3];
225 	cline->region_b[2].c.x = x[5];
226 	cline->region_b[2].c.y = y[5];
227 	cline->region_b[3].c.x = x[4];
228 	cline->region_b[3].c.y = y[4];
229 
230 	/* calcurate boundary rectangle */
231 	cline->xmax = cline->xmin = x[0];
232 	cline->ymax = cline->ymin = y[0];
233 	for (k=1; k<6; k++) {
234 	  if (cline->xmax < x[k]) {
235 	    cline->xmax = x[k];
236 	  }
237 	  if (cline->xmin > x[k]) {
238 	    cline->xmin = x[k];
239 	  }
240 	  if (cline->ymax < y[k]) {
241 	    cline->ymax = y[k];
242 	  }
243 	  if (cline->ymin > y[k]) {
244 	    cline->ymin = y[k];
245 	  }
246 	}
247 
248 	/* rotate 90 degree */
249 	for (k=0; k<4; k++) {
250 	  gr_vertex_sub_xy (cline->rot_a+k,
251 			    cline->region_a + (k+1) % 4,
252 			    cline->region_a + k);
253 	  f = cline->rot_a[k].c.x;
254 	  cline->rot_a[k].c.x = - cline->rot_a[k].c.y;
255 	  cline->rot_a[k].c.y = f;
256 
257 	  gr_vertex_sub_xy (cline->rot_b+k,
258 			    cline->region_b + (k+1) % 4,
259 			    cline->region_b + k);
260 	  f = cline->rot_b[k].c.x;
261 	  cline->rot_b[k].c.x = - cline->rot_b[k].c.y;
262 	  cline->rot_b[k].c.y = f;
263 	}
264       }
265 
266       break;
267 
268     case TOKEN_NUM_MAT:
269       next_word (data, &i);
270       sscanf (data+i, "%d", &course->num_mats);
271       course->mats = gr_new (GrCMaterial, course->num_mats);
272       next_line (data, &i);
273       for (j=0; j<course->num_mats; j++) {
274 	sscanf (data+i, "MAT %d %f %f %f",
275 	    	&course->mats[j].flag,
276 	    	&course->mats[j].friction,
277 	    	&course->mats[j].exp,
278 	    	&course->mats[j].mu);
279 	next_line (data, &i);
280       }
281       break;
282 
283     case TOKEN_NUM_SEG:
284       next_word (data, &i);
285       sscanf (data+i, "%d", &course->num_segs);
286       course->segs = gr_new (GrCSegment *, course->num_segs);
287       next_line (data, &i);
288       for (j=0; j<course->num_mats; j++) {
289 	course->segs[j] = read_segment (course, data, &i);
290       }
291       break;
292     }
293   }
294 
295   for (i=0; i<course->num_segs; i++) {
296     initialize_surface (course->segs[i]);
297     create_boundary (course->segs[i]);
298   }
299 
300   return course;
301 
302 ERROR:
303   if (course) {
304     gr_DECREF (course);
305   }
306   return NULL;
307 }
308 
309 
310 static GrCSurface *
gr_course_find_seg_surface(GrCourse * course,float x,float y,int segment_cur)311 gr_course_find_seg_surface (GrCourse *course,
312     			    float x, float y,
313 			    int segment_cur)
314 {
315   GrSList *list;
316   GrBoundary *yboundary;
317   GrCSegment *seg;
318   int i, j;
319   GrCSurface *surf;
320   GrVertex v;
321 
322   v.c.x = x;
323   v.c.y = y;
324 
325   seg = course->segs[segment_cur];
326 
327   for (i=100; i>0; i--) {
328     yboundary = (GrBoundary *) gr_boundary_check (seg->boundary, x, &i);
329     if (!yboundary)
330       return NULL;
331 
332     for (j=100; j>0; j--) {
333       list = (GrSList *) gr_boundary_check (yboundary, y, &j);
334 
335       if (!list)
336 	break;
337 
338       while (list) {
339 	surf = (GrCSurface *) list->data;
340 
341 	if (gr_vertex_check_inner_xy (&v, 3, surf->v))
342 	  return surf;
343 
344 	list = list->next;
345       }
346     }
347   }
348 
349   return NULL;
350 }
351 
352 GrCSurface*
gr_course_find_surface(GrCourse * course,float x,float y,int segment_cur,int * segment_ret)353 gr_course_find_surface (GrCourse *course,
354 		        float x, float y,
355 		        int segment_cur,
356 		        int *segment_ret)
357 {
358   GrCSurface *surf;
359   int seg;
360   int i;
361 
362   if (course == NULL)
363     return NULL;
364 
365   surf = gr_course_find_seg_surface (course, x, y, segment_cur);
366   if (surf) {
367     *segment_ret = segment_cur;
368     return surf;
369   }
370   for (i=1; i<course->num_segs/2; i++) {
371     seg = (segment_cur + i) % course->num_segs;
372     surf = gr_course_find_seg_surface (course, x, y, seg);
373     if (surf) {
374       *segment_ret = seg;
375       return surf;
376     }
377     seg = (segment_cur - i) % course->num_segs;
378     surf = gr_course_find_seg_surface (course, x, y, seg);
379     if (surf) {
380       *segment_ret = seg;
381       return surf;
382     }
383   }
384 
385   return NULL;
386 }
387 
388 void
gr_course_write_file(GrCourse * course,FILE * file)389 gr_course_write_file (GrCourse *course, FILE *file)
390 {
391   int i, j;
392   GrControlLine *cline;
393 
394   fputs ("GRACER COURSE/1.0\n", file);
395 
396   fputs ("TITLE ", file);
397   put_name (course->title, file);
398   fputc('\n', file);
399 
400   fputs ("DESC ", file);
401   put_name (course->desc, file);
402   fputc('\n', file);
403 
404   fputs ("MODEL ", file);
405   put_name (course->model, file);
406   fputc('\n', file);
407 
408   fputs ("TIMESTAMP ", file);
409   put_name (course->timestamp, file);
410   fputc('\n', file);
411 
412   fprintf (file, "NUM_GRID %d\n", course->num_grids);
413   for (i=0; i<course->num_grids; i++) {
414     fprintf (file, "GRID %d %d %f %f %f\n",
415 	     course->grids[i].flag,
416 	     course->grids[i].segment,
417 	     course->grids[i].x,
418 	     course->grids[i].y,
419 	     course->grids[i].dir);
420   }
421   fprintf (file, "NUM_CLINE %d\n", course->num_clines);
422   for (i=0; i<course->num_clines; i++) {
423     cline = course->clines + i;
424 
425     fprintf (file, "CLINE %d %d\n", cline->flag, cline->segment);
426     fprintf (file, "%f %f\n", cline->region_a[0].c.x, cline->region_a[0].c.y);
427     fprintf (file, "%f %f\n", cline->region_a[1].c.x, cline->region_a[1].c.y);
428     fprintf (file, "%f %f\n", cline->region_a[3].c.x, cline->region_a[3].c.y);
429     fprintf (file, "%f %f\n", cline->region_a[2].c.x, cline->region_a[2].c.y);
430     fprintf (file, "%f %f\n", cline->region_b[3].c.x, cline->region_b[3].c.y);
431     fprintf (file, "%f %f\n", cline->region_b[2].c.x, cline->region_b[2].c.y);
432   }
433   fprintf (file, "NUM_MAT %d\n", course->num_mats);
434   for (i=0; i<course->num_mats; i++) {
435     fprintf (file, "MAT %d %f %f %f\n",
436 	     course->mats[i].flag,
437 	     course->mats[i].friction,
438 	     course->mats[i].exp,
439 	     course->mats[i].mu);
440   }
441   fprintf (file, "NUM_SEG %d\n", course->num_segs);
442   for (i=0; i<course->num_segs; i++) {
443     fprintf (file, "SEG %d %f %f %f %f %f %f\n",
444 	     course->segs[i]->flag,
445 	     course->segs[i]->max.c.x,
446 	     course->segs[i]->min.c.x,
447 	     course->segs[i]->max.c.y,
448 	     course->segs[i]->min.c.y,
449 	     course->segs[i]->max.c.z,
450 	     course->segs[i]->min.c.z);
451     fprintf (file, "NUM_VERT %d\n", course->segs[i]->num_verts);
452     for (j=0; j<course->segs[i]->num_verts; j++) {
453       fprintf (file, "%f %f %f\n",
454 	       course->segs[i]->verts[j].c.x,
455 	       course->segs[i]->verts[j].c.y,
456 	       course->segs[i]->verts[j].c.z);
457     }
458     fprintf (file, "NUM_SURF %d\n", course->segs[i]->num_surfs);
459     for (j=0; j<course->segs[i]->num_surfs; j++) {
460       fprintf (file, "%d %d %d %d %d\n",
461 	       course->segs[i]->surfs[j].flag,
462 	       course->segs[i]->surfs[j].mat,
463 	       course->segs[i]->surfs[j].p[0],
464 	       course->segs[i]->surfs[j].p[1],
465 	       course->segs[i]->surfs[j].p[2]);
466     }
467   }
468 }
469 
470 static int
find_token(char * data,int * index)471 find_token (char *data, int *index)
472 {
473   int i;
474   int j;
475   char c;
476 
477   i = next_word (data, index);
478 
479   if (data[i] != '\0') {
480     for (j=0; tokens[j].str != NULL; j++) {
481       if (!strncmp (data+i, tokens[j].str, tokens[j].len) &&
482 	  (c = data[i+tokens[j].len],
483 	   c == ' ' || c == '\t' || c == '\n' || c == '\0'))
484       {
485 	i += tokens[j].len;
486 	*index = i;
487 	return tokens[j].type;
488       }
489     }
490   }
491 
492   return TOKEN_INVALID;
493 }
494 
495 static int
next_line(char * data,int * index)496 next_line (char *data, int *index)
497 {
498   int i = *index;
499 
500   for (; data[i] != '\0' && data[i] != '\n'; i++) {}
501   if (data[i] != 0) {
502     i++;
503   }
504   *index = i;
505 
506   return i;
507 }
508 
509 
510 static int
next_word(char * data,int * index)511 next_word (char *data, int *index)
512 {
513   int i = *index;
514 
515   while (data[i] == ' ' || data[i] == '\t' || data[i] == '\n') {
516     i++;
517   }
518 
519   *index = i;
520 
521   return i;
522 }
523 
524 static char *
get_name(char * data,int * index)525 get_name (char *data, int *index)
526 {
527   char *name = NULL;
528   char *tmp;
529   int i = *index;
530   int len;
531 
532   if (data[i] == '"') {
533     i++;
534     tmp = strchr (data+i, '"');
535     len = tmp - (data + i);
536     if (len > 0) {
537       name = gr_new (char, len+1);
538       strncpy (name, data+i, len);
539       name[len] = '\0';
540     }
541     i += len + 1;
542   } else {
543     tmp = strpbrk (data+i, " \t");
544     len = tmp - (data + i);
545     name = gr_new (char, len+1);
546     strncpy (name, data+i, len);
547     name[len] = '\0';
548     i += len;
549   }
550 
551   *index = i;
552   return name;
553 }
554 
555 static GrCSegment *
read_segment(GrCourse * course,char * data,int * i)556 read_segment (GrCourse *course, char *data, int *i)
557 {
558   GrCSegment *seg;
559   int j;
560 
561   seg = gr_new (GrCSegment, 1);
562   memset (seg, 0, sizeof(GrCSegment));
563 
564   sscanf (data+*i, "SEG %d %f %f %f %f %f %f",
565 	  &seg->flag,
566 	  &seg->max.c.x, &seg->min.c.x,
567 	  &seg->max.c.y, &seg->min.c.y,
568 	  &seg->max.c.z, &seg->min.c.z);
569   next_line (data, i);
570 
571   sscanf (data+*i, "NUM_VERT %d", &seg->num_verts);
572   next_line (data, i);
573   seg->verts = gr_new (GrVertex, seg->num_verts);
574   for (j=0; j<seg->num_verts; j++) {
575     sscanf (data+*i, "%f %f %f",
576 	    &seg->verts[j].c.x, &seg->verts[j].c.y, &seg->verts[j].c.z);
577     next_line (data, i);
578   }
579 
580   sscanf (data+*i, "NUM_SURF %d", &seg->num_surfs);
581   next_line (data, i);
582   seg->surfs = gr_new (GrCSurface, seg->num_surfs);
583   for (j=0; j<seg->num_surfs; j++) {
584     sscanf (data+*i, "%d %d %d %d %d",
585 	    &seg->surfs[j].flag,
586 	    &seg->surfs[j].mat,
587 	    &seg->surfs[j].p[0],
588 	    &seg->surfs[j].p[1],
589 	    &seg->surfs[j].p[2]);
590     seg->surfs[j].v[0] = seg->verts[seg->surfs[j].p[0]];
591     seg->surfs[j].v[1] = seg->verts[seg->surfs[j].p[1]];
592     seg->surfs[j].v[2] = seg->verts[seg->surfs[j].p[2]];
593     next_line (data, i);
594   }
595 
596   return seg;
597 }
598 
599 static void
put_name(char * str,FILE * file)600 put_name (char *str, FILE *file)
601 {
602   int i;
603   fputc ('"', file);
604   if (str) {
605     for (i=0; str[i] != '\0'; i++) {
606       if (str[i] == '"' || str[i] == '\\') {
607 	fputc ('\\', file);
608       }
609       fputc (str[i], file);
610     }
611   }
612   fputc ('"', file);
613 }
614 
615 static void
create_boundary(GrCSegment * seg)616 create_boundary (GrCSegment *seg)
617 {
618   int i, j;
619   float val;
620   float xmx, xmn, ymx, ymn, zmx, zmn;
621   GrSList **list;
622   GrBoundary **b;
623 
624   seg->boundary = gr_boundary_new (100, seg->min.c.x - 0.1, seg->max.c.x + 0.1,
625       				   (GrBoundaryDestroyCB) gr_boundary_free);
626   assert (seg->boundary);
627 
628   for (i=0; i<seg->num_surfs; i++) {
629     xmx = xmn = seg->verts[seg->surfs[i].p[0]].c.x;
630     ymx = ymn = seg->verts[seg->surfs[i].p[0]].c.y;
631     zmx = zmn = seg->verts[seg->surfs[i].p[0]].c.z;
632     for (j=1; j<3; j++) {
633       val = seg->verts[seg->surfs[i].p[j]].c.x;
634       if (xmx < val) xmx = val;
635       if (xmn > val) xmn = val;
636 
637       val = seg->verts[seg->surfs[i].p[j]].c.y;
638       if (ymx < val) ymx = val;
639       if (ymn > val) ymn = val;
640 
641       val = seg->verts[seg->surfs[i].p[j]].c.z;
642       if (zmx < val) zmx = val;
643       if (zmn > val) zmn = val;
644     }
645 
646     b = (GrBoundary **) gr_boundary_register (seg->boundary, xmx, xmn);
647     assert (b);
648 
649     if (!(*b)) {
650       *b = gr_boundary_new (100, seg->min.c.y - 0.1, seg->max.c.y + 0.1,
651 	  		    (GrBoundaryDestroyCB) gr_boundary_free);
652       assert (*b);
653     }
654 
655     b = (GrBoundary **) gr_boundary_register (*b, ymx, ymn);
656     assert (b);
657 
658     if (!(*b)) {
659       *b = gr_boundary_new (100, seg->min.c.z - 0.1, seg->max.c.z + 0.1,
660 	  		    (GrBoundaryDestroyCB) gr_slist_free);
661       assert (*b);
662     }
663 
664     list = (GrSList **) gr_boundary_register (*b, zmn, zmx);
665     assert (list);
666 
667     *list = gr_slist_prepend (*list, (void *) i);
668   }
669 }
670 
671 static void
initialize_surface(GrCSegment * seg)672 initialize_surface (GrCSegment *seg)
673 {
674   int i, j;
675   GrVertex v[3], tmp;
676   GrCSurface *surf;
677 
678   for (i=0; i<seg->num_surfs; i++) {
679     surf = seg->surfs + i;
680 
681     v[0] = seg->verts[surf->p[0]];
682     v[1] = seg->verts[surf->p[1]];
683     v[2] = seg->verts[surf->p[2]];
684     gr_plane_init (&surf->plane, v+0, v+1, v+2);
685 
686     for (j=0; j<3; j++) {
687       gr_matrix_mult_vertex (&surf->plane.m, v+j, surf->v+j);
688     }
689     for (j=0; j<3; j++) {
690       gr_vertex_sub (&tmp, surf->v+((j+1) % 3), surf->v+j);
691       gr_vertex_cross (surf->rv+j, gr_vertex_unit_z, &tmp);
692     }
693   }
694 }
695 
696 int
gr_course_check_control_line(GrCourse * course,GrCLineInfo * cinfo)697 gr_course_check_control_line (GrCourse *course, GrCLineInfo *cinfo)
698 {
699   int i, j;
700   GrVertex v;
701   GrControlLine *cline;
702   float product = 0;
703   GrCLineType new_res;
704 
705   if (!course || !cinfo)
706     return 0;
707 
708   new_res = (cinfo->res & GR_CLINE_MASK) >> 2;
709 
710   for (i=0; i<course->num_clines; i++) {
711     if (cinfo->current.pos.c.x < course->clines[i].xmin ||
712 	cinfo->current.pos.c.x > course->clines[i].xmax ||
713 	cinfo->current.pos.c.y < course->clines[i].ymin ||
714 	cinfo->current.pos.c.y > course->clines[i].ymax)
715       continue;
716 
717     cline = course->clines + i;
718 
719     /* CHECK REGION A */
720     for (j=0; j<4; j++) {
721       gr_vertex_sub_xy (&v, &cinfo->current.pos, cline->region_a + j);
722       product = gr_vertex_product_xy (&v, cline->rot_a + j);
723       if (product < 0) {
724 	break;
725       }
726     }
727     if (j == 4) {
728       cinfo->res = new_res | GR_CLINE_CURRENT_A;
729       cinfo->current.cline = i;
730       return 1;
731     }
732 
733     /* CHECK REGION B */
734     for (j=0; j<4; j++) {
735       gr_vertex_sub_xy (&v, &cinfo->current.pos, cline->region_b + j);
736       product = gr_vertex_product_xy (&v, cline->rot_b + j);
737       if (product < 0) {
738 	break;
739       }
740     }
741     if (j == 4) {
742       cinfo->res = new_res | GR_CLINE_CURRENT_B;
743       cinfo->current.cline = i;
744 
745       if (new_res & GR_CLINE_PREV_A) {
746 	/* calc cross ratio */
747 
748 	gr_vertex_sub_xy (&v, &cinfo->prev.pos, cline->region_b);
749 	cinfo->cross_ratio = product
750 		      / (product - gr_vertex_product_xy (&v, cline->rot_b));
751       }
752 
753       return 1;
754     }
755   }
756 
757   cinfo->res = new_res | GR_CLINE_CURRENT_C;
758   return 1;
759 }
760 
761 
762 void
gr_course_foreach_surface(GrCourse * course,GrVertex * center,float r,GrCSurfaceCallback callback,void * data)763 gr_course_foreach_surface (GrCourse *course,
764     			   GrVertex *center,
765 			   float r,
766 			   GrCSurfaceCallback callback,
767 			   void *data)
768 {
769   GrBoundary *xboundary;
770   GrBoundary *yboundary;
771   GrBoundary *zboundary;
772   GrCSegment *segment;
773   int i, j, k, seg, surf;
774   float xmax, xmin;
775   float ymax, ymin;
776   float zmax, zmin;
777   GrSList *ylist = NULL;
778   GrSList *zlist = NULL;
779   GrSList *list = NULL;
780   GrSList *slist = NULL;
781 
782   assert (course);
783   assert (center);
784   assert (callback);
785 
786   xmax = center->c.x + r;
787   xmin = center->c.x - r;
788   ymax = center->c.y + r;
789   ymin = center->c.y - r;
790   zmax = center->c.z + r;
791   zmin = center->c.z - r;
792 
793   for (seg=0; seg<course->num_segs; seg++) {
794     segment = course->segs[seg];
795     if (xmax < segment->min.c.x || xmin > segment->max.c.x ||
796         ymax < segment->min.c.y || ymin > segment->max.c.y ||
797         zmax < segment->min.c.z || zmin > segment->max.c.z) {
798       continue;
799     }
800     xboundary = segment->boundary;
801 
802     for (i=100; i>0; i--) {
803       ylist = gr_boundary_check_region (xboundary, xmin, xmax, &i);
804 
805       while (ylist) {
806 	yboundary = (GrBoundary *) ylist->data;
807 
808 	for (j=100; j>0; j--) {
809 	  zlist = gr_boundary_check_region (yboundary, ymin, ymax, &j);
810 
811 	  while (zlist) {
812 	    zboundary = (GrBoundary *) zlist->data;
813 
814 	    for (k=100; k>0; k--) {
815 	      list = gr_boundary_check_region (zboundary, zmin, zmax, &k);
816 
817 	      while (list) {
818 		slist = list->data;
819 		while (slist) {
820 		  surf = (int) slist->data;
821 
822 		  if ((*callback) (course, seg, surf, data)) {
823 		    goto FINISH;
824 		  }
825 		  slist = slist->next;
826 		}
827 
828 		list = gr_slist_remove (list);
829 	      }
830 	    }
831 	    zlist = gr_slist_remove (zlist);
832 	  }
833 	}
834 	ylist = gr_slist_remove (ylist);
835       }
836     }
837   }
838 
839 FINISH:
840   if (list)
841     gr_slist_free (list);
842   if (ylist)
843     gr_slist_free (ylist);
844   if (zlist)
845     gr_slist_free (zlist);
846 }
847 
848 void
gr_course_foreach_surface_xy(GrCourse * course,GrVertex * pos,GrCSurfaceXYCallback callback,void * data)849 gr_course_foreach_surface_xy (GrCourse *course,
850 			      GrVertex *pos,
851 			      GrCSurfaceXYCallback callback,
852 			      void *data)
853 {
854   GrBoundary *xboundary;
855   GrBoundary *yboundary;
856   GrBoundary *zboundary;
857   GrCSegment *segment;
858   GrCSurface *surface;
859   int i, j, k, seg, surf;
860   GrSList *list = NULL, *slist;
861   GrVertex cross;
862 
863   assert (course);
864   assert (callback);
865 
866   for (seg=0; seg<course->num_segs; seg++) {
867     segment = course->segs[seg];
868     if (pos->c.x < segment->min.c.x || pos->c.x > segment->max.c.x ||
869         pos->c.y < segment->min.c.y || pos->c.y > segment->max.c.y) {
870       continue;
871     }
872     xboundary = segment->boundary;
873 
874     for (i=100; i>0; i--) {
875       yboundary = gr_boundary_check (xboundary, pos->c.x, &i);
876 
877       if (!yboundary)
878 	return;
879 
880       for (j=100; j>0; j--) {
881 	zboundary = gr_boundary_check (yboundary, pos->c.y, &j);
882 
883 	if (!zboundary)
884 	  return;
885 
886 	for (k=100; k>0; k--) {
887 	  list = gr_boundary_check_region (zboundary,
888 					   segment->min.c.z,
889 					   segment->max.c.z, &k);
890 
891 	  while (list) {
892 	    slist = list->data;
893 	    while (slist) {
894 	      surf = (int) slist->data;
895 	      surface = segment->surfs + surf;
896 
897 	      if (gr_plane_get_crossing (&surface->plane, &cross,
898 					 pos, gr_vertex_unit_z) &&
899 	          gr_course_surface_check_inner (surface, &cross)) {
900 		if ((*callback) (course, seg, surf, cross.c.z, data)) {
901 		  goto FINISH;
902 		}
903 	      }
904 	      slist = slist->next;
905 	    }
906 
907 	    list = gr_slist_remove (list);
908 	  }
909 	}
910       }
911     }
912   }
913 
914 FINISH:
915   if (list)
916     gr_slist_free (list);
917 }
918 
919 int
gr_course_surface_check_inner(GrCSurface * surf,GrVertex * p)920 gr_course_surface_check_inner (GrCSurface *surf, GrVertex *p)
921 {
922   int i;
923   GrVertex tmp;
924 
925   for (i=0; i<3; i++) {
926     gr_vertex_sub (&tmp, p, surf->v+i);
927     if (gr_vertex_product_xy (&tmp, surf->rv+i) < -0.05)
928       return 0;
929   }
930 
931   return 1;
932 }
933 
934