change dag implementation
This commit is contained in:
parent
9c8417780a
commit
054d3bc5e5
1 changed files with 33 additions and 39 deletions
|
@ -35,7 +35,7 @@ type DrawDAG struct {
|
||||||
Child interface{}
|
Child interface{}
|
||||||
Hides
|
Hides
|
||||||
|
|
||||||
*dag
|
dag
|
||||||
boxCache map[DrawBoxer]geom.Box // used to find components that moved
|
boxCache map[DrawBoxer]geom.Box // used to find components that moved
|
||||||
chunks map[image.Point]drawerSet // chunk coord -> drawers with bounding rects intersecting chunk
|
chunks map[image.Point]drawerSet // chunk coord -> drawers with bounding rects intersecting chunk
|
||||||
chunksRev map[DrawBoxer]image.Rectangle // comopnent -> rectangle of chunk coords
|
chunksRev map[DrawBoxer]image.Rectangle // comopnent -> rectangle of chunk coords
|
||||||
|
@ -108,7 +108,7 @@ func (DrawDAG) ManagesDrawingSubcomponents() {}
|
||||||
|
|
||||||
// Prepare adds all subcomponents to the DAG.
|
// Prepare adds all subcomponents to the DAG.
|
||||||
func (d *DrawDAG) Prepare(game *Game) error {
|
func (d *DrawDAG) Prepare(game *Game) error {
|
||||||
d.dag = newDAG()
|
d.dag = make(dag)
|
||||||
d.boxCache = make(map[DrawBoxer]geom.Box)
|
d.boxCache = make(map[DrawBoxer]geom.Box)
|
||||||
d.chunks = make(map[image.Point]drawerSet)
|
d.chunks = make(map[image.Point]drawerSet)
|
||||||
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
||||||
|
@ -319,76 +319,70 @@ func (s drawerSet) String() string {
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
type dag struct {
|
type edges struct {
|
||||||
all drawerSet
|
in, out drawerSet
|
||||||
in, out map[Drawer]drawerSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDAG() *dag {
|
type dag map[Drawer]edges
|
||||||
return &dag{
|
|
||||||
all: make(drawerSet),
|
|
||||||
in: make(map[Drawer]drawerSet),
|
|
||||||
out: make(map[Drawer]drawerSet),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dot returns a dot-syntax-like description of the graph.
|
// Dot returns a dot-syntax-like description of the graph.
|
||||||
func (d *dag) Dot() string {
|
func (d dag) Dot() string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteString("digraph {\n")
|
sb.WriteString("digraph {\n")
|
||||||
for v, e := range d.out {
|
for v, e := range d {
|
||||||
fmt.Fprintf(&sb, "%v -> %v\n", v, e)
|
fmt.Fprintf(&sb, "%v -> %v\n", v, e.out)
|
||||||
}
|
}
|
||||||
sb.WriteString(" }\n")
|
sb.WriteString(" }\n")
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// addEdge adds the edge u-v in O(1).
|
// addEdge adds the edge u-v in O(1).
|
||||||
func (d *dag) addEdge(u, v Drawer) {
|
func (d dag) addEdge(u, v Drawer) {
|
||||||
d.all[u], d.all[v] = struct{}{}, struct{}{}
|
d.addVertex(u)
|
||||||
if d.in[v] == nil {
|
d.addVertex(v)
|
||||||
d.in[v] = make(drawerSet)
|
d[v].in[u] = struct{}{}
|
||||||
}
|
d[u].out[v] = struct{}{}
|
||||||
if d.out[u] == nil {
|
|
||||||
d.out[u] = make(drawerSet)
|
|
||||||
}
|
|
||||||
d.in[v][u] = struct{}{}
|
|
||||||
d.out[u][v] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeEdge removes the edge u-v in O(1).
|
// removeEdge removes the edge u-v in O(1).
|
||||||
func (d *dag) removeEdge(u, v Drawer) {
|
func (d dag) removeEdge(u, v Drawer) {
|
||||||
delete(d.in[v], u)
|
delete(d[v].in, u)
|
||||||
delete(d.out[u], v)
|
delete(d[u].out, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addVertex ensures the vertex is present, even if there are no edges.
|
// addVertex ensures the vertex is present, even if there are no edges.
|
||||||
func (d *dag) addVertex(v Drawer) {
|
func (d dag) addVertex(v Drawer) {
|
||||||
d.all[v] = struct{}{}
|
if _, found := d[v]; found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d[v] = edges{
|
||||||
|
in: make(drawerSet),
|
||||||
|
out: make(drawerSet),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
||||||
func (d *dag) removeVertex(v Drawer) {
|
func (d dag) removeVertex(v Drawer) {
|
||||||
for u := range d.in[v] {
|
for u := range d[v].in {
|
||||||
d.removeEdge(u, v)
|
d.removeEdge(u, v)
|
||||||
}
|
}
|
||||||
for w := range d.out[v] {
|
for w := range d[v].out {
|
||||||
d.removeEdge(v, w)
|
d.removeEdge(v, w)
|
||||||
}
|
}
|
||||||
delete(d.all, v)
|
delete(d, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// topWalk visits each vertex in topological order, in time O(|V| + |E|) and
|
// topWalk visits each vertex in topological order, in time O(|V| + |E|) and
|
||||||
// O(|V|) temporary memory (for acyclic graphs) and a bit longer if it has to
|
// O(|V|) temporary memory (for acyclic graphs) and a bit longer if it has to
|
||||||
// break cycles.
|
// break cycles.
|
||||||
func (d *dag) topWalk(visit func(Drawer)) {
|
func (d dag) topWalk(visit func(Drawer)) {
|
||||||
// Count indegrees - indegree(v) = len(d.in[v]) for each vertex v.
|
// Count indegrees - indegree(v) = len(d.in[v]) for each vertex v.
|
||||||
// If indegree(v) = 0, enqueue. Total: O(|V|).
|
// If indegree(v) = 0, enqueue. Total: O(|V|).
|
||||||
queue := make([]Drawer, 0, len(d.in))
|
queue := make([]Drawer, 0, len(d))
|
||||||
indegree := make(map[Drawer]int)
|
indegree := make(map[Drawer]int)
|
||||||
for u := range d.all {
|
for u := range d {
|
||||||
// NB: zero indegree vertices may be missing from d.in
|
// NB: zero indegree vertices may be missing from d.in
|
||||||
e := d.in[u]
|
e := d[u].in
|
||||||
if len(e) == 0 {
|
if len(e) == 0 {
|
||||||
queue = append(queue, u)
|
queue = append(queue, u)
|
||||||
} else {
|
} else {
|
||||||
|
@ -421,7 +415,7 @@ func (d *dag) topWalk(visit func(Drawer)) {
|
||||||
|
|
||||||
// Decrement indegree for all out edges, and enqueue target if its
|
// Decrement indegree for all out edges, and enqueue target if its
|
||||||
// indegree is now 0.
|
// indegree is now 0.
|
||||||
for v := range d.out[u] {
|
for v := range d[u].out {
|
||||||
if _, ready := indegree[v]; !ready {
|
if _, ready := indegree[v]; !ready {
|
||||||
// Vertex already drawn. This happens if there was a cycle.
|
// Vertex already drawn. This happens if there was a cycle.
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in a new issue