diff --git a/gpxsee.qrc b/gpxsee.qrc index c5a53a67..eb672f47 100644 --- a/gpxsee.qrc +++ b/gpxsee.qrc @@ -191,6 +191,7 @@ icons/map/marine/cable-area-line.png icons/map/marine/pipeline-area-line.png icons/map/marine/windmotor.png + icons/map/marine/gauge.png diff --git a/icons/map/marine/gauge.png b/icons/map/marine/gauge.png new file mode 100644 index 00000000..ef9e19da Binary files /dev/null and b/icons/map/marine/gauge.png differ diff --git a/src/map/ENC/attributes.h b/src/map/ENC/attributes.h index f2ebec31..5b0f85aa 100644 --- a/src/map/ENC/attributes.h +++ b/src/map/ENC/attributes.h @@ -11,6 +11,7 @@ #define CATREA 56 #define CATSCF 65 #define CATWRK 71 +#define COMCHA 77 #define DRVAL1 87 #define ELEVAT 90 #define FUNCTN 94 @@ -22,6 +23,8 @@ #define I_CATACH 17000 #define I_RESTRN 17004 +#define I_CATHAF 17008 +#define I_RDOCAL 17017 #define I_WTWDIS 17064 #define I_HUNITS 17103 diff --git a/src/map/ENC/mapdata.cpp b/src/map/ENC/mapdata.cpp index ceea0d40..14d27ee9 100644 --- a/src/map/ENC/mapdata.cpp +++ b/src/map/ENC/mapdata.cpp @@ -49,18 +49,20 @@ static QMap orderMapInit() map.insert(TYPE(OBSTRN), 24); map.insert(TYPE(WRECKS), 25); map.insert(TYPE(UWTROC), 26); - map.insert(TYPE(I_TRNBSN), 27); - map.insert(TYPE(HRBFAC), 28); - map.insert(TYPE(PILPNT), 29); - map.insert(TYPE(ACHBRT), 30); - map.insert(TYPE(I_ACHBRT), 30); - map.insert(TYPE(CRANES), 31); - map.insert(TYPE(I_CRANES), 31); - map.insert(TYPE(LNDMRK), 32); - map.insert(TYPE(SILTNK), 33); - map.insert(TYPE(LNDELV), 34); - map.insert(TYPE(SMCFAC), 35); - map.insert(TYPE(BUISGL), 36); + map.insert(TYPE(I_RDOCAL), 27); + map.insert(TYPE(I_TRNBSN), 28); + map.insert(TYPE(HRBFAC), 29); + map.insert(TYPE(PILPNT), 30); + map.insert(TYPE(ACHBRT), 31); + map.insert(TYPE(I_ACHBRT), 31); + map.insert(TYPE(CRANES), 32); + map.insert(TYPE(I_CRANES), 32); + map.insert(TYPE(LNDMRK), 33); + map.insert(TYPE(SILTNK), 34); + map.insert(TYPE(LNDELV), 35); + map.insert(TYPE(SMCFAC), 36); + map.insert(TYPE(BUISGL), 37); + map.insert(TYPE(I_WTWGAG), 38); map.insert(TYPE(I_DISMAR), 0xFFFFFFFE); map.insert(TYPE(SOUNDG), 0xFFFFFFFF); @@ -214,34 +216,36 @@ static QString hUnits(uint type) } MapData::Point::Point(uint type, const Coordinates &c, const QString &label, - const QByteArray ¶m) : _type(type), _pos(c), _label(label) + const QVector ¶ms) : _type(type), _pos(c), _label(label) { uint hash = (uint)qHash(QPair(c.lon(), c.lat())); _id = ((quint64)order(type))<<32 | hash; - if ((type & 0xFFFF0000) == TYPE(I_DISMAR)) { - _label = hUnits((type>>8)&0xFF) + " " + QString::fromLatin1(param); + if (type>>16 == I_DISMAR) { + _label = hUnits((type>>8)&0xFF) + " " + QString::fromLatin1(params.at(0)); _type = SUBTYPE(I_DISMAR, type & 0xFF); + } else if (type == TYPE(I_RDOCAL)) { + if (!params.at(1).isEmpty()) + _label = QString("VHF ") + QString::fromLatin1(params.at(1)); + _param = QVariant(params.at(0).toDouble()); } } -MapData::Poly::Poly(uint type, const Polygon &path, const QByteArray ¶m) - : _type(type), _path(path) +MapData::Poly::Poly(uint type, const Polygon &path, + const QVector ¶ms) : _type(type), _path(path) { if (type == TYPE(DEPARE)) - _type = SUBTYPE(DEPARE, depthLevel(param)); - else if (type == TYPE(TSSLPT)) { - double angle = param.toDouble(); - _type = SUBTYPE(TSSLPT, (uint)(angle * 10)); - } + _type = SUBTYPE(DEPARE, depthLevel(params.at(0))); + else if (type == TYPE(TSSLPT)) + _param = QVariant(params.at(0).toDouble()); } MapData::Line::Line(uint type, const QVector &path, - const QString &label, const QByteArray ¶m) : _type(type), _path(path), - _label(label) + const QString &label, const QVector ¶ms) + : _type(type), _path(path), _label(label) { if (type == TYPE(DEPCNT) || type == TYPE(LNDELV)) - _label = QString::fromLatin1(param); + _label = QString::fromLatin1(params.at(0)); } RectC MapData::Line::bounds() const @@ -477,7 +481,7 @@ Polygon MapData::polyGeometry(const ISO8211::Record &r, const RecordMap &vc, MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL) { QString label; - QByteArray param; + QVector params(2); uint subtype = 0; const ISO8211::Field *ATTF = r.field("ATTF"); @@ -492,6 +496,7 @@ MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL) label = QString::fromLatin1(av.at(1).toByteArray()); if ((OBJL == HRBFAC && key == CATHAF) + || (OBJL == I_HRBFAC && key == I_CATHAF) || (OBJL == LNDMRK && key == CATLMK) || (OBJL == WRECKS && key == CATWRK) || (OBJL == MORFAC && key == CATMOR) @@ -505,17 +510,20 @@ MapData::Attr MapData::pointAttr(const ISO8211::Record &r, uint OBJL) else if (OBJL == I_DISMAR && key == I_HUNITS) subtype |= av.at(1).toByteArray().toUInt() << 8; - if (OBJL == I_DISMAR && key == I_WTWDIS) - param = av.at(1).toByteArray(); + if ((OBJL == I_DISMAR && key == I_WTWDIS) + || (OBJL == I_RDOCAL && key == ORIENT)) + params[0] = av.at(1).toByteArray(); + if (OBJL == I_RDOCAL && key == COMCHA) + params[1] = av.at(1).toByteArray(); } - return Attr(subtype, label, param); + return Attr(subtype, label, params); } MapData::Attr MapData::lineAttr(const ISO8211::Record &r, uint OBJL) { QString label; - QByteArray param; + QVector params(1); uint subtype = 0; const ISO8211::Field *ATTF = r.field("ATTF"); @@ -534,16 +542,16 @@ MapData::Attr MapData::lineAttr(const ISO8211::Record &r, uint OBJL) if ((OBJL == DEPCNT && key == VALDCO) || (OBJL == LNDELV && key == ELEVAT)) - param = av.at(1).toByteArray(); + params[0] = av.at(1).toByteArray(); } - return Attr(subtype, label, param); + return Attr(subtype, label, params); } MapData::Attr MapData::polyAttr(const ISO8211::Record &r, uint OBJL) { QString label; - QByteArray param; + QVector params(1); uint subtype = 0; const ISO8211::Field *ATTF = r.field("ATTF"); @@ -570,15 +578,16 @@ MapData::Attr MapData::polyAttr(const ISO8211::Record &r, uint OBJL) if ((OBJL == TSSLPT && key == ORIENT) || (OBJL == DEPARE && key == DRVAL1)) - param = av.at(1).toByteArray(); + params[0] = av.at(1).toByteArray(); } - return Attr(subtype, label, param); + return Attr(subtype, label, params); } MapData::Point *MapData::pointObject(const Sounding &s) { - return new Point(TYPE(SOUNDG), s.c, QString::number(s.depth), QByteArray()); + return new Point(TYPE(SOUNDG), s.c, QString::number(s.depth), + QVector()); } MapData::Point *MapData::pointObject(const ISO8211::Record &r, @@ -588,7 +597,7 @@ MapData::Point *MapData::pointObject(const ISO8211::Record &r, Attr attr(pointAttr(r, OBJL)); return (c.isNull() ? 0 : new Point(SUBTYPE(OBJL,attr.subtype()), c, - attr.label(), attr.param())); + attr.label(), attr.params())); } MapData::Line *MapData::lineObject(const ISO8211::Record &r, @@ -598,7 +607,7 @@ MapData::Line *MapData::lineObject(const ISO8211::Record &r, Attr attr(lineAttr(r, OBJL)); return (path.isEmpty() ? 0 : new Line(SUBTYPE(OBJL, attr.subtype()), path, - attr.label(), attr.param())); + attr.label(), attr.params())); } MapData::Poly *MapData::polyObject(const ISO8211::Record &r, @@ -608,7 +617,7 @@ MapData::Poly *MapData::polyObject(const ISO8211::Record &r, Attr attr(polyAttr(r, OBJL)); return (path.isEmpty() ? 0 : new Poly(SUBTYPE(OBJL, attr.subtype()), path, - attr.param())); + attr.params())); } bool MapData::processRecord(const ISO8211::Record &record, diff --git a/src/map/ENC/mapdata.h b/src/map/ENC/mapdata.h index 74c1a219..7a88ec23 100644 --- a/src/map/ENC/mapdata.h +++ b/src/map/ENC/mapdata.h @@ -15,21 +15,23 @@ class MapData public: class Poly { public: - Poly(uint type, const Polygon &path, const QByteArray ¶m); + Poly(uint type, const Polygon &path, const QVector ¶ms); RectC bounds() const {return _path.boundingRect();} const Polygon &path() const {return _path;} uint type() const {return _type;} + const QVariant ¶m() const {return _param;} private: uint _type; Polygon _path; + QVariant _param; }; class Line { public: Line(uint type, const QVector &path, const QString &label, - const QByteArray ¶m); + const QVector ¶ms); RectC bounds() const; const QVector &path() const {return _path;} @@ -45,11 +47,12 @@ public: class Point { public: Point(uint type, const Coordinates &c, const QString &label, - const QByteArray ¶m); + const QVector ¶ms); const Coordinates &pos() const {return _pos;} uint type() const {return _type;} const QString &label() const {return _label;} + const QVariant ¶m() const {return _param;} bool operator<(const Point &other) const {return _id < other._id;} @@ -59,6 +62,7 @@ public: Coordinates _pos; QString _label; quint64 _id; + QVariant _param; }; MapData(const QString &path); @@ -116,17 +120,18 @@ private: class Attr { public: Attr() : _subtype(0) {} - Attr(uint subtype, const QString &label, const QByteArray ¶m) - : _subtype(subtype), _label(label), _param(param) {} + Attr(uint subtype, const QString &label, + const QVector ¶ms) + : _subtype(subtype), _label(label), _params(params) {} unsigned subtype() const {return _subtype;} const QString &label() const {return _label;} - const QByteArray ¶m() const {return _param;} + const QVector ¶ms() const {return _params;} private: unsigned _subtype; QString _label; - QByteArray _param; + QVector _params; }; struct Sounding { diff --git a/src/map/ENC/objects.h b/src/map/ENC/objects.h index bc73aa69..ffc4340c 100644 --- a/src/map/ENC/objects.h +++ b/src/map/ENC/objects.h @@ -91,7 +91,9 @@ #define I_BRIDGE 17011 #define I_CBLOHD 17012 #define I_FERYRT 17013 +#define I_HRBFAC 17015 #define I_LOKBSN 17016 +#define I_RDOCAL 17017 #define I_HULKES 17020 #define I_PONTON 17021 #define I_PIPOHD 17024 @@ -104,5 +106,6 @@ #define I_WTWAXS 17051 #define I_TERMNL 17064 #define I_TRNBSN 17065 +#define I_WTWGAG 17067 #endif // ENC_OBJECTS_H diff --git a/src/map/ENC/rastertile.cpp b/src/map/ENC/rastertile.cpp index 79f04b2c..a5fb28a6 100644 --- a/src/map/ENC/rastertile.cpp +++ b/src/map/ENC/rastertile.cpp @@ -10,7 +10,8 @@ using namespace ENC; #define ICON_PADDING 2 -#define ARROW_SIZE 0.005 +#define TSSLPT_SIZE 0.005 /* ll */ +#define RDOCAL_SIZE 12 /* px */ const float C1 = 0.866025f; /* sqrt(3)/2 */ @@ -84,6 +85,39 @@ static Coordinates centroid(const QVector &polygon) return Coordinates(cx * factor, cy * factor); } +static QImage *rdocalArrow(qreal angle) +{ + QImage *img = new QImage(RDOCAL_SIZE*2, RDOCAL_SIZE*2, + QImage::Format_ARGB32_Premultiplied); + img->fill(Qt::transparent); + QPainter p(img); + p.setPen(QPen(QColor("#eb49eb"), 1)); + + QPointF arrow[3]; + arrow[0] = QPointF(img->width()/2, img->height()/2); + arrow[1] = arrow[0] + QPointF(qSin(angle - M_PI/3) * RDOCAL_SIZE, + qCos(angle - M_PI/3) * RDOCAL_SIZE); + arrow[2] = arrow[0] + QPointF(qSin(angle - M_PI + M_PI/3) * RDOCAL_SIZE, + qCos(angle - M_PI + M_PI/3) * RDOCAL_SIZE); + + QLineF l(arrow[1], arrow[2]); + QPointF pt(l.pointAt(0.5)); + + p.translate(arrow[0] - pt); + p.drawPolyline(QPolygonF() << arrow[1] << arrow[0] << arrow[2]); + p.drawEllipse(pt, RDOCAL_SIZE/2, RDOCAL_SIZE/2); + + return img; +} + +static QImage *image(uint type, const QVariant ¶m) +{ + if (type>>16 == I_RDOCAL) + return rdocalArrow(deg2rad(90 - param.toDouble())); + else + return 0; +} + QPainterPath RasterTile::painterPath(const Polygon &polygon) const { QPainterPath path; @@ -110,24 +144,24 @@ QPolygonF RasterTile::polyline(const QVector &path) const return polygon; } -QPolygonF RasterTile::arrow(const Coordinates &c, qreal angle) const +QPolygonF RasterTile::tsslptArrow(const Coordinates &c, qreal angle) const { Coordinates t[3], r[4]; QPolygonF polygon; t[0] = c; - t[1] = Coordinates(t[0].lon() - qCos(angle - M_PI/3) * ARROW_SIZE, - t[0].lat() - qSin(angle - M_PI/3) * ARROW_SIZE); - t[2] = Coordinates(t[0].lon() - qCos(angle - M_PI + M_PI/3) * ARROW_SIZE, - t[0].lat() - qSin(angle - M_PI + M_PI/3) * ARROW_SIZE); + t[1] = Coordinates(t[0].lon() - qCos(angle - M_PI/3) * TSSLPT_SIZE, + t[0].lat() - qSin(angle - M_PI/3) * TSSLPT_SIZE); + t[2] = Coordinates(t[0].lon() - qCos(angle - M_PI + M_PI/3) * TSSLPT_SIZE, + t[0].lat() - qSin(angle - M_PI + M_PI/3) * TSSLPT_SIZE); LineC l(t[1], t[2]); r[0] = l.pointAt(0.25); r[1] = l.pointAt(0.75); - r[2] = Coordinates(r[0].lon() - C1 * ARROW_SIZE * qCos(angle - M_PI/2), - r[0].lat() - C1 * ARROW_SIZE * qSin(angle - M_PI/2)); - r[3] = Coordinates(r[1].lon() - C1 * ARROW_SIZE * qCos(angle - M_PI/2), - r[1].lat() - C1 * ARROW_SIZE * qSin(angle - M_PI/2)); + r[2] = Coordinates(r[0].lon() - C1 * TSSLPT_SIZE * qCos(angle - M_PI/2), + r[0].lat() - C1 * TSSLPT_SIZE * qSin(angle - M_PI/2)); + r[3] = Coordinates(r[1].lon() - C1 * TSSLPT_SIZE * qCos(angle - M_PI/2), + r[1].lat() - C1 * TSSLPT_SIZE * qSin(angle - M_PI/2)); polygon << ll2xy(t[0]) << ll2xy(t[2]) << ll2xy(r[1]) << ll2xy(r[3]) << ll2xy(r[2]) << ll2xy(r[0]) << ll2xy(t[1]); @@ -137,16 +171,15 @@ QPolygonF RasterTile::arrow(const Coordinates &c, qreal angle) const void RasterTile::drawArrows(QPainter *painter) { - painter->setPen(QPen(QColor("#eb49eb"), 1)); - painter->setBrush(QBrush("#80eb49eb")); - for (int i = 0; i < _polygons.size(); i++) { const MapData::Poly *poly = _polygons.at(i); if (poly->type()>>16 == TSSLPT) { - qreal angle = (poly->type() & 0xFFFF) / 10.0; - QPolygonF polygon(arrow(centroid(poly->path().first()), - deg2rad(180 - angle))); + QPolygonF polygon(tsslptArrow(centroid(poly->path().first()), + deg2rad(180 - poly->param().toDouble()))); + + painter->setPen(QPen(QColor("#eb49eb"), 1)); + painter->setBrush(QBrush("#80eb49eb")); painter->drawPolygon(polygon); } } @@ -227,7 +260,8 @@ void RasterTile::processPolygons(QList &textItems) } } -void RasterTile::processPoints(QList &textItems) +void RasterTile::processPoints(QList &textItems, + QList &images) { const Style &s = style(); @@ -238,21 +272,27 @@ void RasterTile::processPoints(QList &textItems) const Style::Point &style = s.point(point->type()); const QString *label = point->label().isEmpty() ? 0 : &(point->label()); - const QImage *img = style.img().isNull() ? 0 : &style.img(); + QImage *rimg = style.img().isNull() + ? image(point->type(), point->param()) : 0; + const QImage *img = style.img().isNull() ? rimg : &style.img(); const QFont *fnt = font(style.textFontSize()); const QColor *color = &style.textColor(); - const QColor *hColor = (Style::isSounding(point->type()) - || Style::isDistanceMark(point->type())) ? 0 : &haloColor; + const QColor *hColor = style.haloColor().isValid() + ? &style.haloColor() : 0; if ((!label || !fnt) && !img) continue; TextPointItem *item = new TextPointItem(ll2xy(point->pos()).toPoint(), label, fnt, img, color, hColor, 0, ICON_PADDING); - if (item->isValid() && !item->collides(textItems)) + if (item->isValid() && !item->collides(textItems)) { textItems.append(item); - else + if (rimg) + images.append(rimg); + } else { delete item; + delete rimg; + } } } @@ -284,12 +324,13 @@ void RasterTile::processLines(QList &textItems) void RasterTile::render() { QList textItems; + QList images; _pixmap.setDevicePixelRatio(_ratio); _pixmap.fill(Qt::transparent); processPolygons(textItems); - processPoints(textItems); + processPoints(textItems, images); processLines(textItems); QPainter painter(&_pixmap); @@ -304,6 +345,7 @@ void RasterTile::render() drawTextItems(&painter, textItems); qDeleteAll(textItems); + qDeleteAll(images); //painter.setPen(Qt::red); //painter.setBrush(Qt::NoBrush); diff --git a/src/map/ENC/rastertile.h b/src/map/ENC/rastertile.h index 9a90da26..7acf2a58 100644 --- a/src/map/ENC/rastertile.h +++ b/src/map/ENC/rastertile.h @@ -32,8 +32,8 @@ private: {return _transform.proj2img(_proj.ll2xy(c));} QPainterPath painterPath(const Polygon &polygon) const; QPolygonF polyline(const QVector &path) const; - QPolygonF arrow(const Coordinates &c, qreal angle) const; - void processPoints(QList &textItems); + QPolygonF tsslptArrow(const Coordinates &c, qreal angle) const; + void processPoints(QList &textItems, QList &images); void processLines(QList &textItems); void processPolygons(QList &textItems); void drawBitmapPath(QPainter *painter, const QImage &img, diff --git a/src/map/ENC/style.cpp b/src/map/ENC/style.cpp index 15ea58a6..1f5fd195 100644 --- a/src/map/ENC/style.cpp +++ b/src/map/ENC/style.cpp @@ -174,6 +174,7 @@ void Style::pointStyle() _points[SUBTYPE(BUAARE, 6)].setTextFontSize(Small); _points[SUBTYPE(BUAARE, 0)].setTextFontSize(Small); _points[TYPE(SOUNDG)].setTextFontSize(Small); + _points[TYPE(SOUNDG)].setHaloColor(QColor()); _points[TYPE(LIGHTS)] = Point(QImage(":/marine/light-major.png"), Small); _points[TYPE(BOYCAR)] = Point(QImage(":/marine/buoy.png"), Small); _points[TYPE(BOYINB)] = Point(QImage(":/marine/buoy.png"), Small); @@ -226,16 +227,19 @@ void Style::pointStyle() _points[SUBTYPE(I_DISMAR, 1)] = Point(QImage(":/marine/distance-mark.png")); _points[SUBTYPE(I_DISMAR, 1)].setTextColor(QColor("#ffffff")); _points[SUBTYPE(I_DISMAR, 1)].setTextFontSize(Small); + _points[SUBTYPE(I_DISMAR, 1)].setHaloColor(QColor()); _points[SUBTYPE(I_DISMAR, 2)] = Point(QImage(":/marine/distance-mark-land.png")); _points[SUBTYPE(I_DISMAR, 2)].setTextFontSize(Small); - _points[SUBTYPE(I_DISMAR, 3)] = Point(QImage(":/marine/distance-mark-land.png")); - _points[SUBTYPE(I_DISMAR, 3)].setTextFontSize(Small); + _points[SUBTYPE(I_DISMAR, 2)].setHaloColor(QColor()); + _points[SUBTYPE(I_DISMAR, 3)] = _points[SUBTYPE(I_DISMAR, 2)]; _points[TYPE(CGUSTA)] = Point(QImage(":/marine/coast-guard.png")); _points[TYPE(RDOSTA)] = Point(QImage(":/marine/radio.png")); _points[TYPE(RADSTA)] = Point(QImage(":/marine/radar.png")); _points[TYPE(RTPBCN)] = Point(QImage(":/marine/radar-transponder.png")); _points[TYPE(SILTNK)] = Point(QImage(":/marine/silo.png")); _points[TYPE(I_TRNBSN)] = Point(QImage(":/marine/turning-basin.png")); + _points[TYPE(I_WTWGAG)] = Point(QImage(":/marine/gauge.png")); + _points[TYPE(I_RDOCAL)].setTextColor(QColor("#eb49eb")); _points[SUBTYPE(SMCFAC, 7)] = Point(QImage(":/POI/restaurant-11.png")); _points[SUBTYPE(SMCFAC, 11)] = Point(QImage(":/POI/pharmacy-11.png")); diff --git a/src/map/ENC/style.h b/src/map/ENC/style.h index 1eb5d995..f36373b6 100644 --- a/src/map/ENC/style.h +++ b/src/map/ENC/style.h @@ -68,19 +68,23 @@ public: class Point { public: - Point() : _textColor(Qt::black), _textFontSize(Normal) {} + Point() : _textColor(Qt::black), _haloColor(Qt::white), + _textFontSize(Normal) {} Point(const QImage &img, FontSize fontSize = Normal) - : _textColor(Qt::black), _textFontSize(fontSize), _img(img) {} + : _textColor(Qt::black), _haloColor(Qt::white), + _textFontSize(fontSize), _img(img) {} void setTextColor(const QColor &color) {_textColor = color;} + void setHaloColor(const QColor &color) {_haloColor = color;} void setTextFontSize(FontSize size) {_textFontSize = size;} const QColor &textColor() const {return _textColor;} + const QColor &haloColor() const {return _haloColor;} FontSize textFontSize() const {return _textFontSize;} const QImage &img() const {return _img;} private: - QColor _textColor; + QColor _textColor, _haloColor; FontSize _textFontSize; QImage _img; }; @@ -92,11 +96,6 @@ public: const Point &point(uint type) const; const QVector &drawOrder() const {return _drawOrder;} - static bool isSounding(uint type) - {return type == TYPE(SOUNDG);} - static bool isDistanceMark(uint type) - {return (type & 0xFFFF0000) == TYPE(I_DISMAR);} - private: void polygonStyle(); void lineStyle();