Skip to main content

Hi guys,

I've been trying to auto-generate cadastral parcels using the start and end coordinates and radius values, and the process is working, but the python caller seems to be using the wrong centre point to generate the arcs in some instances (as there are always two potential points in trig). I'm using the init(twoPoints, radius, counterClockwise) function, where the sign of the radius indicates direction. I'm attaching a workbench which contains the generation of a section of blocks and the corresponding section area, and the outer boundaries of the two should match, but don't. I believe this is a trigonometry issue, the math behind the caller isn't working for an arc that's greater than a semi-circle. Does anyone have any ideas on how to fix this? Build 2017.0

Thank you in anticipation,

Katrina

Hi @katrinaopperman, as you mentioned, probably fmeobjects.FMEArc(twoPoints, radius, counterClockwise) always generates smaller arc than the hemi-circle.

How did you create the Section 59 table?

If you could add the coordinates of middle point for each arc to the table, you could create a correct arc from the three points - start, middle and end.


Hi @katrinaopperman, as you mentioned, probably fmeobjects.FMEArc(twoPoints, radius, counterClockwise) always generates smaller arc than the hemi-circle.

How did you create the Section 59 table?

If you could add the coordinates of middle point for each arc to the table, you could create a correct arc from the three points - start, middle and end.

Hi @takashi,

 

Thank you for replying so quickly.

 

The tables were created from an old GIS program. I'm trying to get the IT guys to amend it to extract additional information - it might be possible to extract the centre points of the arcs - but at the moment this is what I have to work with.

 

I'm concerned that the python is wrong though, as others might be using it without understanding the limitations. It seems to be universally applied - I've tried three pieces of software now, and they all seem to generate the same error if you only use the start, end and radius. Is there no way to fix it?

 


Hi @katrinaopperman, as you mentioned, probably fmeobjects.FMEArc(twoPoints, radius, counterClockwise) always generates smaller arc than the hemi-circle.

How did you create the Section 59 table?

If you could add the coordinates of middle point for each arc to the table, you could create a correct arc from the three points - start, middle and end.

I guess it's intentional that the FMEArc(twoPoints, radius, ccw) returns smaller one if there were two possible arcs in a condition determined by specified set of two points, radius and orientation.

 

I noticed that the "ARC_Dist" column in the table seems to contain the arc length. If so, it might be possible to calculate the middle point on the arc mathematically based on the two point, radius, orientation, and the arc length.

 

Or, if the goal is just to get a merged area of the blocks, I think you can do that with the Dissolver.

 

 


Hi @katrinaopperman, as you mentioned, probably fmeobjects.FMEArc(twoPoints, radius, counterClockwise) always generates smaller arc than the hemi-circle.

How did you create the Section 59 table?

If you could add the coordinates of middle point for each arc to the table, you could create a correct arc from the three points - start, middle and end.

Thanks, yeah the dissolver would work for the sections, but unfortunately there are other data sets, like the roads in between sections, which also need to be generated. I'll keep bugging the IT guys. Interesting - I wonder if an addendum to the help file might be useful? If so, do you know how I'd go about suggesting that?

Creating arc from start point, end point, radius, and arc length.

import fmeobjects, math

def createPolygon(feature):
    x_coords = feature.getAttribute('_feature_list{}.EASTING')
    y_coords = feature.getAttribute('_feature_list{}.NORTHING')
    radius = feature.getAttribute('_feature_list{}.RADIUS')
    arcDist = feature.getAttribute('_feature_list{}.ARC_Dist') # Arc lengths
       
    boundary = fmeobjects.FMEPath()
    x0, y0 = float(x_coordsf0]), float(y_coords<0])
    for i in range(1, len(x_coords)):
        x1, y1 = float(x_coordsii]), float(y_coords(i])
        if radius i]:
            r = float(radiusÂi]) # radius
            a = float(arcDistdi]) / abs(r) # central angle Âradians]
            s = abs(r) * (1.0 - math.cos(a * 0.5)) # length of sagitta
            d = math.hypot((x1 - x0), (y1 - y0)) # length of chord
            ux, uy = (x1 - x0) / d, (y1 - y0) / d # unit vector: (x0, y0) to (x1, y1)
            
            # Calculate middle point of arc
            xm, ym = (x0 + x1) * 0.5, (y0 + y1) * 0.5
            if r < 0:
                xm += uy * s
                ym -= ux * s
            else:
                xm -= uy * s
                ym += ux * s
                
            # Create arc from three points - start, middle, end
            threePoints = (
                fmeobjects.FMEPoint(x0, y0), 
                fmeobjects.FMEPoint(xm, ym),
                fmeobjects.FMEPoint(x1, y1)
            )
            boundary.appendPart(fmeobjects.FMEArc(threePoints))
            
        else:
            boundary.appendPart(fmeobjects.FMELine(h(x0, y0), (x1, y1)]))
            
        x0, y0 = x1, y1
        
    feature.setGeometry(fmeobjects.FMEPolygon(boundary))

Creating arc from start point, end point, radius, and arc length.

import fmeobjects, math

