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 "gl_headers.h" // Must be included before anything using GL stuff
28
29#include <wx/colour.h>
30#include <wx/gdicmn.h>
31#include <wx/pen.h>
32
33#include "model/config_vars.h"
34#include "model/gui_vars.h"
35#include "model/own_ship.h"
36#include "model/routeman.h"
37
38#include "color_handler.h"
39#include "gl_chart_canvas.h"
40#include "navutil.h"
41#include "track_gui.h"
42#include "user_colors.h"
43
44extern ocpnGLOptions g_GLOptions; // FIXME (leamas) Fix GL dependency mess
45
46void TrackPointGui::Draw(ChartCanvas *cc, ocpnDC &dc) {
47 wxPoint r;
48 wxRect hilitebox;
49
50 cc->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
51
52 wxPen *pen;
53 pen = g_pRouteMan->GetRoutePointPen();
54
55 int sx2 = 8;
56 int sy2 = 8;
57
58 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
59
60 hilitebox = r1;
61 hilitebox.x -= r.x;
62 hilitebox.y -= r.y;
63 float radius;
64 hilitebox.Inflate(4);
65 radius = 4.0f;
66
67 wxColour hi_colour = pen->GetColour();
68 unsigned char transparency = 100;
69
70 // Highlite any selected point
71 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
72 hilitebox.height, radius, hi_colour, transparency);
73}
74
75void TrackGui::Finalize() {
76 if (m_track.SubTracks.size()) // subtracks already computed
77 return;
78
79 // OCPNStopWatch sw1;
80
81 int n = m_track.TrackPoints.size() - 1;
82 int level = 0;
83 while (n > 0) {
84 std::vector<SubTrack> new_level;
85 new_level.resize(n);
86 if (level == 0)
87 for (int i = 0; i < n; i++) {
88 new_level[i].m_box.SetFromSegment(m_track.TrackPoints[i]->m_lat,
89 m_track.TrackPoints[i]->m_lon,
90 m_track.TrackPoints[i + 1]->m_lat,
91 m_track.TrackPoints[i + 1]->m_lon);
92 new_level[i].m_scale = 0;
93 }
94 else {
95 for (int i = 0; i < n; i++) {
96 int p = i << 1;
97 new_level[i].m_box = m_track.SubTracks[level - 1][p].m_box;
98 if (p + 1 < (int)m_track.SubTracks[level - 1].size())
99 new_level[i].m_box.Expand(m_track.SubTracks[level - 1][p + 1].m_box);
100
101 int left = i << level;
102 int right = wxMin(left + (1 << level), m_track.TrackPoints.size() - 1);
103 new_level[i].m_scale = m_track.ComputeScale(left, right);
104 }
105 }
106 m_track.SubTracks.push_back(new_level);
107
108 if (n > 1 && n & 1) n++;
109 n >>= 1;
110 level++;
111 }
112 // if(m_track.TrackPoints.size() > 100)
113 // printf("fin time %f %d\n", sw1.GetTime(),
114 // (int)m_track.TrackPoints.size());
115}
116
117void TrackGui::GetPointLists(ChartCanvas *cc,
118 std::list<std::list<wxPoint> > &pointlists,
119 ViewPort &VP, const LLBBox &box) {
120 if (!m_track.IsVisible() || m_track.GetnPoints() == 0) return;
121 Finalize();
122 // OCPNStopWatch sw;
123 Segments(cc, pointlists, box, VP.view_scale_ppm);
124#if 0
125 if(GetnPoints() > 40000) {
126 double t = sw.GetTime();
127 double c = 0;
128 for(std::list< std::list<wxPoint> >::iterator lines = pointlists.begin();
129 lines != pointlists.end(); lines++) {
130 if(lines->size() > 1)
131 c += lines->size();
132 continue;
133 }
134 printf("assemble time %f %f segments %f seg/ms\n", sw.GetTime(), c, c/t);
135 }
136#endif
137
138 // Add last segment, dynamically, maybe.....
139 // we should not add this segment if it is not on the screen...
140 if (m_track.IsRunning()) {
141 std::list<wxPoint> new_list;
142 pointlists.push_back(new_list);
143 AddPointToList(cc, pointlists, m_track.TrackPoints.size() - 1);
144 wxPoint r;
145 cc->GetCanvasPointPix(gLat, gLon, &r);
146 pointlists.back().push_back(r);
147 }
148}
149
150void TrackGui::Draw(ChartCanvas *cc, ocpnDC &dc, ViewPort &VP,
151 const LLBBox &box) {
152 std::list<std::list<wxPoint> > pointlists;
153 GetPointLists(cc, pointlists, VP, box);
154
155 if (!pointlists.size()) return;
156
157 // Establish basic colour
158 wxColour basic_colour;
159 if (m_track.IsRunning())
160 basic_colour = GetGlobalColor("URED");
161 else
162 basic_colour = user_colors::GetDimColor(g_colourTrackLineColour);
163
164 wxPenStyle style = wxPENSTYLE_SOLID;
165 int width = g_pRouteMan->GetTrackPen()->GetWidth();
166 wxColour col;
167 if (m_track.m_style != wxPENSTYLE_INVALID) style = m_track.m_style;
168 if (m_track.m_width != WIDTH_UNDEFINED) width = m_track.m_width;
169 if (m_track.m_Colour == "") {
170 col = basic_colour;
171 // Render tracks associated with persistent AIS targets as a contrasting
172 // color
173 if (m_track.GetName().StartsWith("AIS")) col = GetGlobalColor("TEAL1");
174 } else {
175 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
176 i++) {
177 if (m_track.m_Colour == ::GpxxColorNames[i]) {
178 col = ::GpxxColors[i];
179 break;
180 }
181 }
182 }
183
184 double radius = 0.;
185 if (g_bHighliteTracks) {
186 double radius_meters = 20; // 1.5 mm at original scale
187 double scale = VP.view_scale_ppm;
188 radius = wxMax((radius_meters * wxMin(scale, 1.1)), 6.0);
189 if (scale < 0.004) radius = 0;
190 }
191
192 {
193 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
194#ifdef ocpnUSE_GL
195 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
196 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
197 }
198#endif
199 dc.SetPen(p);
200 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
201 for (std::list<std::list<wxPoint> >::iterator lines = pointlists.begin();
202 lines != pointlists.end(); lines++) {
203 // convert from linked list to array
204 wxPoint *points = new wxPoint[lines->size()];
205 int i = 0;
206 for (std::list<wxPoint>::iterator line = lines->begin();
207 line != lines->end(); line++) {
208 points[i] = *line;
209 i++;
210 }
211
212 int hilite_width = radius;
213 if (hilite_width >= 1.0) {
214 // Save for base track
215 wxPen psave = dc.GetPen();
216
217 wxColor trackLine_dim_colour =
218 user_colors::GetDimColor(g_colourTrackLineColour);
219 wxColour hilt(trackLine_dim_colour.Red(), trackLine_dim_colour.Green(),
220 trackLine_dim_colour.Blue(), 128);
221 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
222 dc.SetPen(HiPen);
223 // Draw highlighted track
224 dc.StrokeLines(i, points);
225
226 dc.SetPen(psave);
227 // Draw base track visible above highlight
228 dc.StrokeLines(i, points);
229 } else
230 dc.StrokeLines(i, points);
231
232 delete[] points;
233 }
234 }
235
236 if (m_track.m_HighlightedTrackPoint >= 0)
237 TrackPointGui(m_track.TrackPoints[m_track.m_HighlightedTrackPoint])
238 .Draw(cc, dc);
239}
240
241// Entry to recursive Assemble at the head of the SubTracks tree
242void TrackGui::Segments(ChartCanvas *cc,
243 std::list<std::list<wxPoint> > &pointlists,
244 const LLBBox &box, double scale) {
245 if (!m_track.SubTracks.size()) return;
246
247 int level = m_track.SubTracks.size() - 1, last = -2;
248 Assemble(cc, pointlists, box, 1 / scale / scale, last, level, 0);
249}
250
251/* assembles lists of line strips from the given track recursively traversing
252 the subtracks data */
253void TrackGui::Assemble(ChartCanvas *cc,
254 std::list<std::list<wxPoint> > &pointlists,
255 const LLBBox &box, double scale, int &last, int level,
256 int pos) {
257 if (pos == (int)m_track.SubTracks[level].size()) return;
258
259 SubTrack &s = m_track.SubTracks[level][pos];
260 if (box.IntersectOut(s.m_box)) return;
261
262 if (s.m_scale < scale) {
263 pos <<= level;
264
265 if (last < pos - 1) {
266 std::list<wxPoint> new_list;
267 pointlists.push_back(new_list);
268 }
269
270 if (last < pos) AddPointToList(cc, pointlists, pos);
271 last = wxMin(pos + (1 << level), m_track.TrackPoints.size() - 1);
272 AddPointToList(cc, pointlists, last);
273 } else {
274 Assemble(cc, pointlists, box, scale, last, level - 1, pos << 1);
275 Assemble(cc, pointlists, box, scale, last, level - 1, (pos << 1) + 1);
276 }
277}
278
279void TrackGui::AddPointToList(ChartCanvas *cc,
280 std::list<std::list<wxPoint> > &pointlists,
281 int n) {
282 wxPoint r(INVALID_COORD, INVALID_COORD);
283 if ((size_t)n < m_track.TrackPoints.size())
284 cc->GetCanvasPointPix(m_track.TrackPoints[n]->m_lat,
285 m_track.TrackPoints[n]->m_lon, &r);
286
287 std::list<wxPoint> &pointlist = pointlists.back();
288 if (r.x == INVALID_COORD) {
289 if (pointlist.size()) {
290 std::list<wxPoint> new_list;
291 pointlists.push_back(new_list);
292 }
293 return;
294 }
295
296 if (pointlist.size() == 0)
297 pointlist.push_back(r);
298 else {
299 wxPoint l = pointlist.back();
300 // ensure the segment is at least 2 pixels
301 if ((abs(r.x - l.x) > 1) || (abs(r.y - l.y) > 1)) pointlist.push_back(r);
302 }
303}
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:173
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4547
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.
Platform independent GL includes.
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.