#include #include #include #include #include #include #include #include #include #define bytes(value) reinterpret_cast(value) #pragma pack(push, 1) struct BMPFileHeader { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; }; struct BMPInfoHeader { uint32_t biSize; int32_t biWidth; int32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; }; struct BGR { uint8_t b,g,r; }; #pragma pack(pop) struct vertex { float x,y; }; struct BGRHash { size_t operator()(const BGR& c) const noexcept { return (c.r<<16)|(c.g<<8)|c.b; } }; bool operator==(const BGR&a,const BGR&b){ return a.r==b.r && a.g==b.g && a.b==b.b; } BGR EMPTY_COLOR{255,255,255}; uint8_t* imageData; uint8_t* tempImageData; size_t width,height,rowSize; std::unordered_map>,BGRHash> pixelsPerProvincesPerState; inline BGR getPixelSafe(size_t r,size_t c){ if(r>=height||c>=width) return EMPTY_COLOR; return *reinterpret_cast( imageData + r*rowSize + c*3 ); } inline BGR getPixelSafeIndex(size_t i){ return getPixelSafe(i/width,i%width); } /* ================= FLOOD FILL ================= */ void FloodFill(){ size_t size=width*height; for(size_t i=0;i(tempImageData + (i/width)*rowSize + (i%width)*3)==EMPTY_COLOR) continue; BGR color=*reinterpret_cast(tempImageData + (i/width)*rowSize + (i%width)*3); std::vector prov; std::queue q; q.push(i); while(!q.empty()){ size_t n=q.front(); q.pop(); BGR& px=*reinterpret_cast(tempImageData + (n/width)*rowSize + (n%width)*3); if(px!=color) continue; px=EMPTY_COLOR; prov.push_back(n); if(n>=width) q.push(n-width); if(n+width&prov,BGR id){ for(size_t i:prov){ size_t r=i/width,c=i%width; if(getPixelSafe(r-1,c)!=id|| getPixelSafe(r+1,c)!=id|| getPixelSafe(r,c-1)!=id|| getPixelSafe(r,c+1)!=id) return i; } return std::numeric_limits::max(); } void FindContour(){ for(auto&[state,provs]:pixelsPerProvincesPerState){ for(auto&prov:provs){ if(prov.empty()) continue; BGR id=getPixelSafeIndex(prov[0]); size_t start=FindStart(prov,id); if(start==std::numeric_limits::max()) continue; std::vector contour; contour.push_back(start); size_t cur=start; size_t prev = (start % width > 0) ? start - 1 : start + 1; const size_t MAX=prov.size()*8; for(size_t i=0;i img(rowSize*height); std::vector tmp(rowSize*height); fin.seekg(fh.bfOffBits); fin.read((char*)img.data(),img.size()); fin.seekg(fh.bfOffBits); fin.read((char*)tmp.data(),tmp.size()); imageData=img.data(); tempImageData=tmp.data(); FloodFill(); FindContour(); Aproximate(0); Triangulate(); GenVertices(fout); }