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