source: git/src/printwx.cc@ c11ceba

RELEASE/1.2 debug-ci debug-ci-sanitisers faster-cavernlog log-select main stereo stereo-2025 walls-data walls-data-hanging-as-warning warn-only-for-hanging-survey
Last change on this file since c11ceba was a72ed95, checked in by Olly Betts <olly@…>, 11 years ago
  • .gitignore,Makefile.am,debian/survex.install,doc/,lib/,src/: Aven's

support for reading colours and font sizes for printouts from
print.ini has never worked - the contents of the ini files are
ignored due to a bug which has been there since the code was added
in 2005 - but nobody has ever complained. So just strip out that
code entirely - we should support setting the colours and font sizes,
but a GUI interface for setting them would be better.

  • Property mode set to 100644
File size: 57.3 KB
RevLine 
[a80e6f3]1/* printwx.cc */
[1324d6c]2/* wxWidgets specific parts of Survex wxWidgets printing code */
[18ff765]3/* Copyright (C) 1993-2003,2004,2005,2006,2010,2011,2012,2013,2014,2015 Olly Betts
[79c239e]4 * Copyright (C) 2001,2004 Philip Underwood
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
[9f6ea6c]18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
[79c239e]19 */
20
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
[255f3269]25#include <wx/confbase.h>
26#include <wx/filename.h>
27#include <wx/print.h>
28#include <wx/printdlg.h>
29#include <wx/spinctrl.h>
30#include <wx/radiobox.h>
31#include <wx/statbox.h>
32#include <wx/valgen.h>
[741d94f]33
[255f3269]34#include <vector>
[741d94f]35
[79c239e]36#include <stdio.h>
37#include <stdlib.h>
38#include <math.h>
39#include <string.h>
40#include <ctype.h>
41#include <float.h>
42#include <limits.h>
43
44#include "debug.h" /* for BUG and SVX_ASSERT */
[5940815]45#include "export.h"
[79c239e]46#include "filelist.h"
47#include "filename.h"
48#include "message.h"
49#include "useful.h"
50
[e0ffc2c]51#include "aven.h"
[79c239e]52#include "avenprcore.h"
53#include "mainfrm.h"
[741d94f]54#include "printwx.h"
[79c239e]55
[255f3269]56using namespace std;
57
[4a66219]58// How many decimal points to show on angles:
59#define ANGLE_DP 1
60
61#if ANGLE_DP == 0
62# define ANGLE_FMT wxT("%03.f")
63# define ANGLE2_FMT wxT("%.f")
64#elif ANGLE_DP == 1
65# define ANGLE_FMT wxT("%05.1f")
66# define ANGLE2_FMT wxT("%.1f")
67#elif ANGLE_DP == 2
68# define ANGLE_FMT wxT("%06.2f")
69# define ANGLE2_FMT wxT("%.2f")
70#else
71# error Need to add ANGLE_FMT and ANGLE2_FMT for the currently set ANGLE_DP
72#endif
73
74static wxString
75format_angle(const wxChar * fmt, double angle)
76{
77 wxString s;
78 s.Printf(fmt, angle);
79 size_t dot = s.find('.');
80 size_t i = s.size();
81 while (i > dot) {
82 --i;
83 if (s[i] != '0') {
84 if (i != dot) ++i;
85 s.resize(i);
86 break;
87 }
88 }
89 s += wmsg(/*°*/344);
90 return s;
91}
92
[d64e7df]93enum {
[de8488a6]94 svx_EXPORT = 1200,
[583c17d]95 svx_FORMAT,
[d64e7df]96 svx_SCALE,
97 svx_BEARING,
98 svx_TILT,
99 svx_LEGS,
100 svx_STATIONS,
101 svx_NAMES,
[e90a41e]102 svx_XSECT,
103 svx_WALLS,
104 svx_PASSAGES,
[d64e7df]105 svx_BORDERS,
106 svx_BLANKS,
[08e858b]107 svx_LEGEND,
[d180604]108 svx_SURFACE,
[d64e7df]109 svx_PLAN,
[583c17d]110 svx_ELEV,
[7b55ac2]111 svx_ENTS,
112 svx_FIXES,
113 svx_EXPORTS,
[6d3938b]114 svx_PROJ_LABEL,
[7b55ac2]115 svx_PROJ,
116 svx_GRID,
117 svx_TEXT_HEIGHT,
[bc1fac5]118 svx_MARKER_SIZE,
119 svx_CENTRED,
120 svx_FULLCOORDS
[d64e7df]121};
122
[256c4c8]123class BitValidator : public wxValidator {
124 // Disallow assignment.
125 BitValidator & operator=(const BitValidator&);
126
127 protected:
128 int * val;
129
130 int mask;
131
132 public:
133 BitValidator(int * val_, int mask_)
134 : val(val_), mask(mask_) { }
135
[38500b0]136 BitValidator(const BitValidator &o) : wxValidator() {
137 Copy(o);
138 }
139
[256c4c8]140 ~BitValidator() { }
141
[1298787]142 wxObject *Clone() const { return new BitValidator(val, mask); }
[256c4c8]143
[38500b0]144 bool Copy(const BitValidator& o) {
145 wxValidator::Copy(o);
146 val = o.val;
147 mask = o.mask;
148 return true;
149 }
150
[256c4c8]151 bool Validate(wxWindow *) { return true; }
152
153 bool TransferToWindow() {
154 if (!m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)))
155 return false;
156 ((wxCheckBox*)m_validatorWindow)->SetValue(*val & mask);
157 return true;
158 }
159
160 bool TransferFromWindow() {
161 if (!m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)))
162 return false;
163 if (((wxCheckBox*)m_validatorWindow)->IsChecked())
164 *val |= mask;
165 else
166 *val &= ~mask;
167 return true;
168 }
169};
170
[79c239e]171class svxPrintout : public wxPrintout {
[ce403f1]172 MainFrm *mainfrm;
[79c239e]173 layout *m_layout;
[5a36f76]174 wxPageSetupDialogData* m_data;
[79c239e]175 wxDC* pdc;
[3d3a91c]176 // Currently unused, but "skip blank pages" would use it.
[79c239e]177 static const int cur_pass = 0;
178
179 wxPen *pen_frame, *pen_cross, *pen_surface_leg, *pen_leg;
180 wxColour colour_text, colour_labels, colour_frame, colour_leg;
181 wxColour colour_cross,colour_surface_leg;
182
183 long x_t, y_t;
184 double font_scaling_x, font_scaling_y;
185 wxFont * current_font;
186
187 int check_intersection(long x_p, long y_p);
188 void draw_info_box();
189 void draw_scale_bar(double x, double y, double MaxLength);
190 int next_page(int *pstate, char **q, int pageLim);
191 void drawticks(border clip, int tsize, int x, int y);
192
193 void MOVEMM(double X, double Y) {
194 MoveTo((long)(X * m_layout->scX), (long)(Y * m_layout->scY));
195 }
196 void DRAWMM(double X, double Y) {
197 DrawTo((long)(X * m_layout->scX), (long)(Y * m_layout->scY));
198 }
199 void MoveTo(long x, long y);
200 void DrawTo(long x, long y);
201 void DrawCross(long x, long y);
202 void SetFont(int fontcode);
203 void SetColour(int colourcode);
[5627cbb]204 void WriteString(const wxString & s);
[79c239e]205 void DrawEllipse(long x, long y, long r, long R);
206 void SolidRectangle(long x, long y, long w, long h);
207 int Pre();
208 void NewPage(int pg, int pagesX, int pagesY);
[ee05463]209 void PlotLR(const vector<XSect> & centreline);
210 void PlotUD(const vector<XSect> & centreline);
[a72ed95]211 void Init();
[79c239e]212 public:
[5a36f76]213 svxPrintout(MainFrm *mainfrm, layout *l, wxPageSetupDialogData *data, const wxString & title);
[79c239e]214 bool OnPrintPage(int pageNum);
[13da582]215 void GetPageInfo(int *minPage, int *maxPage,
216 int *pageFrom, int *pageTo);
217 bool HasPage(int pageNum);
[79c239e]218 void OnBeginPrinting();
219 void OnEndPrinting();
220};
221
222BEGIN_EVENT_TABLE(svxPrintDlg, wxDialog)
[583c17d]223 EVT_CHOICE(svx_FORMAT, svxPrintDlg::OnChange)
[79c239e]224 EVT_TEXT(svx_SCALE, svxPrintDlg::OnChange)
225 EVT_COMBOBOX(svx_SCALE, svxPrintDlg::OnChange)
226 EVT_SPINCTRL(svx_BEARING, svxPrintDlg::OnChangeSpin)
227 EVT_SPINCTRL(svx_TILT, svxPrintDlg::OnChangeSpin)
[de8488a6]228 EVT_BUTTON(wxID_PRINT, svxPrintDlg::OnPrint)
[5940815]229 EVT_BUTTON(svx_EXPORT, svxPrintDlg::OnExport)
[4ed8154]230 EVT_BUTTON(wxID_CANCEL, svxPrintDlg::OnCancel)
[cca2ce1]231#ifdef AVEN_PRINT_PREVIEW
[de8488a6]232 EVT_BUTTON(wxID_PREVIEW, svxPrintDlg::OnPreview)
[cca2ce1]233#endif
[79c239e]234 EVT_BUTTON(svx_PLAN, svxPrintDlg::OnPlan)
235 EVT_BUTTON(svx_ELEV, svxPrintDlg::OnElevation)
[102ba1d]236 EVT_UPDATE_UI(svx_PLAN, svxPrintDlg::OnPlanUpdate)
237 EVT_UPDATE_UI(svx_ELEV, svxPrintDlg::OnElevationUpdate)
[6b2113d]238 EVT_CHECKBOX(svx_LEGS, svxPrintDlg::OnChange)
239 EVT_CHECKBOX(svx_STATIONS, svxPrintDlg::OnChange)
240 EVT_CHECKBOX(svx_NAMES, svxPrintDlg::OnChange)
241 EVT_CHECKBOX(svx_SURFACE, svxPrintDlg::OnChange)
[7b55ac2]242 EVT_CHECKBOX(svx_ENTS, svxPrintDlg::OnChange)
243 EVT_CHECKBOX(svx_FIXES, svxPrintDlg::OnChange)
244 EVT_CHECKBOX(svx_EXPORTS, svxPrintDlg::OnChange)
[79c239e]245END_EVENT_TABLE()
246
[4c46260]247static wxString scales[] = {
[5627cbb]248 wxT(""),
249 wxT("25"),
250 wxT("50"),
251 wxT("100"),
252 wxT("250"),
253 wxT("500"),
254 wxT("1000"),
255 wxT("2500"),
256 wxT("5000"),
257 wxT("10000"),
258 wxT("25000"),
259 wxT("50000"),
260 wxT("100000")
[79c239e]261};
262
[583c17d]263static wxString formats[] = {
264 wxT("DXF"),
265 wxT("EPS"),
266 wxT("GPX"),
267 wxT("HPGL"),
[1fe107a]268 wxT("JSON"),
[1534ed9]269 wxT("KML"),
[583c17d]270 wxT("Plot"),
[9fc1cac]271 wxT("Skencil"),
[583c17d]272 wxT("SVG")
273};
274
[9b5a5fd]275#if 0
276static wxString projs[] = {
277 /* CUCC Austria: */
278 wxT("+proj=tmerc +lat_0=0 +lon_0=13d20 +k=1 +x_0=0 +y_0=-5200000 +ellps=bessel +towgs84=577.326,90.129,463.919,5.137,1.474,5.297,2.4232"),
279 /* British grid SD (Yorkshire): */
280 wxT("+proj=tmerc +lat_0=49d +lon_0=-2d +k=0.999601 +x_0=100000 +y_0=-500000 +ellps=airy +towgs84=375,-111,431,0,0,0,0"),
281 /* British full grid reference: */
282 wxT("+proj=tmerc +lat_0=49d +lon_0=-2d +k=0.999601 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=375,-111,431,0,0,0,0")
283};
284#endif
285
[583c17d]286static unsigned format_info[] = {
[bc1fac5]287 LABELS|LEGS|SURF|STNS|PASG|XSECT|WALLS|MARKER_SIZE|TEXT_HEIGHT|GRID|FULL_COORDS,
[583c17d]288 LABELS|LEGS|SURF|STNS,
[6d3938b]289 LABELS|LEGS|SURF|ENTS|FIXES|EXPORTS|PROJ|EXPORT_3D,
[bc1fac5]290 LABELS|LEGS|SURF|STNS|CENTRED,
[1fe107a]291 LEGS|CENTRED|EXPORT_3D,
[1534ed9]292 LABELS|ENTS|FIXES|EXPORTS|PROJ|EXPORT_3D,
[583c17d]293 LABELS|LEGS|SURF,
[7b55ac2]294 LABELS|LEGS|SURF|STNS|MARKER_SIZE|GRID|SCALE,
295 LABELS|LEGS|SURF|STNS|PASG|XSECT|WALLS|MARKER_SIZE|TEXT_HEIGHT|SCALE
[583c17d]296};
297
298static const char * extension[] = {
299 ".dxf",
300 ".eps",
301 ".gpx",
302 ".hpgl",
[1fe107a]303 ".json",
[1534ed9]304 ".kml",
[583c17d]305 ".plt",
306 ".sk",
307 ".svg"
308};
309
310static int msg_filetype[] = {
311 /*DXF files*/411,
312 /*EPS files*/412,
313 /*GPX files*/413,
[0b8c321]314 /* TRANSLATORS: Here "plotter" refers to a machine which draws a printout
315 * on a (usually large) sheet of paper using a pen mounted in a motorised
316 * mechanism. */
[583c17d]317 /*HPGL for plotters*/414,
[1fe107a]318 /*JSON files*/445,
[1534ed9]319 /*KML files*/444,
[0b8c321]320 /* TRANSLATORS: "Compass" and "Carto" are the names of software packages,
321 * so should not be translated:
322 * http://www.fountainware.com/compass/
323 * http://www.psc-cavers.org/carto/ */
[583c17d]324 /*Compass PLT for use with Carto*/415,
[0b8c321]325 /* TRANSLATORS: "Skencil" is the name of a software package, so should not be
326 * translated: http://www.skencil.org/ */
[9fc1cac]327 /*Skencil files*/416,
[583c17d]328 /*SVG files*/417
329};
330
[79c239e]331// there are three jobs to do here...
332// User <-> wx - this should possibly be done in a separate file
[ce403f1]333svxPrintDlg::svxPrintDlg(MainFrm* mainfrm_, const wxString & filename,
[6d3938b]334 const wxString & title, const wxString & cs_proj,
[f10cf8f]335 const wxString & datestamp, time_t datestamp_numeric,
[79c239e]336 double angle, double tilt_angle,
[5940815]337 bool labels, bool crosses, bool legs, bool surf,
[fdea415]338 bool tubes, bool ents, bool fixes, bool exports,
[4ed8154]339 bool printing, bool close_after_)
[736f7df]340 : wxDialog(mainfrm_, -1, wxString(printing ?
341 /* TRANSLATORS: Title of the print
342 * dialog */
343 wmsg(/*Print*/399) :
344 /* TRANSLATORS: Title of the export
345 * dialog */
346 wmsg(/*Export*/383))),
[ea69247]347 m_layout(printing ? wxGetApp().GetPageSetupDialogData() : NULL),
[4ed8154]348 m_File(filename), mainfrm(mainfrm_), close_after(close_after_)
[79c239e]349{
[5940815]350 m_scale = NULL;
351 m_printSize = NULL;
352 m_bearing = NULL;
353 m_tilt = NULL;
[583c17d]354 m_format = NULL;
[d713e5d]355 int show_mask = 0;
356 if (labels)
357 show_mask |= LABELS;
358 if (crosses)
359 show_mask |= STNS;
360 if (legs)
361 show_mask |= LEGS;
362 if (surf)
363 show_mask |= SURF;
[fdea415]364 if (tubes)
[5624403]365 show_mask |= XSECT|WALLS|PASG;
[fdea415]366 if (ents)
367 show_mask |= ENTS;
368 if (fixes)
369 show_mask |= FIXES;
370 if (exports)
371 show_mask |= EXPORTS;
[d713e5d]372 m_layout.show_mask = show_mask;
[5627cbb]373 m_layout.datestamp = datestamp;
[f10cf8f]374 m_layout.datestamp_numeric = datestamp_numeric;
[4a66219]375 m_layout.rot = angle;
[5627cbb]376 m_layout.title = title;
[6d3938b]377 m_layout.cs_proj = cs_proj;
[eef68f9]378 if (mainfrm->IsExtendedElevation()) {
[79c239e]379 m_layout.view = layout::EXTELEV;
[4a66219]380 if (m_layout.rot != 0.0 && m_layout.rot != 180.0) m_layout.rot = 0;
[79c239e]381 m_layout.tilt = 0;
382 } else {
[4a66219]383 m_layout.tilt = tilt_angle;
384 if (m_layout.tilt == -90.0) {
[79c239e]385 m_layout.view = layout::PLAN;
[4a66219]386 } else if (m_layout.tilt == 0.0) {
[79c239e]387 m_layout.view = layout::ELEV;
388 } else {
389 m_layout.view = layout::TILT;
390 }
391 }
392
393 /* setup our print dialog*/
394 wxBoxSizer* v1 = new wxBoxSizer(wxVERTICAL);
395 wxBoxSizer* h1 = new wxBoxSizer(wxHORIZONTAL); // holds controls
[736f7df]396 /* TRANSLATORS: Used as a label for the surrounding box for the "Bearing"
397 * and "Tilt angle" fields, and the "Plan view" and "Elevation" buttons in
398 * the "what to print/export" dialog. */
[7b55ac2]399 m_viewbox = new wxStaticBoxSizer(new wxStaticBox(this, -1, wmsg(/*View*/283)), wxVERTICAL);
[736f7df]400 /* TRANSLATORS: Used as a label for the surrounding box for the "survey
401 * legs" "stations" "names" etc checkboxes in the "what to print" dialog.
402 * "Elements" isn’t a good name for this but nothing better has yet come to
403 * mind! */
[5627cbb]404 wxBoxSizer* v3 = new wxStaticBoxSizer(new wxStaticBox(this, -1, wmsg(/*Elements*/256)), wxVERTICAL);
[9b5a5fd]405 wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
406 wxBoxSizer* h3 = new wxBoxSizer(wxHORIZONTAL); // holds buttons
[79c239e]407
[583c17d]408 if (!printing) {
409 wxStaticText* label;
410 label = new wxStaticText(this, -1, wxString(wmsg(/*Export format*/410)));
[9feb252]411 const size_t n_formats = sizeof(formats) / sizeof(formats[0]);
412 m_format = new wxChoice(this, svx_FORMAT,
413 wxDefaultPosition, wxDefaultSize,
414 n_formats, formats);
[a322a09]415 unsigned current_format = 0;
[3972b26]416 wxConfigBase * cfg = wxConfigBase::Get();
417 wxString s;
418 if (cfg->Read(wxT("export_format"), &s, wxString())) {
[9feb252]419 for (unsigned i = 0; i != n_formats; ++i) {
[3972b26]420 if (s == formats[i]) {
[a322a09]421 current_format = i;
[3972b26]422 break;
423 }
424 }
425 }
[a322a09]426 m_format->SetSelection(current_format);
[583c17d]427 wxBoxSizer* formatbox = new wxBoxSizer(wxHORIZONTAL);
428 formatbox->Add(label, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
429 formatbox->Add(m_format, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
430
431 v1->Add(formatbox, 0, wxALIGN_LEFT|wxALL, 0);
432 }
[5940815]433
[7b55ac2]434 wxStaticText* label;
435 label = new wxStaticText(this, -1, wxString(wmsg(/*Scale*/154)) + wxT(" 1:"));
436 if (scales[0].empty()) {
437 if (printing) {
[736f7df]438 /* TRANSLATORS: used in the scale drop down selector in the print
439 * dialog the implicit meaning is "choose a suitable scale to fit
440 * the plot on a single page", but we need something shorter */
[7b55ac2]441 scales[0].assign(wmsg(/*One page*/258));
442 } else {
443 scales[0].assign(wxT("1000"));
444 }
445 }
446 m_scale = new wxComboBox(this, svx_SCALE, scales[0], wxDefaultPosition,
447 wxDefaultSize, sizeof(scales) / sizeof(scales[0]),
448 scales);
449 m_scalebox = new wxBoxSizer(wxHORIZONTAL);
450 m_scalebox->Add(label, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
451 m_scalebox->Add(m_scale, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
452
453 m_viewbox->Add(m_scalebox, 0, wxALIGN_LEFT|wxALL, 0);
[5940815]454
[7b55ac2]455 if (printing) {
[5940815]456 // Make the dummy string wider than any sane value and use that to
457 // fix the width of the control so the sizers allow space for bigger
458 // page layouts.
[5627cbb]459 m_printSize = new wxStaticText(this, -1, wxString::Format(wmsg(/*%d pages (%dx%d)*/257), 9604, 98, 98));
[7b55ac2]460 m_viewbox->Add(m_printSize, 0, wxALIGN_LEFT|wxALL, 5);
[79c239e]461 }
462
[bc1fac5]463 /* FIXME:
[9b5a5fd]464 * svx_GRID, // double - spacing, default: 100m
465 * svx_TEXT_HEIGHT, // default 0.6
466 * svx_MARKER_SIZE // default 0.8
467 */
[7b55ac2]468
[79c239e]469 if (m_layout.view != layout::EXTELEV) {
[eef68f9]470 wxFlexGridSizer* anglebox = new wxFlexGridSizer(2);
471 wxStaticText * brg_label, * tilt_label;
[5627cbb]472 brg_label = new wxStaticText(this, -1, wmsg(/*Bearing*/259));
[eef68f9]473 anglebox->Add(brg_label, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 5);
[4a66219]474 m_bearing = new wxSpinCtrlDouble(this, svx_BEARING);
475 m_bearing->SetRange(0.0, 360.0);
476 m_bearing->SetDigits(ANGLE_DP);
[eef68f9]477 anglebox->Add(m_bearing, 0, wxALIGN_CENTER|wxALL, 5);
[736f7df]478 /* TRANSLATORS: Used in the print dialog: */
[5627cbb]479 tilt_label = new wxStaticText(this, -1, wmsg(/*Tilt angle*/263));
[eef68f9]480 anglebox->Add(tilt_label, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 5);
[4a66219]481 m_tilt = new wxSpinCtrlDouble(this, svx_TILT);
482 m_tilt->SetRange(-90.0, 90.0);
483 m_tilt->SetDigits(ANGLE_DP);
[eef68f9]484 anglebox->Add(m_tilt, 0, wxALIGN_CENTER|wxALL, 5);
485
[7b55ac2]486 m_viewbox->Add(anglebox, 0, wxALIGN_LEFT|wxALL, 0);
[eef68f9]487
[79c239e]488 wxBoxSizer * planelevsizer = new wxBoxSizer(wxHORIZONTAL);
[8a78ca1b]489 planelevsizer->Add(new wxButton(this, svx_PLAN, wmsg(/*P&lan view*/117)),
[79c239e]490 0, wxALIGN_CENTRE_VERTICAL|wxALL, 5);
[8a78ca1b]491 planelevsizer->Add(new wxButton(this, svx_ELEV, wmsg(/*&Elevation*/285)),
[79c239e]492 0, wxALIGN_CENTRE_VERTICAL|wxALL, 5);
493
[7b55ac2]494 m_viewbox->Add(planelevsizer, 0, wxALIGN_LEFT|wxALL, 5);
[79c239e]495 }
496
[736f7df]497 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
498 * "survey stations". */
[256c4c8]499 v3->Add(new wxCheckBox(this, svx_LEGS, wmsg(/*Underground Survey Legs*/262),
500 wxDefaultPosition, wxDefaultSize, 0,
501 BitValidator(&m_layout.show_mask, LEGS)),
502 0, wxALIGN_LEFT|wxALL, 2);
[736f7df]503 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
504 * "survey stations". */
[256c4c8]505 v3->Add(new wxCheckBox(this, svx_SURFACE, wmsg(/*Sur&face Survey Legs*/403),
506 wxDefaultPosition, wxDefaultSize, 0,
507 BitValidator(&m_layout.show_mask, SURF)),
508 0, wxALIGN_LEFT|wxALL, 2);
509 v3->Add(new wxCheckBox(this, svx_STATIONS, wmsg(/*Crosses*/261),
510 wxDefaultPosition, wxDefaultSize, 0,
511 BitValidator(&m_layout.show_mask, STNS)),
512 0, wxALIGN_LEFT|wxALL, 2);
513 v3->Add(new wxCheckBox(this, svx_NAMES, wmsg(/*Station Names*/260),
514 wxDefaultPosition, wxDefaultSize, 0,
515 BitValidator(&m_layout.show_mask, LABELS)),
516 0, wxALIGN_LEFT|wxALL, 2);
[7b55ac2]517 v3->Add(new wxCheckBox(this, svx_ENTS, wmsg(/*Entrances*/418),
518 wxDefaultPosition, wxDefaultSize, 0,
519 BitValidator(&m_layout.show_mask, ENTS)),
520 0, wxALIGN_LEFT|wxALL, 2);
521 v3->Add(new wxCheckBox(this, svx_FIXES, wmsg(/*Fixed Points*/419),
522 wxDefaultPosition, wxDefaultSize, 0,
523 BitValidator(&m_layout.show_mask, FIXES)),
524 0, wxALIGN_LEFT|wxALL, 2);
[da6367cd]525 v3->Add(new wxCheckBox(this, svx_EXPORTS, wmsg(/*Exported Stations*/420),
[7b55ac2]526 wxDefaultPosition, wxDefaultSize, 0,
527 BitValidator(&m_layout.show_mask, EXPORTS)),
528 0, wxALIGN_LEFT|wxALL, 2);
[256c4c8]529 v3->Add(new wxCheckBox(this, svx_XSECT, wmsg(/*Cross-sections*/393),
530 wxDefaultPosition, wxDefaultSize, 0,
531 BitValidator(&m_layout.show_mask, XSECT)),
532 0, wxALIGN_LEFT|wxALL, 2);
533 if (!printing) {
534 v3->Add(new wxCheckBox(this, svx_WALLS, wmsg(/*Walls*/394),
535 wxDefaultPosition, wxDefaultSize, 0,
536 BitValidator(&m_layout.show_mask, WALLS)),
537 0, wxALIGN_LEFT|wxALL, 2);
538 v3->Add(new wxCheckBox(this, svx_PASSAGES, wmsg(/*Passages*/395),
539 wxDefaultPosition, wxDefaultSize, 0,
540 BitValidator(&m_layout.show_mask, PASG)),
541 0, wxALIGN_LEFT|wxALL, 2);
[bc1fac5]542 v3->Add(new wxCheckBox(this, svx_CENTRED, wmsg(/*Origin in centre*/421),
543 wxDefaultPosition, wxDefaultSize, 0,
544 BitValidator(&m_layout.show_mask, CENTRED)),
545 0, wxALIGN_LEFT|wxALL, 2);
546 v3->Add(new wxCheckBox(this, svx_FULLCOORDS, wmsg(/*Full coordinates*/422),
547 wxDefaultPosition, wxDefaultSize, 0,
548 BitValidator(&m_layout.show_mask, FULL_COORDS)),
549 0, wxALIGN_LEFT|wxALL, 2);
[256c4c8]550 }
[5940815]551 if (printing) {
[736f7df]552 /* TRANSLATORS: used in the print dialog - controls drawing lines
553 * around each page */
[256c4c8]554 v3->Add(new wxCheckBox(this, svx_BORDERS, wmsg(/*Page Borders*/264),
555 wxDefaultPosition, wxDefaultSize, 0,
556 wxGenericValidator(&m_layout.Border)),
557 0, wxALIGN_LEFT|wxALL, 2);
[736f7df]558 /* TRANSLATORS: will be used in the print dialog - check this to print
559 * blank pages (otherwise they’ll be skipped to save paper) */
[5627cbb]560// m_blanks = new wxCheckBox(this, svx_BLANKS, wmsg(/*Blank Pages*/266));
[5940815]561// v3->Add(m_blanks, 0, wxALIGN_LEFT|wxALL, 2);
[736f7df]562 /* TRANSLATORS: As in the legend on a map. Used in the print dialog -
563 * controls drawing the box at the lower left with survey name, view
564 * angles, etc */
[08e858b]565 v3->Add(new wxCheckBox(this, svx_LEGEND, wmsg(/*Legend*/265),
[256c4c8]566 wxDefaultPosition, wxDefaultSize, 0,
567 wxGenericValidator(&m_layout.Legend)),
568 0, wxALIGN_LEFT|wxALL, 2);
[5940815]569 }
[ee05463]570
[79c239e]571 h1->Add(v3, 0, wxALIGN_LEFT|wxALL, 5);
[6d3938b]572 h1->Add(m_viewbox, 0, wxALIGN_LEFT|wxLEFT, 5);
[79c239e]573
[736f7df]574 /* TRANSLATORS: The PROJ library is used to do coordinate transformations
[6d3938b]575 * (https://trac.osgeo.org/proj/) - if the .3d file doesn't contain details
576 * of the coordinate projection in use, the user must specify it here for
577 * export formats which need to know it (e.g. GPX).
[736f7df]578 */
[6d3938b]579 h2->Add(new wxStaticText(this, svx_PROJ_LABEL, wmsg(/*Coordinate projection*/440)),
580 0, wxLEFT|wxALIGN_CENTRE_VERTICAL, 5);
581 long style = 0;
582 if (!m_layout.cs_proj.empty()) {
583 // If the input file specified the coordinate system, don't let the
584 // user mess with it.
585 style = wxTE_READONLY;
586 } else {
587#if 0 // FIXME: Is it a good idea to save this?
588 wxConfigBase * cfg = wxConfigBase::Get();
589 wxString input_projection;
590 cfg->Read(wxT("input_projection"), &input_projection);
591 if (!input_projection.empty())
592 proj_edit.SetValue(input_projection);
[9b5a5fd]593#endif
[6d3938b]594 }
595 wxTextCtrl * proj_edit = new wxTextCtrl(this, svx_PROJ, m_layout.cs_proj,
596 wxDefaultPosition, wxDefaultSize,
597 style);
598 h2->Add(proj_edit, 1, wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL, 5);
599 v1->Add(h2, 0, wxALIGN_LEFT|wxEXPAND, 5);
600
601 v1->Add(h1, 0, wxALIGN_LEFT|wxALL, 5);
[9b5a5fd]602
[583c17d]603 // When we enable/disable checkboxes in the export dialog, ideally we'd
604 // like the dialog to resize, but not sure how to achieve that, so we
605 // add a stretchable spacer here so at least the buttons stay in the
606 // lower right corner.
607 v1->AddStretchSpacer();
608
[79c239e]609 wxButton * but;
[73b3388]610 but = new wxButton(this, wxID_CANCEL);
[9b5a5fd]611 h3->Add(but, 0, wxALIGN_RIGHT|wxALL, 5);
[5940815]612 if (printing) {
[cca2ce1]613#ifdef AVEN_PRINT_PREVIEW
[de8488a6]614 but = new wxButton(this, wxID_PREVIEW);
[9b5a5fd]615 h3->Add(but, 0, wxALIGN_RIGHT|wxALL, 5);
[de8488a6]616 but = new wxButton(this, wxID_PRINT);
[b72f4b5]617#else
[ee7511a]618 but = new wxButton(this, wxID_PRINT, wmsg(/*&Print…*/400));
[b72f4b5]619#endif
[5940815]620 } else {
[736f7df]621 /* TRANSLATORS: The text on the action button in the "Export" settings
622 * dialog */
[ee7511a]623 but = new wxButton(this, svx_EXPORT, wmsg(/*&Export…*/230));
[5940815]624 }
[79c239e]625 but->SetDefault();
[9b5a5fd]626 h3->Add(but, 0, wxALIGN_RIGHT|wxALL, 5);
627 v1->Add(h3, 0, wxALIGN_RIGHT|wxALL, 5);
[ee05463]628
[79c239e]629 SetAutoLayout(true);
630 SetSizer(v1);
631 v1->SetSizeHints(this);
632
633 LayoutToUI();
[583c17d]634 SomethingChanged(0);
[79c239e]635}
636
[ee05463]637void
[79c239e]638svxPrintDlg::OnPrint(wxCommandEvent&) {
[583c17d]639 SomethingChanged(0);
[0056ee1]640 TransferDataFromWindow();
[e0ffc2c]641 wxPageSetupDialogData * psdd = wxGetApp().GetPageSetupDialogData();
642 wxPrintDialogData pd(psdd->GetPrintData());
[79c239e]643 wxPrinter pr(&pd);
[e0ffc2c]644 svxPrintout po(mainfrm, &m_layout, psdd, m_File);
[79c239e]645 if (pr.Print(this, &po, true)) {
646 // Close the print dialog if printing succeeded.
647 Destroy();
648 }
649}
650
[5940815]651void
652svxPrintDlg::OnExport(wxCommandEvent&) {
653 UIToLayout();
[54b7650]654 TransferDataFromWindow();
[583c17d]655 wxString leaf;
656 wxFileName::SplitPath(m_File, NULL, NULL, &leaf, NULL, wxPATH_NATIVE);
657 unsigned format_idx = ((wxChoice*)FindWindow(svx_FORMAT))->GetSelection();
658 leaf += wxString::FromUTF8(extension[format_idx]);
659
660 wxString filespec = wmsg(msg_filetype[format_idx]);
661 filespec += wxT("|*");
662 filespec += wxString::FromUTF8(extension[format_idx]);
663 filespec += wxT("|");
664 filespec += wmsg(/*All files*/208);
665 filespec += wxT("|");
666 filespec += wxFileSelectorDefaultWildcardStr;
667
[736f7df]668 /* TRANSLATORS: Title of file dialog to choose name and type of exported
669 * file. */
[583c17d]670 wxFileDialog dlg(this, wmsg(/*Export as:*/401), wxString(), leaf,
671 filespec, wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
[5940815]672 if (dlg.ShowModal() == wxID_OK) {
[6d3938b]673 wxString input_projection = ((wxTextCtrl*)FindWindow(svx_PROJ))->GetValue();
[7b55ac2]674 double grid = 100; // metres
675 double text_height = 0.6;
676 double marker_size = 0.8;
677
[6d3938b]678 try {
679 if (!Export(dlg.GetPath(), m_layout.title,
680 m_layout.datestamp, m_layout.datestamp_numeric, mainfrm,
681 m_layout.rot, m_layout.tilt, m_layout.show_mask,
682 export_format(format_idx), input_projection.mb_str(),
[18ff765]683 grid, text_height, marker_size, m_layout.Scale)) {
[6d3938b]684 wxString m = wxString::Format(wmsg(/*Couldn’t write file “%s”*/402).c_str(),
685 m_File.c_str());
686 wxGetApp().ReportError(m);
687 }
688 } catch (const wxString & m) {
[6e63fd3]689 wxGetApp().ReportError(m);
[5940815]690 }
691 }
692 Destroy();
693}
694
[cca2ce1]695#ifdef AVEN_PRINT_PREVIEW
[ee05463]696void
[79c239e]697svxPrintDlg::OnPreview(wxCommandEvent&) {
[583c17d]698 SomethingChanged(0);
[54b7650]699 TransferDataFromWindow();
[e0ffc2c]700 wxPageSetupDialogData * psdd = wxGetApp().GetPageSetupDialogData();
701 wxPrintDialogData pd(psdd->GetPrintData());
[79c239e]702 wxPrintPreview* pv;
[e0ffc2c]703 pv = new wxPrintPreview(new svxPrintout(mainfrm, &m_layout, psdd, m_File),
704 new svxPrintout(mainfrm, &m_layout, psdd, m_File),
[79c239e]705 &pd);
[736f7df]706 // TRANSLATORS: Title of the print preview dialog
[5627cbb]707 wxPreviewFrame *frame = new wxPreviewFrame(pv, mainfrm, wmsg(/*Print Preview*/398));
[79c239e]708 frame->Initialize();
709
710 // Size preview frame so that all of the controlbar and canvas can be seen
711 // if possible.
712 int w, h;
713 // GetBestSize gives us the width needed to show the whole controlbar.
714 frame->GetBestSize(&w, &h);
715#ifdef __WXMAC__
716 // wxMac opens the preview window at minimum size by default.
717 // 360x480 is apparently enough to show A4 portrait.
718 if (h < 480 || w < 360) {
719 if (h < 480) h = 480;
720 if (w < 360) w = 360;
721 }
722#else
723 if (h < w) {
724 // On wxGTK at least, GetBestSize() returns much too small a height.
725 h = w * 6 / 5;
726 }
727#endif
728 // Ensure that we don't make the window bigger than the screen.
729 // Use wxGetClientDisplayRect() so we don't cover the MS Windows
730 // task bar either.
731 wxRect disp = wxGetClientDisplayRect();
732 if (w > disp.GetWidth()) w = disp.GetWidth();
733 if (h > disp.GetHeight()) h = disp.GetHeight();
734 // Centre the window within the "ClientDisplayRect".
735 int x = disp.GetLeft() + (disp.GetWidth() - w) / 2;
736 int y = disp.GetTop() + (disp.GetHeight() - h) / 2;
737 frame->SetSize(x, y, w, h);
738
739 frame->Show();
740}
[cca2ce1]741#endif
[79c239e]742
[ee05463]743void
[79c239e]744svxPrintDlg::OnPlan(wxCommandEvent&) {
[4a66219]745 m_tilt->SetValue(-90.0);
[583c17d]746 SomethingChanged(svx_TILT);
[79c239e]747}
748
[ee05463]749void
[79c239e]750svxPrintDlg::OnElevation(wxCommandEvent&) {
[4a66219]751 m_tilt->SetValue(0.0);
[583c17d]752 SomethingChanged(svx_TILT);
[79c239e]753}
754
[102ba1d]755void
756svxPrintDlg::OnPlanUpdate(wxUpdateUIEvent& e) {
[4a66219]757 e.Enable(m_tilt->GetValue() != -90.0);
[102ba1d]758}
759
760void
761svxPrintDlg::OnElevationUpdate(wxUpdateUIEvent& e) {
[4a66219]762 e.Enable(m_tilt->GetValue() != 0.0);
[102ba1d]763}
764
[ee05463]765void
[583c17d]766svxPrintDlg::OnChangeSpin(wxSpinEvent& e) {
767 SomethingChanged(e.GetId());
[79c239e]768}
769
[ee05463]770void
[583c17d]771svxPrintDlg::OnChange(wxCommandEvent& e) {
772 SomethingChanged(e.GetId());
[79c239e]773}
774
[4ed8154]775void
776svxPrintDlg::OnCancel(wxCommandEvent&) {
777 if (close_after)
778 mainfrm->Close();
[d4885c3]779 Destroy();
[4ed8154]780}
781
[79c239e]782void
[583c17d]783svxPrintDlg::SomethingChanged(int control_id) {
[7b55ac2]784 if ((control_id == 0 || control_id == svx_FORMAT) && m_format) {
[583c17d]785 // Update the shown/hidden fields for the newly selected export filter.
[a322a09]786 int new_filter_idx = m_format->GetSelection();
787 if (new_filter_idx != wxNOT_FOUND) {
788 unsigned mask = format_info[new_filter_idx];
[9feb252]789 static const struct { int id; unsigned mask; } controls[] = {
790 { svx_LEGS, LEGS },
791 { svx_SURFACE, SURF },
792 { svx_STATIONS, STNS },
793 { svx_NAMES, LABELS },
794 { svx_XSECT, XSECT },
795 { svx_WALLS, WALLS },
796 { svx_PASSAGES, PASG },
797 { svx_ENTS, ENTS },
798 { svx_FIXES, FIXES },
799 { svx_EXPORTS, EXPORTS },
800 { svx_CENTRED, CENTRED },
801 { svx_FULLCOORDS, FULL_COORDS },
[6d3938b]802 { svx_PROJ_LABEL, PROJ },
[9feb252]803 { svx_PROJ, PROJ },
804 };
805 static unsigned n_controls = sizeof(controls) / sizeof(controls[0]);
806 for (unsigned i = 0; i != n_controls; ++i) {
807 wxWindow * control = FindWindow(controls[i].id);
808 if (control) control->Show(mask & controls[i].mask);
809 }
[7b55ac2]810 m_scalebox->Show(bool(mask & SCALE));
811 m_viewbox->Show(!bool(mask & EXPORT_3D));
[a322a09]812 GetSizer()->Layout();
813 if (control_id == svx_FORMAT) {
814 wxConfigBase * cfg = wxConfigBase::Get();
815 cfg->Write(wxT("export_format"), formats[new_filter_idx]);
816 }
817 }
[583c17d]818 }
819
[79c239e]820 UIToLayout();
[18ff765]821
822 if (m_printSize || m_scale) {
823 // Update the bounding box.
824 RecalcBounds();
825
826 if (m_scale) {
827 (m_scale->GetValue()).ToDouble(&(m_layout.Scale));
828 if (m_layout.Scale == 0.0) {
829 m_layout.pick_scale(1, 1);
830 }
[6ca9f08]831 }
832 }
833
[18ff765]834 if (m_printSize && m_layout.xMax >= m_layout.xMin) {
[79c239e]835 m_layout.pages_required();
[5627cbb]836 m_printSize->SetLabel(wxString::Format(wmsg(/*%d pages (%dx%d)*/257), m_layout.pages, m_layout.pagesX, m_layout.pagesY));
[79c239e]837 }
838}
839
[ee05463]840void
[79c239e]841svxPrintDlg::LayoutToUI(){
842// m_blanks->SetValue(m_layout.SkipBlank);
[eef68f9]843 if (m_layout.view != layout::EXTELEV) {
844 m_tilt->SetValue(m_layout.tilt);
845 m_bearing->SetValue(m_layout.rot);
[79c239e]846 }
847
848 // Do this last as it causes an OnChange message which calls UIToLayout
[5940815]849 if (m_scale) {
850 if (m_layout.Scale != 0) {
851 wxString temp;
852 temp << m_layout.Scale;
853 m_scale->SetValue(temp);
854 } else {
[5627cbb]855 if (scales[0].empty()) scales[0].assign(wmsg(/*One page*/258));
[5940815]856 m_scale->SetValue(scales[0]);
857 }
[79c239e]858 }
859}
860
[ee05463]861void
[79c239e]862svxPrintDlg::UIToLayout(){
863// m_layout.SkipBlank = m_blanks->IsChecked();
864
[de9aa88]865 if (m_layout.view != layout::EXTELEV && m_tilt) {
[79c239e]866 m_layout.tilt = m_tilt->GetValue();
[4a66219]867 if (m_layout.tilt == -90.0) {
[79c239e]868 m_layout.view = layout::PLAN;
[4a66219]869 } else if (m_layout.tilt == 0.0) {
[79c239e]870 m_layout.view = layout::ELEV;
871 } else {
872 m_layout.view = layout::TILT;
873 }
[256c4c8]874
875 bool enable_passage_opts = (m_layout.view != layout::TILT);
876 wxWindow * win;
877 win = FindWindow(svx_XSECT);
878 if (win) win->Enable(enable_passage_opts);
879 win = FindWindow(svx_WALLS);
880 if (win) win->Enable(enable_passage_opts);
881 win = FindWindow(svx_PASSAGES);
882 if (win) win->Enable(enable_passage_opts);
883
[79c239e]884 m_layout.rot = m_bearing->GetValue();
885 }
886}
887
888void
889svxPrintDlg::RecalcBounds()
890{
891 m_layout.yMax = m_layout.xMax = -DBL_MAX;
892 m_layout.yMin = m_layout.xMin = DBL_MAX;
893
[5940815]894 double SIN = sin(rad(m_layout.rot));
895 double COS = cos(rad(m_layout.rot));
896 double SINT = sin(rad(m_layout.tilt));
897 double COST = cos(rad(m_layout.tilt));
[79c239e]898
[d713e5d]899 if (m_layout.show_mask & LEGS) {
[c61aa79]900 list<traverse>::const_iterator trav = mainfrm->traverses_begin();
901 list<traverse>::const_iterator tend = mainfrm->traverses_end();
[ce403f1]902 for ( ; trav != tend; ++trav) {
[d4650b3]903 vector<PointInfo>::const_iterator pos = trav->begin();
904 vector<PointInfo>::const_iterator end = trav->end();
[ce403f1]905 for ( ; pos != end; ++pos) {
906 double x = pos->GetX();
907 double y = pos->GetY();
908 double z = pos->GetZ();
909 double X = x * COS - y * SIN;
910 if (X > m_layout.xMax) m_layout.xMax = X;
911 if (X < m_layout.xMin) m_layout.xMin = X;
[7a57dc7]912 double Y = z * COST - (x * SIN + y * COS) * SINT;
[ce403f1]913 if (Y > m_layout.yMax) m_layout.yMax = Y;
914 if (Y < m_layout.yMin) m_layout.yMin = Y;
915 }
916 }
917 }
[d713e5d]918 if (m_layout.show_mask & SURF) {
[c61aa79]919 list<traverse>::const_iterator trav = mainfrm->surface_traverses_begin();
920 list<traverse>::const_iterator tend = mainfrm->surface_traverses_end();
[ce403f1]921 for ( ; trav != tend; ++trav) {
[d4650b3]922 vector<PointInfo>::const_iterator pos = trav->begin();
923 vector<PointInfo>::const_iterator end = trav->end();
[ce403f1]924 for ( ; pos != end; ++pos) {
925 double x = pos->GetX();
926 double y = pos->GetY();
927 double z = pos->GetZ();
928 double X = x * COS - y * SIN;
929 if (X > m_layout.xMax) m_layout.xMax = X;
930 if (X < m_layout.xMin) m_layout.xMin = X;
[7a57dc7]931 double Y = z * COST - (x * SIN + y * COS) * SINT;
[ce403f1]932 if (Y > m_layout.yMax) m_layout.yMax = Y;
933 if (Y < m_layout.yMin) m_layout.yMin = Y;
[79c239e]934 }
935 }
936 }
[d713e5d]937 if (m_layout.show_mask & (LABELS|STNS)) {
[ce403f1]938 list<LabelInfo*>::const_iterator label = mainfrm->GetLabels();
939 while (label != mainfrm->GetLabelsEnd()) {
[79c239e]940 double x = (*label)->GetX();
941 double y = (*label)->GetY();
942 double z = (*label)->GetZ();
[d713e5d]943 if ((m_layout.show_mask & SURF) || (*label)->IsUnderground()) {
[79c239e]944 double X = x * COS - y * SIN;
945 if (X > m_layout.xMax) m_layout.xMax = X;
946 if (X < m_layout.xMin) m_layout.xMin = X;
[7a57dc7]947 double Y = z * COST - (x * SIN + y * COS) * SINT;
[79c239e]948 if (Y > m_layout.yMax) m_layout.yMax = Y;
949 if (Y < m_layout.yMin) m_layout.yMin = Y;
950 }
951 ++label;
952 }
953 }
954}
955
956static int xpPageWidth, ypPageDepth;
957static long MarginLeft, MarginRight, MarginTop, MarginBottom;
958static long x_offset, y_offset;
959static wxFont *font_labels, *font_default;
960static int fontsize, fontsize_labels;
961
962/* FIXME: allow the font to be set */
963
964static const char *fontname = "Arial", *fontname_labels = "Arial";
965
966// wx <-> prcore (calls to print_page etc...)
[5627cbb]967svxPrintout::svxPrintout(MainFrm *mainfrm_, layout *l,
968 wxPageSetupDialogData *data, const wxString & title)
[79c239e]969 : wxPrintout(title)
970{
[ce403f1]971 mainfrm = mainfrm_;
[79c239e]972 m_layout = l;
973 m_data = data;
974}
975
976void
977svxPrintout::draw_info_box()
978{
979 layout *l = m_layout;
[995cf6a]980 int boxwidth = 70;
[79c239e]981 int boxheight = 30;
982
983 SetColour(PR_COLOUR_FRAME);
984
[995cf6a]985 int div = boxwidth;
[79c239e]986 if (l->view != layout::EXTELEV) {
[995cf6a]987 boxwidth += boxheight;
988 MOVEMM(div, boxheight);
989 DRAWMM(div, 0);
990 MOVEMM(0, 30); DRAWMM(div, 30);
[79c239e]991 }
992
993 MOVEMM(0, boxheight);
994 DRAWMM(boxwidth, boxheight);
995 DRAWMM(boxwidth, 0);
996 if (!l->Border) {
997 DRAWMM(0, 0);
998 DRAWMM(0, boxheight);
999 }
1000
[995cf6a]1001 MOVEMM(0, 20); DRAWMM(div, 20);
1002 MOVEMM(0, 10); DRAWMM(div, 10);
[79c239e]1003
1004 switch (l->view) {
1005 case layout::PLAN: {
1006 long ax, ay, bx, by, cx, cy, dx, dy;
1007
[995cf6a]1008 long xc = boxwidth - boxheight / 2;
1009 long yc = boxheight / 2;
[725cd74d]1010 const double RADIUS = boxheight / 3;
[995cf6a]1011 DrawEllipse(long(xc * l->scX), long(yc * l->scY),
1012 long(RADIUS * l->scX), long(RADIUS * l->scY));
1013
1014 ax = (long)((xc - (RADIUS - 1) * sin(rad(000.0 + l->rot))) * l->scX);
1015 ay = (long)((yc + (RADIUS - 1) * cos(rad(000.0 + l->rot))) * l->scY);
1016 bx = (long)((xc - RADIUS * 0.5 * sin(rad(180.0 + l->rot))) * l->scX);
1017 by = (long)((yc + RADIUS * 0.5 * cos(rad(180.0 + l->rot))) * l->scY);
1018 cx = (long)((xc - (RADIUS - 1) * sin(rad(160.0 + l->rot))) * l->scX);
1019 cy = (long)((yc + (RADIUS - 1) * cos(rad(160.0 + l->rot))) * l->scY);
1020 dx = (long)((xc - (RADIUS - 1) * sin(rad(200.0 + l->rot))) * l->scX);
1021 dy = (long)((yc + (RADIUS - 1) * cos(rad(200.0 + l->rot))) * l->scY);
[79c239e]1022
1023 MoveTo(ax, ay);
1024 DrawTo(bx, by);
1025 DrawTo(cx, cy);
1026 DrawTo(ax, ay);
1027 DrawTo(dx, dy);
1028 DrawTo(bx, by);
1029
1030 SetColour(PR_COLOUR_TEXT);
[725cd74d]1031 MOVEMM(div + 0.5, boxheight - 5.5);
[5627cbb]1032 WriteString(wmsg(/*North*/115));
[79c239e]1033
[4a66219]1034 wxString angle = format_angle(ANGLE_FMT, l->rot);
[995cf6a]1035 wxString s;
[736f7df]1036 /* TRANSLATORS: This is used on printouts of plans, with %s replaced by
1037 * something like "123°". The bearing is up the page. */
[995cf6a]1038 s.Printf(wmsg(/*Plan view, %s up page*/168), angle.c_str());
1039 MOVEMM(2, 12); WriteString(s);
[79c239e]1040 break;
1041 }
[995cf6a]1042 case layout::ELEV: case layout::TILT: {
1043 const int L = div + 2;
1044 const int R = boxwidth - 2;
[725cd74d]1045 const int H = boxheight / 2;
[995cf6a]1046 MOVEMM(L, H); DRAWMM(L + 5, H - 3); DRAWMM(L + 3, H); DRAWMM(L + 5, H + 3);
[79c239e]1047
[995cf6a]1048 DRAWMM(L, H); DRAWMM(R, H);
[79c239e]1049
[995cf6a]1050 DRAWMM(R - 5, H + 3); DRAWMM(R - 3, H); DRAWMM(R - 5, H - 3); DRAWMM(R, H);
[79c239e]1051
[995cf6a]1052 MOVEMM((L + R) / 2, H - 2); DRAWMM((L + R) / 2, H + 2);
[79c239e]1053
1054 SetColour(PR_COLOUR_TEXT);
[725cd74d]1055 MOVEMM(div + 2, boxheight - 8);
[736f7df]1056 /* TRANSLATORS: "Elevation on" 020 <-> 200 degrees */
[5627cbb]1057 WriteString(wmsg(/*Elevation on*/116));
1058
[725cd74d]1059 MOVEMM(L, 2);
[4a66219]1060 WriteString(format_angle(ANGLE_FMT, fmod(l->rot + 270.0, 360.0)));
[725cd74d]1061 MOVEMM(R - 10, 2);
[4a66219]1062 WriteString(format_angle(ANGLE_FMT, fmod(l->rot + 90.0, 360.0)));
[995cf6a]1063
[4a66219]1064 wxString angle = format_angle(ANGLE_FMT, l->rot);
[995cf6a]1065 wxString s;
1066 if (l->view == layout::ELEV) {
[736f7df]1067 /* TRANSLATORS: This is used on printouts of elevations, with %s
1068 * replaced by something like "123°". The bearing is the direction
1069 * we’re looking. */
[995cf6a]1070 s.Printf(wmsg(/*Elevation facing %s*/169), angle.c_str());
1071 } else {
[4a66219]1072 wxString a2 = format_angle(ANGLE2_FMT, l->tilt);
[736f7df]1073 /* TRANSLATORS: This is used on printouts of tilted elevations, with
1074 * the first %s replaced by something like "123°", and the second by
1075 * something like "-45°". The bearing is the direction we’re
1076 * looking. */
[995cf6a]1077 s.Printf(wmsg(/*Elevation facing %s, tilted %s*/284), angle.c_str(), a2.c_str());
1078 }
1079 MOVEMM(2, 12); WriteString(s);
[79c239e]1080 break;
[995cf6a]1081 }
[79c239e]1082 case layout::EXTELEV:
1083 SetColour(PR_COLOUR_TEXT);
[f6dff8b]1084 MOVEMM(2, 12);
[736f7df]1085 /* TRANSLATORS: This is used on printouts of extended elevations. */
[5627cbb]1086 WriteString(wmsg(/*Extended elevation*/191));
[79c239e]1087 break;
1088 }
1089
[f6dff8b]1090 MOVEMM(2, boxheight - 8); WriteString(l->title);
[79c239e]1091
[995cf6a]1092 MOVEMM(2, 2);
1093 // FIXME: "Original Scale" better?
[5627cbb]1094 WriteString(wxString::Format(wmsg(/*Scale*/154) + wxT(" 1:%.0f"),
1095 l->Scale));
[79c239e]1096
1097 /* This used to be a copyright line, but it was occasionally
1098 * mis-interpreted as us claiming copyright on the survey, so let's
1099 * give the website URL instead */
1100 MOVEMM(boxwidth + 2, 2);
[1671258]1101 WriteString(wxT("Survex "VERSION" - http://survex.com/"));
[79c239e]1102
1103 draw_scale_bar(boxwidth + 10.0, 17.0, l->PaperWidth - boxwidth - 18.0);
1104}
1105
1106/* Draw fancy scale bar with bottom left at (x,y) (both in mm) and at most */
1107/* MaxLength mm long. The scaling in use is 1:scale */
1108void
1109svxPrintout::draw_scale_bar(double x, double y, double MaxLength)
1110{
1111 double StepEst, d;
[5627cbb]1112 int E, Step, n, c;
1113 wxString buf;
[79c239e]1114 /* Limit scalebar to 20cm to stop people with A0 plotters complaining */
1115 if (MaxLength > 200.0) MaxLength = 200.0;
1116
1117#define dmin 10.0 /* each division >= dmin mm long */
1118#define StepMax 5 /* number in steps of at most StepMax (x 10^N) */
1119#define epsilon (1e-4) /* fudge factor to prevent rounding problems */
1120
1121 E = (int)ceil(log10((dmin * 0.001 * m_layout->Scale) / StepMax));
1122 StepEst = pow(10.0, -(double)E) * (dmin * 0.001) * m_layout->Scale - epsilon;
1123
1124 /* Force labelling to be in multiples of 1, 2, or 5 */
1125 Step = (StepEst <= 1.0 ? 1 : (StepEst <= 2.0 ? 2 : 5));
1126
1127 /* Work out actual length of each scale bar division */
1128 d = Step * pow(10.0, (double)E) / m_layout->Scale * 1000.0;
1129
[ccb83b7]1130 /* FIXME: Non-metric units here... */
[79c239e]1131 /* Choose appropriate units, s.t. if possible E is >=0 and minimized */
[ccb83b7]1132 int units;
1133 if (E >= 3) {
1134 E -= 3;
1135 units = /*km*/423;
1136 } else if (E >= 0) {
1137 units = /*m*/424;
1138 } else {
1139 E += 2;
1140 units = /*cm*/425;
1141 }
[79c239e]1142
[5627cbb]1143 buf = wmsg(/*Scale*/154);
[79c239e]1144
1145 /* Add units used - eg. "Scale (10m)" */
[ccb83b7]1146 double pow10_E = pow(10.0, (double)E);
1147 if (E >= 0) {
1148 buf += wxString::Format(wxT(" (%.f%s)"), pow10_E, wmsg(units).c_str());
1149 } else {
1150 int sf = -(int)floor(E);
1151 buf += wxString::Format(wxT(" (%.*f%s)"), sf, pow10_E, wmsg(units).c_str());
1152 }
[79c239e]1153 SetColour(PR_COLOUR_TEXT);
1154 MOVEMM(x, y + 4); WriteString(buf);
1155
1156 /* Work out how many divisions there will be */
1157 n = (int)(MaxLength / d);
1158
1159 SetColour(PR_COLOUR_FRAME);
1160
1161 long Y = long(y * m_layout->scY);
1162 long Y2 = long((y + 3) * m_layout->scY);
1163 long X = long(x * m_layout->scX);
1164 long X2 = long((x + n * d) * m_layout->scX);
1165
1166 /* Draw top of scale bar */
1167 MoveTo(X2, Y2);
1168 DrawTo(X, Y2);
1169#if 0
1170 DrawTo(X2, Y);
1171 DrawTo(X, Y);
1172 MOVEMM(x + n * d, y); DRAWMM(x, y);
1173#endif
1174 /* Draw divisions and label them */
1175 for (c = 0; c <= n; c++) {
1176 SetColour(PR_COLOUR_FRAME);
1177 X = long((x + c * d) * m_layout->scX);
1178 MoveTo(X, Y);
1179 DrawTo(X, Y2);
1180#if 0 // Don't waste toner!
1181 /* Draw a "zebra crossing" scale bar. */
1182 if (c < n && (c & 1) == 0) {
1183 X2 = long((x + (c + 1) * d) * m_layout->scX);
1184 SolidRectangle(X, Y, X2 - X, Y2 - Y);
1185 }
1186#endif
[5627cbb]1187 buf.Printf(wxT("%d"), c * Step);
[79c239e]1188 SetColour(PR_COLOUR_TEXT);
[30f1caa]1189 MOVEMM(x + c * d - buf.length(), y - 5);
[79c239e]1190 WriteString(buf);
1191 }
1192}
1193
1194#if 0
[ee05463]1195void
[79c239e]1196make_calibration(layout *l) {
1197 img_point pt = { 0.0, 0.0, 0.0 };
1198 l->xMax = l->yMax = 0.1;
1199 l->xMin = l->yMin = 0;
1200
1201 stack(l,img_MOVE, NULL, &pt);
1202 pt.x = 0.1;
1203 stack(l,img_LINE, NULL, &pt);
1204 pt.y = 0.1;
1205 stack(l,img_LINE, NULL, &pt);
1206 pt.x = 0.0;
1207 stack(l,img_LINE, NULL, &pt);
1208 pt.y = 0.0;
1209 stack(l,img_LINE, NULL, &pt);
1210 pt.x = 0.05;
1211 pt.y = 0.001;
1212 stack(l,img_LABEL, "10cm", &pt);
1213 pt.x = 0.001;
1214 pt.y = 0.05;
1215 stack(l,img_LABEL, "10cm", &pt);
1216 l->Scale = 1.0;
1217}
1218#endif
1219
1220int
1221svxPrintout::next_page(int *pstate, char **q, int pageLim)
1222{
1223 char *p;
1224 int page;
1225 int c;
1226 p = *q;
1227 if (*pstate > 0) {
1228 /* doing a range */
1229 (*pstate)++;
1230 SVX_ASSERT(*p == '-');
1231 p++;
1232 while (isspace((unsigned char)*p)) p++;
1233 if (sscanf(p, "%u%n", &page, &c) > 0) {
1234 p += c;
1235 } else {
1236 page = pageLim;
1237 }
1238 if (*pstate > page) goto err;
1239 if (*pstate < page) return *pstate;
1240 *q = p;
1241 *pstate = 0;
1242 return page;
1243 }
1244
1245 while (isspace((unsigned char)*p) || *p == ',') p++;
1246
1247 if (!*p) return 0; /* done */
1248
1249 if (*p == '-') {
1250 *q = p;
1251 *pstate = 1;
1252 return 1; /* range with initial parameter omitted */
1253 }
1254 if (sscanf(p, "%u%n", &page, &c) > 0) {
1255 p += c;
1256 while (isspace((unsigned char)*p)) p++;
1257 *q = p;
1258 if (0 < page && page <= pageLim) {
1259 if (*p == '-') *pstate = page; /* range with start */
1260 return page;
1261 }
1262 }
1263 err:
1264 *pstate = -1;
1265 return 0;
1266}
1267
1268/* Draws in alignment marks on each page or borders on edge pages */
1269void
1270svxPrintout::drawticks(border clip, int tsize, int x, int y)
1271{
1272 long i;
1273 int s = tsize * 4;
1274 int o = s / 8;
1275 bool fAtCorner = fFalse;
1276 SetColour(PR_COLOUR_FRAME);
1277 if (x == 0 && m_layout->Border) {
1278 /* solid left border */
1279 MoveTo(clip.x_min, clip.y_min);
1280 DrawTo(clip.x_min, clip.y_max);
1281 fAtCorner = fTrue;
1282 } else {
1283 if (x > 0 || y > 0) {
1284 MoveTo(clip.x_min, clip.y_min);
1285 DrawTo(clip.x_min, clip.y_min + tsize);
1286 }
1287 if (s && x > 0 && m_layout->Cutlines) {
1288 /* dashed left border */
1289 i = (clip.y_max - clip.y_min) -
1290 (tsize + ((clip.y_max - clip.y_min - tsize * 2L) % s) / 2);
1291 for ( ; i > tsize; i -= s) {
1292 MoveTo(clip.x_min, clip.y_max - (i + o));
1293 DrawTo(clip.x_min, clip.y_max - (i - o));
1294 }
1295 }
1296 if (x > 0 || y < m_layout->pagesY - 1) {
1297 MoveTo(clip.x_min, clip.y_max - tsize);
1298 DrawTo(clip.x_min, clip.y_max);
1299 fAtCorner = fTrue;
1300 }
1301 }
1302
1303 if (y == m_layout->pagesY - 1 && m_layout->Border) {
1304 /* solid top border */
1305 if (!fAtCorner) MoveTo(clip.x_min, clip.y_max);
1306 DrawTo(clip.x_max, clip.y_max);
1307 fAtCorner = fTrue;
1308 } else {
1309 if (y < m_layout->pagesY - 1 || x > 0) {
1310 if (!fAtCorner) MoveTo(clip.x_min, clip.y_max);
1311 DrawTo(clip.x_min + tsize, clip.y_max);
1312 }
1313 if (s && y < m_layout->pagesY - 1 && m_layout->Cutlines) {
1314 /* dashed top border */
1315 i = (clip.x_max - clip.x_min) -
1316 (tsize + ((clip.x_max - clip.x_min - tsize * 2L) % s) / 2);
1317 for ( ; i > tsize; i -= s) {
1318 MoveTo(clip.x_max - (i + o), clip.y_max);
1319 DrawTo(clip.x_max - (i - o), clip.y_max);
1320 }
1321 }
1322 if (y < m_layout->pagesY - 1 || x < m_layout->pagesX - 1) {
1323 MoveTo(clip.x_max - tsize, clip.y_max);
1324 DrawTo(clip.x_max, clip.y_max);
1325 fAtCorner = fTrue;
1326 } else {
1327 fAtCorner = fFalse;
1328 }
1329 }
1330
1331 if (x == m_layout->pagesX - 1 && m_layout->Border) {
1332 /* solid right border */
1333 if (!fAtCorner) MoveTo(clip.x_max, clip.y_max);
1334 DrawTo(clip.x_max, clip.y_min);
1335 fAtCorner = fTrue;
1336 } else {
1337 if (x < m_layout->pagesX - 1 || y < m_layout->pagesY - 1) {
1338 if (!fAtCorner) MoveTo(clip.x_max, clip.y_max);
1339 DrawTo(clip.x_max, clip.y_max - tsize);
1340 }
1341 if (s && x < m_layout->pagesX - 1 && m_layout->Cutlines) {
1342 /* dashed right border */
1343 i = (clip.y_max - clip.y_min) -
1344 (tsize + ((clip.y_max - clip.y_min - tsize * 2L) % s) / 2);
1345 for ( ; i > tsize; i -= s) {
1346 MoveTo(clip.x_max, clip.y_min + (i + o));
1347 DrawTo(clip.x_max, clip.y_min + (i - o));
1348 }
1349 }
1350 if (x < m_layout->pagesX - 1 || y > 0) {
1351 MoveTo(clip.x_max, clip.y_min + tsize);
1352 DrawTo(clip.x_max, clip.y_min);
1353 fAtCorner = fTrue;
1354 } else {
1355 fAtCorner = fFalse;
1356 }
1357 }
1358
1359 if (y == 0 && m_layout->Border) {
1360 /* solid bottom border */
1361 if (!fAtCorner) MoveTo(clip.x_max, clip.y_min);
1362 DrawTo(clip.x_min, clip.y_min);
1363 } else {
1364 if (y > 0 || x < m_layout->pagesX - 1) {
1365 if (!fAtCorner) MoveTo(clip.x_max, clip.y_min);
1366 DrawTo(clip.x_max - tsize, clip.y_min);
1367 }
1368 if (s && y > 0 && m_layout->Cutlines) {
1369 /* dashed bottom border */
1370 i = (clip.x_max - clip.x_min) -
1371 (tsize + ((clip.x_max - clip.x_min - tsize * 2L) % s) / 2);
1372 for ( ; i > tsize; i -= s) {
1373 MoveTo(clip.x_min + (i + o), clip.y_min);
1374 DrawTo(clip.x_min + (i - o), clip.y_min);
1375 }
1376 }
1377 if (y > 0 || x > 0) {
1378 MoveTo(clip.x_min + tsize, clip.y_min);
1379 DrawTo(clip.x_min, clip.y_min);
1380 }
1381 }
1382}
1383
[ee05463]1384bool
[79c239e]1385svxPrintout::OnPrintPage(int pageNum) {
1386 GetPageSizePixels(&xpPageWidth, &ypPageDepth);
1387 pdc = GetDC();
[cca2ce1]1388#ifdef AVEN_PRINT_PREVIEW
[79c239e]1389 if (IsPreview()) {
1390 int dcx, dcy;
1391 pdc->GetSize(&dcx, &dcy);
1392 pdc->SetUserScale((double)dcx / xpPageWidth, (double)dcy / ypPageDepth);
1393 }
[cca2ce1]1394#endif
[79c239e]1395
1396 layout * l = m_layout;
1397 {
1398 int pwidth, pdepth;
1399 GetPageSizeMM(&pwidth, &pdepth);
1400 l->scX = (double)xpPageWidth / pwidth;
1401 l->scY = (double)ypPageDepth / pdepth;
1402 font_scaling_x = l->scX * (25.4 / 72.0);
1403 font_scaling_y = l->scY * (25.4 / 72.0);
1404 MarginLeft = m_data->GetMarginTopLeft().x;
1405 MarginTop = m_data->GetMarginTopLeft().y;
1406 MarginBottom = m_data->GetMarginBottomRight().y;
1407 MarginRight = m_data->GetMarginBottomRight().x;
1408 xpPageWidth -= (int)(l->scX * (MarginLeft + MarginRight));
1409 ypPageDepth -= (int)(l->scY * (10 + MarginBottom + MarginRight));
1410 // xpPageWidth -= 1;
1411 pdepth -= 10;
1412 x_offset = (long)(l->scX * MarginLeft);
1413 y_offset = (long)(l->scY * MarginTop);
1414 l->PaperWidth = pwidth -= MarginLeft + MarginRight;
1415 l->PaperDepth = pdepth -= MarginTop + MarginBottom;
1416 }
1417
[5940815]1418 double SIN = sin(rad(l->rot));
1419 double COS = cos(rad(l->rot));
1420 double SINT = sin(rad(l->tilt));
1421 double COST = cos(rad(l->tilt));
[79c239e]1422
1423 NewPage(pageNum, l->pagesX, l->pagesY);
1424
[256c4c8]1425 if (l->Legend && pageNum == (l->pagesY - 1) * l->pagesX + 1) {
[79c239e]1426 SetFont(PR_FONT_DEFAULT);
1427 draw_info_box();
1428 }
1429
[55918ca]1430 pdc->SetClippingRegion(x_offset, y_offset,xpPageWidth+1, ypPageDepth+1);
1431
[741d94f]1432 const double Sc = 1000 / l->Scale;
[79c239e]1433
[d713e5d]1434 if (l->show_mask & LEGS) {
[ce403f1]1435 SetColour(PR_COLOUR_LEG);
[c61aa79]1436 list<traverse>::const_iterator trav = mainfrm->traverses_begin();
1437 list<traverse>::const_iterator tend = mainfrm->traverses_end();
[ce403f1]1438 for ( ; trav != tend; ++trav) {
[d4650b3]1439 vector<PointInfo>::const_iterator pos = trav->begin();
1440 vector<PointInfo>::const_iterator end = trav->end();
[ce403f1]1441 for ( ; pos != end; ++pos) {
1442 double x = pos->GetX();
1443 double y = pos->GetY();
1444 double z = pos->GetZ();
1445 double X = x * COS - y * SIN;
[7a57dc7]1446 double Y = z * COST - (x * SIN + y * COS) * SINT;
[ce403f1]1447 long px = (long)((X * Sc + l->xOrg) * l->scX);
1448 long py = (long)((Y * Sc + l->yOrg) * l->scY);
1449 if (pos == trav->begin()) {
1450 MoveTo(px, py);
1451 } else {
1452 DrawTo(px, py);
1453 }
1454 }
[ee05463]1455 }
1456 }
1457
[d713e5d]1458 if ((l->show_mask & XSECT) &&
1459 (l->tilt == 0.0 || l->tilt == 90.0 || l->tilt == -90.0)) {
[ee05463]1460 list<vector<XSect> >::const_iterator trav = mainfrm->tubes_begin();
1461 list<vector<XSect> >::const_iterator tend = mainfrm->tubes_end();
1462 for ( ; trav != tend; ++trav) {
1463 if (l->tilt == 90.0 || l->tilt == -90.0) PlotLR(*trav);
[0fdd3aa]1464 if (l->tilt == 0.0) PlotUD(*trav);
[ce403f1]1465 }
1466 }
1467
[d713e5d]1468 if (l->show_mask & SURF) {
[ce403f1]1469 SetColour(PR_COLOUR_SURFACE_LEG);
[c61aa79]1470 list<traverse>::const_iterator trav = mainfrm->surface_traverses_begin();
1471 list<traverse>::const_iterator tend = mainfrm->surface_traverses_end();
[ce403f1]1472 for ( ; trav != tend; ++trav) {
[d4650b3]1473 vector<PointInfo>::const_iterator pos = trav->begin();
1474 vector<PointInfo>::const_iterator end = trav->end();
[ce403f1]1475 for ( ; pos != end; ++pos) {
1476 double x = pos->GetX();
1477 double y = pos->GetY();
1478 double z = pos->GetZ();
1479 double X = x * COS - y * SIN;
[1b2e819]1480 double Y = z * COST - (x * SIN + y * COS) * SINT;
[ce403f1]1481 long px = (long)((X * Sc + l->xOrg) * l->scX);
1482 long py = (long)((Y * Sc + l->yOrg) * l->scY);
1483 if (pos == trav->begin()) {
1484 MoveTo(px, py);
[79c239e]1485 } else {
[ce403f1]1486 DrawTo(px, py);
[79c239e]1487 }
1488 }
1489 }
1490 }
1491
[d713e5d]1492 if (l->show_mask & (LABELS|STNS)) {
1493 if (l->show_mask & LABELS) SetFont(PR_FONT_LABELS);
[ce403f1]1494 list<LabelInfo*>::const_iterator label = mainfrm->GetLabels();
1495 while (label != mainfrm->GetLabelsEnd()) {
[79c239e]1496 double px = (*label)->GetX();
1497 double py = (*label)->GetY();
1498 double pz = (*label)->GetZ();
[d713e5d]1499 if ((l->show_mask & SURF) || (*label)->IsUnderground()) {
[79c239e]1500 double X = px * COS - py * SIN;
[7a57dc7]1501 double Y = pz * COST - (px * SIN + py * COS) * SINT;
[79c239e]1502 long xnew, ynew;
1503 xnew = (long)((X * Sc + l->xOrg) * l->scX);
1504 ynew = (long)((Y * Sc + l->yOrg) * l->scY);
[d713e5d]1505 if (l->show_mask & STNS) {
[79c239e]1506 SetColour(PR_COLOUR_CROSS);
1507 DrawCross(xnew, ynew);
1508 }
[d713e5d]1509 if (l->show_mask & LABELS) {
[79c239e]1510 SetColour(PR_COLOUR_LABELS);
1511 MoveTo(xnew, ynew);
1512 WriteString((*label)->GetText());
1513 }
1514 }
1515 ++label;
1516 }
1517 }
1518
1519 return true;
1520}
1521
[13da582]1522void
1523svxPrintout::GetPageInfo(int *minPage, int *maxPage,
1524 int *pageFrom, int *pageTo)
1525{
1526 *minPage = *pageFrom = 1;
1527 *maxPage = *pageTo = m_layout->pages;
1528}
1529
1530bool
1531svxPrintout::HasPage(int pageNum) {
1532 return (pageNum <= m_layout->pages);
1533}
1534
[ee05463]1535void
[79c239e]1536svxPrintout::OnBeginPrinting() {
[a72ed95]1537 Init();
[79c239e]1538 Pre();
[0804fbe]1539 m_layout->footer = wmsg(/*Survey “%s” Page %d (of %d) Processed on %s*/167);
[79c239e]1540}
1541
1542void
1543svxPrintout::OnEndPrinting() {
[03e2031]1544 delete font_labels;
1545 delete font_default;
1546 delete pen_frame;
1547 delete pen_leg;
1548 delete pen_surface_leg;
1549 delete pen_cross;
[79c239e]1550}
1551
1552
1553// prcore -> wx.grafx (calls to move pens around and stuff - low level)
1554// this seems to have been done...
1555
1556
1557
1558static border clip;
1559
1560
1561int
1562svxPrintout::check_intersection(long x_p, long y_p)
1563{
1564#define U 1
1565#define D 2
1566#define L 4
1567#define R 8
1568 int mask_p = 0, mask_t = 0;
1569 if (x_p < 0)
1570 mask_p = L;
1571 else if (x_p > xpPageWidth)
1572 mask_p = R;
1573
1574 if (y_p < 0)
1575 mask_p |= D;
1576 else if (y_p > ypPageDepth)
1577 mask_p |= U;
1578
1579 if (x_t < 0)
1580 mask_t = L;
1581 else if (x_t > xpPageWidth)
1582 mask_t = R;
1583
1584 if (y_t < 0)
1585 mask_t |= D;
1586 else if (y_t > ypPageDepth)
1587 mask_t |= U;
1588
1589#if 0
1590 /* approximation to correct answer */
1591 return !(mask_t & mask_p);
1592#else
1593 /* One end of the line is on the page */
1594 if (!mask_t || !mask_p) return 1;
1595
1596 /* whole line is above, left, right, or below page */
1597 if (mask_t & mask_p) return 0;
1598
1599 if (mask_t == 0) mask_t = mask_p;
1600 if (mask_t & U) {
1601 double v = (double)(y_p - ypPageDepth) / (y_p - y_t);
1602 return v >= 0 && v <= 1;
1603 }
1604 if (mask_t & D) {
1605 double v = (double)y_p / (y_p - y_t);
1606 return v >= 0 && v <= 1;
1607 }
1608 if (mask_t & R) {
1609 double v = (double)(x_p - xpPageWidth) / (x_p - x_t);
1610 return v >= 0 && v <= 1;
1611 }
1612 SVX_ASSERT(mask_t & L);
1613 {
1614 double v = (double)x_p / (x_p - x_t);
1615 return v >= 0 && v <= 1;
1616 }
1617#endif
1618#undef U
1619#undef D
1620#undef L
1621#undef R
1622}
1623
1624void
1625svxPrintout::MoveTo(long x, long y)
1626{
1627 x_t = x_offset + x - clip.x_min;
1628 y_t = y_offset + clip.y_max - y;
1629}
1630
1631void
1632svxPrintout::DrawTo(long x, long y)
1633{
1634 long x_p = x_t, y_p = y_t;
1635 x_t = x_offset + x - clip.x_min;
1636 y_t = y_offset + clip.y_max - y;
1637 if (cur_pass != -1) {
[5940815]1638 pdc->DrawLine(x_p, y_p, x_t, y_t);
[79c239e]1639 } else {
1640 if (check_intersection(x_p, y_p)) fBlankPage = fFalse;
1641 }
1642}
1643
1644#define POINTS_PER_INCH 72.0
1645#define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
1646#define PWX_CROSS_SIZE (int)(2 * m_layout->scX / POINTS_PER_MM)
1647
1648void
1649svxPrintout::DrawCross(long x, long y)
1650{
1651 if (cur_pass != -1) {
1652 MoveTo(x - PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1653 DrawTo(x + PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1654 MoveTo(x + PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1655 DrawTo(x - PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1656 MoveTo(x, y);
1657 } else {
1658 if ((x + PWX_CROSS_SIZE > clip.x_min &&
1659 x - PWX_CROSS_SIZE < clip.x_max) ||
1660 (y + PWX_CROSS_SIZE > clip.y_min &&
1661 y - PWX_CROSS_SIZE < clip.y_max)) {
1662 fBlankPage = fFalse;
1663 }
1664 }
1665}
1666
1667void
1668svxPrintout::SetFont(int fontcode)
1669{
1670 switch (fontcode) {
1671 case PR_FONT_DEFAULT:
1672 current_font = font_default;
1673 break;
1674 case PR_FONT_LABELS:
1675 current_font = font_labels;
1676 break;
1677 default:
1678 BUG("unknown font code");
1679 }
1680}
1681
1682void
1683svxPrintout::SetColour(int colourcode)
1684{
1685 switch (colourcode) {
1686 case PR_COLOUR_TEXT:
1687 pdc->SetTextForeground(colour_text);
1688 break;
1689 case PR_COLOUR_LABELS:
1690 pdc->SetTextForeground(colour_labels);
1691 pdc->SetBackgroundMode(wxTRANSPARENT);
1692 break;
1693 case PR_COLOUR_FRAME:
1694 pdc->SetPen(*pen_frame);
1695 break;
1696 case PR_COLOUR_LEG:
1697 pdc->SetPen(*pen_leg);
1698 break;
1699 case PR_COLOUR_CROSS:
1700 pdc->SetPen(*pen_cross);
1701 break;
1702 case PR_COLOUR_SURFACE_LEG:
1703 pdc->SetPen(*pen_surface_leg);
1704 break;
1705 default:
1706 BUG("unknown colour code");
1707 }
1708}
1709
1710void
[5627cbb]1711svxPrintout::WriteString(const wxString & s)
[79c239e]1712{
1713 double xsc, ysc;
1714 pdc->GetUserScale(&xsc, &ysc);
1715 pdc->SetUserScale(xsc * font_scaling_x, ysc * font_scaling_y);
1716 pdc->SetFont(*current_font);
1717 int w, h;
1718 if (cur_pass != -1) {
[5627cbb]1719 pdc->GetTextExtent(wxT("My"), &w, &h);
[ee05463]1720 pdc->DrawText(s,
[79c239e]1721 long(x_t / font_scaling_x),
1722 long(y_t / font_scaling_y) - h);
1723 } else {
1724 pdc->GetTextExtent(s, &w, &h);
1725 if ((y_t + h > 0 && y_t - h < clip.y_max - clip.y_min) ||
1726 (x_t < clip.x_max - clip.x_min && x_t + w > 0)) {
1727 fBlankPage = fFalse;
1728 }
1729 }
1730 pdc->SetUserScale(xsc, ysc);
1731}
1732
1733void
1734svxPrintout::DrawEllipse(long x, long y, long r, long R)
1735{
1736 /* Don't need to check in first-pass - circle is only used in title box */
1737 if (cur_pass != -1) {
1738 x_t = x_offset + x - clip.x_min;
1739 y_t = y_offset + clip.y_max - y;
[2bf75f3]1740 const wxBrush & save_brush = pdc->GetBrush();
[79c239e]1741 pdc->SetBrush(*wxTRANSPARENT_BRUSH);
1742 pdc->DrawEllipse(x_t - r, y_t - R, 2 * r, 2 * R);
[2bf75f3]1743 pdc->SetBrush(save_brush);
[79c239e]1744 }
1745}
1746
1747void
1748svxPrintout::SolidRectangle(long x, long y, long w, long h)
1749{
1750 long X = x_offset + x - clip.x_min;
1751 long Y = y_offset + clip.y_max - y;
1752 pdc->SetBrush(*wxBLACK_BRUSH);
1753 pdc->DrawRectangle(X, Y - h, w, h);
1754}
1755
1756int
1757svxPrintout::Pre()
1758{
[5627cbb]1759 font_labels = new wxFont(fontsize_labels, wxDEFAULT, wxNORMAL, wxNORMAL,
1760 false, wxString(fontname_labels, wxConvUTF8),
1761 wxFONTENCODING_ISO8859_1);
1762 font_default = new wxFont(fontsize, wxDEFAULT, wxNORMAL, wxNORMAL,
1763 false, wxString(fontname, wxConvUTF8),
1764 wxFONTENCODING_ISO8859_1);
[79c239e]1765 current_font = font_default;
[2bf75f3]1766 pen_leg = new wxPen(colour_leg);
1767 pen_surface_leg = new wxPen(colour_surface_leg);
1768 pen_cross = new wxPen(colour_cross);
1769 pen_frame = new wxPen(colour_frame);
[79c239e]1770 return 1; /* only need 1 pass */
1771}
1772
1773void
1774svxPrintout::NewPage(int pg, int pagesX, int pagesY)
1775{
1776 int x, y;
1777 x = (pg - 1) % pagesX;
1778 y = pagesY - 1 - ((pg - 1) / pagesX);
1779
1780 clip.x_min = (long)x * xpPageWidth;
1781 clip.y_min = (long)y * ypPageDepth;
1782 clip.x_max = clip.x_min + xpPageWidth; /* dm/pcl/ps had -1; */
1783 clip.y_max = clip.y_min + ypPageDepth; /* dm/pcl/ps had -1; */
1784
1785 //we have to write the footer here. PostScript is being weird. Really weird.
1786 pdc->SetFont(*font_labels);
[0f8ab4d]1787 MoveTo(clip.x_min, clip.y_min - (long)(7 * m_layout->scY));
1788 wxString footer;
1789 footer.Printf(m_layout->footer,
1790 m_layout->title.c_str(),
1791 pg,
1792 m_layout->pagesX * m_layout->pagesY,
1793 m_layout->datestamp.c_str());
1794 WriteString(footer);
[79c239e]1795 pdc->DestroyClippingRegion();
1796 drawticks(clip, (int)(9 * m_layout->scX / POINTS_PER_MM), x, y);
1797}
1798
[741d94f]1799void
[ee05463]1800svxPrintout::PlotLR(const vector<XSect> & centreline)
[741d94f]1801{
1802 assert(centreline.size() > 1);
[ee05463]1803 XSect prev_pt_v;
[741d94f]1804 Vector3 last_right(1.0, 0.0, 0.0);
1805
1806 const double Sc = 1000 / m_layout->Scale;
[0fdd3aa]1807 const double SIN = sin(rad(m_layout->rot));
1808 const double COS = cos(rad(m_layout->rot));
[741d94f]1809
[ee05463]1810 vector<XSect>::const_iterator i = centreline.begin();
1811 vector<XSect>::size_type segment = 0;
[741d94f]1812 while (i != centreline.end()) {
1813 // get the coordinates of this vertex
[ee05463]1814 const XSect & pt_v = *i++;
[741d94f]1815
1816 Vector3 right;
1817
1818 const Vector3 up_v(0.0, 0.0, 1.0);
1819
1820 if (segment == 0) {
1821 assert(i != centreline.end());
1822 // first segment
1823
1824 // get the coordinates of the next vertex
[ee05463]1825 const XSect & next_pt_v = *i;
[741d94f]1826
1827 // calculate vector from this pt to the next one
[d67450e]1828 Vector3 leg_v = next_pt_v - pt_v;
[741d94f]1829
1830 // obtain a vector in the LRUD plane
1831 right = leg_v * up_v;
1832 if (right.magnitude() == 0) {
1833 right = last_right;
1834 } else {
1835 last_right = right;
1836 }
1837 } else if (segment + 1 == centreline.size()) {
1838 // last segment
1839
1840 // Calculate vector from the previous pt to this one.
[d67450e]1841 Vector3 leg_v = pt_v - prev_pt_v;
[741d94f]1842
1843 // Obtain a horizontal vector in the LRUD plane.
1844 right = leg_v * up_v;
1845 if (right.magnitude() == 0) {
[d67450e]1846 right = Vector3(last_right.GetX(), last_right.GetY(), 0.0);
[741d94f]1847 } else {
1848 last_right = right;
1849 }
1850 } else {
1851 assert(i != centreline.end());
1852 // Intermediate segment.
1853
1854 // Get the coordinates of the next vertex.
[ee05463]1855 const XSect & next_pt_v = *i;
[741d94f]1856
1857 // Calculate vectors from this vertex to the
1858 // next vertex, and from the previous vertex to
1859 // this one.
[d67450e]1860 Vector3 leg1_v = pt_v - prev_pt_v;
1861 Vector3 leg2_v = next_pt_v - pt_v;
[741d94f]1862
1863 // Obtain horizontal vectors perpendicular to
1864 // both legs, then normalise and average to get
1865 // a horizontal bisector.
1866 Vector3 r1 = leg1_v * up_v;
1867 Vector3 r2 = leg2_v * up_v;
1868 r1.normalise();
1869 r2.normalise();
1870 right = r1 + r2;
1871 if (right.magnitude() == 0) {
1872 // This is the "mid-pitch" case...
1873 right = last_right;
1874 }
1875 last_right = right;
1876 }
1877
1878 // Scale to unit vectors in the LRUD plane.
1879 right.normalise();
1880
1881 Double l = pt_v.GetL();
1882 Double r = pt_v.GetR();
1883
1884 if (l >= 0) {
[d67450e]1885 Vector3 p = pt_v - right * l;
1886 double X = p.GetX() * COS - p.GetY() * SIN;
1887 double Y = (p.GetX() * SIN + p.GetY() * COS);
[741d94f]1888 long x = (long)((X * Sc + m_layout->xOrg) * m_layout->scX);
1889 long y = (long)((Y * Sc + m_layout->yOrg) * m_layout->scY);
1890 MoveTo(x - PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1891 DrawTo(x, y);
1892 DrawTo(x - PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1893 }
1894 if (r >= 0) {
[d67450e]1895 Vector3 p = pt_v + right * r;
1896 double X = p.GetX() * COS - p.GetY() * SIN;
1897 double Y = (p.GetX() * SIN + p.GetY() * COS);
[741d94f]1898 long x = (long)((X * Sc + m_layout->xOrg) * m_layout->scX);
1899 long y = (long)((Y * Sc + m_layout->yOrg) * m_layout->scY);
1900 MoveTo(x + PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1901 DrawTo(x, y);
1902 DrawTo(x + PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1903 }
1904
1905 prev_pt_v = pt_v;
1906
1907 ++segment;
1908 }
1909}
1910
[0fdd3aa]1911void
[ee05463]1912svxPrintout::PlotUD(const vector<XSect> & centreline)
[0fdd3aa]1913{
1914 assert(centreline.size() > 1);
1915 const double Sc = 1000 / m_layout->Scale;
1916
[ee05463]1917 vector<XSect>::const_iterator i = centreline.begin();
[0fdd3aa]1918 while (i != centreline.end()) {
1919 // get the coordinates of this vertex
[ee05463]1920 const XSect & pt_v = *i++;
[0fdd3aa]1921
[4f40e6c]1922 Double u = pt_v.GetU();
1923 Double d = pt_v.GetD();
[0fdd3aa]1924
1925 if (u >= 0 || d >= 0) {
[d67450e]1926 Vector3 p = pt_v;
[0fdd3aa]1927 double SIN = sin(rad(m_layout->rot));
1928 double COS = cos(rad(m_layout->rot));
[d67450e]1929 double X = p.GetX() * COS - p.GetY() * SIN;
1930 double Y = p.GetZ();
[0fdd3aa]1931 long x = (long)((X * Sc + m_layout->xOrg) * m_layout->scX);
1932 if (u >= 0) {
1933 long y = (long)(((Y + u) * Sc + m_layout->yOrg) * m_layout->scY);
1934 MoveTo(x - PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1935 DrawTo(x, y);
1936 DrawTo(x + PWX_CROSS_SIZE, y + PWX_CROSS_SIZE);
1937 }
1938 if (d >= 0) {
1939 long y = (long)(((Y - d) * Sc + m_layout->yOrg) * m_layout->scY);
1940 MoveTo(x - PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1941 DrawTo(x, y);
1942 DrawTo(x + PWX_CROSS_SIZE, y - PWX_CROSS_SIZE);
1943 }
1944 }
1945 }
1946}
1947
[79c239e]1948/* Initialise printer routines */
[a72ed95]1949void
1950svxPrintout::Init()
[79c239e]1951{
1952 fontsize_labels = 10;
1953 fontsize = 10;
1954
1955 colour_text = colour_labels = colour_frame = colour_leg = colour_cross = colour_surface_leg = *wxBLACK;
1956 m_layout->scX = 1;
1957 m_layout->scY = 1;
1958}
Note: See TracBrowser for help on using the repository browser.