FME Geometry, PythonCaller, GenerativeArt
#main_script
import fmeobjects
import numpy as np
from fmeobjects import FMELine, FMEPoint, FMEPolygon
import numpy as np
import math
from sklearn.cluster import KMeans
from sklearn.neighbors import KDTree
from sklearn.decomposition import PCA
"""
Generate a network of connected points:
"""
def generate_connected_network(n_points=55, n_clusters=3, n_neighbors=11, seed=7):
rng = np.random.RandomState(seed)
# generate rand points
raw_points = rng.randn(n_points, 2) * 33
# clustering
kmeans = KMeans(n_clusters=n_clusters, random_state=seed, n_init=10)
labels = kmeans.fit_predict(raw_points)
# Connect neighbors by KDTree
tree = KDTree(raw_points)
distances, indices = tree.query(raw_points, k=n_neighbors + 1) # +1 because self is included
edges_idx = set()
for i, neighbors in enumerate(indices):
for j in neighbors[1:]: # skip self (index 0)
edge = (min(i, j), max(i, j)) # undirected
edges_idx.add(edge)
# 4. Rotate with PCA (align principal axis to X)
pca = PCA(n_components=2)
points = pca.fit_transform(raw_points)
# edge list
edges = [
((points[i][0], points[i][1]), (points[j][0], points[j][1]))
for i, j in edges_idx
]
return points, edges, labels
class FeatureProcessor(object):
def __init__(self):
pass
def input(self, feature: fmeobjects.FMEFeature):
points, lines, b = generate_connected_network(n_points=55, n_clusters=3, n_neighbors=2, seed=7)
# output the star boundary
for i,line in enumerate(lines):
tri_ring = (list(map(tuple, line)))
tri_line = FMELine([tuple(p) for p in tri_ring])
out_feat = fmeobjects.FMEFeature(feature)
out_feat.setGeometry(tri_line)
self.pyoutput(out_feat)
for i,point in enumerate(points):
pt_coords = tuple(point)
pt = FMEPoint()
newX, newY = pt_coords
newZ = 0
pt.setXYZ(newX, newY, newZ)
out_feat = fmeobjects.FMEFeature(feature)
out_feat.setGeometry(pt)
out_feat.setAttribute("label",str(b[i]))
self.pyoutput(out_feat)