void rb_iprint_tree(Rb_node t, int level) { int i; if (ishead(t) && t->p.parent == t) { printf("tree 0x%p is empty\n", (void *) t); } else if (ishead(t)) { printf("Head: 0x%p. Root = 0x%p, < = 0x%p, > = 0x%p\n", (void *) t, (void *) t->p.root, (void *) t->c.list.blink, (void *) t->c.list.flink); rb_iprint_tree(t->p.root, 0); } else { if (isext(t)) { for (i = 0; i < level; i++) putchar(' '); printf("Ext node 0x%p: %c,%c: p=0x%p, <=0x%p, >=0x%p k=%d\n", (void *) t, isred(t)?'R':'B', isleft(t)?'l':'r', (void *) t->p.parent, (void *) t->c.list.blink, (void *) t->c.list.flink, t->k.ikey); } else { rb_iprint_tree(t->c.child.left, level+2); rb_iprint_tree(t->c.child.right, level+2); for (i = 0; i < level; i++) putchar(' '); printf("Int node 0x%p: %c,%c: l=0x%p, r=0x%p, p=0x%p, lr=(%d,%d)\n", (void *) t, isred(t)?'R':'B', isleft(t)?'l':'r', (void *) t->c.child.left, (void *) t->c.child.right, (void *) t->p.parent, t->k.lext->k.ikey, t->v.rext->k.ikey); } } }
static JRB jrb_insert_b(JRB n, Jval key, Jval val) { JRB newleft, newright, newnode, p; if (ishead(n)) { if (n->parent == n) { /* Tree is empty */ mk_new_ext(newnode, key, val); insert(newnode, n); n->parent = newnode; newnode->parent = n; setroot(newnode); return newnode; } else { mk_new_ext(newright, key, val); insert(newright, n); newleft = newright->blink; setnormal(newleft); mk_new_int(newleft, newright, newleft->parent, isleft(newleft)); p = rprev(newright); if (!ishead(p)) setlext(p, newright); return newright; } } else { mk_new_ext(newleft, key, val); insert(newleft, n); setnormal(n); mk_new_int(newleft, n, n->parent, isleft(n)); p = lprev(newleft); if (!ishead(p)) setrext(p, newleft); return newleft; } }
void jrb_iprint_tree(JRB t, int level) { int i; if (ishead(t) && t->parent == t) { printf("tree 0x%x is empty\n", t); } else if (ishead(t)) { printf("Head: 0x%x. Root = 0x%x, < = 0x%x, > = 0x%x\n", t, t->parent, t->blink, t->flink); jrb_iprint_tree(t->parent, 0); } else { if (isext(t)) { for (i = 0; i < level; i++) putchar(' '); printf("Ext node 0x%x: %c,%c: p=0x%x, <=0x%x, >=0x%x k=%d\n", t, isred(t)?'R':'B', isleft(t)?'l':'r', t->parent, t->blink, t->flink, t->key.i); } else { jrb_iprint_tree(t->flink, level+2); jrb_iprint_tree(t->blink, level+2); for (i = 0; i < level; i++) putchar(' '); printf("Int node 0x%x: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%d,%d)\n", t, isred(t)?'R':'B', isleft(t)?'l':'r', t->flink, t->blink, t->parent, getlext(t)->key.i, getrext(t)->key.i); } } }
Rb_node rb_insert_b(Rb_node n, char *key, char *val) { Rb_node newleft, newright, newnode, p; if (ishead(n)) { if (n->p.root == n) { /* Tree is empty */ mk_new_ext(newnode, key, val); insert(newnode, n); n->p.root = newnode; newnode->p.parent = n; setroot(newnode); return newnode; } else { mk_new_ext(newright, key, val); insert(newright, n); newleft = newright->c.list.blink; setnormal(newleft); mk_new_int(newleft, newright, newleft->p.parent, isleft(newleft)); p = rprev(newright); if (!ishead(p)) p->k.lext = newright; return newright; } } else { mk_new_ext(newleft, key, val); insert(newleft, n); setnormal(n); mk_new_int(newleft, n, n->p.parent, isleft(n)); p = lprev(newleft); if (!ishead(p)) p->v.rext = newleft; return newleft; } }
bool isValid(string s) { // Start typing your C/C++ solution below // DO NOT write int main() function if(s.size()==0) return false; stack<char> sck; sck.push(s[0]); int cur = 1; while(cur<s.size()) { char curchar = s[cur]; if(isright(curchar)) { if(sck.empty()) //Need to return false if the right parenthese is entered when sck is empty, we need to this case on the top because the second case need the stack to be not empty return false; if(!ispair(sck.top(),curchar)) //Need to check if sck is empty before peek, or the empty stack has been checked and returned if empty { return false; } if(!sck.empty()) //Need to pop in the valid case, cannot be on top of the second case sck.pop(); } else if(isleft(curchar)) sck.push(curchar); else return false; cur++; } if(cur!=s.size() || !sck.empty()) return false; return true; }
static void recolor(JRB n) { JRB p, gp, s; int done = 0; while (!done) { if (isroot(n)) { setblack(n); return; } p = n->parent; if (isblack(p)) return; if (isroot(p)) { setblack(p); return; } gp = p->parent; s = sibling(p); if (isred(s)) { setblack(p); setred(gp); setblack(s); n = gp; } else { done = 1; } } /* p's sibling is black, p is red, gp is black */ if ((isleft(n) == 0) == (isleft(p) == 0)) { single_rotate(gp, isleft(n)); setblack(p); setred(gp); } else { single_rotate(p, isleft(n)); single_rotate(gp, isleft(n)); setblack(n); setred(gp); } }
node * brother(node *nd) { if(!father(nd)) return NULL; if(isleft(nd)) return right(father(nd)); return left(father(nd)); }
Rb_node rprev(Rb_node n) { if (ishead(n)) return n; while (!isroot(n)) { if (isleft(n)) return n->p.parent; n = n->p.parent; } return n->p.parent; }
JRB rprev(JRB n) { if (ishead(n)) return n; while (!isroot(n)) { if (isleft(n)) return n->parent; n = n->parent; } return n->parent; }
static void single_rotate(JRB y, int l) { int rl, ir; JRB x, yp; char *tmp; ir = isroot(y); yp = y->parent; if (!ir) { rl = isleft(y); } if (l) { x = y->flink; y->flink = x->blink; setleft(y->flink); y->flink->parent = y; x->blink = y; setright(y); } else { x = y->blink; y->blink = x->flink; setright(y->blink); y->blink->parent = y; x->flink = y; setleft(y); } x->parent = yp; y->parent = x; if (ir) { yp->parent = x; setnormal(y); setroot(x); } else { if (rl) { yp->flink = x; setleft(x); } else { yp->blink = x; setright(x); } } }
static void single_rotate(Rb_node y, int l) { int rl, ir; Rb_node x, yp; ir = isroot(y); yp = y->p.parent; if (!ir) { rl = isleft(y); } if (l) { x = y->c.child.left; y->c.child.left = x->c.child.right; setleft(y->c.child.left); y->c.child.left->p.parent = y; x->c.child.right = y; setright(y); } else { x = y->c.child.right; y->c.child.right = x->c.child.left; setright(y->c.child.right); y->c.child.right->p.parent = y; x->c.child.left = y; setleft(y); } x->p.parent = yp; y->p.parent = x; if (ir) { yp->p.root = x; setnormal(y); setroot(x); } else { if (rl) { yp->c.child.left = x; setleft(x); } else { yp->c.child.right = x; setright(x); } } }
int grammarAnalyze(const char* line) { int ret = 0; if (line == NULL) return -1; int i = 0; LinkStack *stack = NULL; stack = LinkStack_Create(); if (stack == NULL) return -2; while (*(line + i) != '\0') { if (isalpha(line[i])) { i++; continue; } else if (isleft(line[i])) { LinkStack_Push(stack, (void *)&line[i]); } else if (isright(line[i])) { char *tmp; tmp = (char *)LinkStack_Pop(stack); if (tmp == NULL || !ismatch(*tmp, line[i])) { break; } } i++; } if (LinkStack_Size(stack) == 0 && line[i] == '\0') { ret = 1; } LinkList_Destroy(stack); return ret; }
obj *circgen(type) { static float rad[2] = { HT2, WID2 }; static float rad2[2] = { HT2, HT2 }; static float x0, y0, x1, y1, x2, y2; int i, at, t, invis, ddtype, with; float xwith, ywith; float r, r2, ddval; obj *p, *ppos; Attr *ap; at = invis = ddtype = 0; with = xwith = ywith = 0; t = (type == CIRCLE) ? 0 : 1; if (type == CIRCLE) r = r2 = getfval("circlerad"); else if (type == ELLIPSE) { r = getfval("ellipsewid") / 2; r2 = getfval("ellipseht") / 2; } for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case RADIUS: r = ap->a_val.f; break; case DIAMETER: case WIDTH: r = ap->a_val.f / 2; break; case HEIGHT: r2 = ap->a_val.f / 2; break; case SAME: r = rad[t]; r2 = rad2[t]; break; case WITH: with = ap->a_val.i; break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case INVIS: invis = INVIS; break; case DOT: case DASH: ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; } } if (type == CIRCLE) r2 = r; /* probably superfluous */ if (with) { switch (with) { case NORTH: ywith = -r2; break; case SOUTH: ywith = r2; break; case EAST: xwith = -r; break; case WEST: xwith = r; break; case NE: xwith = -r * 0.707; ywith = -r2 * 0.707; break; case SE: xwith = -r * 0.707; ywith = r2 * 0.707; break; case NW: xwith = r * 0.707; ywith = -r2 * 0.707; break; case SW: xwith = r * 0.707; ywith = r2 * 0.707; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; } p = makenode(type, 2); p->o_val[0] = rad[t] = r; p->o_val[1] = rad2[t] = r2; if (r <= 0 || r2 <= 0) { yyerror("%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2); } p->o_attr = invis | ddtype; extreme(curx+r, cury+r2); extreme(curx-r, cury-r2); if (type == CIRCLE) dprintf("C %g %g %g\n", curx, cury, r); if (type == ELLIPSE) dprintf("E %g %g %g %g\n", curx, cury, r, r2); if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; return(p); }
obj * circgen(int type) { static double rad[2] = { HT2, WID2 }; static double rad2[2] = { HT2, HT2 }; struct objattr obat; double xwith, ywith, r, r2; int i, at, t, with; obj *p, *ppos; Attr *ap; obat.a_layer = (int)getfval("curlayer"); obat.a_flags = EDGED; obat.a_weight = obat.a_lcolor = obat.a_pcolor = obat.a_tcolor = -1; obat.a_dashpat.a = (float *)0; at = with = xwith = ywith = 0; if ((t = (type == CIRCLE) ? 0 : 1)) { r = getfval("ellipsewid") / 2; r2 = getfval("ellipseht") / 2; } else r = r2 = getfval("circlerad"); set_text(); for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { default: miscattrs(ap, &obat); break; case RADIUS: r = ap->a_val.f; break; case DIAMETER: case WIDTH: r = ap->a_val.f / 2; break; case HEIGHT: r2 = ap->a_val.f / 2; break; case SAME: r = rad[t]; r2 = rad2[t]; break; case WITH: with = ap->a_val.i; break; case AT: ppos = ap->a_val.o; curx = Xformx(ppos, 1, ppos->o_x, ppos->o_y); cury = Xformy(ppos, 0, ppos->o_x, ppos->o_y); at++; break; } } if (type == CIRCLE) r2 = r; /* probably superfluous */ if (with) { if (pic_compat) /* map NE to 2nd, etc. */ with = with == NE ? 2 : with == NW ? 4 : with == SW ? 6 : with == SE ? 8 : with; switch (with) { case NORTH: ywith = -r2; break; case SOUTH: ywith = r2; break; case EAST: xwith = -r; break; case WEST: xwith = r; break; case NE: xwith = -r; ywith = -r2; break; case SE: xwith = -r; ywith = r2; break; case NW: xwith = r; ywith = -r2; break; case SW: xwith = r; ywith = r2; break; case CENTER: case START: case END: break; default: xwith = -r * xdelta[with % 8]; ywith = -r2 * ydelta[with % 8]; if (with % 2 == 0) { xwith *= M_SQRT1_2; ywith *= M_SQRT1_2; } break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; } if (r <= 0 || r2 <= 0) yyerror("%s has invalid radius %g", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2); p = makenode(type, N_VAL, obat.a_layer); p->o_wid = 2 * (rad[t] = r); p->o_ht = 2 * (rad2[t] = r2); primattrs(p, &obat); text_bounds(p); if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; r += p->o_weight/2; r2 += p->o_weight/2; track_bounds (p->o_x - r, p->o_y - r2, p->o_x + r, p->o_y + r2); return(p); }
obj *boxgen(void) { static double prevh = HT; static double prevw = WID; /* golden mean, sort of */ int i, at, battr, with; double ddval, fillval, xwith, ywith; double h, w, x0, y0, x1, y1; obj *p, *ppos; Attr *ap; h = getfval("boxht"); w = getfval("boxwid"); at = battr = with = 0; ddval = fillval = xwith = ywith = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case HEIGHT: h = ap->a_val.f; break; case WIDTH: w = ap->a_val.f; break; case SAME: h = prevh; w = prevw; break; case WITH: with = ap->a_val.i; /* corner */ break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case INVIS: battr |= INVIS; break; case NOEDGE: battr |= NOEDGEBIT; break; case DOT: case DASH: battr |= ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; case FILL: battr |= FILLBIT; if (ap->a_sub == DEFAULT) fillval = getfval("fillval"); else fillval = ap->a_val.f; break; case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; } } if (with) { switch (with) { case NORTH: ywith = -h / 2; break; case SOUTH: ywith = h / 2; break; case EAST: xwith = -w / 2; break; case WEST: xwith = w / 2; break; case NE: xwith = -w / 2; ywith = -h / 2; break; case SE: xwith = -w / 2; ywith = h / 2; break; case NW: xwith = w / 2; ywith = -h / 2; break; case SW: xwith = w / 2; ywith = h / 2; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += w / 2; else if (isleft(hvmode)) curx -= w / 2; else if (isup(hvmode)) cury += h / 2; else cury -= h / 2; } x0 = curx - w / 2; y0 = cury - h / 2; x1 = curx + w / 2; y1 = cury + h / 2; extreme(x0, y0); extreme(x1, y1); p = makenode(BOX, 2); p->o_val[0] = w; p->o_val[1] = h; p->o_attr = battr; p->o_ddval = ddval; p->o_fillval = fillval; dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w); if (isright(hvmode)) curx = x1; else if (isleft(hvmode)) curx = x0; else if (isup(hvmode)) cury = y1; else cury = y0; prevh = h; prevw = w; return(p); }
obj* blockgen(obj *p, obj *q) /* handles [...] */ { int i, invis, at, with; double ddval, h, w, xwith, ywith; double x0, y0, x1, y1, cx, cy; obj *ppos; Attr *ap; invis = at = 0; with = xwith = ywith = 0; ddval = 0; w = p->o_val[2] - p->o_val[0]; h = p->o_val[3] - p->o_val[1]; cx = (p->o_val[2] + p->o_val[0]) / 2; /* geom ctr of [] wrt local orogin */ cy = (p->o_val[3] + p->o_val[1]) / 2; dprintf("cx,cy=%g,%g\n", cx, cy); for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case HEIGHT: h = ap->a_val.f; break; case WIDTH: w = ap->a_val.f; break; case WITH: with = ap->a_val.i; /* corner */ break; case PLACE: /* actually with position ... */ ppos = ap->a_val.o; xwith = cx - ppos->o_x; ywith = cy - ppos->o_y; with = PLACE; break; case AT: case FROM: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case INVIS: invis = INVIS; break; case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; } } if (with) { switch (with) { case NORTH: ywith = -h / 2; break; case SOUTH: ywith = h / 2; break; case EAST: xwith = -w / 2; break; case WEST: xwith = w / 2; break; case NE: xwith = -w / 2; ywith = -h / 2; break; case SE: xwith = -w / 2; ywith = h / 2; break; case NW: xwith = w / 2; ywith = -h / 2; break; case SW: xwith = w / 2; ywith = h / 2; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += w / 2; else if (isleft(hvmode)) curx -= w / 2; else if (isup(hvmode)) cury += h / 2; else cury -= h / 2; } x0 = curx - w / 2; y0 = cury - h / 2; x1 = curx + w / 2; y1 = cury + h / 2; extreme(x0, y0); extreme(x1, y1); p->o_x = curx; p->o_y = cury; p->o_nt1 = ntext1; p->o_nt2 = ntext; ntext1 = ntext; p->o_val[0] = w; p->o_val[1] = h; p->o_val[2] = cx; p->o_val[3] = cy; p->o_val[5] = q->o_nobj - 1; /* last item in [...] */ p->o_ddval = ddval; p->o_attr = invis; dprintf("[] %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w); if (isright(hvmode)) curx = x1; else if (isleft(hvmode)) curx = x0; else if (isup(hvmode)) cury = y1; else cury = y0; for (i = 0; i <= 5; i++) q->o_val[i] = p->o_val[i]; stack[nstack+1].p_symtab = NULL; /* so won't be found again */ blockadj(p); /* fix up coords for enclosed blocks */ return(p); }
obj *textgen(void) { int i, sub, nstr, at, with, hset, invis; double xwith, ywith, h, w, x0, y0, x1, y1; obj *p, *ppos; Attr *ap; at = with = nstr = hset = invis = 0; h = getfval("textht"); w = getfval("textwid"); for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case HEIGHT: h = ap->a_val.f; hset++; break; case WIDTH: w = ap->a_val.f; break; case WITH: with = ap->a_val.i; break; case INVIS: invis = INVIS; break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case TEXTATTR: sub = ap->a_sub; if (ap->a_val.p == NULL) /* an isolated modifier */ text[ntext-1].t_type = sub; else { savetext(sub, ap->a_val.p); nstr++; } break; } } if (hset == 0) /* no explicit ht cmd */ h *= nstr; if (with) { xwith = ywith = 0.0; switch (with) { case NORTH: ywith = -h / 2; break; case SOUTH: ywith = h / 2; break; case EAST: xwith = -w / 2; break; case WEST: xwith = w / 2; break; case NE: xwith = -w / 2; ywith = -h / 2; break; case SE: xwith = -w / 2; ywith = h / 2; break; case NW: xwith = w / 2; ywith = -h / 2; break; case SW: xwith = w / 2; ywith = h / 2; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += w / 2; else if (isleft(hvmode)) curx -= w / 2; else if (isup(hvmode)) cury += h / 2; else cury -= h / 2; } x0 = curx - w / 2; y0 = cury - h / 2; x1 = curx + w / 2; y1 = cury + h / 2; extreme(x0, y0); extreme(x1, y1); dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury); p = makenode(TEXT, 2); p->o_attr = invis; p->o_val[0] = w; p->o_val[1] = h; if (isright(hvmode)) curx = x1; else if (isleft(hvmode)) curx = x0; else if (isup(hvmode)) cury = y1; else cury = y0; return(p); }
void jrb_delete_node(JRB n) { JRB s, p, gp; char ir; if (isint(n)) { fprintf(stderr, "Cannot delete an internal node: 0x%p\n", (void *)n); exit(1); } if (ishead(n)) { fprintf(stderr, "Cannot delete the head of an jrb_tree: 0x%p\n", (void *)n); exit(1); } delete_item(n); /* Delete it from the list */ p = n->parent; /* The only node */ if (isroot(n)) { p->parent = p; free(n); return; } s = sibling(n); /* The only node after deletion */ if (isroot(p)) { s->parent = p->parent; s->parent->parent = s; setroot(s); free(p); free(n); return; } gp = p->parent; /* Set parent to sibling */ s->parent = gp; if (isleft(p)) { gp->flink = s; setleft(s); } else { gp->blink = s; setright(s); } ir = isred(p); free(p); free(n); if (isext(s)) { /* Update proper rext and lext values */ p = lprev(s); if (!ishead(p)) setrext(p, s); p = rprev(s); if (!ishead(p)) setlext(p, s); } else if (isblack(s)) { fprintf(stderr, "DELETION PROB -- sib is black, internal\n"); exit(1); } else { p = lprev(s); if (!ishead(p)) setrext(p, s->flink); p = rprev(s); if (!ishead(p)) setlext(p, s->blink); setblack(s); return; } if (ir) return; /* Recolor */ n = s; p = n->parent; s = sibling(n); while(isblack(p) && isblack(s) && isint(s) && isblack(s->flink) && isblack(s->blink)) { setred(s); n = p; if (isroot(n)) return; p = n->parent; s = sibling(n); } if (isblack(p) && isred(s)) { /* Rotation 2.3b */ single_rotate(p, isright(n)); setred(p); setblack(s); s = sibling(n); } { JRB x, z; char il; if (isext(s)) { fprintf(stderr, "DELETION ERROR: sibling not internal\n"); exit(1); } il = isleft(n); x = il ? s->flink : s->blink ; z = sibling(x); if (isred(z)) { /* Rotation 2.3f */ single_rotate(p, !il); setblack(z); if (isred(p)) setred(s); else setblack(s); setblack(p); } else if (isblack(x)) { /* Recoloring only (2.3c) */ if (isred(s) || isblack(p)) { fprintf(stderr, "DELETION ERROR: 2.3c not quite right\n"); exit(1); } setblack(p); setred(s); return; } else if (isred(p)) { /* 2.3d */ single_rotate(s, il); single_rotate(p, !il); setblack(x); setred(s); return; } else { /* 2.3e */ single_rotate(s, il); single_rotate(p, !il); setblack(x); return; } } }
/* chainhull2d(): Andrew's monotone chain 2D convex hull algorithm Input: p[] = an array of 2D points presorted by increasing x- and y-coordinates n = the number of points in p[] Output: h[] = an array of the convex hull vertices (max is n) Return: the number of points in h[] */ int chainhull2d(struct p_s *p,int n,struct p_s *h) { /* the output array h[] will be used as the stack */ int bot=0, top=(-1); /* indices for bottom and top of the stack */ int i; /* array scan index */ int minmin,minmax,maxmin,maxmax; double xmin,xmax; int n2; /* sort by increasing x- and then y-coordinates */ qsort(p,n,sizeof(p[0]),compp); /* remove duplicates */ n2=1; for(i=1;i<n;i++) { if(i!=n2) p[n2]=p[i]; if(p[i].x!=p[i-1].x || p[i].y!=p[i-1].y) n2++; } n=n2; /* Get the indices of points with min x-coord and min|max y-coord */ minmin = 0; xmin = p[0].x; for(i=1;i<n;i++) if (p[i].x != xmin) break; minmax = i-1; if (minmax == n-1) { /* degenerate case: all x-coords == xmin */ h[++top] = p[minmin]; if (p[minmax].y != p[minmin].y) /* a nontrivial segment */ h[++top] = p[minmax]; h[++top] = p[minmin]; /* add polygon endpoint */ return top+1; } /* Get the indices of points with max x-coord and min|max y-coord */ maxmax = n-1; xmax = p[n-1].x; for (i=n-2; i>=0; i--) if (p[i].x != xmax) break; maxmin = i+1; /* Compute the lower hull on the stack H */ h[++top] = p[minmin]; /* push minmin point onto stack */ i = minmax; while (++i <= maxmin) { /* the lower line joins P[minmin] with P[maxmin] */ if (isleft( p[minmin], p[maxmin], p[i]) >= 0 && i < maxmin) continue; /* ignore P[i] above or on the lower line */ while (top > 0) { /* there are at least 2 points on the stack */ /* test if P[i] is left of the line at the stack top */ if (isleft( h[top-1], h[top], p[i]) > 0) break; /* P[i] is a new hull vertex */ else top--; /* pop top point off stack */ } h[++top] = p[i]; /* push P[i] onto stack */ } /* Next, compute the upper hull on the stack H above the bottom hull */ if (maxmax != maxmin) /* if distinct xmax points */ h[++top] = p[maxmax]; /* push maxmax point onto stack */ bot = top; /* the bottom point of the upper hull stack */ i = maxmin; while (--i >= minmax) { /* the upper line joins P[maxmax] with P[minmax] */ if (isleft( p[maxmax], p[minmax], p[i]) >= 0 && i > minmax) continue; /* ignore P[i] below or on the upper line */ while (top > bot) { /* at least 2 points on the upper stack */ /* test if P[i] is left of the line at the stack top */ if (isleft( h[top-1], h[top], p[i]) > 0) break; /* P[i] is a new hull vertex */ else top--; /* pop top point off stack */ } h[++top] = p[i]; /* push P[i] onto stack */ } if (minmax != minmin) h[++top] = p[minmin]; /* push joining endpoint onto stack */ return top; }