# Is there a PostGIS function to get a tangent and normal line?

I'm looking for a function that will return a tangent (and normal) for a LINESTRING in PostGIS. I think this is the 3rd time I've come across the need for this function and everytime, I end porting whatever I'm working on to c#/ArcObjects in order to use the QueryTangent/QueryNormal method rather than make the effort to research a PostGIS option.

Is there an existing functions in PostGIS (I'm not tied to a specific version)?

And if it doesn't exist, has anyone already written it and wouldn't mind posting it as an answer?

• I'm on the fence as to whether split this into 2 questions (one for tangent and one for normal). – Jay Cummins Aug 25 '14 at 13:52

## 2 Answers

Hope this works for anyone looking for something similar. This is just the tangent angle. Getting an actual line tangent with this angle is just a matter of using `ST_Project(point_in_line, tangent_length, north_heading)` or regular vector construction from an angle

The inputs are the line you want to calculate the tangent from and a point to project into the line in order to find the point over the line in which calculate the tangent.

This just calculates from this point two point, slightly backwards and forwards from where the actual point is and calculates the azimuth with them. Is not completely rigurous, as it is thought to use with curves aproximated with segments, avoiding discontinuities in the corners.

``````select
--(distance-delta_az  + abs(distance-delta_az))/2 ensures that we are not getting a value < 0
--((distance+delta_az + 1) - abs(distance +delta_az-1))/2 ensures that we are not getting a value > 1

st_azimuth(ST_LineInterpolatePoint(line, (distance - delta_az  + abs(distance - delta_az))/2),
ST_LineInterpolatePoint(line,((distance+delta_az + 1) - abs(distance +delta_az-1))/2
)) as north_heading
,point_in_line
from (
Select *
--Distance for the sampling of the points. We will get on point backwoards 2.5 meters and the other one 2.5 moeters forward
,2.5/ST_Length_Spheroid(line,'SPHEROID["WGS 84",6378137,298.257223563]')  as delta_az
,ST_LineLocatePoint (line, point) as distance
from(
select
ST_SetSRID(ST_Point(0.19584,51.39155),4326) AS point
,ST_GeomFromText('SRID=4326;LINESTRING(0.202544569141249 51.3858947009165,0.20214201912261 51.3859754995475,0.201683988262174 51.3860550822334,0.201298681646241 51.3861307695392,0.200913995595119 51.3862191151881,0.200637871611774 51.3862902129407,0.20044232848043 51.3863521883245,0.200282594069191 51.3864008195477,0.199948062309506 51.3865211707015,0.199693747016039 51.3866248073675,0.199534739925771 51.3866886402226,0.199415984061462 51.3867466360683,0.199308876506529 51.3867942778896,0.199182264028808 51.3868574930971,0.199059822217586 51.386923165929,0.198822779306642 51.3870492919278,0.198534819235256 51.387211859763,0.198392189933678 51.387298999546,0.198260075102574 51.3873914096544,0.198220556826889 51.3874215586129,0.198117246716962 51.3875002082031,0.197980334002478 51.3876124928192,0.197943631428003 51.3876414197499,0.197861227817486 51.3877064570105,0.197746472298164 51.3878012387669,0.197694529027124 51.3878537616336,0.197648011221446 51.3878977291898,0.197573411113245 51.3879690589074,0.197490720806948 51.3880731313035,0.197370548455971 51.3882048859675,0.197297349975127 51.3882970891593,0.197198502035664 51.3884239471226,0.197085062209489 51.3885762593183,0.196978931078594 51.3887311322609,0.196860246313642 51.3889240114968,0.196750278864077 51.3890888485544,0.196626966904429 51.3893051963346,0.196524635643854 51.3895094595789,0.196408588074721 51.3897274695162,0.196314613355284 51.389926180026,0.196221772736419 51.3901185740255,0.196144040118593 51.3902962957841,0.196080138320337 51.3904476782601,0.195893943582872 51.3909269027984,0.195857932027267 51.3910453872398,0.195830537126725 51.3911637101636,0.195817148207303 51.3912473270379,0.195811715923981 51.3912809730726,0.1958015115104 51.3913980744727,0.195795668868183 51.3915762471116,0.195803014351775 51.3917575629566,0.195814050762164 51.3919880377752,0.195820566773037 51.392208462103,0.195847957750903 51.3923575037398,0.195887620778652 51.3925088603915,0.195922772326274 51.3926395455476,0.195981449491801 51.3927758060993,0.196036086212748 51.3929015305168,0.196103116172887 51.3930320946954,0.196174438895448 51.3931676414717,0.196249327132776 51.3932929861565,0.196331830538879 51.3934080438311,0.196431612830755 51.3935456019569,0.196542246810266 51.3936882174974,0.196689523244294 51.3938518282194,0.196849554588933 51.3940116023527,0.196974271993363 51.3941243751481,0.197106042021335 51.3942343176252,0.197242078338479 51.3943432806348,0.197529908536757 51.3945600113125,0.197810833605237 51.3947525894999,0.198426995681651 51.3951610060778,0.199127880673162 51.3956271835559,0.200057987844421 51.3962563240803,0.20154750476639 51.3972215852691,0.202578470597449 51.3978812308674)') as line
) as inputs
) as azimuth_points
``````

References:

ST_Project

ST_Azimuth

I guess you are talking about curves?

What parameters do you want as input?

If you use ST_Shortestline with a point at some distance from your curve/linestring, you will get a line perpenicular from your linestring/curve to the point.