Skip to main content
Solved

Python caller issue/ Grouping points into tiles

  • February 19, 2018
  • 2 replies
  • 17 views

!

Hi

I am trying to use this python script which would be very helpful for me. I have a huge amount of data from a WFS which needs to be tiled in a good way. @takashi had a very good code, but I can’t get it to work in 2017.10.154 edition (the version I have).

I have a test file with more than 2000 points and I want tiles with 230 points each.

I have python installed on my computer and I am using the python caller.

I get error messages:

” FME Configuration: No destination coordinate system set

PythonFactory failed to load python symbol `FeatureProcessor'

Factory proxy not initialized f_4(PythonFactory): PythonFactory failed to process feature”

Why is that?

Any suggestions?

/Regards, Tobias

Best answer by daveatsafe

Hi @trydlinge,

In your PythonCaller, please change the Class or Function to Process Features to 'NonUniformBoxGenerator'. It is presently set to the default 'FeatureProcessor', but there is no class or function with that name in your script.

This post is closed to further activity.
It may be an old question, an answered question, an implemented idea, or a notification-only post.
Please check post dates before relying on any information in a question or answer.
For follow-up or related questions, please post a new question or idea.
If there is a genuine update to be made, please contact us and request that the post is reopened.

2 replies

daveatsafe
Safer
Forum|alt.badge.img+19
  • Safer
  • 1637 replies
  • Best Answer
  • February 19, 2018

Hi @trydlinge,

In your PythonCaller, please change the Class or Function to Process Features to 'NonUniformBoxGenerator'. It is presently set to the default 'FeatureProcessor', but there is no class or function with that name in your script.


takashi
Celebrity
  • 7843 replies
  • February 20, 2018

The script was created for the old pyfme module (maybe in FME 2013 and earlier), so it may not work in the current FME even if you have modified the parameter setting. This is updated version.

Note: Your sample data contains many duplicate points. In my observation, the maximum number of duplicates was 1330, so this script cannot finish iteration for dividing bounding box if you set  230 (less than 1330) to stopping condition. If you need to separate the duplicate points into groups having 230 or less points, the script would not be useful.

import fmeobjects

class NonUniformBoxGenerator(object):
    def __init__(self):
        self.points = [] # List of (x, y, point feature)
        self.boxId = 0 # Bounding Box ID
        
    def input(self, feature):
        # Extract coordinate and store the point feature.
        coord = feature.getCoordinate(0)
        self.points.append((coord[0], coord[1], feature))
        
    def close(self):
        # Calculate initial extent.
        xmin, ymin, p = self.points[0]
        xmax, ymax = xmin, ymin
        for x, y, p in self.points[1:]:
            if x < xmin:
                xmin = x
            elif xmax < x:
                xmax = x
            if y < ymin:
                ymin = y
            elif ymax < y:
                ymax = y
                
        # Start creating boxes.
        self.createBoundingBox((xmin, ymin, xmax, ymax), self.points)    
    
    # This method will be called recursively to divide box by four,
    # until the number of inside points becomes less than 230.
    def createBoundingBox(self, extent, points):
        xmin, ymin, xmax, ymax = extent
        
        if len(points) < 230:
            # Create a box polygon; output the polygon and inside points.
            # Output features can be classified by the GeometryFilter.
            coords = [(xmin,ymin),(xmax,ymin),(xmax,ymax),(xmin,ymax),(xmin,ymin)]
            boundary = fmeobjects.FMELine(coords)
            box = fmeobjects.FMEFeature()
            box.setGeometry(fmeobjects.FMEPolygon(boundary))
            box.setAttribute('_box_id', self.boxId)
            self.pyoutput(box)
            
            for x, y, p in points:
                p.setAttribute('_box_id', self.boxId)
                self.pyoutput(p)
            self.boxId += 1
            
        else:
            # Calculate extent of divided boxes.
            xc = (xmin + xmax) * 0.5 # Center X
            yc = (ymin + ymax) * 0.5 # Center Y
            extentList = [
                (xmin, ymin, xc, yc), # bottom-left
                (xc, ymin, xmax, yc), # bottom-right
                (xmin, yc, xc, ymax), # top-left
                (xc, yc, xmax, ymax) # top-right
            ]
            
            # Collect inside points for each box.
            pointsList = [[], [], [], []]
            for x, y, p in points:
                if y < yc:
                    if x < xc: # bottom-left
                        pointsList[0].append((x, y, p))
                    else: # bottom-right
                        pointsList[1].append((x, y, p))
                else:
                    if x < xc: # top-left
                        pointsList[2].append((x, y, p))
                    else: # top-right
                        pointsList[3].append((x, y, p))
            del points # save memory
            
            # Call the method for each box.
            for extent, points in zip(extentList, pointsList):
                self.createBoundingBox(extent, points)