Solved

Create lines between all polygon vertices

  • 11 January 2024
  • 6 replies
  • 17 views

Userlevel 3
Badge +26

 

I have a unique requirement that I'm racking my brain trying to find a solution. I have a set of irregular shaped polygons, and I would like to draw a line between all unique pair of vertices. In the crude example below, the black line represents the input polygon and the yellow represents the desired result. Ultimately, after building the lines, I want to query out the longest line for additional processing.image

icon

Best answer by hkingsbury 11 January 2024, 20:15

View original

6 replies

Badge +4

Hi @dustin, thank you for your question. To help you get started and find ideas, the following article and links are offered:

For filtering lines, the following links are offered:

Userlevel 5
Badge +29

I've made an example workbench in 2022.2 (attached) showing one way of doing it

Userlevel 3
Badge +26

I've made an example workbench in 2022.2 (attached) showing one way of doing it

Perfect, thanks @hkingsbury​ !

Userlevel 2
Badge +11

@dustin​ The number of lines between vertices should be 

n * (n - 1) / 2

which from @hkingsbury​ 's sample data should result in 66 lines. I'm attaching a modified workspace that does that and also finds the longest line.  The downside is that it uses TclCallers which will soon be deprecated. :^| Use for demonstration purposes only!

Userlevel 5
Badge +29

@dustin​ The number of lines between vertices should be 

n * (n - 1) / 2

which from @hkingsbury​ 's sample data should result in 66 lines. I'm attaching a modified workspace that does that and also finds the longest line.  The downside is that it uses TclCallers which will soon be deprecated. :^| Use for demonstration purposes only!

Good point Dan, it is still creating a lot of duplicate lines!

 

Spinning off of your TCL Idea, i've replicated it in python as well - Yet another great example of doing the same thing different ways in FME

import fme
import fmeobjects
from itertools import combinations
 
class FeatureProcessor(object):
    """Template Class Interface:
    When using this class, make sure its name is set as the value of the 'Class
    to Process Features' transformer parameter.
    """
 
    def __init__(self):
        """Base constructor for class members."""
        pass
 
    def input(self, feature):
        """This method is called for each FME Feature entering the 
        PythonCaller. If knowledge of all input Features is not required for 
        processing, then the processed Feature can be emitted from this method 
        through self.pyoutput(). Otherwise, the input FME Feature should be 
        cached to a list class member and processed in process_group() when 
        'Group by' attributes(s) are specified, or the close() method.
 
        :param fmeobjects.FMEFeature feature: FME Feature entering the 
            transformer.
        """
        xIn = (feature.getAttribute('_indices{}.x'))
        yIn = (feature.getAttribute('_indices{}.y'))
        zIn = (feature.getAttribute('_indices{}.z'))
        
        if zIn == None:
            zIn = [None]*len(xIn)
 
        pointsIn = list(zip(xIn[1:],yIn[1:],zIn[1:]))
        lines = list(combinations(pointsIn,2))
        
        for line in lines:
            feature.setAttribute('x1',line[0][0])
            feature.setAttribute('y1',line[0][1])
            feature.setAttribute('z1',line[0][2])
            feature.setAttribute('x2',line[1][0])
            feature.setAttribute('y2',line[1][1])
            feature.setAttribute('z2',line[1][2])
            self.pyoutput(feature)
 
    def close(self):
        """This method is called once all the FME Features have been processed
        from input().
        """
        pass
 
    def process_group(self):
        """When 'Group By' attribute(s) are specified, this method is called 
        once all the FME Features in a current group have been sent to input().
 
        FME Features sent to input() should generally be cached for group-by 
        processing in this method when knowledge of all Features is required. 
        The resulting Feature(s) from the group-by processing should be emitted 
        through self.pyoutput().
 
        FME will continue calling input() a number of times followed
        by process_group() for each 'Group By' attribute, so this 
        implementation should reset any class members for the next group.
        """
        pass
 
    def has_support_for(self, support_type):
        """This method returns whether this PythonCaller supports a certain type.
        The only supported type is fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM.
        
        :param int support_type: The support type being queried.
        :returns: True if the passed in support type is supported.
        :rtype: bool
        """
        if support_type == fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM:
            # If this is set to return True, FME will pass features to the input() method that
            # come from a feature table object. This allows for significant performance gains
            # when processing large numbers of features.
            # To enable this, the following conditions must be met:
            #   1) features passed into the input() method cannot be copied or cached for later use
            #   2) features cannot be read or modified after being passed to self.pyoutput()
            #   3) Group Processing must not be enabled
            # Violations will cause undefined behavior.
            return False
 
        return False

 

Userlevel 3
Badge +26

@danatsafe​ @hkingsbury​ Well done!👍

Reply