26 |
import org.fenfire as ff |
import org.fenfire as ff |
27 |
from org.fenfire.vocab import STRUCTLINK, RDF |
from org.fenfire.vocab import STRUCTLINK, RDF |
28 |
from org.fenfire.vocab.lava import MINDSTRUCT |
from org.fenfire.vocab.lava import MINDSTRUCT |
29 |
|
from org.fenfire.util.lava import Traversals |
30 |
from org.fenfire.fenmm import MindNet |
from org.fenfire.fenmm import MindNet, MMGeometry |
31 |
|
|
32 |
def p(*s): |
def p(*s): |
33 |
print 'mindMapView2D', s |
print 'mindMapView2D', s |
115 |
vs.coords.activate(cs) |
vs.coords.activate(cs) |
116 |
|
|
117 |
class MindMapView2D(ff.view.View2D): |
class MindMapView2D(ff.view.View2D): |
118 |
def __init__(self, fen, context, depth): |
def __init__(self, fen, context): |
119 |
self.fen = fen |
self.fen = fen |
120 |
self.context = context |
self.context = context |
121 |
|
|
122 |
self.multiplexer = self.context.multiplexer |
self.multiplexer = self.context.multiplexer |
123 |
|
|
124 |
self.filletWidth = 15. # divider |
self.depth = 5 |
125 |
self.filletLength = 4. # divider |
self.filletWidth = 20 |
126 |
self.rotation = 0. |
self.filletLength = 150 |
127 |
|
self.initRotation = 0 |
|
self.maxDepth = depth |
|
|
|
|
|
self.box = None |
|
|
|
|
|
# Stored data to help interpolation to nodes next to accursed |
|
|
self.current = {'centerNode': None, 'startAngle': 0., 'rotationAngle': 0.} |
|
|
self.previous = {'centerNode': None, 'startAngle': 0., 'rotationAngle': 0.} |
|
128 |
|
|
129 |
# fillet set up |
# fillet set up |
130 |
self.angle = 1 |
self.angle = 1 |
148 |
self.tblsize = 20 |
self.tblsize = 20 |
149 |
self.mode = 0 |
self.mode = 0 |
150 |
|
|
151 |
def getNodeSize(self, depth): |
self.oldCenter = None |
|
"""Node size is relative to depth as 1-(Math.log(depth)/Math.E).""" |
|
|
assert depth <= self.maxDepth, 'Depth is greater than maxDepth.' |
|
|
|
|
|
s =(self.box[1] * 1./self.filletWidth) * self.context.getScale(depth) |
|
|
if dbg: p('fillet size:', s) |
|
|
return s |
|
|
|
|
|
def getDistance(self, depth): |
|
|
"""Node distance is relative to depth as 1-(Math.log(depth)/Math.E).""" |
|
|
assert depth <= self.maxDepth, 'Depth is greater than maxDepth.' |
|
|
if depth == 0: return 0 |
|
|
|
|
|
d = (self.box[0] * 1./self.filletLength) * self.context.getScale(depth) |
|
|
if dbg: p('fillet length: ', d) |
|
|
return d |
|
152 |
|
|
153 |
def render(self, vs, node, |
def render(self, vs, node, |
154 |
matchingParent, box2screen, box2plane): |
matchingParent, box2screen, box2plane): |
155 |
self.matchingParent = matchingParent |
self.matchingParent = matchingParent |
|
# p("Rendering view.") |
|
|
|
|
|
# if dbg: |
|
|
# p('Drawing screenbox') |
|
|
# dbg1 = vs.unitSqCS(box2screen, "UNIT_SCREEN") |
|
|
# vs.put(vob.coloredQuad((0,1,0)), dbg1) |
|
|
|
|
|
# paper2box = vs.invertCS(box2plane, "minMap_INv") |
|
|
# paper2screen = vs.concatCS(box2screen, 'mindMap_CONCAT', |
|
|
# paper2box) |
|
156 |
|
|
157 |
paper2screen = vs.concatCS(box2screen, 'mindMap_CONCAT', |
paper2screen = vs.concatCS(box2screen, 'mindMap_CONCAT', |
158 |
box2plane) |
box2plane) |
159 |
box = jarray.zeros(2, 'f') |
box = jarray.zeros(2, 'f') |
160 |
vs.coords.getSqSize(box2screen, box) |
vs.coords.getSqSize(box2screen, box) |
|
self.box = box |
|
|
|
|
161 |
paper2screen = vs.translateCS(paper2screen, 'mindMap_TRANS', |
paper2screen = vs.translateCS(paper2screen, 'mindMap_TRANS', |
162 |
box[0], box[1], 0) |
box[0], box[1], 0) |
163 |
# XXX |
# XXX |
164 |
self.zoomPanCS = paper2screen |
self.zoomPanCS = paper2screen |
165 |
|
|
166 |
# links between nodes and also storin nodes currently. |
path = Traversals.findShortestPath((self.oldCenter or node), |
167 |
self.net = MindNet() |
STRUCTLINK.linkedTo, |
168 |
|
node, self.fen.graph) |
169 |
|
if not path or path.size() == 0: |
170 |
### Get the cs for center node |
path = java.util.ArrayList(1) |
171 |
pl = self.getPlace(vs, paper2screen, 0,0, node, 0,0) |
path.add(node) |
172 |
self.net.put(node, pl, 0) |
|
173 |
|
geometry = MMGeometry(self.fen.graph, self.filletLength, self.filletWidth, |
174 |
# If update interpolation help data only, if has moved |
self.initRotation, self.depth) |
175 |
if self.current['centerNode'] != node: self.previous = self.current.copy() |
self.net = geometry.buildMindNet(vs, paper2screen, path) |
|
|
|
|
links = self.getLinks(self.fen, node) |
|
|
|
|
|
# Now, let's see, where we have came from... |
|
|
previousIndex = None |
|
|
currentIndex = None |
|
|
if (self.previous['centerNode'] != None): |
|
|
previousLinks = self.getLinks(self.fen, self.previous['centerNode']) |
|
|
try: |
|
|
previousIndex = previousLinks.index(node) |
|
|
currentIndex = links.index(self.previous['centerNode']) |
|
|
except ValueError: pass |
|
|
|
|
|
if len(links) == 0: |
|
|
self.net.link(node, node) # XXX probably not the right way |
|
|
if len(links) > 0: |
|
|
rotationAngle = 2*Math.PI / float(len(links)) |
|
|
|
|
|
# Calculates the "correct" starting angle |
|
|
if previousIndex != None and currentIndex != None: |
|
|
startAngle = self.previous['startAngle'] \ |
|
|
+ self.previous['rotationAngle']*float(previousIndex)-Math.PI \ |
|
|
+ rotationAngle*float(len(links)-currentIndex) |
|
|
else: startAngle = 0 |
|
|
|
|
|
for i in range(2, self.maxDepth+1): |
|
|
self.doMindMapCS(vs, paper2screen, node, None, links, 0,0, |
|
|
startAngle + self.rotation, rotationAngle, 1, i) |
|
|
self.current['startAngle'] = startAngle |
|
|
self.current['rotationAngle'] = rotationAngle |
|
176 |
self.drawMindMap(vs) |
self.drawMindMap(vs) |
177 |
self.current['centerNode'] = node |
self.oldCenter = node |
178 |
|
|
179 |
def drawMindMap(self, vs): |
def drawMindMap(self, vs): |
180 |
i = self.net.iterator() |
i = self.net.iterator() |
182 |
node = i.next() |
node = i.next() |
183 |
pl = self.net.getPlace(node) |
pl = self.net.getPlace(node) |
184 |
if pl == None: continue |
if pl == None: continue |
185 |
c = [ pl[0] ] |
c = [ pl.cs ] |
186 |
|
|
187 |
it = self.net.iterator(node) |
it = self.net.iterator(node) |
188 |
while it.hasNext(): |
while it.hasNext(): |
189 |
n = it.next() |
n = it.next() |
190 |
pl2 = self.net.getPlace(n) |
pl2 = self.net.getPlace(n) |
191 |
if pl2 == None: continue |
if pl2 == None: continue |
192 |
c.append(pl2[0]) |
c.append(pl2.cs) |
193 |
if dbg: p('info:', pl2[0], pl2[1], pl2[2]) |
if dbg: p('info:', pl2.cs, pl2.x, pl2.y) |
194 |
|
|
195 |
if dbg: p('Fillet coordinates:', c) |
if dbg: p('Fillet coordinates:', c) |
196 |
def pc(conns, cs): |
def pc(conns, cs): |
202 |
vob.fillet.light3d.drawFillets(self, vs, pc) |
vob.fillet.light3d.drawFillets(self, vs, pc) |
203 |
|
|
204 |
# draw text etc.. |
# draw text etc.. |
205 |
cs = vs.coords.translate(pl[0], 0,0, -100) |
cs = vs.coords.translate(pl.cs, 0,0, -100) |
206 |
vs.matcher.add(self.matchingParent, cs, node) |
vs.matcher.add(self.matchingParent, cs, node) |
207 |
self.putNodeContent(vs, node, cs) |
self.putNodeContent(vs, node, cs) |
208 |
|
|
|
def getLinks(self, fen, node): |
|
|
"""Get all links available with node.""" |
|
|
nodes = [] |
|
|
iter = fen.graph.findN_11X_Iter(node, STRUCTLINK.linkedTo) |
|
|
while iter.hasNext(): |
|
|
nodes.append(iter.next()) |
|
|
iter = fen.graph.findN_X11_Iter(STRUCTLINK.linkedTo, node) |
|
|
while iter.hasNext(): |
|
|
nodes.append(iter.next()) |
|
|
if dbg: p('Found linked nodes: ', nodes) |
|
|
return nodes |
|
|
|
|
|
def doMindMapCS(self, vs, into, centerNode, oldCenter, links, x, y, |
|
|
startAngle, rotationAngle, depth, maxDepth): |
|
|
""" Recursively go through all cs """ |
|
|
fen = self.fen |
|
|
|
|
|
if depth < maxDepth: |
|
|
for i in range(len(links)): |
|
|
link = links[i] |
|
|
if link == centerNode: raise 'own node!!' |
|
|
if self.net.hasBeenLinked(centerNode, link): continue |
|
|
self.net.link(centerNode, link) |
|
|
|
|
|
if self.net.getPlace(link) == None: |
|
|
pl = self.getPlace(vs, into, x, y, link, startAngle+rotationAngle*i, depth) |
|
|
if dbg: p('Add a new node', pl) |
|
|
self.net.put(link, pl, depth) |
|
|
else: |
|
|
pl = self.net.getPlace(link) |
|
|
if dbg: p('Reached an old node', pl) |
|
|
|
|
|
if depth >= maxDepth: return |
|
|
for i in range(len(links)): |
|
|
link = links[i] |
|
|
if link == oldCenter: continue |
|
|
|
|
|
place = self.net.getPlace(link) |
|
|
newLinks = self.getLinks(fen, link) |
|
|
newAngle = Math.PI*2./float(len(newLinks)) |
|
|
|
|
|
fromIndex = None |
|
|
try: fromIndex = newLinks.index(centerNode) |
|
|
except ValueError: pass |
|
|
if fromIndex != None: |
|
|
newStartAngle = (startAngle+rotationAngle*i-Math.PI) \ |
|
|
+ newAngle*float(len(newLinks)-fromIndex) |
|
|
else: newStartAngle = 0 |
|
|
|
|
|
self.doMindMapCS(vs, into, link, centerNode, newLinks, place[1], place[2], |
|
|
newStartAngle, newAngle, depth + 1, maxDepth) |
|
|
|
|
|
def getPlace(self, vs, into, x0,y0, key, angle, depth): |
|
|
xy = self.getXY(x0,y0, angle, depth) |
|
|
x,y = xy[0], xy[1] |
|
|
|
|
|
s = self.getNodeSize(depth) |
|
|
if (dbg): print 'size', s |
|
|
cs = vs.orthoBoxCS(into,'foo'+str(key),depth, x-s/2.0,y-s/2.0, 1,1, s,s) |
|
|
if dbg: |
|
|
p('Place seed:',x0, y0, angle) |
|
|
p('Constructed place:',cs, xy, angle, s) |
|
|
return [cs, x, y, angle] |
|
|
|
|
|
def getXY(self, x0, y0, angle, depth): |
|
|
if depth == 0: return [0,0] |
|
|
|
|
|
r = self.getDistance(depth) |
|
|
x = x0 + Math.sin(angle) * r |
|
|
y = y0 + Math.cos(angle) * r |
|
|
return [x,y, r] |
|
|
|
|
|
|
|
209 |
def putNodeContent(self, vs, node, cs): |
def putNodeContent(self, vs, node, cs): |
210 |
# scaling after depth |
# scaling after depth |
211 |
depth = self.net.getDepth(node) |
depth = self.net.getDepth(node) |
212 |
scale = self.context.getTextScale(depth) |
scale = ff.fenmm.MMGeometry.getScale(depth) |
213 |
|
textScale = ff.fenmm.MMGeometry.getTextScale(depth) |
214 |
|
|
215 |
p = self.multiplexer.f(self.fen.graph, node) |
p = self.multiplexer.f(self.fen.graph, node) |
216 |
|
|
217 |
x = self.getNodeSize(depth)/2 - (p.getWidth()*scale)/2.0 |
x = (self.filletWidth*scale)/2 - (p.getWidth()*textScale)/2.0 |
218 |
y = self.getNodeSize(depth)/2 - (p.getHeight()*scale)/2.0 |
y = (self.filletWidth*scale)/2 - (p.getHeight()*textScale)/2.0 |
219 |
|
|
220 |
cs = vs.orthoBoxCS(cs,node,0, x,y, scale, scale, p.getWidth(), p.getHeight()) |
cs = vs.orthoBoxCS(cs,node,0, x,y, textScale, textScale, p.getWidth(), p.getHeight()) |
221 |
p.place(vs, cs) |
p.place(vs, cs) |
222 |
vs.coords.activate(cs) |
vs.coords.activate(cs) |