00001
00002
00003
00004
00005
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 }