Skip to main content
Solved

Create Cubic Bezier Curves


takashi
Celebrity
Hi,

 

 

I have to transform a series of points to a line consisting of cubic Bezier curves. I couldn't find a function to do that in existing transformers or the Python API of FME Objects. The Generalizer (NURBfit algotirhm) creates a spline curve, but it's not exact cubic Bezier curves. The expected line has to pass through the both ends of each 3 segments.

 

  So, I wrote the following script. Is this the "re-invention of the wheel"? If you know an existing function (transformer or Python function) that creates cubic Bezier curves based on control points, please let me know. 

 

-----

 

import fmeobjects   class CubicBezierCurveReplacer(object):     def __init__(self):         self.set_coefficients(32)              def set_coefficients(self, n):         self.n = n         r = 1.0 / float(self.n)         s = range(0, self.n)         self.k0 = [(1.0 - (r * m))**3 for m in s]         self.k1 = [3.0 * (r * m) * (1.0 - r * m)**2 for m in s]         self.k2 = [3.0 * (1.0 - (r * m)) * (r * m)**2 for m in s]         self.k3 = [(r * m)**3 for m in s]              def bezier_coords(self, p):         coords = []         x0, x1, x2, x3 = p[0][0], p[1][0], p[2][0], p[3][0]         y0, y1, y2, y3 = p[0][1], p[1][1], p[2][1], p[3][1]         for i in range(1, self.n):             x = self.k0[i] * x0 + self.k1[i] * x1 + self.k2[i] * x2 + self.k3[i] * x3             y = self.k0[i] * y0 + self.k1[i] * y1 + self.k2[i] * y2 + self.k3[i] * y3             coords.append((x, y))         return coords              def input(self, feature):         # If the number of coordinates is less than 2, return nothing.         if feature.numCoords() < 2: return                  # Get all coordinates of the input feature as control points.         points = feature.getAllCoordinates()                  # Append coordinates while (number of control points - 1)         # is not divisible by 3 evenly.         while (len(points) - 1) % 3 != 0:             points.append(points[-1])                      # Create  cubic Bezier curves.         bezier = feature.cloneAttributes();         bezier.setGeometryType(fmeobjects.FME_GEOM_LINE)         bezier.setCoordSys(feature.getCoordSys())         bezier.addCoordinate(points[0][0], points[0][1])         for i in range(3, len(points), 3):             bezier.addCoordinates(self.bezier_coords(points[i - 3 : i + 1]))             bezier.addCoordinate(points[i][0], points[i][1])         self.pyoutput(bezier)              def close(self):         pass -----

 

 

Takashi

Best answer by takashi

... found a solution. Using the Chopper, break an input line into lines each of which consists of 3 segments (4 vertices), then create spline curve for each line via Generalizer. I re-invented the wheel, just as I feared. I lost a half of a day (:-( Thanks.

 

Takashi
View original
Did this help you find an answer to your question?
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.

4 replies

takashi
Celebrity
  • Author
  • Best Answer
  • June 24, 2013
... found a solution. Using the Chopper, break an input line into lines each of which consists of 3 segments (4 vertices), then create spline curve for each line via Generalizer. I re-invented the wheel, just as I feared. I lost a half of a day (:-( Thanks.

 

Takashi

geo-x
Supporter
Forum|alt.badge.img+6
  • Supporter
  • August 28, 2018
takashi wrote:
... found a solution. Using the Chopper, break an input line into lines each of which consists of 3 segments (4 vertices), then create spline curve for each line via Generalizer. I re-invented the wheel, just as I feared. I lost a half of a day (:-( Thanks.

 

Takashi
Dear @takashi your solution is great, but my Generalizer doesn't work, I tried some configurations but my segments don't change :-(

 


geo-x
Supporter
Forum|alt.badge.img+6
  • Supporter
  • August 28, 2018
takashi wrote:
... found a solution. Using the Chopper, break an input line into lines each of which consists of 3 segments (4 vertices), then create spline curve for each line via Generalizer. I re-invented the wheel, just as I feared. I lost a half of a day (:-( Thanks.

 

Takashi
This is my case geojson2none.fmwt and I need to keep all original vertices.

 

Thank you for your help.

 


david_r
Celebrity
  • September 9, 2022

Posting the reformatted code here for posterity.

1import fmeobjects
2 
3class CubicBezierCurveReplacer(object):
4 
5     def __init__(self):
6         self.set_coefficients(32)
7 
8     def set_coefficients(self, n):
9         self.n = n
10         r = 1.0 / float(self.n)
11         s = range(0, self.n)
12         self.k0 = [(1.0 - (r * m))**3 for m in s]
13         self.k1 = [3.0 * (r * m) * (1.0 - r * m)**2 for m in s]
14         self.k2 = [3.0 * (1.0 - (r * m)) * (r * m)**2 for m in s]
15         self.k3 = [(r * m)**3 for m in s]
16 
17     def bezier_coords(self, p):
18         coords = []
19         x0, x1, x2, x3 = p[0][0], p[1][0], p[2][0], p[3][0]
20         y0, y1, y2, y3 = p[0][1], p[1][1], p[2][1], p[3][1]
21         for i in range(1, self.n):
22             x = self.k0[i] * x0 + self.k1[i] * x1 + self.k2[i] * x2 + self.k3[i] * x3
23             y = self.k0[i] * y0 + self.k1[i] * y1 + self.k2[i] * y2 + self.k3[i] * y3
24             coords.append((x, y))
25         return coords
26 
27     def input(self, feature):
28         # If the number of coordinates is less than 2, return nothing.
29         if feature.numCoords() < 2: return
30         # Get all coordinates of the input feature as control points.
31         points = feature.getAllCoordinates()
32         # Append coordinates while (number of control points - 1)
33         # is not divisible by 3 evenly.
34         while (len(points) - 1) % 3 != 0:
35             points.append(points[-1])
36         # Create  cubic Bezier curves.
37         bezier = feature.cloneAttributes()
38         bezier.setGeometryType(fmeobjects.FME_GEOM_LINE)
39         bezier.setCoordSys(feature.getCoordSys())
40         bezier.addCoordinate(points[0][0], points[0][1])
41         for i in range(3, len(points), 3):
42             bezier.addCoordinates(self.bezier_coords(points[i - 3 : i + 1]))
43             bezier.addCoordinate(points[i][0], points[i][1])
44         self.pyoutput(bezier)
45 
46     def close(self):
47         pass

 


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings