Copyright (C) 1994, Digital Equipment Corp.
by Steve Glassman and Stephen Harrison
<*PRAGMA LL*> MODULEA TreeView provides the basic structure for a tree. A tree must be further sub-typed to provide more appropriate or efficient representations for specific kinds of trees; RadialTree
IMPORT GenericTree, Math, MG, R2, R2Box; CONST Pi = FLOAT(Math.Pi, LONGREAL); TwoPi = 2.0D0 * Pi; TYPE GV = GenericTree.V; GT = GenericTree.GenericTree; GST = GenericTree.SubTree; REVEAL (* parent of a Tree must be a Tree. angle field is set if child is a tree *) V = GV BRANDED OBJECT END; T = GT BRANDED OBJECT depth := 0; angle := 0.0D0; radius := 0.0; OVERRIDES init := Init; calculateSize := Size; translate := Translate; END;calculate the maximum child radius, then the actual radius of node. Must be MAX(2 * max child radius + node's graphic's radius, max child radius / sin(2 * pi/num children)) latter is the chord distance between children
PROCEDUREcenter the node at north - diameter/2, west + diameterSize (node: T; v: GV) = VAR maxChildDiameter, chordalDiameter := 0.0; diameter: REAL; ch := node.succ(v, NIL); bounds := node.graphic.appearance.boundingBox(node.graphic, v); size := R2Box.Size(bounds); BEGIN node.radius := MAX(size[0], size[1]) / 2.0; IF node.numChildren > 0 THEN WHILE ch # NIL DO maxChildDiameter := MAX(maxChildDiameter, ch.width); ch := node.succ(v, ch); END; IF node.numChildren > 2 THEN chordalDiameter := maxChildDiameter / FLOAT( Math.sin(Pi / FLOAT(node.numChildren, LONGREAL))); END; node.radius := node.radius + MAX(node.dxChildren + maxChildDiameter / 2.0, chordalDiameter / 2.0); END; diameter := 2.0 * node.radius + maxChildDiameter; node.width := diameter; node.height := diameter; END Size;
PROCEDURETranslate (node: T; v: GV; north, west: REAL) = VAR ppos := GenericTree.ParentPos(node.parent, v); xCenter := ppos[0] + west + node.width / 2.0; yCenter := ppos[1] + north - node.height / 2.0; ch := node.succ(v, NIL); pos := MG.PosLocked(node, v); BEGIN IF node.parent = NIL THEN node.depth := 0; ELSE node.depth := NARROW(node.parent, T).depth + 1; END; IF GenericTree.LinearAnimation( v, R2.T{xCenter - pos[0], yCenter - pos[1]}, node) THEN VAR alpha := TwoPi / FLOAT(MAX(2, node.numChildren), LONGREAL); theta := node.angle; BEGIN IF node.depth # 0 THEN theta := theta + Pi + alpha / 2.0D0; IF theta > TwoPi THEN theta := theta - TwoPi END; END; WHILE ch # NIL DO TYPECASE ch OF | T (treeChild) => treeChild.angle := theta; ELSE END; ch.translate( v, node.radius * FLOAT(Math.sin(theta)) + ch.height / 2.0, node.radius * FLOAT(Math.cos(theta)) - ch.width / 2.0); ch := node.succ(v, ch); theta := theta + alpha; END; END; END; END Translate; PROCEDUREInit (t: T; v: GV; graphic: MG.T): GST = BEGIN EVAL GT.init(t, v, graphic); WITH diameter = MAX(t.width, t.height), dChildren = MAX(t.dxChildren, t.dyChildren) DO t.width := diameter; t.height := diameter; t.dxChildren := dChildren; t.dyChildren := dChildren; END; RETURN t; END Init; BEGIN END RadialTree.