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