Solved

Looking for sample python code (for PythonCaller transformer) that can iterate through various parts of a feature geometry and process part's coordinates.

  • 17 January 2022
  • 5 replies
  • 6 views

Badge

Hello ,

 

I have a feature geometry with two parts (IFMEMultiArea with two IFMEPolygons). Using PythonCaller transformation, I want process line segments in various parts of the geometry.

  • Is there an API for getting the coordinates of any part of geometry?fme-comm-geom-with-two-parts

I am able to get the part count as follows:

partsCount = feature.numParts(True,True)

 

I can get the parts as follows:

areaPart = feature.getGeometry().getPartAt(0)

 

But I could not find a suitable API for getting coordinates of a particular part in the API documentation.

 

Thanks in advance.

 

Regards,

Byju

 

 

icon

Best answer by ebygomm 17 January 2022, 11:43

View original

5 replies

Badge +10

There may be a more direct way but you could do something like this

partFeature = fmeobjects.FMEFeature()
partFeature.setGeometry(feature.getGeometry().getPartAt(0))
coords = partFeature.getAllCoordinates()

 

Userlevel 4

Iterating over the parts in Python is fairly easy, but modifying the coordinates on all the parts in Python can be surprisingly complicated depending on on the complexity of the features. You'd basically need to deconstruct and rebuild all the geometry parts, with all their specific methods.

 

Are you 100% sure that you cannot achieve your goal using transformers such as the AffineWarper or the Affiner?

 

On a side note: some years ago I requested something like a coordinate iterator with a custom callback in the fmepython libraries, but I do not think this was ever implemented. That would have made this fairly easy.

Badge

Iterating over the parts in Python is fairly easy, but modifying the coordinates on all the parts in Python can be surprisingly complicated depending on on the complexity of the features. You'd basically need to deconstruct and rebuild all the geometry parts, with all their specific methods.

 

Are you 100% sure that you cannot achieve your goal using transformers such as the AffineWarper or the Affiner?

 

On a side note: some years ago I requested something like a coordinate iterator with a custom callback in the fmepython libraries, but I do not think this was ever implemented. That would have made this fairly easy.

Thank you for the suggestion of Affiner and AffineWarper. I might need them as my work need to find the closest line segment which is parallel to a line through a given point and angle.

 

(Here ESRI dimension is being exploded as text, lines and points. Special variant of dimensions has underline for the dimension text. In the image you see rectangles around the text. The line at the bottom side of the text will be taken as underline.)

 

Though I had developed few custom Reader/Writer modules for FME very long time ago, my experience with transformers is very limited! Any help will be appreciated.

Badge

There may be a more direct way but you could do something like this

partFeature = fmeobjects.FMEFeature()
partFeature.setGeometry(feature.getGeometry().getPartAt(0))
coords = partFeature.getAllCoordinates()

 

Thanks for the suggestion of building a new feature with part geometry. I failed to see that option. So I came up with an alternative coding as follows:

if(partsCount == 2):

      areaPart = feature.getGeometry().getPartAt(0)

      polyline = areaPart.getBoundaryAsCurve()

      point1 = polyline.getPointAt(2)

      point2 = polyline.getPointAt(3)

      (x1,y1,z1) = point1.getXYZ()

      (x2,y2,z2) = point2.getXYZ()

Userlevel 4

In case it's useful, here is some sample code to iterate over geometry parts in a PythonCaller:

from fmeobjects import *
 
def FeatureHandler(feature):
    # Decompose aggregates / donuts, if necessary
    if feature.getGeometryType() == FME_GEOM_AGGREGATE:
        aggregate_parts = feature.splitAggregate(True)
    elif feature.getGeometryType() == FME_GEOM_DONUT:
        aggregate_parts = feature.getDonutParts()
    else:
        aggregate_parts = [feature,]
    
    for part in aggregate_parts:
        geom_type = part.getGeometryType()
        if geom_type == FME_GEOM_POINT:
            # Handle point geometry
        elif geom_type == FME_GEOM_LINE:
            # Handle line geometry
        elif geom_type == FME_GEOM_POLYGON:
            # Handle polygon geometry
        else:
            raise FMEException('Unsupported geometry type: ' + str(geom_type))

You can easily extend the if/elif block to handle additional geometry types.

Reply