Hi @ishback
Just a thought.
You could offset the line segments of your tree with a dedicated library (preferably one that handles intersections) and then adjust the vertices of the offsetted contour based on the depth of their closest tree node.
A quick example using the Clipper library in Python mode:
import clipper as cp
# List of nodes
nodes = [PVector(320, 682), PVector(332, 397),
PVector(194, 250), PVector(33, 205),
PVector(410, 175), PVector(255, 98),
PVector(343, 67), PVector(422, 76),
PVector(201, 53), PVector(510, 46)]
# Connectivity information (bottom-up) as a Python dictionary (tree)
d = {0: [1],
1: [2, 4],
2: [3, 5],
3: [],
4: [7, 9],
5: [8, 6],
6: [],
7: [],
8: [],
9: []}
# Maximum depth of that tree
max_depth = 5
def setup():
size(550, 700, P2D)
background(255)
smooth(8)
# Get all line segments
segs = [nodes[:3]]
for i in d.keys()[1:]:
p1 = nodes[i]
for j in d[i]:
if j != 2:
p2 = nodes[j]
segs.append([p1, p2])
# Offset those segments (distance=13)
contours = cp.OffsetPolyLines(segs, 13)
# Adjust contour vertices based on the depth of their closest node
for i, side in enumerate(contours):
for j, pt in enumerate(side):
pvec = PVector(*pt) #convert vertex to PVector (original vertices are in Clipper "Point" format)
closest_node, closest_index = get_closest(pvec, nodes) #find the index and location of closest node
dir = closest_node.copy().sub(pvec) #compute direction from vertex to closest node
factor = map(get_depth(closest_index), max_depth, 1, 0, 1) #compute a factor value based on the depth of that closest node
dir.mult(factor) #multiply direction vector by that value (the deeper the node, the closer is the associated vertex)
contours[i][j] = pvec.add(dir) #move node in this direction and update contours accordingly
# Draw the updated contours
for side in contours:
for p1, p2 in zip(side, side[1:] + side[:1]):
line(p1.x, p1.y, p2.x, p2.y)
def get_closest(p, cloud):
min_dist = 1000
closest_p = None
closest_i = None
for i, e in enumerate(cloud):
d = p.dist(e)
if d < min_dist:
min_dist = d
closest_p = e
closest_i = i
return closest_p, closest_i
def get_depth(k):
if not d[k]:
return 1
return 1 + max(get_depth(child) for child in d[k])