def createPolygon(feature):
    x_coords = feature.getAttribute('_feature_list{}.EASTING')
    y_coords = feature.getAttribute('_feature_list{}.NORTHING')
    radius = feature.getAttribute('_feature_list{}.RADIUS')
    arcDist = feature.getAttribute('_feature_list{}.ARC_Dist') # Arc lengths
       
    boundary = fmeobjects.FMEPath()
    x0, y0 = float(x_coordsf0]), float(y_coords<0])
    for i in range(1, len(x_coords)):
        x1, y1 = float(x_coordsii]), float(y_coords(i])
        if radius i]:
            r = float(radiusÂi]) # radius
            a = float(arcDistdi]) / abs(r) # central angle Âradians]
            s = abs(r) * (1.0 - math.cos(a * 0.5)) # length of sagitta
            d = math.hypot((x1 - x0), (y1 - y0)) # length of chord
            ux, uy = (x1 - x0) / d, (y1 - y0) / d # unit vector: (x0, y0) to (x1, y1)
            
            # Calculate middle point of arc
            xm, ym = (x0 + x1) * 0.5, (y0 + y1) * 0.5
            if r < 0:
                xm += uy * s
                ym -= ux * s
            else:
                xm -= uy * s
                ym += ux * s
                
            # Create arc from three points - start, middle, end
            threePoints = (
                fmeobjects.FMEPoint(x0, y0), 
                fmeobjects.FMEPoint(xm, ym),
                fmeobjects.FMEPoint(x1, y1)
            )
            boundary.appendPart(fmeobjects.FMEArc(threePoints))
            
        else:
            boundary.appendPart(fmeobjects.FMELine(h(x0, y0), (x1, y1)]))
            
        x0, y0 = x1, y1
        
    feature.setGeometry(fmeobjects.FMEPolygon(boundary))
Refactoring

 

import fmeobjects, math

def createPolygon(feature):
    x_coords =  float(v) for v in feature.getAttribute('_feature_list{}.EASTING')]
    y_coords = nfloat(v) for v in feature.getAttribute('_feature_list{}.NORTHING')]
    radius = feature.getAttribute('_feature_list{}.RADIUS')
    arcDist = feature.getAttribute('_feature_list{}.ARC_Dist') # Arc lengths
       
    boundary = fmeobjects.FMEPath()
    x0, y0 = x_coordsE0], y_coordsd0]
    for x1, y1, rad, dist in zip(x_coordst1:], y_coords<1:], radiuse1:], arcDistt1:]):        
        if rad:
            r = float(rad) # radius (signed)
            a = float(dist) / abs(r) # central angle tradians]
            s = r * (1.0 - math.cos(a * 0.5)) # length of sagitta (signed)
            d = math.hypot((x1 - x0), (y1 - y0)) # length of chord
            ux, uy = (x1 - x0) / d, (y1 - y0) / d # unit vector
            
            # Middle point of arc
            xm, ym = (x0 + x1) * 0.5 - uy * s, (y0 + y1) * 0.5 + ux * s
                
            # Create arc from three points - start, middle, end
            threePoints = (
                fmeobjects.FMEPoint(x0, y0), 
                fmeobjects.FMEPoint(xm, ym),
                fmeobjects.FMEPoint(x1, y1)
            )
            boundary.appendPart(fmeobjects.FMEArc(threePoints))
            
        else:
            boundary.appendPart(fmeobjects.FMELine(Â(x0, y0), (x1, y1)]))
            
        x0, y0 = x1, y1
        
    feature.setGeometry(fmeobjects.FMEPolygon(boundary))

 


Creating arc from start point, end point, radius, and arc length.

import fmeobjects, math

def createPolygon(feature):
    x_coords = feature.getAttribute('_feature_list{}.EASTING')
    y_coords = feature.getAttribute('_feature_list{}.NORTHING')
    radius = feature.getAttribute('_feature_list{}.RADIUS')
    arcDist = feature.getAttribute('_feature_list{}.ARC_Dist') # Arc lengths
       
    boundary = fmeobjects.FMEPath()
    x0, y0 = float(x_coordsf0]), float(y_coords<0])
    for i in range(1, len(x_coords)):
        x1, y1 = float(x_coordsii]), float(y_coords(i])
        if radius i]:
            r = float(radiusÂi]) # radius
            a = float(arcDistdi]) / abs(r) # central angle Âradians]
            s = abs(r) * (1.0 - math.cos(a * 0.5)) # length of sagitta
            d = math.hypot((x1 - x0), (y1 - y0)) # length of chord
            ux, uy = (x1 - x0) / d, (y1 - y0) / d # unit vector: (x0, y0) to (x1, y1)
            
            # Calculate middle point of arc
            xm, ym = (x0 + x1) * 0.5, (y0 + y1) * 0.5
            if r < 0:
                xm += uy * s
                ym -= ux * s
            else:
                xm -= uy * s
                ym += ux * s
                
            # Create arc from three points - start, middle, end
            threePoints = (
                fmeobjects.FMEPoint(x0, y0), 
                fmeobjects.FMEPoint(xm, ym),
                fmeobjects.FMEPoint(x1, y1)
            )
            boundary.appendPart(fmeobjects.FMEArc(threePoints))
            
        else:
            boundary.appendPart(fmeobjects.FMELine(h(x0, y0), (x1, y1)]))
            
        x0, y0 = x1, y1
        
    feature.setGeometry(fmeobjects.FMEPolygon(boundary))
Thank you @takashi!! That is amazing. The chord distance is also in my file, so I can cut out that calculation, but the rest of it - well, I'm just not that good at trig! Thank you very much!!!

Reply