Skip to main content
Solved

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

  • August 25, 2018
  • 5 replies
  • 135 views

bobo
Contributor
Forum|alt.badge.img+3
  • Contributor
  • 46 replies

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.

Best answer by takashi

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 post is closed to further activity.
It may be an old question, an answered question, an implemented idea, or a notification-only post.
Please check post dates before relying on any information in a question or answer.
For follow-up or related questions, please post a new question or idea.
If there is a genuine update to be made, please contact us and request that the post is reopened.

5 replies

takashi
Celebrity
  • 7843 replies
  • Best Answer
  • August 25, 2018

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.


bobo
Contributor
Forum|alt.badge.img+3
  • Author
  • Contributor
  • 46 replies
  • August 26, 2018

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.

takashi
Celebrity
  • 7843 replies
  • August 26, 2018

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.

bobo
Contributor
Forum|alt.badge.img+3
  • Author
  • Contributor
  • 46 replies
  • August 26, 2018

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?

 

 


takashi
Celebrity
  • 7843 replies
  • August 26, 2018
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)