1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Use, modification and distribution is subject to the Boost Software License,
5 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // wxWidgets World Mapper example
11 // #define EXAMPLE_WX_USE_GRAPHICS_CONTEXT 1
16 #include <boost/foreach.hpp>
17 #include <boost/shared_ptr.hpp>
18 #include <boost/scoped_array.hpp>
20 #include <boost/geometry/geometry.hpp>
21 #include <boost/geometry/geometries/geometries.hpp>
22 #include <boost/geometry/geometries/point_xy.hpp>
23 #include <boost/geometry/geometries/multi_geometries.hpp>
25 #include <boost/geometry/geometries/register/point.hpp>
26 #include <boost/geometry/geometries/register/ring.hpp>
27 #include <boost/geometry/extensions/algorithms/selected.hpp>
30 // wxWidgets, if these headers are NOT found, adapt include path (and lib path)
34 #include "wx/stockitem.h"
37 #ifdef EXAMPLE_WX_USE_GRAPHICS_CONTEXT
38 #include "wx/graphics.h"
39 #include "wx/dcgraph.h"
42 typedef boost::geometry::model::d2::point_xy
<double> point_2d
;
43 typedef boost::geometry::model::multi_polygon
45 boost::geometry::model::polygon
<point_2d
>
48 // Adapt wxWidgets points to Boost.Geometry points such that they can be used
49 // in e.g. transformations (see below)
50 BOOST_GEOMETRY_REGISTER_POINT_2D(wxPoint
, int, cs::cartesian
, x
, y
)
51 BOOST_GEOMETRY_REGISTER_POINT_2D(wxRealPoint
, double, cs::cartesian
, x
, y
)
54 // wxWidgets draws using wxPoint*, so we HAVE to use that.
55 // Therefore have to make a wxPoint* array
56 // 1) compatible with Boost.Geometry
57 // 2) compatible with Boost.Range (required by Boost.Geometry)
58 // 3) compatible with std::back_inserter (required by Boost.Geometry)
61 typedef std::pair
<wxPoint
*,wxPoint
*> wxPointPointerPair
;
64 BOOST_GEOMETRY_REGISTER_RING(wxPointPointerPair
);
68 // Specialize back_insert_iterator for the wxPointPointerPair
69 // (has to be done within "namespace std")
74 class back_insert_iterator
<wxPointPointerPair
>
77 typedef std::output_iterator_tag iterator_category
;
78 typedef void value_type
;
79 typedef void difference_type
;
81 typedef void reference
;
83 typedef wxPointPointerPair container_type
;
85 explicit back_insert_iterator(wxPointPointerPair
& x
)
86 : current(boost::begin(x
))
90 inline back_insert_iterator
<wxPointPointerPair
>&
91 operator=(wxPoint
const& value
)
93 // Check if not passed beyond
102 inline back_insert_iterator
<wxPointPointerPair
>& operator*() { return *this; }
103 inline back_insert_iterator
<wxPointPointerPair
>& operator++() { return *this; }
104 inline back_insert_iterator
<wxPointPointerPair
>& operator++(int) { return *this; }
107 boost::range_iterator
<wxPointPointerPair
>::type current
, end
;
113 // ----------------------------------------------------------------------------
114 // Read an ASCII file containing WKT's
115 // ----------------------------------------------------------------------------
116 template <typename Geometry
, typename Box
>
117 inline void read_wkt(std::string
const& filename
, std::vector
<Geometry
>& geometries
, Box
& box
)
119 std::ifstream
cpp_file(filename
.c_str());
120 if (cpp_file
.is_open())
122 while (! cpp_file
.eof() )
125 std::getline(cpp_file
, line
);
129 boost::geometry::read_wkt(line
, geometry
);
130 geometries
.push_back(geometry
);
131 boost::geometry::expand(box
, boost::geometry::return_envelope
<Box
>(geometry
));
138 // ----------------------------------------------------------------------------
139 class HelloWorldFrame
: public wxFrame
142 HelloWorldFrame(wxFrame
*frame
, wxString
const& title
, wxPoint
const& pos
, wxSize
const& size
);
144 void OnCloseWindow(wxCloseEvent
& );
145 void OnExit(wxCommandEvent
& );
147 DECLARE_EVENT_TABLE()
151 // ----------------------------------------------------------------------------
152 class HelloWorldCanvas
: public wxWindow
155 HelloWorldCanvas(wxFrame
*frame
);
158 void DrawCountries(wxDC
& dc
);
159 void DrawCountry(wxDC
& dc
, country_type
const& country
);
161 void OnPaint(wxPaintEvent
& );
162 void OnMouseMove(wxMouseEvent
&);
164 typedef boost::geometry::strategy::transform::map_transformer
168 > map_transformer_type
;
170 typedef boost::geometry::strategy::transform::inverse_transformer
173 > inverse_transformer_type
;
175 boost::shared_ptr
<map_transformer_type
> m_map_transformer
;
176 boost::shared_ptr
<inverse_transformer_type
> m_inverse_transformer
;
178 boost::geometry::model::box
<point_2d
> m_box
;
179 std::vector
<country_type
> m_countries
;
185 DECLARE_EVENT_TABLE()
190 // ----------------------------------------------------------------------------
191 class HelloWorldApp
: public wxApp
196 // Create the main frame window
197 HelloWorldFrame
*frame
= new HelloWorldFrame(NULL
, _T("Boost.Geometry for wxWidgets - Hello World!"), wxDefaultPosition
, wxSize(640, 480));
199 wxMenu
*file_menu
= new wxMenu
;
200 file_menu
->Append(wxID_EXIT
, wxGetStockLabel(wxID_EXIT
));
201 wxMenuBar
* menuBar
= new wxMenuBar
;
202 menuBar
->Append(file_menu
, _T("&File"));
203 frame
->SetMenuBar(menuBar
);
206 frame
->GetClientSize(&width
, &height
);
208 (void) new HelloWorldCanvas(frame
);
219 // ----------------------------------------------------------------------------
220 HelloWorldFrame::HelloWorldFrame(wxFrame
*frame
, wxString
const& title
, wxPoint
const& pos
, wxSize
const& size
)
221 : wxFrame(frame
, wxID_ANY
, title
, pos
, size
, wxDEFAULT_FRAME_STYLE
| wxFULL_REPAINT_ON_RESIZE
)
227 void HelloWorldFrame::OnExit(wxCommandEvent
& )
232 void HelloWorldFrame::OnCloseWindow(wxCloseEvent
& )
234 static bool destroyed
= false;
243 // ----------------------------------------------------------------------------
244 HelloWorldCanvas::HelloWorldCanvas(wxFrame
*frame
)
245 : wxWindow(frame
, wxID_ANY
)
249 boost::geometry::assign_inverse(m_box
);
250 read_wkt("../data/world.wkt", m_countries
, m_box
);
251 m_orange
= wxBrush(wxColour(255, 128, 0), wxSOLID
);
256 void HelloWorldCanvas::OnMouseMove(wxMouseEvent
&event
)
258 namespace bg
= boost::geometry
;
260 if (m_inverse_transformer
)
262 // Boiler-plate wxWidgets code
265 m_owner
->PrepareDC(dc
);
267 // Transform the point to Lon/Lat
269 bg::transform(event
.GetPosition(), point
, *m_inverse_transformer
);
271 // Determine selected object
273 int previous_focus
= m_focus
;
275 BOOST_FOREACH(country_type
const& country
, m_countries
)
277 if (bg::selected(country
, point
, 0))
285 if (m_focus
!= previous_focus
)
288 if (previous_focus
>= 0)
290 dc
.SetBrush(*wxWHITE_BRUSH
);
291 DrawCountry(dc
, m_countries
[previous_focus
]);
296 dc
.SetBrush(m_orange
);
297 DrawCountry(dc
, m_countries
[m_focus
]);
301 // Create a string and set it in the status text
302 std::ostringstream out
;
303 out
<< "Position: " << point
.x() << ", " << point
.y();
304 m_owner
->SetStatusText(wxString(out
.str().c_str(), wxConvUTF8
));
310 void HelloWorldCanvas::OnPaint(wxPaintEvent
& )
312 #if defined(EXAMPLE_WX_USE_GRAPHICS_CONTEXT)
315 wxDC
& dc
= (wxDC
&) gdc
;
322 static bool running
= false;
327 // Update the transformers
328 wxSize sz
= dc
.GetSize();
329 m_map_transformer
.reset(new map_transformer_type(m_box
, sz
.x
, sz
.y
));
330 m_inverse_transformer
.reset(new inverse_transformer_type(*m_map_transformer
));
339 void HelloWorldCanvas::DrawCountries(wxDC
& dc
)
341 namespace bg
= boost::geometry
;
343 dc
.SetBackground(*wxLIGHT_GREY_BRUSH
);
346 BOOST_FOREACH(country_type
const& country
, m_countries
)
348 DrawCountry(dc
, country
);
352 dc
.SetBrush(m_orange
);
353 DrawCountry(dc
, m_countries
[m_focus
]);
358 void HelloWorldCanvas::DrawCountry(wxDC
& dc
, country_type
const& country
)
360 namespace bg
= boost::geometry
;
362 BOOST_FOREACH(bg::model::polygon
<point_2d
> const& poly
, country
)
364 // Use only exterior ring, holes are (for the moment) ignored. This would need
365 // a holey-polygon compatible wx object
367 std::size_t n
= boost::size(bg::exterior_ring(poly
));
369 boost::scoped_array
<wxPoint
> points(new wxPoint
[n
]);
371 wxPointPointerPair pair
= std::make_pair(points
.get(), points
.get() + n
);
372 bg::transform(bg::exterior_ring(poly
), pair
, *m_map_transformer
);
374 dc
.DrawPolygon(n
, points
.get());
378 // ----------------------------------------------------------------------------
381 BEGIN_EVENT_TABLE(HelloWorldFrame
, wxFrame
)
382 EVT_CLOSE(HelloWorldFrame::OnCloseWindow
)
383 EVT_MENU(wxID_EXIT
, HelloWorldFrame::OnExit
)
387 BEGIN_EVENT_TABLE(HelloWorldCanvas
, wxWindow
)
388 EVT_PAINT(HelloWorldCanvas::OnPaint
)
389 EVT_MOTION(HelloWorldCanvas::OnMouseMove
)
393 IMPLEMENT_APP(HelloWorldApp
)