#include #include #include #include #include #include #include #include #include #include #include #include"BitmapFont.h" using namespace hgl; OSString csv_filename; using BitmapRGB8=bitmap::Bitmap; using BitmapRGBA8=bitmap::Bitmap; using BitmapU32=bitmap::Bitmap; using DrawBitmapU32=bitmap::DrawGeometry; using DrawBitmapRGBA8=bitmap::DrawGeometry; struct BlendColorU32Additive:public bitmap::BlendColor { const uint32 operator()(const uint32 &src,const uint32 &dst)const { uint64 result=src+dst; return (result>HGL_U32_MAX)?HGL_U32_MAX:(result&HGL_U32_MAX); } const uint32 operator()(const uint32 &src,const uint32 &dst,const float &alpha)const { uint64 result=src*alpha+dst; return (result>HGL_U32_MAX)?HGL_U32_MAX:(result&HGL_U32_MAX); } }; struct BlendColorRGBA8:public bitmap::BlendColor { const Vector4u8 operator()(const Vector4u8 &src,const Vector4u8 &dst)const { uint8 na=255-src.a; return Vector4u8((src.r*src.a+dst.r*na)/255, (src.g*src.a+dst.g*na)/255, (src.b*src.a+dst.b*na)/255, dst.a); } const Vector4u8 operator()(const Vector4u8 &src,const Vector4u8 &dst,const float &alpha)const { uint8 a=src.a*alpha; uint8 na=255-src.a; return Vector4u8((src.r*src.a+dst.r*na)/255, (src.g*src.a+dst.g*na)/255, (src.b*src.a+dst.b*na)/255, dst.a); } }; template<> void bitmap::BlendBitmap::operator()(const bitmap::Bitmap *src_bitmap,bitmap::Bitmap *dst_bitmap,const float alpha)const { if(!src_bitmap||!dst_bitmap||alpha<=0)return; const uint width=src_bitmap->GetWidth(); const uint height=src_bitmap->GetHeight(); if(width!=dst_bitmap->GetWidth()||height!=dst_bitmap->GetHeight()) return; Vector3u8 *dst=dst_bitmap->GetData(); const Vector4u8 *src=src_bitmap->GetData(); float a; float na; for(uint i=0;ia*alpha; na=255-src->a; dst->r=(src->r*a+dst->r*na)/255; dst->g=(src->g*a+dst->g*na)/255; dst->b=(src->b*a+dst->b*na)/255; ++dst; ++src; } } BitmapRGB8 *BackgroundBitmap=nullptr; using BlendRGBA2RGB=bitmap::BlendBitmap; bool LoadBackgroundBitmap() { io::OpenFileInputStream fis(OS_TEXT("mini_map.tga")); if(!fis) return(false); util::TGAHeader tga_header; util::TGAImageDesc tga_desc; fis->Read(&tga_header,sizeof(util::TGAHeader)); if(tga_header.image_type!=util::TGA_IMAGE_TYPE_TRUE_COLOR) return(false); if(tga_header.bit!=24) return(false); tga_desc.image_desc=tga_header.image_desc; BackgroundBitmap=new BitmapRGB8; BackgroundBitmap->Create(tga_header.width,tga_header.height); const uint total_bytes=BackgroundBitmap->GetTotalBytes(); if(fis->Read(BackgroundBitmap->GetData(),total_bytes)!=total_bytes) { delete BackgroundBitmap; BackgroundBitmap=nullptr; return(false); } if(tga_desc.direction==util::TGA_DIRECTION_LOWER_LEFT) BackgroundBitmap->Flip(); return(true); } uint CHAR_BITMAP_WIDTH=0; uint CHAR_BITMAP_HEIGHT=0; bool InitBitmapFont() { if(!LoadBitmapFont()) return(false); CHAR_BITMAP_WIDTH=GetCharWidth(); CHAR_BITMAP_HEIGHT=GetCharHeight(); return(true); } constexpr const float LOW_GAP=0.2f; constexpr const Vector4u8 black_color={0,0,0,255}; constexpr const Vector4u8 white_color={255,255,255,255}; constexpr const Vector4u8 stop_color[]= { { 0, 0,255,255}, { 0,255,255,255}, { 0,255, 0,255}, {255,255, 0,255}, {255, 0, 0,255} }; constexpr const uint STOP_COUNT=sizeof(stop_color)/sizeof(Vector4u8); uint stop_count[STOP_COUNT]; uint top_count=0; HGL_GRADIENT_DEFINE(GradientColor3u8,uint,Vector3u8) { result.r=start.r+float(end.r-start.r)*pos; result.g=start.g+float(end.g-start.g)*pos; result.b=start.b+float(end.b-start.b)*pos; } GradientColor3u8 ColorGradient; void InitGradient(uint max_count) { for(uint i=0;ix)) return(false); sp=cp+2; cp=hgl::strchr(sp,'Z'); if(!cp)return(false); if(!hgl::stoi(sp,result->y)) return(false); return(true); } struct PositionStat { uint count; Vector2i minp,maxp; Vector2i gap; Vector2i *data; public: PositionStat(const uint c) { count=c; hgl_zero(minp); hgl_zero(maxp); hgl_zero(gap); data=new Vector2i[count]; hgl_zero(data,count); } ~PositionStat() { delete[] data; } }; PositionStat *ToVector2i(const UTF8StringList &sl) { const uint count=sl.GetCount(); PositionStat *ps=new PositionStat(count); Vector2i *p=ps->data; UTF8String str; uint result=0; for(uint i=0;ix>=BackgroundBitmap->GetWidth() ||p->y>=BackgroundBitmap->GetHeight()) continue; //std::cout<<"X="<x<<",Y="<y<xminp.x)ps->minp.x=p->x; // if(p->x>ps->maxp.x)ps->maxp.x=p->x; // if(p->yminp.y)ps->minp.y=p->y; // if(p->y>ps->maxp.y)ps->maxp.y=p->y; ++result; ++p; } //std::cout<<"minp: "<minp.x<<","<minp.y<maxp.x<<","<maxp.y<maxp.x=1023; ps->maxp.y=1023; ps->count=result; return ps; } struct Chart { uint width,height; uint max_count; BitmapU32 count_bitmap; BitmapU32 circle_bitmap; BitmapRGBA8 chart_bitmap; DrawBitmapU32 *draw_circle=nullptr; BlendColorU32Additive blend_u32_additive; DrawBitmapRGBA8 *draw_chart=nullptr; BlendColorRGBA8 blend_rgba8; public: Chart(const uint w,const uint h) { width=w; height=h; count_bitmap.Create(width,height); circle_bitmap.Create(width,height); chart_bitmap.Create(width,height); count_bitmap.ClearColor(0); circle_bitmap.ClearColor(0); chart_bitmap.ClearColor(black_color); draw_circle=new DrawBitmapU32(&circle_bitmap); draw_circle->SetBlend(&blend_u32_additive); draw_chart=new DrawBitmapRGBA8(&chart_bitmap); draw_chart->SetBlend(&blend_rgba8); max_count=0; } ~Chart() { delete draw_chart; delete draw_circle; } void DrawCircle(uint x,uint y,uint radius) { draw_circle->SetDrawColor(1); draw_circle->DrawSolidCircle(x,y,radius); } private: void DrawChar(const char ch,const uint x,const uint y) { const uint8 *sp=GetBitmapChar(ch); if(!sp)return; draw_chart->DrawMonoBitmap(x,y,sp,CHAR_BITMAP_WIDTH,CHAR_BITMAP_HEIGHT); } public: void DrawString(const AnsiString &str,const uint x,const uint y,const Vector3u8 &stop_color) { const char *sp=str.c_str(); const uint len=str.Length(); uint pos=x; draw_chart->CloseBlend(); draw_chart->SetDrawColor(Vector4u8(stop_color,255)); for(uint i=0;iCloseBlend(); for(uint i=0;iSetDrawColor(color); draw_chart->DrawHLine(left,top+i,w); } } }; Chart *CreateChart() { const uint width=BackgroundBitmap->GetWidth(); const uint height=BackgroundBitmap->GetHeight(); std::cout<<"width: "<data; for(uint i=0;icount;i++) { x=p->x-ps->minp.x; y=p->y-ps->minp.y; cp32=count_bitmap.GetData(x,y); ++(*cp32); if(*cp32>top_count)top_count=*cp32; ++p; } } } void ChartStat(Chart *chart,const uint data_count) { const uint width=chart->width; const uint height=chart->height; //统计占比 { uint32 *cp32=chart->count_bitmap.GetData(); hgl_zero(stop_count); for(uint y=0;y0) for(uint i=0;itop_count*(STOP_COUNT-1-i)/STOP_COUNT) { stop_count[i]+=*cp32; break; } ++cp32; } } } //画圆 { uint32 *cp32=chart->count_bitmap.GetData(); for(uint y=0;y0) chart->DrawCircle(x,y,(*cp32)); ++cp32; } } } //统计最大值 { uint32 *cp32=chart->circle_bitmap.GetData(); for(uint i=0;ichart->max_count)chart->max_count=*cp32; ++cp32; } std::cout<<"max_count: "<max_count<max_count); //生成权重图 { uint32 *cp32=chart->circle_bitmap.GetData(); Vector4u8 *cp8=chart->chart_bitmap.GetData(); float alpha; Vector3u8 final_color; for(uint i=0;imax_count); ColorGradient.Get(final_color,*cp32); if(*cp32>0) //为了避免最后什么都看不见,所以把没数据的挑出来,剩下的透明度全部加0.25 { alpha+=LOW_GAP; if(alpha>1) alpha=1; } cp8->b=final_color.b; cp8->g=final_color.g; cp8->r=final_color.r; cp8->a=alpha*255.0f; ++cp32; ++cp8; } } if(CHAR_BITMAP_HEIGHT==0) return; //写入数值 { int col=10; int row=10; int stop_str_width=0; AnsiString str; AnsiString num_str; const AnsiString str_total=AnsiString::numberOf(data_count); AnsiString step_str[STOP_COUNT]; const uint dradient_bar_height=CHAR_BITMAP_HEIGHT*STOP_COUNT; char space[32]; memset(space,' ',32); for(uint i=0;iDrawString(str,col,row,black_color); row+=CHAR_BITMAP_HEIGHT*2; str=AnsiString("Total: ")+str_total; chart->DrawString(str,col,row,white_color); row+=CHAR_BITMAP_HEIGHT; chart->DrawGradient(col,row,CHAR_BITMAP_WIDTH,dradient_bar_height); col+=CHAR_BITMAP_WIDTH*2; chart->DrawGradient(col+(stop_str_width+1)*CHAR_BITMAP_WIDTH, row,CHAR_BITMAP_WIDTH,dradient_bar_height); chart->DrawGradient(col+(str_total.Length()+stop_str_width+4)*CHAR_BITMAP_WIDTH, row,CHAR_BITMAP_WIDTH,dradient_bar_height); for(uint i=0;i0) { num_str=AnsiString::floatOf(float(stop_count[i])*100.0f/float(data_count),4); str.Strcat(space,3+(8-num_str.Length())); str+=num_str; str+="%"; } chart->DrawString(str,col,row,stop_color[i]); row+=CHAR_BITMAP_HEIGHT; } } //混合底图 if(BackgroundBitmap) { BlendRGBA2RGB blend; blend(&(chart->chart_bitmap),BackgroundBitmap,1.0); } } int os_main(int argc,os_char **argv) { std::cout<<"Distribution Chart 2D"< ps=ToVector2i(sl); AutoDelete chart=CreateChart(); StatCount(chart->count_bitmap,ps); ChartStat(chart,ps->count); OSString tga_filename; { tga_filename=filesystem::ReplaceExtName(csv_filename,OSString(OS_TEXT(".tga"))); os_out<width,chart->height,3); io::OpenFileOutputStream fos(tga_filename.c_str(),io::FileOpenMode::CreateTrunc); if(fos) { fos->Write(&tga_header,util::TGAHeaderSize); fos->Write(BackgroundBitmap->GetData(),BackgroundBitmap->GetTotalBytes()); fos->Close(); } else std::cerr<<"Create chart.tga failed!"<