Class: Geoboundary

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/has_geo_lookup/models/geoboundary.rb

Overview

Administrative boundary geometries from GeoBoundaries.org

This model stores precise administrative boundary polygons from GeoBoundaries.org, providing accurate geometric shapes for countries, states, counties, and municipalities worldwide. Each boundary includes PostGIS geometry data for spatial queries and containment testing.

GeoBoundaries provides multiple administrative levels:

  • ADM0: Country boundaries
  • ADM1: State/province boundaries (e.g., California, Ontario)
  • ADM2: County/district boundaries (e.g., Los Angeles County)
  • ADM3: Municipality boundaries (e.g., city limits)
  • ADM4: Neighborhood/ward boundaries
  • ADM5: Sub-neighborhood boundaries (city blocks, micro-districts)

The boundary geometries are stored using PostGIS and can be used for precise point-in-polygon queries to determine administrative containment.

Examples:

Find boundaries containing a point

Geoboundary.where("ST_Contains(boundary, ST_GeomFromText('POINT(-74.0060 40.7128)', 4326))")

Find state-level boundaries for the US

Geoboundary.where(level: "ADM1").where("shape_iso LIKE '%USA%'")

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#boundaryRGeo::Geos::CAPIGeometryMethods

PostGIS geometry (polygon/multipolygon)

Returns:

  • (RGeo::Geos::CAPIGeometryMethods)

    the current value of boundary



34
35
36
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 34

def boundary
  @boundary
end

#levelString

Administrative level (ADM0, ADM1, ADM2, ADM3, ADM4, ADM5)

Returns:

  • (String)

    the current value of level



34
35
36
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 34

def level
  @level
end

#nameString

Official boundary name

Returns:

  • (String)

    the current value of name



34
35
36
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 34

def name
  @name
end

#shape_groupString

Grouping identifier for related boundaries

Returns:

  • (String)

    the current value of shape_group



34
35
36
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 34

def shape_group
  @shape_group
end

#shape_isoString

ISO3 country code for this boundary

Returns:

  • (String)

    the current value of shape_iso



34
35
36
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 34

def shape_iso
  @shape_iso
end

Instance Method Details

#area_km2Float

Calculate the area of this boundary in square kilometers

Uses PostGIS ST_Area function with spheroid calculations for accurate area computation on the Earth's surface.

Examples:

boundary.area_km2
# => 10991.5 (area in square kilometers)

Returns:

  • (Float)

    Area in square kilometers



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 96

def area_km2
  return nil unless boundary
  
  area_m2 = self.class.connection.select_value(
    "SELECT ST_Area(ST_Transform(ST_GeomFromText(?), 3857))", 
    boundary.to_s
  )
  
  area_m2 ? (area_m2 / 1_000_000).round(2) : nil
rescue => e
  Rails.logger.warn "Error calculating boundary area: #{e.message}"
  nil
end

#centroidArray<Float>?

Get the centroid (center point) of this boundary

Uses PostGIS ST_Centroid function to find the geometric center of the boundary polygon.

Examples:

boundary.centroid
# => [40.7589, -73.9851] (lat, lng of boundary center)

Returns:

  • (Array<Float>, nil)

    [latitude, longitude] of centroid, or nil if error



120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 120

def centroid
  return nil unless boundary
  
  result = self.class.connection.select_one(
    "SELECT ST_Y(ST_Centroid(ST_GeomFromText(?))) AS lat, ST_X(ST_Centroid(ST_GeomFromText(?))) AS lng",
    boundary.to_s, boundary.to_s
  )
  
  result ? [result['lat'].to_f, result['lng'].to_f] : nil
rescue => e
  Rails.logger.warn "Error calculating boundary centroid: #{e.message}"
  nil
end

#contains_point?(latitude, longitude) ⇒ Boolean

Check if this boundary contains the given coordinates

Uses MySQL ST_Contains function to perform precise geometric containment testing against the boundary polygon.

Examples:

boundary.contains_point?(40.7128, -74.0060)
# => true (if NYC coordinates are within this boundary)

Parameters:

  • latitude (Float)

    Latitude in decimal degrees

  • longitude (Float)

    Longitude in decimal degrees

Returns:

  • (Boolean)

    true if the point is within this boundary



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 72

def contains_point?(latitude, longitude)
  return false unless latitude && longitude && boundary
  
  point_wkt = "POINT(#{latitude} #{longitude})"
  
  self.class.connection.select_value(
    "SELECT ST_Contains(ST_GeomFromText(?), ST_GeomFromText(?, 4326)) AS contains",
    boundary.to_s, point_wkt
  ) == 1
rescue => e
  Rails.logger.warn "Error checking point containment: #{e.message}"
  false
end

#country?Boolean

Check if this is a country-level boundary

Returns:

  • (Boolean)

    true if level is "ADM0"



163
164
165
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 163

def country?
  level == "ADM0"
end

#county_district?Boolean

Check if this is a county/district-level boundary

Returns:

  • (Boolean)

    true if level is "ADM2"



175
176
177
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 175

def county_district?
  level == "ADM2"
end

#display_nameString

Returns a human-readable description of this boundary

Includes the boundary name, administrative level, and country context for clear identification.

Examples:

boundary.display_name
# => "Los Angeles County (ADM2 - County/District, USA)"

Returns:

  • (String)

    Formatted description



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 144

def display_name
  level_description = case level
  when "ADM0" then "Country"
  when "ADM1" then "State/Province"
  when "ADM2" then "County/District"
  when "ADM3" then "Municipality"
  when "ADM4" then "Neighborhood/Ward"
  when "ADM5" then "Sub-Neighborhood/Block"
  else level
  end
  
  country_info = extract_country_from_shape_iso
  country_suffix = country_info ? ", #{country_info}" : ""
  
  "#{name} (#{level} - #{level_description}#{country_suffix})"
end

#municipality?Boolean

Check if this is a municipality-level boundary

Returns:

  • (Boolean)

    true if level is "ADM3"



181
182
183
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 181

def municipality?
  level == "ADM3"
end

#neighborhood?Boolean

Check if this is a neighborhood-level boundary

Returns:

  • (Boolean)

    true if level is "ADM4"



187
188
189
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 187

def neighborhood?
  level == "ADM4"
end

#state_province?Boolean

Check if this is a state/province-level boundary

Returns:

  • (Boolean)

    true if level is "ADM1"



169
170
171
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 169

def state_province?
  level == "ADM1"
end

#sub_neighborhood?Boolean

Check if this is a sub-neighborhood-level boundary

Returns:

  • (Boolean)

    true if level is "ADM5"



193
194
195
# File 'lib/has_geo_lookup/models/geoboundary.rb', line 193

def sub_neighborhood?
  level == "ADM5"
end