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 "navutil.h"
40#include "track_gui.h"
41#include "gl_chart_canvas.h"
42
43extern wxColor GetDimColor(wxColor c); // ocpn_frame: FIXME (leamas) new home
44
45extern ocpnGLOptions g_GLOptions; // FIXME (leamas) Fix GL dependency mess
46
47void TrackPointGui::Draw(ChartCanvas *cc, ocpnDC &dc) {
48 wxPoint r;
49 wxRect hilitebox;
50
51 cc->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
52
53 wxPen *pen;
54 pen = g_pRouteMan->GetRoutePointPen();
55
56 int sx2 = 8;
57 int sy2 = 8;
58
59 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
60
61 hilitebox = r1;
62 hilitebox.x -= r.x;
63 hilitebox.y -= r.y;
64 float radius;
65 hilitebox.Inflate(4);
66 radius = 4.0f;
67
68 wxColour hi_colour = pen->GetColour();
69 unsigned char transparency = 100;
70
71 // Highlite any selected point
72 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
73 hilitebox.height, radius, hi_colour, transparency);
74}
75
76void TrackGui::Finalize() {
77 if (m_track.SubTracks.size()) // subtracks already computed
78 return;
79
80 // OCPNStopWatch sw1;
81
82 int n = m_track.TrackPoints.size() - 1;
83 int level = 0;
84 while (n > 0) {
85 std::vector<SubTrack> new_level;
86 new_level.resize(n);
87 if (level == 0)
88 for (int i = 0; i < n; i++) {
89 new_level[i].m_box.SetFromSegment(m_track.TrackPoints[i]->m_lat,
90 m_track.TrackPoints[i]->m_lon,
91 m_track.TrackPoints[i + 1]->m_lat,
92 m_track.TrackPoints[i + 1]->m_lon);
93 new_level[i].m_scale = 0;
94 }
95 else {
96 for (int i = 0; i < n; i++) {
97 int p = i << 1;
98 new_level[i].m_box = m_track.SubTracks[level - 1][p].m_box;
99 if (p + 1 < (int)m_track.SubTracks[level - 1].size())
100 new_level[i].m_box.Expand(m_track.SubTracks[level - 1][p + 1].m_box);
101
102 int left = i << level;
103 int right = wxMin(left + (1 << level), m_track.TrackPoints.size() - 1);
104 new_level[i].m_scale = m_track.ComputeScale(left, right);
105 }
106 }
107 m_track.SubTracks.push_back(new_level);
108
109 if (n > 1 && n & 1) n++;
110 n >>= 1;
111 level++;
112 }
113 // if(m_track.TrackPoints.size() > 100)
114 // printf("fin time %f %d\n", sw1.GetTime(),
115 // (int)m_track.TrackPoints.size());
116}
117
118void TrackGui::GetPointLists(ChartCanvas *cc,
119 std::list<std::list<wxPoint> > &pointlists,
120 ViewPort &VP, const LLBBox &box) {
121 if (!m_track.IsVisible() || m_track.GetnPoints() == 0) return;
122 Finalize();
123 // OCPNStopWatch sw;
124 Segments(cc, pointlists, box, VP.view_scale_ppm);
125#if 0
126 if(GetnPoints() > 40000) {
127 double t = sw.GetTime();
128 double c = 0;
129 for(std::list< std::list<wxPoint> >::iterator lines = pointlists.begin();
130 lines != pointlists.end(); lines++) {
131 if(lines->size() > 1)
132 c += lines->size();
133 continue;
134 }
135 printf("assemble time %f %f segments %f seg/ms\n", sw.GetTime(), c, c/t);
136 }
137#endif
138
139 // Add last segment, dynamically, maybe.....
140 // we should not add this segment if it is not on the screen...
141 if (m_track.IsRunning()) {
142 std::list<wxPoint> new_list;
143 pointlists.push_back(new_list);
144 AddPointToList(cc, pointlists, m_track.TrackPoints.size() - 1);
145 wxPoint r;
146 cc->GetCanvasPointPix(gLat, gLon, &r);
147 pointlists.back().push_back(r);
148 }
149}
150
151void TrackGui::Draw(ChartCanvas *cc, ocpnDC &dc, ViewPort &VP,
152 const LLBBox &box) {
153 std::list<std::list<wxPoint> > pointlists;
154 GetPointLists(cc, pointlists, VP, box);
155
156 if (!pointlists.size()) return;
157
158 // Establish basic colour
159 wxColour basic_colour;
160 if (m_track.IsRunning())
161 basic_colour = GetGlobalColor("URED");
162 else
163 basic_colour = GetDimColor(g_colourTrackLineColour);
164
165 wxPenStyle style = wxPENSTYLE_SOLID;
166 int width = g_pRouteMan->GetTrackPen()->GetWidth();
167 wxColour col;
168 if (m_track.m_style != wxPENSTYLE_INVALID) style = m_track.m_style;
169 if (m_track.m_width != WIDTH_UNDEFINED) width = m_track.m_width;
170 if (m_track.m_Colour == "") {
171 col = basic_colour;
172 // Render tracks associated with persistent AIS targets as a contrasting
173 // color
174 if (m_track.GetName().StartsWith("AIS")) col = GetGlobalColor("TEAL1");
175 } else {
176 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
177 i++) {
178 if (m_track.m_Colour == ::GpxxColorNames[i]) {
179 col = ::GpxxColors[i];
180 break;
181 }
182 }
183 }
184
185 double radius = 0.;
186 if (g_bHighliteTracks) {
187 double radius_meters = 20; // 1.5 mm at original scale
188 double scale = VP.view_scale_ppm;
189 radius = wxMax((radius_meters * wxMin(scale, 1.1)), 6.0);
190 if (scale < 0.004) radius = 0;
191 }
192
193 {
194 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
195#ifdef ocpnUSE_GL
196 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
197 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
198 }
199#endif
200 dc.SetPen(p);
201 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
202 for (std::list<std::list<wxPoint> >::iterator lines = pointlists.begin();
203 lines != pointlists.end(); lines++) {
204 // convert from linked list to array
205 wxPoint *points = new wxPoint[lines->size()];
206 int i = 0;
207 for (std::list<wxPoint>::iterator line = lines->begin();
208 line != lines->end(); line++) {
209 points[i] = *line;
210 i++;
211 }
212
213 int hilite_width = radius;
214 if (hilite_width >= 1.0) {
215 // Save for base track
216 wxPen psave = dc.GetPen();
217
218 wxColor trackLine_dim_colour = 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: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:4495
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.