Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
Fitting Bezier Polygon to Points
A colleague asked if I could implement the fitting of a 2D linestring to a set of points using a bezier approximation returning a polygon.
The original implementation is Smooth a 2D polyline through a set of points by interpolation (Catmull-Rom) or approximation (Chaikin)..
First off, we do a Chaikin smoothing (method 1) of a set of points using 3 iterations.
WITH data AS ( SELECT 1 as method, 3 as iterations, geometry::STGeomFromText('MULTIPOINT((3 0.5),(2 1),(3 2),(3 3),(4 2.5),(4.8 3.7),(3 5.5),(6 8),(7 9.5),(8.3 5.1),(6.5 4.2),(9 3),(9 2),(8 2),(7 3),(3 0.5))',0) as geom ) SELECT 'Chaikin' as Method, f.bGeom as geom FROM (SELECT cast(method as varchar(2)) as Method, [dbo].[STBezier](d.geom,0.5,d.iterations,d.method) as bGeom FROM data as d ) as f UNION ALL SELECT cast(p.uid as varchar(7)) as method, p.point.STBuffer(0.2) as geom FROM data as d cross apply [dbo].[STDumpPoints](d.geom) as p GO
This looks like the following. Note that the polygon does not pass through the individual points.
To make the polygon exterior ring pass through the supplied points, we can move to a Catmull-Rom curve fitting (method 2). In the following we use a minimal amount of iterations (2) which will result in a less smooth curve fitting.
WITH data AS ( SELECT 2 as method, 2 as iterations, geometry::STGeomFromText('MULTIPOINT((3 0.5),(2 1),(3 2),(3 3),(4 2.5),(4.8 3.7),(3 5.5),(6 8),(7 9.5),(8.3 5.1),(6.5 4.2),(9 3),(9 2),(8 2),(7 3),(3 0.5))',0) as geom ) SELECT 'Catmull-Rom' as Method, f.bGeom as geom FROM (SELECT cast(method as varchar(2)) as Method, [dbo].[STBezier](d.geom,0.5,d.iterations,d.method) as bGeom FROM data as d ) as f UNION ALL SELECT cast(p.uid as varchar(7)) as method, p.point.STBuffer(0.2) as geom FROM data as d cross apply [dbo].[STDumpPoints](d.geom) as p GO
This looks like the following:
Upping the number of iterations to, say 5, results in smoother exterior ring.
WITH data AS ( SELECT 2 as method, 5 as iterations, geometry::STGeomFromText('MULTIPOINT((3 0.5),(2 1),(3 2),(3 3),(4 2.5),(4.8 3.7),(3 5.5),(6 8),(7 9.5),(8.3 5.1),(6.5 4.2),(9 3),(9 2),(8 2),(7 3),(3 0.5))',0) as geom ) SELECT 'Catmull-Rom' as Method, f.bGeom as geom FROM (SELECT cast(method as varchar(2)) as Method, [dbo].[STBezier](d.geom,0.5,d.iterations,d.method) as bGeom FROM data as d ) as f UNION ALL SELECT cast(p.uid as varchar(7)) as method, p.point.STBuffer(0.2) as geom FROM data as d cross apply [dbo].[STDumpPoints](d.geom) as p GO
The following example, uses data in an actual projected space, SRID 27700 (OSGB36 / British National Grid — United Kingdom Ordnance Survey). In particular we will look at the role of, or need for, a closing point when processing the data using a Chaikin smoothing:
First, smoothing using a closing point.
WITH data AS ( SELECT geometry::STGeomFromText( 'MULTIPOINT( (534239.6309 258830.8997), (534232.6309 258836.8997), (534224.6309 258830.8997), (534232.6309 258826.8997), (534239.6309 258830.8997))',27700) as geom ) SELECT 'Chaikin' as method, f.bGeom as geom FROM (SELECT [dbo].[STBezier](d.geom,0.5,3,1) as bGeom FROM data as d ) as f UNION ALL SELECT cast(p.uid as varchar) as method, p.point.STBuffer(0.5) as geom FROM data as d cross apply [dbo].[STDumpPoints](d.geom) as p GO
This looks like this:
Now, without the last point.
WITH data AS ( SELECT geometry::STGeomFromText( 'MULTIPOINT( (534239.6309 258830.8997), (534232.6309 258836.8997), (534224.6309 258830.8997), (534232.6309 258826.8997), (534239.6309 258830.8997))',27700) as geom ) SELECT 'Chaikin' as method, f.bGeom as geom FROM (SELECT [dbo].[STBezier](d.geom,0.5,3,1) as bGeom FROM data as d ) as f UNION ALL SELECT cast(p.uid as varchar) as method, p.point.STBuffer(0.5) as geom FROM data as d cross apply [dbo].[STDumpPoints](d.geom) as p GO
Which looks like this.
I hope this is of interest to someone out there.
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions