Code cleanup
[GPXSee.git] / src / map / ENC / mapdata.cpp
blobc460a08757e1d95158864f2fe669a647b023bfbd
1 #include "common/util.h"
2 #include "objects.h"
3 #include "attributes.h"
4 #include "style.h"
5 #include "mapdata.h"
7 using namespace ENC;
9 #define RCNM_VI 110
10 #define RCNM_VC 120
11 #define RCNM_VE 130
12 #define RCNM_VF 140
14 #define PRIM_P 1
15 #define PRIM_L 2
16 #define PRIM_A 3
18 static QMap<uint,uint> orderMapInit()
20 QMap<uint,uint> map;
22 map.insert(TYPE(LIGHTS), 0);
23 map.insert(TYPE(FOGSIG), 0);
25 map.insert(TYPE(CGUSTA), 1);
26 map.insert(TYPE(RSCSTA), 1);
27 map.insert(SUBTYPE(BUAARE, 1), 2);
28 map.insert(SUBTYPE(BUAARE, 5), 3);
29 map.insert(SUBTYPE(BUAARE, 4), 4);
30 map.insert(SUBTYPE(BUAARE, 3), 5);
31 map.insert(SUBTYPE(BUAARE, 2), 6);
32 map.insert(SUBTYPE(BUAARE, 6), 7);
33 map.insert(SUBTYPE(BUAARE, 0), 8);
34 map.insert(TYPE(RDOSTA), 9);
35 map.insert(TYPE(RADSTA), 10);
36 map.insert(TYPE(RTPBCN), 11);
37 map.insert(TYPE(BCNISD), 12);
38 map.insert(TYPE(BCNLAT), 13);
39 map.insert(TYPE(I_BCNLAT), 13);
40 map.insert(TYPE(BCNSAW), 14);
41 map.insert(TYPE(BCNSPP), 15);
42 map.insert(TYPE(BOYCAR), 16);
43 map.insert(TYPE(BOYINB), 17);
44 map.insert(TYPE(BOYISD), 18);
45 map.insert(TYPE(BOYLAT), 19);
46 map.insert(TYPE(I_BOYLAT), 19);
47 map.insert(TYPE(BOYSAW), 20);
48 map.insert(TYPE(BOYSPP), 21);
49 map.insert(TYPE(MORFAC), 22);
50 map.insert(TYPE(OFSPLF), 23);
51 map.insert(TYPE(OBSTRN), 24);
52 map.insert(TYPE(WRECKS), 25);
53 map.insert(TYPE(UWTROC), 26);
54 map.insert(TYPE(WATTUR), 27);
55 map.insert(TYPE(CURENT), 28);
56 map.insert(TYPE(PILBOP), 29);
57 map.insert(TYPE(SISTAT), 30);
58 map.insert(TYPE(I_SISTAT), 30);
59 map.insert(TYPE(RDOCAL), 31);
60 map.insert(TYPE(I_RDOCAL), 31);
61 map.insert(TYPE(I_TRNBSN), 32);
62 map.insert(TYPE(HRBFAC), 33);
63 map.insert(TYPE(I_HRBFAC), 33);
64 map.insert(TYPE(PILPNT), 34);
65 map.insert(TYPE(ACHBRT), 35);
66 map.insert(TYPE(I_ACHBRT), 35);
67 map.insert(TYPE(CRANES), 36);
68 map.insert(TYPE(I_CRANES), 36);
69 map.insert(TYPE(I_WTWGAG), 37);
70 map.insert(TYPE(PYLONS), 38);
71 map.insert(TYPE(SLCONS), 39);
72 map.insert(TYPE(LNDMRK), 40);
73 map.insert(TYPE(SILTNK), 41);
74 map.insert(TYPE(LNDELV), 42);
75 map.insert(TYPE(SMCFAC), 43);
76 map.insert(TYPE(BUISGL), 44);
78 map.insert(TYPE(I_DISMAR), 0xFFFFFFFE);
79 map.insert(TYPE(SOUNDG), 0xFFFFFFFF);
81 return map;
84 static QMap<uint,uint> orderMap = orderMapInit();
86 static uint order(uint type)
88 uint st = ((type>>16) == BUAARE) ? type : (type & 0xFFFF0000);
89 QMap<uint, uint>::const_iterator it(orderMap.find(st));
90 return (it == orderMap.constEnd()) ? (type>>16) + 512 : it.value();
93 static void warning(const ISO8211::Field &FRID, uint PRIM)
95 uint RCID = 0xFFFFFFFF;
96 FRID.subfield("RCID", &RCID);
98 switch (PRIM) {
99 case PRIM_P:
100 qWarning("%u: invalid point feature", RCID);
101 break;
102 case PRIM_L:
103 qWarning("%u: invalid line feature", RCID);
104 break;
105 case PRIM_A:
106 qWarning("%u: invalid area feature", RCID);
107 break;
111 static void pointBounds(const Coordinates &c, double min[2], double max[2])
113 min[0] = c.lon();
114 min[1] = c.lat();
115 max[0] = c.lon();
116 max[1] = c.lat();
119 static void rectcBounds(const RectC &rect, double min[2], double max[2])
121 min[0] = rect.left();
122 min[1] = rect.bottom();
123 max[0] = rect.right();
124 max[1] = rect.top();
127 static bool parseNAME(const ISO8211::Field *f, quint8 *type, quint32 *id,
128 int idx = 0)
130 QByteArray ba(f->data().at(idx).at(0).toByteArray());
131 if (ba.size() != 5)
132 return false;
134 *type = (quint8)(*ba.constData());
135 *id = UINT32(ba.constData() + 1);
137 return true;
140 static const ISO8211::Field *SGXD(const ISO8211::Record &r)
142 const ISO8211::Field *f;
144 if ((f = ISO8211::field(r, "SG2D")))
145 return f;
146 else if ((f = ISO8211::field(r, "SG3D")))
147 return f;
148 else
149 return 0;
152 static bool pointCb(const MapData::Point *point, void *context)
154 QList<MapData::Point> *points = (QList<MapData::Point>*)context;
155 points->append(*point);
156 return true;
159 static bool lineCb(const MapData::Line *line, void *context)
161 QList<MapData::Line> *lines = (QList<MapData::Line>*)context;
162 lines->append(*line);
163 return true;
166 static bool polygonCb(const MapData::Poly *polygon, void *context)
168 QList<MapData::Poly> *polygons = (QList<MapData::Poly>*)context;
169 polygons->append(*polygon);
170 return true;
173 static Coordinates coordinates(int x, int y, uint COMF)
175 return Coordinates(x / (double)COMF, y / (double)COMF);
178 static Coordinates point(const ISO8211::Record &r, uint COMF)
180 const ISO8211::Field *f = SGXD(r);
181 if (!f)
182 return Coordinates();
184 int y = f->data().at(0).at(0).toInt();
185 int x = f->data().at(0).at(1).toInt();
187 return coordinates(x, y, COMF);
190 static uint depthLevel(const QByteArray &ba)
192 double minDepth = ba.isEmpty() ? -1 : ba.toDouble();
194 if (minDepth < 0)
195 return 0;
196 else if (minDepth < 2)
197 return 1;
198 else if (minDepth < 5)
199 return 2;
200 else if (minDepth < 10)
201 return 3;
202 else if (minDepth < 20)
203 return 4;
204 else if (minDepth < 50)
205 return 5;
206 else
207 return 6;
210 static QString hUnits(uint type)
212 switch (type) {
213 case 1:
214 return "m";
215 case 2:
216 return "ft";
217 case 3:
218 return "km";
219 case 4:
220 return "hm";
221 case 5:
222 return "mi";
223 case 6:
224 return "nm";
225 default:
226 return QString();
230 static QString sistat(uint type)
232 switch (type) {
233 case 1:
234 return "SS (Port Control)";
235 case 3:
236 return "SS (INT)";
237 case 6:
238 return "SS (Lock)";
239 case 8:
240 return "SS (Bridge)";
241 default:
242 return "SS";
246 MapData::Point::Point(uint type, const Coordinates &c, const QString &label,
247 const QVector<QByteArray> &params) : _type(type), _pos(c), _label(label)
249 uint hash = (uint)qHash(QPair<double,double>(c.lon(), c.lat()));
250 _id = ((quint64)order(type))<<32 | hash;
252 if (type>>16 == I_DISMAR && params.size()) {
253 _label = hUnits((type>>8)&0xFF) + " " + QString::fromLatin1(params.at(0));
254 _type = SUBTYPE(I_DISMAR, type & 0xFF);
255 } else if ((type>>16 == I_RDOCAL || type>>16 == RDOCAL) && params.size() > 1) {
256 if (!params.at(1).isEmpty())
257 _label = QString("VHF ") + QString::fromLatin1(params.at(1));
258 _param = QVariant(params.at(0).toDouble());
259 } else if (type>>16 == CURENT && params.size() > 1) {
260 if (!params.at(1).isEmpty())
261 _label = QString::fromLatin1(params.at(1))
262 + QString::fromUtf8("\xE2\x80\x89kt");
263 _param = QVariant(params.at(0).toDouble());
264 } else if (type>>16 == I_SISTAT || type>>16 == SISTAT) {
265 if (_label.isEmpty())
266 _label = sistat(type & 0xFF);
267 _type = TYPE(SISTAT);
268 } else if (type>>16 == LNDELV && params.size()) {
269 if (_label.isEmpty())
270 _label = QString::fromLatin1(params.at(0))
271 + QString::fromUtf8("\xE2\x80\x89m");
272 else
273 _label += "\n(" + QString::fromLatin1(params.at(0))
274 + "\xE2\x80\x89m)";
278 MapData::Poly::Poly(uint type, const Polygon &path,
279 const QVector<QByteArray> &params) : _type(type), _path(path)
281 if (type == TYPE(DEPARE) && params.size())
282 _type = SUBTYPE(DEPARE, depthLevel(params.at(0)));
283 else if (type == TYPE(TSSLPT) && params.size())
284 _param = QVariant(params.at(0).toDouble());
287 MapData::Line::Line(uint type, const QVector<Coordinates> &path,
288 const QString &label, const QVector<QByteArray> &params)
289 : _type(type), _path(path), _label(label)
291 if ((type == TYPE(DEPCNT) || type == TYPE(LNDELV)) && params.size())
292 _label = QString::fromLatin1(params.at(0));
295 RectC MapData::Line::bounds() const
297 RectC b;
299 for (int i = 0; i < _path.size(); i++)
300 b = b.united(_path.at(i));
302 return b;
305 QVector<MapData::Sounding> MapData::soundings(const ISO8211::Record &r,
306 uint COMF, uint SOMF)
308 QVector<Sounding> s;
309 const ISO8211::Field *f = ISO8211::field(r, "SG3D");
310 if (!f)
311 return QVector<Sounding>();
313 s.reserve(f->data().size());
314 for (int i = 0; i < f->data().size(); i++) {
315 int y = f->data().at(i).at(0).toInt();
316 int x = f->data().at(i).at(1).toInt();
317 int z = f->data().at(i).at(2).toInt();
318 s.append(Sounding(coordinates(x, y, COMF), z / (double)SOMF));
321 return s;
324 QVector<MapData::Sounding> MapData::soundingGeometry(const ISO8211::Record &r,
325 const RecordMap &vi, const RecordMap &vc, uint COMF, uint SOMF)
327 quint8 type;
328 quint32 id;
329 RecordMapIterator it;
331 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
332 if (!FSPT || FSPT->data().at(0).size() != 4)
333 return QVector<Sounding>();
335 if (!parseNAME(FSPT, &type, &id))
336 return QVector<Sounding>();
338 if (type == RCNM_VI) {
339 it = vi.find(id);
340 if (it == vi.constEnd())
341 return QVector<Sounding>();
342 } else if (type == RCNM_VC) {
343 it = vc.find(id);
344 if (it == vc.constEnd())
345 return QVector<Sounding>();
346 } else
347 return QVector<Sounding>();
349 return soundings(it.value(), COMF, SOMF);
352 Coordinates MapData::pointGeometry(const ISO8211::Record &r,
353 const RecordMap &vi, const RecordMap &vc, uint COMF)
355 quint8 type;
356 quint32 id;
357 RecordMapIterator it;
359 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
360 if (!FSPT || FSPT->data().at(0).size() != 4)
361 return Coordinates();
363 if (!parseNAME(FSPT, &type, &id))
364 return Coordinates();
366 if (type == RCNM_VI) {
367 it = vi.find(id);
368 if (it == vi.constEnd())
369 return Coordinates();
370 } else if (type == RCNM_VC) {
371 it = vc.find(id);
372 if (it == vc.constEnd())
373 return Coordinates();
374 } else
375 return Coordinates();
377 return point(it.value(), COMF);
380 QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r,
381 const RecordMap &vc, const RecordMap &ve, uint COMF)
383 QVector<Coordinates> path;
384 Coordinates c[2];
385 uint ORNT;
386 quint8 type;
387 quint32 id;
389 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
390 if (!FSPT || FSPT->data().at(0).size() != 4)
391 return QVector<Coordinates>();
393 for (int i = 0; i < FSPT->data().size(); i++) {
394 if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE)
395 return QVector<Coordinates>();
396 ORNT = FSPT->data().at(i).at(1).toUInt();
398 RecordMapIterator it = ve.find(id);
399 if (it == ve.constEnd())
400 return QVector<Coordinates>();
401 const ISO8211::Record &FRID = it.value();
402 const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT");
403 if (!VRPT || VRPT->data().size() != 2)
404 return QVector<Coordinates>();
406 for (int j = 0; j < 2; j++) {
407 if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC)
408 return QVector<Coordinates>();
410 RecordMapIterator jt = vc.find(id);
411 if (jt == vc.constEnd())
412 return QVector<Coordinates>();
413 c[j] = point(jt.value(), COMF);
414 if (c[j].isNull())
415 return QVector<Coordinates>();
418 const ISO8211::Field *vertexes = SGXD(FRID);
419 if (ORNT == 2) {
420 path.append(c[1]);
421 if (vertexes) {
422 for (int j = vertexes->data().size() - 1; j >= 0; j--) {
423 const QVector<QVariant> &cv = vertexes->data().at(j);
424 path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
425 COMF));
428 path.append(c[0]);
429 } else {
430 path.append(c[0]);
431 if (vertexes) {
432 for (int j = 0; j < vertexes->data().size(); j++) {
433 const QVector<QVariant> &cv = vertexes->data().at(j);
434 path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
435 COMF));
438 path.append(c[1]);
442 return path;
445 Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc,
446 const RecordMap &ve, uint COMF)
448 Polygon path;
449 QVector<Coordinates> v;
450 Coordinates c[2];
451 uint ORNT, USAG;
452 quint8 type;
453 quint32 id;
455 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
456 if (!FSPT || FSPT->data().at(0).size() != 4)
457 return Polygon();
459 for (int i = 0; i < FSPT->data().size(); i++) {
460 if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE)
461 return Polygon();
462 ORNT = FSPT->data().at(i).at(1).toUInt();
463 USAG = FSPT->data().at(i).at(2).toUInt();
465 if (USAG == 2 && path.isEmpty()) {
466 path.append(v);
467 v.clear();
470 RecordMapIterator it = ve.find(id);
471 if (it == ve.constEnd())
472 return Polygon();
473 const ISO8211::Record &FRID = it.value();
474 const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT");
475 if (!VRPT || VRPT->data().size() != 2)
476 return Polygon();
478 for (int j = 0; j < 2; j++) {
479 if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC)
480 return Polygon();
482 RecordMapIterator jt = vc.find(id);
483 if (jt == vc.constEnd())
484 return Polygon();
485 c[j] = point(jt.value(), COMF);
486 if (c[j].isNull())
487 return Polygon();
490 const ISO8211::Field *vertexes = SGXD(FRID);
491 if (ORNT == 2) {
492 v.append(c[1]);
493 if (USAG == 3)
494 v.append(Coordinates());
495 if (vertexes) {
496 for (int j = vertexes->data().size() - 1; j >= 0; j--) {
497 const QVector<QVariant> &cv = vertexes->data().at(j);
498 v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
499 COMF));
502 if (USAG == 3)
503 v.append(Coordinates());
504 v.append(c[0]);
505 } else {
506 v.append(c[0]);
507 if (USAG == 3)
508 v.append(Coordinates());
509 if (vertexes) {
510 for (int j = 0; j < vertexes->data().size(); j++) {
511 const QVector<QVariant> &cv = vertexes->data().at(j);
512 v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
513 COMF));
516 if (USAG == 3)
517 v.append(Coordinates());
518 v.append(c[1]);
521 if (USAG == 2 && v.first() == v.last()) {
522 path.append(v);
523 v.clear();
527 if (!v.isEmpty())
528 path.append(v);
530 return path;
533 MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL)
535 QString label;
536 QVector<QByteArray> params(2);
537 uint subtype = 0;
539 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
540 if (!(ATTF && ATTF->data().at(0).size() == 2))
541 return Attr();
543 for (int i = 0; i < ATTF->data().size(); i++) {
544 const QVector<QVariant> &av = ATTF->data().at(i);
545 uint key = av.at(0).toUInt();
547 if (key == OBJNAM)
548 label = QString::fromLatin1(av.at(1).toByteArray());
550 if ((OBJL == HRBFAC && key == CATHAF)
551 || (OBJL == I_HRBFAC && key == I_CATHAF)
552 || (OBJL == LNDMRK && key == CATLMK)
553 || (OBJL == WRECKS && key == CATWRK)
554 || (OBJL == MORFAC && key == CATMOR)
555 || (OBJL == UWTROC && key == WATLEV)
556 || (OBJL == BUAARE && key == CATBUA)
557 || (OBJL == SMCFAC && key == CATSCF)
558 || (OBJL == BUISGL && key == FUNCTN)
559 || (OBJL == WATTUR && key == CATWAT)
560 || (OBJL == SISTAT && key == CATSIT)
561 || (OBJL == I_SISTAT && key == I_CATSIT)
562 || (OBJL == RDOCAL && key == TRAFIC)
563 || (OBJL == I_RDOCAL && key == TRAFIC)
564 || (OBJL == SILTNK && key == CATSIL))
565 subtype = av.at(1).toByteArray().toUInt();
566 else if (OBJL == I_DISMAR && key == CATDIS)
567 subtype |= av.at(1).toByteArray().toUInt();
568 else if (OBJL == I_DISMAR && key == I_HUNITS)
569 subtype |= av.at(1).toByteArray().toUInt() << 8;
571 if ((OBJL == I_DISMAR && key == I_WTWDIS)
572 || (OBJL == RDOCAL && key == ORIENT)
573 || (OBJL == I_RDOCAL && key == ORIENT)
574 || (OBJL == CURENT && key == ORIENT)
575 || (OBJL == LNDELV && key == ELEVAT))
576 params[0] = av.at(1).toByteArray();
577 if ((OBJL == I_RDOCAL && key == COMCHA)
578 || (OBJL == RDOCAL && key == COMCHA)
579 || (OBJL == CURENT && key == CURVEL))
580 params[1] = av.at(1).toByteArray();
583 return Attr(subtype, label, params);
586 MapData::Attr MapData::lineAttr(const ISO8211::Record &r, uint OBJL)
588 QString label;
589 QVector<QByteArray> params(1);
590 uint subtype = 0;
592 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
593 if (!(ATTF && ATTF->data().at(0).size() == 2))
594 return Attr();
596 for (int i = 0; i < ATTF->data().size(); i++) {
597 const QVector<QVariant> &av = ATTF->data().at(i);
598 uint key = av.at(0).toUInt();
600 if (key == OBJNAM)
601 label = QString::fromLatin1(av.at(1).toByteArray());
603 if ((OBJL == RECTRC || OBJL == RCRTCL) && key == CATTRK)
604 subtype = av.at(1).toByteArray().toUInt();
606 if ((OBJL == DEPCNT && key == VALDCO)
607 || (OBJL == LNDELV && key == ELEVAT))
608 params[0] = av.at(1).toByteArray();
611 return Attr(subtype, label, params);
614 MapData::Attr MapData::polyAttr(const ISO8211::Record &r, uint OBJL)
616 QString label;
617 QVector<QByteArray> params(1);
618 uint subtype = 0;
620 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
621 if (!(ATTF && ATTF->data().at(0).size() == 2))
622 return Attr();
624 for (int i = 0; i < ATTF->data().size(); i++) {
625 const QVector<QVariant> &av = ATTF->data().at(i);
626 uint key = av.at(0).toUInt();
628 if ((OBJL == RESARE && key == CATREA)
629 || (OBJL == I_RESARE && key == CATREA)
630 || (OBJL == ACHARE && key == CATACH)
631 || (OBJL == I_ACHARE && key == I_CATACH)
632 || (OBJL == HRBFAC && key == CATHAF)
633 || (OBJL == MARKUL && key == CATMFA)
634 || (OBJL == I_BERTHS && key == I_CATBRT))
635 subtype = av.at(1).toByteArray().toUInt();
636 else if ((OBJL == RESARE && key == RESTRN)
637 || (OBJL == I_RESARE && key == I_RESTRN)) {
638 if (av.at(1).toByteArray().toUInt() == 1)
639 subtype = 2;
640 if (av.at(1).toByteArray().toUInt() == 7)
641 subtype = 17;
644 if ((OBJL == TSSLPT && key == ORIENT)
645 || (OBJL == DEPARE && key == DRVAL1))
646 params[0] = av.at(1).toByteArray();
649 return Attr(subtype, label, params);
652 MapData::Point *MapData::pointObject(const Sounding &s)
654 return new Point(TYPE(SOUNDG), s.c, QString::number(s.depth),
655 QVector<QByteArray>());
658 MapData::Point *MapData::pointObject(const ISO8211::Record &r,
659 const RecordMap &vi, const RecordMap &vc, uint COMF, uint OBJL)
661 Coordinates c(pointGeometry(r, vi, vc, COMF));
662 Attr attr(pointAttr(r, OBJL));
664 return (c.isNull() ? 0 : new Point(SUBTYPE(OBJL,attr.subtype()), c,
665 attr.label(), attr.params()));
668 MapData::Line *MapData::lineObject(const ISO8211::Record &r,
669 const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL)
671 QVector<Coordinates> path(lineGeometry(r, vc, ve, COMF));
672 Attr attr(lineAttr(r, OBJL));
674 return (path.isEmpty() ? 0 : new Line(SUBTYPE(OBJL, attr.subtype()), path,
675 attr.label(), attr.params()));
678 MapData::Poly *MapData::polyObject(const ISO8211::Record &r,
679 const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL)
681 Polygon path(polyGeometry(r, vc, ve, COMF));
682 Attr attr(polyAttr(r, OBJL));
684 return (path.isEmpty() ? 0 : new Poly(SUBTYPE(OBJL, attr.subtype()), path,
685 attr.params()));
688 bool MapData::processRecord(const ISO8211::Record &record,
689 QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve,
690 RecordMap &vf, uint &COMF, uint &SOMF)
692 if (record.size() < 2)
693 return false;
695 const ISO8211::Field &f = record.at(1);
696 const QByteArray &ba = f.tag();
698 if (ba == "VRID") {
699 if (f.data().at(0).size() < 2)
700 return false;
701 int RCNM = f.data().at(0).at(0).toInt();
702 uint RCID = f.data().at(0).at(1).toUInt();
704 switch (RCNM) {
705 case RCNM_VI:
706 vi.insert(RCID, record);
707 break;
708 case RCNM_VC:
709 vc.insert(RCID, record);
710 break;
711 case RCNM_VE:
712 ve.insert(RCID, record);
713 break;
714 case RCNM_VF:
715 vf.insert(RCID, record);
716 break;
717 default:
718 return false;
720 } else if (ba == "FRID") {
721 fe.append(record);
722 } else if (ba == "DSPM") {
723 if (!(f.subfield("COMF", &COMF) && f.subfield("SOMF", &SOMF)))
724 return false;
727 return true;
730 MapData::MapData(const QString &path)
732 RecordMap vi, vc, ve, vf;
733 QVector<ISO8211::Record> fe;
734 ISO8211 ddf(path);
735 ISO8211::Record record;
736 uint PRIM, OBJL, COMF = 1, SOMF = 1;
737 Poly *poly;
738 Line *line;
739 Point *point;
740 double min[2], max[2];
743 if (!ddf.readDDR())
744 return;
745 while (ddf.readRecord(record))
746 if (!processRecord(record, fe, vi, vc, ve, vf, COMF, SOMF))
747 qWarning("Invalid S-57 record");
749 for (int i = 0; i < fe.size(); i++) {
750 const ISO8211::Record &r = fe.at(i);
751 const ISO8211::Field &f = r.at(1);
753 if (f.data().at(0).size() < 5)
754 continue;
755 PRIM = f.data().at(0).at(2).toUInt();
756 OBJL = f.data().at(0).at(4).toUInt();
758 switch (PRIM) {
759 case PRIM_P:
760 if (OBJL == SOUNDG) {
761 QVector<Sounding> s(soundingGeometry(r, vi, vc, COMF, SOMF));
762 for (int i = 0; i < s.size(); i++) {
763 point = pointObject(s.at(i));
764 pointBounds(point->pos(), min, max);
765 _points.Insert(min, max, point);
767 } else {
768 if ((point = pointObject(r, vi, vc, COMF, OBJL))) {
769 pointBounds(point->pos(), min, max);
770 _points.Insert(min, max, point);
771 } else
772 warning(f, PRIM);
774 break;
775 case PRIM_L:
776 if ((line = lineObject(r, vc, ve, COMF, OBJL))) {
777 rectcBounds(line->bounds(), min, max);
778 _lines.Insert(min, max, line);
779 } else
780 warning(f, PRIM);
781 break;
782 case PRIM_A:
783 if ((poly = polyObject(r, vc, ve, COMF, OBJL))) {
784 rectcBounds(poly->bounds(), min, max);
785 _areas.Insert(min, max, poly);
786 } else
787 warning(f, PRIM);
788 break;
793 MapData::~MapData()
795 LineTree::Iterator lit;
796 for (_lines.GetFirst(lit); !_lines.IsNull(lit); _lines.GetNext(lit))
797 delete _lines.GetAt(lit);
799 PolygonTree::Iterator ait;
800 for (_areas.GetFirst(ait); !_areas.IsNull(ait); _areas.GetNext(ait))
801 delete _areas.GetAt(ait);
803 PointTree::Iterator pit;
804 for (_points.GetFirst(pit); !_points.IsNull(pit); _points.GetNext(pit))
805 delete _points.GetAt(pit);
808 void MapData::points(const RectC &rect, QList<Point> *points) const
810 double min[2], max[2];
812 rectcBounds(rect, min, max);
813 _points.Search(min, max, pointCb, points);
816 void MapData::lines(const RectC &rect, QList<Line> *lines) const
818 double min[2], max[2];
820 rectcBounds(rect, min, max);
821 _lines.Search(min, max, lineCb, lines);
824 void MapData::polygons(const RectC &rect, QList<Poly> *polygons) const
826 double min[2], max[2];
828 rectcBounds(rect, min, max);
829 _areas.Search(min, max, polygonCb, polygons);