Added land and see areas labels
[GPXSee.git] / src / map / ENC / mapdata.cpp
bloba850b6e5f567d101e3d1012a387acf72ec7e10d8
1 #include "GUI/units.h"
2 #include "objects.h"
3 #include "attributes.h"
4 #include "mapdata.h"
6 using namespace ENC;
8 #define RCNM_VI 110
9 #define RCNM_VC 120
10 #define RCNM_VE 130
11 #define RCNM_VF 140
13 #define PRIM_P 1
14 #define PRIM_L 2
15 #define PRIM_A 3
17 static QMap<uint,uint> orderMapInit()
19 QMap<uint,uint> map;
21 map.insert(TYPE(LIGHTS), 0);
22 map.insert(TYPE(FOGSIG), 0);
24 map.insert(TYPE(CGUSTA), 1);
25 map.insert(TYPE(RSCSTA), 1);
26 map.insert(SUBTYPE(BUAARE, 1), 2);
27 map.insert(SUBTYPE(BUAARE, 5), 3);
28 map.insert(SUBTYPE(BUAARE, 4), 4);
29 map.insert(SUBTYPE(BUAARE, 3), 5);
30 map.insert(SUBTYPE(BUAARE, 2), 6);
31 map.insert(SUBTYPE(BUAARE, 6), 7);
32 map.insert(SUBTYPE(BUAARE, 0), 8);
33 map.insert(TYPE(RDOSTA), 9);
34 map.insert(TYPE(RADSTA), 10);
35 map.insert(TYPE(RTPBCN), 11);
36 map.insert(TYPE(BCNISD), 12);
37 map.insert(TYPE(BCNLAT), 13);
38 map.insert(TYPE(I_BCNLAT), 13);
39 map.insert(TYPE(BCNSAW), 14);
40 map.insert(TYPE(BCNSPP), 15);
41 map.insert(TYPE(BOYCAR), 16);
42 map.insert(TYPE(BOYINB), 17);
43 map.insert(TYPE(BOYISD), 18);
44 map.insert(TYPE(BOYLAT), 19);
45 map.insert(TYPE(I_BOYLAT), 19);
46 map.insert(TYPE(BOYSAW), 20);
47 map.insert(TYPE(BOYSPP), 21);
48 map.insert(TYPE(MORFAC), 22);
49 map.insert(TYPE(OFSPLF), 23);
50 map.insert(TYPE(OBSTRN), 24);
51 map.insert(TYPE(WRECKS), 25);
52 map.insert(TYPE(UWTROC), 26);
53 map.insert(TYPE(WATTUR), 27);
54 map.insert(TYPE(CURENT), 28);
55 map.insert(TYPE(PILBOP), 29);
56 map.insert(TYPE(SISTAT), 30);
57 map.insert(TYPE(I_SISTAT), 30);
58 map.insert(TYPE(RDOCAL), 31);
59 map.insert(TYPE(I_RDOCAL), 31);
60 map.insert(TYPE(I_TRNBSN), 32);
61 map.insert(TYPE(HRBFAC), 33);
62 map.insert(TYPE(I_HRBFAC), 33);
63 map.insert(TYPE(PILPNT), 34);
64 map.insert(TYPE(ACHBRT), 35);
65 map.insert(TYPE(I_ACHBRT), 35);
66 map.insert(TYPE(CRANES), 36);
67 map.insert(TYPE(I_CRANES), 36);
68 map.insert(TYPE(I_WTWGAG), 37);
69 map.insert(TYPE(PYLONS), 38);
70 map.insert(TYPE(SLCONS), 39);
71 map.insert(TYPE(LNDMRK), 40);
72 map.insert(TYPE(SILTNK), 41);
73 map.insert(TYPE(LNDELV), 42);
74 map.insert(TYPE(SMCFAC), 43);
75 map.insert(TYPE(BUISGL), 44);
77 map.insert(TYPE(I_DISMAR), 0xFFFFFFFE);
78 map.insert(TYPE(SOUNDG), 0xFFFFFFFF);
80 return map;
83 static QMap<uint,uint> orderMap = orderMapInit();
85 static uint order(uint type)
87 uint st = ((type>>16) == BUAARE) ? type : (type & 0xFFFF0000);
88 QMap<uint, uint>::const_iterator it(orderMap.find(st));
89 return (it == orderMap.constEnd()) ? (type>>16) + 512 : it.value();
92 static void warning(const ISO8211::Field &FRID, uint PRIM)
94 uint RCID = 0xFFFFFFFF;
95 FRID.subfield("RCID", &RCID);
97 switch (PRIM) {
98 case PRIM_P:
99 qWarning("%u: invalid point feature", RCID);
100 break;
101 case PRIM_L:
102 qWarning("%u: invalid line feature", RCID);
103 break;
104 case PRIM_A:
105 qWarning("%u: invalid area feature", RCID);
106 break;
110 static void pointBounds(const Coordinates &c, double min[2], double max[2])
112 min[0] = c.lon();
113 min[1] = c.lat();
114 max[0] = c.lon();
115 max[1] = c.lat();
118 static void rectcBounds(const RectC &rect, double min[2], double max[2])
120 min[0] = rect.left();
121 min[1] = rect.bottom();
122 max[0] = rect.right();
123 max[1] = rect.top();
126 static bool parseNAME(const ISO8211::Field *f, quint8 *type, quint32 *id,
127 int idx = 0)
129 QByteArray ba(f->data().at(idx).at(0).toByteArray());
130 if (ba.size() != 5)
131 return false;
133 *type = (quint8)(*ba.constData());
134 *id = UINT32(ba.constData() + 1);
136 return true;
139 static const ISO8211::Field *SGXD(const ISO8211::Record &r)
141 const ISO8211::Field *f;
143 if ((f = ISO8211::field(r, "SG2D")))
144 return f;
145 else if ((f = ISO8211::field(r, "SG3D")))
146 return f;
147 else
148 return 0;
151 static bool pointCb(const MapData::Point *point, void *context)
153 QList<MapData::Point> *points = (QList<MapData::Point>*)context;
154 points->append(*point);
155 return true;
158 static bool lineCb(const MapData::Line *line, void *context)
160 QList<MapData::Line> *lines = (QList<MapData::Line>*)context;
161 lines->append(*line);
162 return true;
165 static bool polygonCb(const MapData::Poly *polygon, void *context)
167 QList<MapData::Poly> *polygons = (QList<MapData::Poly>*)context;
168 polygons->append(*polygon);
169 return true;
172 static Coordinates coordinates(int x, int y, uint COMF)
174 return Coordinates(x / (double)COMF, y / (double)COMF);
177 static Coordinates point(const ISO8211::Record &r, uint COMF)
179 const ISO8211::Field *f = SGXD(r);
180 if (!f)
181 return Coordinates();
183 int y = f->data().at(0).at(0).toInt();
184 int x = f->data().at(0).at(1).toInt();
186 return coordinates(x, y, COMF);
189 static uint depthLevel(const QByteArray &ba)
191 double minDepth = ba.isEmpty() ? -1 : ba.toDouble();
193 if (minDepth < 0)
194 return 0;
195 else if (minDepth < 2)
196 return 1;
197 else if (minDepth < 5)
198 return 2;
199 else if (minDepth < 10)
200 return 3;
201 else if (minDepth < 20)
202 return 4;
203 else if (minDepth < 50)
204 return 5;
205 else
206 return 6;
209 static QString hUnits(uint type)
211 switch (type) {
212 case 1:
213 return "m";
214 case 2:
215 return "ft";
216 case 3:
217 return "km";
218 case 4:
219 return "hm";
220 case 5:
221 return "mi";
222 case 6:
223 return "nm";
224 default:
225 return QString();
229 static QString sistat(uint type)
231 switch (type) {
232 case 1:
233 return "SS (Port Control)";
234 case 3:
235 return "SS (INT)";
236 case 6:
237 return "SS (Lock)";
238 case 8:
239 return "SS (Bridge)";
240 default:
241 return "SS";
245 static QString weed(uint type)
247 switch (type) {
248 case 2:
249 return "Wd";
250 case 3:
251 return "Sg";
252 default:
253 return QString();
257 MapData::Point::Point(uint type, const Coordinates &c, const QString &label,
258 const QVector<QByteArray> &params) : _type(type), _pos(c), _label(label)
260 _id = ((quint64)order(type))<<32 | (uint)qHash(c);
262 if (type>>16 == I_DISMAR && params.size()) {
263 _label = hUnits((type>>8)&0xFF) + " " + QString::fromLatin1(params.at(0));
264 _type = SUBTYPE(I_DISMAR, type & 0xFF);
265 } else if ((type>>16 == I_RDOCAL || type>>16 == RDOCAL) && params.size() > 1) {
266 if (!params.at(1).isEmpty())
267 _label = QString("VHF ") + QString::fromLatin1(params.at(1));
268 _param = QVariant(params.at(0).toDouble());
269 } else if (type>>16 == CURENT && params.size() > 1) {
270 if (!params.at(1).isEmpty())
271 _label = QString::fromLatin1(params.at(1))
272 + QString::fromUtf8("\xE2\x80\x89kt");
273 _param = QVariant(params.at(0).toDouble());
274 } else if (type>>16 == I_SISTAT || type>>16 == SISTAT) {
275 if (_label.isEmpty())
276 _label = sistat(type & 0xFF);
277 _type = TYPE(SISTAT);
278 } else if (type>>16 == WEDKLP) {
279 if (_label.isEmpty())
280 _label = weed(type & 0xFF);
281 } else if (type>>16 == LNDELV && params.size()) {
282 if (_label.isEmpty())
283 _label = QString::fromLatin1(params.at(0))
284 + QString::fromUtf8("\xE2\x80\x89m");
285 else
286 _label += "\n(" + QString::fromLatin1(params.at(0))
287 + "\xE2\x80\x89m)";
291 MapData::Poly::Poly(uint type, const Polygon &path, const QString &label,
292 const QVector<QByteArray> &params, uint HUNI) : _type(type), _path(path)
294 if (type == TYPE(DEPARE) && params.size())
295 _type = SUBTYPE(DEPARE, depthLevel(params.at(0)));
296 else if (type == TYPE(TSSLPT) && params.size())
297 _param = QVariant(params.at(0).toDouble());
298 else if ((type == TYPE(BRIDGE) || type == TYPE(I_BRIDGE))
299 && params.size()) {
300 double clr = params.at(0).toDouble();
301 if (clr > 0) {
302 _label = QString::fromUtf8("\xE2\x86\x95") + UNIT_SPACE
303 + QString::number(clr) + UNIT_SPACE + hUnits(HUNI);
305 } else if (type>>16 == LNDARE || type>>16 == SEAARE)
306 _label = label;
309 MapData::Line::Line(uint type, const QVector<Coordinates> &path,
310 const QString &label, const QVector<QByteArray> &params)
311 : _type(type), _path(path), _label(label)
313 if ((type == TYPE(DEPCNT) || type == TYPE(LNDELV)) && params.size())
314 _label = QString::fromLatin1(params.at(0));
317 RectC MapData::Line::bounds() const
319 RectC b;
321 for (int i = 0; i < _path.size(); i++)
322 b = b.united(_path.at(i));
324 return b;
327 QVector<MapData::Sounding> MapData::soundings(const ISO8211::Record &r,
328 uint COMF, uint SOMF)
330 QVector<Sounding> s;
331 const ISO8211::Field *f = ISO8211::field(r, "SG3D");
332 if (!f)
333 return QVector<Sounding>();
335 s.reserve(f->data().size());
336 for (int i = 0; i < f->data().size(); i++) {
337 int y = f->data().at(i).at(0).toInt();
338 int x = f->data().at(i).at(1).toInt();
339 int z = f->data().at(i).at(2).toInt();
340 s.append(Sounding(coordinates(x, y, COMF), z / (double)SOMF));
343 return s;
346 QVector<MapData::Sounding> MapData::soundingGeometry(const ISO8211::Record &r,
347 const RecordMap &vi, const RecordMap &vc, uint COMF, uint SOMF)
349 quint8 type;
350 quint32 id;
351 RecordMapIterator it;
353 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
354 if (!FSPT || FSPT->data().at(0).size() != 4)
355 return QVector<Sounding>();
357 if (!parseNAME(FSPT, &type, &id))
358 return QVector<Sounding>();
360 if (type == RCNM_VI) {
361 it = vi.find(id);
362 if (it == vi.constEnd())
363 return QVector<Sounding>();
364 } else if (type == RCNM_VC) {
365 it = vc.find(id);
366 if (it == vc.constEnd())
367 return QVector<Sounding>();
368 } else
369 return QVector<Sounding>();
371 return soundings(it.value(), COMF, SOMF);
374 Coordinates MapData::pointGeometry(const ISO8211::Record &r,
375 const RecordMap &vi, const RecordMap &vc, uint COMF)
377 quint8 type;
378 quint32 id;
379 RecordMapIterator it;
381 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
382 if (!FSPT || FSPT->data().at(0).size() != 4)
383 return Coordinates();
385 if (!parseNAME(FSPT, &type, &id))
386 return Coordinates();
388 if (type == RCNM_VI) {
389 it = vi.find(id);
390 if (it == vi.constEnd())
391 return Coordinates();
392 } else if (type == RCNM_VC) {
393 it = vc.find(id);
394 if (it == vc.constEnd())
395 return Coordinates();
396 } else
397 return Coordinates();
399 return point(it.value(), COMF);
402 QVector<Coordinates> MapData::lineGeometry(const ISO8211::Record &r,
403 const RecordMap &vc, const RecordMap &ve, uint COMF)
405 QVector<Coordinates> path;
406 Coordinates c[2];
407 uint ORNT;
408 quint8 type;
409 quint32 id;
411 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
412 if (!FSPT || FSPT->data().at(0).size() != 4)
413 return QVector<Coordinates>();
415 for (int i = 0; i < FSPT->data().size(); i++) {
416 if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE)
417 return QVector<Coordinates>();
418 ORNT = FSPT->data().at(i).at(1).toUInt();
420 RecordMapIterator it = ve.find(id);
421 if (it == ve.constEnd())
422 return QVector<Coordinates>();
423 const ISO8211::Record &FRID = it.value();
424 const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT");
425 if (!VRPT || VRPT->data().size() != 2)
426 return QVector<Coordinates>();
428 for (int j = 0; j < 2; j++) {
429 if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC)
430 return QVector<Coordinates>();
432 RecordMapIterator jt = vc.find(id);
433 if (jt == vc.constEnd())
434 return QVector<Coordinates>();
435 c[j] = point(jt.value(), COMF);
436 if (c[j].isNull())
437 return QVector<Coordinates>();
440 const ISO8211::Field *vertexes = SGXD(FRID);
441 if (ORNT == 2) {
442 path.append(c[1]);
443 if (vertexes) {
444 for (int j = vertexes->data().size() - 1; j >= 0; j--) {
445 const QVector<QVariant> &cv = vertexes->data().at(j);
446 path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
447 COMF));
450 path.append(c[0]);
451 } else {
452 path.append(c[0]);
453 if (vertexes) {
454 for (int j = 0; j < vertexes->data().size(); j++) {
455 const QVector<QVariant> &cv = vertexes->data().at(j);
456 path.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
457 COMF));
460 path.append(c[1]);
464 return path;
467 Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc,
468 const RecordMap &ve, uint COMF)
470 Polygon path;
471 QVector<Coordinates> v;
472 Coordinates c[2];
473 uint ORNT, USAG;
474 quint8 type;
475 quint32 id;
477 const ISO8211::Field *FSPT = ISO8211::field(r, "FSPT");
478 if (!FSPT || FSPT->data().at(0).size() != 4)
479 return Polygon();
481 for (int i = 0; i < FSPT->data().size(); i++) {
482 if (!parseNAME(FSPT, &type, &id, i) || type != RCNM_VE)
483 return Polygon();
484 ORNT = FSPT->data().at(i).at(1).toUInt();
485 USAG = FSPT->data().at(i).at(2).toUInt();
487 if (USAG == 2 && path.isEmpty()) {
488 path.append(v);
489 v.clear();
492 RecordMapIterator it = ve.find(id);
493 if (it == ve.constEnd())
494 return Polygon();
495 const ISO8211::Record &FRID = it.value();
496 const ISO8211::Field *VRPT = ISO8211::field(FRID, "VRPT");
497 if (!VRPT || VRPT->data().size() != 2)
498 return Polygon();
500 for (int j = 0; j < 2; j++) {
501 if (!parseNAME(VRPT, &type, &id, j) || type != RCNM_VC)
502 return Polygon();
504 RecordMapIterator jt = vc.find(id);
505 if (jt == vc.constEnd())
506 return Polygon();
507 c[j] = point(jt.value(), COMF);
508 if (c[j].isNull())
509 return Polygon();
512 const ISO8211::Field *vertexes = SGXD(FRID);
513 if (ORNT == 2) {
514 v.append(c[1]);
515 if (USAG == 3)
516 v.append(Coordinates());
517 if (vertexes) {
518 for (int j = vertexes->data().size() - 1; j >= 0; j--) {
519 const QVector<QVariant> &cv = vertexes->data().at(j);
520 v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
521 COMF));
524 if (USAG == 3)
525 v.append(Coordinates());
526 v.append(c[0]);
527 } else {
528 v.append(c[0]);
529 if (USAG == 3)
530 v.append(Coordinates());
531 if (vertexes) {
532 for (int j = 0; j < vertexes->data().size(); j++) {
533 const QVector<QVariant> &cv = vertexes->data().at(j);
534 v.append(coordinates(cv.at(1).toInt(), cv.at(0).toInt(),
535 COMF));
538 if (USAG == 3)
539 v.append(Coordinates());
540 v.append(c[1]);
543 if (USAG == 2 && v.first() == v.last()) {
544 path.append(v);
545 v.clear();
549 if (!v.isEmpty())
550 path.append(v);
552 return path;
555 MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL)
557 QString label;
558 QVector<QByteArray> params(2);
559 uint subtype = 0;
561 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
562 if (!(ATTF && ATTF->data().at(0).size() == 2))
563 return Attr();
565 for (int i = 0; i < ATTF->data().size(); i++) {
566 const QVector<QVariant> &av = ATTF->data().at(i);
567 uint key = av.at(0).toUInt();
569 if (key == OBJNAM)
570 label = QString::fromLatin1(av.at(1).toByteArray());
572 if ((OBJL == HRBFAC && key == CATHAF)
573 || (OBJL == I_HRBFAC && key == I_CATHAF)
574 || (OBJL == LNDMRK && key == CATLMK)
575 || (OBJL == WRECKS && key == CATWRK)
576 || (OBJL == MORFAC && key == CATMOR)
577 || (OBJL == UWTROC && key == WATLEV)
578 || (OBJL == BUAARE && key == CATBUA)
579 || (OBJL == SMCFAC && key == CATSCF)
580 || (OBJL == BUISGL && key == FUNCTN)
581 || (OBJL == WATTUR && key == CATWAT)
582 || (OBJL == SISTAT && key == CATSIT)
583 || (OBJL == I_SISTAT && key == I_CATSIT)
584 || (OBJL == RDOCAL && key == TRAFIC)
585 || (OBJL == I_RDOCAL && key == TRAFIC)
586 || (OBJL == SILTNK && key == CATSIL)
587 || (OBJL == WEDKLP && key == CATWED))
588 subtype = av.at(1).toByteArray().toUInt();
589 else if (OBJL == I_DISMAR && key == CATDIS)
590 subtype |= av.at(1).toByteArray().toUInt();
591 else if (OBJL == I_DISMAR && key == I_HUNITS)
592 subtype |= av.at(1).toByteArray().toUInt() << 8;
594 if ((OBJL == I_DISMAR && key == I_WTWDIS)
595 || (OBJL == RDOCAL && key == ORIENT)
596 || (OBJL == I_RDOCAL && key == ORIENT)
597 || (OBJL == CURENT && key == ORIENT)
598 || (OBJL == LNDELV && key == ELEVAT))
599 params[0] = av.at(1).toByteArray();
600 if ((OBJL == I_RDOCAL && key == COMCHA)
601 || (OBJL == RDOCAL && key == COMCHA)
602 || (OBJL == CURENT && key == CURVEL))
603 params[1] = av.at(1).toByteArray();
606 return Attr(subtype, label, params);
609 MapData::Attr MapData::lineAttr(const ISO8211::Record &r, uint OBJL)
611 QString label;
612 QVector<QByteArray> params(1);
613 uint subtype = 0;
615 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
616 if (!(ATTF && ATTF->data().at(0).size() == 2))
617 return Attr();
619 for (int i = 0; i < ATTF->data().size(); i++) {
620 const QVector<QVariant> &av = ATTF->data().at(i);
621 uint key = av.at(0).toUInt();
623 if (key == OBJNAM)
624 label = QString::fromLatin1(av.at(1).toByteArray());
626 if ((OBJL == RECTRC || OBJL == RCRTCL) && key == CATTRK)
627 subtype = av.at(1).toByteArray().toUInt();
629 if ((OBJL == DEPCNT && key == VALDCO)
630 || (OBJL == LNDELV && key == ELEVAT))
631 params[0] = av.at(1).toByteArray();
634 return Attr(subtype, label, params);
637 MapData::Attr MapData::polyAttr(const ISO8211::Record &r, uint OBJL)
639 QString label;
640 QVector<QByteArray> params(1);
641 uint subtype = 0;
643 const ISO8211::Field *ATTF = ISO8211::field(r, "ATTF");
644 if (!(ATTF && ATTF->data().at(0).size() == 2))
645 return Attr();
647 for (int i = 0; i < ATTF->data().size(); i++) {
648 const QVector<QVariant> &av = ATTF->data().at(i);
649 uint key = av.at(0).toUInt();
651 if (key == OBJNAM)
652 label = QString::fromLatin1(av.at(1).toByteArray());
654 if ((OBJL == RESARE && key == CATREA)
655 || (OBJL == I_RESARE && key == CATREA)
656 || (OBJL == ACHARE && key == CATACH)
657 || (OBJL == I_ACHARE && key == I_CATACH)
658 || (OBJL == HRBFAC && key == CATHAF)
659 || (OBJL == MARKUL && key == CATMFA)
660 || (OBJL == I_BERTHS && key == I_CATBRT))
661 subtype = av.at(1).toByteArray().toUInt();
662 else if ((OBJL == RESARE && key == RESTRN)
663 || (OBJL == I_RESARE && key == I_RESTRN)) {
664 if (av.at(1).toByteArray().toUInt() == 1)
665 subtype = 2;
666 if (av.at(1).toByteArray().toUInt() == 7)
667 subtype = 17;
670 if ((OBJL == TSSLPT && key == ORIENT)
671 || (OBJL == DEPARE && key == DRVAL1))
672 params[0] = av.at(1).toByteArray();
673 if ((OBJL == BRIDGE && key == VERCLR)
674 || (OBJL == I_BRIDGE && key == VERCLR))
675 params[0] = av.at(1).toByteArray();
678 return Attr(subtype, label, params);
681 MapData::Point *MapData::pointObject(const Sounding &s)
683 return new Point(TYPE(SOUNDG), s.c, QString::number(s.depth),
684 QVector<QByteArray>());
687 MapData::Point *MapData::pointObject(const ISO8211::Record &r,
688 const RecordMap &vi, const RecordMap &vc, uint COMF, uint OBJL)
690 Coordinates c(pointGeometry(r, vi, vc, COMF));
691 Attr attr(pointAttr(r, OBJL));
693 return (c.isNull() ? 0 : new Point(SUBTYPE(OBJL,attr.subtype()), c,
694 attr.label(), attr.params()));
697 MapData::Line *MapData::lineObject(const ISO8211::Record &r,
698 const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL)
700 QVector<Coordinates> path(lineGeometry(r, vc, ve, COMF));
701 Attr attr(lineAttr(r, OBJL));
703 return (path.isEmpty() ? 0 : new Line(SUBTYPE(OBJL, attr.subtype()), path,
704 attr.label(), attr.params()));
707 MapData::Poly *MapData::polyObject(const ISO8211::Record &r,
708 const RecordMap &vc, const RecordMap &ve, uint COMF, uint OBJL, uint HUNI)
710 Polygon path(polyGeometry(r, vc, ve, COMF));
711 Attr attr(polyAttr(r, OBJL));
713 return (path.isEmpty() ? 0 : new Poly(SUBTYPE(OBJL, attr.subtype()), path,
714 attr.label(), attr.params(), HUNI));
717 bool MapData::processRecord(const ISO8211::Record &record,
718 QVector<ISO8211::Record> &fe, RecordMap &vi, RecordMap &vc, RecordMap &ve,
719 RecordMap &vf, uint &COMF, uint &SOMF, uint &HUNI)
721 if (record.size() < 2)
722 return false;
724 const ISO8211::Field &f = record.at(1);
725 const QByteArray &ba = f.tag();
727 if (ba == "VRID") {
728 if (f.data().at(0).size() < 2)
729 return false;
730 int RCNM = f.data().at(0).at(0).toInt();
731 uint RCID = f.data().at(0).at(1).toUInt();
733 switch (RCNM) {
734 case RCNM_VI:
735 vi.insert(RCID, record);
736 break;
737 case RCNM_VC:
738 vc.insert(RCID, record);
739 break;
740 case RCNM_VE:
741 ve.insert(RCID, record);
742 break;
743 case RCNM_VF:
744 vf.insert(RCID, record);
745 break;
746 default:
747 return false;
749 } else if (ba == "FRID") {
750 fe.append(record);
751 } else if (ba == "DSPM") {
752 if (!(f.subfield("COMF", &COMF) && f.subfield("SOMF", &SOMF)))
753 return false;
754 if (!f.subfield("HUNI", &HUNI))
755 return false;
758 return true;
761 MapData::MapData(const QString &path)
763 RecordMap vi, vc, ve, vf;
764 QVector<ISO8211::Record> fe;
765 ISO8211 ddf(path);
766 ISO8211::Record record;
767 uint PRIM, OBJL, COMF = 1, SOMF = 1, HUNI = 1;
768 Poly *poly;
769 Line *line;
770 Point *point;
771 double min[2], max[2];
774 if (!ddf.readDDR())
775 return;
776 while (ddf.readRecord(record))
777 if (!processRecord(record, fe, vi, vc, ve, vf, COMF, SOMF, HUNI))
778 qWarning("Invalid S-57 record");
780 for (int i = 0; i < fe.size(); i++) {
781 const ISO8211::Record &r = fe.at(i);
782 const ISO8211::Field &f = r.at(1);
784 if (f.data().at(0).size() < 5)
785 continue;
786 PRIM = f.data().at(0).at(2).toUInt();
787 OBJL = f.data().at(0).at(4).toUInt();
789 switch (PRIM) {
790 case PRIM_P:
791 if (OBJL == SOUNDG) {
792 QVector<Sounding> s(soundingGeometry(r, vi, vc, COMF, SOMF));
793 for (int i = 0; i < s.size(); i++) {
794 point = pointObject(s.at(i));
795 pointBounds(point->pos(), min, max);
796 _points.Insert(min, max, point);
798 } else {
799 if ((point = pointObject(r, vi, vc, COMF, OBJL))) {
800 pointBounds(point->pos(), min, max);
801 _points.Insert(min, max, point);
802 } else
803 warning(f, PRIM);
805 break;
806 case PRIM_L:
807 if ((line = lineObject(r, vc, ve, COMF, OBJL))) {
808 rectcBounds(line->bounds(), min, max);
809 _lines.Insert(min, max, line);
810 } else
811 warning(f, PRIM);
812 break;
813 case PRIM_A:
814 if ((poly = polyObject(r, vc, ve, COMF, OBJL, HUNI))) {
815 rectcBounds(poly->bounds(), min, max);
816 _areas.Insert(min, max, poly);
817 } else
818 warning(f, PRIM);
819 break;
824 MapData::~MapData()
826 LineTree::Iterator lit;
827 for (_lines.GetFirst(lit); !_lines.IsNull(lit); _lines.GetNext(lit))
828 delete _lines.GetAt(lit);
830 PolygonTree::Iterator ait;
831 for (_areas.GetFirst(ait); !_areas.IsNull(ait); _areas.GetNext(ait))
832 delete _areas.GetAt(ait);
834 PointTree::Iterator pit;
835 for (_points.GetFirst(pit); !_points.IsNull(pit); _points.GetNext(pit))
836 delete _points.GetAt(pit);
839 void MapData::points(const RectC &rect, QList<Point> *points) const
841 double min[2], max[2];
843 rectcBounds(rect, min, max);
844 _points.Search(min, max, pointCb, points);
847 void MapData::lines(const RectC &rect, QList<Line> *lines) const
849 double min[2], max[2];
851 rectcBounds(rect, min, max);
852 _lines.Search(min, max, lineCb, lines);
855 void MapData::polygons(const RectC &rect, QList<Poly> *polygons) const
857 double min[2], max[2];
859 rectcBounds(rect, min, max);
860 _areas.Search(min, max, polygonCb, polygons);