Skip to main content
Solved

python caller for loops

  • February 14, 2020
  • 6 replies
  • 102 views

Forum|alt.badge.img

Hello,

I want to calculate slope between neighbor points. I want to use python caller to do something like take the first point (pointID is smallest) go to the next one , calculate the slope between the points and write it in a new attribute (_slope). Then go to the next point (so 2nd and 3rd) calculate slope and save the value.

I am new with python in fme, so could you help me?

Best answer by paalped

import fmeobjects
from functools import reduce
from math import sin, pi

def left_slope(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    
    a_x = float(feature_a.getAttribute('x'))    
    a_y = float(feature_a.getAttribute('y'))
    a_z = float(feature_a.getAttribute('z'))

    b_x = float(feature_b.getAttribute('x'))
    b_y = float(feature_b.getAttribute('y'))
    b_z = float(feature_b.getAttribute('z'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 

    planar_distance = ((a_x-b_x)**2 + (a_y - b_y)**2)**(1/2) 
    delta_z = b_z - a_z
    slope_degree = sin(delta_z/planar_distance) * 180 /pi

    feature_a.setAttribute('_slope', slope_degree)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left_slope, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is a funky solution. It assumes feature are sorted by your point ID definition.

View original
Did this help you find an answer to your question?

6 replies

ebygomm
Influencer
Forum|alt.badge.img+31
  • Influencer
  • February 14, 2020

If the points are in order, this can be done without using a python caller using Adjacent attribute handling. If you have the coordinates exposed, by selecting enable adjacent feature attributes and choosing 1 subsequent feature, you can access the coordinate attributes of the next feature to use in whatever formula you are using for calculating a slope.


paalped
Contributor
Forum|alt.badge.img+5
  • Contributor
  • Best Answer
  • February 17, 2020
import fmeobjects
from functools import reduce
from math import sin, pi

def left_slope(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    
    a_x = float(feature_a.getAttribute('x'))    
    a_y = float(feature_a.getAttribute('y'))
    a_z = float(feature_a.getAttribute('z'))

    b_x = float(feature_b.getAttribute('x'))
    b_y = float(feature_b.getAttribute('y'))
    b_z = float(feature_b.getAttribute('z'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 

    planar_distance = ((a_x-b_x)**2 + (a_y - b_y)**2)**(1/2) 
    delta_z = b_z - a_z
    slope_degree = sin(delta_z/planar_distance) * 180 /pi

    feature_a.setAttribute('_slope', slope_degree)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left_slope, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is a funky solution. It assumes feature are sorted by your point ID definition.


Forum|alt.badge.img
  • Author
  • February 17, 2020
paalped wrote:
import fmeobjects
from functools import reduce
from math import sin, pi

def left_slope(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    
    a_x = float(feature_a.getAttribute('x'))    
    a_y = float(feature_a.getAttribute('y'))
    a_z = float(feature_a.getAttribute('z'))

    b_x = float(feature_b.getAttribute('x'))
    b_y = float(feature_b.getAttribute('y'))
    b_z = float(feature_b.getAttribute('z'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 

    planar_distance = ((a_x-b_x)**2 + (a_y - b_y)**2)**(1/2) 
    delta_z = b_z - a_z
    slope_degree = sin(delta_z/planar_distance) * 180 /pi

    feature_a.setAttribute('_slope', slope_degree)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left_slope, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is a funky solution. It assumes feature are sorted by your point ID definition.

Thank, it solved my problem. Now I want to multiply the slope_degrees the same way (first point * secod pont, second point * third point). I am using the following script, but it gives an error, like: 

Python Exception <TypeError>: float() argument must be a string or a number
Traceback (most recent call last):
  File "<string>", line 23in close
  File "<string>", line 9in left
TypeError: float() argument must be a string or a number
PythonCaller_3(PythonFactory): PythonFactory failed to close properly
PythonCaller_3(PythonFactory): A fatal error has occurred. Check the logfile above for details

Here is my code, can you help me where is my mistake?

import fme
import fmeobjects
from functools import reduce

def left(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    a_z = float(feature_a.getAttribute('_slope'))
    b_z = float(feature_b.getAttribute('_slope'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 
 
    _slope_elojel = b_z - a_z
    feature_a.setAttribute('_slope_elojel', _slope_elojel)
    return feature_b
 
class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

paalped
Contributor
Forum|alt.badge.img+5
  • Contributor
  • February 17, 2020
paalped wrote:
import fmeobjects
from functools import reduce
from math import sin, pi

def left_slope(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    
    a_x = float(feature_a.getAttribute('x'))    
    a_y = float(feature_a.getAttribute('y'))
    a_z = float(feature_a.getAttribute('z'))

    b_x = float(feature_b.getAttribute('x'))
    b_y = float(feature_b.getAttribute('y'))
    b_z = float(feature_b.getAttribute('z'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 

    planar_distance = ((a_x-b_x)**2 + (a_y - b_y)**2)**(1/2) 
    delta_z = b_z - a_z
    slope_degree = sin(delta_z/planar_distance) * 180 /pi

    feature_a.setAttribute('_slope', slope_degree)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left_slope, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is a funky solution. It assumes feature are sorted by your point ID definition.

I totally forgot to mention to use coordinateextracor first to extract x,y,z from index 0 on a point feature class. Sort by pointID


paalped
Contributor
Forum|alt.badge.img+5
  • Contributor
  • February 18, 2020
paalped wrote:
import fmeobjects
from functools import reduce
from math import sin, pi

def left_slope(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    
    a_x = float(feature_a.getAttribute('x'))    
    a_y = float(feature_a.getAttribute('y'))
    a_z = float(feature_a.getAttribute('z'))

    b_x = float(feature_b.getAttribute('x'))
    b_y = float(feature_b.getAttribute('y'))
    b_z = float(feature_b.getAttribute('z'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 

    planar_distance = ((a_x-b_x)**2 + (a_y - b_y)**2)**(1/2) 
    delta_z = b_z - a_z
    slope_degree = sin(delta_z/planar_distance) * 180 /pi

    feature_a.setAttribute('_slope', slope_degree)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left_slope, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is a funky solution. It assumes feature are sorted by your point ID definition.

Hi, I think this error message will occure at the last feature processing. Cause _slope is missing on the last feature. you need to add a condition before casting to float. I can look at it tomorrow.

paalped
Contributor
Forum|alt.badge.img+5
  • Contributor
  • February 19, 2020
gylona wrote:

Thank, it solved my problem. Now I want to multiply the slope_degrees the same way (first point * secod pont, second point * third point). I am using the following script, but it gives an error, like: 

Python Exception <TypeError>: float() argument must be a string or a number
Traceback (most recent call last):
  File "<string>", line 23in close
  File "<string>", line 9in left
TypeError: float() argument must be a string or a number
PythonCaller_3(PythonFactory): PythonFactory failed to close properly
PythonCaller_3(PythonFactory): A fatal error has occurred. Check the logfile above for details

Here is my code, can you help me where is my mistake?

import fme
import fmeobjects
from functools import reduce

def left(feature_a, feature_b):
    # Note last feature wont have a slope attribute cause there is no feature to compare With
    a_z = float(feature_a.getAttribute('_slope'))
    b_z = float(feature_b.getAttribute('_slope'))
    
    # NOTE!! Evaluate formula before using, this is just from the far back of my head 
 
    _slope_elojel = b_z - a_z
    feature_a.setAttribute('_slope_elojel', _slope_elojel)
    return feature_b
 
class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left, self.features) 
        for feature in self.features:
            self.pyoutput(feature)

Here is an update:

 

import fme
import fmeobjects
from functools import reduce

def isnumeric(x):
    try:
        float(x)
        return True
    except:
        return False

def left(feature_a, feature_b):
    # Note last 2 feature wont have a _slope_elojel attribute cause there is no feature to compare With
    a_z = float(feature_a.getAttribute('_slope')) # exists in our case
    # Last feature_b has no slope
    b_z = feature_b.getAttribute('_slope')
    if isnumeric(b_z):
        b_z = float(b_z)
        _slope_elojel = b_z - a_z
        feature_a.setAttribute('_slope_elojel', _slope_elojel)
    return feature_b

class FeatureProcessor(object):
    def __init__(self):
        self.features = []
    def input(self,feature):
        self.features.append(feature)
    def close(self):
        reduce(left, self.features)
        for feature in self.features:
            self.pyoutput(feature)

Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings