问题
So I got 4 rectangular shapes and I'm trying to apply a sorting algorithm (painters algorithm) to know which shapes (in 3d) I need to draw first and which one after.
Note: The camera is in the bottom right corner:
The correct order would be: purple, red, blue, green (for drawing of course reversed order).
So I've implemented an algorithm which creates something like this: Theres every object listed with it's correct successors and predecessors.
ITEM: red
predecessor: -
successor: -
ITEM: green
predecessor: -
successor: red
ITEM: blue
predecessor: green
successor: red
ITEM: purple
predecessor: blue, green
successor: blue, red
How can I sort the items based on the information above to get the correct order? Any help would be really appreciated.
let digraph = {
red: {
predecessor: [],
successor: []
},
green: {
predecessor: [],
successor: ["red"]
},
blue: {
predecessor: ["green"],
successor: ["red"]
},
purple: {
predecessor: ["blue", "green"],
successor: ["blue", "red"]
}
}
let itinerary = {}
for (let e of Object.keys(digraph)) {
if (digraph[e].successor.length != 0) itinerary[e] = digraph[e]
}
//console.log(itinerary)
let sorted_pile = []
let overflow = 0;
while (Object.keys(itinerary).length) {
overflow++;
if (overflow > 40) {
console.error("OVERFLOW");
break;
}
let key = Object.keys(itinerary)[0],
entity = itinerary[key];
delete itinerary[key];
sorted_pile.push(key)
let successors = digraph[key].successor
for (succ of successors) {
digraph[succ].predecessor = digraph[succ].predecessor.filter(function(item) {
return item !== key;
})
if (digraph[succ].predecessor.length === 0) itinerary[key] = digraph[succ]
}
}
console.log(sorted_pile)
Edit:
let tile_entities = [
{x: 8, y: 0, w: 1, h: 5, id: "rot"},
{x: 5, y: 0, w: 2, h: 1, id: "gruen"},
{x: 7, y: 0, w: 1, h: 1, id: "blau"},
{x: 4, y: 5, w: 4, h: 2, id: "lila"},
]
回答1:
I think this does what you want, but I start with an altered version of your input. It's easy enough to transform it, but you might be able to generate this input directly from your current process. (Note that the successor
information is not needed, since it's derivable from the predecessors
)
const isEmpty = arr => arr.length == 0
const removeIndex = (n, arr) => arr.slice(0, n).concat(arr.slice(n + 1))
const sortDigraph = (
digraph,
sorted = [],
idx = digraph.findIndex(node => isEmpty(node.predecessor)),
nodeName = (digraph[idx] || {}).name
) => isEmpty(digraph)
? sorted
: sortDigraph(
removeIndex(idx, digraph).map(({name, predecessor}) => ({
name,
predecessor: predecessor.filter(n => n !== nodeName)
}), digraph),
sorted.concat(nodeName)
)
let digraph = [
{name: 'blue', predecessor: ["green"]},
{name: 'green', predecessor: []},
{name: 'orange', predecessor: ["green"]},
{name: 'purple', predecessor: ["blue", "green"]},
{name: 'red', predecessor: ["yellow"]},
{name: 'yellow', predecessor: ["green", "orange"]},
]
console.log(sortDigraph(digraph))
The basic idea is that you can start with any one that has no predecessors, and then strike out any predecessor links to it from the other ones, and repeat the process. So long as your graph is acyclic, this should simply work. If you have to deal with the more complicated case of the Painter's Algorithm, then you will need to break apart your nodes before trying this.
来源:https://stackoverflow.com/questions/54408175/how-to-sort-objects-painters-algorithm