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 <wx/wxprec.h>
38
39#ifndef WX_PRECOMP
40#include <wx/wx.h>
41#endif
42
43#ifdef __WXMSW__
44// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
45#endif
46
47#include <wx/artprov.h>
48#include <wx/aui/aui.h>
49#include <wx/brush.h>
50#include <wx/colour.h>
51#include <wx/dialog.h>
52#include <wx/intl.h>
53#include <wx/listctrl.h>
54#include <wx/printdlg.h>
55#include <wx/print.h>
56#include <wx/progdlg.h>
57#include <wx/stdpaths.h>
58
59#include "model/navutil_base.h"
60#include "model/route.h"
61#include "model/track.h"
62#include "navutil.h"
63#include "print_dialog.h"
64#include "printtable.h"
65#include "route_printout.h"
66#include "tcmgr.h"
67
68using namespace std;
69
70RoutePrintout::RoutePrintout(Route* route, const std::set<int>& options,
71 const int tz_selection)
72 : BasePrintout(_("Route Print").ToStdString()), m_route(route) {
73 // Offset text from the edge of the cell (Needed on Linux)
74 m_text_offset_x = 5;
75 m_text_offset_y = 8;
76
77 m_table.StartFillHeader();
78
79 m_table << _("Leg");
80
81 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
82 m_table << _("Waypoint");
83 }
84 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
85 m_table << _("Position");
86 }
87 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
88 m_table << _("Course");
89 }
90 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
91 m_table << _("Distance");
92 }
93 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
94 m_table << _("Speed");
95 }
96 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
97 m_table << _("ETA");
98 }
99 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
100 m_table << _("ETD");
101 }
102 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
103 m_table << _("Next tide event");
104 }
105 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
106 m_table << _("Description");
107 }
108
109 // setup widths for columns
110 m_table.StartFillWidths();
111 m_table << 20;
112
113 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
114 m_table << 60;
115 }
116 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
117 m_table << 60;
118 }
119 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
120 m_table << 40;
121 }
122 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
123 m_table << 40;
124 }
125 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
126 m_table << 40;
127 }
128 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
129 m_table << 80;
130 }
131 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
132 m_table << 80;
133 }
134 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
135 m_table << 120;
136 }
137 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
138 m_table << 120;
139 }
140
141 m_table.StartFillData();
142
143 for (int n = 1; n <= m_route->GetnPoints(); n++) {
144 RoutePoint* point = m_route->GetPoint(n);
145 if (NULL == point) continue;
146
147 if (n > 1) {
148 m_table << n - 1;
149 } else {
150 m_table << "---";
151 }
152
153 if (GUI::HasKey(options, RoutePrintOptions::kWaypointName)) {
154 m_table << point->GetName();
155 }
156 if (GUI::HasKey(options, RoutePrintOptions::kWaypointPosition)) {
157 std::wostringstream point_position;
158 point_position << toSDMM(1, point->m_lat, false) << "\n"
159 << toSDMM(2, point->m_lon, false);
160 m_table << point_position.str();
161 }
162 if (GUI::HasKey(options, RoutePrintOptions::kWaypointCourse)) {
163 if (n > 1) {
164 m_table << formatAngle(point->GetCourse());
165 } else {
166 m_table << "---";
167 }
168 }
169 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDistance)) {
170 if (n > 1) {
171 std::ostringstream point_distance;
172 point_distance << std::fixed << std::setprecision(2) << std::setw(6)
173 << toUsrDistance(point->GetDistance())
174 << getUsrDistanceUnit();
175 m_table << point_distance.str();
176 } else {
177 m_table << "---";
178 }
179 }
180 if (GUI::HasKey(options, RoutePrintOptions::kWaypointSpeed)) {
181 std::wostringstream point_speed;
182 if (n > 1) {
183 point_speed << std::fixed << std::setprecision(1);
184 if (point->GetPlannedSpeed() < .1) {
185 point_speed << toUsrSpeed(m_route->m_PlannedSpeed);
186 } else {
187 point_speed << toUsrSpeed(point->GetPlannedSpeed());
188 }
189 point_speed << getUsrSpeedUnit().ToStdString();
190 m_table << point_speed.str();
191 } else {
192 m_table << "---";
193 }
194 }
195 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETA)) {
196 m_table << toUsrDateTime(point->GetETA(), tz_selection, point->m_lon)
197 .FormatISOCombined(' ');
198 }
199 if (GUI::HasKey(options, RoutePrintOptions::kWaypointETD)) {
200 if (point->GetManualETD().IsValid()) {
201 m_table << toUsrDateTime(point->GetManualETD(), tz_selection,
202 point->m_lon)
203 .FormatISOCombined(' ');
204 } else {
205 m_table << "---";
206 }
207 }
208 if (GUI::HasKey(options, RoutePrintOptions::kWaypointTideEvent)) {
209 std::wostringstream point_tide;
210 if (point->m_TideStation.Len() > 0 && point->GetETA().IsValid()) {
211 int station_id = ptcmgr->GetStationIDXbyName(
212 point->m_TideStation, point->m_lat, point->m_lon);
213 if (station_id > 0) {
214 point_tide << ptcmgr->GetTidalEventStr(station_id, point->GetETA(),
215 point->m_lat, point->m_lon,
216 tz_selection);
217 point_tide << "\n@" << point->m_TideStation;
218 m_table << point_tide.str();
219 } else {
220 m_table << "---";
221 }
222 } else {
223 m_table << "---";
224 }
225 }
226 if (GUI::HasKey(options, RoutePrintOptions::kWaypointDescription)) {
227 m_table << point->GetDescription();
228 }
229 m_table << "\n";
230 }
231}
232
233void RoutePrintout::OnPreparePrinting() {
234 wxDC* dc = GetDC();
235 wxFont routePrintFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
236 wxFONTWEIGHT_NORMAL);
237 dc->SetFont(routePrintFont);
238
239 // Get the size of the DC in pixels
240 int w, h;
241 dc->GetSize(&w, &h);
242
243 // We don't know before hand what size the Print DC will be, in pixels. Varies
244 // by host. So, if the dc size is greater than 1000 pixels, we scale
245 // accordinly.
246 int max_x = wxMin(w, 1000);
247 int max_y = wxMin(h, 1000);
248
249 // Calculate a suitable scaling factor
250 double scale_x = (double)(w / max_x);
251 double scale_y = (double)(h / max_y);
252
253 // Use x or y scaling factor, whichever fits on the DC
254 double actual_scale = wxMin(scale_x, scale_y);
255
256 // Set the scale and origin
257 dc->SetUserScale(actual_scale, actual_scale);
258 dc->SetDeviceOrigin((long)m_margin_x, (long)m_margin_y);
259
260 m_table.AdjustCells(dc, m_margin_x, m_margin_y);
261 m_pages = m_table.GetNumberPages();
262}
263
264void RoutePrintout::DrawPage(wxDC* dc, int page) {
265 wxFont title_font(16, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
266 wxFONTWEIGHT_BOLD);
267 wxFont subtitle_font(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
268 wxFONTWEIGHT_NORMAL);
269 wxFont header_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
270 wxFONTWEIGHT_BOLD);
271 wxFont normal_font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
272 wxFONTWEIGHT_NORMAL);
273
274 wxBrush brush(wxColour(255, 255, 255), wxBRUSHSTYLE_TRANSPARENT);
275 dc->SetBrush(brush);
276
277 int current_x = m_margin_x;
278 int current_y = m_margin_y;
279
280 std::wostringstream title;
281 std::wostringstream subtitle;
282 std::wostringstream distance;
283
284 distance << std::fixed << std::setprecision(1)
285 << toUsrDistance(m_route->m_route_length)
286 << getUsrDistanceUnit().ToStdString();
287
288 if (m_route->m_RouteNameString.Trim().Len() > 0) {
289 title << m_route->m_RouteNameString.ToStdString();
290 title << " (" << distance.str() << ")";
291 } else {
292 title << _("Total distance ").ToStdString() << distance.str();
293 }
294
295 if (m_route->m_RouteStartString.Trim().Len() > 0) {
296 subtitle << _("From").ToStdString() << " "
297 << m_route->m_RouteStartString.ToStdString();
298 if (m_route->m_RouteEndString.Trim().Len() > 0) {
299 subtitle << " " << _("To").ToStdString() << " "
300 << m_route->m_RouteEndString.ToStdString();
301 }
302 } else if (m_route->m_RouteEndString.Trim().Len() > 0) {
303 subtitle << _("Destination").ToStdString() << " "
304 << m_route->m_RouteEndString.ToStdString();
305 }
306
307 int title_width, title_height;
308 dc->SetFont(title_font);
309 dc->GetTextExtent(title.str(), &title_width, &title_height);
310 dc->DrawText(title.str(), current_x, current_y);
311 current_y += title_height + m_text_offset_y;
312
313 if (subtitle.str().length() > 0) {
314 int subtitle_width, subtitle_height;
315 dc->SetFont(subtitle_font);
316 dc->GetTextExtent(subtitle.str(), &subtitle_width, &subtitle_height);
317 dc->DrawText(subtitle.str(), current_x, current_y);
318 current_y += subtitle_height + m_text_offset_y;
319 }
320
321 dc->SetFont(normal_font);
322
323 // Route description on page 1.
324 if (page == 1 && m_route->m_RouteDescription.Trim().Len() > 0) {
325 int page_size_x, page_size_y;
326 dc->GetSize(&page_size_x, &page_size_y);
327
328 PrintCell cell_desc;
329 cell_desc.Init(m_route->m_RouteDescription, dc, page_size_x, m_margin_x);
330 dc->DrawText(cell_desc.GetText(), current_x, current_y);
331 current_y += cell_desc.GetHeight() + m_text_offset_y;
332 }
333
334 vector<PrintCell>& header_content = m_table.GetHeader();
335 for (size_t j = 0; j < header_content.size(); j++) {
336 PrintCell& cell = header_content[j];
337 dc->DrawRectangle(current_x, current_y, cell.GetWidth() + m_text_offset_x,
338 cell.GetHeight() + m_text_offset_y);
339 dc->DrawText(cell.GetText(), current_x + m_text_offset_x,
340 current_y + m_text_offset_y);
341 current_x += cell.GetWidth() + m_text_offset_x;
342 }
343
344 wxFont routePrintFont_normal(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
345 wxFONTWEIGHT_NORMAL);
346 dc->SetFont(routePrintFont_normal);
347
348 vector<vector<PrintCell> >& cells = m_table.GetContent();
349 current_y += m_table.GetHeaderHeight() + m_text_offset_y;
350 int current_height = 0;
351 for (size_t i = 0; i < cells.size(); i++) {
352 vector<PrintCell>& content_row = cells[i];
353 current_x = m_margin_x;
354 for (size_t j = 0; j < content_row.size(); j++) {
355 PrintCell& cell = content_row[j];
356 if (cell.GetPage() == page) {
357 wxRect r(current_x, current_y, cell.GetWidth() + m_text_offset_x,
358 cell.GetHeight() + m_text_offset_y);
359 dc->DrawRectangle(r);
360 r.Offset(m_text_offset_x, m_text_offset_y);
361 dc->DrawLabel(cell.GetText(), r);
362 current_x += cell.GetWidth() + m_text_offset_x;
363 current_height = cell.GetHeight() + m_text_offset_y;
364 }
365 }
366 current_y += current_height;
367 }
368}
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
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:2869
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.