⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ptinpoly.c

📁 [Game.Programming].Academic - Graphics Gems (6 books source code)
💻 C
📖 第 1 页 / 共 4 页
字号:
		for ( j = count+1 ; --j ; p_gr++ ) {		    /* test if y is between edges */		    if ( ty >= p_gr->miny && ty < p_gr->maxy ) {			if ( tx > p_gr->maxx ) {			    inside_flag = !inside_flag ;			} else if ( tx > p_gr->minx ) {			    /* full computation */			    if ( ( p_gr->xa -				( p_gr->ya - ty ) * p_gr->slope ) < tx ) {				inside_flag = !inside_flag ;			    }			}		    }		}		break ;	    case GC_AIM_B:		/* bottom edge is clear, shoot Y+ ray */		/* note - this next statement requires that GC_BL_IN is 1 */		inside_flag = gc_flags & GC_BL_IN ;		for ( j = count+1 ; --j ; p_gr++ ) {		    /* test if x is between edges */		    if ( tx >= p_gr->minx && tx < p_gr->maxx ) {			if ( ty > p_gr->maxy ) {			    inside_flag = !inside_flag ;			} else if ( ty > p_gr->miny ) {			    /* full computation */			    if ( ( p_gr->ya - ( p_gr->xa - tx ) *				    p_gr->inv_slope ) < ty ) {				inside_flag = !inside_flag ;			    }			}		    }		}		break ;	    case GC_AIM_R:		/* right edge is clear, shoot X+ ray */		inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ;		/* TBD: Note, we could have sorted the edges to be tested		 * by miny or somesuch, and so be able to cut testing		 * short when the list's miny > point.y .		 */		for ( j = count+1 ; --j ; p_gr++ ) {		    /* test if y is between edges */		    if ( ty >= p_gr->miny && ty < p_gr->maxy ) {			if ( tx <= p_gr->minx ) {			    inside_flag = !inside_flag ;			} else if ( tx <= p_gr->maxx ) {			    /* full computation */			    if ( ( p_gr->xa -				( p_gr->ya - ty ) * p_gr->slope ) >= tx ) {				inside_flag = !inside_flag ;			    }			}		    }		}		break ;	    case GC_AIM_T:		/* top edge is clear, shoot Y+ ray */		inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ;		for ( j = count+1 ; --j ; p_gr++ ) {		    /* test if x is between edges */		    if ( tx >= p_gr->minx && tx < p_gr->maxx ) {			if ( ty <= p_gr->miny ) {			    inside_flag = !inside_flag ;			} else if ( ty <= p_gr->maxy ) {			    /* full computation */			    if ( ( p_gr->ya - ( p_gr->xa - tx ) *				    p_gr->inv_slope ) >= ty ) {				inside_flag = !inside_flag ;			    }			}		    }		}		break ;	    case GC_AIM_C:		/* no edge is clear, bite the bullet and test		 * against the bottom left corner.		 * We use Franklin Antonio's algorithm (Graphics Gems III).		 */		/* TBD: Faster yet might be to test against the closest		 * corner to the cell location, but our hope is that we		 * rarely need to do this testing at all.		 */		inside_flag = ((gc_flags & GC_BL_IN) == GC_BL_IN) ;		init_flag = TRUE ;		/* get lower left corner coordinate */		cornerx = p_gs->glx[(int)xcell] ;		cornery = p_gs->gly[(int)ycell] ;		for ( j = count+1 ; --j ; p_gr++ ) {		    /* quick out test: if test point is		     * less than minx & miny, edge cannot overlap.		     */		    if ( tx >= p_gr->minx && ty >= p_gr->miny ) {			/* quick test failed, now check if test point and			 * corner are on different sides of edge.			 */			if ( init_flag ) {			    /* Compute these at most once for test */			    /* P3 - P4 */			    bx = tx - cornerx ;			    by = ty - cornery ;			    init_flag = FALSE ;			}			denom = p_gr->ay * bx - p_gr->ax * by ;			if ( denom != 0.0 ) {			    /* lines are not collinear, so continue */			    /* P1 - P3 */			    cx = p_gr->xa - tx ;			    cy = p_gr->ya - ty ;			    alpha = by * cx - bx * cy ;			    if ( denom > 0.0 ) {				if ( alpha < 0.0 || alpha >= denom ) {				    /* test edge not hit */				    goto NextEdge ;				}				beta = p_gr->ax * cy - p_gr->ay * cx ;				if ( beta < 0.0 || beta >= denom ) {				    /* polygon edge not hit */				    goto NextEdge ;				}			    } else {				if ( alpha > 0.0 || alpha <= denom ) {				    /* test edge not hit */				    goto NextEdge ;				}				beta = p_gr->ax * cy - p_gr->ay * cx ;				if ( beta > 0.0 || beta <= denom ) {				    /* polygon edge not hit */				    goto NextEdge ;				}			    }			    inside_flag = !inside_flag ;			}		    }		    NextEdge: ;		}		break ;	    }	} else {	    /* simple cell, so if lower left corner is in,	     * then cell is inside.	     */	    inside_flag = p_gc->gc_flags & GC_BL_IN ;	}    }    return( inside_flag ) ;}void GridCleanup( p_gs )pGridSet	p_gs ;{int	i ;pGridCell	p_gc ;    for ( i = 0, p_gc = p_gs->gc	; i < p_gs->tot_cells	; i++, p_gc++ ) {	if ( p_gc->gr ) {	    free( p_gc->gr ) ;	}    }    free( p_gs->glx ) ;    free( p_gs->gly ) ;    free( p_gs->gc ) ;}/* ======= Exterior (convex only) algorithm =============================== *//* Test the edges of the convex polygon against the point.  If the point is * outside any edge, the point is outside the polygon. * * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, * which returns a pointer to a plane set array. * Call testing procedure with a pointer to this array, _numverts_, and * test point _point_, returns 1 if inside, 0 if outside. * Call cleanup with pointer to plane set array to free space. * * RANDOM can be defined for this test. * CONVEX must be defined for this test; it is not usable for general polygons. */#ifdef	CONVEX/* make exterior plane set */pPlaneSet ExteriorSetup( pgon, numverts )double	pgon[][2] ;int	numverts ;{int	p1, p2, flip_edge ;pPlaneSet	pps, pps_return ;#ifdef	RANDOMint	i, ind ;PlaneSet	ps_temp ;#endif    pps = pps_return =	    (pPlaneSet)malloc( numverts * sizeof( PlaneSet )) ;    MALLOC_CHECK( pps ) ;    /* take cross product of vertex to find handedness */    flip_edge = (pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) >		(pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ;    /* Generate half-plane boundary equations now for faster testing later.     * vx & vy are the edge's normal, c is the offset from the origin.     */    for ( p1 = numverts-1, p2 = 0 ; p2 < numverts ; p1 = p2, p2++, pps++ ) {	pps->vx = pgon[p1][Y] - pgon[p2][Y] ;	pps->vy = pgon[p2][X] - pgon[p1][X] ;	pps->c = pps->vx * pgon[p1][X] + pps->vy * pgon[p1][Y] ;	/* check sense and reverse plane edge if need be */	if ( flip_edge ) {	    pps->vx = -pps->vx ;	    pps->vy = -pps->vy ;	    pps->c  = -pps->c ;	}    }#ifdef	RANDOM    /* Randomize the order of the edges to improve chance of early out */    /* There are better orders, but the default order is the worst */    for ( i = 0, pps = pps_return	; i < numverts	; i++ ) {	ind = (int)(RAN01() * numverts ) ;	if ( ( ind < 0 ) || ( ind >= numverts ) ) {	    fprintf( stderr,		"Yikes, the random number generator is returning values\n" ) ;	    fprintf( stderr,		"outside the range [0.0,1.0), so please fix the code!\n" ) ;	    ind = 0 ;	}	/* swap edges */	ps_temp = *pps ;	*pps = pps_return[ind] ;	pps_return[ind] = ps_temp ;    }#endif    return( pps_return ) ;}/* Check point for outside of all planes *//* note that we don't need "pgon", since it's been processed into * its corresponding PlaneSet. */int ExteriorTest( p_ext_set, numverts, point )pPlaneSet	p_ext_set ;int	numverts ;double	point[2] ;{register PlaneSet	*pps ;register int	p0 ;register double tx, ty ;int	inside_flag ;    tx = point[X] ;    ty = point[Y] ;    for ( p0 = numverts+1, pps = p_ext_set ; --p0 ; pps++ ) {	/* test if the point is outside this edge */	if ( pps->vx * tx + pps->vy * ty > pps->c ) {	    return( 0 ) ;	}    }    /* if we make it to here, we were inside all edges */    return( 1 ) ;}void ExteriorCleanup( p_ext_set )pPlaneSet	p_ext_set ;{    free( p_ext_set ) ;}#endif/* ======= Inclusion (convex only) algorithm ============================== *//* Create an efficiency structure (see Preparata) for the convex polygon which * allows binary searching to find which edge to test the point against.  This * algorithm is O(log n). * * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, * which returns a pointer to an inclusion anchor structure. * Call testing procedure with a pointer to this structure and test point * _point_, returns 1 if inside, 0 if outside. * Call cleanup with pointer to inclusion anchor structure to free space. * * CONVEX must be defined for this test; it is not usable for general polygons. */#ifdef	CONVEX/* make inclusion wedge set */pInclusionAnchor InclusionSetup( pgon, numverts )double	pgon[][2] ;int	numverts ;{int	pc, p1, p2, flip_edge ;double	ax,ay, qx,qy, wx,wy, len ;pInclusionAnchor pia ;pInclusionSet	pis ;    /* double the first edge to avoid needing modulo during test search */    pia = (pInclusionAnchor)malloc( sizeof( InclusionAnchor )) ;    MALLOC_CHECK( pia ) ;    pis = pia->pis =	    (pInclusionSet)malloc( (numverts+1) * sizeof( InclusionSet )) ;    MALLOC_CHECK( pis ) ;    pia->hi_start = numverts - 1 ;    /* get average point to make wedges from */    qx = qy = 0.0 ;    for ( p2 = 0 ; p2 < numverts ; p2++ ) {	qx += pgon[p2][X] ;	qy += pgon[p2][Y] ;    }    pia->qx = qx /= (double)numverts ;    pia->qy = qy /= (double)numverts ;    /* take cross product of vertex to find handedness */    pia->flip_edge = flip_edge =		(pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) >		(pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ;    ax = pgon[0][X] - qx ;    ay = pgon[0][Y] - qy ;    len = sqrt( ax * ax + ay * ay ) ;    if ( len == 0.0 ) {	fprintf( stderr, "sorry, polygon for inclusion test is defective\n" ) ;	exit(1) ;    }    pia->ax = ax /= len ;    pia->ay = ay /= len ;    /* loop through edges, and double last edge */    for ( pc = p1 = 0, p2 = 1	; pc <= numverts	; pc++, p1 = p2, p2 = (++p2)%numverts, pis++ ) {	/* wedge border */	wx = pgon[p1][X] - qx ;	wy = pgon[p1][Y] - qy ;	len = sqrt( wx * wx + wy * wy ) ;	wx /= len ;	wy /= len ;	/* cosine of angle from anchor border to wedge border */	pis->dot = ax * wx + ay * wy ;	/* sign from cross product */	if ( ( ax * wy > ay * wx ) == flip_edge ) {	    pis->dot = -2.0 - pis->dot ;	}	/* edge */	pis->ex = pgon[p1][Y] - pgon[p2][Y] ;	pis->ey = pgon[p2][X] - pgon[p1][X] ;	pis->ec = pis->ex * pgon[p1][X] + pis->ey * pgon[p1][Y] ;	/* check sense and reverse plane eqns if need be */	if ( flip_edge ) {	    pis->ex = -pis->ex ;	    pis->ey = -pis->ey ;	    pis->ec = -pis->ec ;	}    }    /* set first angle a little > 1.0 and last < -3.0 just to be safe. */    pia->pis[0].dot = -3.001 ;    pia->pis[numverts].dot = 1.001 ;    return( pia ) ;}/* Find wedge point is in by binary search, then test wedge */int InclusionTest( pia, point )pInclusionAnchor	pia ;double	point[2] ;{register double tx, ty, len, dot ;int	inside_flag, lo, hi, ind ;pInclusionSet	pis ;    tx = point[X] - pia->qx ;    ty = point[Y] - pia->qy ;    len = sqrt( tx * tx + ty * ty ) ;    /* check if point is exactly at anchor point (which is inside polygon) */    if ( len == 0.0 ) return( 1 ) ;    tx /= len ;    ty /= len ;    /* get dot product for searching */    dot = pia->ax * tx + pia->ay * ty ;    if ( ( pia->ax * ty > pia->ay * tx ) == pia->flip_edge ) {	dot = -2.0 - dot ;    }    /* binary search through angle list and find matching angle pair */    lo = 0 ;    hi = pia->hi_start ;    while ( lo <= hi ) {	ind = (lo+hi)/ 2 ;	if ( dot < pia->pis[ind].dot ) {	    hi = ind - 1 ;	} else if ( dot > pia->pis[ind+1].dot ) {	    lo = ind + 1 ;	} else {	    goto Foundit ;	}    }    /* should never reach here, but just in case... */    fprintf( stderr,	    "Hmmm, something weird happened - bad dot product %lg\n", dot);    Foundit:    /* test if the point is outside the wedge's exterior edge */    pis = &pia->pis[ind] ;    inside_flag = ( pis->ex * point[X] + pis->ey * point[Y] <= pis->ec ) ;    return( inside_flag ) ;}void InclusionCleanup( p_inc_anchor )pInclusionAnchor p_inc_anchor ;{    free( p_inc_anchor->pis ) ;    free( p_inc_anchor ) ;}#endif/* ======= Crossings Multiply algorithm =================================== *//* * This version is usually somewhat faster than the original published in * Graphics Gems IV; by turning the division for testing the X axis crossing * into a tricky multiplication test this part of the test became faster, * which had the additional effect of making the test for "both to left or * both to right" a bit slower for triangles than simply computing the * intersection each time.  The main increase is in triangle testing speed, * which was about 15% faster; all other polygon complexities were pretty much * the same as before.  On machines where division is very expensive (not the * case on the HP 9000 series on which I tested) this test should be much * faster overall than the old code.  Your mileage may (in fact, will) vary, * depending on the machine and the test data, but in general I believe this * code is both shorter and faster.  This test was inspired by unpublished * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson. * Related work by Samosky is in: * * Samosky, Joseph, "SectionView: A system for interactively specifying and * visualizing sections through three-dimensional medical image data", * M.S. Thesis, Department of Electrical Engineering and Computer Science, * Massachusetts Institute of Technology, 1993. * *//* Shoot a test ray along +X axis.  The strategy is to compare vertex Y values * to the testing point's Y and quickly discard edges which are entirely to one * side of the test ray.  Note that CONVEX and WINDING code can be added as * for the CrossingsTest() code; it is left out here for clarity. * * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point * _point_, returns 1 if inside, 0 if outside. */int CrossingsMultiplyTest( pgon, numverts, point )double	pgon[][2] ;int	numverts ;double	point[2] ;{register int	j, yflag0, yflag1, inside_flag ;register double	ty, tx, *vtx0, *vtx1 ;    tx = point[X] ;    ty = point[Y] ;    vtx0 = pgon[numverts-1] ;    /* get test bit for above/below X axis */    yflag0 = ( vtx0[Y] >= ty ) ;    vtx1 = pgon[0] ;    inside_flag = 0 ;    for ( j = numverts+1 ; --j ; ) {	yflag1 = ( vtx1[Y] >= ty ) ;	/* Check if endpoints straddle (are on opposite sides) of X axis	 * (i.e. the Y's differ); if so, +X ray could intersect this edge.	 * The old test also checked whether the endpoints are both to the	 * right or to the left of the test point.  However, given the faster	 * intersection point computation used below, this test was found to	 * be a break-even proposition for most polygons and a loser for	 * triangles (where 50% or more of the edges which survive this test	 * will cross quadrants and so have to have the X intersection computed	 * anyway).  I credit Joseph Samosky with inspiring me to try dropping	 * the "both left or both right" part of my code.	 */	if ( yflag0 != yflag1 ) {	    /* Check intersection of pgon segment with +X ray.	     * Note if >= point's X; if so, the ray hits it.	     * The division operation is avoided for the ">=" test by checking	     * the sign of the first vertex wrto the test point; idea inspired	     * by Joseph Samosky's and Mark Haigh-Hutchinson's different	     * polygon inclusion tests.	     */	    if ( ((vtx1[Y]-ty) * (vtx0[X]-vtx1[X]) >=		    (vtx1[X]-tx) * (vtx0[Y]-vtx1[Y])) == yflag1 ) {		inside_flag = !inside_flag ;	    }	}	/* Move to the next pair of vertices, retaining info as possible. */	yflag0 = yflag1 ;	vtx0 = vtx1 ;	vtx1 += 2 ;    }    return( inside_flag ) ;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -