OpenCPN Partial API docs
Loading...
Searching...
No Matches
track_gui.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2022 by David Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
25#include <list>
26
27#include <wx/colour.h>
28#include <wx/gdicmn.h>
29#include <wx/pen.h>
30
31#include "model/config_vars.h"
32#include "model/gui_vars.h"
33#include "model/own_ship.h"
34#include "model/routeman.h"
35
36#include "color_handler.h"
37#include "navutil.h"
38#include "track_gui.h"
39#include "gl_chart_canvas.h"
40
41extern wxColor GetDimColor(wxColor c); // ocpn_frame: FIXME (leamas) new home
42
43extern ocpnGLOptions g_GLOptions; // FIXME (leamas) Fix GL dependency mess
44
45void TrackPointGui::Draw(ChartCanvas *cc, ocpnDC &dc) {
46 wxPoint r;
47 wxRect hilitebox;
48
49 cc->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
50
51 wxPen *pen;
52 pen = g_pRouteMan->GetRoutePointPen();
53
54 int sx2 = 8;
55 int sy2 = 8;
56
57 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
58
59 hilitebox = r1;
60 hilitebox.x -= r.x;
61 hilitebox.y -= r.y;
62 float radius;
63 hilitebox.Inflate(4);
64 radius = 4.0f;
65
66 wxColour hi_colour = pen->GetColour();
67 unsigned char transparency = 100;
68
69 // Highlite any selected point
70 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
71 hilitebox.height, radius, hi_colour, transparency);
72}
73
74void TrackGui::Finalize() {
75 if (m_track.SubTracks.size()) // subtracks already computed
76 return;
77
78 // OCPNStopWatch sw1;
79
80 int n = m_track.TrackPoints.size() - 1;
81 int level = 0;
82 while (n > 0) {
83 std::vector<SubTrack> new_level;
84 new_level.resize(n);
85 if (level == 0)
86 for (int i = 0; i < n; i++) {
87 new_level[i].m_box.SetFromSegment(m_track.TrackPoints[i]->m_lat,
88 m_track.TrackPoints[i]->m_lon,
89 m_track.TrackPoints[i + 1]->m_lat,
90 m_track.TrackPoints[i + 1]->m_lon);
91 new_level[i].m_scale = 0;
92 }
93 else {
94 for (int i = 0; i < n; i++) {
95 int p = i << 1;
96 new_level[i].m_box = m_track.SubTracks[level - 1][p].m_box;
97 if (p + 1 < (int)m_track.SubTracks[level - 1].size())
98 new_level[i].m_box.Expand(m_track.SubTracks[level - 1][p + 1].m_box);
99
100 int left = i << level;
101 int right = wxMin(left + (1 << level), m_track.TrackPoints.size() - 1);
102 new_level[i].m_scale = m_track.ComputeScale(left, right);
103 }
104 }
105 m_track.SubTracks.push_back(new_level);
106
107 if (n > 1 && n & 1) n++;
108 n >>= 1;
109 level++;
110 }
111 // if(m_track.TrackPoints.size() > 100)
112 // printf("fin time %f %d\n", sw1.GetTime(),
113 // (int)m_track.TrackPoints.size());
114}
115
116void TrackGui::GetPointLists(ChartCanvas *cc,
117 std::list<std::list<wxPoint> > &pointlists,
118 ViewPort &VP, const LLBBox &box) {
119 if (!m_track.IsVisible() || m_track.GetnPoints() == 0) return;
120 Finalize();
121 // OCPNStopWatch sw;
122 Segments(cc, pointlists, box, VP.view_scale_ppm);
123#if 0
124 if(GetnPoints() > 40000) {
125 double t = sw.GetTime();
126 double c = 0;
127 for(std::list< std::list<wxPoint> >::iterator lines = pointlists.begin();
128 lines != pointlists.end(); lines++) {
129 if(lines->size() > 1)
130 c += lines->size();
131 continue;
132 }
133 printf("assemble time %f %f segments %f seg/ms\n", sw.GetTime(), c, c/t);
134 }
135#endif
136
137 // Add last segment, dynamically, maybe.....
138 // we should not add this segment if it is not on the screen...
139 if (m_track.IsRunning()) {
140 std::list<wxPoint> new_list;
141 pointlists.push_back(new_list);
142 AddPointToList(cc, pointlists, m_track.TrackPoints.size() - 1);
143 wxPoint r;
144 cc->GetCanvasPointPix(gLat, gLon, &r);
145 pointlists.back().push_back(r);
146 }
147}
148
149void TrackGui::Draw(ChartCanvas *cc, ocpnDC &dc, ViewPort &VP,
150 const LLBBox &box) {
151 std::list<std::list<wxPoint> > pointlists;
152 GetPointLists(cc, pointlists, VP, box);
153
154 if (!pointlists.size()) return;
155
156 // Establish basic colour
157 wxColour basic_colour;
158 if (m_track.IsRunning())
159 basic_colour = GetGlobalColor("URED");
160 else
161 basic_colour = GetDimColor(g_colourTrackLineColour);
162
163 wxPenStyle style = wxPENSTYLE_SOLID;
164 int width = g_pRouteMan->GetTrackPen()->GetWidth();
165 wxColour col;
166 if (m_track.m_style != wxPENSTYLE_INVALID) style = m_track.m_style;
167 if (m_track.m_width != WIDTH_UNDEFINED) width = m_track.m_width;
168 if (m_track.m_Colour == "") {
169 col = basic_colour;
170 // Render tracks associated with persistent AIS targets as a contrasting
171 // color
172 if (m_track.GetName().StartsWith("AIS")) col = GetGlobalColor("TEAL1");
173 } else {
174 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
175 i++) {
176 if (m_track.m_Colour == ::GpxxColorNames[i]) {
177 col = ::GpxxColors[i];
178 break;
179 }
180 }
181 }
182
183 double radius = 0.;
184 if (g_bHighliteTracks) {
185 double radius_meters = 20; // 1.5 mm at original scale
186 double scale = VP.view_scale_ppm;
187 radius = wxMax((radius_meters * wxMin(scale, 1.1)), 6.0);
188 if (scale < 0.004) radius = 0;
189 }
190
191 {
192 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
193#ifdef ocpnUSE_GL
194 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
195 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
196 }
197#endif
198 dc.SetPen(p);
199 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
200 for (std::list<std::list<wxPoint> >::iterator lines = pointlists.begin();
201 lines != pointlists.end(); lines++) {
202 // convert from linked list to array
203 wxPoint *points = new wxPoint[lines->size()];
204 int i = 0;
205 for (std::list<wxPoint>::iterator line = lines->begin();
206 line != lines->end(); line++) {
207 points[i] = *line;
208 i++;
209 }
210
211 int hilite_width = radius;
212 if (hilite_width >= 1.0) {
213 // Save for base track
214 wxPen psave = dc.GetPen();
215
216 wxColor trackLine_dim_colour = GetDimColor(g_colourTrackLineColour);
217 wxColour hilt(trackLine_dim_colour.Red(), trackLine_dim_colour.Green(),
218 trackLine_dim_colour.Blue(), 128);
219 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
220 dc.SetPen(HiPen);
221 // Draw highlighted track
222 dc.StrokeLines(i, points);
223
224 dc.SetPen(psave);
225 // Draw base track visible above highlight
226 dc.StrokeLines(i, points);
227 } else
228 dc.StrokeLines(i, points);
229
230 delete[] points;
231 }
232 }
233
234 if (m_track.m_HighlightedTrackPoint >= 0)
235 TrackPointGui(m_track.TrackPoints[m_track.m_HighlightedTrackPoint])
236 .Draw(cc, dc);
237}
238
239// Entry to recursive Assemble at the head of the SubTracks tree
240void TrackGui::Segments(ChartCanvas *cc,
241 std::list<std::list<wxPoint> > &pointlists,
242 const LLBBox &box, double scale) {
243 if (!m_track.SubTracks.size()) return;
244
245 int level = m_track.SubTracks.size() - 1, last = -2;
246 Assemble(cc, pointlists, box, 1 / scale / scale, last, level, 0);
247}
248
249/* assembles lists of line strips from the given track recursively traversing
250 the subtracks data */
251void TrackGui::Assemble(ChartCanvas *cc,
252 std::list<std::list<wxPoint> > &pointlists,
253 const LLBBox &box, double scale, int &last, int level,
254 int pos) {
255 if (pos == (int)m_track.SubTracks[level].size()) return;
256
257 SubTrack &s = m_track.SubTracks[level][pos];
258 if (box.IntersectOut(s.m_box)) return;
259
260 if (s.m_scale < scale) {
261 pos <<= level;
262
263 if (last < pos - 1) {
264 std::list<wxPoint> new_list;
265 pointlists.push_back(new_list);
266 }
267
268 if (last < pos) AddPointToList(cc, pointlists, pos);
269 last = wxMin(pos + (1 << level), m_track.TrackPoints.size() - 1);
270 AddPointToList(cc, pointlists, last);
271 } else {
272 Assemble(cc, pointlists, box, scale, last, level - 1, pos << 1);
273 Assemble(cc, pointlists, box, scale, last, level - 1, (pos << 1) + 1);
274 }
275}
276
277void TrackGui::AddPointToList(ChartCanvas *cc,
278 std::list<std::list<wxPoint> > &pointlists,
279 int n) {
280 wxPoint r(INVALID_COORD, INVALID_COORD);
281 if ((size_t)n < m_track.TrackPoints.size())
282 cc->GetCanvasPointPix(m_track.TrackPoints[n]->m_lat,
283 m_track.TrackPoints[n]->m_lon, &r);
284
285 std::list<wxPoint> &pointlist = pointlists.back();
286 if (r.x == INVALID_COORD) {
287 if (pointlist.size()) {
288 std::list<wxPoint> new_list;
289 pointlists.push_back(new_list);
290 }
291 return;
292 }
293
294 if (pointlist.size() == 0)
295 pointlist.push_back(r);
296 else {
297 wxPoint l = pointlist.back();
298 // ensure the segment is at least 2 pixels
299 if ((abs(r.x - l.x) > 1) || (abs(r.y - l.y) > 1)) pointlist.push_back(r);
300 }
301}
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4416
ViewPort - Core geographic projection and coordinate transformation engine.
Definition viewport.h:56
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
Definition viewport.h:204
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
Global color handling by name.
Global variables stored in configuration file.
OpenGL chart rendering canvas.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Utility functions.
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
Route Manager.
Track and Trackpoint drawing stuff.