Solved

Python caller issue/ Grouping points into tiles

  • 19 February 2018
  • 2 replies
  • 0 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

icon

Best answer by daveatsafe 19 February 2018, 20:17

View original

2 replies

Userlevel 2
Badge +17

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.

Userlevel 2
Badge +17

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)

 

Reply