674 lines
18 KiB
C++
674 lines
18 KiB
C++
#include "stdafx.h"
|
|
#include "MonsterRespawnRegionExtractor.h"
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <windows.h>
|
|
#include <kfile/KFileManager.h>
|
|
#include <kfile/KStream.h>
|
|
//#include "Util.h"
|
|
#include "TerrainSeamlessWorldInfoForClient.h"
|
|
#include "math.h"
|
|
#include <float.h>
|
|
|
|
bool cMonsterRespawnRegionExtractor::sEventMonster::add(int id)
|
|
{
|
|
std::vector<int>::iterator it = m_monsterList.begin();
|
|
for (; it != m_monsterList.end(); ++it)
|
|
{
|
|
if (*it == id)
|
|
return false;
|
|
}
|
|
m_monsterList.push_back(id);
|
|
return true;
|
|
}
|
|
|
|
bool cMonsterRespawnRegionExtractor::sEventRegion::add(int regionIndex, SCRIPTFUNC_LIST const& scriptList, std::vector<KRect> const& regionList)
|
|
{
|
|
if (0 > regionIndex)
|
|
return false;
|
|
if (regionIndex >= (int)regionList.size())
|
|
return false;
|
|
|
|
m_eventId = getEventId(scriptList);
|
|
m_regionList.push_back(regionList[regionIndex]);
|
|
|
|
return m_eventId != -1;
|
|
}
|
|
|
|
int cMonsterRespawnRegionExtractor::sEventRegion::getEventId(SCRIPTFUNC_LIST const& scriptList)
|
|
{
|
|
size_t s, e;
|
|
SCRIPTFUNC_LIST::const_iterator it = scriptList.begin();
|
|
for (; it != scriptList.end(); ++it)
|
|
{
|
|
s = it->m_strFuncName.find("mob(");
|
|
if (s != std::string::npos)
|
|
{
|
|
s = it->m_strFuncName.find("(");
|
|
e = it->m_strFuncName.find(",");
|
|
if (e != std::string::npos)
|
|
{
|
|
std::string strEventId = it->m_strFuncName.substr(s+1, e-s-1);
|
|
return atoi(strEventId.c_str());
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
*/
|
|
cMonsterRespawnRegionExtractor::~cMonsterRespawnRegionExtractor()
|
|
{
|
|
m_eventMonsterList.clear();
|
|
m_eventRegionList.clear();
|
|
m_monsterRegionList.clear();
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::extract()
|
|
{
|
|
if (!getSeamlessWorldInfo()) return false;
|
|
if (!extractLua()) return false;
|
|
if (!extractNfs()) return false;
|
|
if (!unifyData()) return false;
|
|
|
|
std::map<int, sMonsterRegion> minMonsterRegionList;
|
|
std::map<int, sMonsterRegion> maxMonsterRegionList;
|
|
grouping(minMonsterRegionList, 1500);
|
|
grouping(maxMonsterRegionList, 2000);
|
|
|
|
calcCovariance(minMonsterRegionList);
|
|
calcCovariance(maxMonsterRegionList);
|
|
|
|
if (!writeData("second/monsterMinRegion.lst", minMonsterRegionList)) return false;
|
|
if (!writeData("second/monsterMaxRegion.lst", maxMonsterRegionList)) return false;
|
|
|
|
minMonsterRegionList.clear();
|
|
maxMonsterRegionList.clear();
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::extractNfs()
|
|
{
|
|
char filename[MAX_PATH];
|
|
int mapwidth = 13;
|
|
int mapheight = 10;
|
|
|
|
for (int y = 0; y < mapheight; ++y)
|
|
{
|
|
for (int x = 0; x < mapwidth; ++x)
|
|
{
|
|
KStream* pStream;
|
|
|
|
sprintf(filename, "m%03d_%03d.nfm", x, y);
|
|
pStream = KFileManager::Instance().CreateStreamFromResource(filename);
|
|
if (!pStream)
|
|
continue;
|
|
|
|
SAFE_DELETE(pStream);
|
|
|
|
sprintf(filename, "m%03d_%03d.nfs", x, y);
|
|
pStream = KFileManager::Instance().CreateStreamFromResource(filename);
|
|
if (!pStream)
|
|
continue;
|
|
|
|
NFS_LATESTHEADER headerScript;
|
|
if( sizeof(headerScript) != pStream->Read( &headerScript, sizeof(headerScript) ) )
|
|
{
|
|
SAFE_DELETE(pStream);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(headerScript.szSign, NFSFILE_SIGN) != 0)
|
|
{
|
|
SAFE_DELETE(pStream);
|
|
continue;
|
|
}
|
|
|
|
// 헤더를 다시 읽을 수 있도록 파일의 맨앞으로 이동
|
|
pStream->Seek( 0, KStream::seekSet );
|
|
|
|
switch( headerScript.dwVersion ) // 버전 체크
|
|
{
|
|
case c_dwNFSCurrentVer: LoadScriptFileForVer02(pStream, x, y); break;
|
|
case 1: LoadScriptFileForVer01(pStream, x, y); break;
|
|
}
|
|
|
|
SAFE_DELETE(pStream);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::extractLua()
|
|
{
|
|
ifstream ifs("second/monster_respawn.lua", ifstream::in);
|
|
|
|
if (!ifs.is_open())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int eventId = 0;
|
|
char buffer[MAX_PATH];
|
|
while (ifs.good())
|
|
{
|
|
ifs.getline(buffer, MAX_PATH);
|
|
|
|
if (strstr(buffer, "ID == "))
|
|
{
|
|
std::string str = assignString(buffer, "ID == ", "then");
|
|
eventId = atoi(str.c_str());
|
|
|
|
}
|
|
else if (strstr(buffer, "monster_ID") || strstr(buffer, "Raremob_ID") || strstr(buffer, "Raidmob_ID"))
|
|
{
|
|
if (0 == eventId)
|
|
continue;
|
|
|
|
sEventMonster eventMonster;
|
|
std::string str = assignString(buffer, "{", "}");
|
|
|
|
size_t s = 0;
|
|
while (1)
|
|
{
|
|
size_t found = str.find(",", s);
|
|
if (found == std::string::npos)
|
|
{
|
|
std::string strId = str.substr(s, str.length()-s);
|
|
int id = atoi(strId.c_str());
|
|
if (id)
|
|
eventMonster.add(id);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
std::string strId = str.substr(s, found-s);
|
|
int id = atoi(strId.c_str());
|
|
if (id)
|
|
eventMonster.add(id);
|
|
s = found+1;
|
|
}
|
|
}
|
|
|
|
eventMonster.m_eventId = eventId;
|
|
m_eventMonsterList.insert(std::make_pair(eventId, eventMonster));
|
|
eventId = 0;
|
|
}
|
|
}
|
|
|
|
ifs.close();
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::writeData(char const* filename, std::map<int, sMonsterRegion> const& monsterRegionList)
|
|
{
|
|
KFileStream* pStream = new KFileStream(filename, KFileStream::wronly | KFileStream::truncate);
|
|
if (!pStream->IsValid())
|
|
{
|
|
SAFE_DELETE(pStream);
|
|
return false;
|
|
}
|
|
|
|
_oprint("write monster respawn data : %s\n\n", filename);
|
|
|
|
int count = m_monsterRegionList.size();
|
|
pStream->Write(&count, sizeof (count));
|
|
|
|
_oprint("count : %d\n", count);
|
|
|
|
int i = 0;
|
|
std::map<int, sMonsterRegion>::const_iterator it = monsterRegionList.begin();
|
|
for (; it != monsterRegionList.end(); ++it, ++i)
|
|
{
|
|
int monsterId = it->second.m_monsterId;
|
|
pStream->Write(&monsterId, sizeof (monsterId));
|
|
|
|
int num = it->second.m_regionList.size();
|
|
pStream->Write(&num, sizeof (num));
|
|
|
|
//_oprint("[%d] id = %d, num = %d\n", i, monsterId, num);
|
|
|
|
sMonsterRegion::cit_region it_r = it->second.m_regionList.begin();
|
|
for (; it_r != it->second.m_regionList.end(); ++it_r)
|
|
{
|
|
pStream->Write(&it_r->m_rect, sizeof (it_r->m_rect));
|
|
pStream->Write(&it_r->m_theta, sizeof (it_r->m_theta));
|
|
}
|
|
}
|
|
|
|
pStream->Close();
|
|
SAFE_DELETE(pStream);
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::readData(char const* filename, std::map<int, sMonsterRegion>& monsterRegionList)
|
|
{
|
|
KStream* pStream = KFileManager::Instance().CreateStreamFromResource(filename);
|
|
if (!pStream)
|
|
return false;
|
|
|
|
// _oprint("write monster respawn data : %s\n\n", filename);
|
|
|
|
int count;
|
|
pStream->Read(&count, sizeof (count));
|
|
|
|
// _oprint("count : %d\n", count);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
sMonsterRegion monsterRegion;
|
|
|
|
int monsterId;
|
|
pStream->Read(&monsterId, sizeof (monsterId));
|
|
int regionNum;
|
|
pStream->Read(®ionNum, sizeof (regionNum));
|
|
|
|
monsterRegion.m_monsterId = monsterId;
|
|
|
|
//_oprint("[%d] id = %d, num = %d\n", i, monsterRegion.m_monsterId, regionNum);
|
|
|
|
for (int r = 0; r < regionNum; ++r)
|
|
{
|
|
sMonsterRegionRect mobRegion;
|
|
pStream->Read(&mobRegion.m_rect, sizeof (mobRegion.m_rect));
|
|
pStream->Read(&mobRegion.m_theta, sizeof (mobRegion.m_theta));
|
|
monsterRegion.m_regionList.push_back(mobRegion);
|
|
|
|
// _oprint("\tleft=%d, right=%d, top=%d, bottom=%d\n", rect.left, rect.right, rect.top, rect.bottom);
|
|
}
|
|
|
|
monsterRegionList.insert(std::make_pair(monsterRegion.m_monsterId, monsterRegion));
|
|
}
|
|
|
|
SAFE_DELETE(pStream);
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
std::string cMonsterRespawnRegionExtractor::assignString(char const* buffer, char* openStr, char* closeStr)
|
|
{
|
|
char const* open = strstr(buffer, openStr);
|
|
open += strlen(openStr);
|
|
char const* close = strstr(buffer, closeStr);
|
|
std::string str;
|
|
str.assign(open, close-open);
|
|
return str;
|
|
}
|
|
/*
|
|
*/
|
|
void cMonsterRespawnRegionExtractor::LoadScriptFileForVer02(KStream* pStream, int nMapX, int nMapY )
|
|
{
|
|
// 헤더 읽기
|
|
NFS_HEADER_V02 headerScript;
|
|
if( sizeof(headerScript) != pStream->Read( &headerScript, sizeof(headerScript) ) )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
std::vector<KRect> regionList;
|
|
int nEventLocationCount;
|
|
int nEventLocationScriptCount;
|
|
|
|
int tileLength = (int)m_tileLength;
|
|
|
|
// 이벤트 영역 정보
|
|
{
|
|
// 이벤트 영역 갯수 읽기
|
|
pStream->Read( &nEventLocationCount, sizeof(nEventLocationCount) );
|
|
|
|
for( int n( 0 ); n < nEventLocationCount; ++n )
|
|
{
|
|
// 이벤트 영역 좌표 읽기
|
|
KRect rcLocation;
|
|
pStream->Read( &rcLocation.left, sizeof(rcLocation.left) );
|
|
pStream->Read( &rcLocation.top, sizeof(rcLocation.top) );
|
|
pStream->Read( &rcLocation.right, sizeof(rcLocation.right) );
|
|
pStream->Read( &rcLocation.bottom, sizeof(rcLocation.bottom) );
|
|
|
|
rcLocation.left += (nMapX * m_tileCountPerMap);
|
|
rcLocation.top += (nMapY * m_tileCountPerMap);
|
|
rcLocation.right += (nMapX * m_tileCountPerMap);
|
|
rcLocation.bottom += (nMapY * m_tileCountPerMap);
|
|
|
|
rcLocation.left *= tileLength;
|
|
rcLocation.right *= tileLength;
|
|
rcLocation.top *= tileLength;
|
|
rcLocation.bottom *= tileLength;
|
|
|
|
// 이벤트 영역 이름 읽기
|
|
std::string strEvLocName = CStringUtil::ReadString( pStream );
|
|
|
|
regionList.push_back(rcLocation);
|
|
}
|
|
}
|
|
|
|
// 이벤트 영역의 스크립트펑션 리스트 정보
|
|
{
|
|
// 스크립트펑션 리스트들의 갯수
|
|
pStream->Read( &nEventLocationScriptCount, sizeof(nEventLocationScriptCount) );
|
|
|
|
for( int n( 0 ); n < nEventLocationScriptCount; ++n )
|
|
{
|
|
// 스크립트 펑션 리스트 읽기
|
|
SCRIPTFUNC_LIST ScriptFuncList;
|
|
int nIndex = LoadEvLocScriptFuncListForV01( pStream, ScriptFuncList );
|
|
|
|
sEventRegion eventRegion;
|
|
if (eventRegion.add(nIndex, ScriptFuncList, regionList))
|
|
addEventRegion(eventRegion);//m_eventRegionList.insert(std::make_pair(eventRegion.m_eventId, eventRegion));
|
|
|
|
ScriptFuncList.clear();
|
|
}
|
|
}
|
|
|
|
regionList.clear();
|
|
|
|
}
|
|
/*
|
|
*/
|
|
void cMonsterRespawnRegionExtractor::LoadScriptFileForVer01(KStream* pStream, int nMapX, int nMapY )
|
|
{
|
|
// 헤더 읽기
|
|
NFS_HEADER_V01 headerScript;
|
|
if( sizeof(headerScript) != pStream->Read( &headerScript, sizeof(headerScript) ) )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
std::vector<KRect> regionList;
|
|
|
|
// 이벤트 영역 정보
|
|
{
|
|
// 이벤트 영역 갯수 읽기
|
|
int nEventLocationCount;
|
|
pStream->Read( &nEventLocationCount, sizeof(nEventLocationCount) );
|
|
|
|
for( int n( 0 ); n < nEventLocationCount; ++n )
|
|
{
|
|
// 이벤트 영역 좌표 읽기
|
|
KRect rcLocation;
|
|
pStream->Read( &rcLocation.left, sizeof(rcLocation.left) );
|
|
pStream->Read( &rcLocation.top, sizeof(rcLocation.top) );
|
|
pStream->Read( &rcLocation.right, sizeof(rcLocation.right) );
|
|
pStream->Read( &rcLocation.bottom, sizeof(rcLocation.bottom) );
|
|
|
|
rcLocation.left += (nMapX * m_tileCountPerMap);
|
|
rcLocation.top += (nMapY * m_tileCountPerMap);
|
|
rcLocation.right += (nMapX * m_tileCountPerMap);
|
|
rcLocation.bottom += (nMapY * m_tileCountPerMap);
|
|
|
|
// 이벤트 영역 이름 읽기
|
|
std::string strEvLocName = CStringUtil::ReadString( pStream );
|
|
|
|
regionList.push_back(rcLocation);
|
|
}
|
|
}
|
|
|
|
// 이벤트 영역의 스크립트펑션 리스트 정보
|
|
{
|
|
// 스크립트펑션 리스트들의 갯수
|
|
int nEventLocationScriptCount = 0;
|
|
pStream->Read( &nEventLocationScriptCount, sizeof(nEventLocationScriptCount) );
|
|
|
|
for( int n( 0 ); n < nEventLocationScriptCount; ++n )
|
|
{
|
|
// 스크립트 펑션 리스트 읽기
|
|
SCRIPTFUNC_LIST ScriptFuncList;
|
|
int nIndex = LoadEvLocScriptFuncListForV01( pStream, ScriptFuncList );
|
|
|
|
|
|
sEventRegion eventRegion;
|
|
if (eventRegion.add(nIndex, ScriptFuncList, regionList))
|
|
addEventRegion(eventRegion);//m_eventRegionList.insert(std::make_pair(eventRegion.m_eventId, eventRegion));
|
|
|
|
ScriptFuncList.clear();
|
|
}
|
|
}
|
|
regionList.clear();
|
|
}
|
|
/*
|
|
*/
|
|
int cMonsterRespawnRegionExtractor::LoadEvLocScriptFuncListForV01( KStream* pStream, SCRIPTFUNC_LIST& rScriptFuncList )
|
|
{
|
|
// 인덱스 읽기
|
|
int nIndex = 0;
|
|
pStream->Read( &nIndex, sizeof(nIndex) );
|
|
|
|
// 스크립트 펑션 갯수 읽기
|
|
int nScriptFuncCount = 0;
|
|
pStream->Read( &nScriptFuncCount, sizeof(nScriptFuncCount) );
|
|
|
|
for( int n( 0 ); n < nScriptFuncCount; ++n )
|
|
{
|
|
// 트리거 읽기
|
|
int nTrigger = 0;
|
|
pStream->Read( &nTrigger, sizeof(nTrigger) );
|
|
|
|
// 펑션 이름 읽기
|
|
std::string strFuncName = CStringUtil::ReadString( pStream );
|
|
|
|
rScriptFuncList.push_back( ScriptFunction( SCRIPT_TRIGGER(nTrigger), strFuncName.c_str() ) );
|
|
}
|
|
return nIndex;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::getSeamlessWorldInfo()
|
|
{
|
|
CTerrainSeamlessWorldInfoForClient seamlessWorldInfo;
|
|
if( !seamlessWorldInfo.Initialize("TerrainSeamlessWorld.cfg", false))
|
|
return false;
|
|
|
|
m_segmentCountPerMap = seamlessWorldInfo.GetSegmentCountPerMap();
|
|
m_tileCountPerSegment = seamlessWorldInfo.GetTileCountPerSegment();
|
|
m_tileCountPerMap = m_segmentCountPerMap * m_tileCountPerSegment;
|
|
m_tileLength = seamlessWorldInfo.GetTileLength();
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
bool cMonsterRespawnRegionExtractor::unifyData()
|
|
{
|
|
/// event monster list
|
|
std::map<int, sEventMonster>::iterator it_em = m_eventMonsterList.begin();
|
|
for (; it_em != m_eventMonsterList.end(); ++it_em)
|
|
{
|
|
int eventId = it_em->second.m_eventId;
|
|
|
|
std::vector<int>::iterator it_m = it_em->second.m_monsterList.begin();
|
|
for (; it_m != it_em->second.m_monsterList.end(); ++it_m)
|
|
{
|
|
int monsterId = *it_m;
|
|
|
|
/// event region list
|
|
std::map<int, sEventRegion>::iterator it_er = m_eventRegionList.find(eventId);
|
|
if (it_er != m_eventRegionList.end())
|
|
{
|
|
std::vector<KRect>::iterator it_r = it_er->second.m_regionList.begin();
|
|
|
|
/// monster region list
|
|
std::map<int, sMonsterRegion>::iterator it_mr = m_monsterRegionList.find(monsterId);
|
|
if (it_mr != m_monsterRegionList.end())
|
|
{
|
|
for (; it_r != it_er->second.m_regionList.end(); ++it_r)
|
|
it_mr->second.m_regionList.push_back(*it_r);
|
|
}
|
|
else
|
|
{
|
|
sMonsterRegion mr;
|
|
mr.m_monsterId = monsterId;
|
|
for (; it_r != it_er->second.m_regionList.end(); ++it_r)
|
|
mr.m_regionList.push_back(sMonsterRegionRect(*it_r));
|
|
|
|
m_monsterRegionList.insert(std::make_pair(monsterId, mr));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
*/
|
|
void cMonsterRespawnRegionExtractor::addEventRegion(sEventRegion const& eventRegion)
|
|
{
|
|
std::map<int, sEventRegion>::iterator it = m_eventRegionList.find(eventRegion.m_eventId);
|
|
if (it == m_eventRegionList.end())
|
|
{
|
|
m_eventRegionList.insert(std::make_pair(eventRegion.m_eventId, eventRegion));
|
|
}
|
|
else
|
|
{
|
|
/// eventRegion.m_regionList는 꼭 한이다.
|
|
it->second.m_regionList.push_back(eventRegion.m_regionList[0]);
|
|
}
|
|
}
|
|
/*
|
|
*/
|
|
void cMonsterRespawnRegionExtractor::grouping(std::map<int,sMonsterRegion> &monsterRegionList, int groupLength)
|
|
{
|
|
std::map<int, sMonsterRegion>::iterator it = m_monsterRegionList.begin();
|
|
for (; it != m_monsterRegionList.end(); ++it)
|
|
{
|
|
sMonsterRegion monsterRegion;
|
|
monsterRegion.m_monsterId = it->second.m_monsterId;
|
|
monsterRegion.m_regionList = it->second.m_regionList;
|
|
|
|
sMonsterRegion::it_region it_first = monsterRegion.m_regionList.begin();
|
|
for (; it_first != monsterRegion.m_regionList.end(); ++it_first)
|
|
{
|
|
sMonsterRegion::it_region it_second = it_first + 1;
|
|
for (; it_second != monsterRegion.m_regionList.end(); )
|
|
{
|
|
int len = getRectLength(it_first->m_rect, it_second->m_rect);
|
|
if (len < groupLength)
|
|
{
|
|
KRect r = getGroupRect(it_first->m_rect, it_second->m_rect);
|
|
it_first->setRect(r);
|
|
it_first->addGroup(it_second->m_rect);
|
|
|
|
it_second = monsterRegion.m_regionList.erase(it_second);
|
|
}
|
|
else
|
|
{
|
|
++it_second;
|
|
}
|
|
}
|
|
}
|
|
|
|
monsterRegionList.insert(std::make_pair(monsterRegion.m_monsterId, monsterRegion));
|
|
}
|
|
}
|
|
/*
|
|
*/
|
|
int cMonsterRespawnRegionExtractor::getRectLength(KRect const& r1, KRect const& r2)
|
|
{
|
|
KPoint p1((r1.left + r1.right) >> 1, (r1.top + r1.bottom) >> 1);
|
|
KPoint p2((r2.left + r2.right) >> 1, (r2.top + r2.bottom) >> 1);
|
|
KPoint p = p2 - p1;
|
|
|
|
double _x = (double)p.x;
|
|
double _y = (double)p.y;
|
|
int len = (int)::sqrt(pow(_x, 2) + pow(_y, 2));
|
|
return len;
|
|
}
|
|
/*
|
|
*/
|
|
KRect cMonsterRespawnRegionExtractor::getGroupRect(KRect const& r1, KRect const& r2)
|
|
{
|
|
KRect r;
|
|
r.left = min(r1.left, r2.left);
|
|
r.right = max(r1.right, r2.right);
|
|
r.top = min(r1.top, r2.top);
|
|
r.bottom = max(r1.bottom, r2.bottom);
|
|
|
|
return r;
|
|
}
|
|
/*
|
|
*/
|
|
void cMonsterRespawnRegionExtractor::calcCovariance(std::map<int,sMonsterRegion> &monsterRegion)
|
|
{
|
|
struct sAverageSize
|
|
{
|
|
void getAverage(std::vector<KRect> const& rectList, KSize& size)
|
|
{
|
|
KSize ave(0, 0);
|
|
int n = rectList.size();
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
ave.cx += rectList[i].GetWidth();
|
|
ave.cy += rectList[i].GetHeight();
|
|
}
|
|
ave.cx /= n;
|
|
ave.cy /= n;
|
|
|
|
size = ave;
|
|
}
|
|
};
|
|
|
|
sCorMatrix corMat;
|
|
|
|
int _x = 0;
|
|
int _y = 0;
|
|
|
|
std::map<int,sMonsterRegion>::iterator it_mr = monsterRegion.begin();
|
|
for (; it_mr != monsterRegion.end(); ++it_mr, ++_x)
|
|
{
|
|
sMonsterRegion::it_region it_r = it_mr->second.m_regionList.begin();
|
|
for (_y = 0; it_r != it_mr->second.m_regionList.end(); ++it_r, ++_y)
|
|
{
|
|
if (1 == it_r->m_groupRectList.size())
|
|
{
|
|
it_r->m_theta = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
corMat.make(it_r->m_groupRectList);
|
|
|
|
float tanTheta, theta;
|
|
float deno = corMat.v[1][1] - corMat.v[0][0];
|
|
if (FLT_EPSILON >= fabs(deno))
|
|
tanTheta = 0.0f;
|
|
else
|
|
tanTheta = (2.0f * corMat.v[0][1])/deno;
|
|
theta = ::atanf(tanTheta) * 0.5f;
|
|
|
|
float _cos = ::cosf(theta);
|
|
float _sin = ::sinf(theta);
|
|
float _cos2 = pow(_cos, 2);
|
|
float _sin2 = pow(_sin, 2);
|
|
float _sincos = _sin * _cos;
|
|
|
|
float r_uu = (corMat.v[0][0] * _cos2) - (2.0f * corMat.v[0][1] * _sincos) + (corMat.v[1][1] * _sin2);
|
|
float r_vv = (corMat.v[0][0] * _sin2) - (2.0f * corMat.v[0][1] * _sincos) + (corMat.v[1][1] * _cos2);
|
|
|
|
float w, h;
|
|
if (1.0f >= fabs(r_uu)) w = 1.0f;
|
|
else w = ::sqrtf(r_uu);
|
|
if (1.0f >= fabs(r_vv)) h = 1.0f;
|
|
else h = ::sqrtf(r_vv);
|
|
|
|
// 공분산 상관관계를 구할 때, 지역의 영역크기는 고려가 안되었기 때문에, 평균 영역 크기를 더해준다.
|
|
KSize aveSize;
|
|
sAverageSize averageSize;
|
|
averageSize.getAverage(it_r->m_groupRectList, aveSize);
|
|
w += aveSize.cx;
|
|
h += aveSize.cy;
|
|
|
|
it_r->m_theta = theta;
|
|
it_r->reSize((int)w, (int)h);
|
|
}
|
|
}
|
|
}
|
|
} |