Skip to content

Instantly share code, notes, and snippets.

@mdamien
Last active November 3, 2019 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mdamien/71d03478fe66782e0863284eab387184 to your computer and use it in GitHub Desktop.
Save mdamien/71d03478fe66782e0863284eab387184 to your computer and use it in GitHub Desktop.
GeoSteiner output parser and import to blender
"""
FST (Full Steiner tree) generator Version 3 parser
Documentation: http://geosteiner.com/geosteiner-5.1-manual.pdf (page 186)
How to use: "./rand_points 10 | ./efst | ./bb -f | python3 fst2json.py"
To note, an alternate method is to grep for the " % @C XXX YYY" output from `bb`,
to get the Steiner points. (page 158 of the manual)
"""
import json
try:
input = raw_input
except NameError:
pass
def line():
return input().replace('\t', ' ').strip()
METRICS = ['Rectilinear', 'Euclidean', 'Graph']
FST_STATUS = ["never needed", "maybe needed", "always needed"]
data = {
"version": line(),
"instance": line(),
"metric": METRICS[int(line())],
"number_of_terminals": int(line()),
"length_minimum_steiner_tree": float(line().split()[0]),
"scaling_factor": line(),
"decimal_integrality": float(line().split()[0]),
"machine": line(),
"cpu_time": int(line()),
"number_of_FSTs": int(line()),
"terminals_coords": [],
"terminal_is_not_a_steiner_point": [],
"fsts": [],
}
for _ in range(data["number_of_terminals"]):
x, y = line().split()[:2]
data["terminals_coords"].append([
float(x),
float(y),
])
data["terminal_is_not_a_steiner_point"] = [int(x) for x in line().split()]
for _ in range(data["number_of_FSTs"]):
fst_data = {
"number_of_terminals": int(line()),
"terminals_indices": [int(x) for x in line().split()],
"length": float(line().split()[0]),
"n_steiner": int(line()),
"steiner_coords": [],
}
for _ in range(fst_data["n_steiner"]):
x, y = line().split()[:2]
fst_data["steiner_coords"].append([
float(x),
float(y),
])
fst_data["n_edges"] = int(line())
fst_data["edges"] = []
for _ in range(fst_data["n_edges"]):
origin, dest = line().split()
fst_data["edges"].append([int(origin), int(dest)])
fst_data["status"] = FST_STATUS[int(line())]
fst_data["n_incompatible_fsts"] = int(line())
if fst_data["n_incompatible_fsts"]:
fst_data["incompatible_fsts"] = line().split()
data["fsts"].append(fst_data)
print(json.dumps(data, indent=2))
# based on http://wiki.theprovingground.org/blender-py-mathmesh
# and https://askubuntu.com/questions/325485/how-to-make-a-mesh-by-using-python-script-on-blender#325515
import bpy
import math
from pprint import pprint as pp
import json
# clear mesh and object
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
data_path = "/path/to/your/fst2json/output"
data = json.load(open(data_path))
pp(data)
# mesh arrays
verts = []
faces = []
edges = []
# get real index of the point (page 181 of the manual)
def conv(fst, x):
# terminal
if x > 0: return fst["terminals_indices"][x - 1] - 1
# steiner point
if x < 0: return len(verts) - len(fst["steiner_coords"]) - x - 1
for x, y in data["terminals_coords"]:
verts.append((x, y, 0))
for fst in data["fsts"]:
for x, y in fst["steiner_coords"]:
verts.append((x, y, 0))
print('len verts', len(verts))
for org, dst in fst["edges"]:
print('edge', org, dst)
org, dst = conv(fst, org), conv(fst, dst)
print(' ->', org, dst)
edges.append((org, dst))
print(verts)
print(edges)
# sanity check to avoid crashes
for org, dst in edges:
if not (len(verts) > org >= 0 and len(verts) > dst >= 0):
print("verts=", len(verts), "org=", org, "dst=", dst)
ooops
#create mesh and object
mesh = bpy.data.meshes.new("steiner-tree")
object = bpy.data.objects.new("steiner-tree",mesh)
#set mesh location
object.location = bpy.context.scene.cursor_location
bpy.context.scene.objects.link(object)
#create mesh from python data
mesh.from_pydata(verts, edges,faces)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment