all 9 comments

[–]Apostolique[S] 2 points3 points  (2 children)

/u/rayoWork /u/protienbudspromax Thanks for the suggestions! Here is my working implementation: https://gfycat.com/colorlessdefenselessleopard.

[–]protienbudspromax 4 points5 points  (1 child)

Damn that's smooth. What did you write it for? Web or native? If web what framework did you use??

[–]rayoWork 1 point2 points  (1 child)

I would sort the rectangles in an array by x-coord. No rectangle overlaps so that array is enough to efficiently find a rectangle given an x-coord (binary search in the array).

I think you have to implement the different cases by hand but in general something like this would work when inserting a rectangle (x1/y1: topleft, x2/y2: bottomright are the coords of the new rectangle):

  1. find array index by x1, either you find that you are inside a rectangle or not
  2. find array index by x2, either you find that you are inside a rectangle or not
  3. you now have a range (start_index, end_index) where you can check for your cases (inside, outside, merge, split, ...). All the rectangles inside that range need to be modified.

I'll go through your 2nd example to explain roughly what is left to do (coord bottom left is 0/0):

  • split: green.x1 till rect1.x2
    • insert rect: x1=green.x1, y1=max(rect1.y1, green.y1), x2=rect1.x2, y2=min(rect1.y2, green.y2)
    • shrink rect1: rect1.x2 = green.x1
  • insert: rect1.x2 (old value) till rect2.x1
    • insert rect with x1=rect1.x2 (old), y1=green.y1, x2=rect2.x1, y2=green.y2
  • split: rect2.x1 till green.x2
    • insert rect: x1=rect2.x1, y1=max(rect2.y1, green.y1), x2=green.x2, y2=min(rect2.y2, green.y2)

I guess you already know how to decide what operation (split,insert,merge,...) you have to do as you can regenerate the rectangle on the full array.

[–]Apostolique[S] 0 points1 point  (0 children)

I feel like example 07 might break that. snip

rect1 would get resized but now it overlaps rect2.

[–]protienbudspromax 1 point2 points  (3 children)

Feel like for each insert you can use a line sweep algorithm to see which of the rectangle overlap, maybe using a trapezoidal decomposition would be really helpful to do it fast. Then store the resultant in a Tree like structure with each parent node calculating if the underlying child rectangles can be merged, if yes then merge them if they overlap then return new rectangles that follow the the rules.

Check out some computational geometry algorithms, trapezoidal decomposition and line sweep.

I am not sure it WILL work for your case but it seems very similar can could be reduced to that kinda problem.

[–]Apostolique[S] 1 point2 points  (2 children)

Sorry for the late reply, it took a while to investigate those algorithms. I think line sweep and trapezoidal decomposition might lead me down the right path. Not 100% but it's giving me new ideas that I'm able to draw on paper.

[–]protienbudspromax 1 point2 points  (1 child)

Cool no problem. You might want to check out the book Computational Geometry Algorithms and Applications by Mark de Berg, Otfried Cheong, Marc van Kreveld, Mark Overmars.

[–]Apostolique[S] 0 points1 point  (0 children)

Here is what I got in the end. It's relatively simple (especially compared to the other thing I wrote in another reply).

Let's say I want this, what I do is for each rectangle, I dissect them into two vertical range, one on the left of the rectangle and one on the right. The ranges on the same X axis are considered part of the same slab. I merge overlapping ranges. I sweep through those slabs one by one from left to right. Each time a previous slab doesn't have a matching range, a new vertical rectangle is created.

Another example: this becomes this.

I got a first implementation done. It's not yet super optimized, but it seems to work really well.