// // RandomGridFiller.cpp // auto_fill_jewel_v3 // // Created by Red on 2024/11/26. // #include "RandomGridFiller.hpp" #include "BoostGeometryTools.hpp" #include #include using std::cout; using std::endl; void RandomGridFiller::fill( vector& jewelsArray , //需要填充的宝石 float bottomLeftX,float bottomLeftY,//盘子有效区域 float topRightX,float topRightY, //盘子有效区域 vector& results //填充结果 ) { results.clear() ; if( jewelsArray.size()==0 ) return ; float width = topRightX - bottomLeftX + 1; float height = topRightY - bottomLeftY+ 1; float minJewWid = jewelsArray[0]._width ; float minJewHei = jewelsArray[0]._height; for(auto it = jewelsArray.begin()+1;it!=jewelsArray.end();++it ) { minJewWid = fmin( minJewWid, it->_width ) ; minJewHei = fmin( minJewHei, it->_height) ; } float gridWid = width/20; float gridHei = height/20; int nrows = width / gridWid ; int ncols = height/ gridHei ; vector potPositions ; for(int irow = 0 ; irow < nrows; ++ irow ) { for(int icol=0;icol fillResults ; float jewDistSum=0; int cov = 0 ; int badcnt = randomFillOneRound(jewelsArray, bottomLeftX, bottomLeftY, topRightX, topRightY, potPositions, fillResults, jewDistSum,gridWid,gridHei,cov); //cout<<"itry-"<& jewelsArray, float bottomLeftX,float bottomLeftY,//盘子有效区域 float topRightX,float topRightY, //盘子有效区域 vector potPositions, //潜在的点位 vector& results, float& jewDistanceSum ,const float gridWid ,const float gridHei ,int& resultTotCov ) { results.clear() ; vector jewIndices ; for(int ij=0;ij distPositions ; generateDistanceRandomSlotPositions(bottomLeftX+(topRightX-bottomLeftX)/2, bottomLeftY+(topRightY-bottomLeftY)/2, potPositions, distPositions) ; //使用网格描述盘子点位占用情况 const int GRID_X_NUM = (topRightX - bottomLeftX+1)/gridWid ; const int GRID_Y_NUM = (topRightY - bottomLeftY+1)/gridHei ; //每个宝石分配一个占用格点数据,用于标记该宝石在盘子中的痕迹 vector< GridData > jewelGridDataArray(jewIndices.size()) ; for(int ij=0;ij resultsJewIndices ; vector randIndicesOfJewIndices = randIndices(jewIndices.size()) ; for(int ij = 0 ; ij < randIndicesOfJewIndices.size() ; ++ij ) { int randJewIndex = randIndicesOfJewIndices[ij] ; int jewTypeIndex = jewIndices[randIndicesOfJewIndices[ij]] ; JewelBox& jewBox = jewelsArray[jewTypeIndex] ; int rotdeg = rand()%360 ; BoostGeometryTools::BoostPolygon jewPoly = BoostGeometryTools::makeRotatedBox( -jewBox._width/2, -jewBox._height/2, jewBox._width, jewBox._height , rotdeg) ; float plateCenterX = bottomLeftX+(topRightX-bottomLeftX)/2 ; float plateCenterY = bottomLeftY+(topRightY-bottomLeftY)/2 ; vector tempFillResults ; vector sumOfTakenCountArray ;//保留占位数求和 vector dist2CenterArray ; const int NUM_TRY = distPositions.size() ;//最大尝试数量 int itry = 0 ;//尝试数量 //将潜在点位按照距离盘子中心的距离进行排序,宝石按照这个距离进行填入盘子 vector positionIndices ; //逐个尝试,尝试NUM_TRY,保留占位数求和最少的。 for(int ip = 0 ; ip < distPositions.size();++ ip ) { if( distPositions[ip]._isTaken ) continue ;//位置占用跳过 ContourData::Point posi = distPositions[ip]._point ; BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jewPoly, posi.x, posi.y) ; //是否落在盘子内部 bool isJewWithinPlate = BoostGeometryTools::isAWithinB(jpoly2, plateBox) ; if( isJewWithinPlate ) { float dist1 = sqrt( (posi.x-plateCenterX)*(posi.x-plateCenterX)+(posi.y-plateCenterY)*(posi.y-plateCenterY) ); itry ++ ; FillResult fr ; fr._jewelTypeId = jewBox._jewelTypeId ; fr._rotdeg = rotdeg ; fr._x = posi.x ; fr._y = posi.y ; fr._width = jewBox._width ; fr._height = jewBox._height ; tempFillResults.push_back(fr) ; int tsum = totalCoverageGridCount(jpoly2, jewelGridDataArray) ; //cout<<"ij-"<0 ) { FillResult fr = tempFillResults[0] ; int tsum = sumOfTakenCountArray[0] ; int posiIndex =positionIndices[0] ; float tdist = dist2CenterArray[0] ; for(int itry1 = 0 ; itry1 < tempFillResults.size();++ itry1 ) { if( tsum > sumOfTakenCountArray[itry1]) { tsum = sumOfTakenCountArray[itry1] ; tdist = dist2CenterArray[itry1]; fr = tempFillResults[itry1] ; posiIndex =positionIndices[itry1] ; }else if( tsum == sumOfTakenCountArray[itry1] && tdist < dist2CenterArray[itry1] ) { tsum = sumOfTakenCountArray[itry1] ; tdist = dist2CenterArray[itry1]; fr = tempFillResults[itry1] ; posiIndex =positionIndices[itry1] ; } } distPositions[posiIndex]._isTaken = true ;//记录位置已经占用 num2fill-- ; BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jewPoly, fr._x, fr._y) ; setGridCoverageByBox(jpoly2, jewelGridDataArray[randJewIndex]);//写入子网格数据 results.push_back(fr);//记录最优结果 resultsJewIndices.push_back(randJewIndex) ; } } //重新计算覆盖度(这个看上去好像解决不了什么问题)后面可以删掉这部分代码 vector coverageArray(results.size(),0 ) ; resultTotCov = 0; for(int ij = 0 ; ij < results.size();++ij ) { FillResult& fr = results[ij] ; int jewIndex = resultsJewIndices[ij] ; BoostGeometryTools::BoostPolygon jpoly = BoostGeometryTools::makeRotatedBox(-fr._width/2,-fr._height/2, fr._width,fr._height , fr._rotdeg) ; BoostGeometryTools::BoostPolygon jpoly2 = BoostGeometryTools::translatePolygon(jpoly, fr._x, fr._y) ; coverageArray[jewIndex] = totalCoverageGridCount(jpoly2, jewelGridDataArray, jewIndex ) ; //cout<<"ji-"< RandomGridFiller::randIndices(const int count0 ) { int count = count0 ; vector indices ; unordered_map dict ; while( count > 0 ) { int r = rand()%count0; if( dict.find(r) == dict.end() ) { dict[r] = true ; indices.push_back(r) ; count-- ; } } return indices; } int RandomGridFiller::sumOfSubGridTakenCounts(const int x,const int y,const int radius, const float gridwid,const float gridhei,const vector>& rowColSubGrid) { int sum = 0 ; int gridXNum = rowColSubGrid[0].size() ; int gridYNum = rowColSubGrid.size() ; int centerGridX = x*1.0 / gridwid + 0.5 ; int centerGridY = y*1.0 / gridhei + 0.5 ; int gridRadiusX = radius/gridwid ; int gridRadiusY = radius/gridhei ; for( int igridy = -gridRadiusY; igridy <= gridRadiusY; ++ igridy ) { for(int igridx = -gridRadiusX; igridx <= gridRadiusX; ++ igridx ) { int gridx = centerGridX + igridx ; int gridy = centerGridY + igridy ; if( gridx>=0 && gridx < gridXNum && gridy>=0 && gridy < gridYNum ) { sum += rowColSubGrid[gridy][gridx] ; } } } return sum ; } void RandomGridFiller::subGridTakenCountsAddOne(const int x,const int y,const int radius, const float gridwid,const float gridhei,vector>& rowColSubGrid) { int gridXNum = rowColSubGrid[0].size() ; int gridYNum = rowColSubGrid.size() ; int centerGridX = x*1.0 / gridwid + 0.5 ; int centerGridY = y*1.0 / gridhei + 0.5 ; int gridRadiusX = radius/gridwid ; int gridRadiusY = radius/gridhei ; for( int igridy = -gridRadiusY; igridy <= gridRadiusY; ++ igridy ) { for(int igridx = -gridRadiusX; igridx <= gridRadiusX; ++ igridx ) { int gridx = centerGridX + igridx ; int gridy = centerGridY + igridy ; if( gridx>=0 && gridx < gridXNum && gridy>=0 && gridy < gridYNum ) { rowColSubGrid[gridy][gridx]+=1 ; } } } } //多边形盖住的格点数量 int RandomGridFiller::coverageGridCount( BoostGeometryTools::BoostPolygon& box, const GridData& grid ) { int sum = 0 ; int nrows = grid._rows.size(); int ncols = 0; if( nrows>0 ) ncols = grid._rows[0].size(); for(int irow = 0 ; irow < grid._rows.size();++ irow ) { for(int icol=0;icol(x); bp.set<1>(y) ; sum += BoostGeometryTools::pointIntersetsBox(bp, box)?1:0 ; } } } return sum ; } int RandomGridFiller::totalCoverageGridCount(BoostGeometryTools::BoostPolygon& box, const vector& grids ,int excludeIndex) { int sum = 0 ; for(int ij=0;ij0 ) ncols = grid._rows[0].size(); for(int irow = 0 ; irow < grid._rows.size();++ irow ) { for(int icol=0;icol(x); bp.set<1>(y) ; grid._rows[irow][icol] = BoostGeometryTools::pointIntersetsBox(bp, box) ; } } } void RandomGridFiller::generateDistanceRandomSlotPositions(const float centerx,const float centery,const vector& points, vector& results ) { results.clear() ; vector randindices = randIndices( points.size() ) ; for(int ir = 0 ; ir bool{return p1._distance>p2._distance; } ); }