#help_index "Graphics/CGrVectMap" /* This processes a monocrome map, finds edges and generates vect graphic representations of the map broken into small rectangles. The rectangles are encoded a bit-oriented structure. PolyLineStruct { 1 Bit : set is valid polyline, clear is end of polyline list (R_BITS) : X-coordinate of polyline start (R_BITS) : Y-coordinate of polyline start (poly_line_cnt_bits): Number of polyline direction entries N*3 : N-long seq of 1 pixel directional movements } FloodFillStruct { 1 Bit : set is valid flood fill entry, clear is end of floodfill list (1+R_BITS): X-coordinate*2 of flood fill (half pixels) (1+R_BITS): Y-coordinate*2 of flood fill (half pixels) } Rect { 1 Bit : set is valid rectangle entry, clear is end of rectangle list PolyLineStructList FloodFillStructList } */ #define R_BITS 6 #define R_BORDER 1 #define R_WIDTH (1<body; F64 d=scale/2; dc->pen_width=scale+0.5; dc->color=rect_dft=Bt(body,bit++); not_rect_dft=1-rect_dft; dc->bkcolor=vm->bkcolor; GrRect(dc,0,0,dc->width,dc->height); dc->color=not_rect_dft; while (Bt(body,bit++)) { j=BFieldExtU32(body,bit,R_BITS); bit+=R_BITS; i=BFieldExtU32(body,bit,R_BITS); bit+=R_BITS; cnt=BFieldExtU32(body,bit,vm->poly_line_cnt_bits); bit+=vm->poly_line_cnt_bits; if (!cnt) GrPlot3(dc,(j-R_BORDER)*scale+d,(i-R_BORDER)*scale+d,0); else { i0=i;j0=j; while (cnt--) { k=BFieldExtU32(body,bit,3); bit+=3; i+=gr_y_offsets[k]; j+=gr_x_offsets[k]; GrLine3(dc,(j0-R_BORDER)*scale+d,(i0-R_BORDER)*scale+d,0, (j-R_BORDER)*scale+d,(i-R_BORDER)*scale+d,0); i0=i; j0=j; } } } while (Bt(body,bit++)) { j=BFieldExtU32(body,bit,R_BITS+1); bit+=R_BITS+1; i=BFieldExtU32(body,bit,R_BITS+1); bit+=R_BITS+1; if (GrPeek(dc,(j/2.0-R_BORDER)*scale+d,(i/2.0-R_BORDER)*scale+d)==rect_dft) GrFloodFill(dc,(j/2.0-R_BORDER)*scale+d,(i/2.0-R_BORDER)*scale+d); } } class CMPVMBlot { CDC *dc,*rect_dc; CGrVectMap *vm; I64 bit; I64 xx,yy; F64 scale; I64 busy; }; U0 MPGrVectMapBlotRect(CMPVMBlot *mp) { GrVectMapBlotRect(mp->rect_dc,mp->vm,mp->bit,mp->scale); GrBlot(mp->dc,mp->xx,mp->yy,mp->rect_dc); mp->busy=FALSE; } public U0 GrVectMapBlotMP(CDC *dc,I64 x,I64 y,CGrVectMap *vm,F64 scale=1.0,I64 _mp_cnt=0) { I64 i,i_lo,i_hi,j,j_lo,j_hi,k,cpu,pass, w=(vm->width +R_WIDTH-1)/R_WIDTH, h=(vm->height+R_HEIGHT-1)/R_HEIGHT; F64 xx,yy,r_scale=scale*(R_WIDTH+1.0/scale)/R_WIDTH; CMPVMBlot *mp; if (!dc || !vm) return; if (Gs->num) _mp_cnt=1; //Only core #0 can be master else if (!_mp_cnt) _mp_cnt=mp_cnt; else if (_mp_cnt>mp_cnt) _mp_cnt=mp_cnt; cpu=_mp_cnt-1; mp=MAlloc(_mp_cnt*sizeof(CMPVMBlot)); for (i=0;i<_mp_cnt;i++) { mp[i].rect_dc=DCNew(DCT_COLOR8,R_WIDTH*r_scale,R_HEIGHT*r_scale,Fs); mp[i].dc=DCAlias(dc,dc->win_task); mp[i].dc->color=dc->color; mp[i].vm=vm; mp[i].scale=r_scale; mp[i].busy=FALSE; } if (y<0) i_lo=-y/(R_HEIGHT*scale); else i_lo=0; if (R_HEIGHT*scale*h+y>dc->height) i_hi=MinI64((dc->height-y)/(R_HEIGHT*scale)+1,h); else i_hi=h; if (x<0) j_lo=-x/(R_WIDTH*scale); else j_lo=0; if (R_WIDTH*scale*w+x>dc->width) j_hi=MinI64((dc->width-x)/(R_WIDTH*scale)+1,w); else j_hi=w; xx=x+j_lo*R_WIDTH*scale; for (j=j_lo;j1) { pass=0; //Does up to two passes while (TRUE) if (!pass && !cpu) { pass++; cpu=_mp_cnt-1; } else if (mp[cpu].busy) //by the way, core #0 is never busy cpu--; else break; } mp[cpu].xx=xx; mp[cpu].yy=yy; mp[cpu].bit=vm->rect_start_bits[k]; if (!cpu) MPGrVectMapBlotRect(mp); else { mp[cpu].busy=TRUE; MPJob(&MPGrVectMapBlotRect,&mp[cpu],cpu); } k+=w; yy+=R_HEIGHT*scale; } xx+=R_WIDTH*scale; } for (i=_mp_cnt-1;i>=0;i--) { while(mp[i].busy) Yield; DCDel(mp[i].rect_dc); DCDel(mp[i].dc); } Free(mp); } Bool IsSolidSquare(CDC *dc,I64 x,I64 y,I64 edge,CColorROPU32 color) { I64 i,j; edge>>=1; for (i=-edge;ibody; Bool found; if (_max_poly_line_cnt_bits) max_poly_line_cnt_bits=*_max_poly_line_cnt_bits; else max_poly_line_cnt_bits=3; //Count ON pixels for (y=0;y=R_WIDTH*R_HEIGHT/2) rect_dft=1; else rect_dft=0; not_rect_dft=1-rect_dft; BEqu(body,bit++,rect_dft); if (!cnt || cnt==R_WIDTH*R_HEIGHT) { //Rect is all ON or OFF Btr(body,bit++); //End of poly-line list Btr(body,bit++); //End of flood-fill list } else { for (y=0;ycolor=0; if (GrPeek(b_desired,x,y)==not_rect_dft) for (k=0;k<8;k++) if (GrPeek(b_desired,x+gr_x_offsets[k],y+gr_y_offsets[k])==rect_dft) b_edge->color=1; GrPlot(b_edge,x,y); } b_edge->color=0; link_bit1=bit; for (y=0;ymax_poly_line_cnt_bits) max_poly_line_cnt_bits=Bsr(cnt)+1; } //Connect adjacent groups with link to prevent flood-fill leaks. link_bit_limit=bit; while (link_bit1color=1; GrPlot(b_link_check,xx,yy); cnt=BFieldExtU32(body,link_bit2,poly_line_cnt_bits); link_bit2+=poly_line_cnt_bits; while (cnt--) { kk=BFieldExtU32(body,link_bit2,3); link_bit2+=3; yy+=gr_y_offsets[kk]; xx+=gr_x_offsets[kk]; GrPlot(b_link_check,xx,yy); } link_bit1=link_bit2; } Btr(body,bit++); //End of poly-line list b_desired->color=rect_dft; GrLineRect4(b_desired,0,0,R_WIDTH+2*R_BORDER-1,R_HEIGHT+2*R_BORDER-1); Btr(body,bit); //Temp end of flood-fill list for (step_bits=2;step_bits>=1;step_bits-=1) { step=1<color=not_rect_dft; GrLineRect4(b_actual,0,0,R_WIDTH+2*R_BORDER-1,R_HEIGHT+2*R_BORDER-1); //Flood fill for (y=R_BORDER;y>step_bits,y>>step_bits)==rect_dft) { Bts(body,bit++); //Show not end of flood-fill list yy=y; xx=x; for (k=0;k<4;k++) { yy2=yy; while (yy2>step_bits,yy2>>step_bits)==rect_dft) yy2++; while (yy>R_BORDER && IsSolidSquare(b_desired,xx,yy,step,not_rect_dft) && GrPeek(b_actual,xx>>step_bits,yy>>step_bits)==rect_dft) yy--; yy1=yy+yy2; yy=yy1/2; xx2=xx; while (xx2>step_bits,yy>>step_bits)==rect_dft) xx2++; while (xx>R_BORDER && IsSolidSquare(b_desired,xx,yy,step,not_rect_dft) && GrPeek(b_actual,xx>>step_bits,yy>>step_bits)==rect_dft) xx--; xx1=xx+xx2; xx=xx1/2; } GrFloodFill(b_actual,xx>>step_bits,yy>>step_bits); BFieldOrU32(body,bit,xx1); //Flood fill X-coordinate in rect bit+=R_BITS+1; BFieldOrU32(body,bit,yy1); //Flood fill Y-coordinate in rect bit+=R_BITS+1; } DCDel(b_actual); Btr(body,bit); //Temp end of flood-fill list } bit++; //End of flood-fill list } DCDel(b_desired); DCDel(b_edge); DCDel(b_link_check); if (_max_poly_line_cnt_bits) *_max_poly_line_cnt_bits=max_poly_line_cnt_bits; return bit-_bit; } #define TEMP_BODY_SIZE 0x10000 public CGrVectMap *DC2VectMap(CDC *dc,CTask *mem_task=NULL,I64 *_size=NULL) { //Currently does not convert outer 1 pixel border I64 i,j,k,cnt,size, w=(dc->width-R_BORDER*2+R_WIDTH-1)/R_WIDTH, h=(dc->height-R_BORDER*2+R_HEIGHT-1)/R_HEIGHT, rect_cnt=w*h,poly_line_cnt_bits=12,max_poly_line_cnt_bits=3; U32 *rect_start_bits; U8 *body; CGrVectMap *result,tempv; body=MAlloc(TEMP_BODY_SIZE); //Pass 1: Get max_poly_line_cnt_bits for (i=0;iwidth-R_BORDER*2; tempv.height=dc->height-R_BORDER*2; tempv.body=body; tempv.rect_cnt=rect_cnt; tempv.r_bits=R_BITS; tempv.poly_line_cnt_bits=poly_line_cnt_bits; GrVectizeRect(dc,R_BORDER+j*R_WIDTH,R_BORDER+i*R_HEIGHT,&tempv,0,poly_line_cnt_bits,&max_poly_line_cnt_bits); } //Pass 2: Get cnt poly_line_cnt_bits=max_poly_line_cnt_bits; cnt=0; for (i=0;iwidth-R_BORDER*2; tempv.height=dc->height-R_BORDER*2; tempv.body=body; tempv.rect_cnt=rect_cnt; tempv.r_bits=R_BITS; tempv.poly_line_cnt_bits=poly_line_cnt_bits; cnt+=GrVectizeRect(dc,R_BORDER+j*R_WIDTH,R_BORDER+i*R_HEIGHT,&tempv,0,poly_line_cnt_bits,NULL); } Free(body); //Pass 3 size=(cnt+7)/8; result=CAlloc(sizeof(CGrVectMap),mem_task); result->body=CAlloc(size,mem_task); rect_start_bits=MAlloc((rect_cnt+1)*sizeof(U32),mem_task); result->width =dc->width-R_BORDER*2; result->height=dc->height-R_BORDER*2; result->rect_cnt=rect_cnt; result->r_bits=R_BITS; result->poly_line_cnt_bits=poly_line_cnt_bits; result->rect_start_bits=rect_start_bits; k=0; cnt=0; for (i=0;irect_start_bits); Free(vm->body); Free(vm); } U32 *GrVectMapRectStartBits(CGrVectMap *vm,CTask *mem_task=NULL) { I64 k=0,bit=0; U8 *body=vm->body; U32 *result=MAlloc((vm->rect_cnt+1)*sizeof(U32),mem_task); for (k=0;krect_cnt;k++) { result[k]=bit++; while (Bt(body,bit++)) { bit+=2*R_BITS; bit+=vm->poly_line_cnt_bits+3*BFieldExtU32(body,bit,vm->poly_line_cnt_bits); } while (Bt(body,bit++)) bit+=2*(R_BITS+1); } result[k]=bit; return result; }