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)