From 819a67158a4cad232d94e283fadce06b118140a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Mon, 10 Feb 2025 09:29:46 +0100 Subject: [PATCH] IMG marine lights --- gpxsee.pro | 1 + gpxsee.qrc | 1 + icons/map/marine/light-white.png | Bin 0 -> 330 bytes icons/map/marine/light-yellow.png | Bin 470 -> 4428 bytes src/map/IMG/lights.h | 51 ++++++++++++++ src/map/IMG/mapdata.h | 3 +- src/map/IMG/rastertile.cpp | 83 ++++++++++++++++++++--- src/map/IMG/rastertile.h | 11 +-- src/map/IMG/rgnfile.cpp | 109 ++++++++++++++++++++++++++++-- src/map/IMG/rgnfile.h | 5 +- src/map/IMG/style.cpp | 38 +++++++++++ src/map/IMG/style.h | 8 ++- 12 files changed, 289 insertions(+), 21 deletions(-) create mode 100644 icons/map/marine/light-white.png create mode 100644 src/map/IMG/lights.h diff --git a/gpxsee.pro b/gpxsee.pro index 9c512cca..4b279f37 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -118,6 +118,7 @@ HEADERS += src/common/config.h \ src/data/gpsdumpparser.h \ src/data/style.h \ src/data/twonavparser.h \ + src/map/IMG/lights.h \ src/map/downloader.h \ src/map/demloader.h \ src/map/ENC/attributes.h \ diff --git a/gpxsee.qrc b/gpxsee.qrc index ff3134f2..8eca235c 100644 --- a/gpxsee.qrc +++ b/gpxsee.qrc @@ -196,6 +196,7 @@ icons/map/marine/light-red.png icons/map/marine/light-green.png icons/map/marine/light-yellow.png + icons/map/marine/light-white.png icons/map/marine/building.png icons/map/marine/fog-signal.png icons/map/marine/construction.png diff --git a/icons/map/marine/light-white.png b/icons/map/marine/light-white.png new file mode 100644 index 0000000000000000000000000000000000000000..a0e2d062212d3b9e26e57f1c59c7153332e41976 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9c!3HGfPKx~mq}YnA5es| zz$3C4sN*^aGdgL^t^f+Y@^o7|_9ds9VTj%I9 z?LN+u9x;>s_AzrNxsBHRWpWD}H1#&#V~aW}?8LE<>3+c-w%5s0NvfRr8*hs2UKf;l zLxNdnx|8glWf5$43&Oi(!^A&#J-6R+Ad0i>v-p&y)d%Zjw={l_j9~J6G~wUc$&tEg zH&!e;8p!x1kg4=z<}Ke-8iv literal 0 HcmV?d00001 diff --git a/icons/map/marine/light-yellow.png b/icons/map/marine/light-yellow.png index 6181322491cd0c0247b2aff9af4bdeacaa291a15..4b7ca018f929127dad2168b42445c310277b861b 100644 GIT binary patch literal 4428 zcmeHKdr(y86~Bw}$XeqwQH)Nmo5b+&?tSdt*OfIq7T8r5DWZaD2JhYnUfkWg?p|Oq z!Gc;7(J-T6lR-0MYAZ%aOk&$OCaJWQCKHp|YFlDb(P9aCPy-qJ(1h4??=G)4GaY7{ z|Ja>xzjM!b&hIf(@@ zFdv3Nfjl4P6ELJFqkH`VWc8Dzeg6egB8-ta-|ZV-cxH_bk1C7sR(y%E>8m=j5QlkSt0*0YM^%>-IZbzs_9TRlfEo#c6lnJ7??L zMb8cV$k6mNeeUtul|NX&q`)}5W7$l1b~)9)_l3J+WyTvGne zq`|)%e|zey3&Zx?f85bkU++4+X}2^_o_)dhK|+6BZ%X?4v?2S@F86{5xBvA_@6dhy z2hPV`*w=db-Hfd*rOT^cx!Bd=t2}q<9J%gNYWdr>9ig7yj&+}P)UEmYSFWt`vX7Ye zzWd{spL)nO`}reH`V%kDXTt9fnx z*2;^k8y{@wS@71ah10TM&ussT?dn@iml)lS3!MjhhPqoj2Oj?9>85*E#3lT^Vee;6 z#|CuItmqtUUV7-&^ms|%Wf z>Av#e*@_Q_hmq=Yq2n2gXFUrg7?Da!l~PXu!^wUl%gbKD81VP8=dOV}>fpClk-~*4aL7X%axZjVD_XsPw)c_I;=o>x4CAC2TFBZabRfrRE ztA&8_z<3Cr8}$!Xg?w5%JckQD!4IZk*p-~HrF!8;JyZ%RB!5uz0N~%&^D5^P=ttCtu`8??QpDKS~OuaA(DjI zBAO^(90#!`BtccOzVT71P&_~pw2k6~^!&M$sf^V>KwAWAfyX zpM~R;{A`7Q2Llz_f=W1(RpfRUC?heZDe|$32o4TIffT5Uj4hN%eqpV`s%(;0lby6u zCdy3PEEelH@AX0`43(&2YOPaqSC55(WPn&!ty2Kd^pFda6B1ZO4wcBV&tVvCx}(b; zxK2E)uufJH0CcnsmyERGbb@4vXaFjlN9HB5_J3Kcmj}%NdpL5J6o&n4HC6ORtrfOL zpQ4XGNxMoYs$B|(<)SHs*=m8;;smVd61SNRR0z;LV&yubm%gDC%qE_rY2Jc~yw`@& zw8?^btyUVdTWC%&n+TS-SSO-~Wl^bNLqb*s@CaN%d1`;4&=l>UQYTv1Y!=j00KzbW z!bsvj3BzLv<7&?s$v6Z5FHSNvgK>g;wN?%-{KAcJ+;ZC z_?@C_impj9Fe&4y>YAc!QVdMWc&fVoZ*=L$UZ;cr{1;RMFH6HKE4$!DE5W-u--+B& zzenC|YX;3-L04HA-p;z!q03G=6ai(T;`ZbweiEloOirHr8|Nuded=~*mDtX|_=l5) z+3dplq5gW4Ezd+XcICz8lN&FePHes&_eNZQ{Ku!`7aclU>Y09}U|Fiz_HhzZw|x3X zEuTC32mSK!--f?@{^t9g?TDvuIsvbvEfwW#aXd3)7!| AfB*mh delta 444 zcmV;t0Ym=GBGv004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv00000008+zyMF)x z010qNS#tmY4c7nw4c7reD4Tcy00AvYL_t(I%dOPCN}N#;#((kOE?S5|u&_>w6l0f8 zTPv{>Bo|-`gWv^-E^29|g&)LQu(S}tDi#J32u4B2O2pDeqG+RH^9F)s_kA}y<#QhX zb7s!Wk!jQ`L>+H4?PhxaQqT&zaF}T(Q^)^+YLKZPztD*Te2(zF-5ZH;f~7+HfNz=B zGxf9uDq;>te}CzdILV2G$}xQ~|vyN_^KO z`43D)IA{qfV8hsH(UN;CV*#Wj}}&2H4%+3-wLSVVUro#Io3 m{aU;KPBHm|xWdl}kMIP6;88do5AKuz0000h_ +#include + +namespace IMG { + +class Lights +{ +public: + enum Color {None, Red, Green, White, Blue, Yellow, Violet, Amber}; + + struct Sector + { + Sector() : color(None), angle(0), range(0) {} + Sector(Color color, quint32 angle, quint32 range) + : color(color), angle(angle), range(range) {} + + Color color; + quint32 angle; + quint32 range; + }; + + Lights() : color(None), range(0) {} + bool isSectorLight() const {return ((color && range) || !sectors.isEmpty());} + + Color color; + quint32 range; + QVector sectors; +}; + +} + +#ifndef QT_NO_DEBUG +inline QDebug operator<<(QDebug dbg, const IMG::Lights::Sector §or) +{ + dbg.nospace() << "Sector(" << sector.color << ", " << sector.angle + << ", " << sector.range << ")"; + return dbg.space(); +} + +inline QDebug operator<<(QDebug dbg, const IMG::Lights &lights) +{ + dbg.nospace() << "Lights(" << lights.color << ", " << lights.range << ", " + << lights.sectors << ")"; + return dbg.space(); +} +#endif // QT_NO_DEBUG + +#endif // IMG_LIGHTS_H diff --git a/src/map/IMG/mapdata.h b/src/map/IMG/mapdata.h index a1cd688f..4f591e98 100644 --- a/src/map/IMG/mapdata.h +++ b/src/map/IMG/mapdata.h @@ -14,6 +14,7 @@ #include "map/matrix.h" #include "label.h" #include "raster.h" +#include "lights.h" #include "zoom.h" namespace IMG { @@ -51,11 +52,11 @@ public: enum Flags { NoFlag = 0, ClassLabel = 1, - Light = 2 }; Coordinates coordinates; Label label; + Lights lights; quint64 id; quint32 type; quint32 flags; diff --git a/src/map/IMG/rastertile.cpp b/src/map/IMG/rastertile.cpp index be67893b..3d823091 100644 --- a/src/map/IMG/rastertile.cpp +++ b/src/map/IMG/rastertile.cpp @@ -18,13 +18,13 @@ using namespace IMG; #define TEXT_EXTENT 160 #define ICON_PADDING 2 +#define RANGE_FACTOR 4 +#define ROAD 0 +#define WATER 1 #define AREA(rect) \ (rect.size().width() * rect.size().height()) -#define ROAD 0 -#define WATER 1 - static const QColor textColor(Qt::black); static const QColor haloColor(Qt::white); static const QColor shieldColor(Qt::white); @@ -226,6 +226,67 @@ void RasterTile::drawTextItems(QPainter *painter, } } +static QRect lightRect(const QPoint &pos, quint32 range) +{ + return QRect(pos.x() - range * RANGE_FACTOR, pos.y() - range * RANGE_FACTOR, + 2*range * RANGE_FACTOR, 2*range * RANGE_FACTOR); +} + +void RasterTile::drawSectorLights(QPainter *painter, + const QList &lights) const +{ + for (int i = 0; i < lights.size(); i++) { + const MapData::Point *p = lights.at(i); + QPoint pos(p->coordinates.lon(), p->coordinates.lat()); + + if (p->lights.sectors.size()) { + for (int j = 0; j < p->lights.sectors.size(); j++) { + const Lights::Sector &start = p->lights.sectors.at(j); + const Lights::Sector &end = (j == p->lights.sectors.size() - 1) + ? p->lights.sectors.at(0) : p->lights.sectors.at(j+1); + + if (start.color && start.range) { + double a1 = -(end.angle / 10.0 + 90.0); + double a2 = -(start.angle / 10.0 + 90.0); + if (a1 > a2) + a2 += 360; + double as = (a2 - a1); + if (as == 0) + as = 360; + + QRect rect(lightRect(pos, start.range)); + + painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, + Qt::FlatCap)); + painter->drawArc(rect, a1 * 16, as * 16); + painter->setPen(QPen(Style::color(start.color), 4, + Qt::SolidLine, Qt::FlatCap)); + painter->drawArc(rect, a1 * 16, as * 16); + + if (a2 - a1 != 0) { + QLineF ln(pos, QPointF(pos.x() + rect.width(), pos.y())); + ln.setAngle(a1); + painter->setPen(QPen(Qt::black, 1, Qt::DashLine)); + painter->drawLine(ln); + ln.setAngle(a2); + painter->drawLine(ln); + } + } + } + } else { + if (p->lights.color && p->lights.range) { + QRect rect(lightRect(pos, p->lights.range)); + + painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, Qt::FlatCap)); + painter->drawArc(rect, 0, 360 * 16); + painter->setPen(QPen(Style::color(p->lights.color), 4, + Qt::SolidLine, Qt::FlatCap)); + painter->drawArc(rect, 0, 360 * 16); + } + } + } +} + static void removeDuplicitLabel(QList &labels, const QString &text, const QRectF &tileRect) { @@ -398,7 +459,7 @@ void RasterTile::processShields(const QList &lines, } void RasterTile::processPoints(QList &points, - QList &textItems) + QList &textItems, QList &lights) { std::sort(points.begin(), points.end()); @@ -408,6 +469,9 @@ void RasterTile::processPoints(QList &points, const Style::Point &ps = style->point(point.type); bool poi = Style::isPOI(point.type); + if (point.lights.isSectorLight()) + lights.append(&point); + const QString *label = point.label.text().isEmpty() ? 0 : &(point.label.text()); const QImage *img = ps.img().isNull() ? 0 : &ps.img(); @@ -428,11 +492,12 @@ void RasterTile::processPoints(QList &points, TextPointItem *item = new TextPointItem(pos + offset, label, fnt, img, color, hcolor, 0, ICON_PADDING); - if (item->isValid() && !item->collides(textItems)) { + if (point.lights.isSectorLight() + || (item->isValid() && !item->collides(textItems))) { textItems.append(item); - if (Style::isLight(point.type) || point.flags & MapData::Point::Light) + if (point.lights.color && !point.lights.isSectorLight()) textItems.append(new TextPointItem(pos + style->lightOffset(), - 0, 0, style->light(), 0, 0, 0, 0)); + 0, 0, style->light(point.lights.color), 0, 0, 0, 0)); } else delete item; } @@ -521,6 +586,7 @@ void RasterTile::render() QList lines; QList points; QList textItems; + QList lights; QImage arrows[2]; arrows[ROAD] = Util::svg2img(":/symbols/oneway.svg", _ratio); @@ -531,7 +597,7 @@ void RasterTile::render() ll2xy(lines); ll2xy(points); - processPoints(points, textItems); + processPoints(points, textItems, lights); processPolygons(polygons, textItems); processLines(lines, textItems, arrows); @@ -546,6 +612,7 @@ void RasterTile::render() drawPolygons(&painter, polygons); drawHillShading(&painter); drawLines(&painter, lines); + drawSectorLights(&painter, lights); drawTextItems(&painter, textItems); qDeleteAll(textItems); diff --git a/src/map/IMG/rastertile.h b/src/map/IMG/rastertile.h index c394a841..84c29052 100644 --- a/src/map/IMG/rastertile.h +++ b/src/map/IMG/rastertile.h @@ -34,7 +34,8 @@ public: private: typedef RTree DEMTRee; - struct ElevationCTX { + struct ElevationCTX + { ElevationCTX(const DEMTRee &tree, const Coordinates &c, double &ele) : tree(tree), c(c), ele(ele) {} @@ -42,7 +43,8 @@ private: const Coordinates &c; double &ele; }; - struct EdgeCTX { + struct EdgeCTX + { EdgeCTX(const Coordinates &c, double &ele) : c(c), ele(ele) {} const Coordinates &c; @@ -62,13 +64,14 @@ private: void drawLines(QPainter *painter, const QList &lines) const; void drawTextItems(QPainter *painter, const QList &textItems) const; void drawHillShading(QPainter *painter) const; + void drawSectorLights(QPainter *painter, const QList &lights) const; void processPolygons(const QList &polygons, QList &textItems); void processLines(QList &lines, QList &textItems, const QImage (&arrows)[2]); - void processPoints(QList &points, - QList &textItems); + void processPoints(QList &points, QList &textItems, + QList &lights); void processShields(const QList &lines, QList &textItems); void processStreetNames(const QList &lines, diff --git a/src/map/IMG/rgnfile.cpp b/src/map/IMG/rgnfile.cpp index ef629710..06760059 100644 --- a/src/map/IMG/rgnfile.cpp +++ b/src/map/IMG/rgnfile.cpp @@ -107,7 +107,8 @@ bool RGNFile::readObstructionInfo(Handle &hdl, quint8 flags, quint32 size, return true; } -bool RGNFile::readBuoyInfo(Handle &hdl, quint8 flags, MapData::Point *point) const +bool RGNFile::readBuoyInfo(Handle &hdl, quint8 flags, quint32 size, + MapData::Point *point) const { quint16 val; quint8 lc; @@ -115,7 +116,7 @@ bool RGNFile::readBuoyInfo(Handle &hdl, quint8 flags, MapData::Point *point) con if ((flags & 0xe0) != 0xe0) return true; - if (!readUInt16(hdl, val)) + if (!(size >= 2 && readUInt16(hdl, val))) return false; lc = (val >> 10) & 0x0f; @@ -123,7 +124,105 @@ bool RGNFile::readBuoyInfo(Handle &hdl, quint8 flags, MapData::Point *point) con lc = (val >> 6) & 7; if (lc) - point->flags |= MapData::Point::Light; + point->lights.color = (Lights::Color)lc; + + return true; +} + +bool RGNFile::readLightInfo(Handle &hdl, quint8 flags, quint32 size, + MapData::Point *point) const +{ + quint16 flags1; + quint8 flags2; + quint32 unused; + + if (!(size >= 3 && readUInt16(hdl, flags1) && readUInt8(hdl, flags2))) + return false; + size -= 3; + if (flags2 >> 6) { + if (!(size >= (flags2 >> 6) && readVUInt32(hdl, (flags2 >> 6), unused))) + return false; + size -= (flags2 >> 6); + } + if (flags2 >> 2 & 3) { + if (!(size >= (flags2 >> 2 & 3) + && readVUInt32(hdl, (flags2 >> 2 & 3), unused))) + return false; + size -= (flags2 >> 2 & 3); + } + if (flags1 & 0xc0) { + if (flags1 & 0x80) { + if (!(size >= 1 && readUInt8(hdl, unused))) + return false; + unused |= ((flags1 & 0x40) << 2); + size--; + } else { + if (!(size >= 2 && readUInt16(hdl, unused))) + return false; + size -= 2; + } + } + if (flags & 2) { + if (!(size >= 3 && readUInt24(hdl, unused))) + return false; + size -= 3; + } + if (flags & 4) { + if (!(size >= 3 && readUInt24(hdl, unused))) + return false; + size -= 3; + } + if (flags & 8) { + if (!(size >= 3 && readUInt24(hdl, unused))) + return false; + size -= 3; + } + if (flags1 & 0x200) { + if (!(size >= 2 && readUInt16(hdl, unused))) + return false; + size -= 2; + } + if (flags1 & 0x400) { + if (!(size >= 1 && readUInt8(hdl, unused))) + return false; + size--; + } + if (flags1 & 0x800) { + quint16 la; + quint8 cf, range = 0; + + do { + if (!(size >= 2 && readUInt16(hdl, la))) + return false; + size -= 2; + + cf = la >> 8; + Lights::Color c = (Lights::Color)(cf >> 4 & 7); + if (c) { + if (!(size >= 1 && readUInt8(hdl, range))) + return false; + size--; + } + point->lights.sectors.append(Lights::Sector(c, la & 0xfff, range)); + } while (!(cf >> 7)); + } else { + quint8 v1, v2, range; + + if (!(size >= 1 && readUInt8(hdl, v1))) + return false; + size--; + + range = v1 & 0x1f; + if ((v1 & 0x1f) == 0x1f) { + if (!(size >= 1 && readUInt8(hdl, v2))) + return false; + size--; + range += v2; + } + + point->lights.color = (Lights::Color)(v1 >> 5); + point->lights.range = range; + } return true; } @@ -183,7 +282,9 @@ bool RGNFile::readClassFields(Handle &hdl, SegmentType segmentType, if (point && Style::isObstructionPoint(point->type)) readObstructionInfo(hdl, flags, rs, point); if (point && Style::isBuoy(point->type)) - readBuoyInfo(hdl, flags, point); + readBuoyInfo(hdl, flags, rs, point); + if (point && Style::isLight(point->type)) + readLightInfo(hdl, flags, rs, point); return seek(hdl, off + rs); } diff --git a/src/map/IMG/rgnfile.h b/src/map/IMG/rgnfile.h index 7040250c..fc739010 100644 --- a/src/map/IMG/rgnfile.h +++ b/src/map/IMG/rgnfile.h @@ -64,7 +64,10 @@ private: MapData::Point *point) const; bool readObstructionInfo(Handle &hdl, quint8 flags, quint32 size, MapData::Point *point) const; - bool readBuoyInfo(Handle &hdl, quint8 flags, MapData::Point *point) const; + bool readBuoyInfo(Handle &hdl, quint8 flags, quint32 size, + MapData::Point *point) const; + bool readLightInfo(Handle &hdl, quint8 flags, quint32 size, + MapData::Point *point) const; bool readLabel(Handle &hdl, LBLFile *lbl, Handle &lblHdl, quint8 flags, quint32 size, MapData::Point *point) const; diff --git a/src/map/IMG/style.cpp b/src/map/IMG/style.cpp index 7014d2e6..1c215dce 100644 --- a/src/map/IMG/style.cpp +++ b/src/map/IMG/style.cpp @@ -1319,6 +1319,10 @@ Style::Style(qreal ratio, SubFile *typ) _extraSmall = pixelSizeFont(10); _light = QImage(":/marine/light.png"); + _lightRed = QImage(":/marine/light-red.png"); + _lightGreen = QImage(":/marine/light-green.png"); + _lightYellow = QImage(":/marine/light-yellow.png"); + _lightWhite = QImage(":/marine/light-white.png"); _lightOffset = QPoint(11, 11); defaultLineStyle(ratio); @@ -1373,6 +1377,40 @@ const QFont *Style::font(Style::FontSize size, Style::FontSize defaultSize) cons } } +const QImage *Style::light(Lights::Color color) const +{ + switch (color) { + case Lights::Red: + return &_lightRed; + case Lights::Green: + return &_lightGreen; + case Lights::White: + return &_lightWhite; + case Lights::Yellow: + case Lights::Amber: + return &_lightYellow; + default: + return &_light; + } +} + +QColor Style::color(Lights::Color c) +{ + switch (c) { + case Lights::Red: + return Qt::red; + case Lights::Green: + return Qt::green; + case Lights::White: + return Qt::white; + case Lights::Yellow: + case Lights::Amber: + return Qt::yellow; + default: + return Qt::magenta; + } +} + #ifndef QT_NO_DEBUG static QString penColor(const QPen &pen) { diff --git a/src/map/IMG/style.h b/src/map/IMG/style.h index 88fae052..a3f21fad 100644 --- a/src/map/IMG/style.h +++ b/src/map/IMG/style.h @@ -5,6 +5,7 @@ #include #include #include +#include "lights.h" #include "subfile.h" #define TYPE(t) ((t)<<8) @@ -112,8 +113,7 @@ public: const QList &drawOrder() const {return _drawOrder;} const QFont *font(Style::FontSize size, Style::FontSize defaultSize = Style::Normal) const; - - const QImage *light() const {return &_light;} + const QImage *light(Lights::Color color) const; const QPoint &lightOffset() const {return _lightOffset;} static bool isPOI(quint32 type) @@ -157,6 +157,8 @@ public: static bool isMarina(quint32 type) {return type == 0x10703;} + static QColor color(Lights::Color c); + private: struct Section { quint32 offset; @@ -203,7 +205,7 @@ private: /* Fonts and images must be initialized after QGuiApplication! */ QFont _large, _normal, _small, _extraSmall; - QImage _light; + QImage _light, _lightRed, _lightGreen, _lightYellow, _lightWhite; QPoint _lightOffset; };