Solved

Is there a way to batch get river/road width?

  • 25 August 2018
  • 5 replies
  • 24 views

I've got thousands of thin polygon and their centreline. And I can calculate average width of each by using polygon area divide centreline length. I want to generate some random width number based on the average width and the numbers are between max and min width of the polygon.

My first thought is to create points along the centreline with small interval like 1 meter, and create station lines based on the points. Then use polygon to clip these station lines, the shortest and longest length of station lines will be the max and min range. So I can generate random width numbers in excel.

I've already got the interval points by using @takashi 's LineDivider, and some articles about calculate line angle and create bearing line. I just want to know if there's an easier way to do so, and only in FME. To get my thought work, I have to switch between FME and ArcGIS, and also some third party add-on in ArcGIS. It is too complicated for others to use it.

icon

Best answer by takashi 25 August 2018, 23:21

View original

5 replies

Userlevel 3
Badge +17

I suppose that you are going to generate section lines perpendicular to the centerline, with a certain interval. If I understood your requirement correctly, this workflow might help you.

  1. LineDivider (from FME Hub): Split the center line with a certain interval.
  2. CoordinateExtractor: Extract coordinates of the last vertex for each split line.
  3. VertexRemover: Keep only the first vertex.
  4. VertexCreator: Add the last vertex to the first vertex to form line segment.
  5. CenterPointExtractor: Extract coordinates of the center point for each line segment.
  6. Rotator: Rotate the line segment around the center point by 90 degrees.
  7. LineExtender: Extend the line segments by a certain length to make them cross with the polygon.

I suppose that you are going to generate section lines perpendicular to the centerline, with a certain interval. If I understood your requirement correctly, this workflow might help you.

  1. LineDivider (from FME Hub): Split the center line with a certain interval.
  2. CoordinateExtractor: Extract coordinates of the last vertex for each split line.
  3. VertexRemover: Keep only the first vertex.
  4. VertexCreator: Add the last vertex to the first vertex to form line segment.
  5. CenterPointExtractor: Extract coordinates of the center point for each line segment.
  6. Rotator: Rotate the line segment around the center point by 90 degrees.
  7. LineExtender: Extend the line segments by a certain length to make them cross with the polygon.

Thank you very much, Mr.Takashi. I got it work yesterday, but my way is a little complicated, I used TopologyBuilder to get the rotate angle and VertexCreator to create a line segment along the X axis, then rotated the segment by the angle and angle+180, at last used LineCombiner combine two segment together.

 

 

Furthermore, now I have the minimum, maximum and average length of the polygon, I'd like to generate some random number like 5, between minimum and maximum length based on average length. I've tried RandomNumberGenerator, it output the right number between the range, but all 5 numbers' average number doesn't equal to the desired average number. Any ideas? I'm thinking maybe Python, but I can't Google any result.
Userlevel 3
Badge +17

I suppose that you are going to generate section lines perpendicular to the centerline, with a certain interval. If I understood your requirement correctly, this workflow might help you.

  1. LineDivider (from FME Hub): Split the center line with a certain interval.
  2. CoordinateExtractor: Extract coordinates of the last vertex for each split line.
  3. VertexRemover: Keep only the first vertex.
  4. VertexCreator: Add the last vertex to the first vertex to form line segment.
  5. CenterPointExtractor: Extract coordinates of the center point for each line segment.
  6. Rotator: Rotate the line segment around the center point by 90 degrees.
  7. LineExtender: Extend the line segments by a certain length to make them cross with the polygon.

This custom transformer generates pseudo random numbers which are within minimum and maximum and also average of them is equal to a specified average value.

 

rangerandomnumbergenerator.zip (FME 2018.1.0.0)

 

The logic is simple. I think you can implement a Python script with the same logic.

 

Hope this helps.

I suppose that you are going to generate section lines perpendicular to the centerline, with a certain interval. If I understood your requirement correctly, this workflow might help you.

  1. LineDivider (from FME Hub): Split the center line with a certain interval.
  2. CoordinateExtractor: Extract coordinates of the last vertex for each split line.
  3. VertexRemover: Keep only the first vertex.
  4. VertexCreator: Add the last vertex to the first vertex to form line segment.
  5. CenterPointExtractor: Extract coordinates of the center point for each line segment.
  6. Rotator: Rotate the line segment around the center point by 90 degrees.
  7. LineExtender: Extend the line segments by a certain length to make them cross with the polygon.

Thanks again! I've tried an alternative way which I created an excel template with formula "if (average($A2:$E2)=$F2,A2, randbetween($G2,$H2)), F2, G2, H2 are average, minimum and maximum number.

 

But randbetween only support integer, I have to convert them first then convert them back.

 

The custom transformer you attached is more efficient.

 

Thank you very much. How do you know so much! Do you work for Safe Software?

 

 

Userlevel 3
Badge +17
Thanks again! I've tried an alternative way which I created an excel template with formula "if (average($A2:$E2)=$F2,A2, randbetween($G2,$H2)), F2, G2, H2 are average, minimum and maximum number.

 

But randbetween only support integer, I have to convert them first then convert them back.

 

The custom transformer you attached is more efficient.

 

Thank you very much. How do you know so much! Do you work for Safe Software?

 

 

Good to hear. No, I'm not a Safer, but my company is a partner of Safe Software ;-)

 

Addition. This is a Python script example.

 

# PythonCaller Script Example:
# Generates pseudo random numbers within specified range,
# and stores them into a list attribute called "_random_number{}".
# Average of the random numbers will be equal to specified average value.
# Assume the input feature has these attributes.
# _num: the number of random numbers to be generated
# _min: minimun of the range
# _max: maximum of the range
# _average: the average value (_min < _average < _max)
def generateRandomNumbers(feature):
    rmin = float(feature.getAttribute('_min'))
    rmax = float(feature.getAttribute('_max'))
    n = int(feature.getAttribute('_num'))
    a = float(feature.getAttribute('_average'))
    if 0 < n and rmin < a and a < rmax:
        rands = []
        generate(rmin, rmax, n, a, rands)
        for i, r in enumerate(rands):
            feature.setAttribute('_random_number{%d}' % i, r)

def generate(rmin, rmax, n, a, rands):
    if n == 1:
        rands.append(a)
    else:
        from random import uniform
        r = uniform(a, rmin if (a - rmin < rmax - a) else rmax)
        if n % 2 == 1:
            rands.append(r)
            n -= 1
            generate(rmin, rmax, n, a + (a - r) / n, rands)
        else:
            n /= 2
            generate(rmin, rmax, n, r, rands)
            generate(rmin, rmax, n, a + (a - r), rands)

 

Reply