FME Geometry, PythonCaller, GenerativeArt
#main_script
import fmeobjects
import numpy as np
from fmeobjects import FMELine, FMEPoint, FMEPolygon
import math
from sklearn.cluster import KMeans
from sklearn.neighbors import KDTree
from sklearn.manifold import TSNE
from sklearn.cluster import SpectralClustering
"""
Generate a network using spectral clustering
Spectral clustering shines on non-convex shapes where KMeans fails
"""
def generate_spectral_network(n_points=200, n_clusters=5, n_neighbors=3, seed=42):
# output: [((x1,y1), (x2,y2)), ...] connected coordinate pairs
rng = np.random.RandomState(seed)
angles = rng.uniform(0, 2 * np.pi, n_points)
radii = rng.choice([3, 7, 12], size=n_points)
noise = rng.randn(n_points, 2) * 0.5
points = np.column_stack([
radii * np.cos(angles),
radii * np.sin(angles)
]) + noise
spectral = SpectralClustering(
n_clusters=n_clusters,
affinity="nearest_neighbors",
n_neighbors=n_neighbors * 2,
random_state=seed,
assign_labels="kmeans"
)
labels = spectral.fit_predict(points)
tree = KDTree(points)
_, indices = tree.query(points, k=n_neighbors + 1)
edges_idx = set()
for i, neighbors in enumerate(indices):
for j in neighbors[1:]:
edges_idx.add((min(i, j), max(i, j)))
edges = [
(
(float(points[i][0]), float(points[i][1])),
(float(points[j][0]), float(points[j][1]))
)
for i, j in edges_idx
]
return edges
class FeatureProcessor(object):
def __init__(self):
pass
def input(self, feature: fmeobjects.FMEFeature):
lines = generate_spectral_network(n_points=210, n_clusters=5, n_neighbors=7, seed=42)
print(lines)
# 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)