OpenCPN Partial API docs
Loading...
Searching...
No Matches
route_printout.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2012 by David S. Register *
3 * Copyright (C) 2025 by NoCodeHummel *
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#ifdef __WXMSW__
26#include <stdlib.h>
27#include <math.h>
28#include <time.h>
29#include <psapi.h>
30#endif
31
32#ifndef __WXMSW__
33#include <signal.h>
34#include <setjmp.h>
35#endif
36
37#include "gl_headers.h" // Must be included before anything using GL stuff
38
39#include <wx/wxprec.h>
40
41#ifndef WX_PRECOMP
42#include <wx/wx.h>
43#endif
44
45#ifdef __WXMSW__
46// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
47#endif
48
49#include <wx/artprov.h>
50#include <wx/aui/aui.h>
51#include <wx/brush.h>
52#include <wx/colour.h>
53#include <wx/dialog.h>
54#include <wx/intl.h>
55#include <wx/listctrl.h>
56#include <wx/printdlg.h>
57#include <wx/print.h>
58#include <wx/progdlg.h>
59#include <wx/stdpaths.h>
60
61#include "model/navutil_base.h"
62#include "model/route.h"
63#include "model/track.h"
64#include "navutil.h"
65#include "print_dialog.h"
66#include "printtable.h"
67#include "route_printout.h"
68#include "tcmgr.h"
69
70using namespace std;
71
72RoutePrintout::RoutePrintout(Route* route, const std::set<int>& options,
73 const int tz_selection)
74 : BasePrintout(_("Route Print").ToStdString()), m_route(route) {
75 // Offset text from the edge of the cell (Needed on Linux)
76 m_text_offset_x = 5;
77 m_text_offset_y = 8;
78
79 m_table.StartFillHeader();
80
81 m_table << _("Leg");
82
83 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
84 m_table << _("Waypoint");
85 }
86 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
87 m_table << _("Position");
88 }
89 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
90 m_table << _("Course");
91 }
92 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
93 m_table << _("Distance");
94 }
95 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
96 m_table << _("Speed");
97 }
98 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
99 m_table << _("ETA");
100 }
101 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
102 m_table << _("ETD");
103 }
104 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
105 m_table << _("Next tide event");
106 }
107 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
108 m_table << _("Description");
109 }
110
111 // setup widths for columns
112 m_table.StartFillWidths();
113 m_table << 20;
114
115 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
116 m_table << 60;
117 }
118 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
119 m_table << 60;
120 }
121 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
122 m_table << 40;
123 }
124 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
125 m_table << 40;
126 }
127 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
128 m_table << 40;
129 }
130 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
131 m_table << 80;
132 }
133 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
134 m_table << 80;
135 }
136 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
137 m_table << 120;
138 }
139 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
140 m_table << 120;
141 }
142
143 m_table.StartFillData();
144
145 for (int n = 1; n <= m_route->GetnPoints(); n++) {
146 RoutePoint* point = m_route->GetPoint(n);
147 if (NULL == point) continue;
148
149 if (n > 1) {
150 m_table << n - 1;
151 } else {
152 m_table << "---";
153 }
154
155 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
156 m_table << point->GetName();
157 }
158 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
159 std::wostringstream point_position;
160 point_position << toSDMM(1, point->m_lat, false) << "\n"
161 << toSDMM(2, point->m_lon, false);
162 m_table << point_position.str();
163 }
164 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
165 if (n > 1) {
166 m_table << formatAngle(point->GetCourse());
167 } else {
168 m_table << "---";
169 }
170 }
171 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
172 if (n > 1) {
173 std::ostringstream point_distance;
174 point_distance << std::fixed << std::setprecision(2) << std::setw(6)
175 << toUsrDistance(point->GetDistance())
176 << getUsrDistanceUnit();
177 m_table << point_distance.str();
178 } else {
179 m_table << "---";
180 }
181 }
182 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
183 std::wostringstream point_speed;
184 if (n > 1) {
185 point_speed << std::fixed << std::setprecision(1);
186 if (point->GetPlannedSpeed() < .1) {
187 point_speed << toUsrSpeed(m_route->m_PlannedSpeed);
188 } else {
189 point_speed << toUsrSpeed(point->GetPlannedSpeed());
190 }
191 point_speed << getUsrSpeedUnit().ToStdString();
192 m_table << point_speed.str();
193 } else {
194 m_table << "---";
195 }
196 }
197 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
198 m_table << toUsrDateTime(point->GetETA(), tz_selection, point->m_lon)
199 .FormatISOCombined(' ');
200 }
201 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
202 if (point->GetManualETD().IsValid()) {
203 m_table << toUsrDateTime(point->GetManualETD(), tz_selection,
204 point->m_lon)
205 .FormatISOCombined(' ');
206 } else {
207 m_table << "---";
208 }
209 }
210 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
211 std::wostringstream point_tide;
212 if (point->m_TideStation.Len() > 0 && point->GetETA().IsValid()) {
213 int station_id = ptcmgr->GetStationIDXbyName(
214 point->m_TideStation, point->m_lat, point->m_lon);
215 if (station_id > 0) {
216 point_tide << ptcmgr->GetTidalEventStr(station_id, point->GetETA(),
217 point->m_lat, point->m_lon,
218 tz_selection);
219 point_tide << "\n@" << point->m_TideStation;
220 m_table << point_tide.str();
221 } else {
222 m_table << "---";
223 }
224 } else {
225 m_table << "---";
226 }
227 }
228 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
229 m_table << point->GetDescription();
230 }
231 m_table << "\n";
232 }
233}
234
235void RoutePrintout::OnPreparePrinting() {
236 wxDC* dc = GetDC();
237 wxFont routePrintFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
238 wxFONTWEIGHT_NORMAL);
239 dc->SetFont(routePrintFont);
240
241 // Get the size of the DC in pixels
242 int w, h;
243 dc->GetSize(&w, &h);
244
245 // We don't know before hand what size the Print DC will be, in pixels. Varies
246 // by host. So, if the dc size is greater than 1000 pixels, we scale
247 // accordinly.
248 int max_x = wxMin(w, 1000);
249 int max_y = wxMin(h, 1000);
250
251 // Calculate a suitable scaling factor
252 double scale_x = (double)(w / max_x);
253 double scale_y = (double)(h / max_y);
254
255 // Use x or y scaling factor, whichever fits on the DC
256 double actual_scale = wxMin(scale_x, scale_y);
257
258 // Set the scale and origin
259 dc->SetUserScale(actual_scale, actual_scale);
260 dc->SetDeviceOrigin((long)m_margin_x, (long)m_margin_y);
261
262 m_table.AdjustCells(dc, m_margin_x, m_margin_y);
263 m_pages = m_table.GetNumberPages();
264}
265
266void RoutePrintout::DrawPage(wxDC* dc, int page) {
267 wxFont title_font(16, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
268 wxFONTWEIGHT_BOLD);
269 wxFont subtitle_font(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
270 wxFONTWEIGHT_NORMAL);
271 wxFont header_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
272 wxFONTWEIGHT_BOLD);
273 wxFont normal_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
274 wxFONTWEIGHT_NORMAL);
275
276 wxBrush brush(wxColour(255, 255, 255), wxBRUSHSTYLE_TRANSPARENT);
277 dc->SetBrush(brush);
278
279 int current_x = m_margin_x;
280 int current_y = m_margin_y;
281
282 std::wostringstream title;
283 std::wostringstream subtitle;
284 std::wostringstream distance;
285
286 distance << std::fixed << std::setprecision(1)
287 << toUsrDistance(m_route->m_route_length)
288 << getUsrDistanceUnit().ToStdString();
289
290 if (m_route->m_RouteNameString.Trim().Len() > 0) {
291 title << m_route->m_RouteNameString.ToStdString();
292 title << " (" << distance.str() << ")";
293 } else {
294 title << _("Total distance ").ToStdString() << distance.str();
295 }
296
297 if (m_route->m_RouteStartString.Trim().Len() > 0) {
298 subtitle << _("From").ToStdString() << " "
299 << m_route->m_RouteStartString.ToStdString();
300 if (m_route->m_RouteEndString.Trim().Len() > 0) {
301 subtitle << " " << _("To").ToStdString() << " "
302 << m_route->m_RouteEndString.ToStdString();
303 }
304 } else if (m_route->m_RouteEndString.Trim().Len() > 0) {
305 subtitle << _("Destination").ToStdString() << " "
306 << m_route->m_RouteEndString.ToStdString();
307 }
308
309 int title_width, title_height;
310 dc->SetFont(title_font);
311 dc->GetTextExtent(title.str(), &title_width, &title_height);
312 dc->DrawText(title.str(), current_x, current_y);
313 current_y += title_height + m_text_offset_y;
314
315 if (subtitle.str().length() > 0) {
316 int subtitle_width, subtitle_height;
317 dc->SetFont(subtitle_font);
318 dc->GetTextExtent(subtitle.str(), &subtitle_width, &subtitle_height);
319 dc->DrawText(subtitle.str(), current_x, current_y);
320 current_y += subtitle_height + m_text_offset_y;
321 }
322
323 dc->SetFont(normal_font);
324
325 // Route description on page 1.
326 if (page == 1 && m_route->m_RouteDescription.Trim().Len() > 0) {
327 int page_size_x, page_size_y;
328 dc->GetSize(&page_size_x, &page_size_y);
329
330 PrintCell cell_desc;
331 cell_desc.Init(m_route->m_RouteDescription, dc, page_size_x, m_margin_x);
332 dc->DrawText(cell_desc.GetText(), current_x, current_y);
333 current_y += cell_desc.GetHeight() + m_text_offset_y;
334 }
335
336 vector<PrintCell>& header_content = m_table.GetHeader();
337 for (size_t j = 0; j < header_content.size(); j++) {
338 PrintCell& cell = header_content[j];
339 dc->DrawRectangle(current_x, current_y, cell.GetWidth() + m_text_offset_x,
340 cell.GetHeight() + m_text_offset_y);
341 dc->DrawText(cell.GetText(), current_x + m_text_offset_x,
342 current_y + m_text_offset_y);
343 current_x += cell.GetWidth() + m_text_offset_x;
344 }
345
346 wxFont routePrintFont_normal(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
347 wxFONTWEIGHT_NORMAL);
348 dc->SetFont(routePrintFont_normal);
349
350 vector<vector<PrintCell> >& cells = m_table.GetContent();
351 current_y += m_table.GetHeaderHeight() + m_text_offset_y;
352 int current_height = 0;
353 for (size_t i = 0; i < cells.size(); i++) {
354 vector<PrintCell>& content_row = cells[i];
355 current_x = m_margin_x;
356 for (size_t j = 0; j < content_row.size(); j++) {
357 PrintCell& cell = content_row[j];
358 if (cell.GetPage() == page) {
359 wxRect r(current_x, current_y, cell.GetWidth() + m_text_offset_x,
360 cell.GetHeight() + m_text_offset_y);
361 dc->DrawRectangle(r);
362 r.Offset(m_text_offset_x, m_text_offset_y);
363 dc->DrawLabel(cell.GetText(), r);
364 current_x += cell.GetWidth() + m_text_offset_x;
365 current_height = cell.GetHeight() + m_text_offset_y;
366 }
367 }
368 current_y += current_height;
369 }
370}
Application print support.
This class takes multilined string and modifies it to fit into given width for given device.
Definition printtable.h:106
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
double GetPlannedSpeed()
Return the planned speed associated with this waypoint.
wxString m_TideStation
Associated tide station identifier.
wxDateTime GetETA()
Retrieves the Estimated Time of Arrival for this waypoint, in UTC.
RoutePrintout(Route *route, const std::set< int > &options, const int tz_selection)
Create route prinout.
void DrawPage(wxDC *dc, int page) override
Called by the print framework to draw the page.
Represents a navigational route in the navigation system.
Definition route.h:99
double m_PlannedSpeed
Default planned speed for the route in knots.
Definition route.h:321
wxString m_RouteStartString
Name or description of the route's starting point.
Definition route.h:252
wxString m_RouteDescription
Additional descriptive information about the route.
Definition route.h:262
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
Definition route.h:237
wxString m_RouteEndString
Name or description of the route's ending point.
Definition route.h:257
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
Platform independent GL includes.
bool HasKey(const std::set< int > &set, T key)
Check if a key exists in a set.
Definition ui_utils.h:60
wxDateTime toUsrDateTime(const wxDateTime ts, const int format, const double lon)
Converts a timestamp from UTC to the user's preferred time format.
Definition navutil.cpp:2876
Utility functions.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
Navigation Utility Functions without GUI dependencies.
Generic, styled prit dialog.
OpenCPN Route table printout.
Route abstraction.
Route print dialog.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
Tide and Current Manager @TODO Add original author copyright.
Recorded track abstraction.