#define RM_DISABLE_WCHAR #include #include #include #include #include #include #include #include using namespace relational; typedef double Float; typedef int ID; const Float R = 6371.0; const Float TWOPI = 2.0*3.1415926536; typedef std::pair SortOrder; RM_DEFINE_ROW_6(LocationRow, indexed, location, indexed, z, Float, x, Float, y, int, neighbours, SortOrder, sortorder); class Location : public LocationRow { std::string m_city; public: Location() { } Location(int id0, const std::string &name, const std::string &city, Float lon_deg, Float lat_deg) : m_city(city) { sortorder.second = name; location = id0; Float lat_rad = lat_deg * TWOPI / 360.0; Float lon_rad = lon_deg * TWOPI / 360.0; // Convert polar to Cartesian coordinates x = R * cos(lat_rad) * sin(lon_rad); y = R * cos(lat_rad) * cos(lon_rad); z = R * sin(lat_rad); } const std::string &getName() const { return sortorder.second; } const std::string &getCity() const { return m_city; } Float euclideanDistance2(const Location &other) const { Float dx = x - other.x; Float dy = y - other.y; Float dz = z - other.z; return dx*dx + dy*dy + dz*dz; } }; class WorldMap { table m_locations; Float m_cutoff, m_cutoff2; class AddLocation { WorldMap &m_wm; Location &m_location; public: AddLocation(WorldMap &m, Location &l) : m_wm(m), m_location(l), count(0) { } void operator()(const Location &loc) { if(m_location.euclideanDistance2(loc) <= m_wm.m_cutoff2) { ++count; m_wm.m_locations.update_row(loc, loc.neighbours+1); } } int count; }; class RemoveLocation { WorldMap &m_wm; const Location &m_location; public: RemoveLocation(WorldMap &m, const Location &l) : m_wm(m), m_location(l) { } void operator()(const Location &loc) { if(loc.euclideanDistance2(m_location) <= m_wm.m_cutoff2) { m_wm.m_locations.update_row(loc, loc.neighbours-1); } } }; struct PrintLocation { std::ostream &m_os; public: PrintLocation(std::ostream &os) : m_os(os) { } void operator()(const Location &loc) { m_os << std::setw(8) << loc.location << std::setw(15) << loc.getCity() << std::setw(15) << loc.getName() << std::setw(6) << loc.neighbours << std::endl; } }; public: WorldMap(Float c) : m_cutoff(c), m_cutoff2(c*c) { } void addLocation(Location &loc) { AddLocation add(*this, loc); for_each(select(m_locations, m_locations.x>=loc.x-m_cutoff && m_locations.x<=loc.x+m_cutoff && m_locations.y>=loc.y-m_cutoff && m_locations.y<=loc.y+m_cutoff && m_locations.z>=loc.z-m_cutoff && m_locations.z<=loc.z+m_cutoff), add); loc.neighbours = add.count; m_locations.insert(loc); } void removeLocation(ID location) { const Location &loc = find_ex(select(m_locations, m_locations.location == location)); RemoveLocation remove(*this, loc); relational::for_each(select(m_locations, m_locations.x>=loc.x-m_cutoff && m_locations.x<=loc.x+m_cutoff && m_locations.y>=loc.y-m_cutoff && m_locations.y<=loc.y+m_cutoff && m_locations.z>=loc.z-m_cutoff && m_locations.z<=loc.z+m_cutoff), remove); m_locations.erase_row(loc); } void listHighestConnectivity(std::ostream &os, int n) { // This is a horrible hack because RML does not yet have the capability to // sort on multiple columns for(table::iterator i=m_locations.begin(); i!=m_locations.end(); ++i) const_cast(*i).sortorder.first = -i->neighbours; PrintLocation pl(os); for_each(limit(sort(m_locations.sortorder, m_locations),n), pl); os << "There are " << m_locations.size() << " locations\n"; } void removeHighestConnectivity() { removeLocation(find_ex(sort(m_locations.sortorder, m_locations)).location); } }; void acquireRealData(std::vector &data) { // This is a hack not production quality code std::ifstream file("aslatlong.txt"); while(file) { char line[500]; file.getline(line, 500); if(file.gcount()>40 && line[0]!='#') { char *p = strtok(line, "\t"); // Never use strtok in production code int id = atoi(p); p = strtok(0, "\t"); Float lat = atof(p); p = strtok(0, "\t"); Float lon = atof(p); p = strtok(0, "\t"); std::string name(p); p = strtok(0, "\t"); data.push_back(Location(id, name, p, lat, lon)); } } } void test(Float cutoff, std::vector &data, int count) { clock_t t0, t1, t2; std::ostringstream ss; WorldMap wm(cutoff); try { t0 = clock(); for(std::vector::iterator i=data.begin(); i!=data.end(); ++i) wm.addLocation(*i); wm.listHighestConnectivity(ss, count); t1 = clock(); wm.removeHighestConnectivity(); wm.listHighestConnectivity(ss, count); t2= clock(); } catch(duplicate_key&) { ss << "Test failed because of a duplicate id\n"; } std::cout << ss.str(); std::cout << "Insert time = " << (1000*(t1-t0))/CLOCKS_PER_SEC << " milliseconds\n"; std::cout << "Delete and redisplay = " << (1000*(t2-t1))/CLOCKS_PER_SEC << " milliseconds\n"; } int main(int argc, char *argv[]) { std::vector data; acquireRealData(data); test(5.0, data, 50); return 0; }