6

I'm trying to optimize a sort for an isometric renderer. What is proving tricky is that the comparitor can return "A > B", "A < B", or "the relationship between A and B is ambiguous." All of the standard sorting algorithms expect that you can compare the values of any two objects, but I cannot do that here. Are there known algorithms that are made for this situation?

For example, there can be a situation where the relationship between A and C is ambiguous, but we know A > B, and B > C. The final list should be A,B,C.

Note also that there may be multiple solutions. If A > B, but C is ambiguous to both A and B, then the answer may be C,A,B or A,B,C.

Edit: I did say it was for sorting in an isometric renderer, but several people asked for more info so here goes. I've got an isometric game and I'm trying to sort the objects. Each object has a rectangular, axis-aligned footprint in the world, which means that they appears as a sort of diamond shapes from the perspective of the camera. Height of the objects is not known, so an object in front of another object is assumed to be capable of occluding the one in the back, and therefore must be drawn after (sorted later in the list than) the one in the back.

I also left off an important consideration, which is that a small number of objects (the avatars) move around.

Edit #2: I finally have enough rep to post pictures! A and B...well, they aren't strictly ambiguous because in each case they have a definite relationship compared to each other. However, that relationship cannot be known by looking at the variables of A and B themselves. Only when we look at C as well can we know what order they go in.

I definitely think topographical sort is the way to go, so I'm considering the question answered, but I'm happy to make clarifications to the question for posterity.

enter image description here

  • As Eric answered (and has since deleted) can't you just use a standard sort but assume ambiguous is equal or no swap? If you use a sort that can potentially do multiple comparisons per element against all others e.g. bubble sort then the ordering should definitely resolve itself; but even if you don't, e.g. the quicksort that Eric suggested, you ought still end up with something that fits one of your multiple solutions. – Rup Apr 22 '15 at 01:21
  • You could first do a normal bubble sort. But if the realtionship between two elements is ambiguous you don't swap them. Next you go through the sorted list and whenever you find an element whose relationship to it's neighbours is ambiguous you check whether it is smaller or bigger than any of the other elements in the list. – Tesseract Apr 22 '15 at 01:22
  • 2
    Can you add more information about the objects being compared? What are they? How the ambiguity arises?... Maybe a clever user can see a non trivial relationship among the elements if you add more information about the nature of the objects being compared – higuaro Apr 22 '15 at 04:29
  • Additional info added. I had drawn a nice picture, only to discover I don't have the rep to post pictures. >< I think we are doing something like the bubble sort idea now, and it's problematic. The relationship between most objects is ambiguous, so we spend a lot of time comparing objects vs all the other objects. I'm leaning towards topological sorting, as while it has expensive setup, the per-frame sorting is close to linear. – Patrick Cyr Apr 23 '15 at 09:09
  • Can you share with us statistic data of ambiguous comparison? If you have `n` element, O(n^2) comparison pars, how many of them are ambiguous? How many of elements have at least one element which cannot be compared with him? How many elements have exactly one such element? Maybe specific building BST or sorting part of data and after using topological sort is sufficient to receive nice expected time. – Tacet Apr 23 '15 at 09:47
  • Your edit doesn't describe an ambiguity. If you know that object A is in front of object B, then the heights don't matter. You need to explain on what fields you're sorting, and why that causes an ambiguity. – Jim Mischel Apr 23 '15 at 20:51
  • Tacet: Most are ambiguous. In a scene with maybe 100 objects, each object only needs to be in front or behind maybe on average 5 other objects, with the min being zero and max being maybe 10 or 15. – Patrick Cyr Apr 27 '15 at 18:28

2 Answers2

4

You may want to look at sorts for partial orders.

https://math.stackexchange.com/questions/55891/algorithm-to-sort-based-on-a-partial-order links to the right papers on this topic (specifically topological sorting).

Edit:

Given the definition of the nodes:

You need to make sure objects never can cause mutual occlusion. Take a look at the following grid, where the camera is in the bottom left corner.

______
____X_
_YYYX_
_YXXX_
_Y____

As you can see, parts of Y are hidden by X and parts of X are hidden by Y. Any drawing order will cause weird rendering. This can be solved in many ways, the simplest being to only allow convex, hole-free shapes as renderable primitives. Anything concave needs to be broken into chunks.

If you do this, you can then turn your partial order into a total order. Here's an example:

def compare(a,b):
    if a.max_x < b.min_x:
        return -1
    elif a.max_y < b.min_y:
        return -1
    elif b.max_x < a.min_x:
        return 1
    elif b.max_y < a.min_y:
        return 1
    else:
        # The bounding boxes intersect
        # If the objects are both rectangular,
        # this should be impossible
        # If you allow non-rectangular convex shapes,
        # like circles, you may need to do something fancier here.
        raise NotImplementedException("I only handle non-intersecting bounding boxes")

And use any old sorting algortithm to give you your drawing order.

Community
  • 1
  • 1
Christophe Biocca
  • 3,388
  • 1
  • 23
  • 24
  • Well it links to one Wikipedia article which (I think) assumes that you've already built a DAG of all possible non-ambiguous comparisons, which is probably quite expensive per render frame. – Rup Apr 22 '15 at 01:18
  • Without knowing what is being sorted, I can't comment as to the efficiency or lack thereof. – Christophe Biocca Apr 22 '15 at 01:22
  • 1
    Hmm, this sounds pretty good. That linked question sounds exactly like what I'm trying to ask--makes me wonder if he's doing the same thing. I think building the initial DAG will be time consuming (n^2?), but thankfully on a per-frame basis only one or two objects at most will be moving around, so hopefully the DAG changes can be done in linear time. – Patrick Cyr Apr 23 '15 at 09:03
  • 1
    @PatrickCyr I've edited the question as I believe you *can* define a total order, and that will make your render pass faster. – Christophe Biocca Apr 23 '15 at 12:24
  • 1
    Thank you for the additional info, Christophe! We've built this engine around the rules that all objects are axis-aligned rects and can never overlap, so we will thankfully never have a situation like the one in your drawning. – Patrick Cyr Apr 23 '15 at 17:20
  • 1
    Great, then the comparator I gave you defines a *total* (as opposed to partial) order, and you can use any sorting function you want. – Christophe Biocca Apr 23 '15 at 20:18
0

You should first build a directed graph, using that graph you will be able to find the relationships, by DFS-ing from each node.

Once you have relationships, some pairs might still be ambiguous. In that case look for partial sorting.

Neithrik
  • 2,002
  • 2
  • 20
  • 33