Class: Tina4::Point

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/point.rb

Overview

Immutable SRID-aware longitude/latitude point (ADR-0057).

Constant Summary collapse

DEFAULT_SRID =
4326
EWKB_SRID =
0x20000000
EWKB_M =
0x40000000
EWKB_Z =
0x80000000

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lon, lat, srid: DEFAULT_SRID) ⇒ Point

Returns a new instance of Point.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/tina4/point.rb', line 17

def initialize(lon, lat, srid: DEFAULT_SRID)
  raise ArgumentError, "Point longitude and latitude must be numbers" if lon == true || lon == false || lat == true || lat == false
  @lon = Float(lon)
  @lat = Float(lat)
  @srid = Integer(srid)
  raise ArgumentError, "Point longitude and latitude must be finite" unless @lon.finite? && @lat.finite?
  if @srid == DEFAULT_SRID
    raise ArgumentError, "Point longitude #{@lon} is outside -180..180; Tina4 uses longitude, latitude order" unless (-180.0..180.0).cover?(@lon)
    raise ArgumentError, "Point latitude #{@lat} is outside -90..90; Tina4 uses longitude, latitude order" unless (-90.0..90.0).cover?(@lat)
  end
  freeze
rescue TypeError, ArgumentError => e
  raise e if e.message.start_with?("Point ")
  raise ArgumentError, "Point longitude, latitude and SRID must be numeric"
end

Instance Attribute Details

#latObject (readonly)

Returns the value of attribute lat.



15
16
17
# File 'lib/tina4/point.rb', line 15

def lat
  @lat
end

#lonObject (readonly)

Returns the value of attribute lon.



15
16
17
# File 'lib/tina4/point.rb', line 15

def lon
  @lon
end

#sridObject (readonly)

Returns the value of attribute srid.



15
16
17
# File 'lib/tina4/point.rb', line 15

def srid
  @srid
end

Class Method Details

.geometry_binding(value, srid: DEFAULT_SRID) ⇒ Object

Raises:

  • (ArgumentError)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/tina4/point.rb', line 58

def self.geometry_binding(value, srid: DEFAULT_SRID)
  return [parse(value, srid: srid).ewkt, :ewkt] if value.is_a?(Point) || value.is_a?(Array)
  if value.is_a?(Hash)
    geometry = value.fetch(:type, value["type"]).to_s.downcase == "feature" ? (value[:geometry] || value["geometry"]) : value
    type = (geometry[:type] || geometry["type"]).to_s.downcase
    allowed = %w[point linestring polygon multipoint multilinestring multipolygon geometrycollection]
    raise ArgumentError, "GeoJSON geometry has an unsupported type" unless allowed.include?(type)
    return [JSON.generate(geometry), :geojson]
  end
  if value.is_a?(String) && value.match?(/\A\s*(?:SRID\s*=\s*\d+\s*;\s*)?(?:POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)\b/i)
    return [value.match?(/\A\s*SRID/i) ? value.strip : "SRID=#{srid};#{value.strip}", :ewkt]
  end
  raise ArgumentError, "Geometry must be Point, coordinate pair, WKT/EWKT or GeoJSON"
end

.parse(value, srid: DEFAULT_SRID) ⇒ Object

Raises:

  • (ArgumentError)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/tina4/point.rb', line 40

def self.parse(value, srid: DEFAULT_SRID)
  return value if value.is_a?(Point)
  if value.is_a?(Array)
    raise ArgumentError, "Point coordinate pair needs longitude and latitude" if value.length < 2
    return new(value[0], value[1], srid: srid)
  end
  return from_geojson(value, srid) if value.is_a?(Hash)
  if value.is_a?(String)
    text = value.strip
    match = text.match(/\A(?:SRID\s*=\s*(\d+)\s*;\s*)?POINT\s*(?:Z|M|ZM)?\s*\(\s*([-+0-9.eE]+)\s+([-+0-9.eE]+)(?:\s+[-+0-9.eE]+)*\s*\)\z/i)
    return new(match[2], match[3], srid: match[1] ? match[1].to_i : srid) if match
    raw = [text].pack("H*") if text.length >= 42 && text.length.even? && text.match?(/\A[0-9a-f]+\z/i)
    raw ||= value.b if [0, 1].include?(value.getbyte(0))
    return from_wkb(raw, srid) if raw
  end
  raise ArgumentError, "Point must be Point, [longitude, latitude], WKT/EWKT, GeoJSON or WKB/EWKB"
end

Instance Method Details

#ewktObject



34
# File 'lib/tina4/point.rb', line 34

def ewkt = "SRID=#{@srid};#{wkt}"

#geojsonObject



35
# File 'lib/tina4/point.rb', line 35

def geojson = { type: "Point", coordinates: [@lon, @lat] }

#to_aObject



37
# File 'lib/tina4/point.rb', line 37

def to_a = [@lon, @lat]

#to_hObject



36
# File 'lib/tina4/point.rb', line 36

def to_h = geojson

#to_json(*args) ⇒ Object



38
# File 'lib/tina4/point.rb', line 38

def to_json(*args) = geojson.to_json(*args)

#wktObject



33
# File 'lib/tina4/point.rb', line 33

def wkt = "POINT(#{format_coordinate(@lon)} #{format_coordinate(@lat)})"