/home/martin/workspace/OpenStreetNav/src/displayer/MapDrawingArea.cpp
Go to the documentation of this file.
00001 /*
00002  * MapDrawingArea.cpp
00003  *
00004  *  Created on: Nov 14, 2011
00005  *      Author: martin
00006  */
00007 
00008 #include "MapDrawingArea.h"
00009 #include <cmath>
00010 #include <iostream>
00011 #include "../util.h"
00012 #include <set>
00013 
00014 namespace display
00015 {
00016 
00017 MapDrawingArea::MapDrawingArea(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder> &):
00018     Gtk::DrawingArea(cobject),
00019     pressed(false),
00020     zoom(6),
00021     tran_x(0),
00022     tran_y(0),
00023     topleft(-1, -1),
00024     bottomright(1, 1),
00025     lat(0),
00026     lon(0)
00027 {
00028     add_events(Gdk::SCROLL_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK);
00029     setup_projection();
00030     setup_surfaces();
00031     setup_bounds();
00032 }
00033 
00034 void MapDrawingArea::add_dp(int priority, std::shared_ptr<DisplayProvider> dp)
00035 {
00036     dps.insert(std::pair<int, std::shared_ptr<DisplayProvider> >(-priority, dp));
00037     if (dps.size() == 1)
00038     {
00039         lat = dp->center_lat();
00040         lon = dp->center_lon();
00041     }
00042     after_change();
00043 }
00044 
00045 MapDrawingArea::~MapDrawingArea()
00046 {
00047 }
00048 
00049 bool MapDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> & cr)
00050 {
00051     cr->translate(tran_x, tran_y);
00052     cr->set_source(surface, 0, 0);
00053     cr->paint();
00054     return true;
00055 }
00056 
00057 bool MapDrawingArea::on_button_press_event(GdkEventButton* event)
00058 {
00059     if (event->button == 3)
00060     {
00061         pressed = true;
00062         press_x = event->x;
00063         press_y = event->y;
00064     }
00065     if (event->button == 1)
00066     {
00067         double new_x = event->x;
00068         double new_y = event->y;
00069         inverse.transform_point(new_x, new_y);
00070         auto p1 = proj->unproject(new_x - 0.01, new_y - 0.01);
00071         auto p2 = proj->unproject(new_x + 0.01, new_y + 0.01);
00072         auto v = get_selected(p1, p2, zoom);
00073         element_clicked(v);
00074     }
00075     return true;
00076 }
00077 
00078 bool MapDrawingArea::on_button_release_event(GdkEventButton* event)
00079 {
00080     if (event->button == 3)
00081     {
00082         tran_x = 0;
00083         tran_y = 0;
00084         pressed = false;
00085         move_center(press_x - event->x, press_y - event->y);
00086         after_change();
00087     }
00088     return true;
00089 }
00090 
00091 bool MapDrawingArea::on_motion_notify_event(GdkEventMotion* event)
00092 {
00093     if (pressed)
00094     {
00095         tran_x = event->x - press_x;
00096         tran_y = event->y - press_y;
00097         invalidate();
00098     }
00099     return true;
00100 }
00101 
00102 bool MapDrawingArea::on_leave_notify_event(GdkEventCrossing*)
00103 {
00104     return true;
00105 }
00106 
00107 bool MapDrawingArea::on_enter_notify_event(GdkEventCrossing*)
00108 {
00109     return true;
00110 }
00111 
00112 bool MapDrawingArea::on_scroll_event(GdkEventScroll* event)
00113 {
00114     int z = zoom;
00115     switch (event->direction)
00116     {
00117         case GDK_SCROLL_UP:
00118             z = set_zoom(zoom + 1);
00119             break;
00120         case GDK_SCROLL_DOWN:
00121             z = set_zoom(zoom - 1);
00122             break;
00123         default:
00124             break;
00125     }
00126     if (z != zoom)
00127     {
00128         after_change();
00129         zoom_changed(zoom);
00130     }
00131     return true;
00132 }
00133 
00134 void MapDrawingArea::on_size_allocate(Gtk::Allocation& alloc)
00135 {
00136     DrawingArea::on_size_allocate(alloc);
00137     setup_surfaces();
00138     setup_bounds();
00139     after_change();
00140 }
00141 
00142 void MapDrawingArea::setup_surfaces()
00143 {
00144     surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, get_width(), get_height());
00145 }
00146 
00147 void MapDrawingArea::setup_bounds()
00148 {
00149     double x1, x2, y1, y2;
00150     double scale;
00151     if (get_width() > get_height())
00152     {
00153         x1 = -1;
00154         x2 = 1;
00155         y1 = (double)((get_height())) / (double)((get_width()));
00156         y2 = -y1;
00157         scale = get_width();
00158     }
00159     else
00160     {
00161         x2 = ((double)(get_width())) / (double)((get_height()));
00162         x1 = -x2;
00163         y1 = 1;
00164         y2 = -1;
00165         scale = get_height();
00166     }
00167     topleft = proj::FlatPoint(x1, y1);
00168     bottomright = proj::FlatPoint(x2, y2);
00169     inverse = Cairo::identity_matrix();
00170     if (scale > 0)
00171     {
00172         inverse.scale(scale / 2.0, scale / 2.0);
00173     }
00174     inverse.translate(get_width() / scale, get_height() / scale);
00175     inverse.scale(1, -1);
00176     matrix = inverse;
00177     inverse.invert();
00178 }
00179 
00180 void MapDrawingArea::setup_projection()
00181 {
00182     proj = std::unique_ptr < proj::MapProjection > (new proj::OrthoProjection(geo::Point(lat, lon), get_radius_for_zoom()));
00183 }
00184 
00185 void MapDrawingArea::redraw_from_db()
00186 {
00187     auto cr = Cairo::Context::create(surface);
00188     cr->transform(matrix);
00189     cr->set_source_rgb(0, 0, 0);
00190     cr->paint();
00191     cr->set_line_width(0.005);
00192     cr->set_source_rgb(0.8, 0.8, 0.8);
00193 
00194     class DisplayElemPtrLess
00195     {
00196     public:
00197         bool operator()(DisplayElement* a, DisplayElement* b)
00198         {
00199             return *a < *b;
00200         }
00201     };
00202     std::set<DisplayElement*, DisplayElemPtrLess> displayed;
00203     for (auto it = dps.begin(); it != dps.end(); ++it)
00204     {
00205         auto const& vect = it->second->get_display_elements();
00206         for (unsigned int i = 0; i < vect.size(); ++i)
00207         {
00208             if (displayed.find(vect[i].get()) == displayed.end())
00209             {
00210                 vect[i]->draw(cr, *proj);
00211                 displayed.insert(vect[i].get());
00212             }
00213         }
00214     }
00215     invalidate();
00216 }
00217 
00218 void MapDrawingArea::invalidate()
00219 {
00220     Glib::RefPtr<Gdk::Window> win = get_window();
00221     if (win)
00222     {
00223         Gdk::Rectangle r(0, 0, get_allocation().get_width(), get_allocation().get_height());
00224         win->invalidate_rect(r, false);
00225     }
00226 }
00227 
00228 void MapDrawingArea::after_change()
00229 {
00230     setup_projection();
00231     setup_db();
00232     redraw_from_db();
00233 }
00234 
00235 void MapDrawingArea::move_center(double x, double y)
00236 {
00237     x += get_width() / 2.0;
00238     y += get_height() / 2.0;
00239     inverse.transform_point(x, y);
00240     auto p = proj->unproject(x, y);
00241     lat = p.lat;
00242     lon = p.lon;
00243 }
00244 
00245 double MapDrawingArea::get_radius_for_zoom()
00246 {
00247     return (double)(((((((8 << zoom)))))));
00248 }
00249 
00250 void MapDrawingArea::setup_db()
00251 {
00252     geo::Point tl = proj->unproject(topleft);
00253     geo::Point br = proj->unproject(bottomright);
00254     geo::Point tr = proj->unproject(bottomright.x, topleft.y);
00255     geo::Point bl = proj->unproject(topleft.x, bottomright.y);
00256     for (auto it = dps.begin(); it != dps.end(); ++it)
00257         it->second->set_bounds(geo::Point(std::max(tl.lat, tr.lat), std::min(tl.lon, bl.lon)), geo::Point(std::min(br.lat, bl.lat), std::max(br.lon, tr.lon)), zoom);
00258 }
00259 
00260 int MapDrawingArea::set_zoom(int z)
00261 {
00262     zoom = std::max(std::min(z, 15), 1);
00263     after_change();
00264     zoom_changed(zoom);
00265     return zoom;
00266 }
00267 
00268 void MapDrawingArea::set_latitude(double lat)
00269 {
00270     this->lat = lat;
00271 }
00272 
00273 void MapDrawingArea::set_longitude(double lon)
00274 {
00275     this->lon = lon;
00276 }
00277 
00278 int MapDrawingArea::get_zoom()
00279 {
00280     return zoom;
00281 }
00282 
00283 std::vector<std::unique_ptr<osm::Element> > MapDrawingArea::get_selected(const geo::Point& p1, const geo::Point& p2, int zoom)
00284 {
00285     std::vector<std::unique_ptr<osm::Element> > ret;
00286 
00287     for (auto it = dps.begin(); it != dps.end(); ++it)
00288     {
00289         auto v(std::move(it->second->get_selected(p1, p2, zoom)));
00290         for (unsigned int i = 0; i < v.size(); ++i)
00291         {
00292             if (util::find<decltype(osm::deref_eq_by_id(v[i], v[i]))>(ret.begin(), ret.end(), v[i]) == ret.end())
00293                 ret.push_back(std::move(v[i]));
00294         }
00295     }
00296     return ret;
00297 }
00298 
00299 } /* namespace display */
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines