STLineToCurve. A Function that Converts a LineString to a CircularString, CompoundCurve or CurvePolygon.

All the main databases’ spatial types support the CircularStrings, CompoundCurves or CurvePolygons.

All the examples in this blog come from SQL Server Spatial + my functions.

NOTE: The author is aware of the BufferWithCurves Extended Method on Geometry Instances.

Some GIS software do not support Curved elements, and so require those elements to be “stroked”, that is, converted into LineString equivalents.

The following is a CircularString in its normal and stroked form (stroking achieved with CurveToLineWithTolerance):

select geometry::STGeomFromText('CIRCULARSTRING (1958269.512022 1808899.505778, 1958269.512022 1808919.505778, 1958269.02134526 1808899.51782344, 1958269.02134526 1808899.51782344, 1958269.512022 1808899.505778)',2240).CurveToLineWithTolerance ( 0.03, 1 )
union all
select geometry::STGeomFromText('CIRCULARSTRING (1958269.512022 1808899.505778, 1958269.512022 1808919.505778, 1958269.02134526 1808899.51782344, 1958269.02134526 1808899.51782344, 1958269.512022 1808899.505778)',2240)

This looks like this:

Closed CircularString in native and stroked form.

A customer is being supplied with stroked LineStrings that contain CircularStrings and would prefer the data to be described by CircularString elements. So, I wrote a function, dbo.STLineToCurve that takes a stroked LineString and, given certain controlling parameters, attempts to identify any CircularStrings within the LineString, building a result that may contain CircularStrings. The result can be a CircularString or a CompoundCurve or CurvePolygon (exterior ring only).

The function is described in the SQL Server Spatial General TSQL functions.

The following example creates a circle by buffering a point.

SELECT geometry::STGeomFromText('POINT (1958269.512022 1808909.505778)', 2240).STBuffer(10.0).STAsText()

circle
POLYGON ((1958269.512022 1808899.505778, 1958270.0026987433 1808899.5178234379, 1958270.4921934034 1808899.5539307334, 1958270.9793267446 1808899.6140129003, 1958271.4629252201 1808899.697925196, 1958271.9418237992 1808899.805465468, 1958272.4148687725 1808899.9363746427, 1958272.880920534 1808900.0903373482, 1958273.3388563236 1808900.2669826748, 1958273.7875729343 1808900.4658850688, 1958274.2259893683 1808900.6865653566, 1958274.653049442 1808900.9284919, 1958275.0677243304 1808901.1910818769, 1958275.4690150449 1808901.4737026852, 1958275.8559548417 1808901.7756734663, 1958276.2276115485 1808902.0962667465, 1958276.583089812 1808902.4347101881, 1958276.9215332535 1808902.7901884515, 1958277.2421265338 1808903.1618451583, 1958277.5440973148 1808903.5487849552, 1958277.8267181232 1808903.9500756697, 1958278.0893081 1808904.364750558, 1958278.3312346435 1808904.7918106318, 1958278.5519149313 1808905.2302270657, 1958278.7508173252 1808905.6789436764, 1958278.9274626519 1808906.136879466, 1958279.0814253574 1808906.6029312275, 1958279.2123345321 1808907.0759762009, 1958279.319874804 1808907.55487478, 1958279.4037870998 1808908.0384732555, 1958279.4638692667 1808908.5256065966, 1958279.4999765621 1808909.0151012568, 1958279.512022 1808909.505778, 1958279.4999765621 1808909.9964547432, 1958279.4638692667 1808910.4859494034, 1958279.4037870998 1808910.9730827445, 1958279.319874804 1808911.45668122, 1958279.2123345321 1808911.9355797991, 1958279.0814253574 1808912.4086247724, 1958278.9274626519 1808912.874676534, 1958278.7508173252 1808913.3326123236, 1958278.5519149313 1808913.7813289342, 1958278.3312346435 1808914.2197453682, 1958278.0893081 1808914.6468054419, 1958277.8267181232 1808915.0614803303, 1958277.5440973148 1808915.4627710448, 1958277.2421265338 1808915.8497108417, 1958276.9215332535 1808916.2213675485, 1958276.583089812 1808916.5768458119, 1958276.2276115485 1808916.9152892535, 1958275.8559548417 1808917.2358825337, 1958275.4690150449 1808917.5378533148, 1958275.0677243304 1808917.8204741231, 1958274.653049442 1808918.0830641, 1958274.2259893683 1808918.3249906434, 1958273.7875729343 1808918.5456709312, 1958273.3388563236 1808918.7445733252, 1958272.880920534 1808918.9212186518, 1958272.4148687725 1808919.0751813573, 1958271.9418237992 1808919.206090532, 1958271.4629252201 1808919.313630804, 1958270.9793267446 1808919.3975430997, 1958270.4921934034 1808919.4576252666, 1958270.0026987433 1808919.4937325621, 1958269.512022 1808919.505778, 1958269.0213452568 1808919.4937325621, 1958268.5318505967 1808919.4576252666, 1958268.0447172555 1808919.3975430997, 1958267.56111878 1808919.313630804, 1958267.0822202009 1808919.206090532, 1958266.6091752276 1808919.0751813573, 1958266.1431234661 1808918.9212186518, 1958265.6851876765 1808918.7445733252, 1958265.2364710658 1808918.5456709312, 1958264.7980546318 1808918.3249906434, 1958264.3709945581 1808918.0830641, 1958263.9563196697 1808917.8204741231, 1958263.5550289552 1808917.5378533148, 1958263.1680891584 1808917.2358825337, 1958262.7964324516 1808916.9152892535, 1958262.4409541881 1808916.5768458119, 1958262.1025107466 1808916.2213675485, 1958261.7819174663 1808915.8497108417, 1958261.4799466853 1808915.4627710448, 1958261.1973258769 1808915.0614803303, 1958260.9347359 1808914.6468054419, 1958260.6928093566 1808914.2197453682, 1958260.4721290688 1808913.7813289342, 1958260.2732266749 1808913.3326123236, 1958260.0965813482 1808912.874676534, 1958259.9426186427 1808912.4086247724, 1958259.811709468 1808911.9355797991, 1958259.7041691961 1808911.45668122, 1958259.6202569003 1808910.9730827445, 1958259.5601747334 1808910.4859494034, 1958259.524067438 1808909.9964547432, 1958259.512022 1808909.505778, 1958259.524067438 1808909.0151012568, 1958259.5601747334 1808908.5256065966, 1958259.6202569003 1808908.0384732555, 1958259.7041691961 1808907.55487478, 1958259.811709468 1808907.0759762009, 1958259.9426186427 1808906.6029312275, 1958260.0965813482 1808906.136879466, 1958260.2732266749 1808905.6789436764, 1958260.4721290688 1808905.2302270657, 1958260.6928093566 1808904.7918106318, 1958260.9347359 1808904.364750558, 1958261.1973258769 1808903.9500756697, 1958261.4799466853 1808903.5487849552, 1958261.7819174663 1808903.1618451583, 1958262.1025107466 1808902.7901884515, 1958262.4409541881 1808902.4347101881, 1958262.7964324516 1808902.0962667465, 1958263.1680891584 1808901.7756734663, 1958263.5550289552 1808901.4737026852, 1958263.9563196697 1808901.1910818769, 1958264.3709945581 1808900.9284919, 1958264.7980546318 1808900.6865653566, 1958265.2364710658 1808900.4658850688, 1958265.6851876765 1808900.2669826748, 1958266.1431234661 1808900.0903373482, 1958266.6091752276 1808899.9363746427, 1958267.0822202009 1808899.805465468, 1958267.56111878 1808899.697925196, 1958268.0447172555 1808899.6140129003, 1958268.5318505967 1808899.5539307334, 1958269.0213452568 1808899.5178234379, 1958269.512022 1808899.505778))
Stroked Circle Polygon
A stroked circle polygon created by buffering a point.

The stroked circle polygon is then passed to the dbo.STLineToCurve function who extracts the equivalent CircularString.

SELECT [dbo].[STLineToCurve] (
          geometry::STGeomFromText('POINT (1958269.512022 1808909.505778)', 2240).STBuffer(10.0),
          'A',3
       ).AsTextZM() as curve;

curve
CURVEPOLYGON (
 COMPOUNDCURVE (
  CIRCULARSTRING (1958269.512022 1808899.505778, 1958269.512022 1808919.505778, 1958269.02134526 1808899.51782344, 1958269.02134526 1808899.51782344, 1958269.512022 1808899.505778)
 )
)

Much tidier than the stroked equivalent.

A more powerful example is one where the LineString contains many “hidden” CircularStrings separated by LineStrings.

Compound Curve as Stroked LineString
A complex LineString containing a number of stroked CircularStrings
SELECT [dbo].[STLineToCurve] (
geometry::STGeomFromText('
COMPOUNDCURVE (
CIRCULARSTRING (1958269.512022 1808909.505778 NULL 0, 1958331.263475 1810230.986863 NULL 1508.1865, 1958479.466961 1808767.477437 NULL 5159.862),
(1958479.466961 1808767.477437 NULL 5159.862, 1958985.828872 1808162.313202 NULL 5948.9286, 1959016.704599 1807964.708553 NULL 6148.9309, 1958868.501112 1807723.877888 NULL 6431.7094),
CIRCULARSTRING (1958868.501112 1807723.877888 NULL 6431.7094, 1958806.74966 1807748.578469 NULL 6498.2237, 1959115.506923 1807588.024693 NULL 15108.4376),
(1959115.506923 1807588.024693 NULL 15108.4376, 1959924.450951 1807748.578469  NULL 15933.1606, 1960418.462572 1808613.098805 NULL 16928.8728)
)', 2240).CurveToLineWithTolerance ( 0.003, 1 ),'A',3).AsTextZM() as curve;

curve
COMPOUNDCURVE (
CIRCULARSTRING (1958269.512022 1808909.505778, 1959334.88390227 1810258.20508517, 1958479.466961 1808767.477437), 
(1958479.466961 1808767.477437, 1958985.828872 1808162.313202, 1959016.704599 1807964.708553, 1958868.501112 1807723.877888), 
CIRCULARSTRING (1958868.501112 1807723.877888, 1957621.04956707 1805163.3068159, 1959115.506923 1807588.024693), 
(1959115.506923 1807588.024693, 1959924.450951 1807748.578469, 1960418.462572 1808613.098805))

Note how the output CompoundCurve is the same as the input. This cannot always be guaranteed, but the “shape” of the output should always be the same as the input (bugs aside).

I hope this function is of interest to someone.

One problem with such a function is the identification of quadrilateral objects in the stroked linestring and not attempting to convert it to a CompoundCurve. The dbo.STisQuadrilateral function is used by this function deftly identifying and avoiding conversion where invalid.