GRASS 8 Programmer's Manual 8.6.0dev(2026)-0f6a7341fc
Loading...
Searching...
No Matches
gs_query.c
Go to the documentation of this file.
1/*!
2 \file lib/ogsf/gs_query.c
3
4 \brief OGSF library - query (lower level functions)
5
6 GRASS OpenGL gsurf OGSF Library
7
8 SPDX-FileCopyrightText: 1999-2008 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Bill Brown USACERL (January 1994)
12 \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
13 */
14
15#include <math.h>
16
17#include <grass/gis.h>
18#include <grass/ogsf.h>
19
20/*!
21 \brief Values needed for Ray-Convex Polyhedron Intersection Test below
22 originally by Eric Haines, erich@eye.com
23 */
24#ifndef HUGE_VAL
25#define HUGE_VAL 1.7976931348623157e+308
26#endif
27
28/* return codes */
29#define MISSED 0
30#define FRONTFACE 1
31#define BACKFACE -1
32/* end Ray-Convex Polyhedron Intersection Test values */
33
34/*!
35 \brief Crude method of intersecting line of sight with closest part of
36 surface.
37
38 Uses los vector to determine the point of first intersection
39 which is returned in point. Returns 0 if los doesn't intersect.
40
41 \param surfid surface id
42 \param los should be in surf-world coordinates
43 \param[out] point intersect point (real)
44
45 \return 0 on failure
46 \return 1 on success
47 */
48int gs_los_intersect1(int surfid, float (*los)[3], float *point)
49{
50 float dx, dy, dz, u_d[3];
51 float a[3], incr, min_incr, tlen, len;
52 int outside, above, below, edge, istep;
53 float b[3];
54 geosurf *gs;
55 typbuff *buf;
56
57 G_debug(3, "gs_los_intersect1():");
58
59 if (NULL == (gs = gs_get_surf(surfid))) {
60 return (0);
61 }
62
63 if (0 == GS_v3dir(los[FROM], los[TO], u_d)) {
64 return (0);
65 }
66
68
69 istep = edge = below = 0;
70
71 len = 0.0;
72 tlen = GS_distance(los[FROM], los[TO]);
73
74 incr = tlen / 1000.0;
75 min_incr = incr / 1000.0;
76
77 dx = incr * u_d[X];
78 dy = incr * u_d[Y];
79 dz = incr * u_d[Z];
80
81 a[X] = los[FROM][X];
82 a[Y] = los[FROM][Y];
83 a[Z] = los[FROM][Z];
84
85 b[X] = a[X] - gs->x_trans;
86 b[Y] = a[Y] - gs->y_trans;
87
88 if (viewcell_tri_interp(gs, buf, b, 0)) {
89 /* expects surface coords */
90 b[Z] += gs->z_trans;
91
92 if (a[Z] < b[Z]) {
93 /* viewing from below surface */
94 /* don't use this method
95 fprintf(stderr,"view from below\n");
96 below = 1;
97 */
98
99 return (0);
100 }
101 }
102
103 while (incr > min_incr) {
104 outside = 0;
105 above = 0;
106 b[X] = a[X] - gs->x_trans;
107 b[Y] = a[Y] - gs->y_trans;
108
109 if (viewcell_tri_interp(gs, buf, b, 0)) {
110 /* ignores masks */
111 b[Z] += gs->z_trans;
112 above = (a[Z] > b[Z]);
113 }
114 else {
115 outside = 1;
116
117 if (istep > 10) {
118 edge = 1;
119 below = 1;
120 }
121 }
122
123 while (outside || above) {
124 a[X] += dx;
125 a[Y] += dy;
126 a[Z] += dz;
127 len += incr;
128 outside = 0;
129 above = 0;
130 b[X] = a[X] - gs->x_trans;
131 b[Y] = a[Y] - gs->y_trans;
132
133 if (viewcell_tri_interp(gs, buf, b, 0)) {
134 b[Z] += gs->z_trans;
135 above = (a[Z] > b[Z]);
136 }
137 else {
138 outside = 1;
139 }
140
141 if (len > tlen) {
142 return 0; /* over surface */ /* under surface */
143 }
144 }
145
146 /* could look for spikes here - see if any data points along
147 shadow of line on surf go above los */
148
149 /* back up several spots? */
150 a[X] -= (1.0 * dx);
151 a[Y] -= (1.0 * dy);
152 a[Z] -= (1.0 * dz);
153 incr /= 2.0;
154 ++istep;
155 dx = incr * u_d[X];
156 dy = incr * u_d[Y];
157 dz = incr * u_d[Z];
158 }
159
160 if ((edge) && (b[Z] - (a[Z] + dz * 2.0) > incr * u_d[Z])) {
161 G_debug(3, " looking under surface");
162
163 return 0;
164 }
165
166 point[X] = b[X];
167 point[Y] = b[Y];
168 point[Z] = b[Z] - gs->z_trans;
169
170 return (1);
171}
172
173/*!
174 \brief Crude method of intersecting line of sight with closest part of
175 surface.
176
177 This version uses the shadow of the los projected down to
178 the surface to generate a line_on_surf, then follows each
179 point in that line until the los intersects it.
180
181 \param surfid surface id
182 \param los should be in surf-world coordinates
183 \param[out] point intersect point (real)
184
185 \return 0 on failure
186 \return 1 on success
187 */
188int gs_los_intersect(int surfid, float **los, float *point)
189{
190 double incr;
191 float p1, p2, u_d[3];
192 int above, ret, num, i, usedx;
193 float a[3], b[3];
194 float bgn[3], end[3], a1[3];
195 geosurf *gs;
196 typbuff *buf;
197 Point3 *points;
198
199 G_debug(3, "gs_los_intersect");
200
201 if (NULL == (gs = gs_get_surf(surfid))) {
202 return (0);
203 }
204
205 if (0 == GS_v3dir(los[FROM], los[TO], u_d)) {
206 return (0);
207 }
208
209 buf = gs_get_att_typbuff(gs, ATT_TOPO, 0);
210
211 GS_v3eq(bgn, los[FROM]);
212 GS_v3eq(end, los[TO]);
213
214 bgn[X] -= gs->x_trans;
215 bgn[Y] -= gs->y_trans;
216
217 end[X] -= gs->x_trans;
218 end[Y] -= gs->y_trans;
219
220 /* trans? */
221 points = gsdrape_get_allsegments(gs, bgn, end, &num);
222
223 /* DEBUG
224 {
225 float t1[3], t2[3];
226
227 t1[X] = los[FROM][X] ;
228 t1[Y] = los[FROM][Y] ;
229
230 t2[X] = los[TO][X] ;
231 t2[Y] = los[TO][Y] ;
232
233 GS_set_draw(GSD_FRONT);
234 gsd_pushmatrix();
235 gsd_do_scale(1);
236 gsd_translate(gs->x_trans, gs->y_trans, gs->z_trans);
237 gsd_linewidth(1);
238 gsd_color_func(GS_default_draw_color());
239 gsd_line_onsurf(gs, t1, t2);
240 gsd_popmatrix();
241 GS_set_draw(GSD_BACK);
242 gsd_flush();
243 }
244 fprintf(stderr,"%d points to check\n", num);
245 fprintf(stderr,"point0 = %.6lf %.6lf %.6lf FT =%.6lf %.6lf %.6lf\n",
246 points[0][X],points[0][Y],points[0][Z],
247 los[FROM][X],los[FROM][Y],los[FROM][Z]);
248 fprintf(stderr,"incr1 = %.6lf: %.6lf %.6lf
249 %.6lf\n",incr,u_d[X],u_d[Y],u_d[Z]); fprintf(stderr,"first point below
250 surf\n"); fprintf(stderr,"incr2 = %f\n", (float)incr);
251 fprintf(stderr,"(%d/%d) %f > %f\n", i,num, a[Z], points[i][Z]);
252 fprintf(stderr,"incr3 = %f\n", (float)incr);
253 fprintf(stderr,"all points above surf\n");
254 */
255
256 if (num < 2) {
257 G_debug(3, " %d points to check", num);
258
259 return (0);
260 }
261
262 /* use larger of deltas for better precision */
263 usedx = (fabs(u_d[X]) > fabs(u_d[Y]));
264 if (usedx) {
265 incr = ((points[0][X] - (los[FROM][X] - gs->x_trans)) / u_d[X]);
266 }
267 else if (u_d[Y]) {
268 incr = ((points[0][Y] - (los[FROM][Y] - gs->y_trans)) / u_d[Y]);
269 }
270 else {
271 point[X] = los[FROM][X] - gs->x_trans;
272 point[Y] = los[FROM][Y] - gs->y_trans;
273
274 return (viewcell_tri_interp(gs, buf, point, 1));
275 }
276
277 /* DEBUG
278 fprintf(stderr,"-----------------------------\n");
279 fprintf(stderr,"%d points to check\n", num);
280 fprintf(stderr,"incr1 = %.6lf: %.9f %.9f
281 %.9f\n",incr,u_d[X],u_d[Y],u_d[Z]); fprintf(stderr,
282 "\tpoint0 = %.6f %.6f %.6f\n\tFT = %.6f %.6f %.6f\n\tpoint%d = %.6f
283 %.6f\n", points[0][X],points[0][Y],points[0][Z],
284 los[FROM][X],los[FROM][Y],los[FROM][Z],
285 num-1, points[num-1][X],points[num-1][Y]);
286 */
287
288 /* This should bring us right above (or below) the first point */
289 a[X] = los[FROM][X] + incr * u_d[X] - gs->x_trans;
290 a[Y] = los[FROM][Y] + incr * u_d[Y] - gs->y_trans;
291 a[Z] = los[FROM][Z] + incr * u_d[Z] - gs->z_trans;
292
293 if (a[Z] < points[0][Z]) {
294 /* viewing from below surface */
295 /* don't use this method */
296 /* DEBUG
297 fprintf(stderr,"first point below surf\n");
298 fprintf(stderr,"aZ= %.6f point0 = %.6f %.6f %.6f FT =%.6f %.6f
299 %.6f\n", a[Z], points[0][X],points[0][Y],points[0][Z],
300 los[FROM][X],los[FROM][Y],los[FROM][Z]);
301 */
302 return (0);
303 }
304
305 GS_v3eq(a1, a);
306 GS_v3eq(b, a);
307
308 for (i = 1; i < num; i++) {
309 if (usedx) {
310 incr = ((points[i][X] - a1[X]) / u_d[X]);
311 }
312 else {
313 incr = ((points[i][Y] - a1[Y]) / u_d[Y]);
314 }
315
316 a[X] = a1[X] + (incr * u_d[X]);
317 a[Y] = a1[Y] + (incr * u_d[Y]);
318 a[Z] = a1[Z] + (incr * u_d[Z]);
319 above = (a[Z] >= points[i][Z]);
320
321 if (above) {
322 GS_v3eq(b, a);
323 continue;
324 }
325
326 /*
327 * Now we know b[Z] is above points[i-1]
328 * and a[Z] is below points[i]
329 * Since there should only be one polygon along this seg,
330 * just interpolate to intersect
331 */
332
333 if (usedx) {
334 incr = ((a[X] - b[X]) / u_d[X]);
335 }
336 else {
337 incr = ((a[Y] - b[Y]) / u_d[Y]);
338 }
339
340 if (1 == (ret = segs_intersect(1.0, points[i][Z], 0.0, points[i - 1][Z],
341 1.0, a[Z], 0.0, b[Z], &p1, &p2))) {
342 point[X] = points[i - 1][X] + (u_d[X] * incr * p1);
343 point[Y] = points[i - 1][Y] + (u_d[Y] * incr * p1);
344 point[Z] = p2;
345
346 return (1);
347 }
348
349 G_debug(3, " line of sight error %d", ret);
350
351 return 0;
352 }
353
354 /* over surface */
355 return 0;
356}
357
358/*!
359 \brief Ray-Convex Polyhedron Intersection Test
360
361 Originally by Eric Haines, erich@eye.com
362
363 This test checks the ray against each face of a polyhedron, checking whether
364 the set of intersection points found for each ray-plane intersection
365 overlaps the previous intersection results. If there is no overlap (i.e.
366 no line segment along the ray that is inside the polyhedron), then the
367 ray misses and returns 0; else 1 is returned if the ray is entering the
368 polyhedron, -1 if the ray originates inside the polyhedron. If there is
369 an intersection, the distance and the number of the face hit is returned.
370
371 \param org,dir origin and direction of ray
372 \param tmax maximum useful distance along ray
373 \param phdrn list of planes in convex polyhedron
374 \param ph_num number of planes in convex polyhedron
375 \param[out] tresult distance of intersection along ray
376 \param[out] pn number of face hit (0 to ph_num-1)
377
378 \return FACE code
379 */
381 int ph_num, double *tresult, int *pn)
382{
383 double tnear, tfar, t, vn, vd;
384 int fnorm_num, bnorm_num; /* front/back face # hit */
385
386 tnear = -HUGE_VAL;
387 tfar = tmax;
388
389 /* Test each plane in polyhedron */
390 for (; ph_num--;) {
391 /* Compute intersection point T and sidedness */
392 vd = DOT3(dir, phdrn[ph_num]);
393 vn = DOT3(org, phdrn[ph_num]) + phdrn[ph_num][W];
394
395 if (vd == 0.0) {
396 /* ray is parallel to plane - check if ray origin is inside plane's
397 half-space */
398 if (vn > 0.0) {
399 /* ray origin is outside half-space */
400 return (MISSED);
401 }
402 }
403 else {
404 /* ray not parallel - get distance to plane */
405 t = -vn / vd;
406
407 if (vd < 0.0) {
408 /* front face - T is a near point */
409 if (t > tfar) {
410 return (MISSED);
411 }
412
413 if (t > tnear) {
414 /* hit near face, update normal */
416 tnear = t;
417 }
418 }
419 else {
420 /* back face - T is a far point */
421 if (t < tnear) {
422 return (MISSED);
423 }
424
425 if (t < tfar) {
426 /* hit far face, update normal */
428 tfar = t;
429 }
430 }
431 }
432 }
433
434 /* survived all tests */
435 /* Note: if ray originates on polyhedron, may want to change 0.0 to some
436 * epsilon to avoid intersecting the originating face.
437 */
438 if (tnear >= 0.0) {
439 /* outside, hitting front face */
440 *tresult = tnear;
441 *pn = fnorm_num;
442
443 return (FRONTFACE);
444 }
445 else {
446 if (tfar < tmax) {
447 /* inside, hitting back face */
448 *tresult = tfar;
449 *pn = bnorm_num;
450
451 return (BACKFACE);
452 }
453 else {
454 /* inside, but back face beyond tmax */
455 return (MISSED);
456 }
457 }
458}
459
460/*!
461 \brief Get data bounds for plane
462
463 \param[out] planes
464 */
466{
467 float n, s, w, e, b, t;
469
470 GS_get_zrange(&b, &t, 0);
471 gs_get_xrange(&w, &e);
472 gs_get_yrange(&s, &n);
473
474 tlfront[X] = tlfront[Y] = 0.0;
475 tlfront[Z] = t;
476
477 brback[X] = e - w;
478 brback[Y] = n - s;
479 brback[Z] = b;
480
481 /* top */
482 planes[0][X] = planes[0][Y] = 0.0;
483 planes[0][Z] = 1.0;
484 planes[0][W] = -(DOT3(planes[0], tlfront));
485
486 /* bottom */
487 planes[1][X] = planes[1][Y] = 0.0;
488 planes[1][Z] = -1.0;
489 planes[1][W] = -(DOT3(planes[1], brback));
490
491 /* left */
492 planes[2][Y] = planes[2][Z] = 0.0;
493 planes[2][X] = -1.0;
494 planes[2][W] = -(DOT3(planes[2], tlfront));
495
496 /* right */
497 planes[3][Y] = planes[3][Z] = 0.0;
498 planes[3][X] = 1.0;
499 planes[3][W] = -(DOT3(planes[3], brback));
500
501 /* front */
502 planes[4][X] = planes[4][Z] = 0.0;
503 planes[4][Y] = -1.0;
504 planes[4][W] = -(DOT3(planes[4], tlfront));
505
506 /* back */
507 planes[5][X] = planes[5][Z] = 0.0;
508 planes[5][Y] = 1.0;
509 planes[5][W] = -(DOT3(planes[5], brback));
510
511 return;
512}
513
514/*!
515 Gets all current cutting planes & data bounding planes
516
517 Intersects los with resulting convex polyhedron, then replaces los[FROM] with
518 first point on ray inside data.
519
520 \param[out] los
521
522 \return 0 on failure
523 \return 1 on success
524 */
526{
527 Point4 planes[12]; /* MAX_CPLANES + 6 - should define this */
528 Point3 dir;
529 double dist, maxdist;
530 int num, ret, retp; /* might want to tell if retp is a clipping plane */
531
533 num = gsd_get_cplanes(planes + 6);
534 GS_v3dir(los[FROM], los[TO], dir);
536
537 ret = RayCvxPolyhedronInt(los[0], dir, maxdist, planes, num + 6, &dist,
538 &retp);
539
540 if (ret == MISSED) {
541 return (0);
542 }
543
544 if (ret == FRONTFACE) {
545 GS_v3mult(dir, (float)dist);
546 GS_v3add(los[FROM], dir);
547 }
548
549 return (1);
550}
551
552/***********************************************************************/
553/* DEBUG ****
554 void pr_plane(int pnum)
555 {
556 switch(pnum)
557 {
558 case 0:
559 fprintf(stderr,"top plane");
560
561 break;
562 case 1:
563 fprintf(stderr,"bottom plane");
564
565 break;
566 case 2:
567 fprintf(stderr,"left plane");
568
569 break;
570 case 3:
571 fprintf(stderr,"right plane");
572
573 break;
574 case 4:
575 fprintf(stderr,"front plane");
576
577 break;
578 case 5:
579 fprintf(stderr,"back plane");
580
581 break;
582 default:
583 fprintf(stderr,"clipping plane %d", 6 - pnum);
584
585 break;
586 }
587
588 return;
589 }
590 ******* */
#define NULL
Definition ccmath.h:32
int G_debug(int, const char *,...) __attribute__((format(printf
void GS_v3mult(float *, float)
Multiple vectors.
Definition gs_util.c:225
Point3 * gsdrape_get_allsegments(geosurf *, float *, float *, int *)
Get all segments.
Definition gsdrape.c:396
int gs_get_yrange(float *, float *)
Get y-range.
Definition gs.c:1158
int GS_get_zrange(float *, float *, int)
Get z-extent for all loaded surfaces.
Definition gs2.c:2684
int gsd_get_cplanes(Point4 *)
Get cplaces.
Definition gsd_cplane.c:158
void GS_v3add(float *, float *)
Sum vectors.
Definition gs_util.c:191
geosurf * gs_get_surf(int)
Get geosurf struct.
Definition gs.c:59
int segs_intersect(float, float, float, float, float, float, float, float, float *, float *)
Line intersect.
Definition gsdrape.c:1206
void GS_v3eq(float *, float *)
Copy vector values.
Definition gs_util.c:174
int gs_get_xrange(float *, float *)
Get x-range.
Definition gs.c:1120
int viewcell_tri_interp(geosurf *, typbuff *, Point3, int)
ADD.
Definition gsdrape.c:505
typbuff * gs_get_att_typbuff(geosurf *, int, int)
Get attribute data buffer.
Definition gs.c:677
int GS_v3dir(float *, float *, float *)
Get a normalized direction from v1 to v2, store in v3.
Definition gs_util.c:347
float GS_distance(float *, float *)
Calculate distance.
Definition gs_util.c:137
void gs_get_databounds_planes(Point4 *planes)
Get data bounds for plane.
Definition gs_query.c:465
#define BACKFACE
Definition gs_query.c:31
#define MISSED
Definition gs_query.c:29
int gs_los_intersect1(int surfid, float(*los)[3], float *point)
Crude method of intersecting line of sight with closest part of surface.
Definition gs_query.c:48
#define FRONTFACE
Definition gs_query.c:30
int gs_setlos_enterdata(Point3 *los)
Definition gs_query.c:525
int gs_los_intersect(int surfid, float **los, float *point)
Crude method of intersecting line of sight with closest part of surface.
Definition gs_query.c:188
#define HUGE_VAL
Values needed for Ray-Convex Polyhedron Intersection Test below originally by Eric Haines,...
Definition gs_query.c:25
int RayCvxPolyhedronInt(Point3 org, Point3 dir, double tmax, Point4 *phdrn, int ph_num, double *tresult, int *pn)
Ray-Convex Polyhedron Intersection Test.
Definition gs_query.c:380
OGSF header file (structures)
#define X
Definition ogsf.h:141
#define ATT_TOPO
Definition ogsf.h:76
float Point3[3]
Definition ogsf.h:206
#define Z
Definition ogsf.h:143
#define W
Definition ogsf.h:144
#define Y
Definition ogsf.h:142
#define FROM
Definition ogsf.h:145
float Point4[4]
Definition ogsf.h:205
#define DOT3(a, b)
Definition ogsf.h:181
#define TO
Definition ogsf.h:146
double b
Definition r_raster.c:37
double t
Definition r_raster.c:37
Definition ogsf.h:267