2013-10-30

Advanced Geometric Operation: Divide a Line at Equal Interval

There are many transformers for geometric operations in FME Workbench; one of them or combination of some transformers can do most of all geometric operations we need usually. But sometimes, I encounter a case which needs to create a custom transformer or Python scripting.

I think that dividing a line at equal interval is one of such cases, and also that is relatively frequent required operation.
The Snipper transformer can be used to divide a line. However, it divides a line into only two parts (snipped and remnant) per one processing. If I set the length of the snipped part as the specified interval, the dividing operation has to be performed repeatedly while the length of the remnant part is greater than specified interval.

So, I think a custom transformer having a loop is an effective solution to do that.
This screenshot is a simplified example without any validation against input features.
Note: Actually the LengthCalculator and the Tester may not be essential. But when lacking them, the Workbench will display warning messages.
=====
2013-11-25
It is a kind of "reinventing the wheel". FME Store provides the IterativeSnipper_2013 custom transformer. Look at this as an exercise for the loop functionality of a custom transformer.
=====










Similar operation can be also defined as Python script for the PythonCaller.
-----
# Example: Divide Line at Equal Interval
# 2013-11-27 Modified
import fmeobjects

class LineDivider(object):
    def __init__(self):
        self.geomCloner = fmeobjects.FMEFeature()
   
    def input(self, feature):
        try:
            interval = float(feature.getAttribute('_interval'))
            if interval < 1.0e-6:
                raise fmeobjects.FMEException()
           
            dim = int(feature.getAttribute('_length_dimension'))
            measure3D = (True if dim == 3 else False)
       
            remnant = feature.getGeometry()
            if isinstance(remnant, fmeobjects.FMESimpleArea):
                remnant = remnant.getBoundaryAsCurve()
       
            curveList = []
            while interval < remnant.getLength(measure3D):
                self.geomCloner.setGeometry(remnant)
                curve = self.geomCloner.getGeometry()
                curve.snip(fmeobjects.SNIP_DISTANCE, measure3D, 0, interval)
                curveList.append(curve)
                remnant.snip(fmeobjects.SNIP_DISTANCE, measure3D, interval, -1)
            if 0.0 < remnant.getLength(measure3D):
                curveList.append(remnant)
       
            for i, geom in enumerate(curveList):
                feat = feature.cloneAttributes()
                feat.setGeometry(geom)
                feat.setAttribute('_index', i)
                feat.setAttribute('_result', 'success')
                feat.setCoordSys(feature.getCoordSys())
                self.pyoutput(feat)
        except:
            feature.setAttribute('_result', 'fail')
            self.pyoutput(feature)
       
    def close(self):
        pass
-----

Next: Effective Cloner

2 comments:

  1. Yes, I learned the Cloner method recently. Thanks.
    And, please call me just Takashi. "mr." is too formal.

    ReplyDelete
  2. Sorry, I deleted the original comment by mistaking. Recover here. Takashi

    Original comment from Anonymous:
    -----
    ..a cloner and a snipper will do.

    table based (arbitrary lengths): a merger, listexploder and snipper

    no iteration required.

    Hey! Hi mr.Takashi!
    -----

    ReplyDelete