FME Geometry, PythonCaller, GenerativeArt

#main_script import fmeobjects import numpy as np from fmeobjects import FMELine, FMEPoint, FMEPolygon import math from sklearn.decomposition import PCA from sklearn.metrics.pairwise import rbf_kernel import numpy as np from numpy.lib.stride_tricks import sliding_window_view import shapely from collections import namedtuple arr = np.arange(16) window_size = 5 step = 2 STEP = 2 """ generate watermelon slice """ def perpendicular_segment_np(x0, y0, x1, y1, width): p0 = np.array([x0, y0]) p1 = np.array([x1, y1]) d = p1 - p0 u = d / np.linalg.norm(d) # unit direction n = np.array([-u[1], u[0]]) # perpendicular half = width / 2 perp_start = (p0 - n*half, p0 + n*half) perp_end = (p1 - n*half, p1 + n*half) return perp_start, perp_end def compute_bearing(x0,y0,x1,y1): delta_x,delta_y = x1- x0, y1 - y0 theta = math.atan2(delta_x, delta_y) return (math.degrees(theta) + 360) % 360 def smooth_polyline(n=200, scale=10, seed=0): rng = np.random.RandomState(seed) t = np.linspace(0, 5, n)[:, None] noise = rng.randn(n, 4) K = rbf_kernel(t, t, gamma=1/scale) smooth_noise = np.dot(K, noise) data = np.column_stack([t.ravel(), smooth_noise]) pts = PCA(n_components=2).fit_transform(data) return pts class FeatureProcessor(object): def __init__(self): pass def input(self, feature: fmeobjects.FMEFeature): lines = smooth_polyline(n=200, scale=20, seed=0) pline_input = list(map(tuple, lines)) tri_line = FMELine(pline_input) out_feat = fmeobjects.FMEFeature(feature) out_feat.setGeometry(tri_line) self.pyoutput(out_feat) _geom = out_feat.getGeometry() length = int(_geom.getLength(False)) _step = STEP _sequence = [(i, min(i + _step, length)) for i in range(0, length, _step)] group_size = 3 segments = [] for i, j in enumerate(_sequence): # crucial step to workaround # inplace geom modification _clone = out_feat.clone() end = j[-1] start = j[0] seq_group_floating = end // group_size _clone.setAttribute('end',end) _clone.setAttribute('start',start) _clone.setAttribute('seq_num',i) _clone.setAttribute('seq_group2',seq_group_floating) _clone.performFunction(f"@Snip({start}, {end}, 1)") self.pyoutput(_clone) # get coords of snipped geom snipped_geom = out_feat.getGeometry() _start = _clone.getGeometry().getStartPoint().getXYZ() _end = _clone.getGeometry().getEndPoint().getXYZ() x0,y0,z0 = _start x1,y1,z1 = _end bearing = compute_bearing(x0,y0,x1,y1) perp_start, perp_end = perpendicular_segment_np(x0, y0, x1, y1, width=2.0) perp_start_fme, perp_end_fme = list(map(tuple, perp_start)), list(map(tuple, perp_end)) perp_line_start,perp_line_end = FMELine(perp_start_fme), FMELine(perp_end_fme) out_perp_line_start,out_perp_line_end = fmeobjects.FMEFeature(feature),fmeobjects.FMEFeature(feature) # Garage # science # use i // 4 == 0: to group 4 elements at a time into polygons window_index = i // 4 out_perp_line_start.setAttribute("window_index",window_index) out_perp_line_end.setAttribute("window_index",window_index) out_perp_line_start.setGeometry(perp_line_start) out_perp_line_end.setGeometry(perp_line_end) self.pyoutput(out_perp_line_start) self.pyoutput(out_perp_line_end)