Question

Help with creating geometries from Python


Userlevel 4
Badge +26

Hi guys, I'm after a bit of help for creating FME Geometries with a Python Caller.

 

The module I'm using is giving me an object in the following form (it should be a TIN)

 

 

[((x1, y1, z1), (x2, y2, z2), (xn, yn, zn)), ((next triangle)), ((last triangle))]

 

 

I want to have this as a multi polygon or TIN and my Python skills are fairly lacking. My first thought was to try and format it as WKT in FME but I figured there must be a more elegant way to do this in the Python script itself.

 

 

Any suggestions on the best approach here would be nice. The ideal output would be either a multi-polygon or Multi-Surface.

11 replies

Badge

I think you could use the FMEFace class.

Here's how you can create a simple FMEFace in the PythonCreator:

import fmeobjects

class FeatureCreator(object):
    def __init__(self):
        pass
        
    def input(self,feature):
        newFeature = fmeobjects.FMEFeature()
        points = [(0,0,0),(1,0,0),(1,1,0)]
        mode = 0
        newFeature.setGeometry(fmeobjects.FMEFace(points,mode))
        self.pyoutput(newFeature)
        
    def close(self):
        pass

The points variable holds the coordinate tuples of your TIN so you just need to loop through your triangles creating FMEFaces and then you could create a MultiSurface or Mesh by passing in the newly created FMEFaces.

Also, have a look at FMETriangleFan & FMETriangleStrip, I think you can create them in a similar way and they might be useful in your scenario.

 

 

Hope this helps!
Userlevel 4

Based on @gerhardatsafe, here's the code adapted to the specific use case with aggregate / MultiSurface generation:

from fmeobjects import *

MY_TRIANGLES = [((0,0,0),(1,0,0),(2,1,1)), ((0,0,0),(2,1,1),(2,2,1))]

class CreateTriangles(object):

    def __init__(self):
        pass
        
    def input(self, feature):
        triangles = MY_TRIANGLES
        
        aggregate = FMEAggregate()  # or FMEMultiSurface()
        for triangle in triangles:
            # Add first vertex as last to close polygon
            vertices = list(triangle) + [triangle[0],]
            mode = 0
            aggregate.appendPart(FMEFace(vertices, mode))
                
        feature.setGeometry(aggregate)
        self.pyoutput(feature)
        
    def close(self):
        pass
Badge +2

Here's my thought on how to do it. Tin example.fmwTin Data.txt

 

You can use a regular expression to do the string replacers but for this example it's best to show each step so it's easy to understand the basic flow.

 

I used arbitrary data

 

[((4, 3, 7), (2, 3, 1), (3, 2, 3), (10, 3, 7), (4, 3, 1), (2, 2, 3))]

 

 

 

 

 

Userlevel 4
Badge +26

Based on @gerhardatsafe, here's the code adapted to the specific use case with aggregate / MultiSurface generation:

from fmeobjects import *

MY_TRIANGLES = [((0,0,0),(1,0,0),(2,1,1)), ((0,0,0),(2,1,1),(2,2,1))]

class CreateTriangles(object):

    def __init__(self):
        pass
        
    def input(self, feature):
        triangles = MY_TRIANGLES
        
        aggregate = FMEAggregate()  # or FMEMultiSurface()
        for triangle in triangles:
            # Add first vertex as last to close polygon
            vertices = list(triangle) + [triangle[0],]
            mode = 0
            aggregate.appendPart(FMEFace(vertices, mode))
                
        feature.setGeometry(aggregate)
        self.pyoutput(feature)
        
    def close(self):
        pass

This is just what I was hoping for David. I will give this a testing. Part of my struggle was adding that extra vertex. I really need to play with Python more. I think it can add so much power to an FME workspace. I will report back with my results. 

Userlevel 4
Badge +26

I think you could use the FMEFace class.

Here's how you can create a simple FMEFace in the PythonCreator:

import fmeobjects

class FeatureCreator(object):
    def __init__(self):
        pass
        
    def input(self,feature):
        newFeature = fmeobjects.FMEFeature()
        points = [(0,0,0),(1,0,0),(1,1,0)]
        mode = 0
        newFeature.setGeometry(fmeobjects.FMEFace(points,mode))
        self.pyoutput(newFeature)
        
    def close(self):
        pass

The points variable holds the coordinate tuples of your TIN so you just need to loop through your triangles creating FMEFaces and then you could create a MultiSurface or Mesh by passing in the newly created FMEFaces.

Also, have a look at FMETriangleFan & FMETriangleStrip, I think you can create them in a similar way and they might be useful in your scenario.

 

 

Hope this helps!

Thanks Gerhard! This is what I was playing with but I had some issues. I will report back once I've played around little more

Userlevel 4

This is just what I was hoping for David. I will give this a testing. Part of my struggle was adding that extra vertex. I really need to play with Python more. I think it can add so much power to an FME workspace. I will report back with my results.

FME and Python is a really powerful combo, that's for sure.

Userlevel 4
Badge +26

FME and Python is a really powerful combo, that's for sure.

Just FYI David, This worked perfectly and was just what I needed to get me going! Thanks a bunch

Userlevel 4

Just FYI David, This worked perfectly and was just what I needed to get me going! Thanks a bunch

Thanks for the kind words Matt, glad to hear it was useful.

Badge +3

Based on @gerhardatsafe, here's the code adapted to the specific use case with aggregate / MultiSurface generation:

from fmeobjects import *

MY_TRIANGLES = [((0,0,0),(1,0,0),(2,1,1)), ((0,0,0),(2,1,1),(2,2,1))]

class CreateTriangles(object):

    def __init__(self):
        pass
        
    def input(self, feature):
        triangles = MY_TRIANGLES
        
        aggregate = FMEAggregate()  # or FMEMultiSurface()
        for triangle in triangles:
            # Add first vertex as last to close polygon
            vertices = list(triangle) + [triangle[0],]
            mode = 0
            aggregate.appendPart(FMEFace(vertices, mode))
                
        feature.setGeometry(aggregate)
        self.pyoutput(feature)
        
    def close(self):
        pass

hi ,how set setAppearance for geomeatry, i want add color texture , the AppearanceSetter transform run slower

Badge

hi ,how set setAppearance for geomeatry, i want add color texture , the AppearanceSetter transform run slower

Hi @charry​ I would recommend creating a new post for your question if you are having problems with the performance of the AppearanceSetter.

Badge +3

hi ,how set setAppearance for geomeatry, i want add color texture , the AppearanceSetter transform run slower

hi , if i can set color for FMEFace use python,@david_r (Partner) gerhardatsafe (Safer)

Reply