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

📄 vispoly.c

📁 source code to compute the visibility polygon of a point in a polygon.
💻 C
字号:
/* Brian O'Connor * * vispoly.C * * Functions for creating a visibility polygon  */#include <stdio.h>#include <assert.h>#include "input.h"#include "line.h"#include "cell.h"#include "pursuer.h"#include "vispoly.h"void MakeGapEdges(EdgeInfo *eInfo, Point *p, EdgeInfo *vEdges);void DumpGapEdges(EdgeInfo *vEdges);void CalcPoly(EdgeInfo *edges, EdgeInfo *vEdges, VPoly *vpoly);VPEdge *GapToObEdge(EdgeInfo *edgeInfo, EdgeInfo *vEdges, VPEdge *vpe,		    VPEdge *lastOb, int bFirst);VPEdge *ObToGapEdge(VPEdge *vpe, EdgeInfo *vEdges);VPEdge *ObToObEdge(VPEdge *vpe, EdgeInfo *edgeInfo, EdgeInfo *vEdges);int ClosestVisEdge(Line *edge, EdgeInfo *vEdges, Point *inGap, Point		   *badGap, int i1, int i2);void OrderPoly(VPoly *vpoly);/* given the edges composing the obstacles & a point, return the * visibility polygon for this point. */int MakeVisPoly(EdgeInfo *eInfo, Point *p, VPoly *vpoly){  EdgeInfo *vEdges;    vEdges = new EdgeInfo;  MakeGapEdges(eInfo, p, vEdges);//  DumpGapEdges(vEdges);  CalcPoly(eInfo, vEdges, vpoly);  if( vpoly->nEdges < 3 ) {    return(FALSE);  }  OrderPoly(vpoly);  return(TRUE);}void MakeGapEdges(EdgeInfo *eInfo, Point *p, EdgeInfo *vEdges){  int i;  vEdges->nEdges = 0;  vEdges->edges = new (Line *)[eInfo->nEdges];    for( i = 0; i < eInfo->nEdges; i++ ) {    ExtendGapEdge(p, eInfo->edges[i]->A, eInfo, vEdges, 		  eInfo->edges[i]->ob);  }}/* very similar to ExtendOneRay in cell.C; will either: * 1) nothing if the path between p1 & p2 is not clear; * 2) a ray between p1 and p2 if p2 is blocked; * 3) a ray from p2 to another edge along the p1,p2 line if p2 is clear. * These edges can then be used as gap edges or for testing if a vertex * is visible when constructing a visibility polygon. */void ExtendGapEdge(Point *p1, Point *p2, EdgeInfo *e, EdgeInfo *vEdges,	Obstacle *o2){  Line *l, *l2;  int i;  int p2vis;  int visible = TRUE;  double maxDist, currDist;  Point *maxPt, *currPt;    /* initialize fields */  maxDist = INFINITY;  p2vis = TRUE;    l = PointsToLine(p1, p2);  l->ob = NULL;    if( !OpenEdgeTest(o2, p1, p2) ) {    p2vis = FALSE;  }  maxPt = NULL;  currPt = NewPoint();  for( i = 0; i < e->nEdges; i++ ) {    l2 = e->edges[i];    if( (l2->A == p1 && l2->B == p2) ||	(l2->B == p1 && l2->A == p2) ) continue;        LineIntersectionDistance(l, l2, currPt, &currDist);    if( !PointOnSegment(l2, currPt) ) currDist = INFINITY;    if( currDist == INFINITY ) continue;    if( FloatCompare(currDist, 0.0) > 0 &&	FloatCompare(currDist, l->length) < 0 ) {      visible = FALSE;      return;    } else if( FloatCompare(currDist, l->length) > 0 &&	       FloatCompare(currDist, maxDist) < 0 ) {      if( l2->ob != o2 ||	  !InsideTest(l2, currPt, p2)) {	maxDist = currDist;	if( maxPt != NULL ) delete maxPt;	maxPt = currPt;	currPt = NewPoint();      } else {	/* we are closed off at this end & shouldn't extend: broken test? */	/*if( maxPt != NULL ) delete maxPt;	maxPt = p2;	maxDist = -INFINITY; */      }    }  }    /* make rays out of the data we've found */  if( maxPt == NULL ) maxPt = p2;    if( visible && p2vis && !PointEqual(maxPt, p2) ) {    vEdges->edges[vEdges->nEdges++] = new VPEdge(p2, maxPt);    ((VPEdge *)vEdges->edges[vEdges->nEdges - 1])->bGap = TRUE;  } else if( visible ) {    vEdges->edges[vEdges->nEdges++] = new VPEdge(p1, p2);    ((VPEdge *)vEdges->edges[vEdges->nEdges - 1])->bGap = FALSE;  } else {    /* delete resources */  }    /* cleanup */  if( currPt != maxPt ) delete currPt;}void DumpGapEdges(EdgeInfo *vEdges){	int i;	VPEdge *e;	for( i = 0; i < vEdges->nEdges; i++ ) {		e = (VPEdge *)vEdges->edges[i];			if( e->bGap ) {			printf("Gap Edge: (%f, %f), (%f, %f)\n",				e->A->x, e->A->y, e->B->x, e->B->y );		} else {			printf("Visibility edge: (%f, %f), (%f, %f)\n",				e->A->x, e->A->y, e->B->x, e->B->y );		}	}	printf("\n");}/* algorithm:  * select next edge by: *  gap edge: take cell edge that the opposite endpoint connects to *  ob  edge: look for unmarked cell edges & take any; otherwise *	take adjacent edge we haven't visited & which has an  *	unmarked visibility edge. * terminate when we hit an edge w. all vedges out marked. */void CalcPoly(EdgeInfo *edges, EdgeInfo *vEdges, VPoly *vpoly){  int i,j, bPrevGap;  VPEdge *vpe, *result;  vpoly->edges = new (VPEdge *)[CALCPOLY_PTS];    i = 0;  vpoly->nEdges = 0;  if( ((VPEdge *)vEdges->edges[0])->bGap) {    vpoly->edges[i++] = (VPEdge *)vEdges->edges[0];  }  bPrevGap = FALSE;  ((VPEdge *)vEdges->edges[0])->bMark = TRUE;  while(TRUE) {    vpoly->nEdges = i;    assert( i < CALCPOLY_PTS );    if( i == 0 ) {      /* special case: first vEdge we used was not a gap edge */      vpoly->edges[i++] = GapToObEdge(edges, vEdges,				      (VPEdge *) vEdges->edges[0],NULL,				      TRUE);      assert(vpoly->edges[i - 1] != NULL);    } else if( vpoly->edges[i-1]->bGap ) {      /* case 1: last edge was a gap edge; search edgelist for a match. */      vpoly->edges[i++] = GapToObEdge(edges, vEdges, vpoly->edges[i-1],				      i>1?vpoly->edges[i-2]:NULL, FALSE);      assert(vpoly->edges[i -1] != NULL);      bPrevGap = TRUE;    } else {      /* case 2: last edge was an obstacle edge;	 first look for an unmarked gap edge out, then look for	 an unmarked visibility edge indicating which edge to visit next.	 */      assert(i > 0 );      vpe = (VPEdge *)vpoly->edges[i - 1];      if(!bPrevGap) result = ObToGapEdge(vpe, vEdges);      else result = NULL;      if( result == NULL ) result = ObToObEdge(vpe, edges, vEdges);      if(bPrevGap && result == NULL) result = ObToGapEdge(vpe, vEdges);       if( result == NULL ) break; /* finished polygon */      bPrevGap = FALSE;      vpoly->edges[i++] = result;    }  }  vpoly->nEdges = i;}VPEdge *GapToObEdge(EdgeInfo *edgeInfo, EdgeInfo *vEdges, VPEdge *vpe,		    VPEdge *lastOb, int bFirst){  Line *edge;  VPEdge *visEdge;  Point *p;  Point *p2;  int i,j, firstVisEdge, nextGapEdge, nextVisEdge;  double minDist;    /* find an unused ob edge that we are connected to */  for( i = 0; i < edgeInfo->nEdges; i++ ) {    edge = NULL;    p = NULL;    p2 = NULL;    firstVisEdge = -1;    nextGapEdge = -1;    nextVisEdge = -1;    minDist = INFINITY;        if( PointOnSegment(edgeInfo->edges[i], vpe->B) && 	(lastOb == NULL || !PointOnSegment(lastOb, vpe->B)) ) {      edge = edgeInfo->edges[i];      p = vpe->B;    } else if( PointOnSegment(edgeInfo->edges[i], vpe->A) &&	       (lastOb == NULL || !PointOnSegment(lastOb, vpe->A)) ) {      edge = edgeInfo->edges[i];      p = vpe->A;    } else continue;        if( bFirst ) { // entering edge was really a vis edge      if( PointEqual(p, edge->A) ) {	return( new VPEdge(p, edge->B) );      } else if( PointEqual(p, edge->B)) {	return( new VPEdge(p, edge->A) );      } else assert(0);    }        /*    for( j = 0; j < vEdges->nEdges; j++ ) {      visEdge = (VPEdge *)vEdges->edges[j];      if( PointOnSegment(edge, visEdge->A) ) {	p2 = visEdge->A;      } else if( PointOnSegment(edge, visEdge->B) ) {	p2 = visEdge->B;      } else continue;      if( firstVisEdge == -1 && !visEdge->bGap && !visEdge->bMark ) {	firstVisEdge = j;      } else if( !visEdge->bGap && !visEdge->bMark ) {	assert(nextVisEdge == -1);	nextVisEdge = j;      } else if( visEdge->bGap && !visEdge->bMark ) {		assert(nextGapEdge == -1);	nextGapEdge = j;      }    }*/        for( j = 0; j < vEdges->nEdges; j++ ) {      visEdge = (VPEdge *)vEdges->edges[j];      if( !visEdge->bMark ) {	if( PointOnSegment(edge, visEdge->A) ) {	  p2 = visEdge->A;	} else if( PointOnSegment(edge, visEdge->B) ) {	  p2 = visEdge->B;	} else continue;	if( FloatCompare(LineDistance(p, p2), minDist) < 0 ) {	  firstVisEdge = j;	  minDist = LineDistance(p, p2);	}      }    }          if( firstVisEdge != -1 ) break;  } /* end for loop, get a new value for edge */   /* can't continue; close off the polygon */  if( firstVisEdge == -1) {    if( PointOnSegment( lastOb, vpe->A) ) p = vpe->B;    else if( PointOnSegment( lastOb, vpe->B) ) p = vpe->A;    else assert(0);    return( new VPEdge(p,vEdges->edges[0]->B) );   }  assert( p != NULL );  assert(firstVisEdge != -1);  /* now convert firstVisEdge into an endpoint on an obstacle edge */  if( PointOnSegment(edge, vEdges->edges[firstVisEdge]->A) ) {    p2 = vEdges->edges[firstVisEdge]->A;  } else if( PointOnSegment(edge, vEdges->edges[firstVisEdge]->B) ) {    p2 = vEdges->edges[firstVisEdge]->B;  } else assert(0);  return( new VPEdge(p, p2) );}VPEdge *ObToGapEdge(VPEdge *vpe, EdgeInfo *vEdges){  int i;  VPEdge *vpeNew;  Point *p1, *p2;  double dist, minDist;  Point *minp1, *minp2;  VPEdge *minvpe;   minDist = INFINITY;  for(i = 0; i < vEdges->nEdges; i++) {    vpeNew = (VPEdge *)vEdges->edges[i];    if( PointOnSegment(vpe, vpeNew->A) ) {      dist = LineDistance(vpeNew->A, vpe->A);      p1 = vpeNew->A;      p2 = vpeNew->B;    } else if( PointOnSegment(vpe, vpeNew->B) ) {      dist = LineDistance(vpeNew->B, vpe->A);      p1 = vpeNew->B;      p2 = vpeNew->A;    } else continue;    if(FloatCompare(dist, minDist) < 0 && vpeNew->bGap && !vpeNew->bMark ) {      minvpe = vpeNew;      minp1 = p1;      minp2 = p2;      minDist = dist;    }  }  if( minDist < INFINITY ) {    /* endpt of ob edge = start pt of gap edge */    vpe->B = minp1;    minvpe->A = minp1;    minvpe->B = minp2;    minvpe->bMark = TRUE;    return(minvpe);  }  return(NULL); /* no unmarked gap edge leaving this edge */}VPEdge *ObToObEdge(VPEdge *obEdge, EdgeInfo *edgeInfo, EdgeInfo *vEdges){  int i;  VPEdge *vpe;  Point *p;  Point *p2;  p = NULL;  for(i = 0; p == NULL && i < vEdges->nEdges; i++ ) {    vpe = (VPEdge *)vEdges->edges[i];    if( !vpe->bGap && !vpe->bMark ) {      if( PointEqual(vpe->A, obEdge->A) ) { p = vpe->A; p2 = obEdge->B; }      else if( PointEqual(vpe->A, obEdge->B) ) { p = vpe->A; p2 = obEdge->A; }      else if( PointEqual(vpe->B, obEdge->A) ) { p = vpe->B; p2 = obEdge->B; }      else if( PointEqual(vpe->B, obEdge->B) ) { p = vpe->B; p2 = obEdge->A; }    }  }  if( p == NULL) return(NULL); /* no vis edges connected to adjacent edges */  /* mark vpe so that we don't try to use it again in the future */  vpe->bMark = TRUE;  /* now find the other edge that contains point p; the PointOnSegment     check verifies that we don't select a new edge == obEdge. */  for( i = 0; i < edgeInfo->nEdges; i++ ) {    if( (PointEqual(p, edgeInfo->edges[i]->A) &&	 !PointOnSegment(edgeInfo->edges[i], p2) )) {      return( new VPEdge(p, edgeInfo->edges[i]->B));    } else if( PointEqual(p, edgeInfo->edges[i]->B) &&	 !PointOnSegment(edgeInfo->edges[i], p2) ) {      return( new VPEdge(p, edgeInfo->edges[i]->A) );    }  }  assert(0); /* should always find a matching edge */}int ClosestVisEdge(Line *edge, EdgeInfo *vEdges, Point *inGap, Point		   *badGap, int i1, int i2){  Point *p1, *p2;  double d1in, d2in, d1bad, d2bad;  assert( i1 != i2 );  p1 = vEdges->edges[i1]->B;  p2 = vEdges->edges[i2]->B;   d1in = LineDistance(inGap, p1);  d2in = LineDistance(inGap, p2);  d1bad = LineDistance(badGap, p1);  d2bad = LineDistance(badGap, p2);  /* select pt that is closer to p1 than to p2 */  if( d1in <= d1bad) {    assert( d2in >= d2bad );    return(i1);  } else {    assert( d2in <= d2bad );    return(i2);  }}/* flip order of edges around so that they all line up. */void OrderPoly(VPoly *vpoly){	int i, bGap, bMark;	Point *p1, *p2;	assert(vpoly->nEdges > 1); // check for bad vpoly	if( !PointEqual(vpoly->edges[0]->B, vpoly->edges[1]->A) ) {		p1 = vpoly->edges[0]->A;		p2 = vpoly->edges[0]->B;                bGap = ( (VPEdge *)vpoly->edges[0])->bGap;                bMark = ( (VPEdge *)vpoly->edges[0])->bMark;		assert( PointEqual(vpoly->edges[1]->A, p1) );		delete vpoly->edges[0];		vpoly->edges[0] = new VPEdge(p2, p1);		vpoly->edges[0]->bGap = bGap;		vpoly->edges[0]->bMark = bMark;	}}

⌨️ 快捷键说明

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