/*! \brief Check if point is masked \param gs pointer to geosurf struct \param pt point coordinates (X,Y,Z) \return 1 masked \return 0 not masked */ int gs_point_is_masked(geosurf * gs, float *pt) { int vrow, vcol, drow, dcol; int retmask = 0, npts = 0; float p2[2]; if (!gs->curmask) { return (0); } vrow = Y2VROW(gs, pt[Y]); vcol = X2VCOL(gs, pt[X]); /* check right & bottom edges */ if (pt[X] == VCOL2X(gs, VCOLS(gs))) { /* right edge */ vcol -= 1; } if (pt[Y] == VROW2Y(gs, VROWS(gs))) { /* bottom edge */ vrow -= 1; } drow = VROW2DROW(gs, vrow); dcol = VCOL2DCOL(gs, vcol); if (BM_get(gs->curmask, dcol, drow)) { retmask |= MASK_TL; npts++; } dcol = VCOL2DCOL(gs, vcol + 1); if (BM_get(gs->curmask, dcol, drow)) { retmask |= MASK_TR; npts++; } drow = VROW2DROW(gs, vrow + 1); if (BM_get(gs->curmask, dcol, drow)) { retmask |= MASK_BR; npts++; } dcol = VCOL2DCOL(gs, vcol); if (BM_get(gs->curmask, dcol, drow)) { retmask |= MASK_BL; npts++; } if (npts != 1) { /* zero or masked */ return (retmask | npts); } p2[X] = VCOL2X(gs, vcol); p2[Y] = VROW2Y(gs, vrow + 1); switch (retmask) { case MASK_TL: if ((pt[X] - p2[X]) / VXRES(gs) > (pt[Y] - p2[Y]) / VYRES(gs)) { /* lower triangle */ return (0); } return (retmask | npts); case MASK_TR: return (retmask | npts); case MASK_BR: if ((pt[X] - p2[X]) / VXRES(gs) <= (pt[Y] - p2[Y]) / VYRES(gs)) { /* upper triangle */ return (0); } return (retmask | npts); case MASK_BL: return (retmask | npts); } /* Assume that if we get here it is an error */ return (0); }
/*! \brief Get horizontal intersects \param gs surface (geosurf) \param bgn begin point \param end end point \param dir \return number of intersects */ int get_horz_intersects(geosurf * gs, float *bgn, float *end, float *dir) { int frow, lrow, incr, hits, num, offset, dcol1, dcol2; float xl, yb, xr, yt, z1, z2, alpha; float xres, yres, xi, yi; int bgnrow, endrow, rows, cols; xres = VXRES(gs); yres = VYRES(gs); cols = VCOLS(gs); rows = VROWS(gs); bgnrow = Y2VROW(gs, bgn[Y]); endrow = Y2VROW(gs, end[Y]); if (bgnrow == endrow) { return 0; } if (bgnrow > rows && endrow > rows) { return 0; } frow = dir[Y] > 0 ? bgnrow : bgnrow + 1; lrow = dir[Y] > 0 ? endrow + 1 : endrow; /* assuming only showing FULL rows */ incr = lrow - frow > 0 ? 1 : -1; while (frow > rows || frow < 0) { frow += incr; } while (lrow > rows || lrow < 0) { lrow -= incr; } num = abs(lrow - frow) + 1; xl = 0.0 - EPSILON; xr = xres * cols + EPSILON; for (hits = 0; hits < num; hits++) { yb = yt = VROW2Y(gs, frow); if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yb, &xi, &yi)) { Hi[hits][X] = xi; Hi[hits][Y] = yi; /* find data cols */ if (Flat) { Hi[hits][Z] = gs->att[ATT_TOPO].constant; } else { dcol1 = X2VCOL(gs, Hi[hits][X]) * gs->x_mod; dcol2 = (1 + X2VCOL(gs, Hi[hits][X])) * gs->x_mod; if (dcol2 >= gs->cols) { dcol2 = gs->cols - 1; /* right edge */ } alpha = (Hi[hits][X] - (dcol1 * gs->xres)) / xres; offset = DRC2OFF(gs, frow * gs->y_mod, dcol1); GET_MAPATT(Ebuf, offset, z1); offset = DRC2OFF(gs, frow * gs->y_mod, dcol2); GET_MAPATT(Ebuf, offset, z2); Hi[hits][Z] = LERP(alpha, z1, z2); } } /* if they don't intersect, something's wrong! */ /* should only happen on endpoint, so it will be added later */ else { hits--; num--; } frow += incr; } return (hits); }
/*! \brief ADD In gsd_surf, tmesh draws polys like so: <pre> -------------- | /| | / | | / | | / | | / | | / | | / | | / | | / | | / | | / | |/ | -------------- </pre> UNLESS the top right or bottom left point is masked, in which case a single triangle with the opposite diagonal is drawn. This case is not yet handled here & should only occur on edges. pt has X & Y coordinates in it, we interpolate Z here This could probably be much shorter, but not much faster. \return 1 if point is in view region \return otherwise 0 (if masked) */ int viewcell_tri_interp(geosurf * gs, typbuff * buf, Point3 pt, int check_mask) { Point3 p1, p2, p3; int offset, drow, dcol, vrow, vcol; float xmax, ymin, ymax, alpha; xmax = VCOL2X(gs, VCOLS(gs)); ymax = VROW2Y(gs, 0); ymin = VROW2Y(gs, VROWS(gs)); if (check_mask) { if (gs_point_is_masked(gs, pt)) { return (0); } } if (pt[X] < 0.0 || pt[Y] > ymax) { /* outside on left or top */ return (0); } if (pt[Y] < ymin || pt[X] > xmax) { /* outside on bottom or right */ return (0); } if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) { pt[Z] = gs->att[ATT_TOPO].constant; return (1); } else if (MAP_ATT != gs_get_att_src(gs, ATT_TOPO)) { return (0); } vrow = Y2VROW(gs, pt[Y]); vcol = X2VCOL(gs, pt[X]); if (vrow < VROWS(gs) && vcol < VCOLS(gs)) { /*not on bottom or right edge */ if (pt[X] > 0.0 && pt[Y] < ymax) { /* not on left or top edge */ p1[X] = VCOL2X(gs, vcol + 1); p1[Y] = VROW2Y(gs, vrow); drow = VROW2DROW(gs, vrow); dcol = VCOL2DCOL(gs, vcol + 1); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p1[Z]); /* top right */ p2[X] = VCOL2X(gs, vcol); p2[Y] = VROW2Y(gs, vrow + 1); drow = VROW2DROW(gs, vrow + 1); dcol = VCOL2DCOL(gs, vcol); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p2[Z]); /* bottom left */ if ((pt[X] - p2[X]) / VXRES(gs) > (pt[Y] - p2[Y]) / VYRES(gs)) { /* lower triangle */ p3[X] = VCOL2X(gs, vcol + 1); p3[Y] = VROW2Y(gs, vrow + 1); drow = VROW2DROW(gs, vrow + 1); dcol = VCOL2DCOL(gs, vcol + 1); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p3[Z]); /* bottom right */ } else { /* upper triangle */ p3[X] = VCOL2X(gs, vcol); p3[Y] = VROW2Y(gs, vrow); drow = VROW2DROW(gs, vrow); dcol = VCOL2DCOL(gs, vcol); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p3[Z]); /* top left */ } return (Point_on_plane(p1, p2, p3, pt)); } else if (pt[X] == 0.0) { /* on left edge */ if (pt[Y] < ymax) { vrow = Y2VROW(gs, pt[Y]); drow = VROW2DROW(gs, vrow); offset = DRC2OFF(gs, drow, 0); GET_MAPATT(buf, offset, p1[Z]); drow = VROW2DROW(gs, vrow + 1); offset = DRC2OFF(gs, drow, 0); GET_MAPATT(buf, offset, p2[Z]); alpha = (VROW2Y(gs, vrow) - pt[Y]) / VYRES(gs); pt[Z] = LERP(alpha, p1[Z], p2[Z]); } else { /* top left corner */ GET_MAPATT(buf, 0, pt[Z]); } return (1); } else if (pt[Y] == gs->yrange) { /* on top edge, not a corner */ vcol = X2VCOL(gs, pt[X]); dcol = VCOL2DCOL(gs, vcol); GET_MAPATT(buf, dcol, p1[Z]); dcol = VCOL2DCOL(gs, vcol + 1); GET_MAPATT(buf, dcol, p2[Z]); alpha = (pt[X] - VCOL2X(gs, vcol)) / VXRES(gs); pt[Z] = LERP(alpha, p1[Z], p2[Z]); return (1); } } else if (vrow == VROWS(gs)) { /* on bottom edge */ drow = VROW2DROW(gs, VROWS(gs)); if (pt[X] > 0.0 && pt[X] < xmax) { /* not a corner */ vcol = X2VCOL(gs, pt[X]); dcol = VCOL2DCOL(gs, vcol); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p1[Z]); dcol = VCOL2DCOL(gs, vcol + 1); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p2[Z]); alpha = (pt[X] - VCOL2X(gs, vcol)) / VXRES(gs); pt[Z] = LERP(alpha, p1[Z], p2[Z]); return (1); } else if (pt[X] == 0.0) { /* bottom left corner */ offset = DRC2OFF(gs, drow, 0); GET_MAPATT(buf, offset, pt[Z]); return (1); } else { /* bottom right corner */ dcol = VCOL2DCOL(gs, VCOLS(gs)); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, pt[Z]); return (1); } } else { /* on right edge, not bottom corner */ dcol = VCOL2DCOL(gs, VCOLS(gs)); if (pt[Y] < ymax) { vrow = Y2VROW(gs, pt[Y]); drow = VROW2DROW(gs, vrow); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p1[Z]); drow = VROW2DROW(gs, vrow + 1); offset = DRC2OFF(gs, drow, dcol); GET_MAPATT(buf, offset, p2[Z]); alpha = (VROW2Y(gs, vrow) - pt[Y]) / VYRES(gs); pt[Z] = LERP(alpha, p1[Z], p2[Z]); return (1); } else { /* top right corner */ GET_MAPATT(buf, dcol, pt[Z]); return (1); } } return (0); }
/*! \brief ADD \todo For consistancy, need to decide how last row & last column are displayed - would it look funny to always draw last row/col with finer resolution if necessary, or would it be better to only show full rows/cols? Colinear already eliminated \param gs surface (geosurf) \param bgn begin point \param end end point \param dir direction \return */ int get_vert_intersects(geosurf * gs, float *bgn, float *end, float *dir) { int fcol, lcol, incr, hits, num, offset, drow1, drow2; float xl, yb, xr, yt, z1, z2, alpha; float xres, yres, xi, yi; int bgncol, endcol, cols, rows; xres = VXRES(gs); yres = VYRES(gs); cols = VCOLS(gs); rows = VROWS(gs); bgncol = X2VCOL(gs, bgn[X]); endcol = X2VCOL(gs, end[X]); if (bgncol > cols && endcol > cols) { return 0; } if (bgncol == endcol) { return 0; } fcol = dir[X] > 0 ? bgncol + 1 : bgncol; lcol = dir[X] > 0 ? endcol : endcol + 1; /* assuming only showing FULL cols */ incr = lcol - fcol > 0 ? 1 : -1; while (fcol > cols || fcol < 0) { fcol += incr; } while (lcol > cols || lcol < 0) { lcol -= incr; } num = abs(lcol - fcol) + 1; yb = gs->yrange - (yres * rows) - EPSILON; yt = gs->yrange + EPSILON; for (hits = 0; hits < num; hits++) { xl = xr = VCOL2X(gs, fcol); if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yt, xr, yb, &xi, &yi)) { Vi[hits][X] = xi; Vi[hits][Y] = yi; /* find data rows */ if (Flat) { Vi[hits][Z] = gs->att[ATT_TOPO].constant; } else { drow1 = Y2VROW(gs, Vi[hits][Y]) * gs->y_mod; drow2 = (1 + Y2VROW(gs, Vi[hits][Y])) * gs->y_mod; if (drow2 >= gs->rows) { drow2 = gs->rows - 1; /*bottom edge */ } alpha = ((gs->yrange - drow1 * gs->yres) - Vi[hits][Y]) / yres; offset = DRC2OFF(gs, drow1, fcol * gs->x_mod); GET_MAPATT(Ebuf, offset, z1); offset = DRC2OFF(gs, drow2, fcol * gs->x_mod); GET_MAPATT(Ebuf, offset, z2); Vi[hits][Z] = LERP(alpha, z1, z2); } } /* if they don't intersect, something's wrong! */ /* should only happen on endpoint, so it will be added later */ else { hits--; num--; } fcol += incr; } return (hits); }
/*! \brief Get diagonal intersects Colinear already eliminated \param gs surface (geosurf) \param bgn begin point \param end end point \param dir ? (unused) \return number of intersects */ int get_diag_intersects(geosurf * gs, float *bgn, float *end, float *dir) { int fdig, ldig, incr, hits, num, offset; int vrow, vcol, drow1, drow2, dcol1, dcol2; float xl, yb, xr, yt, z1, z2, alpha; float xres, yres, xi, yi, dx, dy; int diags, cols, rows, lower; Point3 pt; xres = VXRES(gs); yres = VYRES(gs); cols = VCOLS(gs); rows = VROWS(gs); diags = rows + cols; /* -1 ? */ /* determine upper/lower triangle for last */ vrow = Y2VROW(gs, end[Y]); vcol = X2VCOL(gs, end[X]); pt[X] = VCOL2X(gs, vcol); pt[Y] = VROW2Y(gs, vrow + 1); lower = ((end[X] - pt[X]) / xres > (end[Y] - pt[Y]) / yres); ldig = lower ? vrow + vcol + 1 : vrow + vcol; /* determine upper/lower triangle for first */ vrow = Y2VROW(gs, bgn[Y]); vcol = X2VCOL(gs, bgn[X]); pt[X] = VCOL2X(gs, vcol); pt[Y] = VROW2Y(gs, vrow + 1); lower = ((bgn[X] - pt[X]) / xres > (bgn[Y] - pt[Y]) / yres); fdig = lower ? vrow + vcol + 1 : vrow + vcol; /* adjust according to direction */ if (ldig > fdig) { fdig++; } if (fdig > ldig) { ldig++; } incr = ldig - fdig > 0 ? 1 : -1; while (fdig > diags || fdig < 0) { fdig += incr; } while (ldig > diags || ldig < 0) { ldig -= incr; } num = abs(ldig - fdig) + 1; for (hits = 0; hits < num; hits++) { yb = gs->yrange - (yres * (fdig < rows ? fdig : rows)) - EPSILON; xl = VCOL2X(gs, (fdig < rows ? 0 : fdig - rows)) - EPSILON; yt = gs->yrange - (yres * (fdig < cols ? 0 : fdig - cols)) + EPSILON; xr = VCOL2X(gs, (fdig < cols ? fdig : cols)) + EPSILON; if (segs_intersect(bgn[X], bgn[Y], end[X], end[Y], xl, yb, xr, yt, &xi, &yi)) { Di[hits][X] = xi; Di[hits][Y] = yi; if (ISNODE(xi, xres)) { /* then it's also a ynode */ num--; hits--; continue; } /* find data rows */ drow1 = Y2VROW(gs, Di[hits][Y]) * gs->y_mod; drow2 = (1 + Y2VROW(gs, Di[hits][Y])) * gs->y_mod; if (drow2 >= gs->rows) { drow2 = gs->rows - 1; /* bottom edge */ } /* find data cols */ if (Flat) { Di[hits][Z] = gs->att[ATT_TOPO].constant; } else { dcol1 = X2VCOL(gs, Di[hits][X]) * gs->x_mod; dcol2 = (1 + X2VCOL(gs, Di[hits][X])) * gs->x_mod; if (dcol2 >= gs->cols) { dcol2 = gs->cols - 1; /* right edge */ } dx = DCOL2X(gs, dcol2) - Di[hits][X]; dy = DROW2Y(gs, drow1) - Di[hits][Y]; alpha = sqrt(dx * dx + dy * dy) / sqrt(xres * xres + yres * yres); offset = DRC2OFF(gs, drow1, dcol2); GET_MAPATT(Ebuf, offset, z1); offset = DRC2OFF(gs, drow2, dcol1); GET_MAPATT(Ebuf, offset, z2); Di[hits][Z] = LERP(alpha, z1, z2); } } /* if they don't intersect, something's wrong! */ /* should only happen on endpoint, so it will be added later */ else { hits--; num--; } fdig += incr; } return (hits); }