2 /* Aven printing code */
3 /* Copyright (C) 1993-2003,2004,2005,2006,2010,2011,2012,2013,2014,2015,2016 Olly Betts
4 * Copyright (C) 2001,2004 Philip Underwood
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.
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.
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
25 #include <wx/confbase.h>
26 #include <wx/filename.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>
51 #include "avenprcore.h"
57 // How many decimal points to show on angles:
61 # define ANGLE_FMT wxT("%03.f")
62 # define ANGLE2_FMT wxT("%.f")
64 # define ANGLE_FMT wxT("%05.1f")
65 # define ANGLE2_FMT wxT("%.1f")
67 # define ANGLE_FMT wxT("%06.2f")
68 # define ANGLE2_FMT wxT("%.2f")
70 # error Need to add ANGLE_FMT and ANGLE2_FMT for the currently set ANGLE_DP
74 format_angle(const wxChar
* fmt
, double angle
)
78 size_t dot
= s
.find('.');
123 class BitValidator
: public wxValidator
{
124 // Disallow assignment.
125 BitValidator
& operator=(const BitValidator
&);
133 BitValidator(int * val_
, int mask_
)
134 : val(val_
), mask(mask_
) { }
136 BitValidator(const BitValidator
&o
) : wxValidator() {
142 wxObject
*Clone() const { return new BitValidator(val
, mask
); }
144 bool Copy(const BitValidator
& o
) {
145 wxValidator::Copy(o
);
151 bool Validate(wxWindow
*) { return true; }
153 bool TransferToWindow() {
154 if (!m_validatorWindow
->IsKindOf(CLASSINFO(wxCheckBox
)))
156 ((wxCheckBox
*)m_validatorWindow
)->SetValue(*val
& mask
);
160 bool TransferFromWindow() {
161 if (!m_validatorWindow
->IsKindOf(CLASSINFO(wxCheckBox
)))
163 if (((wxCheckBox
*)m_validatorWindow
)->IsChecked())
171 class svxPrintout
: public wxPrintout
{
174 wxPageSetupDialogData
* m_data
;
176 wxFont
*font_labels
, *font_default
;
177 // Currently unused, but "skip blank pages" would use it.
178 bool scan_for_blank_pages
;
180 wxPen
*pen_frame
, *pen_cross
, *pen_leg
, *pen_surface_leg
, *pen_splay
;
181 wxColour colour_text
, colour_labels
;
184 double font_scaling_x
, font_scaling_y
;
187 long x_min
, y_min
, x_max
, y_max
;
192 int check_intersection(long x_p
, long y_p
);
193 void draw_info_box();
194 void draw_scale_bar(double x
, double y
, double MaxLength
);
195 int next_page(int *pstate
, char **q
, int pageLim
);
196 void drawticks(int tsize
, int x
, int y
);
198 void MOVEMM(double X
, double Y
) {
199 MoveTo((long)(X
* m_layout
->scX
), (long)(Y
* m_layout
->scY
));
201 void DRAWMM(double X
, double Y
) {
202 DrawTo((long)(X
* m_layout
->scX
), (long)(Y
* m_layout
->scY
));
204 void MoveTo(long x
, long y
);
205 void DrawTo(long x
, long y
);
206 void DrawCross(long x
, long y
);
207 void SetFont(wxFont
* font
) {
210 void WriteString(const wxString
& s
);
211 void DrawEllipse(long x
, long y
, long r
, long R
);
212 void SolidRectangle(long x
, long y
, long w
, long h
);
213 void NewPage(int pg
, int pagesX
, int pagesY
);
214 void PlotLR(const vector
<XSect
> & centreline
);
215 void PlotUD(const vector
<XSect
> & centreline
);
217 svxPrintout(MainFrm
*mainfrm
, layout
*l
, wxPageSetupDialogData
*data
, const wxString
& title
);
218 bool OnPrintPage(int pageNum
);
219 void GetPageInfo(int *minPage
, int *maxPage
,
220 int *pageFrom
, int *pageTo
);
221 bool HasPage(int pageNum
);
222 void OnBeginPrinting();
223 void OnEndPrinting();
226 BEGIN_EVENT_TABLE(svxPrintDlg
, wxDialog
)
227 EVT_CHOICE(svx_FORMAT
, svxPrintDlg::OnChange
)
228 EVT_TEXT(svx_SCALE
, svxPrintDlg::OnChange
)
229 EVT_COMBOBOX(svx_SCALE
, svxPrintDlg::OnChange
)
230 EVT_SPINCTRLDOUBLE(svx_BEARING
, svxPrintDlg::OnChangeSpin
)
231 EVT_SPINCTRLDOUBLE(svx_TILT
, svxPrintDlg::OnChangeSpin
)
232 EVT_BUTTON(wxID_PRINT
, svxPrintDlg::OnPrint
)
233 EVT_BUTTON(svx_EXPORT
, svxPrintDlg::OnExport
)
234 EVT_BUTTON(wxID_CANCEL
, svxPrintDlg::OnCancel
)
235 #ifdef AVEN_PRINT_PREVIEW
236 EVT_BUTTON(wxID_PREVIEW
, svxPrintDlg::OnPreview
)
238 EVT_BUTTON(svx_PLAN
, svxPrintDlg::OnPlan
)
239 EVT_BUTTON(svx_ELEV
, svxPrintDlg::OnElevation
)
240 EVT_UPDATE_UI(svx_PLAN
, svxPrintDlg::OnPlanUpdate
)
241 EVT_UPDATE_UI(svx_ELEV
, svxPrintDlg::OnElevationUpdate
)
242 EVT_CHECKBOX(svx_LEGS
, svxPrintDlg::OnChange
)
243 EVT_CHECKBOX(svx_STATIONS
, svxPrintDlg::OnChange
)
244 EVT_CHECKBOX(svx_NAMES
, svxPrintDlg::OnChange
)
245 EVT_CHECKBOX(svx_SURFACE
, svxPrintDlg::OnChange
)
246 EVT_CHECKBOX(svx_SPLAYS
, svxPrintDlg::OnChange
)
247 EVT_CHECKBOX(svx_ENTS
, svxPrintDlg::OnChange
)
248 EVT_CHECKBOX(svx_FIXES
, svxPrintDlg::OnChange
)
249 EVT_CHECKBOX(svx_EXPORTS
, svxPrintDlg::OnChange
)
252 static wxString scales
[] = {
268 static wxString formats
[] = {
282 static wxString projs
[] = {
284 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"),
285 /* British grid SD (Yorkshire): */
286 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"),
287 /* British full grid reference: */
288 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")
292 static const unsigned format_info
[] = {
293 LABELS
|LEGS
|SURF
|SPLAYS
|STNS
|PASG
|XSECT
|WALLS
|MARKER_SIZE
|TEXT_HEIGHT
|GRID
|FULL_COORDS
,
294 LABELS
|LEGS
|SURF
|SPLAYS
|STNS
|PASG
|XSECT
|WALLS
,
295 LABELS
|LEGS
|SURF
|SPLAYS
|ENTS
|FIXES
|EXPORTS
|PROJ
|EXPORT_3D
,
296 LABELS
|LEGS
|SURF
|SPLAYS
|STNS
|CENTRED
,
297 LEGS
|SPLAYS
|CENTRED
|EXPORT_3D
,
298 LABELS
|LEGS
|SPLAYS
|ENTS
|FIXES
|EXPORTS
|PROJ
|EXPORT_3D
,
299 LABELS
|LEGS
|SURF
|SPLAYS
,
300 LABELS
|LEGS
|SURF
|SPLAYS
|STNS
|MARKER_SIZE
|GRID
|SCALE
,
301 LABELS
|ENTS
|FIXES
|EXPORTS
|EXPORT_3D
,
302 LABELS
|LEGS
|SURF
|SPLAYS
|STNS
|PASG
|XSECT
|WALLS
|MARKER_SIZE
|TEXT_HEIGHT
|SCALE
305 static const char * extension
[] = {
318 static const int msg_filetype
[] = {
322 /* TRANSLATORS: Here "plotter" refers to a machine which draws a printout
323 * on a (usually large) sheet of paper using a pen mounted in a motorised
325 /*HPGL for plotters*/414,
328 /* TRANSLATORS: "Compass" and "Carto" are the names of software packages,
329 * so should not be translated:
330 * http://www.fountainware.com/compass/
331 * http://www.psc-cavers.org/carto/ */
332 /*Compass PLT for use with Carto*/415,
333 /* TRANSLATORS: "Skencil" is the name of a software package, so should not be
334 * translated: http://www.skencil.org/ */
335 /*Skencil files*/416,
336 /* TRANSLATORS: Survex is the name of the software, and "pos" refers to a
337 * file extension, so neither should be translated. */
338 /*Survex pos files*/166,
342 // We discriminate as "One Page" isn't valid for exporting.
343 static wxString default_scale_print
;
344 static wxString default_scale_export
;
346 svxPrintDlg::svxPrintDlg(MainFrm
* mainfrm_
, const wxString
& filename
,
347 const wxString
& title
, const wxString
& cs_proj
,
348 const wxString
& datestamp
, time_t datestamp_numeric
,
349 double angle
, double tilt_angle
,
350 bool labels
, bool crosses
, bool legs
, bool surf
,
351 bool splays
, bool tubes
, bool ents
, bool fixes
,
352 bool exports
, bool printing
, bool close_after_
)
353 : wxDialog(mainfrm_
, -1, wxString(printing
?
354 /* TRANSLATORS: Title of the print
357 /* TRANSLATORS: Title of the export
359 wmsg(/*Export*/383))),
360 m_layout(printing
? wxGetApp().GetPageSetupDialogData() : NULL
),
361 m_File(filename
), mainfrm(mainfrm_
), close_after(close_after_
)
380 show_mask
|= XSECT
|WALLS
|PASG
;
386 show_mask
|= EXPORTS
;
387 m_layout
.show_mask
= show_mask
;
388 m_layout
.datestamp
= datestamp
;
389 m_layout
.datestamp_numeric
= datestamp_numeric
;
390 m_layout
.rot
= angle
;
391 m_layout
.title
= title
;
392 m_layout
.cs_proj
= cs_proj
;
393 if (mainfrm
->IsExtendedElevation()) {
394 m_layout
.view
= layout::EXTELEV
;
395 if (m_layout
.rot
!= 0.0 && m_layout
.rot
!= 180.0) m_layout
.rot
= 0;
398 m_layout
.tilt
= tilt_angle
;
399 if (m_layout
.tilt
== -90.0) {
400 m_layout
.view
= layout::PLAN
;
401 } else if (m_layout
.tilt
== 0.0) {
402 m_layout
.view
= layout::ELEV
;
404 m_layout
.view
= layout::TILT
;
408 /* setup our print dialog*/
409 wxBoxSizer
* v1
= new wxBoxSizer(wxVERTICAL
);
410 wxBoxSizer
* h1
= new wxBoxSizer(wxHORIZONTAL
); // holds controls
411 /* TRANSLATORS: Used as a label for the surrounding box for the "Bearing"
412 * and "Tilt angle" fields, and the "Plan view" and "Elevation" buttons in
413 * the "what to print/export" dialog. */
414 m_viewbox
= new wxStaticBoxSizer(new wxStaticBox(this, -1, wmsg(/*View*/283)), wxVERTICAL
);
415 /* TRANSLATORS: Used as a label for the surrounding box for the "survey
416 * legs" "stations" "names" etc checkboxes in the "what to print" dialog.
417 * "Elements" isn’t a good name for this but nothing better has yet come to
419 wxBoxSizer
* v3
= new wxStaticBoxSizer(new wxStaticBox(this, -1, wmsg(/*Elements*/256)), wxVERTICAL
);
420 wxBoxSizer
* h2
= new wxBoxSizer(wxHORIZONTAL
);
421 wxBoxSizer
* h3
= new wxBoxSizer(wxHORIZONTAL
); // holds buttons
425 label
= new wxStaticText(this, -1, wxString(wmsg(/*Export format*/410)));
426 const size_t n_formats
= sizeof(formats
) / sizeof(formats
[0]);
427 m_format
= new wxChoice(this, svx_FORMAT
,
428 wxDefaultPosition
, wxDefaultSize
,
430 unsigned current_format
= 0;
431 wxConfigBase
* cfg
= wxConfigBase::Get();
433 if (cfg
->Read(wxT("export_format"), &s
, wxString())) {
434 for (unsigned i
= 0; i
!= n_formats
; ++i
) {
435 if (s
== formats
[i
]) {
441 m_format
->SetSelection(current_format
);
442 wxBoxSizer
* formatbox
= new wxBoxSizer(wxHORIZONTAL
);
443 formatbox
->Add(label
, 0, wxALIGN_CENTER_VERTICAL
|wxALL
, 5);
444 formatbox
->Add(m_format
, 0, wxALIGN_CENTER_VERTICAL
|wxALL
, 5);
446 v1
->Add(formatbox
, 0, wxALIGN_LEFT
|wxALL
, 0);
450 label
= new wxStaticText(this, -1, wxString(wmsg(/*Scale*/154)) + wxT(" 1:"));
451 if (printing
&& scales
[0].empty()) {
452 /* TRANSLATORS: used in the scale drop down selector in the print
453 * dialog the implicit meaning is "choose a suitable scale to fit
454 * the plot on a single page", but we need something shorter */
455 scales
[0].assign(wmsg(/*One page*/258));
457 wxString default_scale
;
459 default_scale
= default_scale_print
;
460 if (default_scale
.empty()) default_scale
= scales
[0];
462 default_scale
= default_scale_export
;
463 if (default_scale
.empty()) default_scale
= wxT("1000");
465 const wxString
* scale_list
= scales
;
466 size_t n_scales
= sizeof(scales
) / sizeof(scales
[0]);
471 m_scale
= new wxComboBox(this, svx_SCALE
, default_scale
, wxDefaultPosition
,
472 wxDefaultSize
, n_scales
, scale_list
);
473 m_scalebox
= new wxBoxSizer(wxHORIZONTAL
);
474 m_scalebox
->Add(label
, 0, wxALIGN_CENTER_VERTICAL
|wxALL
, 5);
475 m_scalebox
->Add(m_scale
, 0, wxALIGN_CENTER_VERTICAL
|wxALL
, 5);
477 m_viewbox
->Add(m_scalebox
, 0, wxALIGN_LEFT
|wxALL
, 0);
480 // Make the dummy string wider than any sane value and use that to
481 // fix the width of the control so the sizers allow space for bigger
483 m_printSize
= new wxStaticText(this, -1, wxString::Format(wmsg(/*%d pages (%dx%d)*/257), 9604, 98, 98));
484 m_viewbox
->Add(m_printSize
, 0, wxALIGN_LEFT
|wxALL
, 5);
488 * svx_GRID, // double - spacing, default: 100m
489 * svx_TEXT_HEIGHT, // default 0.6
490 * svx_MARKER_SIZE // default 0.8
493 if (m_layout
.view
!= layout::EXTELEV
) {
494 wxFlexGridSizer
* anglebox
= new wxFlexGridSizer(2);
495 wxStaticText
* brg_label
, * tilt_label
;
496 brg_label
= new wxStaticText(this, -1, wmsg(/*Bearing*/259));
497 anglebox
->Add(brg_label
, 0, wxALIGN_CENTER_VERTICAL
|wxALIGN_LEFT
|wxALL
, 5);
498 // wSP_WRAP means that you can scroll past 360 to 0, and vice versa.
499 m_bearing
= new wxSpinCtrlDouble(this, svx_BEARING
, wxEmptyString
,
500 wxDefaultPosition
, wxDefaultSize
, wxSP_ARROW_KEYS
|wxSP_WRAP
);
501 m_bearing
->SetRange(0.0, 360.0);
502 m_bearing
->SetDigits(ANGLE_DP
);
503 anglebox
->Add(m_bearing
, 0, wxALIGN_CENTER
|wxALL
, 5);
504 /* TRANSLATORS: Used in the print dialog: */
505 tilt_label
= new wxStaticText(this, -1, wmsg(/*Tilt angle*/263));
506 anglebox
->Add(tilt_label
, 0, wxALIGN_CENTER_VERTICAL
|wxALIGN_LEFT
|wxALL
, 5);
507 m_tilt
= new wxSpinCtrlDouble(this, svx_TILT
);
508 m_tilt
->SetRange(-90.0, 90.0);
509 m_tilt
->SetDigits(ANGLE_DP
);
510 anglebox
->Add(m_tilt
, 0, wxALIGN_CENTER
|wxALL
, 5);
512 m_viewbox
->Add(anglebox
, 0, wxALIGN_LEFT
|wxALL
, 0);
514 wxBoxSizer
* planelevsizer
= new wxBoxSizer(wxHORIZONTAL
);
515 planelevsizer
->Add(new wxButton(this, svx_PLAN
, wmsg(/*P&lan view*/117)),
516 0, wxALIGN_CENTRE_VERTICAL
|wxALL
, 5);
517 planelevsizer
->Add(new wxButton(this, svx_ELEV
, wmsg(/*&Elevation*/285)),
518 0, wxALIGN_CENTRE_VERTICAL
|wxALL
, 5);
520 m_viewbox
->Add(planelevsizer
, 0, wxALIGN_LEFT
|wxALL
, 5);
523 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
524 * "survey stations". */
525 v3
->Add(new wxCheckBox(this, svx_LEGS
, wmsg(/*Underground Survey Legs*/262),
526 wxDefaultPosition
, wxDefaultSize
, 0,
527 BitValidator(&m_layout
.show_mask
, LEGS
)),
528 0, wxALIGN_LEFT
|wxALL
, 2);
529 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
530 * "survey stations". */
531 v3
->Add(new wxCheckBox(this, svx_SURFACE
, wmsg(/*Sur&face Survey Legs*/403),
532 wxDefaultPosition
, wxDefaultSize
, 0,
533 BitValidator(&m_layout
.show_mask
, SURF
)),
534 0, wxALIGN_LEFT
|wxALL
, 2);
535 v3
->Add(new wxCheckBox(this, svx_SPLAYS
, wmsg(/*Spla&y Legs*/406),
536 wxDefaultPosition
, wxDefaultSize
, 0,
537 BitValidator(&m_layout
.show_mask
, SPLAYS
)),
538 0, wxALIGN_LEFT
|wxALL
, 2);
539 v3
->Add(new wxCheckBox(this, svx_STATIONS
, wmsg(/*Crosses*/261),
540 wxDefaultPosition
, wxDefaultSize
, 0,
541 BitValidator(&m_layout
.show_mask
, STNS
)),
542 0, wxALIGN_LEFT
|wxALL
, 2);
543 v3
->Add(new wxCheckBox(this, svx_NAMES
, wmsg(/*Station Names*/260),
544 wxDefaultPosition
, wxDefaultSize
, 0,
545 BitValidator(&m_layout
.show_mask
, LABELS
)),
546 0, wxALIGN_LEFT
|wxALL
, 2);
547 v3
->Add(new wxCheckBox(this, svx_ENTS
, wmsg(/*Entrances*/418),
548 wxDefaultPosition
, wxDefaultSize
, 0,
549 BitValidator(&m_layout
.show_mask
, ENTS
)),
550 0, wxALIGN_LEFT
|wxALL
, 2);
551 v3
->Add(new wxCheckBox(this, svx_FIXES
, wmsg(/*Fixed Points*/419),
552 wxDefaultPosition
, wxDefaultSize
, 0,
553 BitValidator(&m_layout
.show_mask
, FIXES
)),
554 0, wxALIGN_LEFT
|wxALL
, 2);
555 v3
->Add(new wxCheckBox(this, svx_EXPORTS
, wmsg(/*Exported Stations*/420),
556 wxDefaultPosition
, wxDefaultSize
, 0,
557 BitValidator(&m_layout
.show_mask
, EXPORTS
)),
558 0, wxALIGN_LEFT
|wxALL
, 2);
559 v3
->Add(new wxCheckBox(this, svx_XSECT
, wmsg(/*Cross-sections*/393),
560 wxDefaultPosition
, wxDefaultSize
, 0,
561 BitValidator(&m_layout
.show_mask
, XSECT
)),
562 0, wxALIGN_LEFT
|wxALL
, 2);
564 v3
->Add(new wxCheckBox(this, svx_WALLS
, wmsg(/*Walls*/394),
565 wxDefaultPosition
, wxDefaultSize
, 0,
566 BitValidator(&m_layout
.show_mask
, WALLS
)),
567 0, wxALIGN_LEFT
|wxALL
, 2);
568 // TRANSLATORS: Label for checkbox which controls whether there's a
569 // layer in the exported file (for formats such as DXF and SVG)
570 // containing polygons for the inside of cave passages).
571 v3
->Add(new wxCheckBox(this, svx_PASSAGES
, wmsg(/*Passages*/395),
572 wxDefaultPosition
, wxDefaultSize
, 0,
573 BitValidator(&m_layout
.show_mask
, PASG
)),
574 0, wxALIGN_LEFT
|wxALL
, 2);
575 v3
->Add(new wxCheckBox(this, svx_CENTRED
, wmsg(/*Origin in centre*/421),
576 wxDefaultPosition
, wxDefaultSize
, 0,
577 BitValidator(&m_layout
.show_mask
, CENTRED
)),
578 0, wxALIGN_LEFT
|wxALL
, 2);
579 v3
->Add(new wxCheckBox(this, svx_FULLCOORDS
, wmsg(/*Full coordinates*/422),
580 wxDefaultPosition
, wxDefaultSize
, 0,
581 BitValidator(&m_layout
.show_mask
, FULL_COORDS
)),
582 0, wxALIGN_LEFT
|wxALL
, 2);
585 /* TRANSLATORS: used in the print dialog - controls drawing lines
586 * around each page */
587 v3
->Add(new wxCheckBox(this, svx_BORDERS
, wmsg(/*Page Borders*/264),
588 wxDefaultPosition
, wxDefaultSize
, 0,
589 wxGenericValidator(&m_layout
.Border
)),
590 0, wxALIGN_LEFT
|wxALL
, 2);
591 /* TRANSLATORS: will be used in the print dialog - check this to print
592 * blank pages (otherwise they’ll be skipped to save paper) */
593 // m_blanks = new wxCheckBox(this, svx_BLANKS, wmsg(/*Blank Pages*/266));
594 // v3->Add(m_blanks, 0, wxALIGN_LEFT|wxALL, 2);
595 /* TRANSLATORS: As in the legend on a map. Used in the print dialog -
596 * controls drawing the box at the lower left with survey name, view
598 v3
->Add(new wxCheckBox(this, svx_LEGEND
, wmsg(/*Legend*/265),
599 wxDefaultPosition
, wxDefaultSize
, 0,
600 wxGenericValidator(&m_layout
.Legend
)),
601 0, wxALIGN_LEFT
|wxALL
, 2);
604 h1
->Add(v3
, 0, wxALIGN_LEFT
|wxALL
, 5);
605 h1
->Add(m_viewbox
, 0, wxALIGN_LEFT
|wxLEFT
, 5);
608 /* TRANSLATORS: The PROJ library is used to do coordinate
609 * transformations (https://trac.osgeo.org/proj/) - if the .3d file
610 * doesn't contain details of the coordinate projection in use, the
611 * user must specify it here for export formats which need to know it
614 h2
->Add(new wxStaticText(this, svx_PROJ_LABEL
, wmsg(/*Coordinate projection*/440)),
615 0, wxLEFT
|wxALIGN_CENTRE_VERTICAL
, 5);
617 if (!m_layout
.cs_proj
.empty()) {
618 // If the input file specified the coordinate system, don't let the
619 // user mess with it.
620 style
= wxTE_READONLY
;
622 #if 0 // FIXME: Is it a good idea to save this?
623 wxConfigBase
* cfg
= wxConfigBase::Get();
624 wxString input_projection
;
625 cfg
->Read(wxT("input_projection"), &input_projection
);
626 if (!input_projection
.empty())
627 proj_edit
.SetValue(input_projection
);
630 wxTextCtrl
* proj_edit
= new wxTextCtrl(this, svx_PROJ
, m_layout
.cs_proj
,
631 wxDefaultPosition
, wxDefaultSize
,
633 h2
->Add(proj_edit
, 1, wxALL
|wxEXPAND
|wxALIGN_CENTRE_VERTICAL
, 5);
634 v1
->Add(h2
, 0, wxALIGN_LEFT
|wxEXPAND
, 5);
637 v1
->Add(h1
, 0, wxALIGN_LEFT
|wxALL
, 5);
639 // When we enable/disable checkboxes in the export dialog, ideally we'd
640 // like the dialog to resize, but not sure how to achieve that, so we
641 // add a stretchable spacer here so at least the buttons stay in the
642 // lower right corner.
643 v1
->AddStretchSpacer();
646 but
= new wxButton(this, wxID_CANCEL
);
647 h3
->Add(but
, 0, wxALIGN_RIGHT
|wxALL
, 5);
649 #ifdef AVEN_PRINT_PREVIEW
650 but
= new wxButton(this, wxID_PREVIEW
);
651 h3
->Add(but
, 0, wxALIGN_RIGHT
|wxALL
, 5);
652 but
= new wxButton(this, wxID_PRINT
);
654 but
= new wxButton(this, wxID_PRINT
, wmsg(/*&Print...*/400));
657 /* TRANSLATORS: The text on the action button in the "Export" settings
659 but
= new wxButton(this, svx_EXPORT
, wmsg(/*&Export...*/230));
662 h3
->Add(but
, 0, wxALIGN_RIGHT
|wxALL
, 5);
663 v1
->Add(h3
, 0, wxALIGN_RIGHT
|wxALL
, 5);
667 v1
->SetSizeHints(this);
674 svxPrintDlg::OnPrint(wxCommandEvent
&) {
676 TransferDataFromWindow();
677 wxPageSetupDialogData
* psdd
= wxGetApp().GetPageSetupDialogData();
678 wxPrintDialogData
pd(psdd
->GetPrintData());
680 svxPrintout
po(mainfrm
, &m_layout
, psdd
, m_File
);
681 if (m_layout
.SkipBlank
) {
682 // FIXME: wx's printing requires a contiguous range of valid page
683 // numbers. To achieve that, we need to run a scan for blank pages
684 // here, so that GetPageInfo() knows what range to return, and so
685 // that OnPrintPage() can map a page number back to where in the
686 // MxN multi-page layout.
688 po
.scan_for_blank_pages
= true;
689 for (int page
= 1; page
<= m_layout
->pages
; ++page
) {
690 po
.fBlankPage
= fTrue
;
691 po
.OnPrintPage(page
);
692 // FIXME: Do something with po.fBlankPage
694 po
.scan_for_blank_pages
= false;
697 if (pr
.Print(this, &po
, true)) {
698 // Close the print dialog if printing succeeded.
704 svxPrintDlg::OnExport(wxCommandEvent
&) {
706 TransferDataFromWindow();
708 wxFileName::SplitPath(m_File
, NULL
, NULL
, &leaf
, NULL
, wxPATH_NATIVE
);
709 unsigned format_idx
= ((wxChoice
*)FindWindow(svx_FORMAT
))->GetSelection();
710 leaf
+= wxString::FromUTF8(extension
[format_idx
]);
712 wxString filespec
= wmsg(msg_filetype
[format_idx
]);
713 filespec
+= wxT("|*");
714 filespec
+= wxString::FromUTF8(extension
[format_idx
]);
715 filespec
+= wxT("|");
716 filespec
+= wmsg(/*All files*/208);
717 filespec
+= wxT("|");
718 filespec
+= wxFileSelectorDefaultWildcardStr
;
720 /* TRANSLATORS: Title of file dialog to choose name and type of exported
722 wxFileDialog
dlg(this, wmsg(/*Export as:*/401), wxString(), leaf
,
723 filespec
, wxFD_SAVE
|wxFD_OVERWRITE_PROMPT
);
724 if (dlg
.ShowModal() == wxID_OK
) {
725 wxString input_projection
= ((wxTextCtrl
*)FindWindow(svx_PROJ
))->GetValue();
726 double grid
= 100; // metres
727 double text_height
= 0.6;
728 double marker_size
= 0.8;
731 if (!Export(dlg
.GetPath(), m_layout
.title
,
732 m_layout
.datestamp
, m_layout
.datestamp_numeric
, mainfrm
,
733 m_layout
.rot
, m_layout
.tilt
,
734 m_layout
.get_effective_show_mask(),
735 export_format(format_idx
), input_projection
.utf8_str(),
736 grid
, text_height
, marker_size
, m_layout
.Scale
)) {
737 wxString m
= wxString::Format(wmsg(/*Couldn’t write file “%s”*/402).c_str(),
739 wxGetApp().ReportError(m
);
741 } catch (const wxString
& m
) {
742 wxGetApp().ReportError(m
);
748 #ifdef AVEN_PRINT_PREVIEW
750 svxPrintDlg::OnPreview(wxCommandEvent
&) {
752 TransferDataFromWindow();
753 wxPageSetupDialogData
* psdd
= wxGetApp().GetPageSetupDialogData();
754 wxPrintDialogData
pd(psdd
->GetPrintData());
756 pv
= new wxPrintPreview(new svxPrintout(mainfrm
, &m_layout
, psdd
, m_File
),
757 new svxPrintout(mainfrm
, &m_layout
, psdd
, m_File
),
759 // TRANSLATORS: Title of the print preview dialog
760 wxPreviewFrame
*frame
= new wxPreviewFrame(pv
, mainfrm
, wmsg(/*Print Preview*/398));
763 // Size preview frame so that all of the controlbar and canvas can be seen
766 // GetBestSize gives us the width needed to show the whole controlbar.
767 frame
->GetBestSize(&w
, &h
);
769 // On wxGTK at least, GetBestSize() returns much too small a height.
772 // Ensure that we don't make the window bigger than the screen.
773 // Use wxGetClientDisplayRect() so we don't cover the MS Windows
775 wxRect disp
= wxGetClientDisplayRect();
776 if (w
> disp
.GetWidth()) w
= disp
.GetWidth();
777 if (h
> disp
.GetHeight()) h
= disp
.GetHeight();
778 // Centre the window within the "ClientDisplayRect".
779 int x
= disp
.GetLeft() + (disp
.GetWidth() - w
) / 2;
780 int y
= disp
.GetTop() + (disp
.GetHeight() - h
) / 2;
781 frame
->SetSize(x
, y
, w
, h
);
788 svxPrintDlg::OnPlan(wxCommandEvent
&) {
789 m_tilt
->SetValue(-90.0);
790 SomethingChanged(svx_TILT
);
794 svxPrintDlg::OnElevation(wxCommandEvent
&) {
795 m_tilt
->SetValue(0.0);
796 SomethingChanged(svx_TILT
);
800 svxPrintDlg::OnPlanUpdate(wxUpdateUIEvent
& e
) {
801 e
.Enable(m_tilt
->GetValue() != -90.0);
805 svxPrintDlg::OnElevationUpdate(wxUpdateUIEvent
& e
) {
806 e
.Enable(m_tilt
->GetValue() != 0.0);
810 svxPrintDlg::OnChangeSpin(wxSpinDoubleEvent
& e
) {
811 SomethingChanged(e
.GetId());
815 svxPrintDlg::OnChange(wxCommandEvent
& e
) {
816 if (e
.GetId() == svx_SCALE
) {
817 default_scale_print
= m_scale
->GetValue();
818 if (default_scale_print
!= scales
[0]) {
819 // Don't store "One Page" for use when exporting.
820 default_scale_export
= default_scale_print
;
823 SomethingChanged(e
.GetId());
827 svxPrintDlg::OnCancel(wxCommandEvent
&) {
834 svxPrintDlg::SomethingChanged(int control_id
) {
835 if ((control_id
== 0 || control_id
== svx_FORMAT
) && m_format
) {
836 // Update the shown/hidden fields for the newly selected export filter.
837 int new_filter_idx
= m_format
->GetSelection();
838 if (new_filter_idx
!= wxNOT_FOUND
) {
839 unsigned mask
= format_info
[new_filter_idx
];
840 static const struct { int id
; unsigned mask
; } controls
[] = {
842 { svx_SURFACE
, SURF
},
843 { svx_SPLAYS
, SPLAYS
},
844 { svx_STATIONS
, STNS
},
845 { svx_NAMES
, LABELS
},
846 { svx_XSECT
, XSECT
},
847 { svx_WALLS
, WALLS
},
848 { svx_PASSAGES
, PASG
},
850 { svx_FIXES
, FIXES
},
851 { svx_EXPORTS
, EXPORTS
},
852 { svx_CENTRED
, CENTRED
},
853 { svx_FULLCOORDS
, FULL_COORDS
},
854 { svx_PROJ_LABEL
, PROJ
},
857 static unsigned n_controls
= sizeof(controls
) / sizeof(controls
[0]);
858 for (unsigned i
= 0; i
!= n_controls
; ++i
) {
859 wxWindow
* control
= FindWindow(controls
[i
].id
);
860 if (control
) control
->Show(mask
& controls
[i
].mask
);
862 m_scalebox
->Show(bool(mask
& SCALE
));
863 m_viewbox
->Show(!bool(mask
& EXPORT_3D
));
864 GetSizer()->Layout();
865 if (control_id
== svx_FORMAT
) {
866 wxConfigBase
* cfg
= wxConfigBase::Get();
867 cfg
->Write(wxT("export_format"), formats
[new_filter_idx
]);
874 if (m_printSize
|| m_scale
) {
875 // Update the bounding box.
879 if (!(m_scale
->GetValue()).ToDouble(&(m_layout
.Scale
)) ||
880 m_layout
.Scale
== 0.0) {
881 m_layout
.pick_scale(1, 1);
886 if (m_printSize
&& m_layout
.xMax
>= m_layout
.xMin
) {
887 m_layout
.pages_required();
888 m_printSize
->SetLabel(wxString::Format(wmsg(/*%d pages (%dx%d)*/257), m_layout
.pages
, m_layout
.pagesX
, m_layout
.pagesY
));
893 svxPrintDlg::LayoutToUI()
895 // m_blanks->SetValue(m_layout.SkipBlank);
896 if (m_layout
.view
!= layout::EXTELEV
) {
897 m_tilt
->SetValue(m_layout
.tilt
);
898 m_bearing
->SetValue(m_layout
.rot
);
901 if (m_scale
&& m_layout
.Scale
!= 0) {
902 // Do this last as it causes an OnChange message which calls UIToLayout
904 temp
<< m_layout
.Scale
;
905 m_scale
->SetValue(temp
);
910 svxPrintDlg::UIToLayout()
912 // m_layout.SkipBlank = m_blanks->IsChecked();
914 if (m_layout
.view
!= layout::EXTELEV
&& m_tilt
) {
915 m_layout
.tilt
= m_tilt
->GetValue();
916 if (m_layout
.tilt
== -90.0) {
917 m_layout
.view
= layout::PLAN
;
918 } else if (m_layout
.tilt
== 0.0) {
919 m_layout
.view
= layout::ELEV
;
921 m_layout
.view
= layout::TILT
;
924 bool enable_passage_opts
= (m_layout
.view
!= layout::TILT
);
926 win
= FindWindow(svx_XSECT
);
927 if (win
) win
->Enable(enable_passage_opts
);
928 win
= FindWindow(svx_WALLS
);
929 if (win
) win
->Enable(enable_passage_opts
);
930 win
= FindWindow(svx_PASSAGES
);
931 if (win
) win
->Enable(enable_passage_opts
);
933 m_layout
.rot
= m_bearing
->GetValue();
938 svxPrintDlg::RecalcBounds()
940 m_layout
.yMax
= m_layout
.xMax
= -DBL_MAX
;
941 m_layout
.yMin
= m_layout
.xMin
= DBL_MAX
;
943 double SIN
= sin(rad(m_layout
.rot
));
944 double COS
= cos(rad(m_layout
.rot
));
945 double SINT
= sin(rad(m_layout
.tilt
));
946 double COST
= cos(rad(m_layout
.tilt
));
948 int show_mask
= m_layout
.get_effective_show_mask();
949 if (show_mask
& LEGS
) {
950 list
<traverse
>::const_iterator trav
= mainfrm
->traverses_begin();
951 list
<traverse
>::const_iterator tend
= mainfrm
->traverses_end();
952 for ( ; trav
!= tend
; ++trav
) {
953 if (trav
->isSplay
&& !(show_mask
& SPLAYS
))
955 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
956 vector
<PointInfo
>::const_iterator end
= trav
->end();
957 for ( ; pos
!= end
; ++pos
) {
958 double x
= pos
->GetX();
959 double y
= pos
->GetY();
960 double z
= pos
->GetZ();
961 double X
= x
* COS
- y
* SIN
;
962 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
963 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
964 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
965 if (Y
> m_layout
.yMax
) m_layout
.yMax
= Y
;
966 if (Y
< m_layout
.yMin
) m_layout
.yMin
= Y
;
971 if ((show_mask
& XSECT
) &&
972 (m_layout
.tilt
== 0.0 || m_layout
.tilt
== 90.0 || m_layout
.tilt
== -90.0)) {
973 list
<vector
<XSect
> >::const_iterator trav
= mainfrm
->tubes_begin();
974 list
<vector
<XSect
> >::const_iterator tend
= mainfrm
->tubes_end();
975 for ( ; trav
!= tend
; ++trav
) {
977 Vector3
last_right(1.0, 0.0, 0.0);
979 vector
<XSect
>::const_iterator i
= trav
->begin();
980 vector
<XSect
>::size_type segment
= 0;
981 while (i
!= trav
->end()) {
982 // get the coordinates of this vertex
983 const XSect
& pt_v
= *i
++;
984 if (m_layout
.tilt
== 0.0) {
985 Double u
= pt_v
.GetU();
986 Double d
= pt_v
.GetD();
988 if (u
>= 0 || d
>= 0) {
989 double x
= pt_v
.GetX();
990 double y
= pt_v
.GetY();
991 double z
= pt_v
.GetZ();
992 double X
= x
* COS
- y
* SIN
;
993 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
995 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
996 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
997 double U
= Y
+ max(0.0, pt_v
.GetU());
998 if (U
> m_layout
.yMax
) m_layout
.yMax
= U
;
999 double D
= Y
- max(0.0, pt_v
.GetD());
1000 if (D
< m_layout
.yMin
) m_layout
.yMin
= D
;
1003 // More complex, and this duplicates the algorithm from
1004 // PlotLR() - we should try to share that, maybe via a
1008 const Vector3
up_v(0.0, 0.0, 1.0);
1011 assert(i
!= trav
->end());
1014 // get the coordinates of the next vertex
1015 const XSect
& next_pt_v
= *i
;
1017 // calculate vector from this pt to the next one
1018 Vector3 leg_v
= next_pt_v
- pt_v
;
1020 // obtain a vector in the LRUD plane
1021 right
= leg_v
* up_v
;
1022 if (right
.magnitude() == 0) {
1027 } else if (segment
+ 1 == trav
->size()) {
1030 // Calculate vector from the previous pt to this one.
1031 Vector3 leg_v
= pt_v
- prev_pt_v
;
1033 // Obtain a horizontal vector in the LRUD plane.
1034 right
= leg_v
* up_v
;
1035 if (right
.magnitude() == 0) {
1036 right
= Vector3(last_right
.GetX(), last_right
.GetY(), 0.0);
1041 assert(i
!= trav
->end());
1042 // Intermediate segment.
1044 // Get the coordinates of the next vertex.
1045 const XSect
& next_pt_v
= *i
;
1047 // Calculate vectors from this vertex to the
1048 // next vertex, and from the previous vertex to
1050 Vector3 leg1_v
= pt_v
- prev_pt_v
;
1051 Vector3 leg2_v
= next_pt_v
- pt_v
;
1053 // Obtain horizontal vectors perpendicular to
1054 // both legs, then normalise and average to get
1055 // a horizontal bisector.
1056 Vector3 r1
= leg1_v
* up_v
;
1057 Vector3 r2
= leg2_v
* up_v
;
1061 if (right
.magnitude() == 0) {
1062 // This is the "mid-pitch" case...
1068 // Scale to unit vectors in the LRUD plane.
1071 Double l
= pt_v
.GetL();
1072 Double r
= pt_v
.GetR();
1074 if (l
>= 0 || r
>= 0) {
1075 // Get the x and y coordinates of the survey station
1076 double pt_X
= pt_v
.GetX() * COS
- pt_v
.GetY() * SIN
;
1077 double pt_Y
= pt_v
.GetX() * SIN
+ pt_v
.GetY() * COS
;
1081 // Get the x and y coordinates of the end of the left arrow
1082 Vector3 p
= pt_v
- right
* l
;
1083 X
= p
.GetX() * COS
- p
.GetY() * SIN
;
1084 Y
= (p
.GetX() * SIN
+ p
.GetY() * COS
);
1089 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
1090 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
1091 if (Y
> m_layout
.yMax
) m_layout
.yMax
= Y
;
1092 if (Y
< m_layout
.yMin
) m_layout
.yMin
= Y
;
1095 // Get the x and y coordinates of the end of the right arrow
1096 Vector3 p
= pt_v
+ right
* r
;
1097 X
= p
.GetX() * COS
- p
.GetY() * SIN
;
1098 Y
= (p
.GetX() * SIN
+ p
.GetY() * COS
);
1103 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
1104 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
1105 if (Y
> m_layout
.yMax
) m_layout
.yMax
= Y
;
1106 if (Y
< m_layout
.yMin
) m_layout
.yMin
= Y
;
1117 if (show_mask
& SURF
) {
1118 list
<traverse
>::const_iterator trav
= mainfrm
->surface_traverses_begin();
1119 list
<traverse
>::const_iterator tend
= mainfrm
->surface_traverses_end();
1120 for ( ; trav
!= tend
; ++trav
) {
1121 if (trav
->isSplay
&& !(show_mask
& SPLAYS
))
1123 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1124 vector
<PointInfo
>::const_iterator end
= trav
->end();
1125 for ( ; pos
!= end
; ++pos
) {
1126 double x
= pos
->GetX();
1127 double y
= pos
->GetY();
1128 double z
= pos
->GetZ();
1129 double X
= x
* COS
- y
* SIN
;
1130 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
1131 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
1132 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
1133 if (Y
> m_layout
.yMax
) m_layout
.yMax
= Y
;
1134 if (Y
< m_layout
.yMin
) m_layout
.yMin
= Y
;
1138 if (show_mask
& (LABELS
|STNS
)) {
1139 list
<LabelInfo
*>::const_iterator label
= mainfrm
->GetLabels();
1140 while (label
!= mainfrm
->GetLabelsEnd()) {
1141 double x
= (*label
)->GetX();
1142 double y
= (*label
)->GetY();
1143 double z
= (*label
)->GetZ();
1144 if ((show_mask
& SURF
) || (*label
)->IsUnderground()) {
1145 double X
= x
* COS
- y
* SIN
;
1146 if (X
> m_layout
.xMax
) m_layout
.xMax
= X
;
1147 if (X
< m_layout
.xMin
) m_layout
.xMin
= X
;
1148 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
1149 if (Y
> m_layout
.yMax
) m_layout
.yMax
= Y
;
1150 if (Y
< m_layout
.yMin
) m_layout
.yMin
= Y
;
1157 static int xpPageWidth
, ypPageDepth
;
1158 static long x_offset
, y_offset
;
1159 static int fontsize
, fontsize_labels
;
1161 /* FIXME: allow the font to be set */
1163 static const char *fontname
= "Arial", *fontname_labels
= "Arial";
1165 svxPrintout::svxPrintout(MainFrm
*mainfrm_
, layout
*l
,
1166 wxPageSetupDialogData
*data
, const wxString
& title
)
1167 : wxPrintout(title
), font_labels(NULL
), font_default(NULL
),
1168 scan_for_blank_pages(false)
1176 svxPrintout::draw_info_box()
1178 layout
*l
= m_layout
;
1182 pdc
->SetPen(*pen_frame
);
1185 if (l
->view
!= layout::EXTELEV
) {
1186 boxwidth
+= boxheight
;
1187 MOVEMM(div
, boxheight
);
1189 MOVEMM(0, 30); DRAWMM(div
, 30);
1192 MOVEMM(0, boxheight
);
1193 DRAWMM(boxwidth
, boxheight
);
1194 DRAWMM(boxwidth
, 0);
1197 DRAWMM(0, boxheight
);
1200 MOVEMM(0, 20); DRAWMM(div
, 20);
1201 MOVEMM(0, 10); DRAWMM(div
, 10);
1204 case layout::PLAN
: {
1205 long ax
, ay
, bx
, by
, cx
, cy
, dx
, dy
;
1207 long xc
= boxwidth
- boxheight
/ 2;
1208 long yc
= boxheight
/ 2;
1209 const double RADIUS
= boxheight
/ 3;
1210 DrawEllipse(long(xc
* l
->scX
), long(yc
* l
->scY
),
1211 long(RADIUS
* l
->scX
), long(RADIUS
* l
->scY
));
1213 ax
= (long)((xc
- (RADIUS
- 1) * sin(rad(000.0 + l
->rot
))) * l
->scX
);
1214 ay
= (long)((yc
+ (RADIUS
- 1) * cos(rad(000.0 + l
->rot
))) * l
->scY
);
1215 bx
= (long)((xc
- RADIUS
* 0.5 * sin(rad(180.0 + l
->rot
))) * l
->scX
);
1216 by
= (long)((yc
+ RADIUS
* 0.5 * cos(rad(180.0 + l
->rot
))) * l
->scY
);
1217 cx
= (long)((xc
- (RADIUS
- 1) * sin(rad(160.0 + l
->rot
))) * l
->scX
);
1218 cy
= (long)((yc
+ (RADIUS
- 1) * cos(rad(160.0 + l
->rot
))) * l
->scY
);
1219 dx
= (long)((xc
- (RADIUS
- 1) * sin(rad(200.0 + l
->rot
))) * l
->scX
);
1220 dy
= (long)((yc
+ (RADIUS
- 1) * cos(rad(200.0 + l
->rot
))) * l
->scY
);
1229 pdc
->SetTextForeground(colour_text
);
1230 MOVEMM(div
+ 0.5, boxheight
- 5.5);
1231 WriteString(wmsg(/*North*/115));
1233 wxString angle
= format_angle(ANGLE_FMT
, l
->rot
);
1235 /* TRANSLATORS: This is used on printouts of plans, with %s replaced by
1236 * something like "123°". The bearing is up the page. */
1237 s
.Printf(wmsg(/*Plan view, %s up page*/168), angle
.c_str());
1238 MOVEMM(2, 12); WriteString(s
);
1241 case layout::ELEV
: case layout::TILT
: {
1242 const int L
= div
+ 2;
1243 const int R
= boxwidth
- 2;
1244 const int H
= boxheight
/ 2;
1245 MOVEMM(L
, H
); DRAWMM(L
+ 5, H
- 3); DRAWMM(L
+ 3, H
); DRAWMM(L
+ 5, H
+ 3);
1247 DRAWMM(L
, H
); DRAWMM(R
, H
);
1249 DRAWMM(R
- 5, H
+ 3); DRAWMM(R
- 3, H
); DRAWMM(R
- 5, H
- 3); DRAWMM(R
, H
);
1251 MOVEMM((L
+ R
) / 2, H
- 2); DRAWMM((L
+ R
) / 2, H
+ 2);
1253 pdc
->SetTextForeground(colour_text
);
1254 MOVEMM(div
+ 2, boxheight
- 8);
1255 /* TRANSLATORS: "Elevation on" 020 <-> 200 degrees */
1256 WriteString(wmsg(/*Elevation on*/116));
1259 WriteString(format_angle(ANGLE_FMT
, fmod(l
->rot
+ 270.0, 360.0)));
1261 WriteString(format_angle(ANGLE_FMT
, fmod(l
->rot
+ 90.0, 360.0)));
1263 wxString angle
= format_angle(ANGLE_FMT
, l
->rot
);
1265 if (l
->view
== layout::ELEV
) {
1266 /* TRANSLATORS: This is used on printouts of elevations, with %s
1267 * replaced by something like "123°". The bearing is the direction
1269 s
.Printf(wmsg(/*Elevation facing %s*/169), angle
.c_str());
1271 wxString a2
= format_angle(ANGLE2_FMT
, l
->tilt
);
1272 /* TRANSLATORS: This is used on printouts of tilted elevations, with
1273 * the first %s replaced by something like "123°", and the second by
1274 * something like "-45°". The bearing is the direction we’re
1276 s
.Printf(wmsg(/*Elevation facing %s, tilted %s*/284), angle
.c_str(), a2
.c_str());
1278 MOVEMM(2, 12); WriteString(s
);
1281 case layout::EXTELEV
:
1282 pdc
->SetTextForeground(colour_text
);
1284 /* TRANSLATORS: This is used on printouts of extended elevations. */
1285 WriteString(wmsg(/*Extended elevation*/191));
1289 MOVEMM(2, boxheight
- 8); WriteString(l
->title
);
1292 // FIXME: "Original Scale" better?
1293 WriteString(wxString::Format(wmsg(/*Scale*/154) + wxT(" 1:%.0f"),
1296 /* This used to be a copyright line, but it was occasionally
1297 * mis-interpreted as us claiming copyright on the survey, so let's
1298 * give the website URL instead */
1299 MOVEMM(boxwidth
+ 2, 2);
1300 WriteString(wxT("Survex " VERSION
" - https://survex.com/"));
1302 draw_scale_bar(boxwidth
+ 10.0, 17.0, l
->PaperWidth
- boxwidth
- 18.0);
1305 /* Draw fancy scale bar with bottom left at (x,y) (both in mm) and at most */
1306 /* MaxLength mm long. The scaling in use is 1:scale */
1308 svxPrintout::draw_scale_bar(double x
, double y
, double MaxLength
)
1313 /* Limit scalebar to 20cm to stop people with A0 plotters complaining */
1314 if (MaxLength
> 200.0) MaxLength
= 200.0;
1316 #define dmin 10.0 /* each division >= dmin mm long */
1317 #define StepMax 5 /* number in steps of at most StepMax (x 10^N) */
1318 #define epsilon (1e-4) /* fudge factor to prevent rounding problems */
1320 E
= (int)ceil(log10((dmin
* 0.001 * m_layout
->Scale
) / StepMax
));
1321 StepEst
= pow(10.0, -(double)E
) * (dmin
* 0.001) * m_layout
->Scale
- epsilon
;
1323 /* Force labelling to be in multiples of 1, 2, or 5 */
1324 Step
= (StepEst
<= 1.0 ? 1 : (StepEst
<= 2.0 ? 2 : 5));
1326 /* Work out actual length of each scale bar division */
1327 d
= Step
* pow(10.0, (double)E
) / m_layout
->Scale
* 1000.0;
1329 /* FIXME: Non-metric units here... */
1330 /* Choose appropriate units, s.t. if possible E is >=0 and minimized */
1335 } else if (E
>= 0) {
1342 buf
= wmsg(/*Scale*/154);
1344 /* Add units used - eg. "Scale (10m)" */
1345 double pow10_E
= pow(10.0, (double)E
);
1347 buf
+= wxString::Format(wxT(" (%.f%s)"), pow10_E
, wmsg(units
).c_str());
1349 int sf
= -(int)floor(E
);
1350 buf
+= wxString::Format(wxT(" (%.*f%s)"), sf
, pow10_E
, wmsg(units
).c_str());
1352 pdc
->SetTextForeground(colour_text
);
1353 MOVEMM(x
, y
+ 4); WriteString(buf
);
1355 /* Work out how many divisions there will be */
1356 n
= (int)(MaxLength
/ d
);
1358 pdc
->SetPen(*pen_frame
);
1360 long Y
= long(y
* m_layout
->scY
);
1361 long Y2
= long((y
+ 3) * m_layout
->scY
);
1362 long X
= long(x
* m_layout
->scX
);
1363 long X2
= long((x
+ n
* d
) * m_layout
->scX
);
1365 /* Draw top of scale bar */
1371 MOVEMM(x
+ n
* d
, y
); DRAWMM(x
, y
);
1373 /* Draw divisions and label them */
1374 for (c
= 0; c
<= n
; c
++) {
1375 pdc
->SetPen(*pen_frame
);
1376 X
= long((x
+ c
* d
) * m_layout
->scX
);
1379 #if 0 // Don't waste toner!
1380 /* Draw a "zebra crossing" scale bar. */
1381 if (c
< n
&& (c
& 1) == 0) {
1382 X2
= long((x
+ (c
+ 1) * d
) * m_layout
->scX
);
1383 SolidRectangle(X
, Y
, X2
- X
, Y2
- Y
);
1386 buf
.Printf(wxT("%d"), c
* Step
);
1387 pdc
->SetTextForeground(colour_text
);
1388 MOVEMM(x
+ c
* d
- buf
.length(), y
- 5);
1395 make_calibration(layout
*l
) {
1396 img_point pt
= { 0.0, 0.0, 0.0 };
1397 l
->xMax
= l
->yMax
= 0.1;
1398 l
->xMin
= l
->yMin
= 0;
1400 stack(l
, img_MOVE
, NULL
, &pt
);
1402 stack(l
, img_LINE
, NULL
, &pt
);
1404 stack(l
, img_LINE
, NULL
, &pt
);
1406 stack(l
, img_LINE
, NULL
, &pt
);
1408 stack(l
, img_LINE
, NULL
, &pt
);
1411 stack(l
, img_LABEL
, "10cm", &pt
);
1414 stack(l
, img_LABEL
, "10cm", &pt
);
1420 svxPrintout::next_page(int *pstate
, char **q
, int pageLim
)
1429 wxASSERT(*p
== '-');
1431 while (isspace((unsigned char)*p
)) p
++;
1432 if (sscanf(p
, "%u%n", &page
, &c
) > 0) {
1437 if (*pstate
> page
) goto err
;
1438 if (*pstate
< page
) return *pstate
;
1444 while (isspace((unsigned char)*p
) || *p
== ',') p
++;
1446 if (!*p
) return 0; /* done */
1451 return 1; /* range with initial parameter omitted */
1453 if (sscanf(p
, "%u%n", &page
, &c
) > 0) {
1455 while (isspace((unsigned char)*p
)) p
++;
1457 if (0 < page
&& page
<= pageLim
) {
1458 if (*p
== '-') *pstate
= page
; /* range with start */
1467 /* Draws in alignment marks on each page or borders on edge pages */
1469 svxPrintout::drawticks(int tsize
, int x
, int y
)
1474 bool fAtCorner
= fFalse
;
1475 pdc
->SetPen(*pen_frame
);
1476 if (x
== 0 && m_layout
->Border
) {
1477 /* solid left border */
1478 MoveTo(clip
.x_min
, clip
.y_min
);
1479 DrawTo(clip
.x_min
, clip
.y_max
);
1482 if (x
> 0 || y
> 0) {
1483 MoveTo(clip
.x_min
, clip
.y_min
);
1484 DrawTo(clip
.x_min
, clip
.y_min
+ tsize
);
1486 if (s
&& x
> 0 && m_layout
->Cutlines
) {
1487 /* dashed left border */
1488 i
= (clip
.y_max
- clip
.y_min
) -
1489 (tsize
+ ((clip
.y_max
- clip
.y_min
- tsize
* 2L) % s
) / 2);
1490 for ( ; i
> tsize
; i
-= s
) {
1491 MoveTo(clip
.x_min
, clip
.y_max
- (i
+ o
));
1492 DrawTo(clip
.x_min
, clip
.y_max
- (i
- o
));
1495 if (x
> 0 || y
< m_layout
->pagesY
- 1) {
1496 MoveTo(clip
.x_min
, clip
.y_max
- tsize
);
1497 DrawTo(clip
.x_min
, clip
.y_max
);
1502 if (y
== m_layout
->pagesY
- 1 && m_layout
->Border
) {
1503 /* solid top border */
1504 if (!fAtCorner
) MoveTo(clip
.x_min
, clip
.y_max
);
1505 DrawTo(clip
.x_max
, clip
.y_max
);
1508 if (y
< m_layout
->pagesY
- 1 || x
> 0) {
1509 if (!fAtCorner
) MoveTo(clip
.x_min
, clip
.y_max
);
1510 DrawTo(clip
.x_min
+ tsize
, clip
.y_max
);
1512 if (s
&& y
< m_layout
->pagesY
- 1 && m_layout
->Cutlines
) {
1513 /* dashed top border */
1514 i
= (clip
.x_max
- clip
.x_min
) -
1515 (tsize
+ ((clip
.x_max
- clip
.x_min
- tsize
* 2L) % s
) / 2);
1516 for ( ; i
> tsize
; i
-= s
) {
1517 MoveTo(clip
.x_max
- (i
+ o
), clip
.y_max
);
1518 DrawTo(clip
.x_max
- (i
- o
), clip
.y_max
);
1521 if (y
< m_layout
->pagesY
- 1 || x
< m_layout
->pagesX
- 1) {
1522 MoveTo(clip
.x_max
- tsize
, clip
.y_max
);
1523 DrawTo(clip
.x_max
, clip
.y_max
);
1530 if (x
== m_layout
->pagesX
- 1 && m_layout
->Border
) {
1531 /* solid right border */
1532 if (!fAtCorner
) MoveTo(clip
.x_max
, clip
.y_max
);
1533 DrawTo(clip
.x_max
, clip
.y_min
);
1536 if (x
< m_layout
->pagesX
- 1 || y
< m_layout
->pagesY
- 1) {
1537 if (!fAtCorner
) MoveTo(clip
.x_max
, clip
.y_max
);
1538 DrawTo(clip
.x_max
, clip
.y_max
- tsize
);
1540 if (s
&& x
< m_layout
->pagesX
- 1 && m_layout
->Cutlines
) {
1541 /* dashed right border */
1542 i
= (clip
.y_max
- clip
.y_min
) -
1543 (tsize
+ ((clip
.y_max
- clip
.y_min
- tsize
* 2L) % s
) / 2);
1544 for ( ; i
> tsize
; i
-= s
) {
1545 MoveTo(clip
.x_max
, clip
.y_min
+ (i
+ o
));
1546 DrawTo(clip
.x_max
, clip
.y_min
+ (i
- o
));
1549 if (x
< m_layout
->pagesX
- 1 || y
> 0) {
1550 MoveTo(clip
.x_max
, clip
.y_min
+ tsize
);
1551 DrawTo(clip
.x_max
, clip
.y_min
);
1558 if (y
== 0 && m_layout
->Border
) {
1559 /* solid bottom border */
1560 if (!fAtCorner
) MoveTo(clip
.x_max
, clip
.y_min
);
1561 DrawTo(clip
.x_min
, clip
.y_min
);
1563 if (y
> 0 || x
< m_layout
->pagesX
- 1) {
1564 if (!fAtCorner
) MoveTo(clip
.x_max
, clip
.y_min
);
1565 DrawTo(clip
.x_max
- tsize
, clip
.y_min
);
1567 if (s
&& y
> 0 && m_layout
->Cutlines
) {
1568 /* dashed bottom border */
1569 i
= (clip
.x_max
- clip
.x_min
) -
1570 (tsize
+ ((clip
.x_max
- clip
.x_min
- tsize
* 2L) % s
) / 2);
1571 for ( ; i
> tsize
; i
-= s
) {
1572 MoveTo(clip
.x_min
+ (i
+ o
), clip
.y_min
);
1573 DrawTo(clip
.x_min
+ (i
- o
), clip
.y_min
);
1576 if (y
> 0 || x
> 0) {
1577 MoveTo(clip
.x_min
+ tsize
, clip
.y_min
);
1578 DrawTo(clip
.x_min
, clip
.y_min
);
1584 svxPrintout::OnPrintPage(int pageNum
) {
1585 GetPageSizePixels(&xpPageWidth
, &ypPageDepth
);
1587 pdc
->SetBackgroundMode(wxTRANSPARENT
);
1588 #ifdef AVEN_PRINT_PREVIEW
1591 pdc
->GetSize(&dcx
, &dcy
);
1592 pdc
->SetUserScale((double)dcx
/ xpPageWidth
, (double)dcy
/ ypPageDepth
);
1596 layout
* l
= m_layout
;
1599 GetPageSizeMM(&pwidth
, &pdepth
);
1600 l
->scX
= (double)xpPageWidth
/ pwidth
;
1601 l
->scY
= (double)ypPageDepth
/ pdepth
;
1602 font_scaling_x
= l
->scX
* (25.4 / 72.0);
1603 font_scaling_y
= l
->scY
* (25.4 / 72.0);
1604 long MarginLeft
= m_data
->GetMarginTopLeft().x
;
1605 long MarginTop
= m_data
->GetMarginTopLeft().y
;
1606 long MarginBottom
= m_data
->GetMarginBottomRight().y
;
1607 long MarginRight
= m_data
->GetMarginBottomRight().x
;
1608 xpPageWidth
-= (int)(l
->scX
* (MarginLeft
+ MarginRight
));
1609 ypPageDepth
-= (int)(l
->scY
* (FOOTER_HEIGHT_MM
+ MarginBottom
+ MarginTop
));
1610 // xpPageWidth -= 1;
1611 pdepth
-= FOOTER_HEIGHT_MM
;
1612 x_offset
= (long)(l
->scX
* MarginLeft
);
1613 y_offset
= (long)(l
->scY
* MarginTop
);
1614 l
->PaperWidth
= pwidth
-= MarginLeft
+ MarginRight
;
1615 l
->PaperDepth
= pdepth
-= MarginTop
+ MarginBottom
;
1618 double SIN
= sin(rad(l
->rot
));
1619 double COS
= cos(rad(l
->rot
));
1620 double SINT
= sin(rad(l
->tilt
));
1621 double COST
= cos(rad(l
->tilt
));
1623 NewPage(pageNum
, l
->pagesX
, l
->pagesY
);
1625 if (l
->Legend
&& pageNum
== (l
->pagesY
- 1) * l
->pagesX
+ 1) {
1626 SetFont(font_default
);
1630 pdc
->SetClippingRegion(x_offset
, y_offset
, xpPageWidth
+ 1, ypPageDepth
+ 1);
1632 const double Sc
= 1000 / l
->Scale
;
1634 int show_mask
= l
->get_effective_show_mask();
1635 if (show_mask
& LEGS
) {
1636 list
<traverse
>::const_iterator trav
= mainfrm
->traverses_begin();
1637 list
<traverse
>::const_iterator tend
= mainfrm
->traverses_end();
1638 for ( ; trav
!= tend
; ++trav
) {
1639 if (trav
->isSplay
) {
1640 if (!(show_mask
& SPLAYS
))
1642 pdc
->SetPen(*pen_splay
);
1644 pdc
->SetPen(*pen_leg
);
1646 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1647 vector
<PointInfo
>::const_iterator end
= trav
->end();
1648 for ( ; pos
!= end
; ++pos
) {
1649 double x
= pos
->GetX();
1650 double y
= pos
->GetY();
1651 double z
= pos
->GetZ();
1652 double X
= x
* COS
- y
* SIN
;
1653 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
1654 long px
= (long)((X
* Sc
+ l
->xOrg
) * l
->scX
);
1655 long py
= (long)((Y
* Sc
+ l
->yOrg
) * l
->scY
);
1656 if (pos
== trav
->begin()) {
1665 if ((show_mask
& XSECT
) &&
1666 (l
->tilt
== 0.0 || l
->tilt
== 90.0 || l
->tilt
== -90.0)) {
1667 pdc
->SetPen(*pen_splay
);
1668 list
<vector
<XSect
> >::const_iterator trav
= mainfrm
->tubes_begin();
1669 list
<vector
<XSect
> >::const_iterator tend
= mainfrm
->tubes_end();
1670 for ( ; trav
!= tend
; ++trav
) {
1671 if (l
->tilt
== 0.0) {
1674 // m_layout.tilt is 90.0 or -90.0 due to check above.
1680 if (show_mask
& SURF
) {
1681 list
<traverse
>::const_iterator trav
= mainfrm
->surface_traverses_begin();
1682 list
<traverse
>::const_iterator tend
= mainfrm
->surface_traverses_end();
1683 for ( ; trav
!= tend
; ++trav
) {
1684 if (trav
->isSplay
) {
1685 if (!(show_mask
& SPLAYS
))
1687 pdc
->SetPen(*pen_splay
);
1689 pdc
->SetPen(*pen_surface_leg
);
1691 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1692 vector
<PointInfo
>::const_iterator end
= trav
->end();
1693 for ( ; pos
!= end
; ++pos
) {
1694 double x
= pos
->GetX();
1695 double y
= pos
->GetY();
1696 double z
= pos
->GetZ();
1697 double X
= x
* COS
- y
* SIN
;
1698 double Y
= z
* COST
- (x
* SIN
+ y
* COS
) * SINT
;
1699 long px
= (long)((X
* Sc
+ l
->xOrg
) * l
->scX
);
1700 long py
= (long)((Y
* Sc
+ l
->yOrg
) * l
->scY
);
1701 if (pos
== trav
->begin()) {
1710 if (show_mask
& (LABELS
|STNS
)) {
1711 if (show_mask
& LABELS
) SetFont(font_labels
);
1712 list
<LabelInfo
*>::const_iterator label
= mainfrm
->GetLabels();
1713 while (label
!= mainfrm
->GetLabelsEnd()) {
1714 double px
= (*label
)->GetX();
1715 double py
= (*label
)->GetY();
1716 double pz
= (*label
)->GetZ();
1717 if ((show_mask
& SURF
) || (*label
)->IsUnderground()) {
1718 double X
= px
* COS
- py
* SIN
;
1719 double Y
= pz
* COST
- (px
* SIN
+ py
* COS
) * SINT
;
1721 xnew
= (long)((X
* Sc
+ l
->xOrg
) * l
->scX
);
1722 ynew
= (long)((Y
* Sc
+ l
->yOrg
) * l
->scY
);
1723 if (show_mask
& STNS
) {
1724 pdc
->SetPen(*pen_cross
);
1725 DrawCross(xnew
, ynew
);
1727 if (show_mask
& LABELS
) {
1728 pdc
->SetTextForeground(colour_labels
);
1730 WriteString((*label
)->GetText());
1741 svxPrintout::GetPageInfo(int *minPage
, int *maxPage
,
1742 int *pageFrom
, int *pageTo
)
1744 *minPage
= *pageFrom
= 1;
1745 *maxPage
= *pageTo
= m_layout
->pages
;
1749 svxPrintout::HasPage(int pageNum
) {
1750 return (pageNum
<= m_layout
->pages
);
1754 svxPrintout::OnBeginPrinting() {
1755 /* Initialise printer routines */
1756 fontsize_labels
= 10;
1759 colour_text
= colour_labels
= *wxBLACK
;
1761 wxColour colour_frame
, colour_cross
, colour_leg
, colour_surface_leg
;
1762 colour_frame
= colour_cross
= colour_leg
= colour_surface_leg
= *wxBLACK
;
1764 pen_frame
= new wxPen(colour_frame
);
1765 pen_cross
= new wxPen(colour_cross
);
1766 pen_leg
= new wxPen(colour_leg
);
1767 pen_surface_leg
= new wxPen(colour_surface_leg
);
1768 pen_splay
= new wxPen(wxColour(192, 192, 192));
1773 font_labels
= new wxFont(fontsize_labels
, wxDEFAULT
, wxNORMAL
, wxNORMAL
,
1774 false, wxString(fontname_labels
, wxConvUTF8
),
1775 wxFONTENCODING_ISO8859_1
);
1776 font_default
= new wxFont(fontsize
, wxDEFAULT
, wxNORMAL
, wxNORMAL
,
1777 false, wxString(fontname
, wxConvUTF8
),
1778 wxFONTENCODING_ISO8859_1
);
1782 svxPrintout::OnEndPrinting() {
1784 delete font_default
;
1788 delete pen_surface_leg
;
1793 svxPrintout::check_intersection(long x_p
, long y_p
)
1799 int mask_p
= 0, mask_t
= 0;
1802 else if (x_p
> xpPageWidth
)
1807 else if (y_p
> ypPageDepth
)
1812 else if (x_t
> xpPageWidth
)
1817 else if (y_t
> ypPageDepth
)
1821 /* approximation to correct answer */
1822 return !(mask_t
& mask_p
);
1824 /* One end of the line is on the page */
1825 if (!mask_t
|| !mask_p
) return 1;
1827 /* whole line is above, left, right, or below page */
1828 if (mask_t
& mask_p
) return 0;
1830 if (mask_t
== 0) mask_t
= mask_p
;
1832 double v
= (double)(y_p
- ypPageDepth
) / (y_p
- y_t
);
1833 return v
>= 0 && v
<= 1;
1836 double v
= (double)y_p
/ (y_p
- y_t
);
1837 return v
>= 0 && v
<= 1;
1840 double v
= (double)(x_p
- xpPageWidth
) / (x_p
- x_t
);
1841 return v
>= 0 && v
<= 1;
1843 wxASSERT(mask_t
& L
);
1845 double v
= (double)x_p
/ (x_p
- x_t
);
1846 return v
>= 0 && v
<= 1;
1856 svxPrintout::MoveTo(long x
, long y
)
1858 x_t
= x_offset
+ x
- clip
.x_min
;
1859 y_t
= y_offset
+ clip
.y_max
- y
;
1863 svxPrintout::DrawTo(long x
, long y
)
1865 long x_p
= x_t
, y_p
= y_t
;
1866 x_t
= x_offset
+ x
- clip
.x_min
;
1867 y_t
= y_offset
+ clip
.y_max
- y
;
1868 if (!scan_for_blank_pages
) {
1869 pdc
->DrawLine(x_p
, y_p
, x_t
, y_t
);
1871 if (check_intersection(x_p
, y_p
)) fBlankPage
= fFalse
;
1875 #define POINTS_PER_INCH 72.0
1876 #define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
1877 #define PWX_CROSS_SIZE (int)(2 * m_layout->scX / POINTS_PER_MM)
1880 svxPrintout::DrawCross(long x
, long y
)
1882 if (!scan_for_blank_pages
) {
1883 MoveTo(x
- PWX_CROSS_SIZE
, y
- PWX_CROSS_SIZE
);
1884 DrawTo(x
+ PWX_CROSS_SIZE
, y
+ PWX_CROSS_SIZE
);
1885 MoveTo(x
+ PWX_CROSS_SIZE
, y
- PWX_CROSS_SIZE
);
1886 DrawTo(x
- PWX_CROSS_SIZE
, y
+ PWX_CROSS_SIZE
);
1889 if ((x
+ PWX_CROSS_SIZE
> clip
.x_min
&&
1890 x
- PWX_CROSS_SIZE
< clip
.x_max
) ||
1891 (y
+ PWX_CROSS_SIZE
> clip
.y_min
&&
1892 y
- PWX_CROSS_SIZE
< clip
.y_max
)) {
1893 fBlankPage
= fFalse
;
1899 svxPrintout::WriteString(const wxString
& s
)
1902 pdc
->GetUserScale(&xsc
, &ysc
);
1903 pdc
->SetUserScale(xsc
* font_scaling_x
, ysc
* font_scaling_y
);
1904 if (!scan_for_blank_pages
) {
1906 long(x_t
/ font_scaling_x
),
1907 long(y_t
/ font_scaling_y
) - pdc
->GetCharHeight());
1910 pdc
->GetTextExtent(s
, &w
, &h
);
1911 if ((y_t
+ h
> 0 && y_t
- h
< clip
.y_max
- clip
.y_min
) ||
1912 (x_t
< clip
.x_max
- clip
.x_min
&& x_t
+ w
> 0)) {
1913 fBlankPage
= fFalse
;
1916 pdc
->SetUserScale(xsc
, ysc
);
1920 svxPrintout::DrawEllipse(long x
, long y
, long r
, long R
)
1922 if (!scan_for_blank_pages
) {
1923 x_t
= x_offset
+ x
- clip
.x_min
;
1924 y_t
= y_offset
+ clip
.y_max
- y
;
1925 const wxBrush
& save_brush
= pdc
->GetBrush();
1926 pdc
->SetBrush(*wxTRANSPARENT_BRUSH
);
1927 pdc
->DrawEllipse(x_t
- r
, y_t
- R
, 2 * r
, 2 * R
);
1928 pdc
->SetBrush(save_brush
);
1930 /* No need to check - this is only used in the legend. */
1935 svxPrintout::SolidRectangle(long x
, long y
, long w
, long h
)
1937 long X
= x_offset
+ x
- clip
.x_min
;
1938 long Y
= y_offset
+ clip
.y_max
- y
;
1939 pdc
->SetBrush(*wxBLACK_BRUSH
);
1940 pdc
->DrawRectangle(X
, Y
- h
, w
, h
);
1944 svxPrintout::NewPage(int pg
, int pagesX
, int pagesY
)
1946 pdc
->DestroyClippingRegion();
1949 x
= (pg
- 1) % pagesX
;
1950 y
= pagesY
- 1 - ((pg
- 1) / pagesX
);
1952 clip
.x_min
= (long)x
* xpPageWidth
;
1953 clip
.y_min
= (long)y
* ypPageDepth
;
1954 clip
.x_max
= clip
.x_min
+ xpPageWidth
; /* dm/pcl/ps had -1; */
1955 clip
.y_max
= clip
.y_min
+ ypPageDepth
; /* dm/pcl/ps had -1; */
1957 const int FOOTERS
= 4;
1958 wxString footer
[FOOTERS
];
1959 footer
[0] = m_layout
->title
;
1961 double rot
= m_layout
->rot
;
1962 double tilt
= m_layout
->tilt
;
1963 double scale
= m_layout
->Scale
;
1964 switch (m_layout
->view
) {
1966 // TRANSLATORS: Used in the footer of printouts to compactly
1967 // indicate this is a plan view and what the viewing angle is.
1968 // Aven will replace %s with the bearing, and %.0f with the scale.
1970 // This message probably doesn't need translating for most languages.
1971 footer
[1].Printf(wmsg(/*↑%s 1:%.0f*/233),
1972 format_angle(ANGLE_FMT
, rot
).c_str(),
1976 // TRANSLATORS: Used in the footer of printouts to compactly
1977 // indicate this is an elevation view and what the viewing angle
1978 // is. Aven will replace the %s codes with the bearings to the
1979 // left and right of the viewer, and %.0f with the scale.
1981 // This message probably doesn't need translating for most languages.
1982 footer
[1].Printf(wmsg(/*%s↔%s 1:%.0f*/235),
1983 format_angle(ANGLE_FMT
, fmod(rot
+ 270.0, 360.0)).c_str(),
1984 format_angle(ANGLE_FMT
, fmod(rot
+ 90.0, 360.0)).c_str(),
1988 // TRANSLATORS: Used in the footer of printouts to compactly
1989 // indicate this is a tilted elevation view and what the viewing
1990 // angles are. Aven will replace the %s codes with the bearings to
1991 // the left and right of the viewer and the angle the view is
1992 // tilted at, and %.0f with the scale.
1994 // This message probably doesn't need translating for most languages.
1995 footer
[1].Printf(wmsg(/*%s↔%s ∡%s 1:%.0f*/236),
1996 format_angle(ANGLE_FMT
, fmod(rot
+ 270.0, 360.0)).c_str(),
1997 format_angle(ANGLE_FMT
, fmod(rot
+ 90.0, 360.0)).c_str(),
1998 format_angle(ANGLE2_FMT
, tilt
).c_str(),
2001 case layout::EXTELEV
:
2002 // TRANSLATORS: Used in the footer of printouts to compactly
2003 // indicate this is an extended elevation view. Aven will replace
2004 // %.0f with the scale.
2006 // Try to keep the translation short (for example, in English we
2007 // use "Extended" not "Extended elevation") - there is limited room
2008 // in the footer, and the details there are mostly to make it easy
2009 // to check that you have corresponding pages from a multiple page
2011 footer
[1].Printf(wmsg(/*Extended 1:%.0f*/244), scale
);
2015 // TRANSLATORS: N/M meaning page N of M in the page footer of a printout.
2016 footer
[2].Printf(wmsg(/*%d/%d*/232), pg
, m_layout
->pagesX
* m_layout
->pagesY
);
2018 wxString datestamp
= m_layout
->datestamp
;
2019 if (!datestamp
.empty()) {
2020 // Remove any timezone suffix (e.g. " UTC" or " +1200").
2021 wxChar ch
= datestamp
[datestamp
.size() - 1];
2022 if (ch
>= 'A' && ch
<= 'Z') {
2023 for (size_t i
= datestamp
.size() - 1; i
; --i
) {
2025 if (ch
< 'A' || ch
> 'Z') {
2026 if (ch
== ' ') datestamp
.resize(i
);
2030 } else if (ch
>= '0' && ch
<= '9') {
2031 for (size_t i
= datestamp
.size() - 1; i
; --i
) {
2033 if (ch
< '0' || ch
> '9') {
2034 if ((ch
== '-' || ch
== '+') && datestamp
[--i
] == ' ')
2035 datestamp
.resize(i
);
2041 // Remove any day prefix (e.g. "Mon,").
2042 for (size_t i
= 0; i
!= datestamp
.size(); ++i
) {
2043 if (datestamp
[i
] == ',' && i
+ 1 != datestamp
.size()) {
2044 // Also skip a space after the comma.
2045 if (datestamp
[i
+ 1] == ' ') ++i
;
2046 datestamp
.erase(0, i
+ 1);
2052 // TRANSLATORS: Used in the footer of printouts to compactly indicate that
2053 // the date which follows is the date that the survey data was processed.
2055 // Aven will replace %s with a string giving the date and time (e.g.
2056 // "2015-06-09 12:40:44").
2057 footer
[3].Printf(wmsg(/*Processed: %s*/167), datestamp
.c_str());
2059 const wxChar
* footer_sep
= wxT(" ");
2060 int fontsize_footer
= fontsize_labels
;
2061 wxFont
* font_footer
;
2062 font_footer
= new wxFont(fontsize_footer
, wxDEFAULT
, wxNORMAL
, wxNORMAL
,
2063 false, wxString(fontname_labels
, wxConvUTF8
),
2064 wxFONTENCODING_UTF8
);
2065 font_footer
->Scale(font_scaling_x
);
2066 SetFont(font_footer
);
2067 int w
[FOOTERS
], ws
, h
;
2068 pdc
->GetTextExtent(footer_sep
, &ws
, &h
);
2069 int wtotal
= ws
* (FOOTERS
- 1);
2070 for (int i
= 0; i
< FOOTERS
; ++i
) {
2071 pdc
->GetTextExtent(footer
[i
], &w
[i
], &h
);
2076 long Y
= y_offset
+ ypPageDepth
+ (long)(7 * m_layout
->scY
) - pdc
->GetCharHeight();
2078 if (wtotal
> xpPageWidth
) {
2079 // Rescale the footer so it fits.
2080 double rescale
= double(wtotal
) / xpPageWidth
;
2082 pdc
->GetUserScale(&xsc
, &ysc
);
2083 pdc
->SetUserScale(xsc
/ rescale
, ysc
/ rescale
);
2084 SetFont(font_footer
);
2085 wxString fullfooter
= footer
[0];
2086 for (int i
= 1; i
< FOOTERS
- 1; ++i
) {
2087 fullfooter
+= footer_sep
;
2088 fullfooter
+= footer
[i
];
2090 pdc
->DrawText(fullfooter
, X
* rescale
, Y
* rescale
);
2091 // Draw final item right aligned to avoid misaligning.
2092 wxRect
rect(x_offset
* rescale
, Y
* rescale
,
2093 xpPageWidth
* rescale
, pdc
->GetCharHeight() * rescale
);
2094 pdc
->DrawLabel(footer
[FOOTERS
- 1], rect
, wxALIGN_RIGHT
|wxALIGN_TOP
);
2095 pdc
->SetUserScale(xsc
, ysc
);
2097 // Space out the elements of the footer to fill the line.
2098 double extra
= double(xpPageWidth
- wtotal
) / (FOOTERS
- 1);
2099 for (int i
= 0; i
< FOOTERS
- 1; ++i
) {
2100 pdc
->DrawText(footer
[i
], X
+ extra
* i
, Y
);
2103 // Draw final item right aligned to avoid misaligning.
2104 wxRect
rect(x_offset
, Y
, xpPageWidth
, pdc
->GetCharHeight());
2105 pdc
->DrawLabel(footer
[FOOTERS
- 1], rect
, wxALIGN_RIGHT
|wxALIGN_TOP
);
2107 drawticks((int)(9 * m_layout
->scX
/ POINTS_PER_MM
), x
, y
);
2111 svxPrintout::PlotLR(const vector
<XSect
> & centreline
)
2113 assert(centreline
.size() > 1);
2115 Vector3
last_right(1.0, 0.0, 0.0);
2117 const double Sc
= 1000 / m_layout
->Scale
;
2118 const double SIN
= sin(rad(m_layout
->rot
));
2119 const double COS
= cos(rad(m_layout
->rot
));
2121 vector
<XSect
>::const_iterator i
= centreline
.begin();
2122 vector
<XSect
>::size_type segment
= 0;
2123 while (i
!= centreline
.end()) {
2124 // get the coordinates of this vertex
2125 const XSect
& pt_v
= *i
++;
2129 const Vector3
up_v(0.0, 0.0, 1.0);
2132 assert(i
!= centreline
.end());
2135 // get the coordinates of the next vertex
2136 const XSect
& next_pt_v
= *i
;
2138 // calculate vector from this pt to the next one
2139 Vector3 leg_v
= next_pt_v
- pt_v
;
2141 // obtain a vector in the LRUD plane
2142 right
= leg_v
* up_v
;
2143 if (right
.magnitude() == 0) {
2148 } else if (segment
+ 1 == centreline
.size()) {
2151 // Calculate vector from the previous pt to this one.
2152 Vector3 leg_v
= pt_v
- prev_pt_v
;
2154 // Obtain a horizontal vector in the LRUD plane.
2155 right
= leg_v
* up_v
;
2156 if (right
.magnitude() == 0) {
2157 right
= Vector3(last_right
.GetX(), last_right
.GetY(), 0.0);
2162 assert(i
!= centreline
.end());
2163 // Intermediate segment.
2165 // Get the coordinates of the next vertex.
2166 const XSect
& next_pt_v
= *i
;
2168 // Calculate vectors from this vertex to the
2169 // next vertex, and from the previous vertex to
2171 Vector3 leg1_v
= pt_v
- prev_pt_v
;
2172 Vector3 leg2_v
= next_pt_v
- pt_v
;
2174 // Obtain horizontal vectors perpendicular to
2175 // both legs, then normalise and average to get
2176 // a horizontal bisector.
2177 Vector3 r1
= leg1_v
* up_v
;
2178 Vector3 r2
= leg2_v
* up_v
;
2182 if (right
.magnitude() == 0) {
2183 // This is the "mid-pitch" case...
2189 // Scale to unit vectors in the LRUD plane.
2192 Double l
= pt_v
.GetL();
2193 Double r
= pt_v
.GetR();
2195 if (l
>= 0 || r
>= 0) {
2196 // Get the x and y coordinates of the survey station
2197 double pt_X
= pt_v
.GetX() * COS
- pt_v
.GetY() * SIN
;
2198 double pt_Y
= pt_v
.GetX() * SIN
+ pt_v
.GetY() * COS
;
2199 long pt_x
= (long)((pt_X
* Sc
+ m_layout
->xOrg
) * m_layout
->scX
);
2200 long pt_y
= (long)((pt_Y
* Sc
+ m_layout
->yOrg
) * m_layout
->scY
);
2202 // Calculate dimensions for the right arrow
2203 double COSR
= right
.GetX();
2204 double SINR
= right
.GetY();
2205 long CROSS_MAJOR
= (COSR
+ SINR
) * PWX_CROSS_SIZE
;
2206 long CROSS_MINOR
= (COSR
- SINR
) * PWX_CROSS_SIZE
;
2209 // Get the x and y coordinates of the end of the left arrow
2210 Vector3 p
= pt_v
- right
* l
;
2211 double X
= p
.GetX() * COS
- p
.GetY() * SIN
;
2212 double Y
= (p
.GetX() * SIN
+ p
.GetY() * COS
);
2213 long x
= (long)((X
* Sc
+ m_layout
->xOrg
) * m_layout
->scX
);
2214 long y
= (long)((Y
* Sc
+ m_layout
->yOrg
) * m_layout
->scY
);
2216 // Draw the arrow stem
2220 // Rotate the arrow by the page rotation
2221 long dx1
= (+CROSS_MINOR
) * COS
- (+CROSS_MAJOR
) * SIN
;
2222 long dy1
= (+CROSS_MINOR
) * SIN
+ (+CROSS_MAJOR
) * COS
;
2223 long dx2
= (+CROSS_MAJOR
) * COS
- (-CROSS_MINOR
) * SIN
;
2224 long dy2
= (+CROSS_MAJOR
) * SIN
+ (-CROSS_MINOR
) * COS
;
2227 MoveTo(x
+ dx1
, y
+ dy1
);
2229 DrawTo(x
+ dx2
, y
+ dy2
);
2233 // Get the x and y coordinates of the end of the right arrow
2234 Vector3 p
= pt_v
+ right
* r
;
2235 double X
= p
.GetX() * COS
- p
.GetY() * SIN
;
2236 double Y
= (p
.GetX() * SIN
+ p
.GetY() * COS
);
2237 long x
= (long)((X
* Sc
+ m_layout
->xOrg
) * m_layout
->scX
);
2238 long y
= (long)((Y
* Sc
+ m_layout
->yOrg
) * m_layout
->scY
);
2240 // Draw the arrow stem
2244 // Rotate the arrow by the page rotation
2245 long dx1
= (-CROSS_MINOR
) * COS
- (-CROSS_MAJOR
) * SIN
;
2246 long dy1
= (-CROSS_MINOR
) * SIN
+ (-CROSS_MAJOR
) * COS
;
2247 long dx2
= (-CROSS_MAJOR
) * COS
- (+CROSS_MINOR
) * SIN
;
2248 long dy2
= (-CROSS_MAJOR
) * SIN
+ (+CROSS_MINOR
) * COS
;
2251 MoveTo(x
+ dx1
, y
+ dy1
);
2253 DrawTo(x
+ dx2
, y
+ dy2
);
2264 svxPrintout::PlotUD(const vector
<XSect
> & centreline
)
2266 assert(centreline
.size() > 1);
2267 const double Sc
= 1000 / m_layout
->Scale
;
2269 vector
<XSect
>::const_iterator i
= centreline
.begin();
2270 while (i
!= centreline
.end()) {
2271 // get the coordinates of this vertex
2272 const XSect
& pt_v
= *i
++;
2274 Double u
= pt_v
.GetU();
2275 Double d
= pt_v
.GetD();
2277 if (u
>= 0 || d
>= 0) {
2278 // Get the coordinates of the survey point
2280 double SIN
= sin(rad(m_layout
->rot
));
2281 double COS
= cos(rad(m_layout
->rot
));
2282 double X
= p
.GetX() * COS
- p
.GetY() * SIN
;
2283 double Y
= p
.GetZ();
2284 long x
= (long)((X
* Sc
+ m_layout
->xOrg
) * m_layout
->scX
);
2285 long pt_y
= (long)((Y
* Sc
+ m_layout
->yOrg
) * m_layout
->scX
);
2288 // Get the y coordinate of the up arrow
2289 long y
= (long)(((Y
+ u
) * Sc
+ m_layout
->yOrg
) * m_layout
->scY
);
2291 // Draw the arrow stem
2295 // Draw the up arrow
2296 MoveTo(x
- PWX_CROSS_SIZE
, y
- PWX_CROSS_SIZE
);
2298 DrawTo(x
+ PWX_CROSS_SIZE
, y
- PWX_CROSS_SIZE
);
2302 // Get the y coordinate of the down arrow
2303 long y
= (long)(((Y
- d
) * Sc
+ m_layout
->yOrg
) * m_layout
->scY
);
2305 // Draw the arrow stem
2309 // Draw the down arrow
2310 MoveTo(x
- PWX_CROSS_SIZE
, y
+ PWX_CROSS_SIZE
);
2312 DrawTo(x
+ PWX_CROSS_SIZE
, y
+ PWX_CROSS_SIZE
);