#include "vfkstrm.h" static struct VFKLongName { const char *longname; const char *shortname; } vfk_long_names[] = { { "PARCELY", "PAR" }, { "BUDOVY", "BUD" }, { "CASTI_BUDOV", "CABU" }, { "ZP_OCHRANY_NEM", "ZPOCHN" }, { "D_POZEMKU", "DRUPOZ" }, { "ZP_VYUZITI_POZ", "ZPVYPO" }, { "ZDROJE_PARCEL_ZE", "ZDPAZE" }, { "ZP_URCENI_VYMERY", "ZPURVY" }, { "T_BUDOV", "TYPBUD" }, { "MAPOVE_LISTY", "MAPLIS" }, { "KATASTR_UZEMI", "KATUZE" }, { "CASTI_OBCI", "CASOBC" }, { "R_ZPOCHR", "RZO" }, { "ZP_VYUZITI_BUD", "ZPVYBU" }, { "JEDNOTKY", "JED" }, { "T_JEDNOTEK", "TYPJED" }, { "ZP_VYUZITI_JED", "ZPVYJE" }, { "BONIT_DILY_PARC", "BDP" }, { "OPRAV_SUBJEKTY", "OPSUB" }, { "VLASTNICTVI", "VLA" }, { "CHAR_OS", "CHAROS" }, { "TELESA", "TEL" }, { "JINE_PRAVNI_VZTAHY", "JPV" }, { "T_PRAVNICH_VZTAHU", "TYPRAV" }, { "RIZENI_KU", "RIZKU" }, { "OBJEKTY_RIZENI", "OBJRIZ" }, { "PREDMETY_RIZENI", "PRERIZ" }, { "UCASTNICI", "UCAST" }, { "ADRESY", "ADRUC" }, { "LISTINY", "LISTIN" }, { "DALSI_UDAJE_LISTINY", "DUL" }, { "LISTINY_DALSI_UDAJE", "LDU" }, { "T_LISTIN", "TYPLIS" }, { "T_PREDMETU_R", "TYPPRE" }, { "TYPY_RIZENI", "TYPRIZ" }, { "TYPY_UCASTNIKU", "TYPUCA" }, { "UCASTNICI_TYP", "UCTYP" }, { "R_LIST", "RL" }, { "SOURADNICE_OBRAZU", "SOBR" }, { "SPOJENI_B_POLOH", "SBP" }, { "SPOJENI_B_MAPY", "SBM" }, { "KODY_CHAR_Q_BODU", "KODCHB" }, { "T_SOURAD_SYS", "TYPSOS" }, { "HRANICE_PARCEL", "HP" }, { "OBRAZY_PARCEL", "OP" }, { "OBRAZY_BUDOV", "OB" }, { "DALSI_PRVKY_MAPY", "DPM" }, { "OBRAZY_BODU_BP", "OBBP" }, { "T_PRVKU_P_DAT", "TYPPPD" }, { "HRANICE_BPEJ", "HBPEJ" }, { "OZNACENI_BPEJ", "OBPEJ" }, { "NAVRHY_ZMEN_KM", "NZ" }, { "NZ_ZPMZ", "NZZP" }, { "SOURADNICE_POLOHY", "SPOL" }, { "REZ_PARCELNI_CISLA", "RECI" }, { "DOTCENA_PAR_CISLA", "DOCI" }, { "DOT_HIST_PAR_CISLA", "DOHICI" }, { "SROVNAVACI_SESTAVENI", "SRST" }, { 0 } }; static bool IsPointMap(String name) { return name == "SPOJENI_B_MAPY" || name == "SOURADNICE_OBRAZU" || name == "DALSI_PRVKY_MAPY" || name == "OBRAZY_PARCEL" || name == "OBRAZY_BUDOV" || name == "OBRAZY_BODU_BP" || name == "SOURADNICE_POLOHY" || name == "PARCELY" || name == "BUDOVY"; } inline bool IsIdent(char c) { return c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_'; } static String GetVTypeName(int vtype) { switch(vtype) { default: case VOID_V: return "void"; case ERROR_V: return "error"; case UNKNOWN_V: return "unknown"; case VALUE_V: return "Value"; case INT_V: return "int"; case DOUBLE_V: return "double"; case INT64_V: return "int64"; case STRING_V: return "String"; case WSTRING_V: return "WString"; case DATE_V: return "Date"; case TIME_V: return "Time"; case VALUEARRAY_V: return "ValueArray"; return NFormat("unknown(%d)", vtype); } } inline Time VfkReadTime(const char *p, void *endptr) { int fields[6]; ZeroArray(fields); int nfld = 0; for(;;) if(IsDigit(*p)) { int v = ScanInt(p, &p); if(IsNull(v) || v < 0) return Null; fields[nfld++] = v; if(nfld >= 6) break; } else if(*p == ' ' || *p == ':' || *p == '.') p++; else break; if(endptr) *(const char **)endptr = p; if(nfld < 3) return Null; if(fields[0] >= 1 && fields[0] <= 31 && fields[1] >= 1 && fields[1] <= 12 && fields[2] >= 1900 && fields[2] <= 2900 && fields[3] >= 0 && fields[3] <= 23 && fields[4] >= 0 && fields[4] <= 59 && fields[5] >= 0 && fields[5] <= 59) { Time dt(fields[2], fields[1], fields[0], fields[3], fields[4], fields[5]); if(dt.IsValid()) return dt; } return Null; } static String VFKParsePolvz(const char *text) { for(; *text; text++) if(text[0] == 'P' && text[1] == 'O' && text[2] == 'L' && text[3] == 'V' && text[4] == 'Z' && text[5] == ':') { text += 6; while(*text && (byte)*text <= ' ') text++; const char *b = text; bool slash = false; while(*text && (byte)*text > ' ') if(*text++ == '/') slash = true; String out; int len = text - b; if(slash || len <= 4) out = String(b, text); else { out.Cat(b, len - 4); out.Cat('/'); out.Cat(text - 4, 4); } return out; } return Null; } static String VFKParseDOPLKOD(String s) { const char *p = s; while(*p && !(p[0] == '/' && p[1] == ' ' && p[2] == 'D' && p[3] == 'O' && p[4] == 'P' && p[5] == 'L' && p[6] == 'K' && p[7] == 'O' && p[8] == 'D')) p++; if(!*p) return s; while(p > s.Begin() && (byte)p[-1] <= ' ') p--; return s.Left(p - s.Begin()); } /* void VfkStream::Table::FlushCache() { scanned = scanned_sbp = scanned_sobr = false; row_offsets.Clear(); segment_index.Clear(); point_index.Clear(); extents.Clear(); points.Clear(); sobr_map.Clear(); par_ku_map.Clear(); cobce_obec_map.Clear(); tel_ku_map.Clear(); bud_id_index.Clear(); bud_id_zdb.Clear(); bud_id_ob.Clear(); ku_index.Clear(); obec_kod_index.Clear(); } */ int VfkStream::Table::SizeOfInstance() const { return columns.GetCount() * 100 /* + row_offsets.GetCount() * sizeof(int) + segment_index.GetCount() * sizeof(int) + point_index.GetCount() * sizeof(int) + extents.GetCount() * sizeof(Rectf) + points.GetCount() * sizeof(const Pointf *) + sobr_map.GetCount() * (sizeof(double) + sizeof(Pointf) + 4 * sizeof(int)) + par_ku_map.GetCount() * (6 * sizeof(int)) + cobce_obec_map.GetCount() * (6 * sizeof(int)) + tel_ku_map.GetCount() * (6 * sizeof(int)) + bud_id_zdb.GetCount() * (5 * sizeof(int) + sizeof(Pointf)) + bud_id_ob.GetCount() * 200 + ku_index.GetCount() * (4 * sizeof(int)) + bud_id_index.GetCount() * (4 * sizeof(int)) + obec_kod_index.GetCount() * (4 * sizeof(int)); */ ; } VfkStream::Data::Data(VfkStream *vfk_, Table *table_) : vfk(vfk_), table(table_) { header = table->header; row_buffer.SetCount(table->columns.GetCount()); row_index = -1; } int64 VfkStream::Data::GetCount() const { if(!table->IsScanned()) vfk->ScanTable(*table); return table->header ? vfk->header.GetCount() : table->row_count; } const Vector& VfkStream::Data::operator [] (int64 row) const { if(!table->IsScanned()) vfk->ScanTable(*table); if(header) return vfk->header[(int)row]; ASSERT(row >= 0 && row < table->row_count); if(row != row_index) { row_index = row; vfk->ReadRow(*table, row_index = row, row_buffer); } return row_buffer; } GisObject VfkStream::Data::GetPath(int64 row, double resolution) const { return Null; /* int bs = table->segment_index[row + 0], es = table->segment_index[row + 1]; if(es <= bs) return Null; RefPtr path = new GisObjectPath; path->extent = table->extents[row]; if(path->extent.Width() <= resolution && path->extent.Height() <= resolution) { path->index.SetCount(1, 1); path->points.SetCount(1, path->extent.CenterPoint()); } else { path->index.Reserve(es - bs); int bx = table->point_index[bs], ex = table->point_index[es]; for(int t = bs; t < es; t++) path->index.Add(table->point_index[t + 1] - bx); path->points.Reserve(ex - bx); for(int t = bx; t < ex; t++) path->points.Add(*table->points[t]); } return GisObject(~path); */ } GisObject VfkStream::Data::GetArea(int64 row, double resolution) const { return Null; /* int bs = table->segment_index[row + 0], es = table->segment_index[row + 1]; if(es <= bs) return Null; RefPtr area = new GisObjectArea; area->extent = table->extents[row]; if(area->extent.Width() <= resolution && area->extent.Height() <= resolution) { area->index.SetCount(1, 1); area->points.SetCount(1, area->extent.CenterPoint()); } else { area->index.Reserve(es - bs); int bx = table->point_index[bs], ex = table->point_index[es]; for(int t = bs; t < es; t++) area->index.Add(table->point_index[t + 1] - bx); area->points.Reserve(ex - bx); for(int t = bx; t < ex; t++) area->points.Add(*table->points[t]); } return GisObject(~area); */ } VfkStream::VfkStream() { charset = CHARSET_DEFAULT; } void VfkStream::Open(const VectorMap& fns) { Close(); charset = CHARSET_ISO8859_2; file_groups <<= fns; streams.SetCount(file_groups.GetCount()); for(int i = 0; i < streams.GetCount(); i++) if(!streams[i].Open(file_groups[i])) throw Exc(NFormat("cannot open file '%s'", file_groups[i])); indexfilename = GetTempFileName("vfk"); if(!indexfile.Open(indexfilename, FileStream::CREATE)) throw Exc(NFormat("cannot create indexfile '%s'", indexfilename)); String hdrname = "X_HEADER"; Table& hdr = tables.Add(hdrname); hdr.name = hdr.rawname = hdrname; hdr.header = true; hdr.row_count = 0; ASSERT(hdr.columns.GetCount() == HDR_ID); hdr.AddColumn(Column("ID", STRING_V, 30)); ASSERT(hdr.columns.GetCount() == HDR_ORD); hdr.AddColumn(Column("ORD", INT_V)); ASSERT(hdr.columns.GetCount() == HDR_STR); hdr.AddColumn(Column("STR", STRING_V, 1000)); ASSERT(hdr.columns.GetCount() == HDR_NUM); hdr.AddColumn(Column("NUM", DOUBLE_V)); ASSERT(hdr.columns.GetCount() == HDR_DTM); hdr.AddColumn(Column("DTM", TIME_V)); ASSERT(hdr.columns.GetCount() == HDR_COUNT); Scan(); } void VfkStream::Close() { streams.Clear(); if(indexfile.IsOpen()) { indexfile.Close(); FileDelete(indexfilename); } tables.Clear(); header.Clear(); } int VfkStream::SizeOfInstance() const { int si = sizeof(*this); for(int i = 0; i < tables.GetCount(); i++) si += SizeOf(tables[i]); return si; } /* int VfkStream::MappingSizeOfInstance() const { return mapping.IsOpen() ? mapping.GetLength() : 0; } */ Vector VfkStream::GetTables() const { Vector out; out <<= tables.GetKeys(); return out; } VfkStream::Data VfkStream::GetData(String table) { int f = tables.Find(table); ASSERT(f >= 0); /* if(table == "HRANICE_PARCEL") ScanSBP(table, "HP_ID"); else if(table == "OBRAZY_BUDOV") ScanSBP(table, "OB_ID"); else if(table == "DALSI_PRVKY_MAPY") ScanSBP(table, "DPM_ID"); */ return GetDataRaw(f); } void VfkStream::Dump() { puts(NFormat("Index file: %s", indexfilename)); puts(NFormat("%d file group(s):", file_groups.GetCount())); for(int i = 0; i < file_groups.GetCount(); i++) puts(NFormat("\t[%d] = %d / %s (%n B)", i, file_groups.GetKey(i), file_groups[i], streams[i].IsOpen() ? streams[i].GetSize() : 0)); puts("Tables:"); for(int t = 0; t < tables.GetCount(); t++) { const Table& tbl = tables[t]; puts(NFormat("\tTable(%d, %s (%s)) sections:\n", t, tbl.name, tbl.rawname)); for(int s = 0; s < tbl.file_index.GetCount(); s++) puts(NFormat("\t\t[%d]: file index [%d], range %n .. %n, %n bytes, %n rows", s, tbl.file_index[s], tbl.begin_offset[s], tbl.end_offset[s], tbl.end_offset[s] - tbl.begin_offset[s], tbl.row_count)); /* for(int c = 0; c < tbl.columns.GetCount(); c++) { const Column& col = tbl.columns[c]; puts(NFormat("\t\t(%d, %s): %s %~d", c, col.name, GetVTypeName(col.vtype), col.width)); } */ Data data = GetData(tbl.name); puts(NFormat("%d row(s):", data.GetCount())); for(int i = 0; i < 10 && i < data.GetCount(); i++) { const Vector& row = data[i]; String out; for(int v = 0; v < row.GetCount(); v++) out << (v ? ";" : "") << StdFormat(row[v]); puts(out); } } } void VfkStream::SpeedTest() { for(int i = 0; i < tables.GetCount(); i++) { int begin = msecs(); Data data = GetData(tables[i].name); int get = msecs(); if(data.GetCount() > 0) data[0]; int first = msecs(); for(int r = 1; r < data.GetCount(); r++) data[r]; int nth = msecs(); puts(NFormat("%s: get(%d), first(%d), nth(%2v)", tables[i].name, get - begin, first - get, (nth - first) / max((double)data.GetCount() - 1, 1))); } } bool VfkStream::IsDateTime(String field) const { return field == "PLATNOST" || field == "VYTVORENO"; } WString VfkStream::ReadString(const char *b, const char **endptr) const { if(*b++ != '\"') throw Exc("'\"' expected"); StringBuffer out; for(;;) { const char *b0 = b; while(*b && *b != '\"') b++; out.Cat(b0, b - b0); if(*b != '\"' || *++b != '\"') break; out.Cat(*b++); } if(endptr) *endptr = b; return ToUnicode((String)out, charset); } void VfkStream::ScanHeader(const char *b, Table& table) { int colid = 0; while(*b && *b != '\n') { if(IsAlpha(*b)) { const char *id = b; while(IsIdent(*++b)) ; Column col; col.name = String(id, b); try { while(*b == ' ') b++; col.vtype = ERROR_V; col.width = Null; switch(*b++) { case 'N': { col.vtype = DOUBLE_V; break; } case 'T': { col.vtype = STRING_V; if(!IsDigit(*b)) throw Exc("missing string width"); col.width = ScanInt(b, &b); break; } case 'D': { col.vtype = TIME_V; break; } default: { throw Exc(NFormat("invalid data type '%c'", *--b)); } } if(colid < table.columns.GetCount()) { const Column& old = table.columns[colid]; if(old.name != col.name) throw Exc(NFormat("column name mismatch (%s / %s)", old.name, col.name)); if(old.vtype != col.vtype) throw Exc(NFormat("column type mismatch (%d / %d)", old.vtype, col.vtype)); if(old.width != col.width) throw Exc(NFormat("column width mismatch (%~d / %~d)", old.width, col.width)); } else table.AddColumn(col); colid++; } catch(Exc e) { throw Exc(NFormat("column '%s': %s", colid, e)); } } else b++; } } void VfkStream::SkipRow(Stream& strm) { RTIMING("VfkStream::SkipRow"); enum { BATCH = 100 }; char buffer[BATCH + 1]; int count = strm.Get(buffer, BATCH); buffer[count] = '\n'; const char *p = buffer; for(;;) if(*p == '\n') { if(p - buffer < count) { strm.SeekCur((p - buffer) - count + 1); return; } buffer[count = strm.Get(buffer, BATCH)] = '\n'; p = buffer; if(!count) return; } else if(*p++ == '\"') { for(;;) { if(*p == '\n' && p - buffer >= count) { buffer[count = strm.Get(buffer, BATCH)] = '\n'; p = buffer; if(!count) return; } else if(*p++ == '\"') { if(*p == '\n' && p - buffer >= count) { buffer[count = strm.Get(buffer, BATCH)] = '\n'; p = buffer; if(!count) return; } if(*p != '\"') break; p++; } } } } /* void VfkStream::ScanRow(Table& table) const { table.row_offsets.Add(b - (const char *)mapping.Begin() - 1); return SkipRow(b); } */ void VfkStream::ReadRow(const Table& table, int64 index, Vector& row) { RTIMING("VfkStream::ReadRow"); indexfile.Seek(table.row_offsets_xpos + 12 * index); int64 off = indexfile.Get64le(); int len = indexfile.Get16le(); int ixf = indexfile.Get16le(); if(off < 0 || len < 0 || ixf < 0 || ixf > streams.GetCount()) return; Buffer rowbuf(len + 1); Stream& strm = streams[ixf]; strm.Seek(off); strm.Get(rowbuf, len); rowbuf[len] = 0; const char *b = rowbuf; for(int i = 0; *b++ == ';' && i < row.GetCount(); i++) { switch(table.columns[i].vtype) { case DOUBLE_V: { row[i] = ScanDouble(b, &b); break; } case TIME_V: { if(*b == '\"') { row[i] = VfkReadTime(b + 1, &b); if(*b == '\"') b++; } break; } case STRING_V: { row[i] = ReadString(b, &b); break; } default: NEVER(); return; } } } void VfkStream::Scan() { RTIMING("VfkStream::Scan"); for(int i = 0; i < file_groups.GetCount(); i++) ScanFile(i); } void VfkStream::ScanFile(int fx) { RTIMING("VfkStream::ScanFile"); Stream& strm = streams[fx]; int64 last_line = strm.GetSize(); while(last_line > 0) { strm.Seek(last_line - 1); if(strm.Get() == '\n') break; last_line--; } strm.Seek(0); try { int c; int64 rowpos = strm.GetPos(); while((c = strm.Get()) == '&' && ((c = strm.Get()) == 'H' || c == 'D') && IsAlpha(strm.Term())) { char type = c; int64 begin = strm.GetPos(); SkipRow(strm); rowpos = strm.GetPos(); int len = (int)(strm.GetPos() - begin); StringBuffer linebuf(len + 1); strm.Seek(begin); strm.Get(linebuf, len); linebuf[len] = 0; const char *b = linebuf; const char *id = b; while(IsIdent(*++b)) ; String ident(id, b); if(*b++ != ';') throw Exc(NFormat("';' expected after '%s' (found: '%c', %2:02x)", ident, *b)); if(type == 'D') { String fident = "X_" + ident; int f = tables.Find(fident); if(f < 0) throw Exc(NFormat("unexpected data for filter table '%s'", ident)); // b = ScanRow(b, tables[f]); } else if(IsAlpha(*b)) { String fident = "X_" + ident; Table& tbl = tables.GetAdd(fident); tbl.name = tbl.rawname = fident; tbl.row_count = 0; ScanHeader(b, tbl); } else { do { Vector row; row.SetCount(HDR_COUNT); if(*b == '\"') { WString text = ReadString(b, &b); if(IsDateTime(ident) && !IsNull(text)) { Time dt = VfkReadTime(text.ToString(), NULL); if(IsNull(dt)) throw Exc(NFormat("invalid date/time value %s", AsCString(text.ToString()))); row[HDR_DTM] = dt; } else { row[HDR_STR] = text; if(ident == "CODEPAGE") if(text == WString("EE8MSWIN1250")) charset = CHARSET_WIN1250; } } else { double num = ScanDouble(b, &b); if(IsNull(num)) throw Exc("invalid numeric value"); row[HDR_NUM] = num; } int l = header.FindLast(ident); row[HDR_ID] = ident; row[HDR_ORD] = (l >= 0 ? (int)header[l][HDR_ORD] + 1 : 0); header.Add(ident) = row; } while(*b++ == ';'); b--; } } strm.Seek(rowpos); while(strm.Get() == '&' && strm.Get() == 'B' && IsAlpha(strm.Term())) { int64 header_offset = strm.GetPos(); SkipRow(strm); int64 begin_offset = strm.GetPos(); int len = (int)(begin_offset - header_offset); Buffer linebuf(len + 1); strm.Seek(header_offset); strm.Get(linebuf, len); linebuf[len] = 0; const char *b = linebuf; const char *id = b; while(IsIdent(*++b)) ; int idlen = b - id; String ident(id, b); if(*b++ != ';') throw Exc(NFormat("';' expected after '%s' (found: '%c', %2:02x)", ident, *b)); String name = ident; for(const VFKLongName *ln = vfk_long_names; ln->shortname; ln++) if(name == ln->shortname) { name = ln->longname; break; } Table& tbl = tables.GetAdd(name); tbl.name = name; tbl.rawname = ident; ScanHeader(b, tbl); int64 p = begin_offset, e = last_line; Buffer idbuf(idlen + 3); while(p < e) { int64 m = (p + e) >> 1; while(m > p) { char part[100]; int partsize = (int)min(m - p, sizeof(part)); strm.Seek(m - partsize); strm.Get(part, partsize); const char *x = &part[partsize]; while(x > part && x[-1] != '\n') x--; int lfpos = x - part; if(x > part && --x > part && x[-1] == '\r') x--; m -= partsize - lfpos; if(x <= part) continue; if(*--x != '\xA4') break; m -= lfpos - (x - part); } strm.Seek(m); if(strm.Get(idbuf, idlen + 3) != idlen + 3 || idbuf[0] != '&' || idbuf[1] != 'D' || memcmp(~idbuf + 2, id, idlen) || idbuf[idlen + 2] != ';') e = m; else { SkipRow(strm); p = strm.GetPos(); } } int xgrp = file_groups.GetKey(fx); int f; for(f = 0; f < tbl.file_index.GetCount(); f++) if(file_groups.GetKey(tbl.file_index[f]) == xgrp) break; if(f >= tbl.file_index.GetCount()) { tbl.file_index.Add(fx); tbl.begin_offset.Add(begin_offset); tbl.end_offset.Add(p); } strm.Seek(p); } } catch(Exc e) { throw Exc(NFormat("%s (offset %n): %s", file_groups[fx], strm.GetPos(), e)); } } void VfkStream::ScanTable(Table& tbl) { RTIMING("VfkStream::ScanTable"); if(tbl.row_count >= 0) return; tbl.row_count = 0; tbl.row_offsets_xpos = indexfile.GetPos(); int idlen = tbl.rawname.GetLength(); enum { READBUF = 10000000 }; Buffer readbuf(READBUF + 1); for(int i = 0; i < tbl.file_index.GetCount(); i++) { RTIMING("VfkStream::ScanTable / file"); int fx = tbl.file_index[i]; Stream& strm = streams[fx]; int64 pos = tbl.begin_offset[i], end = tbl.end_offset[i]; while(pos < end) { RTIMING("VfkStream::ScanTable / buffer"); strm.Seek(pos); int part = strm.Get(readbuf, (int)min(end - pos, READBUF)); readbuf[part] = '\n'; const char *b = readbuf, *e = b + part; for(;;) { RTIMING("VfkStream::ScanTable / row"); int64 boff = pos + (b - ~readbuf); if(e - b < idlen + 3) { pos = boff; break; } if(b[0] != '&' || b[1] != 'D' || memcmp(b + 2, tbl.rawname, idlen) || b[2 + idlen] != ';') { pos = end; break; } b += 3 + idlen; int64 eoff = -1; while(b < e) { if(*b == '\n') { if(b < e) eoff = pos + (++b - ~readbuf); break; } else if(*b++ == '\"') { for(;;) if(*b == '\n' && b >= e) break; else if(*b++ == '\"') { if(*b == '\n' && b >= e) break; if(*b != '\"') break; b++; } } } if(eoff < 0) { pos = boff; break; } RTIMING("VfkStream::ScanTable / index stream write"); indexfile.Put64le(boff); indexfile.Put16le((int)(eoff - boff)); indexfile.Put16le(fx); tbl.row_count++; } } } } VfkStream::Data VfkStream::GetDataRaw(int t) { RTIMING("VfkStream::GetData"); return Data(this, &tables[t]); } /* void VfkStream::ScanSOBR() { int f = tables.Find("SOURADNICE_OBRAZU"); if(f < 0 || !tables[f].sobr_map.IsEmpty()) return; Table& sobr = tables[f]; int id = sobr.columns.Find("ID"); int px = sobr.columns.Find("SOURADNICE_Y"); int py = sobr.columns.Find("SOURADNICE_X"); if(id < 0 || px < 0 || py < 0) return; Data data = GetDataRaw(f); for(int i = 0, dc = data.GetCount(); i < dc; i++) { const Vector& row = data[i]; double x = row[px], y = row[py]; if(!IsNull(x) && !IsNull(y)) sobr.sobr_map.Add(row[id], Pointf(-x, -y)); } } */ /* void VfkStream::ScanSBP(String table, String sbp_id) { int tf = tables.Find(table), sf = tables.Find("SPOJENI_B_POLOH"), of = tables.Find("SOURADNICE_OBRAZU"); if(tf < 0 || sf < 0 || of < 0) return; Table& tbl = tables[tf]; int tid = tbl.columns.Find("ID"); if(tid < 0 || tbl.scanned_sbp) return; Data tdata = GetDataRaw(tf); tbl.segment_index.SetCount(tdata.GetCount() + 1, 0); tbl.point_index.Add(0); tbl.extents.SetCount(tdata.GetCount(), Null); tbl.scanned_sbp = true; Table& sbp = tables[sf]; int rid = sbp.columns.Find(sbp_id); int por = sbp.columns.Find("PORADOVE_CISLO_BODU"); int pid = sbp.columns.Find("BP_ID"); if(rid < 0 || por < 0 || pid < 0) return; ScanSOBR(); Table& sobr = tables[of]; Index rid_index; Vector< Vector > por_lists; Vector< Vector > pid_lists; Data sdata = GetDataRaw(sf); for(int i = 0, sc = sdata.GetCount(); i < sc; i++) { const Vector& row = sdata[i]; if(!IsNull(row[rid])) { int n = rid_index.FindAdd(row[rid]); por_lists.At(n).Add(row[por]); pid_lists.At(n).Add(row[pid]); } } for(int i = 0, tc = tdata.GetCount(); i < tc; i++) { Rectf ext = Null; int f = rid_index.Find(tdata[i][tid]); if(f >= 0) { Vector& por = por_lists[f]; Vector& pid = pid_lists[f]; IndexSort(por, pid); for(int j = 0; j < pid.GetCount(); j++) { int p = sobr.sobr_map.Find(pid[j]); if(p >= 0) ext |= *(tbl.points.Add() = &sobr.sobr_map[p]); } if(!pid.IsEmpty()) tbl.point_index.Add(tbl.points.GetCount()); } tbl.extents[i] = ext; tbl.segment_index[i + 1] = tbl.point_index.GetCount() - 1; } } */ /* void VfkStream::ScanParKUMap() { int pf = tables.Find("PARCELY"); if(pf < 0) return; Table& par = tables[pf]; if(!par.par_ku_map.IsEmpty()) return; Data pdata = GetDataRaw(pf); int pid = par.columns.Find("BUD_ID"); if(pid < 0) return; int kid = par.columns.Find("KATUZE_KOD"); if(kid < 0) return; for(int i = 0, pc = pdata.GetCount(); i < pc; i++) { const Vector& row = pdata[i]; par.par_ku_map.Add(row[pid], row[kid]); } } */ /* void VfkStream::ScanTelKUMap() { int tf = tables.Find("TELESA"); if(tf < 0) return; Table& tel = tables[tf]; if(!tel.tel_ku_map.IsEmpty()) return; Data tdata = GetDataRaw(tf); int tid = tel.columns.Find("ID"); if(tid < 0) return; int kid = tel.columns.Find("KATUZE_KOD"); if(kid < 0) return; for(int i = 0, tc = tdata.GetCount(); i < tc; i++) { const Vector& row = tdata[i]; tel.tel_ku_map.Add(row[tid], row[kid]); } } */ /* void VfkStream::ScanKuIndex() { int kf = tables.Find("KATASTR_UZEMI"); if(kf < 0) return; Table& kat = tables[kf]; if(!kat.ku_index.IsEmpty()) return; Data tdata = GetDataRaw(kf); int kod = kat.columns.Find("KOD"); if(kod < 0) return; int tc = tdata.GetCount(); kat.ku_index.Reserve(tc); for(int i = 0; i < tc; i++) kat.ku_index.Add(tdata[i][kod]); } */ /* void VfkStream::ScanBudIndex() { int bf = tables.Find("BUDOVY"); if(bf < 0) return; Table& bud = tables[bf]; if(!bud.bud_id_index.IsEmpty()) return; Data tdata = GetDataRaw(bf); int bid = bud.columns.Find("ID"); if(bid < 0) return; int tc = tdata.GetCount(); bud.bud_id_index.Reserve(tc); for(int i = 0; i < tc; i++) bud.bud_id_index.Add(tdata[i][bid]); } */ /* void VfkStream::ScanObrBud() { int of = tables.Find("OBRAZY_BUDOV"); if(of < 0) return; Table& obr = tables[of]; if(!obr.bud_id_ob.IsEmpty() || !obr.bud_id_zdb.IsEmpty()) return; Data tdata = GetDataRaw(of); int bid = obr.columns.Find("BUD_ID"); int sx = obr.columns.Find("SOURADNICE_X"); int sy = obr.columns.Find("SOURADNICE_Y"); int obt = obr.columns.Find("OBRBUD_TYPE"); if(bid < 0 || sx < 0 || sy < 0 || obt < 0) return; int tc = tdata.GetCount(); for(int i = 0; i < tc; i++) { const Vector& row = tdata[i]; int budid = row[bid]; Pointf pt(row[sy], row[sx]); String tp = row[obt]; if(!IsNull(pt.x) && !IsNull(pt.y)) if(tp == "ZDB") obr.bud_id_zdb.Add(budid, -pt); else if(tp == "OB") obr.bud_id_ob.GetAdd(budid).Add(-pt); } } */ /* void VfkStream::ScanObceIndex() { int of = tables.Find("OBCE"); if(of < 0) return; Table& obce = tables[of]; if(!obce.obec_kod_index.IsEmpty()) return; Data tdata = GetDataRaw(of); int kid = obce.columns.Find("KOD"); if(kid < 0) return; int tc = tdata.GetCount(); obce.obec_kod_index.Reserve(tc); for(int i = 0; i < tc; i++) obce.obec_kod_index.Add(tdata[i][kid]); } */ /* void VfkStream::ScanCastiObciMap() { int cf = tables.Find("CASTI_OBCI"); if(cf < 0) return; Table& cobce = tables[cf]; if(!cobce.cobce_obec_map.IsEmpty()) return; Data cdata = GetDataRaw(cf); int ck = cobce.columns.Find("KOD"); if(ck < 0) return; int ok = cobce.columns.Find("OBCE_KOD"); if(ok < 0) return; for(int i = 0, cc = cdata.GetCount(); i < cc; i++) { const Vector& row = cdata[i]; cobce.cobce_obec_map.Add(row[ck], row[ok]); } } */ /* void VfkStream::ScanPAR() { int pf = tables.Find("PARCELY"); if(pf < 0) return; Table& par = tables[pf]; if(par.scanned_sbp) return; par.scanned_sbp = true; Data pdata = GetDataRaw(pf); par.segment_index.SetCount(pdata.GetCount() + 1, 0); par.point_index.Add(0); par.extents.SetCount(pdata.GetCount(), Null); int pid = par.columns.Find("ID"); if(pid < 0) return; int hf = tables.Find("HRANICE_PARCEL"); if(hf < 0) return; Table& hp = tables[hf]; int hp1 = hp.columns.Find("PAR_ID_1"); int hp2 = hp.columns.Find("PAR_ID_2"); if(hp1 < 0 || hp2 < 0) return; ScanSBP("HRANICE_PARCEL", "HP_ID"); Index hp1ix, hp2ix; Data hdata = GetDataRaw(hf); hp1ix.Reserve(hdata.GetCount()); hp2ix.Reserve(hdata.GetCount()); for(int i = 0, dc = hdata.GetCount(); i < dc; i++) { const Vector& row = hdata[i]; hp1ix.Add(row[hp1]); hp2ix.Add(row[hp2]); } for(int i = 0, pc = pdata.GetCount(); i < pc; i++) { Rectf ext = Null; double id = pdata[i][pid]; Index sb, se; Vector sh; for(int i1 = hp1ix.Find(id); i1 >= 0; i1 = hp1ix.FindNext(i1)) { int bi = hp.point_index[hp.segment_index[i1]], li = hp.point_index[hp.segment_index[i1 + 1]] - 1; if(bi < li) { sh.Add(i1); sb.Add(hp.points[bi]); se.Add(hp.points[li]); } } for(int i2 = hp2ix.Find(id); i2 >= 0; i2 = hp2ix.FindNext(i2)) { int bi = hp.point_index[hp.segment_index[i2]], li = hp.point_index[hp.segment_index[i2 + 1]] - 1; if(bi < li) { sh.Add(i2); sb.Add(hp.points[bi]); se.Add(hp.points[li]); } } for(;;) { int f; for(f = 0; f < sh.GetCount() && sb.IsUnlinked(f); f++) ; if(f >= sh.GetCount()) break; int begin = par.points.GetCount(); for(int bi = hp.point_index[hp.segment_index[sh[f]]], ei = hp.point_index[hp.segment_index[sh[f] + 1]]; bi < ei; bi++) ext |= *(par.points.Add() = hp.points[bi]); sb.Unlink(f); se.Unlink(f); const Pointf *close = sb[f]; const Pointf *next = se[f]; while(next != close) { bool direct = true; if((f = sb.Find(next)) >= 0) direct = true; else if((f = se.Find(next)) >= 0) direct = false; else { double d, b = 1e100; for(int x = 0; x < sh.GetCount(); x++) if(!sb.IsUnlinked(x)) { if((d = Distance(*sb[x], *next)) < b) { f = x; direct = true; b = d; } if((d = Distance(*se[x], *next)) < b) { f = x; direct = false; b = d; } } if(f < 0) break; } int bi = hp.point_index[hp.segment_index[sh[f]]]; int ei = hp.point_index[hp.segment_index[sh[f] + 1]]; if(direct) { if(hp.points[bi] != next) ext |= *(par.points.Add() = hp.points[bi]); while(++bi < ei) ext |= *(par.points.Add() = hp.points[bi]); next = hp.points[bi - 1]; } else { if(hp.points[--ei] != next) ext |= *(par.points.Add() = hp.points[ei]); while(--ei >= bi) ext |= *(par.points.Add() = hp.points[ei]); next = hp.points[ei + 1]; } sb.Unlink(f); se.Unlink(f); } if(par.points.GetCount() > begin + 1 && par.points.Top() == par.points[begin]) par.points.Drop(); par.point_index.Add(par.points.GetCount()); } par.segment_index[i + 1] = par.point_index.GetCount() - 1; par.extents[i] = ext; } } */