bool insert(T newData, float x, float y) { //std::cout << "["<< depth <<"] " << newData << " at " << x << " , " << y << " \n"; //Make sure point is within the bounds of this node if (!isPointInRange(x, y, bounds)) { //std::cout << "point not in bounds\n"; //Point is not within bounds return false; } //Node isn't full yet, so add data to this node if (!tL && data.size() < maxCapacity) { QuadPoint<T> newPoint; newPoint.x = x; newPoint.y = y; newPoint.data = newData; data.push_back(newPoint); return true; } //Safety max depth if (depth >= MAX_TREE_DEPTH) { std::cout << "\033[31mWARNING: Max tree depth (" << MAX_TREE_DEPTH << ") reached!\033[0m\n"; //return false; } //Node is full; subdivide (if not already subdivided) if (!tL) { subdivide(); /*if (tL->subdivideInsert(newData, x, y)) return true; if (tR->subdivideInsert(newData, x, y)) return true; if (bL->subdivideInsert(newData, x, y)) return true; if (bR->subdivideInsert(newData, x, y)) return true; //Point wouldn't be accepted by any nodes //std::cout <<"point rejected; keeping\n"; QuadPoint<T> newPoint; newPoint.x = x; newPoint.y = y; newPoint.data = newData; data.push_back(newPoint); return true;*/ } //If already subdivided, try inserting into child nodes if (tL->insert(newData, x, y)) return true; if (tR->insert(newData, x, y)) return true; if (bL->insert(newData, x, y)) return true; if (bR->insert(newData, x, y)) return true; //Shouldn't ever happen //std::cout << "This shouldn't happen\n"; return false; }
void qtreeinit() { quadtree.insert(Line2D(Point2D(100,100),Point2D(100,150))); quadtree.insert(Line2D(Point2D(300,100),Point2D(300,150))); quadtree.insert(Line2D(Point2D(450,320),Point2D(600,320))); quadtree.insert(Line2D(Point2D(50,360),Point2D(50,385))); quadtree.insert(Line2D(Point2D(150,360),Point2D(150,398))); quadtree.insert(Line2D(Point2D(150,405),Point2D(250,405))); quadtree.insert(Line2D(Point2D(150,760),Point2D(150,785))); }
/*bool subdivideInsert(T newData, float x, float y) { //std::cout << this << "\n"; //std::cout << "subdiv insert bounds: " << bounds.x << " , " << bounds.y << " w " << bounds.w << " h " << bounds.h; //std::cout << "; is in range: "; //Make sure point is within the bounds of this node if (!isPointInRange(x, y, bounds)) { //std::cout << "rejected b/c bounds\n"; //Point is not within bounds return false; } //Node isn't full yet, so add data to this node if (data.size() < maxCapacity) { QuadPoint<T> newPoint; newPoint.x = x; newPoint.y = y; newPoint.data = newData; data.push_back(newPoint); //std::cout << "data added\n"; return true; } //Node is already full; don't try to add any more //std::cout << "rejected b/c full\n"; return false; }*/ void subdivide() { float halfWidth = bounds.w/2; float halfHeight = bounds.h/2; tL = new QuadTree<T>(maxCapacity, bounds.x, bounds.y, halfWidth, halfHeight, depth); tR = new QuadTree<T>(maxCapacity, bounds.x + halfWidth, bounds.y, halfWidth, halfHeight, depth); bL = new QuadTree<T>(maxCapacity, bounds.x, bounds.y + halfHeight, halfWidth, halfHeight, depth); bR = new QuadTree<T>(maxCapacity, bounds.x + halfWidth, bounds.y + halfHeight, halfWidth, halfHeight, depth); //Redistribute points into child nodes while(!data.empty()) { //std::cout << "REDIS\n"; QuadPoint<T> newDataPoint = data.back(); T newData = newDataPoint.data; float x = newDataPoint.x; float y = newDataPoint.y; //std::cout << "redis tl\n"; if (tL->insert(newData, x, y)) { //std::cout << "success\n"; data.pop_back(); continue; } //std::cout << "redis tr\n"; if (tR->insert(newData, x, y)) { //std::cout << "success\n"; data.pop_back(); continue; } //std::cout << "redis bl\n"; if (bL->insert(newData, x, y)) { //std::cout << "success\n"; data.pop_back(); continue; } //std::cout << "redis br\n"; if (bR->insert(newData, x, y)) { //std::cout << "success\n"; data.pop_back(); continue; } //For some reason a point will not be accepted, so //stop redistributing //std::cout << "[!] point not accepted\n"; break; } }
bool ZoneContainerComponent::insertActiveArea(Zone* newZone, ActiveArea* activeArea) { if (newZone == NULL) return false; if (!activeArea->isDeplyoed()) activeArea->deploy(); Zone* zone = activeArea->getZone(); ManagedReference<SceneObject*> thisLocker = activeArea; Locker zoneLocker(newZone); if (activeArea->isInQuadTree() && newZone != zone) { activeArea->error("trying to insert to zone an object that is already in a different quadtree"); activeArea->destroyObjectFromWorld(true); //StackTrace::printStackTrace(); } activeArea->setZone(newZone); QuadTree* regionTree = newZone->getRegionTree(); regionTree->insert(activeArea); //regionTree->inRange(activeArea, 512); // lets update area to the in range players SortedVector<QuadTreeEntry*> objects; float range = activeArea->getRadius() + 64; newZone->getInRangeObjects(activeArea->getPositionX(), activeArea->getPositionY(), range, &objects, false); for (int i = 0; i < objects.size(); ++i) { SceneObject* object = cast<SceneObject*>(objects.get(i)); if (!object->isTangibleObject()) { continue; } TangibleObject* tano = cast<TangibleObject*>(object); Vector3 worldPos = object->getWorldPosition(); if (!tano->hasActiveArea(activeArea) && activeArea->containsPoint(worldPos.getX(), worldPos.getY())) { tano->addActiveArea(activeArea); activeArea->enqueueEnterEvent(object); } } newZone->addSceneObject(activeArea); return true; }
void build_tree(QuadTree& tree) { high_resolution_clock::time_point t = high_resolution_clock::now(); double _min = 0, _max = 0; for (int i = 0; i < num_body; ++i) { Body& t = bodies[i]; _min = min(_min, min(t.x, t.y)); _max = max(_max, max(t.x, t.y)); } if (gui) { draw_points(0); draw_lines(_min, _max, _max, _max); draw_lines(_min, _min, _max, _min); draw_lines(_min, _min, _min, _max); draw_lines(_max, _min, _max, _max); } tree.set_region({_min, _max}, {_max, _min}); for (int i = 0; i < num_body; ++i) tree.insert(bodies[i]); build_time += timeit(t); if (gui) draw_points(1); }
// Rebuilds a possibly incorrect tree (LAURENS: This function is not tested yet!) void QuadTree::rebuildTree() { for(int n = 0; n < size; n++) { // Check whether point is erroneous double* point = data + index[n] * QT_NO_DIMS; if(!boundary.containsPoint(point)) { // Remove erroneous point int rem_index = index[n]; for(int m = n + 1; m < size; m++) index[m - 1] = index[m]; index[size - 1] = -1; size--; // Update center-of-mass and counter in all parents bool done = false; QuadTree* node = this; while(!done) { for(int d = 0; d < QT_NO_DIMS; d++) { node->center_of_mass[d] = ((double) node->cum_size * node->center_of_mass[d] - point[d]) / (double) (node->cum_size - 1); } node->cum_size--; if(node->getParent() == NULL) done = true; else node = node->getParent(); } // Reinsert point in the root tree node->insert(rem_index); } } // Rebuild lower parts of the tree northWest->rebuildTree(); northEast->rebuildTree(); southWest->rebuildTree(); southEast->rebuildTree(); }
void simple_test() { std::cout << "Beginning simple_test()..." << std::endl; // -------------------------------------------------------- // a collection of 21 points that make a nice sample tree std::vector< std::pair<Point<int>,char> > simple_points; simple_points.push_back(std::make_pair(Point<int>(20,10), 'A')); simple_points.push_back(std::make_pair(Point<int>(10,5), 'B')); simple_points.push_back(std::make_pair(Point<int>(30,4), 'C')); simple_points.push_back(std::make_pair(Point<int>(11,15), 'D')); simple_points.push_back(std::make_pair(Point<int>(31,16), 'E')); simple_points.push_back(std::make_pair(Point<int>(5,3), 'F')); simple_points.push_back(std::make_pair(Point<int>(15,2), 'G')); simple_points.push_back(std::make_pair(Point<int>(4,7), 'H')); simple_points.push_back(std::make_pair(Point<int>(14,8), 'I')); simple_points.push_back(std::make_pair(Point<int>(25,1), 'J')); simple_points.push_back(std::make_pair(Point<int>(35,2), 'K')); simple_points.push_back(std::make_pair(Point<int>(26,7), 'L')); simple_points.push_back(std::make_pair(Point<int>(36,6), 'M')); simple_points.push_back(std::make_pair(Point<int>(3,13), 'N')); simple_points.push_back(std::make_pair(Point<int>(16,12), 'O')); simple_points.push_back(std::make_pair(Point<int>(4,17), 'P')); simple_points.push_back(std::make_pair(Point<int>(15,18), 'Q')); simple_points.push_back(std::make_pair(Point<int>(25,13), 'R')); simple_points.push_back(std::make_pair(Point<int>(37,14), 'S')); simple_points.push_back(std::make_pair(Point<int>(24,19), 'T')); simple_points.push_back(std::make_pair(Point<int>(36,18), 'U')); // -------------------------------------------------------- // the quad tree data structure starts out empty QuadTree<int,char> simple; assert (simple.size() == 0); // an empty tree has height == -1 assert (simple.height() == -1); // plot the structure with with these dimensions (width=40,height=20) std::cout << "\nan empty tree:" << std::endl; simple.plot(40,20); // -------------------------------------------------------- for (int i = 0; i < simple_points.size(); i++) { // add each point from the collection //cout << "hello"<< endl; simple.insert(simple_points[i].first,simple_points[i].second); // verify the size (total # of points in the tree) //cout << "hello"<< endl; assert (simple.size() == i+1); // a few some specific checks along the way if (i == 0) { std::cout << "\nafter inserting first data point:" << std::endl; simple.plot(40,20); // a tree with 1 node has height == 0 //cout << simple.height() << endl; assert (simple.height() == 0); // check that the newly inserted element can be found //cout << "hello"<< endl; QuadTree<int,char>::iterator itr = simple.find(20,10); //cout << itr.getLabel() << endl; //cout << "hello"<< endl; assert (itr != simple.end()); // read the label & coordinates from the iterator assert (itr.getLabel() == 'A'); // dereference the iterator to get the point const Point<int> &pt = *itr; assert (pt.x == 20); assert (pt.y == 10); //cout << "hello"<< endl; } else if (i <= 4) { std::cout << "\nafter inserting " << i+1 << " data points:" << std::endl; simple.plot(40,20); // the next 4 additions for this simple all happen at the // second level, tree has height = 1 assert (simple.height() == 1); } else if (i == 8) { std::cout << "\nafter inserting " << i+1 << " data points:" << std::endl; simple.plot(40,20); assert (simple.height() == 2); // check for an element that exists QuadTree<int,char>::iterator itr = simple.find(4,7); assert (itr != simple.end()); assert (itr.getLabel() == 'H'); assert ((*itr).x == 4); assert ((*itr).y == 7); // check for a couple elements that aren't in the tree itr = simple.find(14,14); assert (itr == simple.end()); itr = simple.find(15,18); assert (itr == simple.end()); // another visualization of the tree structure // note: this is a pre-order traversal of the data (print the node, then recurse on each child) std::cout << "\na 'sideways' printing of the tree structure with 9 nodes:" << std::endl; simple.print_sideways(); } } // -------------------------------------------------------- // a few more checks std::cout << "\nafter inserting all 21 data points:" << std::endl; simple.plot(40,20); assert (simple.size() == 21); assert (simple.height() == 2); QuadTree<int,char>::iterator itr = simple.find(15,18); assert (itr != simple.end()); assert (itr.getLabel() == 'Q'); assert ((*itr).x == 15); assert ((*itr).y == 18); // plot the data without the lines std::cout << "\na plot of the point data without the lines:" << std::endl; simple.plot(40,20,false); // -------------------------------------------------------- // another visualization of the tree structure // note: this is a pre-order traversal of the data (print the node, then recurse on each child) std::cout << "\na 'sideways' printing of the finished tree structure:" << std::endl; simple.print_sideways(); // -------------------------------------------------------- // use the primary (depth-first) iterator to traverse the tree structure // note: this is a pre-order traversal, the same order as the 'sideways' tree above!! std::cout << "\nA depth-first traversal of the simple tree (should match sideways output!):" << std::endl; QuadTree<int,char>::iterator df_itr = simple.begin(); char expected_depth_first_order[21] = { 'A','B','F','G','H','I','C','J','K','L','M','D','N','O','P','Q','E','R','S','T','U' }; for (int i = 0; i < 21; i++) { assert (df_itr != simple.end()); // get the depth/level of this element in the tree (distance from root node!) int depth = df_itr.getDepth(); // use the depth to indent the output (& match the sideways tree output above) std::cout << std::string(depth*2,' ') << df_itr.getLabel() << " " << *df_itr << std::endl; // check that the output is in the correct order! assert (df_itr.getLabel() == expected_depth_first_order[i]); // test the pre-increment operator++ ++df_itr; } // after 21 increments, we better be at the end! assert (df_itr == simple.end()); // -------------------------------------------------------- // using the breadth-first iterator to traverse the data by level std::cout << "\nA breadth first traversal of the simple tree:"; QuadTree<int,char>::bf_iterator bf_itr = simple.bf_begin(); char expected_breadth_first_order[21] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U' }; int level = -1; for (int i = 0; i < 21; i++) { assert (bf_itr != simple.bf_end()); // get the depth/level of this element in the tree (distance from root node!) int depth = bf_itr.getDepth(); if (level != depth) { level = depth; // starting a new level! std::cout << std::endl << " level " << level << ":"; } // print out this data point std::cout << " " << bf_itr.getLabel() << *bf_itr; // check that the output is in the correct order! assert (bf_itr.getLabel() == expected_breadth_first_order[i]); // test the pre-increment operator++ ++bf_itr; } // after 21 increments, we better be at the end! assert (bf_itr == simple.bf_end()); std::cout << std::endl; // -------------------------------------------------------- std::cout << "\nFinished with simple_test().\n" << std::endl; // Note: the destructor for the QuadTree object 'simple' is // automatically called when we leave this function and the variable // goes out of scope! }
int main() { ios::sync_with_stdio(false); cin.tie(NULL); QuadTree<100000, 4000100> qt; int N, Q; cin >> N >> Q >> ws; vector<string> inp(N, ""); Node *ft = new Node(), *bt = new Node(); for (int i = 0; i < N; ++i) { getline(cin, inp[i]); ft->insert(inp[i]); bt->rinsert(inp[i], inp[i].length() - 1); } int fc = 0, bc = 0; ft->leaf_fix(fc); bt->leaf_fix(bc); vii lr(N, {-1, -1}); for (int i = 0; i < N; ++i) { lr[i].first = ft->getleaf(inp[i], 0).first; lr[i].second = bt->getleaf_r(inp[i], inp[i].length()-1).first; // cerr << i << ' ' << lr[i].first << ' '<<lr[i].second << endl; } vii bysize; for (int i = 0; i < N; ++i) bysize.push_back({inp[i].size(), i}); sort(bysize.rbegin(), bysize.rend()); inp.clear(); vector<string> query(Q, ""); vii qbysize; for (int q = 0; q < Q; ++q) { getline(cin, query[q]); qbysize.push_back({query[q].size(), q}); } sort(qbysize.rbegin(), qbysize.rend()); vi ans(Q, 0LL); // Handle queries one by one for (int _q = 0, i = 0; _q < Q; ++_q) { int q = qbysize[_q].second; // Insert all strings that are strictly smaller while (i < N && bysize[i].first + 1 >= qbysize[_q].first) { int s = bysize[i].second; qt.insert(lr[s], 1); ++i; } // Process the query ii prefr = ft->getleaf_ast(query[q], 0); ii suffr = bt->getleaf_rast(query[q], query[q].length()-1); if (prefr.second == -1 || suffr.second == -1) continue; // cerr << q << " "; // cerr << prefr.first << ' ' <<prefr.second << " "; // cerr << suffr.first << ' ' <<suffr.second << endl; --prefr.second; --suffr.second; ans[q] = qt.query(prefr.first, suffr.first, prefr.second, suffr.second); } for (size_t i = 0; i < ans.size(); ++i) cout << ans[i] << '\n'; return 0; }
int test_main() { os::gfx::Gfx gx; gx.change_mode(os::gfx::VideoMode(800, 600)); reaper::debug::ExitFail ef(1); os::event::EventSystem es(gx); os::event::EventProxy ep = os::event::EventSystem::get_ref(0); qt.insert(new world::Triangle( Point(200, 0, 200), Point(500, 1, 200), Point(500, 1, 500) )); qt.insert(new world::Triangle( Point(500, 10, 500), Point(700, 10, 500), Point(700, 10, 700) )); glViewport(0,0,gx.current_mode().width, gx.current_mode().height); // hela fönstret glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70,1,1,1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,500,0, 0,0,0, 0,0,1); glClearColor(0,0,0,0); ::glEnable(GL_DEPTH_TEST); world::Line line(Point(500, 100, 500), Point(480, -10, 490)); float step = 1; os::time::TimeSpan start = os::time::get_time(); while (true) { if (ep.key(os::event::id::Escape)) break; if (ep.key('1')) line.p1.x += 10.0; if (ep.key('2')) line.p1.x -= 10.0; if (ep.key('3')) line.p1.y += 10.0; if (ep.key('4')) line.p1.y -= 10.0; if (ep.key('5')) line.p1.z += 10.0; if (ep.key('6')) line.p1.z -= 10.0; if (ep.key('7')) line.p2.x += 10.0; if (ep.key('8')) line.p2.x -= 10.0; if (ep.key('9')) line.p2.y += 10.0; if (ep.key('0')) line.p2.y -= 10.0; if (ep.key('-')) line.p2.z += 10.0; if (ep.key('=')) line.p2.z -= 10.0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_it(line); gx.update_screen(); os::time::msleep(50); if (exit_now()) break; } ef.disable(); return 0; }
int main(){ unordered_map<string, Location>* addresses = parseLocFile(); // builds the QuadTree! and reads in all of the restauraunts. // I constructed the restauraunt class so as to simply use the >> operator // to read a line from the CSV file Restauraunt* r = new Restauraunt; ifstream foodFile(FOOD_FILE); foodFile.ignore(1000, '\n'); // Ignore first line QuadTree<Restauraunt> quad; while(!(foodFile >> (*r)).eof()){ // If the location wasn't set, use the address to find the location if(!r->locationSet()){ r->setLocation(getLocationFromAddress(addresses, r->address)); } // Which means that now the metric location of the restauraunt is known, // and can be inserted into the QuadTree quad.insert(r->metricLocation, r); r = new Restauraunt; } delete r; foodFile.close(); /* Data is stored in crime csv as: * COMPNOS,NatureCode,INCIDENT_TYPE_DESCRIPTION,MAIN_CRIMECODE,REPTDISTRICT, * REPORTINGAREA,FROMDATE,WEAPONTYPE,Shooting,DOMESTIC, * SHIFT,Year,Month,DAY_WEEK,UCRPART, * X,Y,STREETNAME,XSTREETNAME,Location * * We want INCIDENT_TYPE_DESCRIPTION [2], FROMDATE [6], WEAPONTYPE [7], Shooting [8], and Location [19] */ ifstream crimeFile(CRIME_FILE); ofstream crimeOut (CRIME_OUT); // Output the crime header crimeOut << "Location, Date, Type, Danger\n"; crimeFile.ignore(1000, '\n'); // Ignore first line char buff[128]; // There were only like 30 destinct incident types, not all of which I understood, so I just assigned // each a numerical value. This unordered_map is how: if an incident was not in incidentTypes, set // the value to the incidentCount and store that in incidentTypes, and increment incidentCount unordered_map<string, unsigned char> incidentTypes; unsigned char incidentCount = 0; string incidentType; unordered_map<string, unsigned char>::const_iterator iter; // m stores metric location, l stores latitude/longitude Location m,l; int i=0; // I realized after a bit that I would want a date representing now to determine how long ago things // happened, but I didn't want too create a new date for every restauraunt or crime, so last minute // I added this variable Date now = Date::now(); vector<struct Crime*> crimes; // I decided for the crimes, ad I wanted to keep tack of incident types // and the like, that rather than doing stream operators I would just do it all // here. It doesn't make or the cleanes code, b while(!crimeFile.eof()){ struct Crime* c = new struct Crime; c->copies = 0; // This loops through the 20 cells of information in the CSV and extracts // the relevent bits for(int i=0;i<19;i++){ crimeFile.getline(buff, 128, ','); if(crimeFile.eof()) break; switch(i){ case 2:// INCIDENT_TYPE_DESCRIPTION ; incidentType = string(buff); iter = incidentTypes.find(incidentType); if(iter == incidentTypes.end()){ // Then the incidentType isn't in incidentTypes incidentTypes.emplace(incidentType, incidentCount); c->type = incidentCount; incidentCount++; }else{ c->type = iter->second; } break; case 6: // FROMDATE c->date.setDate(buff); break; case 7: // WEAPONTYPE (either Unarmed, Other, Knife, or Firearm) switch(buff[0]){ case 'U': // Unarmed c->weapon = 0; break; case 'O': // Other c->weapon = 1; break; case 'K': // Knife c->weapon = 2; break; case 'F': // Firearm c->weapon = 3; break; default: break; } break; case 8: //Shooting (Yes or No) // If there was a shooting, add a shooting flag if(buff[0] == 'Y'){ c->weapon += 4; } break; default: break; } } crimeFile.getline(buff, 128); //This is the location l.setLocation(buff); m.setLocation((l.x - MIN_LAT)*LAT_TO_METERS , (l.y - MIN_LNG)*LNG_TO_METERS); // Output the crime CSV crimeOut << '"' << l << "\", " << c->date << ", " << int(c->type) << ", " << int(c->weapon) << endl; // the call to quad.findNodes(m, 100) finds all nodes in the QuadTree within // a distance of 100 from the location m, which is the metric coordinates of the crime vector<Restauraunt*> v = quad.findNodes(m, 100); // This bit iterates through and adds the crime to the objects of nearby restauraunts if(!v.empty()){ int initialCost = initialCrimeCost(*c); // If the initial cost is 0, no need to add the crime, as that means it was ignorable? // Basically I just decided that a MedAssist incident probably shouldn't be counted, // although I don't actually kknow what that means, its frequency and name suggests // that perhaps the police were merely assisting with something of a medical nature. if(initialCost > 0){ for(Restauraunt* r: v){ r->addCrime(c, m, initialCost, now); } } } // if c->copies = 0, then it wasn't within 100 meters of any restauraunt and should be deleted if(c->copies = 0) delete c; else crimes.push_back(c); i++; if(i%100 == 0) cout << i << " crimes processed\n"; } crimeFile.close(); crimeOut.close(); cout << "MedAssist: " << (int)incidentTypes["MedAssist"] << endl; // This section outputs the food CSV nice and succinctly ofstream foodOut (FOOD_OUT); foodOut << "Location, Name, Date, Address, Description, CrimeCost, Crimes\n"; quad.mapNodes(writeRestauraunt, &foodOut); for(struct Crime* crime : crimes){ delete crime; } delete addresses; // I should free all of the restauraunts in the quad, but this doesn't seem // to work and I don't really care that much for a one-off script: // quad.mapNodes(deleteRestauraunt, NULL); }