User:Andrew Nikitin/Angular

From J Wiki
Jump to: navigation, search

Angular units

Angular values come in different shapes and under different names. Angles can be measured in radians, degrees, hours. Military have their own unit, called mil (which comes in at least 3 different varieties, depending on a country) and French surveyors at some point used (or, maybe still use) grad. Even when expressed in degrees, the fractional part can be expressed in familiar decimals, minutes or minutes and seconds.

This script attempts to deal with some of this complexity. Download script: angular.ijs

coinsert 'geo'

cocurrent 'geo'
NB. Angular units formatting and conversion.
require 'regex'


Units conversion

Download script: convert

NB.*θfζ v convert angular units: obtain θ units from ζ units
NB. Units:
NB. d - degrees
NB. m - minutes(angular) =nm
NB. r - radians
NB. g - grads
NB. h - hours
mfr=:(180 * 60 * 1p_1)&*

f in the name stands for from. This way dfr reads degrees from radians. Since data is visualized as "flowing" from right to left, this seems to be better mnemonic than r2d.

h here is angular hour, such as one used to describe right ascension. There are 24 hours in 360°.

m means minute of arc =1/60°, not 1/60 of an hour. It is also equal to 1 nautical mile on Earth surface.

RFM=:%MFR=:(180 * 60 * 1p_1)

Originally the script included these conversion constants, but there seems to be little use for them.

Base 60 Conversion

Sometimes fraction of a degree (or an hour) is expressed as minutes and fraction of a minute is expressed as seconds. Download script: convert

tomin=:f60=:((_: , #&60)@[ #: 60&^@[ * ])
frommin=:e60=:(60&#. % 60&^@<:@#)

f60 (format-60) converts decimal fraction representation into given number of base 60 parts. x = number of such parts (0 = none, 1 = minutes and decimal fractions of minutes, 2 = minutes, seconds and decimal fraction of seconds, etc.) This works so far only for positive. Negatives need to be investigated

e60 (eval-60) performs backward conversion -- from list of base 60 units into decimal fraction. Download script: convert

NB.*cms v cover verb "convert minutes and seconds"
NB. optional left argument specifies how many base-60 parts should
NB. be on output
cms=:e60 : (f60 e60)

For example:

   cms 1 20 NB. 1 hour 20 minutes
   2 cms 1 20.11 NB. 1 hour 20.11 minutes in hours, minutes, seconds
1 20 6.6

Download script: convert

NB.*toneg v force y into (-x/2..x/2] range
toneg=:(| - [ * | > -:@[)

NB.*round v round y to nearest multiple of x
round=:([ (] - |) -:@[ + ])

NB.*roundup v round y up to a multiple of x
roundup=:] + (| -)

NB.*rounddown v round y down to a multiple of x
rounddown=:] - |


All formatting verbs have names starting with f.

Format individual values

Download script: format

DMS=:'-',u: 16bb0 16bb4 16b2dd NB. unicode positions, >j601

DMS is graphic symbols for sign (-), degree (°), minute (´) and second (˝).

Alternatives for DMS:

DMS=:'- ''"' NB. ascii
DMS=:'-',16bb0 16b92 16b94{a. NB. pre j601, single byte encoding

Download script: format


Labels for hours, minutes, seconds.

All the following formatting verbs take angular value y given in radians and format it as a string. The verbs perform conversion, round and add appropriate marking symbols depending on the assumed meaning of their argument. Download script: format

f2=:(({.@[ #~ 0 > ]) , ;@(}.@[ (,~ ":)&.> 2&tomin@|@]))

This is a generic verb that formats possibly fractional y into 2 level base-60 fraction using x for sign symbol and names for whole, first and second base-60 components Download script: format

fh2=: HMS&f2@hfr
fd2=: DMS&f2@dfr

Format radians as degrees-minutes-seconds or hours-minutes-seconds with proper marking.

fpl=:('fd2';'fd2';']')"_ apply&> ]

Some remnant. Looks like a formatting for a triplet representing a point in spherical coordinates. Download script: format

NB.*faz v format azimuth
faz=:(1{DMS) ,~ _5 {. '00' , 0j1 ": 360 | dfr

Format as azimuth. Show in range 0..360° rounded to 0.1° Download script: format

NB.*fdist v format distance
fdist_nm=:'nm' ,~ '0.1' >@(8!:0) mfr
fdist_km=:'km' ,~ '0.1' >@(8!:0) 6372.797&*

Angular distances on the globe can be displayed in linear units. fdist name is default distance formatter and it selects one of the formatters. Format is rounded to 0.1 of a unit. Appends unit name (nm, km or mi). Download script: format

NB.*fdm v format to decimal minutes
fdm=:3 : 0
  'd m'=.1 tomin | dfr y
  'd m'=.1 tomin | (0.1 % 60) round dfr y

Another generic verb that, probably would not be useful on itself. It outputs the number rounded to 0.1´. Optional x is a 2-character list of names for positive and negative values. Download script: format

NB.*falt v format altitude

Format observed/computed altitude of a body. Download script: format

NB.*fmin v format angle as angular minutes
fmin=: '´' ,~ '0.1' >@(8!:0) mfr

Same as fdist_nm, but different graphic sign. Useful to format corrections/offsets. Download script: format

NB.*flat v format latitude (positive=N, negative=S)

Positive is North, negative is South. The latitude "name" (sign) is located after the numeric values. In some texts it is located in front of the numbers, but placing name in the back seems to be more common. Download script: format

NB.*flon v format longitude (positive=E, negative=W)

Same, but East and West. This verb may benefit from applying 2p1&toneg before it, but so far it is only applied to a longitude which is already in canonical form. Download script: format

NB.*fdec v format declination (positive=N, negative=S)
fdec=:_1 |. flat

It seems that, unlike latitude, declination has its name displayed before the numeric values more often than after.

Format compound values

Download script: format

NB.*fmt v generic format applies formatting verbs from x to elements of y
NB. and joins result together using ' ' as a delimiter
fmt=:(<' ') ;@}.@,@,. apply&.>

Download script: format

NB.*fpos v format 2-element position array (lat,lon)

Download script: format

NB.*fvec v format 2-element vector array (azimuth, distance)

Download script: format

NB.*fobs v format 2-element array of sextant observation (altitude, azimuth)

This is almost same as fvec, except that Hs/Hc are usually recorded with altitude first. Download script: format

NB.*fcat v format catalog entry (Dec,RA)

Format non-angular values

Download script: format

NB.*fdur v format time duration in hours; hours above 24 are displayed
NB. as days, fractions of an hour are displayed as minutes and seconds.
fdur=:3 : 0
  s=.'-' {.~y<0
  d=.(|y) <.@% 24
  y=.1r3600 round 24|y NB. round to nearest second
  t=.(-@(0={:) }. ]) 2 tomin y
  s,((":d),'d ')&,^:(d>0) (":@{.t) , ,(':' , _2{.'00',":)"0 <.}.t

This verb is for formatting time intervals expressed in hours. Stretches longer than 24 hours are converted to days. Example:

   fdur 700%6 NB. 700 miles at 6 knots
4d 20:40
   fdur 70%6 NB. 70 miles at 6 knots

Download script: format

NB.*mmin v move decimal point and everything after it after last symbol
mmin=:(i:~ ({. , _1 |. }.) ])


Download script: parse

NB.*angfstr v parse string containing 1 or more angles in degrees, minutes, etc.
NB. Returns numeric vector
angfstr=:3 : 0
  p=.'([-+NnSsWwEe]?)([0-9.]+)(\s*[°d]\s*([0-9.]+)(\s*[′´''m]\s*(([0-9.]+)\s*[″˝"s]?)?)?)?([NnSsWwEe]?)' rxmatches y
  for_m. p do.
    d=.frommin {.@".&> (2 4 7{m) rxfrom y
    h=.{.toupper >y rxfrom~ 1{m
    s=.1 _1 1 _1 1 _1 1{~ 'NSEW+- ' i. h
    h=.{.toupper >y rxfrom~ 8{m
    r=.r,d*s*1 _1 1 _1 1 _1 1{~ 'NSEW+- ' i. h
  {.^:(1=#) rfd r

hoursfstr=:([: frommin [: ".;._1 ':'&,)

Stub for time/duration parsing. Not included in final script.

According to all of the following is valid and acceptable way to write coordinates

GP_TEST=:<;._2 ] 0 : 0
40:26:46.302N 79:56:55.903W
40°26'47"N 79°58'36"W
40d 26' 47" N 79d 58' 36" W
40.446195N 79.948862W
40.446195, -79.948862
40° 26.7717, -79° 56.93172
N4°35.0´ W12°30.6´
4°35.0´N 12°30.6´W

Download script: parse

NB.*posfstr v parse string into (lat, lon) position
NB. Understands variety of input forms
posfstr=: 3 : 0
  atstart=.(] rxmatch~ '^\s*(' , ')\s*' ,~ [)

  found=._1 0 -.@-: {.
  piece=. >@rxfrom~ 1&{

  r=.i.0 NB. numberic results
  o=.i.0 NB. inferred order

  while. '' -.@-: y do.
    NB. components

    p=.SIGN atstart y
    sgn=.y piece p

    p=.NUMBER atstart y
    assert. found p
    d=._ ". y piece p

    if. -.found p=.DEG atstart y do. goto_trail. end.

    if. -.found p=.NUMBER atstart y do. goto_trail. end.
    m=._ ". y piece p
    y1=.y NB. save in case need to rollback

    if. found p=.MIN atstart y do.
      if. found p=.DEG atstart y do.
        NB. rollback

    if. -.found p=.NUMBER atstart y do. goto_trail. end.
    s=._ ". y piece p
    y1=.y NB. save in case need to rollback

    if. found p=.SEC atstart y do.
      if. found p=.DEG atstart y do.
        NB. rollback

    NB. check for sign if sign is currently empty
    if. ''-:sgn do.
      p=.TAILSIGN atstart y
      if. found p do.
        sgn=.y piece p
    NB. skip separators/trainiling spaces if any
    if. found p=.SEP atstart y do.  y=.y}.~{:{.p end.

    sgn=.toupper {.sgn
    r=.r,(frommin d,m,s)*1 _1 1 _1 1 _1 1{~ 'NSEW+- ' i. sgn
    o=.o,_1 _1 1 1 0 {~ 'NSEW' i. sgn
  rfd r /: o

This sequential parsing routine replaces older version which was simpler and faster, but did not handle some of the example cases.

The intention of this verb is to be able to process copy/paste geo coordinates taken from a random source into canonical form. At least, in some of the cases.


Download script: misc


converts numeric latitude and longitude (in degrees) to radians. Download script: misc

NB.*makevec v convert numeric directional vector into radians
NB.  y=(direction in degrees, speed/distance in knots/nm)

This verb better belongs to drnav script, but all necessary routines are here.

Contributed by Andrew Nikitin