1150 lines
42 KiB
C++
1150 lines
42 KiB
C++
#include "fm_address.h"
|
|
|
|
#include <QDir>
|
|
#include <QCoreApplication>
|
|
#include <QDebug>
|
|
#if (USE_JP_ADDRESS_TOOL)
|
|
#include <QElapsedTimer>
|
|
#include <QThread>
|
|
#include <QFile>
|
|
#include <wchar.h>
|
|
#include <QDateTime>
|
|
#include <qmath.h>
|
|
#include <math.h>
|
|
#endif
|
|
|
|
// TYPE 0: 국토지리원 1. 전자 국토 기본도 (지명 정보) "주거 표시 주소" (2200만건)
|
|
// TYPE 1: 기존DB 1100만건
|
|
// TYPE 2: 국토교통성 지명DB https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_choose_method.cgi
|
|
|
|
|
|
#if (USE_JP_ADDRESS)
|
|
|
|
// 비트팩->바이트 계산
|
|
inline uint32_t _ABitsPackToByte(uint8_t* bits) {
|
|
return ceil((double)(bits[0] + bits[1] + bits[2] + bits[3])/8.0);
|
|
}
|
|
// 영역 포함 확인
|
|
inline bool _AIsInArea(JA_AREA_PACKET* area,int x, int y, int tolerance) {
|
|
return (x >= (area->xmin - tolerance) &&
|
|
x <= (area->xmax + tolerance) &&
|
|
y >= (area->ymin - tolerance) &&
|
|
y <= (area->ymax + tolerance));
|
|
}
|
|
|
|
|
|
#if (USE_JP_ADDRESS_TOOL)
|
|
#define PROCESS_TEST_CITY 0
|
|
QMap<QString,uint32_t> FMAddress::_stringTable;
|
|
#endif // USE_JP_ADDRESS_TOOL
|
|
|
|
FMAddress::FMAddress()
|
|
{
|
|
memset(&_header,0,sizeof(_JA_HEADER));
|
|
|
|
_areas = NULL;
|
|
_strings = NULL;
|
|
_file = NULL;
|
|
|
|
#if (USE_JP_ADDRESS_TOOL)
|
|
_maxLenPref = 0;
|
|
_maxLenCity = 0;
|
|
_maxLenChome = 0;
|
|
_maxA0 = 0;
|
|
_maxA1 = 0;
|
|
QString dateString = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
|
|
strcpy(_header.header,"F-REVERSE ADDRESS GEOCODING TABLE API");
|
|
strcpy(_header.date,dateString.toLocal8Bit().constData());
|
|
strcpy(_header.version,"0.1.0");
|
|
qInfo() << _header.header << _header.date << _header.version;
|
|
_prefs = NULL;
|
|
#endif
|
|
}
|
|
FMAddress::~FMAddress()
|
|
{
|
|
if(_areas != NULL) {
|
|
free(_areas);
|
|
}
|
|
if(_strings != NULL) {
|
|
free(_strings);
|
|
}
|
|
if(_file != NULL) {
|
|
fclose(_file);
|
|
}
|
|
}
|
|
bool FMAddress::open(QString path)
|
|
{
|
|
_file = fopen(path.toLocal8Bit(),"rb");
|
|
if(_file == NULL) {
|
|
return false;
|
|
}
|
|
fread(&_header,sizeof(_JA_HEADER),1,_file);
|
|
_strings = (uint8_t*)malloc(_header.stringSize);
|
|
fread(_strings,_header.stringSize,1,_file);
|
|
uint32_t areaSize = sizeof(_JA_AREA_PACKET) * (_header.pref_count + _header.city_count + _header.town_count);
|
|
_areas = (JA_AREA_PACKET*)malloc(areaSize);
|
|
fread(_areas,areaSize,1,_file);
|
|
|
|
#if (USE_JP_ADDRESS_TOOL)
|
|
qInfo() << "-----------------------------------------------------";
|
|
qInfo() << "HEADER : Bound:" << _header.xmin << _header.ymin << _header.xmax << _header.ymax;
|
|
qInfo() << "HEADER : Bound(Lon/Lat):" << QString().sprintf("%.6f,%.6f,%.6f,%.6f",(double)_header.xmin / 80000.0,(double)_header.ymin / 120000.0,(double)_header.xmax / 80000.0,(double)_header.ymax / 120000.0);
|
|
qInfo() << "HEADER : ID/DATE/VERSION:" << _header.header << _header.date << _header.version;
|
|
qInfo() << "HEADER : SIZE:" << QString().sprintf("0x%X",sizeof(_JA_HEADER));
|
|
qInfo() << "HEADER : STRING SIZE:" << _header.stringSize;
|
|
qInfo() << "HEADER : PREF,COUNT:" << _header.pref_count;
|
|
qInfo() << "HEADER : CITY,COUNT:" << _header.city_count;
|
|
qInfo() << "HEADER : TOWN,COUNT:" << _header.town_count;
|
|
qInfo() << "HEADER : JIBUN,COUNT:" << _header.jibun_count;
|
|
//debugList();
|
|
#endif
|
|
return true;
|
|
}
|
|
bool FMAddress::open()
|
|
{
|
|
if(!isOpened()) {
|
|
QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "jpaddr.bin");
|
|
if(!open(path)) {
|
|
open("C://home//roadmovie//script//jpaddr//20210120_jp_addr.bin");
|
|
}
|
|
}
|
|
return isOpened();
|
|
}
|
|
|
|
bool FMAddress::search(double lon, double lat,QStringList& result,int tolerance)
|
|
{
|
|
wchar_t* p = NULL;
|
|
wchar_t* c = NULL;
|
|
wchar_t* t = NULL;
|
|
int a0 = 0;
|
|
int a1 = 0;
|
|
int dist = 0;
|
|
if(search(lon,lat,&p,&c,&t,&a0,&a1,&dist,tolerance) == false) {
|
|
return false;
|
|
}
|
|
|
|
result.append(QString::fromUtf16((ushort*)p));
|
|
result.append(QString::fromUtf16((ushort*)c));
|
|
result.append(QString::fromUtf16((ushort*)t));
|
|
result.append(QString::number(a0));
|
|
result.append(QString::number(a1));
|
|
result.append(QString::number(dist));
|
|
return true;
|
|
}
|
|
|
|
bool FMAddress::search(double lon,double lat,wchar_t** pref,wchar_t** city,wchar_t** town,int* a0, int*a1, int* pdist, int tolerance)
|
|
{
|
|
qInfo() << QString().sprintf("SEARCH START :%.6f,%.6f [%d]",lat,lon,tolerance);
|
|
|
|
_found_a0 = -1;
|
|
_found_a1 = -1;
|
|
_found_dist_sq = 1000000; // 거리^2
|
|
|
|
int x = (int)(lon * 80000.0);
|
|
int y = (int)(lat * 120000.0);
|
|
bool bFound = false;
|
|
|
|
for(uint32_t p=0;p<_header.pref_count;p++) {
|
|
JA_AREA_PACKET* pp = &_areas[p];
|
|
//qInfo() << "PREF" << QString::fromUtf16((ushort*)&_strings[pp->nameOffset]) << pp->xmin << pp->ymin << pp->xmax << pp->ymax;
|
|
// PREF 포함
|
|
if(_AIsInArea(&_areas[p],x,y,tolerance)) {
|
|
//qInfo() << QString::fromUtf16((ushort*)&_strings[pp->nameOffset]);
|
|
uint32_t cidx = pp->sub_offset / sizeof(_JA_AREA_PACKET);
|
|
for(uint32_t c=0;c<pp->sub_count;c++) {
|
|
JA_AREA_PACKET* cc = &_areas[cidx + c];
|
|
// CITY 포함
|
|
//qInfo() << "\t" << QString::fromUtf16((ushort*)&_strings[cc->nameOffset]);
|
|
if(_AIsInArea(cc,x,y,tolerance)) {
|
|
uint32_t tidx = cc->sub_offset / sizeof(_JA_AREA_PACKET);
|
|
for(uint32_t t=0;t<cc->sub_count;t++) {
|
|
JA_AREA_PACKET* tt = &_areas[tidx + t];
|
|
if(_AIsInArea(tt,x,y,tolerance)) {
|
|
//qInfo() << "\t\t" << QString::fromUtf16((ushort*)&_strings[tt->nameOffset]);
|
|
if(_searchTown(tt,x,y,tolerance)) // 가장 가까운 지점이 발견된 경우
|
|
{
|
|
bFound = true;
|
|
//qInfo() << "\t\t\t" << "FOUND!!!!" << QString::fromUtf16((ushort*)&_strings[tt->nameOffset]) << (int)sqrt((double)_found_dist_sq) ;
|
|
// 리턴
|
|
*pref = (wchar_t*)&_strings[pp->nameOffset];
|
|
*city = (wchar_t*)&_strings[cc->nameOffset];
|
|
*town = (wchar_t*)&_strings[tt->nameOffset];
|
|
*pdist = (int)sqrt((double)_found_dist_sq);
|
|
*a0 = _found_a0;
|
|
*a1 = _found_a1;
|
|
}
|
|
} // IN TOWN
|
|
} // FOR TOWN
|
|
} // IN CITY
|
|
} // FOR CITY
|
|
} // IN PREF
|
|
} // FOR PREF
|
|
return bFound;//(_found_dist_sq < tolerance);
|
|
}
|
|
bool FMAddress::_searchTown(JA_AREA_PACKET* town,int x, int y, int tolerance)
|
|
{
|
|
const int lx = x - town->xmin;
|
|
const int ly = y - town->ymin;
|
|
|
|
JA_AREA_PACKET box = {0,};
|
|
box.xmin = (lx - tolerance);
|
|
box.ymin = (ly - tolerance);
|
|
box.xmax = (lx + tolerance);
|
|
box.ymax = (ly + tolerance);
|
|
|
|
uint32_t bytes = _ABitsPackToByte(town->bits); // 1 지번당 바이트
|
|
const uint32_t xm = ((1 << town->bits[0])-1); // xmask
|
|
const uint32_t ym = ((1 << town->bits[1])-1); // ymask
|
|
const uint32_t a0m = ((1 << town->bits[2])-1); // a0mask
|
|
const uint32_t a1m = ((1 << town->bits[3])-1); // a1mask
|
|
|
|
// A0-A1-x-y shift
|
|
const uint32_t xs = town->bits[1] + town->bits[2] + town->bits[3];
|
|
const uint32_t ys = town->bits[2] + town->bits[3]; // a0
|
|
const uint32_t a0s = town->bits[3]; // a0
|
|
const uint32_t a1s = 0; // a1
|
|
|
|
// 할당 @TODO -> MAX_TOWN_BUFFER 를 생성해서 처리 가능..
|
|
uint8_t* buffer = (uint8_t*)malloc(bytes * town->sub_count);
|
|
uint64_t v; // 데이터 처리용
|
|
fseek(_file,town->sub_offset,SEEK_SET);
|
|
fread(buffer,bytes * town->sub_count,1,_file);
|
|
bool bFound = false;
|
|
for(uint32_t j=0;j<town->sub_count;j++)
|
|
{
|
|
v = 0;
|
|
memcpy(&v,&buffer[bytes*j],bytes);
|
|
int vx = ((v >> xs) & xm);
|
|
int vy = ((v >> ys) & ym);
|
|
|
|
// 영역 포함
|
|
if(_AIsInArea(&box,vx,vy,0))
|
|
{
|
|
int ds2 = ((vx - lx) * (vx - lx)) + ((vy - ly) * (vy - ly));
|
|
if(ds2 < _found_dist_sq) {
|
|
|
|
_found_dist_sq = ds2;
|
|
_found_a0 = (v >> a0s) & a0m;
|
|
_found_a1 = (v >> a1s) & a1m;
|
|
_found_x = town->xmin + vx;
|
|
_found_y = town->ymin + vy;
|
|
|
|
//qInfo() << "FOUND:" << _found_dist_sq << "JIBUN:" << _found_a0 << _found_a1;
|
|
bFound = true;
|
|
}
|
|
}
|
|
// half binary search
|
|
if(vx > box.xmax) {
|
|
break;
|
|
}
|
|
//qInfo() << "\t\t\t" << QString().sprintf("#%d %d-%d %d,%d (%.6f,%.6f)",j+1,va0,va1,vx,vy,((double)(town->xmin + vx))/80000.0,((double)(town->ymin + vy))/120000.0);
|
|
}
|
|
free(buffer);
|
|
return bFound;
|
|
}
|
|
|
|
#if (USE_JP_ADDRESS_TOOL)
|
|
void FMAddress::debugList()
|
|
{
|
|
for(uint32_t p=0;p<_header.pref_count;p++) {
|
|
JA_AREA_PACKET* pp = &_areas[p];
|
|
qInfo() << QString::fromUtf16((ushort*)&_strings[pp->nameOffset]) << QString().sprintf("cities:%d bound: %.6f,%.6f,%.6f,%.6f",pp->sub_count,((double)pp->xmin)/80000.0,((double)pp->xmax)/80000.0,((double)pp->ymin)/120000.0,((double)pp->ymax)/120000.0);
|
|
for(uint32_t c=0;c<pp->sub_count;c++) {
|
|
// AREA 는 TOWN 을 제외하고는 offset 보다는 index 가 좋겠음..
|
|
uint32_t cidx = pp->sub_offset / sizeof(_JA_AREA_PACKET);
|
|
JA_AREA_PACKET* cc = &_areas[cidx + c];
|
|
qInfo() << "\t" << QString::fromUtf16((ushort*)&_strings[cc->nameOffset]) << QString().sprintf("towns:%d bound: %.6f,%.6f,%.6f,%.6f",cc->sub_count,((double)cc->xmin)/80000.0,((double)cc->xmax)/80000.0,((double)cc->ymin)/120000.0,((double)cc->ymax)/120000.0);
|
|
for(uint32_t t=0;t<cc->sub_count;t++) {
|
|
uint32_t tidx = cc->sub_offset / sizeof(_JA_AREA_PACKET);
|
|
JA_AREA_PACKET* tt = &_areas[tidx + t];
|
|
qInfo() << "\t\t" << QString::fromUtf16((ushort*)&_strings[tt->nameOffset]) << QString().sprintf("offset:0x%X jibuns:%d bound: %.6f,%.6f,%.6f,%.6f",tt->sub_offset,tt->sub_count,((double)tt->xmin)/80000.0,((double)tt->xmax)/80000.0,((double)tt->ymin)/120000.0,((double)tt->ymax)/120000.0);
|
|
_debugTown(tt);
|
|
//break;
|
|
}
|
|
//break;
|
|
}
|
|
//break;
|
|
}
|
|
|
|
}
|
|
void FMAddress::_debugTown(JA_AREA_PACKET* town)
|
|
{
|
|
uint32_t bytes = _ABitsPackToByte(town->bits); // 1 지번당 바이트
|
|
const uint32_t xm = ((1 << town->bits[0])-1); // xmask
|
|
const uint32_t ym = ((1 << town->bits[1])-1); // ymask
|
|
const uint32_t a0m = ((1 << town->bits[2])-1); // a0mask
|
|
const uint32_t a1m = ((1 << town->bits[3])-1); // a1mask
|
|
|
|
// A0-A1-x-y shift
|
|
const uint32_t xs = town->bits[1] + town->bits[2] + town->bits[3];
|
|
const uint32_t ys = town->bits[2] + town->bits[3]; // a0
|
|
const uint32_t a0s = town->bits[3]; // a0
|
|
const uint32_t a1s = 0; // a1
|
|
|
|
uint8_t* buffer = (uint8_t*)malloc(bytes * town->sub_count); // 할당
|
|
uint64_t v; // 데이터 처리용
|
|
fseek(_file,town->sub_offset,SEEK_SET);
|
|
fread(buffer,bytes * town->sub_count,1,_file);
|
|
for(uint32_t j=0;j<town->sub_count;j++)
|
|
{
|
|
v = 0;
|
|
memcpy(&v,&buffer[bytes*j],bytes);
|
|
uint32_t vx = (v >> xs) & xm;
|
|
uint32_t vy = (v >> ys) & ym;
|
|
uint32_t va0 = (v >> a0s) & a0m;
|
|
uint32_t va1 = (v >> a1s) & a1m;
|
|
qInfo() << "\t\t\t" << QString().sprintf("#%d %d-%d %d,%d (%.6f,%.6f)",j+1,va0,va1,vx,vy,((double)(town->xmin + vx))/80000.0,((double)(town->ymin + vy))/120000.0);
|
|
}
|
|
free(buffer);
|
|
}
|
|
bool FMAddress::verify(QString src)
|
|
{
|
|
qInfo() << "START VERIFY:" << src << __FUNCTION__ << __LINE__;
|
|
QElapsedTimer et;
|
|
et.start();
|
|
|
|
QFile file(src);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qInfo() << file.errorString();
|
|
return false;
|
|
}
|
|
|
|
#if (USE_ADDR_DB_TYPE == 1)
|
|
// 한줄 버리기
|
|
qInfo() << QString::fromStdString(file.readLine().toStdString());
|
|
#endif
|
|
|
|
int diffCount = 0;
|
|
int processCount = 0;
|
|
int lines = 0;
|
|
while (!file.atEnd())
|
|
{
|
|
QByteArray line = file.readLine();
|
|
lines++;
|
|
if(lines > 0 && lines % 100000 == 0) {
|
|
//qInfo() << lines;
|
|
}
|
|
QString str = QString::fromStdString(line.toStdString());
|
|
QStringList lst = str.split(",");
|
|
#if (USE_ADDR_DB_TYPE == 0)
|
|
QString pref = lst.at(1);
|
|
QString city = lst.at(2);
|
|
QString town = lst.at(3);
|
|
int a0 = lst.at(4).toInt();
|
|
int a1 = lst.at(5).toInt();
|
|
if (a1 > 1000) {
|
|
continue;
|
|
}
|
|
double lon = lst.at(6).toDouble();
|
|
double lat = lst.at(7).toDouble();
|
|
#elif (USE_ADDR_DB_TYPE == 1)
|
|
QString pref = lst.at(0);
|
|
QString city = lst.at(1);
|
|
QString town = lst.at(2);
|
|
// '青森県' and ADDR_2TH.SI_NAME = '三沢市'
|
|
if(town.isEmpty()) {
|
|
town = " ";
|
|
}
|
|
bool bok0, bok2;
|
|
int a0 = lst.at(3).toInt(&bok0);
|
|
int a1 = lst.at(4).toInt(&bok2);
|
|
if(bok0 == false || bok2 == false) {
|
|
continue;
|
|
}
|
|
double lon = lst.at(8).toDouble();
|
|
double lat = lst.at(7).toDouble();
|
|
#endif
|
|
|
|
wchar_t* pname = NULL;
|
|
wchar_t* cname = NULL;
|
|
wchar_t* tname = NULL;
|
|
int ra0 = -1;
|
|
int ra1 = -1;
|
|
int dist = -1;
|
|
processCount += 1;
|
|
if(!search(lon,lat,&pname,&cname,&tname,&ra0,&ra1,&dist,2) || sqrt((double)dist) > 20.0 || a0 != ra0 || a1 != ra1)
|
|
{
|
|
QString qpname = QString::fromUtf16((ushort*)pname);
|
|
QString qcname = QString::fromUtf16((ushort*)cname);
|
|
QString qtname = QString::fromUtf16((ushort*)tname);
|
|
|
|
if(abs((int)(lon*80000.0) - _found_x) > 10 ||
|
|
abs((int)(lat*120000.0) - _found_y) > 10
|
|
// pref != qpname ||
|
|
// city != qcname ||
|
|
// town != qtname
|
|
)
|
|
{
|
|
qInfo() << "NOT FOUND!!!" << str << qpname << qcname << qtname << "DIST:" << sqrt((double)dist) << "RA0-A1" << ra0 << ra1 << "LON/LAT" << QString().sprintf("%.6f,%.6f",((double)_found_x)/80000.0,((double)_found_y)/120000.0);
|
|
file.close();
|
|
return false;
|
|
}
|
|
double min = ((double)et.elapsed()) / 60000.0;
|
|
qInfo() << "DIFF COUNT:" << a0 << ra0 << a1 << ra1 << ++diffCount << "/" << processCount << QString().sprintf("%.1f min",min);
|
|
}
|
|
//qInfo() << "FOUND:" << str << QString::fromUtf16((ushort*)pname) << QString::fromUtf16((ushort*)cname) << QString::fromUtf16((ushort*)tname) << "DIST:" << sqrt((double)dist) << "RA0-A1" << ra0 << ra1;
|
|
}
|
|
file.close();
|
|
double min = ((double)et.elapsed()) / 60000.0;
|
|
qInfo() << "DONE:" << QString().sprintf("%.1f min",min) << __FUNCTION__ << __LINE__;
|
|
return true;
|
|
}
|
|
|
|
bool FMAddress::convert(QString src, QString target)
|
|
{
|
|
qInfo() << "START:" << src << __FUNCTION__ << __LINE__;
|
|
QElapsedTimer et;
|
|
et.start();
|
|
|
|
_currentPref = NULL;
|
|
_freeConvertData();
|
|
|
|
_prefs = (JA_AREA*)malloc(sizeof(_JA_AREA) * MAX_PREF_COUNT);
|
|
memset(_prefs,0,sizeof(_JA_AREA) * MAX_PREF_COUNT);
|
|
|
|
// CODE,PREF,CITY,CHOME,A0,A1,LON,LAT,CDATE
|
|
// 253851,11469174 -> 기존 DB ADDR_1TH,ADDR_2TH
|
|
// ADDR_1TH 의 경우 旭ヶ丘一丁目, 旭ヶ丘二丁目 등으로 각 丁目 별로 BUNJI 1개씩만 저장
|
|
// ADDR_2TH 의 경우 모든 BUNJI 포함하고 HO는 1개씩 저장
|
|
// 22467875 -> 신규 DB
|
|
// X=LON*80000, Y:LAT*120000
|
|
QFile file(src);
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qInfo() << file.errorString();
|
|
return false;
|
|
}
|
|
|
|
QString maxA0 = "";
|
|
QString maxA1 = "";
|
|
|
|
// 초기화
|
|
_currentPrefName = "";
|
|
_currentCityName = "";
|
|
_currentChomeName = "";
|
|
_header.pref_count = 0;
|
|
|
|
#if (PROCESS_TEST_CITY)
|
|
int townCount = 0; // 테스트용
|
|
#endif
|
|
|
|
#if (USE_ADDR_DB_TYPE == 1)
|
|
// 한줄 버리기
|
|
qInfo() << QString::fromStdString(file.readLine().toStdString());
|
|
#endif
|
|
|
|
int lines = 0;
|
|
while (!file.atEnd())
|
|
{
|
|
QByteArray line = file.readLine();
|
|
lines++;
|
|
if(lines > 0 && lines % 100000 == 0) {
|
|
//qInfo() << lines;
|
|
}
|
|
QString str = QString::fromStdString(line.toStdString());
|
|
QStringList lst = str.split(",");
|
|
#if (USE_ADDR_DB_TYPE == 0)
|
|
//QString code = lst.at(0);
|
|
QString pref = lst.at(1);
|
|
QString city = lst.at(2);
|
|
QString chome = lst.at(3);
|
|
int a0 = lst.at(4).toInt();
|
|
int a1 = lst.at(5).toInt();
|
|
if (a1 > 1000) {
|
|
//qInfo() << str;
|
|
continue;
|
|
}
|
|
#else
|
|
QString pref = lst.at(0);
|
|
QString city = lst.at(1);
|
|
QString chome = lst.at(2);
|
|
chome = chome.replace("\"","");
|
|
// '青森県' and ADDR_2TH.SI_NAME = '三沢市'
|
|
if(chome.isEmpty()) {
|
|
chome = " ";
|
|
}
|
|
bool bok0, bok2;
|
|
int a0 = lst.at(3).toInt(&bok0);
|
|
int a1 = lst.at(4).toInt(&bok2);
|
|
if(bok0 == false || bok2 == false) {
|
|
//qInfo() << "ERROR:" << str;
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
// if(lines >= 965764) {
|
|
// // 宮城県
|
|
// qInfo() << str << lines;
|
|
// }
|
|
|
|
// 東京都
|
|
// if(pref != QString::fromUtf8("\xe6\x9d\xb1\xe4\xba\xac\xe9\x83\xbd"))
|
|
// {
|
|
// continue;
|
|
// }
|
|
// 千代田
|
|
// if(lst.at(0) != QString("13101"))
|
|
// {
|
|
// continue;
|
|
// }
|
|
|
|
|
|
// 도도부현 변경시
|
|
if(_currentPrefName != pref) {
|
|
|
|
_currentPrefName = pref;
|
|
qInfo() << _currentPrefName;
|
|
_currentPref = &_prefs[_header.pref_count];
|
|
wcscpy((wchar_t*)&_currentPref->name[0],(wchar_t*)pref.utf16());
|
|
|
|
_currentCity = (JA_AREA*)malloc(sizeof(_JA_AREA) * MAX_CITY_COUNT);
|
|
memset(_currentCity,0,sizeof(_JA_AREA) * MAX_CITY_COUNT);
|
|
_currentPref->subAreas = _currentCity;
|
|
|
|
_header.pref_count += 1;
|
|
_currentPref->count = 0;
|
|
_currentCityName = "";
|
|
|
|
//qInfo() << "pref:" << pref;
|
|
}
|
|
|
|
// 시구군 변경시
|
|
if(_currentCityName != city) {
|
|
|
|
qInfo() << pref << city << lines;
|
|
_currentCity = &_currentPref->subAreas[_currentPref->count];
|
|
_currentPref->count += 1;
|
|
_currentCityName = city;
|
|
wcscpy((wchar_t*)&_currentCity->name[0],(wchar_t*)city.utf16());
|
|
|
|
_currentChome = (JA_AREA*)malloc(sizeof(_JA_AREA) * MAX_CHOME_COUNT);
|
|
memset(_currentChome,0,sizeof(_JA_AREA) * MAX_CHOME_COUNT);
|
|
_currentCity->subAreas = _currentChome;
|
|
_currentChomeName = "";
|
|
|
|
}
|
|
|
|
// 동변경시
|
|
if(_currentChomeName != chome) {
|
|
|
|
//qInfo() << pref << city << chome;
|
|
#if (PROCESS_TEST_CITY)
|
|
if(townCount >= 1) {
|
|
break;
|
|
}
|
|
townCount +=1;
|
|
#endif
|
|
// 기존 CHOME 데이터 크기대로 리사이즈
|
|
if(_currentChome != NULL) {
|
|
_resizeChome(_currentChome);
|
|
}
|
|
// current 변경
|
|
_currentChome = &_currentCity->subAreas[_currentCity->count];
|
|
_currentCity->count += 1; // 개수 추가
|
|
_currentChomeName = chome; // 명칭->저장
|
|
wcscpy((wchar_t*)&_currentChome->name[0],(wchar_t*)chome.utf16());
|
|
// 지번 생성 (개수를 모르니 그냥 처리)
|
|
_currentJibun = (JA_JIBUN*)malloc(sizeof(_JA_JIBUN) * MAX_JIBUN_COUNT);
|
|
memset(_currentJibun,0,sizeof(_JA_JIBUN) * MAX_JIBUN_COUNT);
|
|
_currentChome->subJibuns = _currentJibun;
|
|
//qInfo() << chome << _currentChome->count << __FUNCTION__ << __LINE__;
|
|
}
|
|
|
|
// if(_currentChome->count >= MAX_JIBUN_COUNT) {
|
|
// qInfo() << str << _currentChome->count << lines;
|
|
// break;
|
|
// }
|
|
// if(lines > 659415) {
|
|
// qInfo() << lines;
|
|
// }
|
|
|
|
// 모든 지번 처리
|
|
// CODE,PREF,CITY,CHOME,A0,A1,LON,LAT,CDATE
|
|
_currentJibun = &_currentChome->subJibuns[_currentChome->count];
|
|
_currentChome->count += 1; // 지번
|
|
_currentJibun->a0 = a0;
|
|
_currentJibun->a1 = a1;
|
|
// // X=LON*80000, Y:LAT*120000
|
|
#if (USE_ADDR_DB_TYPE == 0)
|
|
_currentJibun->x = (int)(lst.at(6).toDouble() * 80000.0);
|
|
_currentJibun->y = (int)(lst.at(7).toDouble() * 120000.0);
|
|
#else
|
|
_currentJibun->x = (int)(lst.at(8).toDouble() * 80000.0);
|
|
_currentJibun->y = (int)(lst.at(7).toDouble() * 120000.0);
|
|
#endif
|
|
|
|
if(_currentJibun->x < 0 || _currentJibun->y < 0)
|
|
{
|
|
qInfo() << "!!!!!!" << str;
|
|
}
|
|
|
|
// _maxLenPref: 4 _maxLenCity: 8 _maxLenChome: 12
|
|
_maxLenPref = qMax(pref.length(),_maxLenPref);
|
|
_maxLenCity = qMax(city.length(),_maxLenCity);
|
|
_maxLenChome = qMax(chome.length(),_maxLenChome);
|
|
bool bLog = false;
|
|
if(a0 > _maxA0) {
|
|
maxA0 = str;
|
|
bLog = true;
|
|
}
|
|
if (a1 > _maxA1) {
|
|
maxA1 = str;
|
|
bLog = true;
|
|
}
|
|
_maxA0 = qMax(a0,_maxA0);
|
|
_maxA1 = qMax(a1,_maxA1);
|
|
|
|
//const ushort* ut = pref.utf16();
|
|
//qInfo() << pref << pref.length() << QString::fromUtf16(pref.utf16()) << wcslen((const wchar_t*)ut);
|
|
if(bLog) {
|
|
//qInfo() << str;
|
|
}
|
|
// "27220,大阪府,箕面市,箕面四丁目,16,57555,135.474490149,34.832934236,20190327\n"
|
|
// OK
|
|
// if(code == "27146" &&
|
|
// chome == QString("\xe6\x96\xb0\xe9\x87\x91\xe5\xb2\xa1\xe7\x94\xba\xe4\xba\x94\xe4\xb8\x81") &&
|
|
// a0 == 7) {
|
|
// qInfo() << str;
|
|
// }
|
|
// OK
|
|
// if(code == "40231" &&
|
|
// chome == QString("\xe4\xbb\xb2\xe4\xb8\x80\xe4\xb8\x81\xe7\x9b\xae") &&
|
|
// a0 == 150) {
|
|
// qInfo() << str;
|
|
// }
|
|
// "27220,大阪府,箕面市,小野原西三丁目,9,1314,135.508661045,34.832548066,20190327\n" -> NG
|
|
// if(code == "27220" &&
|
|
// chome == QString("\xe5\xb0\x8f\xe9\x87\x8e\xe5\x8e\x9f\xe8\xa5\xbf\xe4\xb8\x89\xe4\xb8\x81\xe7\x9b\xae") &&
|
|
// a0 == 9) {
|
|
// qInfo() << str;
|
|
// }
|
|
|
|
// "15222,新潟?,上越市,安江二丁目,5,2000,138.264244772,37.170192031,20170804\n" -> NG
|
|
// if(code == "15222" &&
|
|
// chome == QString("\xe5\xae\x89\xe6\xb1\x9f\xe4\xba\x8c\xe4\xb8\x81\xe7\x9b\xae") &&
|
|
// a0 == 5) {
|
|
// qInfo() << str;
|
|
// }
|
|
}
|
|
|
|
// 마지막 TOWN 처리
|
|
if(_currentChome != NULL) {
|
|
_resizeChome(_currentChome);
|
|
}
|
|
|
|
//qInfo() << "_maxLenPref:" << _maxLenPref << "_maxLenCity:" << _maxLenCity << "_maxLenChome:" << _maxLenChome;
|
|
//qInfo() << "_maxA0:" << _maxA0 << "_maxA1:" << _maxA1;
|
|
//qInfo() << "maxA0 addr:" << maxA0;
|
|
//qInfo() << "maxA1 addr:" << maxA1;
|
|
//qInfo() << "REC NO.:" << lines;
|
|
|
|
|
|
uint32_t maxChome = 0;
|
|
uint32_t maxJibun = 0;
|
|
for(uint32_t p=0;p<_header.pref_count;p++) {
|
|
JA_AREA* pref = &_prefs[p];
|
|
//qInfo() << QString::fromUtf16(pref->name) << pref->count;
|
|
JA_AREA* citys = pref->subAreas;
|
|
for(uint32_t c=0;c<(uint32_t)pref->count;c++) {
|
|
JA_AREA* city = &citys[c];
|
|
//qInfo() << "\t\t" << QString::fromUtf16(city->name) << city->count;
|
|
maxChome = qMax(maxChome,(uint32_t)city->count);
|
|
JA_AREA* chomes = city->subAreas;
|
|
for(uint32_t t=0;t<(uint32_t)city->count;t++) {
|
|
JA_AREA* chome = &chomes[t];
|
|
maxJibun = qMax(maxJibun,(uint32_t)chome->count);
|
|
//qInfo() << "\t\t" << QString::fromUtf16(chome->name) << chome->count;
|
|
}
|
|
}
|
|
}
|
|
|
|
//qInfo() << "MAX_CHOME" << maxChome;
|
|
//qInfo() << "MAX_JIBUN" << maxJibun;
|
|
|
|
//qInfo() << __FUNCTION__ << __LINE__;
|
|
|
|
// 데이터 확인 + MIN MAX 처리 + 문자열 테이블 처리
|
|
_createStatCSV();
|
|
|
|
//qInfo() << __FUNCTION__ << __LINE__;
|
|
|
|
// 저장
|
|
_outFile = fopen(target.toLocal8Bit(),"wb");
|
|
|
|
// 데이터 저장
|
|
_saveData();
|
|
|
|
_freeConvertData();
|
|
fclose(_outFile);
|
|
|
|
double min = ((double)et.elapsed()) / 60000.0;
|
|
qInfo() << "DONE:" << QString().sprintf("%.1f min",min) << __FUNCTION__ << __LINE__;
|
|
|
|
return true;
|
|
}
|
|
void FMAddress::_updateBound(_JA_AREA* dest, _JA_AREA* src)
|
|
{
|
|
dest->xmin = qMin(dest->xmin,src->xmin);
|
|
dest->ymin = qMin(dest->ymin,src->ymin);
|
|
dest->xmax = qMax(dest->xmax,src->xmax);
|
|
dest->ymax = qMax(dest->ymax,src->ymax);
|
|
}
|
|
void FMAddress::_updateBoundP(_JA_AREA* dest, _JA_JIBUN* src)
|
|
{
|
|
dest->xmin = qMin(dest->xmin,src->x);
|
|
dest->ymin = qMin(dest->ymin,src->y);
|
|
dest->xmax = qMax(dest->xmax,src->x);
|
|
dest->ymax = qMax(dest->ymax,src->y);
|
|
dest->a0min = qMin(dest->a0min,(uint16_t)src->a0);
|
|
dest->a0max = qMax(dest->a0max,(uint16_t)src->a0);
|
|
dest->a1min = qMin(dest->a1min,(uint16_t)src->a1);
|
|
dest->a1max = qMax(dest->a1max,(uint16_t)src->a1);
|
|
}
|
|
void FMAddress::_initBound(_JA_AREA* dest)
|
|
{
|
|
dest->xmin = 160 * 80000;
|
|
dest->ymin = 50 * 120000;
|
|
dest->xmax = 0;
|
|
dest->ymax = 0;
|
|
// min,max
|
|
dest->a0min = 10000;
|
|
dest->a0max = 0;
|
|
dest->a1min = 10000;
|
|
dest->a1max = 0;
|
|
}
|
|
void FMAddress::_calculateBitPack(_JA_AREA * src) // , uint8_t* byte
|
|
{
|
|
// 32의 경우 5bit 만 사용하면 31까지만 표현가능하여 무조건 1씩 추가
|
|
int a0Bits = ceil(log((double)(src->a0max+1)) / log( 2.0 ));
|
|
int a1Bits = ceil(log((double)(src->a1max+1)) / log( 2.0 ));
|
|
int w = src->xmax - src->xmin;
|
|
int h = src->ymax - src->ymin;
|
|
int xBits = 0;
|
|
if(w > 0) {
|
|
xBits = ceil(log((double)(w+1)) / log( 2.0 ));
|
|
}
|
|
int yBits = 0;
|
|
if(h > 0) {
|
|
yBits = ceil(log((double)(h+1)) / log( 2.0 ));
|
|
}
|
|
|
|
src->bits[0] = xBits = qMax(xBits,4);
|
|
src->bits[1] =yBits = qMax(yBits,4);
|
|
src->bits[2] =a0Bits = qMax(a0Bits,4);
|
|
src->bits[3] =a1Bits = qMax(a1Bits,4);
|
|
|
|
//int bytes = ceil((double)(xBits + yBits + a0Bits + a1Bits)/8.0);
|
|
//*byte = (uint8_t)bytes;
|
|
|
|
//return QString().sprintf("%02d,%02d,%02d,%02d,%02d",bytes,xBits,yBits,a0Bits,a1Bits);
|
|
}
|
|
int _compareJIBUN(const void *j1, const void *j2)
|
|
{
|
|
if(((JA_JIBUN*)j1)->x == ((JA_JIBUN*)j2)->x)
|
|
{
|
|
return ((JA_JIBUN*)j1)->y - ((JA_JIBUN*)j2)->y;
|
|
}
|
|
return ((JA_JIBUN*)j1)->x - ((JA_JIBUN*)j2)->x;
|
|
}
|
|
// 지번 X 순으로 정렬
|
|
void FMAddress::_sortJIBUN(JA_AREA* chome)
|
|
{
|
|
qsort(chome->subJibuns,chome->count,sizeof(_JA_JIBUN),_compareJIBUN);
|
|
}
|
|
|
|
void FMAddress::_saveData()
|
|
{
|
|
// 헤더 저장
|
|
_writeOffset = 0;
|
|
fwrite(&_header,sizeof(_JA_HEADER),1,_outFile);
|
|
_writeOffset += sizeof(_JA_HEADER);
|
|
|
|
// 문자열 테이블 처리+저장
|
|
_saveStringTable();
|
|
//_header.prefOffset = _writeOffset;
|
|
|
|
// 도도부현 저장
|
|
_savePref();
|
|
|
|
qInfo() << "-----------------------------------------------------";
|
|
qInfo() << "HEADER : Bound:" << _header.xmin << _header.ymin << _header.xmax << _header.ymax;
|
|
qInfo() << "HEADER : Bound(Lon/Lat):" << QString().sprintf("%.6f,%.6f,%.6f,%.6f",(double)_header.xmin / 80000.0,(double)_header.ymin / 120000.0,(double)_header.xmax / 80000.0,(double)_header.ymax / 120000.0);
|
|
qInfo() << "HEADER : ID/DATE/VERSION:" << _header.header << _header.date << _header.version;
|
|
qInfo() << "HEADER : STRING SIZE:" << _header.stringSize;
|
|
qInfo() << "HEADER : PREF,COUNT:" << _header.pref_count;
|
|
qInfo() << "HEADER : CITY,COUNT:" << _header.city_count;
|
|
qInfo() << "HEADER : TOWN,COUNT:" << _header.town_count;
|
|
qInfo() << "HEADER : JIBUN,COUNT:" << _header.jibun_count;
|
|
uint32_t area_size = (_header.pref_count + _header.city_count + _header.town_count) * sizeof(_JA_AREA_PACKET);
|
|
qInfo() << "HEADER SIZE:" << sizeof(_JA_HEADER);
|
|
qInfo() << "STRING TABLE SIZE:" << _header.stringSize;
|
|
qInfo() << "AREA TABLE SIZE:" << area_size;
|
|
qInfo() << "JIBUN TOTAL BYTE:" << _totalJibunBytes;
|
|
qInfo() << "CURRENT FILE SIZE:" << sizeof(_JA_HEADER) + _header.stringSize + area_size + _totalJibunBytes; // 2,455,848, 2455850
|
|
|
|
}
|
|
bool _compareStringTable(const QString &k1, const QString &k2)
|
|
{
|
|
return FMAddress::_stringTable.value(k1) < FMAddress::_stringTable.value(k2);
|
|
}
|
|
void FMAddress::_saveStringTable()
|
|
{
|
|
QList<QString> ordered = _stringTable.keys();
|
|
qSort(ordered.begin(),ordered.end(),_compareStringTable);
|
|
|
|
uint32_t offset = 0;
|
|
// 정렬하고
|
|
foreach (QString key, ordered) {
|
|
offset = _stringTable.value(key);
|
|
//qInfo() << key << offset;
|
|
fseek(_outFile, sizeof(_JA_HEADER) + offset,SEEK_SET);
|
|
fwrite((wchar_t*)key.utf16(),key.length() * 2,1,_outFile);
|
|
}
|
|
wchar_t end = {0,};
|
|
fwrite(&end,2,1,_outFile); // 마지막 종료 문자
|
|
_writeOffset = sizeof(_JA_HEADER) + _header.stringSize; // 문자열 테이블 크기까지
|
|
}
|
|
void FMAddress::_copyPacket(JA_AREA_PACKET* dest, JA_AREA* src)
|
|
{
|
|
dest->nameOffset = src->nameOffset;
|
|
dest->sub_count = src->count;
|
|
dest->xmin = src->xmin;
|
|
dest->xmax = src->xmax;
|
|
dest->ymin = src->ymin;
|
|
dest->ymax = src->ymax;
|
|
dest->bits[0] = src->bits[0];
|
|
dest->bits[1] = src->bits[1];
|
|
dest->bits[2] = src->bits[2];
|
|
dest->bits[3] = src->bits[3];
|
|
}
|
|
|
|
bool FMAddress::_packJibun(JA_AREA* town,uint8_t* buffer,uint32_t* offset)
|
|
{
|
|
const uint32_t packetSize = sizeof(_JA_AREA_PACKET);
|
|
// 지번 파일 시작 옵셋
|
|
const uint32_t jStartOffset = sizeof(_JA_HEADER) + _header.stringSize + (_header.pref_count * packetSize) + (_header.city_count * packetSize) + (_header.town_count * packetSize);
|
|
uint32_t byte = _ABitsPackToByte(town->bits);// _bitPackToByte(town); // 레코드당 바이트 크기
|
|
|
|
if(byte > 8) {
|
|
qInfo() << "TOO MANY BYTES!!!!!!!!!!!!!!!!";
|
|
return false;
|
|
}
|
|
|
|
uint32_t off = *offset;
|
|
town->offset = (jStartOffset + off);
|
|
|
|
// mask
|
|
const uint32_t xm = ((1 << town->bits[0])-1); // xmask
|
|
const uint32_t ym = ((1 << town->bits[1])-1); // ymask
|
|
const uint32_t a0m = ((1 << town->bits[2])-1); // a0mask
|
|
const uint32_t a1m = ((1 << town->bits[3])-1); // a1mask
|
|
|
|
|
|
// A0-A1-x-y shift
|
|
const uint32_t xs = town->bits[1] + town->bits[2] + town->bits[3];
|
|
const uint32_t ys = town->bits[2] + town->bits[3]; // a0
|
|
const uint32_t a0s = town->bits[3]; // a0
|
|
const uint32_t a1s = 0; // a1
|
|
|
|
//qInfo() << "---------------------------------------------------";
|
|
//qInfo() << "PACK:" << QString::fromUtf16(town->name) << "BYTE:" << byte << "BITS:" << town->bits[0] << town->bits[1] << town->bits[2] << town->bits[3];
|
|
//qInfo() << "mask:" << xm << ym << a0m << a1m;
|
|
//qInfo() << "shifts:" << xs << ys << a0s << a1s;
|
|
|
|
for(int j = 0;j<town->count;j++)
|
|
{
|
|
uint8_t *pj = &buffer[off];
|
|
|
|
JA_JIBUN* item = &town->subJibuns[j];
|
|
uint32_t x = (uint32_t)(item->x - town->xmin);
|
|
uint32_t y = (uint32_t)(item->y - town->ymin);
|
|
uint32_t a0 = (uint32_t)item->a0;
|
|
uint32_t a1 = (uint32_t)item->a1;
|
|
|
|
uint64_t pp = ((uint64_t)x << xs) | ((uint64_t)y << ys) | (a0 << a0s) | (a1 << a1s);
|
|
uint8_t* pt = (uint8_t*)&pp;
|
|
|
|
// 1244345 -> 235 252 27 0 0 0 0 0
|
|
//qInfo() << "PTB:" << pt[0] << pt[1] << pt[2] << pt[3] << pt[4] << pt[5] << pt[6] << pt[7];
|
|
|
|
memcpy(pj,pt,byte);
|
|
off += byte;
|
|
//qInfo() << "XY:" << x << y << "J:" << a0 << a1 << "P64:" << pp << "OFFSET:" << off;
|
|
|
|
// unpack/verify
|
|
uint8_t vb[8] = {0,};
|
|
memcpy(vb,pt,byte);
|
|
uint64_t *vp = (uint64_t*)vb;
|
|
|
|
uint32_t vx = ((*vp) >> xs) & xm;
|
|
uint32_t vy = ((*vp) >> ys) & ym;
|
|
uint32_t va0 = ((*vp) >> a0s) & a0m;
|
|
uint32_t va1 = ((*vp) >> a1s) & a1m;
|
|
if(vx != x || vy != y || va0 != a0 || va1 != a1) {
|
|
|
|
qInfo() << "PACK:" << QString::fromUtf16(town->name) << "BYTE:" << byte << "BITS:" << town->bits[0] << town->bits[1] << town->bits[2] << town->bits[3];
|
|
qInfo() << "mask:" << xm << ym << a0m << a1m;
|
|
qInfo() << "shifts:" << xs << ys << a0s << a1s;
|
|
qInfo() << "PTB:" << pt[0] << pt[1] << pt[2] << pt[3] << pt[4] << pt[5] << pt[6] << pt[7];
|
|
qInfo() << "XY:" << x << y << "J:" << a0 << a1 << "P64:" << pp << "OFFSET:" << off;
|
|
qInfo() << "!!!!!!! ERROR VXY:" << vx << vy << "J:" << va0 << va1;
|
|
return false;
|
|
}
|
|
}
|
|
*offset = off;
|
|
return true;
|
|
}
|
|
// OFFSET 생성 + 데이터 저장
|
|
void FMAddress::_savePref()
|
|
{
|
|
const uint32_t packetSize = sizeof(_JA_AREA_PACKET);
|
|
|
|
|
|
// 별도로 로딩하여 PREF PACKET = 0 부터 시작해야함
|
|
const uint32_t cityStartOffset = (_header.pref_count * packetSize);
|
|
const uint32_t townStartOffset = cityStartOffset + (_header.city_count * packetSize);
|
|
|
|
// 지번은 파일에서 로딩하여 실제 파일옵셋 저장
|
|
uint8_t *pJibun = (uint8_t*)malloc(_totalJibunBytes);
|
|
memset(pJibun,0,_totalJibunBytes);
|
|
|
|
//uint32_t totalArea = _header.pref_count + countCity + countTown;
|
|
JA_AREA_PACKET* plist = (JA_AREA_PACKET*)malloc(_header.pref_count * packetSize);
|
|
memset(plist,0,_header.pref_count * packetSize);
|
|
|
|
JA_AREA_PACKET* clist = (JA_AREA_PACKET*)malloc(_header.city_count * packetSize);
|
|
memset(clist,0,_header.city_count * packetSize);
|
|
|
|
JA_AREA_PACKET* tlist = (JA_AREA_PACKET*)malloc(_header.town_count * packetSize);
|
|
memset(tlist,0,_header.town_count * packetSize);
|
|
|
|
//int pIndex = 0; == p
|
|
int cIndex = 0;
|
|
int tIndex = 0;
|
|
uint32_t jOffset = 0;
|
|
|
|
// HEADER + STRING TABLE + PREFS.... + CITYS.... + TOWNS.... + JIBUNS....
|
|
for(uint32_t p=0;p<_header.pref_count;p++) { // 도도부현
|
|
JA_AREA* pp = &_prefs[p];
|
|
|
|
JA_AREA_PACKET* ppp = &plist[p];
|
|
_copyPacket(ppp,pp);
|
|
ppp->sub_offset = cityStartOffset + (cIndex * packetSize);
|
|
|
|
for(uint32_t c=0;c<(uint32_t)pp->count;c++) { // 시군구
|
|
JA_AREA* cc = &pp->subAreas[c];
|
|
JA_AREA_PACKET* ccc = &clist[cIndex++];
|
|
_copyPacket(ccc,cc);
|
|
ccc->sub_offset = townStartOffset + (tIndex * packetSize);
|
|
|
|
for(uint32_t t=0;t<(uint32_t)cc->count;t++) { // 동읍면
|
|
JA_AREA* tt = &cc->subAreas[t];
|
|
JA_AREA_PACKET* ttt = &tlist[tIndex++];
|
|
//ttt->sub_offset = 0;//jibunStartOffset;
|
|
|
|
_copyPacket(ttt,tt); // 데이터 저장
|
|
if(_packJibun(tt,pJibun,&jOffset) == false)
|
|
{
|
|
qInfo() << "PACK ERROR:" << QString::fromUtf16((ushort*)pp->name) << QString::fromUtf16((ushort*)cc->name) << QString::fromUtf16((ushort*)tt->name);
|
|
free(plist);
|
|
free(clist);
|
|
free(tlist);
|
|
free(pJibun);
|
|
return;
|
|
}
|
|
ttt->sub_offset = tt->offset;
|
|
|
|
// for(uint32_t j=0;j<(uint32_t)tt->count;j++) { // 번지 BYTE PACKET 생성
|
|
// //JA_JIBUN* jj = &((JA_JIBUN*)tt->offset)[j];
|
|
// // jOffset
|
|
// }
|
|
}
|
|
//tIndex += cc->count;
|
|
}
|
|
//cIndex += pp->count;
|
|
}
|
|
|
|
//uint32_t offset = _writeOffset; // 현재 WRITE OFFSET 에서 시작 (HEADER + STRING TABLE)
|
|
|
|
fwrite(plist,packetSize,_header.pref_count,_outFile);
|
|
fwrite(clist,packetSize,_header.city_count,_outFile);
|
|
fwrite(tlist,packetSize,_header.town_count,_outFile);
|
|
fwrite(pJibun,_totalJibunBytes,1,_outFile);
|
|
|
|
free(plist);
|
|
free(clist);
|
|
free(tlist);
|
|
free(pJibun);
|
|
}
|
|
|
|
//int FMAddress::_bitPackToByte(_JA_AREA * src)
|
|
//{
|
|
// return ceil((double)(src->bits[0] + src->bits[1] + src->bits[2] + src->bits[3])/8.0);
|
|
//}
|
|
|
|
// 중복 문자 필터 + 옵셋 저장
|
|
void FMAddress::_setStringOffset(JA_AREA* area,QString name)
|
|
{
|
|
_totalStringBufferLength += (MAX_JA_AREA_NAME_LEN * 2);
|
|
_totalStringLength += (name.length() * 2);
|
|
if(!_stringTable.contains(name)) {
|
|
area->nameOffset = _currentStringOffset;
|
|
_stringTable.insert(name,area->nameOffset); // HEADER +
|
|
_currentStringOffset += ((name.length()+1) * 2);
|
|
}
|
|
else {
|
|
area->nameOffset = _stringTable.value(name,0);
|
|
}
|
|
}
|
|
void FMAddress::_createStatCSV()
|
|
{
|
|
_totalStringBufferLength = 0;
|
|
_totalStringLength = 0;
|
|
_currentStringOffset = 0;
|
|
|
|
_header.xmin = 160 * 80000;
|
|
_header.ymin = 50 * 120000;
|
|
_header.xmax = 0;
|
|
_header.ymax = 0;
|
|
_header.city_count = 0;
|
|
_header.town_count = 0;
|
|
_header.jibun_count = 0;
|
|
|
|
// LOOP
|
|
for(uint32_t p=0;p<_header.pref_count;p++) { // 도도부현
|
|
JA_AREA* pp = &_prefs[p];
|
|
// qInfo() << QString::fromUtf16(pp->name);
|
|
_initBound(pp);
|
|
|
|
_setStringOffset(pp,QString::fromUtf16(pp->name));
|
|
|
|
_header.city_count += pp->count; // 전체 시구군 개수
|
|
for(uint32_t c=0;c<(uint32_t)pp->count;c++) { // 시구군
|
|
JA_AREA* cc = &pp->subAreas[c];
|
|
//qInfo() << QString::fromUtf16(cc->name) << cc->count << __FUNCTION__ << __LINE__;;
|
|
_setStringOffset(cc,QString::fromUtf16(cc->name));
|
|
_header.town_count += cc->count; // 전체 TOWN 개수
|
|
|
|
_initBound(cc);
|
|
for(uint32_t t=0;t<(uint32_t)cc->count;t++) { // 동읍면
|
|
JA_AREA* tt = &cc->subAreas[t];
|
|
_setStringOffset(tt,QString::fromUtf16(tt->name));
|
|
_header.jibun_count += tt->count; // 전체 지번 개수
|
|
|
|
// qInfo() << QString::fromUtf16(tt->name) << tt->count << __FUNCTION__ << __LINE__;
|
|
// 丁目 로 끝나지 않는 TOWN 도 많음..
|
|
_initBound(tt);
|
|
for(uint32_t j=0;j<(uint32_t)tt->count;j++) { // 번지
|
|
JA_JIBUN* jj = &tt->subJibuns[j];
|
|
_updateBoundP(tt,jj);
|
|
}
|
|
_updateBound(cc,tt);
|
|
_sortJIBUN(tt); // 지번을 X순으로 정렬
|
|
_calculateBitPack(tt); // 지번 데이터 BIT PACK 계산
|
|
}
|
|
_updateBound(pp,cc);
|
|
}
|
|
_header.xmin = qMin(_header.xmin,pp->xmin);
|
|
_header.ymin = qMin(_header.ymin,pp->ymin);
|
|
_header.xmax = qMax(_header.xmax,pp->xmax);
|
|
_header.ymax = qMax(_header.ymax,pp->ymax);
|
|
}
|
|
|
|
//qInfo() << __FUNCTION__ << __LINE__;
|
|
|
|
// LOOP 2 (CSV 생성)
|
|
QString dest = "C://home//roadmovie//script//jpaddr//report.csv";
|
|
QFile outFile( dest );
|
|
outFile.open( QIODevice::WriteOnly | QIODevice::Text);
|
|
QTextStream str( &outFile );
|
|
str.setCodec("UTF-16LE");
|
|
str.setGenerateByteOrderMark(true);
|
|
|
|
str << "DO,SI,DONG,COUND,XMIN,YMIN,XMAX,YMAX,BYTE,XB,YB,A0B,A1B\n";
|
|
_totalJibunBytes = 0;
|
|
|
|
for(uint32_t p=0;p<_header.pref_count;p++) { // 도도부현
|
|
JA_AREA* pp = &_prefs[p];
|
|
str << QString::fromUtf16(pp->name) << ",__,__," << QString::number(pp->count) << ",";
|
|
str << QString::number(pp->xmin) << "," << QString::number(pp->ymin) << "," << QString::number(pp->xmax) << "," << QString::number(pp->ymax) << "\n";
|
|
|
|
for(uint32_t c=0;c<(uint32_t)pp->count;c++) { // 시군구
|
|
JA_AREA* cc = &pp->subAreas[c];
|
|
str << QString::fromUtf16(pp->name) << "," << QString::fromUtf16(cc->name) << ",__," << QString::number(cc->count) << ",";
|
|
str << QString::number(cc->xmin) << "," << QString::number(cc->ymin) << "," << QString::number(cc->xmax) << "," << QString::number(cc->ymax) << "\n";
|
|
for(uint32_t t=0;t<(uint32_t)cc->count;t++) { // 동읍면
|
|
JA_AREA* tt = &cc->subAreas[t];
|
|
str << QString::fromUtf16(pp->name) << "," << QString::fromUtf16(cc->name) << "," << QString::fromUtf16(tt->name) << "," << QString::number(tt->count) << "," ;
|
|
str << QString::number(tt->xmin) << "," << QString::number(tt->ymin) << "," << QString::number(tt->xmax) << "," << QString::number(tt->ymax) << ",";
|
|
|
|
// _bitPackToByte(tt)
|
|
_totalJibunBytes += ( _ABitsPackToByte(tt->bits) * tt->count);
|
|
//uint8_t bt = 0;
|
|
//str << _calculateBitPack(tt,&bt) << "\n";
|
|
//totalByte += ((tt->bits[0] + tt->bits[1] + tt->bits[2] + tt->bits[0]) * tt->count);
|
|
// for(int j=0;j<tt->count;j++) { // 번지
|
|
// JA_JIBUN* jj = &((JA_JIBUN*)tt->offset)[j];
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
//qInfo() << __FUNCTION__ << __LINE__;
|
|
// 현,개수
|
|
// -> 시,개수
|
|
// -> 동,개수,xmin,ymin,xmax,ymax
|
|
outFile.close();
|
|
qInfo() << "TOTAL JIBUN BYTES:" << _totalJibunBytes;
|
|
qInfo() << "STRINGS:" << _totalStringLength << _currentStringOffset << _totalStringBufferLength;
|
|
_header.stringSize = _currentStringOffset;
|
|
|
|
}
|
|
|
|
void FMAddress::_resizeChome(JA_AREA* chome)
|
|
{
|
|
//qInfo() << QString::fromUtf16(chome->name) << chome->count << __FUNCTION__ << __LINE__;
|
|
if(chome->count > 0) {
|
|
JA_JIBUN* nj = (JA_JIBUN*)malloc(sizeof(_JA_JIBUN) * chome->count);
|
|
memcpy(nj,chome->subJibuns,sizeof(_JA_JIBUN) * chome->count);
|
|
free(chome->subJibuns);
|
|
chome->subJibuns = nj;
|
|
}
|
|
}
|
|
|
|
void FMAddress::_freeConvertData() {
|
|
if(_prefs != NULL) {
|
|
for(uint32_t p=0;p<_header.pref_count;p++) {
|
|
JA_AREA* pref = &_prefs[p];
|
|
if (pref->count > 0) {
|
|
JA_AREA* citys = pref->subAreas;
|
|
for(uint32_t c=0;c<(uint32_t)pref->count;c++)
|
|
{
|
|
JA_AREA* city = &citys[c];
|
|
if (city->count > 0) {
|
|
JA_AREA* chomes = city->subAreas;
|
|
for(uint32_t t=0;t<(uint32_t)city->count;t++)
|
|
{
|
|
JA_AREA* chome = &chomes[t];
|
|
if(chome->count > 0)
|
|
{
|
|
free(chome->subJibuns);
|
|
}
|
|
}
|
|
free(chomes);
|
|
}
|
|
}
|
|
free(citys);
|
|
}
|
|
}
|
|
free(_prefs);
|
|
_prefs = NULL;
|
|
}
|
|
_currentJibun = NULL;
|
|
_currentPref = NULL;
|
|
_currentCity = NULL;
|
|
_currentChome = NULL;
|
|
}
|
|
|
|
#endif // USE_JP_ADDRESS_TOOL
|
|
|
|
#endif // USE_JP_ADDRESS
|