source: git/src/printwx.cc @ 36efb03

line_contentsstereotravis-osx
Last change on this file since 36efb03 was 36efb03, checked in by Olly Betts <olly@…>, 5 years ago

src/: Add more TRANSLATORS comments.

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