Coding Challenge #98.1: Quadtree - Part 1

Поділитися
Вставка
  • Опубліковано 20 січ 2025

КОМЕНТАРІ • 367

  • @StarContract
    @StarContract 6 років тому +78

    Just started teaching collision detection, those references are priceless 👌

  • @Em-bi7tn
    @Em-bi7tn 5 років тому +5

    I was going crazy from how dry every fucking person talking about Algorithms is. This keeps my attention, thank you!! What I needed!!

  • @simeon2396
    @simeon2396 6 років тому +228

    I think you missed an important thing!
    When you put for example 11 points in a quadtree (with capacity 10), only the 11th point is stored in one of it's quadrants. Wouldn't it be better if all the 11 points are divided between the 4 quadrants? So what I mean is this: Shouldn't only the most specific quadrants (the leafs of your tree) hold the points? Then you could go recursively down the tree to find the quadrants that are not divided (the leafs) and there you find all the points that are in that specific quadrant. Because now you have points that are stored in a "higher" quadrant (one of the parent quadtrees) and exceed the capacity of a "lower" quadrant. In other words: the capacity of a small quadrant can be exceeded because because you also store points in quadtrees that are divided.
    Ps: I love your videos! Especially your coding challenges!

    • @redhen
      @redhen 6 років тому +6

      That's an interesting question.

    • @TheCodingTrain
      @TheCodingTrain  6 років тому +38

      This definitely could be done, but I'm not sure how much it would improve efficiency in the end. And for simplicity it works "good enough" without doing so. I'd love to try adding this as a feature and see how it works!

    • @simeon2396
      @simeon2396 6 років тому +17

      I guess the only "slower" part about this approach is the construction: you have to give the points of a quadtree to its quadrant instead of keeping them stored in the quadtree itself. But the efficiency of the important part will stay the same: the search for points in a quadrant. Because you go down the tree no matter what! The amount of points you check is the same in both approaches.
      I just found it a bit weird that in your design, there can be more points than the capacity in a quadrant. Capacity doesn't mean " max amount of points in an area" anymore when quadrants that are subdivided hold points themselves! It thought " max amount of points in an area" was the purpose of this variable?
      Much love
      Simeon

    • @Smikay
      @Smikay 6 років тому +25

      The problem comes when you are comparing the points; where you shouldn't be comparing any points in a quadrant that has been divided. The comparisons should only ever occur in the smallest child so having 10 points in the parent even though it has been divided is not true to the algorithm

    • @TheCodingTrain
      @TheCodingTrain  6 років тому +13

      Thanks for all this feedback! Suggestions for improvements can now be added as issues or pull requests to: github.com/CodingTrain/QuadTree

  • @jasonedward
    @jasonedward 4 роки тому +16

    WOW! I have been following your P5 videos for months and didn't even know this concept existed.
    But yesterday I managed to build a quadtree on my own with no tutorial to decrease my grids processing time and I got it right just by imagining the outcome I wanted and messing around.
    So how the hell did UA-cam know I was looking for this and put this in my recommendations the next day??? Crazy

  • @sdegueldre
    @sdegueldre 6 років тому +21

    33:35 there is a problem here, you can clearly see that some squares contain more than 4 points yet did not subdivide. I suspect this is, as was pointed out by others, because a tree that is subdivided is still allowed to contain points.

    • @sigmareaver680
      @sigmareaver680 6 років тому +1

      There is a bug in the rectangle.contains function, where he is including points in a rectangle where p.x >= (r.x - r.w). This is wrong. Should just be p.x >= r.x

    • @Maxparata
      @Maxparata 6 років тому +4

      @@sigmareaver680 Are you sure? The rectangle has its "pivot" in its center, so if the point get past the center on the left, it returns false, and it means it does not contains it although it does.
      I think it's correct. by subtracting by the x.position by the width we make sure that the comparing point does not get past the further left limit.

  • @an0nsaiko890
    @an0nsaiko890 3 роки тому +23

    great video. A small note : at 6:06 its actually *log2(1000) = 10 (with round up) * 1000 = 10.000* because the log in this case has base 2 (not 10 as the calculator has by default)

    • @ronaldc8634
      @ronaldc8634 3 роки тому +6

      Yup, this was the comment I was looking for

    • @davidmooers4072
      @davidmooers4072 Рік тому +3

      Wouldn’t it be log4(1000) since it’s a quadtree?

    • @Shannxy
      @Shannxy Рік тому +1

      ​@@davidmooers4072 log4(N) can be expressed in terms of log2(N) as:
      log4(N) = log2(N) / log2(4) = 0.5 * log2(N)

  • @deepnomusic
    @deepnomusic 2 роки тому +1

    Omg this is exactly what I need for my simulation, THANK YOU so much for how clear you explain these stuffs!!!

  • @dt28469
    @dt28469 22 дні тому

    This was a really good low level breakdown of the programming aspect of Quadtrees. Trying to implement this in PyGame. I've watched too many videos on Quadtree theory that I was going nowhere with. Thanks 👍😃

  • @CallmeSam00
    @CallmeSam00 4 роки тому +2

    You sir, are a credit to your profession. Thank you for making such an understandable, for the layman even, introduction to this topic!

    • @JannisAdmek
      @JannisAdmek 4 роки тому

      just watched your pak choi recipe video :) Looks delicious

  • @aleph618
    @aleph618 Рік тому +2

    I wish I'd known about quadtrees before I wrote my 3D diffusion-limited aggregation sim in Processing. It has 12,000 particles which is 144,000,000 checks per frame. As you can imagine, it's incredibly slow!

  • @ThomasChen-ur2gt
    @ThomasChen-ur2gt 6 років тому +3

    This is the thing I wanted to learn but can't find any good tutorial. Thank you so much!

  • @Otakutaru
    @Otakutaru 6 років тому +11

    Another way to do it would be, instead of "broadcasting" the new point to all the subdivisions and let them figure it out, to push the point to only the subdivision that could take it. It doesn't really matter when to do the check, but it seems to me more logical to let the parent feed each child instead of throwing them the pot... I know... best analogy EVER.

    • @BobrLovr
      @BobrLovr 10 місяців тому

      that defeats the purpose, because then you have to iterate over all of them always

    • @Otakutaru
      @Otakutaru 10 місяців тому +1

      @@BobrLovr yeah, I don't know what I was thinking 5 years ago but it made sense. I guess what I tried to say is, feed the points to the root, and let it route the points ONLY to their corresponding quad, so that quad can then route the point again. Binary search, but 2d.

  • @PeterVC
    @PeterVC 6 років тому +42

    When inserting a point and you are over capacity and you subdivide and put that one point in one of the subtrees, shouldn't the points from the current tree also be distributed into those subtrees? So that only leafs have points ?

    • @Chevifier
      @Chevifier 2 роки тому +1

      Thats exactly whats happening.

  • @johnydl
    @johnydl 6 років тому +9

    In subdivide you could refactor by setting w and h to this.boundary.w/2 and thus.boundary.h/2 and reduce the number of divisions for that section to 2 from 16
    I think others have said but only the lowest limbs of the tree should have the points, because two points could be on top of one another but one could be several steps away based on what order they were added to the array. One way to do this would be to refactor the if !this.divided, if it's divided then its point array should be kept empty so the point down through the tree, if it's not divided and there's space add the point here else subdivide and hand off the collected points from this branch down the tree structure.
    You also do more checks than you need to for what rectangle each point is in because you check it in the rectangle and you check it after it arrives rather than before you send it, 16 checks for every layer the point passes through, if instead you check it's in the global rectangle at the start (4 checks for the top layer) then it can go in the tree and for each sub layer it passes through you only need to check if it's in the North vs South and East vs West, so 2 checks per layer seudocode: if inBoundaries(point) then tree.insert(point) and if point.y

  • @dudley0007
    @dudley0007 5 років тому +1

    first video I've seen from this channel. Just subscribed. Well described and actually very fun to watch. Cheers.

  • @pursuitofcat
    @pursuitofcat 3 роки тому +1

    Just amazing man. So simply explained a "rather" complex looking data-structure.

  • @lfroggyl
    @lfroggyl 6 років тому +5

    At 18:00, when you created local variables to the function to make it more readable, you should've let w = this.boundary.width / 2, and let h = this.boundary.height/2, that way your formulas would be even more short and readable.

  • @jamesodonnell4771
    @jamesodonnell4771 25 днів тому

    Thanks a lot for the full demo this really is helping secure my understanding to use in my own projects!

  • @ArnoldsKtm
    @ArnoldsKtm 6 років тому +5

    This was great. Never knew about a Quadtree.

  • @mootimadness7825
    @mootimadness7825 6 років тому +23

    my fave channel :)

  • @elijahlucian
    @elijahlucian 5 років тому +3

    damn. coding live is like the ultimate pair programming

  • @ben_jammin242
    @ben_jammin242 4 роки тому +4

    Don't forget to make use of your editor. You can forward highlight the duplicates of "this." and replace them with nothing, when you are refactoring at 18:02

  • @sethmoeckel7853
    @sethmoeckel7853 6 років тому +18

    You can partially rebuild quadtree sections... you can change only the sections of a quadtree where the points change. Given its all a tree, just implement some tree-shaking to eliminate dead points and add new ones whenever your graph changes. Should be much faster.

    • @mirza5373
      @mirza5373 7 місяців тому

      How to do that? Can you explain lil bit more about the algorithm?

  • @CodeVault
    @CodeVault 6 років тому +2

    Really helpful tutorial, thank you very much. One small tip:
    At 17:40 you could've used the destructuring syntax from ES2015 like so:
    let {x, y, w, h} = this.boundary;

  • @xthomas7621
    @xthomas7621 6 років тому +2

    Oh! So that’s what a quad tree is. I want to say, you explained it really well and it was easy to follow, and being able to follow is a big compliment, because I wasn’t wearing my contacts, and was watching on my phone, so most people would be hard to watc, but you are easy :P

  • @pavelrahl6284
    @pavelrahl6284 6 років тому +5

    I really like your enthusiasm!

  • @dnoldGames
    @dnoldGames 6 місяців тому

    23:43 I love how he leans on his code editor and takes a look to the right xD

  • @BrazilMentionedHueHue
    @BrazilMentionedHueHue 4 місяці тому

    Top/bottom , left/right >> NE, NW, SE, SW. Change my mind

  • @Ubayla
    @Ubayla 6 років тому +19

    30:08 That larger cell near the top left definitely has more than 4 points.
    The QuadTrees should be pushing their points down to their child tree when they subdivide. Right now cells have their own points AND their children have points. Unless you're not just using the leaves for storing the points, then go off I guess.
    Also seems weird to instantiate a new QuadTree every time you subdivide, but that's just silliness with the naming.

    • @danielturcotte6213
      @danielturcotte6213 3 роки тому +3

      @Ubayla
      Correct. I think he needs to add within insert(point) after this section
      if (this.points.length < this.capacity && !this.divided) {
      ...
      }
      Here:
      if (!this.divided) {
      this.subdivide();
      for (var i = 0; i < this.points.length; i++) {
      this.insert(this.points[i]); // Move points. down into divided quadrants
      }
      // Empty parent node's points
      this.points = [];
      }

  • @skaruts
    @skaruts 2 роки тому +7

    A minor thing I'm usually mindful of when writing non-exercise code: I might call those rectangles Quadrant, or something like that, just because one's brain will never expect a Rectangle to have its origin point at the center. Someone else reading the code might get the wrong idea, and also not feel the need to double check if it works as expected. Or I might read the code in 6 months and get the wrong idea myself. :)

  • @TheCodingTrain
    @TheCodingTrain  6 років тому +19

    Wow, so much excellent feedback! I've created this repo -github.com/CodingTrain/QuadTree - in order to allow pull requests to improve the implementation.

    • @JariOrSomething
      @JariOrSomething 6 років тому +1

      The link is broken, remove the ")" at the end of the url :)

    • @TheCodingTrain
      @TheCodingTrain  6 років тому

      thanks should be fixed now.

  • @orr4945
    @orr4945 6 років тому +6

    2 things:
    First - the iteration number or complexity of the old one, nor the optimized one isn't bigening in an exponential rate... It's by a n^2 factor.
    Second - the log calculation you have done on the calculator(on the Internet) is by a base of 10, while your nlogn complexity is not.
    Just thought you should know...
    Love your channel keep it going :)

    • @TheCodingTrain
      @TheCodingTrain  6 років тому +1

      Yes, thank you for these corrections!

    • @TheCodingTrain
      @TheCodingTrain  6 років тому +1

      Yes, thank you for these corrections!

    • @ilieschamkar6767
      @ilieschamkar6767 3 роки тому +1

      So instead of using log10, we should use ln or it's a generic log?

    • @orr4945
      @orr4945 3 роки тому +1

      @@ilieschamkar6767 I'm going to have to rewatch the video to answer that, my comment was 3 years ago 😅
      I'll try to remember to do it later

    • @ilieschamkar6767
      @ilieschamkar6767 3 роки тому +1

      @@orr4945 I've read in a comment that technically it should be log4, because we are dividing each quadtree four times
      Thanks nonetheless :D

  • @alexkuhn5078
    @alexkuhn5078 2 роки тому

    I love the scheme for mapping conventional x and y coordinates to cardinal directions. I always imagine a map of the US: everything gets higher as you move toward Florida.

  • @rileymeggison326
    @rileymeggison326 3 роки тому +1

    All my tension was relieved when he said the word "visualize"😂

  • @loic.bertrand
    @loic.bertrand 6 років тому +4

    29:21 I think the points are drawn multiple times because that happens in the recursive function show(), maybe that's why it becomes very slow ^^

    • @redhen
      @redhen 6 років тому +2

      I don't think so -- since each quad only renders (shows) its own points, not the points of the parent quad, which has already rendered the points held in its own array. In other words, the function works by a parent quad rendering its own points, and then calling the show function for its child quads and *not its own show function again*.
      The confusion (if I'm correct here) is about what 'recursion' mean here. In a sense, this isn't true recursion, because the function isn't calling itself, but the equivalent function belonging to a different (child) object. So, the 'recursion' here refers to the recursive nature of the parent-child quad relation for this data structure.

    • @misode
      @misode 6 років тому +1

      No they aren't. A point is only in one of the four quadtree's.

    • @misode
      @misode 6 років тому +3

      Actually what's happening is when a fifth point is added, the four original points are not divided into the four quadtree's.

  • @brucewernick6542
    @brucewernick6542 Рік тому

    I applied the QuadTree to a chart of dynamic nodes. It seemed to work but it feels a bit clumsy. Now, I came across the KDTree that seems to be more appropriate to my problem. It is used to find nearest neighbors in a multi-dimensional space. I think it could also work for your example. The code is much smaller and the logic is easier to apply.

    • @brucewernick6542
      @brucewernick6542 Рік тому

      I searched your vids and see that you have actually touched on the subject in this one. #70: Nearest Neighbors Recommendation Engine. But, you don't actually refer to the KDTree.

  • @MrRys
    @MrRys 6 років тому +3

    When you were talking about the west on the right side, I was like "wow I never noticed, your camera records in mirrored image"

    • @TheCodingTrain
      @TheCodingTrain  6 років тому

      😂

    • @allfreetechhub
      @allfreetechhub 4 роки тому +1

      I was stuck with this point, thinking why my implementation doesn't match the one in this video.
      Still not sure, why he did (y - h/2) for north.
      Is there an external concave lens used in the camera?

  • @avananana
    @avananana 6 років тому +42

    "this is a thousand times THIS" *pointing at 1 million and then 10 thousand*. Not sure if I'm positive about this, Dan, how did elementary school go for you?
    Loved it x)

  • @dvdrtrgn
    @dvdrtrgn 2 роки тому +1

    I love this guy! It would go a long way if he would spend a couple hours learning js a little more idiomatically. It hurts to watch the editing and operations struggles 🙏🏽

    • @TheCodingTrain
      @TheCodingTrain  2 роки тому +1

      Thanks for the feedback! Are there some specific moments or bits of code you can share that I should take a closer look at?

    • @dvdrtrgn
      @dvdrtrgn 2 роки тому +1

      @@TheCodingTrain Look into default parameters (to set capacity), destructuring assignment (un-nesting props, let {x, y, w, h} = this.boundary @ 17:30), and spread syntax (for return arrays/objects). Also, check out multiple cursors for fast simultaneous edits in your vscode/atom. You are awesome!

  • @Maxparata
    @Maxparata 6 років тому +1

    3:00 "There are many ways", what are the other ways, apart from quadtree, for avoiding the n^2 function?
    Just some names so I can make research on that.
    Also, does someone has a repo version where the points are stored in the leaf only instead of the tree branches? It would be nice!

    • @phizc
      @phizc 4 роки тому +2

      Long ago, I know. One simple improvement is to not check previous pairs or itself. 1 checks 2 to 9, 2 checks 3 to 9, 3 checks 4 to 9, etc. 10 points results in 45 checks not 100. This is n choose k.
      There are other data structures that can be used. Search for spatial partitioning. Examples are BSP trees, k-d trees, sphere trees and Bounding Volume Hierarchies. The latter is used in real time ray tracing. BSP trees was e.g. used in the original Doom games.

  • @Shannxy
    @Shannxy Рік тому

    19:23 As you look done redoing your cardinal directions I have to ask why the north ones have -y and the south ones have +y?
    For normal math where the origo is bottom left you would have to swap the + and - for the y, so I'm wondering if your origo is for the top left?

  • @alexandresoutonogueira7675
    @alexandresoutonogueira7675 2 роки тому +3

    36:30 hurts my eyes. just return a conditional with an OR operation with the 4 method calls

  • @IbakonFerba
    @IbakonFerba 6 років тому +9

    Shouldnt the Points that are in a quad be removed from that quad when it is subdivided and added to the correct child quads? So the points are allways the leafs of the tree?

    • @pravinpoudel1307
      @pravinpoudel1307 4 роки тому +1

      I don't understand why there is no response to this valid question. Do you have anything that you can add to this yourself?

    • @rocksfire4390
      @rocksfire4390 4 роки тому +1

      @@pravinpoudel1307
      yes that is how it "should" be. when subdividing all points should be pushed into the 4 new quadtress and ofc removed from the parent. this way the ending quadtree of each quadtree are the containers of the data, not the parent nodes.
      this makes data collection when you need it easier because you don't have to check EVERY tree, just the ones that are not subdivided.

    • @Fogmeister
      @Fogmeister 3 роки тому

      How would it cope if you had a quad tree with a node capacity of 4 and you add to it 5 points with the exact same coordinates?

    • @kayfoster7385
      @kayfoster7385 3 роки тому

      @@Fogmeister however you want i guess. but i think it would treat two points as 1 though it takes 2 slots in your array.

    • @Fogmeister
      @Fogmeister 3 роки тому

      @@kayfoster7385 ah yeah, I've done this myself now and you can set a "max depth" for the entir tree. So that if you do get this scenario your don't end up with infinite recursion.

  • @jjppmm29
    @jjppmm29 6 років тому +1

    I felt your pain trying to figure out what to call the nodes of the tree
    also linear interpolation makes figuring out how to set the values so much easier

  • @maribakumon
    @maribakumon 4 роки тому

    I'm attempting to follow along hoping that it'll be more clear to me exactly how this functions, but at 10:17 my console still tells me that Rectangle is undefined even after referencing it in my HTML file. What's going on?

  • @persistent-programmer
    @persistent-programmer 4 місяці тому +1

    The one thing that drives me crazy is that you didnt move the existing points down into the divided subtrees. This would create major problems when trying to query based on a sub-tree.

  • @therationalplanner1574
    @therationalplanner1574 3 роки тому

    at 19:00 u have for NE and NW y-h/2 shouldnt it be y+h/2 because its where u currently are + half of the height to go up.
    and SW SE should be '-' ?
    with your rectangles where is 0,0 ? is it top left? im trying to do x,y,w,h into top_left x1,y1 bottom right x2,y2
    the math is confusing me

  • @rasmadrak
    @rasmadrak 3 роки тому +4

    The parent should probably check which quadrant to insert into, instead of having each child check and verify. That way it's possible to bypass the boundary check completely if the point was sent from a parent. i.e "insertRandom" vs "insertInto"

  • @jacksondice5435
    @jacksondice5435 3 роки тому +2

    I tried your algorithm against a linear search (also using the same search window) and for some reason the linear search is going faster than the quadtree search? tried changing number of points, bucket size and searcharea / quadrants' size.

  • @mukulbhave
    @mukulbhave Рік тому

    Wow. Simple, to the point demo

  • @Dante3085
    @Dante3085 6 років тому +1

    Quick Question: At 25:10
    When he does things like not passing the required number of arguments to the QuadTree Constructor. Why is there no error while editing the code and or running it ?

  • @linnealager6146
    @linnealager6146 5 місяців тому

    Grid is better for moving objects with similar size. If the objects are static and of varying size, a quadtree is very helpful.

  • @AlexanderBollbach
    @AlexanderBollbach 6 років тому +4

    can you do some videos on 2d physics engines? hit detection, collision resolution, angular momentum, etc? its too hard to learn on my own!

  • @GTexperience_Channel
    @GTexperience_Channel Рік тому

    So big question here:
    aren't u supposed to not have points in the connecting nodes of a quad tree? U are assigning points till a square is full, then for the next point you subdivide. But aren't u supposed to reassign the points that u already had assigned to the square to the subdivided squares?

  • @SimonK91
    @SimonK91 6 років тому +1

    @6:05, I think you're wrong in the calculation.
    The quadtree separates the square into 4 parts, shouldn't that mean that you'll check n*log4(n) times? Not n*log10(n) times.
    It should be around 5000 checks and not 3000. Either way it's a massive improvement compared to doing a million checks...

  • @Megasyl200
    @Megasyl200 6 років тому +3

    17:30 -> with es6 you can do something like : let { x, y, w, h } = this.boundary;

  • @KnakuanaRka
    @KnakuanaRka 6 років тому +3

    26:13 Wait, the roots still have points in them even after being divided? A quad tree section should give all its points to its subsections, not just the one that divided it.

    • @JackFlashTech
      @JackFlashTech 4 роки тому

      Not necessarily. In a binary search tree, you’d have to have a value in each node to know whether to go “left” (less than the value in that node) or “right” (greater than the value in that node). Often, though, a database would have a n-ary tree for its indexes where it would scan a whole list of numbers, with a child node “between” each value for the values between those values. You still need at least one value in each node to know whether to go “right” or”left” when looking for a specific value.

    • @angelrodriguez1776
      @angelrodriguez1776 4 роки тому

      @@JackFlashTech if (left !=null), if (right != null).

  • @jmfairlie
    @jmfairlie 6 років тому +2

    at 36:00 instead of all those "if/else if" you can do:
    return this.northeast.insert(point) || this.northwest.insert(point) || this.southeast.insert(point) || this.southwest.insert(point);

  • @adri2350
    @adri2350 6 років тому +4

    You're a genius !! When I see that I wan't learn Javascript !

  • @TheJuliMf
    @TheJuliMf 6 років тому +1

    In the end, I think you do not need a QuadTree and Rectangle class. You can combine both of them into a QuadTreeNode, like you would normally do on a tree (there is no Tree but TreeNode)

    • @TheCodingTrain
      @TheCodingTrain  6 років тому

      Thanks, yes it's true! Thank you for the feedback! I wanted to have a Rectangle class so that the end user of the library could create geometry regions (also a "Circle" for example) without having the make a full node.

  • @tycho25
    @tycho25 2 роки тому

    This method is easily applicable to octrees as well. Thanks!

  • @i.c.weiner556
    @i.c.weiner556 6 років тому +1

    Have you considered using quaternary numbers to reference section?

  • @OneShot_cest_mieux
    @OneShot_cest_mieux 6 років тому +3

    Sorry for my bad english, I am french. You are drawing each point many times in your show function, because you should draw them when a quadtree is not subdivided.

    • @redhen
      @redhen 6 років тому

      Salut! I think that would be true for a tree system that passes its objects (points) down to a child node (quad). This quadtree system keeps its own points, and only passes points to a child quad that are *in addition to* its capacity.
      ...je pense.

    • @OneShot_cest_mieux
      @OneShot_cest_mieux 6 років тому +1

      Red Hen dev yes it's that

  • @Flocksta
    @Flocksta 3 роки тому

    How would you make the squares to be more like rectangles or any other shape? So they are not even squares within squares.

  • @frederikja2210
    @frederikja2210 5 років тому

    Why is it a problem towards the end 35:20 that the points are not part of multiple quads? wouldn't it actually be better in some cases to have them be part of multiple quads? so that way the particle/point is being collision checked in both of the quads.
    Sorry for commenting so late but only just had the need to watch this vid, keep up the nice work man!

  • @BB-dv8nu
    @BB-dv8nu 6 років тому +5

    Nice! I always wonderd how colision detection is reduced to a useful amount of checks.

    • @klontjespap
      @klontjespap 2 роки тому

      mostly through a combination a grid/tile engine implementation and being smart about what to even check with the information on the direction of the vectors mostly (ie, don't check the direction noone's going)
      when you break down things into bigger tiles, you can avoid having to check a ton of expensive pixel or vector calculations
      because you can already determine the objects aren't close enough by their tile/grid coordinates, and can already break out, which is most of the time for most checks when you have a lot of objects going around, so it scales like crazy with a lot of objects.
      you can even choose to store the tile/grid coordinate AND the relative offset in the objects themselves,
      it's way more data, but saves a couple of divisions and rounds in the main loop for when you need that extra object count.
      if you just dupe the same monolithic object a gazillion times it's pretty cheap.
      big saver there
      but if they are close, then check their offset from that tile center, only when that passes, do the expensive stuff
      that can still use raymarching to cheapen up the finer calculations, but most of that can be avoided by a simple grid coordinate system combined with the the object's relative position offset, to just break out all the non-contenders as quickly as possible.
      the gains are already huge on a simple flat tile grid with no children.
      when you think about it, an octree is really just a glorified tile/grid engine type of thingie :D

  • @downstream0114
    @downstream0114 3 роки тому

    How does it handle points on the edges of quads.. and the edge of the outermost..

  • @doctortrouserpants1387
    @doctortrouserpants1387 2 роки тому

    excellent video - really helpful to see you work it out as you write it, I learned a lot, very clear and understandable. thanks - subscribed!

  • @Besmudged
    @Besmudged 6 років тому +8

    Great video! one question though, every internal node in the tree currently contains 4 points itself with this piece of code, while its children also contain 4 points each, which comes down to 4*4 + 4 = 20 points for each internal quadtree node with height 1. Aren't KD-trees defined to use only their leaves to store points in? (4*4=16)

    • @ABaumstumpf
      @ABaumstumpf 6 років тому +1

      His tree is a bit "special" :P

  • @traceeverett6647
    @traceeverett6647 5 років тому +1

    How are you viewing all that information from the console? Like the Size of the rectangle

    • @Olezero221
      @Olezero221 5 років тому

      Console.log( any variable, like the quadtree ) will print all that information to the browser console

    • @TheCodingTrain
      @TheCodingTrain  5 років тому

      This workflow series might help! ua-cam.com/play/PLRqwX-V7Uu6YxDKpFzf_2D84p0cyk4T7X.html&disable_polymer=true

    • @TheCodingTrain
      @TheCodingTrain  5 років тому

      oops, wrong link! ua-cam.com/play/PLRqwX-V7Uu6Zu_uqEA6NqhLzKLACwU74X.html

  • @Jkauppa
    @Jkauppa 3 роки тому

    if you have what 1-dimesional are in numbered partitions (certain width, 1-100, step-1, step-neighbors-0-to-n closest), then you can quickly narrow down, without having a central complicated structure, but the quad-octree binary tree is fine

    • @Jkauppa
      @Jkauppa 3 роки тому

      you can detach the three or two coordinates, to 1-d checks

    • @Jkauppa
      @Jkauppa 3 роки тому

      if you can skip completely any step you would be using n^2 comparisons, then you have defeated the need what you were going to non-needingly do

    • @Jkauppa
      @Jkauppa 3 роки тому

      pair-wise tests, instead, do what

    • @Jkauppa
      @Jkauppa 3 роки тому

      a solution structure

    • @Jkauppa
      @Jkauppa 3 роки тому

      abstract

  • @ChrisFotosMusic
    @ChrisFotosMusic 5 років тому

    I have a question about quadtrees for collision detection. Why not just establish a fixed grid where each square corresponds to an array, and when an object enters a square it gets pushed into that square's array, and then each object only checks for collisions between itself and other objects in the same array as it?

  • @adobeadobe1616
    @adobeadobe1616 Рік тому

    The one thing that is confusing me, and that I notice in yours aswell, is that you can draw more than the capacity in a square? If two are drawn before the first division, they are not counted for any further divisions in the given square. Not sure how much this matters, I think thats just for debugging and the algorithm still works, but not sure if thats a problem or not.

  • @Freedomkwok
    @Freedomkwok 2 роки тому

    did I catch a bug or I missed some step, the first point before the capacity is not divide into any of the four region?

  • @xiaoraymond941
    @xiaoraymond941 4 роки тому

    Nice! Learned a lot!

  • @pekerchou2119
    @pekerchou2119 Рік тому

    Great tutorial. Can you please help me with one question, in the class QuadTree of your code, the properties "this.northwest, this.northeast, this.southwest, and this.southeast" are all defined in subdivide() method of the class other than in the constructor method. Is it legal to do so, or is it better to put the following expressions: (this.northwest = null; this.southwest = null; this.southwest = null; this.southeast = null;) in the constructor method,then we can set their values in the subdivide() method. Many thanks for your help and time.

  • @Error-pb6ee
    @Error-pb6ee 2 роки тому

    great class! i enjoined and learn a lot! thank you!

  • @LeslieSolorzanov
    @LeslieSolorzanov 4 роки тому +1

    That bell is going to drive me crazy. D:

  • @kjanimates
    @kjanimates Рік тому

    In the subdivide function, instead of setting the x,y,w,h manually, you could instead have javascript do it for you! By replacing those with
    let { x, y, w, h } = this.boundary;

  • @OlivierDALET
    @OlivierDALET 4 роки тому +1

    Seeing the trouble you had with ne, nw, se, sw (It challenges my brains the same btw), I wonder what your octree video shall look like :)

  • @musicalbeast
    @musicalbeast 6 років тому +125

    Its not exponential >:(

    • @TheCodingTrain
      @TheCodingTrain  6 років тому +57

      Yes, oops. "polynomial" is correct, yes? Exponential would be 2^n?

    • @filipposoldati1472
      @filipposoldati1472 6 років тому +8

      yes, it's just 100 times instead of 10 times but it's ok to get confused sometimes :P

    • @cazoulable
      @cazoulable 6 років тому +24

      well, polynomial is true but not very specific : O(n) and O(n^10) would also be polynomial.
      I guess the right term here is quadratic ! :)
      Absolutely love your video, keep up the good work with this amazing energy !

    • @malducci
      @malducci 5 років тому

      @@cazoulable non-linear polynomial hahah

    • @olivierdulac
      @olivierdulac Рік тому

      ​@@TheCodingTrain And then it is not log10(n) but log2(n), and 2exp10 is 1024, so for n:=1000 elements, it should take about 1000 x 10 = 10000 computational steps (not 3000)

  • @br3nto
    @br3nto 9 місяців тому

    Why quad and not binary here? Why divide the space by 4 instead of 2? Does it make the implementation easier with 4?

  • @SimonTiger
    @SimonTiger 5 років тому

    5:52 That's not entirely true. If two algoithms have the same big O, it does not mean they perform the same. It just means the graphs of them have (about) the same shape. Also, you didn't type the bas of the log you were computing. It's worst-case log base 4, but the base can be higher.

  • @mindaugasdudenas624
    @mindaugasdudenas624 6 років тому +1

    Tried to follow it up in processing, but somehow I missed few things, would be good if you would check the code more often just to see what results should I expect at a given point and time.

    • @mindaugasdudenas624
      @mindaugasdudenas624 6 років тому

      github.com/dudenas/QuadTree

    • @mindaugasdudenas624
      @mindaugasdudenas624 6 років тому +1

      I was wrong, it worked at the end, but still it would be good to have a check of code from time to time.

  • @pgrafhamster9160
    @pgrafhamster9160 4 роки тому

    I’m probably really late to ask this lol, but why does he not give the points already in the parent quad tree branch to the children subdivided quad tree branch, and then remove those references to the parent one? If let’s say it were to be used as a collision detection system, wouldn’t it cause problems not doing that?

  • @robbie_
    @robbie_ Рік тому

    I guess it really depends on what kind of data you've got. If it's more or less distributed evenly, not bunched up (e.g. not a gravity sim), I would think this method very slow compared to something like spatial hashing.

  • @AnthonyCook78
    @AnthonyCook78 4 роки тому

    Does the quadtree need to divided from the center point or can it be from the top left? Seems unnecessarily complicated to break out from the center.

    • @CivilF11
      @CivilF11 4 роки тому

      It does not need to be from the center at all. I think the reason he chose the center is so that it's easier to determine the x and y coordinates of the sub boundaries. But yes you absolutely do it from the top left as well you'd just have to adjust your numbers!

  • @aarondevelops
    @aarondevelops 16 днів тому

    you helped me a lot, thanks

  • @micky2be
    @micky2be 4 роки тому

    But it's not really done yet. You are not redistributing the points in the sub sections

  • @briturner11
    @briturner11 6 років тому +4

    a parent quad tree should either contain up to N points, or it should be "subdivided". Your code allows a parent quadrant to hold points and sub quadrants.

  • @danielmalka6824
    @danielmalka6824 Рік тому

    hi thats a great video! wonder, can i just use the QuadTreeNode ? it seems that i can save some cpu.. no?

  • @Shannxy
    @Shannxy Рік тому

    6:05 isn't the default log base 10? if you use a base 2 log the equation is more like 1000 * 10 = 10'000, not 3000

  • @persistent-programmer
    @persistent-programmer 4 місяці тому

    An optimization would be to calculate half_width and half_height once at the beginning locally instead of calculating it multiple times per quadrant.

  • @axelbrinck_
    @axelbrinck_ 4 роки тому

    can you use quadtrees to detect collision if you are not using points but circles?

  • @Tasarran
    @Tasarran Рік тому

    In your insert function, you almost had it, you only have to put the equal on two sides, solves the point in both.

  • @wiscatbijles
    @wiscatbijles 6 років тому +1

    The number of checks is actually 10 choose 2. 10! / (8! * 2!) = 90 / 2 = 45. The combination rule!

  • @ДарханВасильев-с7я

    For everyone who is interested I've implemented and tested QuadTree against naive and "spatial hash grid"(SHG) algorithms. Here are results of these tests relative to naive algorithm:
    100 entities: QuadTree is 20% slower, SHG is 2x faster.
    500 entities: QuadTree is 3x faster, SHG is 8x faster.
    1000 entities: QuadTree is 4.5x faster, SHG is 18x faster.
    5000 entities: QuadTree is 17x faster, SHG is 88x faster.
    10000 entities: QuadTree is 25x faster, SHG is 151x faster.
    As you can see SHG is much faster than quadtree, it is also mush simpler to implement and consumes less memory. Though you should take this with grain of salt, as my implementation may lack something important.

  • @Pompiduskus
    @Pompiduskus 6 років тому

    Awesome vids. =))) Super nice

  • @jasonw519
    @jasonw519 6 років тому

    I like your video. it is very straighforward.

  • @lumichlle1422
    @lumichlle1422 4 роки тому +1

    Hey that's a really good video! I have one question: Could I theoretically use this code and somehow change it to an octree by adjusting the rectangle to a cube and adding the according z coordinates? Or if this doesn't work, is there any other way? This would be a big help! Thanks!

    • @CivilF11
      @CivilF11 4 роки тому +2

      Absolutely you could do that! If you follow the basic theory of what he is doing, it shouldn't be terribly hard to implement! Of course drawing it to the screen is a different matter but yes you are very much correct!

    • @tycho25
      @tycho25 2 роки тому +1

      I did exactly that. I would suggest creating the children in a for loop instead of assigning each of them a variable upon subdivision, though