📄 intersection_gpc.c
字号:
for (i= 0; i < c.num_vertices; i++)
/* Ignore superfluous vertices embedded in horizontal edges */
if (OPTIMAL(c.vertex, i, c.num_vertices))
result++;
}
return result;
}
static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree,
int *sbt_entries, gpc_polygon *p, int type,
gpc_op op)
{
int c, i, min, max, num_edges, v, num_vertices;
int total_vertices= 0, e_index=0;
edge_node *e, *edge_table;
for (c= 0; c < p->num_contours; c++)
total_vertices+= count_optimal_vertices(p->contour[c]);
/* Create the entire input polygon edge table in one go */
_MALLOC(edge_table, total_vertices * sizeof(edge_node),
"edge table creation");
for (c= 0; c < p->num_contours; c++)
{
if (p->contour[c].num_vertices < 0)
{
/* Ignore the non-contributing contour and repair the vertex count */
p->contour[c].num_vertices= -p->contour[c].num_vertices;
}
else
{
/* Perform contour optimisation */
num_vertices= 0;
for (i= 0; i < p->contour[c].num_vertices; i++)
if (OPTIMAL(p->contour[c].vertex, i, p->contour[c].num_vertices))
{
edge_table[num_vertices].vertex.x= p->contour[c].vertex[i].x;
edge_table[num_vertices].vertex.y= p->contour[c].vertex[i].y;
/* Record vertex in the scanbeam table */
add_to_sbtree(sbt_entries, sbtree,
edge_table[num_vertices].vertex.y);
num_vertices++;
}
/* Do the contour forward pass */
for (min= 0; min < num_vertices; min++)
{
/* If a forward local minimum... */
if (FWD_MIN(edge_table, min, num_vertices))
{
/* Search for the next local maximum... */
num_edges= 1;
max= NEXT_INDEX(min, num_vertices);
while (NOT_FMAX(edge_table, max, num_vertices))
{
num_edges++;
max= NEXT_INDEX(max, num_vertices);
}
/* Build the next edge list */
e= &edge_table[e_index];
e_index+= num_edges;
v= min;
e[0].bstate[BELOW]= UNBUNDLED;
e[0].bundle[BELOW][CLIP]= FALSE;
e[0].bundle[BELOW][SUBJ]= FALSE;
for (i= 0; i < num_edges; i++)
{
e[i].xb= edge_table[v].vertex.x;
e[i].bot.x= edge_table[v].vertex.x;
e[i].bot.y= edge_table[v].vertex.y;
v= NEXT_INDEX(v, num_vertices);
e[i].top.x= edge_table[v].vertex.x;
e[i].top.y= edge_table[v].vertex.y;
e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) /
(e[i].top.y - e[i].bot.y);
e[i].type= type;
e[i].outp[ABOVE]= NULL;
e[i].outp[BELOW]= NULL;
e[i].next= NULL;
e[i].prev= NULL;
e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ?
&(e[i + 1]) : NULL;
e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL;
e[i].next_bound= NULL;
e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT;
e[i].bside[SUBJ]= LEFT;
}
insert_bound(bound_list(lmt, edge_table[min].vertex.y), e);
}
}
/* Do the contour reverse pass */
for (min= 0; min < num_vertices; min++)
{
/* If a reverse local minimum... */
if (REV_MIN(edge_table, min, num_vertices))
{
/* Search for the previous local maximum... */
num_edges= 1;
max= PREV_INDEX(min, num_vertices);
while (NOT_RMAX(edge_table, max, num_vertices))
{
num_edges++;
max= PREV_INDEX(max, num_vertices);
}
/* Build the previous edge list */
e= &edge_table[e_index];
e_index+= num_edges;
v= min;
e[0].bstate[BELOW]= UNBUNDLED;
e[0].bundle[BELOW][CLIP]= FALSE;
e[0].bundle[BELOW][SUBJ]= FALSE;
for (i= 0; i < num_edges; i++)
{
e[i].xb= edge_table[v].vertex.x;
e[i].bot.x= edge_table[v].vertex.x;
e[i].bot.y= edge_table[v].vertex.y;
v= PREV_INDEX(v, num_vertices);
e[i].top.x= edge_table[v].vertex.x;
e[i].top.y= edge_table[v].vertex.y;
e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) /
(e[i].top.y - e[i].bot.y);
e[i].type= type;
e[i].outp[ABOVE]= NULL;
e[i].outp[BELOW]= NULL;
e[i].next= NULL;
e[i].prev= NULL;
e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ?
&(e[i + 1]) : NULL;
e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL;
e[i].next_bound= NULL;
e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT;
e[i].bside[SUBJ]= LEFT;
}
insert_bound(bound_list(lmt, edge_table[min].vertex.y), e);
}
}
}
}
return edge_table;
}
static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev)
{
if (!*aet)
{
/* Append edge onto the tail end of the AET */
*aet= edge;
edge->prev= prev;
edge->next= NULL;
}
else
{
/* Do primary sort on the xb field */
if (edge->xb < (*aet)->xb)
{
/* Insert edge here (before the AET edge) */
edge->prev= prev;
edge->next= *aet;
(*aet)->prev= edge;
*aet= edge;
}
else
{
if (edge->xb == (*aet)->xb)
{
/* Do secondary sort on the dx field */
if (edge->dx < (*aet)->dx)
{
/* Insert edge here (before the AET edge) */
edge->prev= prev;
edge->next= *aet;
(*aet)->prev= edge;
*aet= edge;
}
else
{
/* Head further into the AET */
add_edge_to_aet(&((*aet)->next), edge, *aet);
}
}
else
{
/* Head further into the AET */
add_edge_to_aet(&((*aet)->next), edge, *aet);
}
}
}
}
static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1,
double x, double y)
{
it_node *existing_node;
if (!*it)
{
/* Append a new node to the tail of the list */
_MALLOC(*it, sizeof(it_node), "IT insertion");
(*it)->ie[0]= edge0;
(*it)->ie[1]= edge1;
(*it)->point.x= x;
(*it)->point.y= y;
(*it)->next= NULL;
}
else
{
if ((*it)->point.y > y)
{
/* Insert a new node mid-list */
existing_node= *it;
_MALLOC(*it, sizeof(it_node), "IT insertion");
(*it)->ie[0]= edge0;
(*it)->ie[1]= edge1;
(*it)->point.x= x;
(*it)->point.y= y;
(*it)->next= existing_node;
}
else
/* Head further down the list */
add_intersection(&((*it)->next), edge0, edge1, x, y);
}
}
static void add_st_edge(st_node **st, it_node **it, edge_node *edge,
double dy)
{
st_node *existing_node;
double den, r, x, y;
if (!*st)
{
/* Append edge onto the tail end of the ST */
_MALLOC(*st, sizeof(st_node), "ST insertion");
(*st)->edge= edge;
(*st)->xb= edge->xb;
(*st)->xt= edge->xt;
(*st)->dx= edge->dx;
(*st)->prev= NULL;
}
else
{
den= ((*st)->xt - (*st)->xb) - (edge->xt - edge->xb);
/* If new edge and ST edge don't cross */
if ((edge->xt >= (*st)->xt) || (edge->dx == (*st)->dx) ||
(fabs(den) <= DBL_EPSILON))
{
/* No intersection - insert edge here (before the ST edge) */
existing_node= *st;
_MALLOC(*st, sizeof(st_node), "ST insertion");
(*st)->edge= edge;
(*st)->xb= edge->xb;
(*st)->xt= edge->xt;
(*st)->dx= edge->dx;
(*st)->prev= existing_node;
}
else
{
/* Compute intersection between new edge and ST edge */
r= (edge->xb - (*st)->xb) / den;
x= (*st)->xb + r * ((*st)->xt - (*st)->xb);
y= r * dy;
/* Insert the edge pointers and the intersection point in the IT */
add_intersection(it, (*st)->edge, edge, x, y);
/* Head further into the ST */
add_st_edge(&((*st)->prev), it, edge, dy);
}
}
}
static void build_intersection_table(it_node **it, edge_node *aet, double dy)
{
st_node *st, *stp;
edge_node *edge;
/* Build intersection table for the current scanbeam */
reset_it(it);
st= NULL;
/* Process each AET edge */
for (edge= aet; edge; edge= edge->next)
{
if ((edge->bstate[ABOVE] == BUNDLE_HEAD) ||
edge->bundle[ABOVE][CLIP] || edge->bundle[ABOVE][SUBJ])
add_st_edge(&st, it, edge, dy);
}
/* Free the sorted edge table */
while (st)
{
stp= st->prev;
FREE(st);
st= stp;
}
}
static int count_contours(polygon_node *polygon)
{
int nc, nv;
vertex_node *v, *nextv;
for (nc= 0; polygon; polygon= polygon->next)
if (polygon->active)
{
/* Count the vertices in the current contour */
nv= 0;
for (v= polygon->proxy->v[LEFT]; v; v= v->next)
nv++;
/* Record valid vertex counts in the active field */
if (nv > 2)
{
polygon->active= nv;
nc++;
}
else
{
/* Invalid contour: just free the heap */
for (v= polygon->proxy->v[LEFT]; v; v= nextv)
{
nextv= v->next;
FREE(v);
}
polygon->active= 0;
}
}
return nc;
}
static void add_left(polygon_node *p, double x, double y)
{
vertex_node *nv;
/* Create a new vertex node and set its fields */
_MALLOC(nv, sizeof(vertex_node), "vertex node creation");
nv->x= x;
nv->y= y;
/* Add vertex nv to the left end of the polygon's vertex list */
nv->next= p->proxy->v[LEFT];
/* Update proxy->[LEFT] to point to nv */
p->proxy->v[LEFT]= nv;
}
static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list)
{
polygon_node *target;
/* Label contour as a hole */
q->proxy->hole= TRUE;
if (p->proxy != q->proxy)
{
/* Assign p's vertex list to the left end of q's list */
p->proxy->v[RIGHT]->next= q->proxy->v[LEFT];
q->proxy->v[LEFT]= p->proxy->v[LEFT];
/* Redirect any p->proxy references to q->proxy */
for (target= p->proxy; list; list= list->next)
{
if (list->proxy == target)
{
list->active= FALSE;
list->proxy= q->proxy;
}
}
}
}
static void add_right(polygon_node *p, double x, double y)
{
vertex_node *nv;
/* Create a new vertex node and set its fields */
_MALLOC(nv, sizeof(vertex_node), "vertex node creation");
nv->x= x;
nv->y= y;
nv->next= NULL;
/* Add vertex nv to the right end of the polygon's vertex list */
p->proxy->v[RIGHT]->next= nv;
/* Update proxy->v[RIGHT] to point to nv */
p->proxy->v[RIGHT]= nv;
}
static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list)
{
polygon_node *target;
/* Label contour as external */
q->proxy->hole= FALSE;
if (p->proxy != q->proxy)
{
/* Assign p's vertex list to the right end of q's list */
q->proxy->v[RIGHT]->next= p->proxy->v[LEFT];
q->proxy->v[RIGHT]= p->proxy->v[RIGHT];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -