class MapPLZ::GeoItem
internal map object record
Public Class Methods
centroid(geo_item)
click to toggle source
# File lib/mapplz.rb, line 865 def self.centroid(geo_item) # generate centroid if possible and not already existing if geo_item.key?(:path) && !geo_item.centroid coordinates = geo_item[:path].clone # centroid calculation from https://code.google.com/p/tokland/source/browse/trunk/centroid consecutive_pairs = (coordinates + [coordinates.first]).each_cons(2) area = 0.5 * consecutive_pairs.map do |(x0, y0), (x1, y1)| (x0 * y1) - (x1 * y0) end area.inject(:+) consecutive_pairs.map! do |(x0, y0), (x1, y1)| cross = (x0 * y1 - x1 * y0) [(x0 + x1) * cross, (y0 + y1) * cross] end (center_lat, center_lng) = consecutive_pairs.transpose.map do |cs| cs.inject(:+) / (6 * area) end geo_item[:centroid] = Digest::SHA256.digest(geo_item[:path].to_s) geo_item[:lat] = center_lat geo_item[:lng] = center_lng end end
new(db = nil)
click to toggle source
# File lib/mapplz.rb, line 713 def initialize(db = nil) db = { type: 'array', client: nil } if db.nil? @db = db @db_type = db[:type] @db_client = db[:client] end
Public Instance Methods
centroid()
click to toggle source
# File lib/mapplz.rb, line 824 def centroid # verify up-to-date centroid exists path_hash = Digest::SHA256.digest(self[:path].to_s) (key?(:path) && key?(:centroid) && self[:centroid] == path_hash) end
delete_item()
click to toggle source
# File lib/mapplz.rb, line 749 def delete_item if @db_type == 'array' keys.each do |key| delete(key) end elsif @db_type == 'mongodb' # update record in database @db[:client].remove(_id: BSON::ObjectId(self[:_id])) elsif @db_type == 'postgis' @db_client.exec("DELETE FROM mapplz WHERE id = #{self[:id]}") elsif @db_type == 'spatialite' @db_client.execute("DELETE FROM mapplz WHERE id = #{self[:id]}") end end
distance_from(user_geo)
click to toggle source
# File lib/mapplz.rb, line 830 def distance_from(user_geo) GeoItem.centroid(self) user_geo = MapPLZ.standardize_geo(user_geo)[0] GeoItem.centroid(user_geo) Geokdtree::Tree.distance([user_geo[:lat], user_geo[:lng]], [self[:lat], self[:lng]]) end
inside?(user_geo)
click to toggle source
# File lib/mapplz.rb, line 838 def inside?(user_geo) GeoItem.centroid(self) # accept [point1, point2, point3, point1] as a polygon search area if user_geo.is_a?(Array) && user_geo[0].is_a?(Array) && !user_geo[0][0].is_a?(Array) user_geo = [user_geo] end user_geo = MapPLZ.standardize_geo(user_geo)[0] path_pts = user_geo[:path] path_pts = path_pts[0] if user_geo[:type] == 'polygon' # point in polygon from http://jakescruggs.blogspot.com/2009/07/point-inside-polygon-in-ruby.html c = false i = -1 j = path_pts.size - 1 while (i += 1) < path_pts.size if (path_pts[i][0] <= self[:lat] && self[:lat] < path_pts[j][0]) || (path_pts[j][0] <= self[:lat] && self[:lat] < path_pts[i][0]) if self[:lng] < (path_pts[j][1] - path_pts[i][1]) * (self[:lat] - path_pts[i][0]) / (path_pts[j][0] - path_pts[i][0]) + path_pts[i][1] c = !c end end j = i end c end
save!()
click to toggle source
# File lib/mapplz.rb, line 720 def save! # update record in database if @db_type == 'mongodb' save_obj = clone save_obj.delete(:_id) save_obj.delete(:lat) save_obj.delete(:lng) save_obj.delete(:path) save_obj.delete(:centroid) save_obj.delete(:type) save_obj[:geo] = JSON.parse(to_geojson)['geometry'] @db[:client].update({ _id: BSON::ObjectId(self[:_id]) }, save_obj) elsif @db_type == 'postgis' geojson_props = (JSON.parse(to_geojson)['properties'] || {}) @db_client.exec("UPDATE mapplz SET geom = ST_GeomFromText('#{to_wkt}'), properties = '#{geojson_props.to_json}' WHERE id = #{self[:id]}") if @db_type == 'postgis' elsif @db_type == 'spatialite' updaters = [] keys.each do |key| next if [:id, :lat, :lng, :path, :type, :centroid].include?(key) updaters << "#{key} = '#{self[key]}'" if self[key].is_a?(String) updaters << "#{key} = #{self[key]}" if self[key].is_a?(Integer) || self[key].is_a?(Float) end updaters << "geom = AsText('#{to_wkt}')" if updaters.length > 0 @db_client.execute("UPDATE mapplz SET #{updaters.join(', ')} WHERE id = #{self[:id]}") end end end
to_geojson()
click to toggle source
# File lib/mapplz.rb, line 781 def to_geojson if key?(:properties) property_list = { properties: self[:properties] } else property_list = clone property_list.delete(:lat) property_list.delete(:lng) property_list.delete(:path) property_list.delete(:type) property_list.delete(:centroid) end output_geo = { type: 'Feature', properties: property_list } if self[:type] == 'point' # point output_geo[:geometry] = { type: 'Point', coordinates: [self[:lng], self[:lat]] } elsif self[:type] == 'polyline' # line output_geo[:geometry] = { type: 'LineString', coordinates: MapPLZ.flip_path(self[:path]) } elsif self[:type] == 'polygon' # polygon rings = self[:path].clone rings.map! do |ring| MapPLZ.flip_path(ring) end output_geo[:geometry] = { type: 'Polygon', coordinates: rings } end output_geo.to_json end
to_wkt()
click to toggle source
# File lib/mapplz.rb, line 764 def to_wkt if self[:type] == 'point' geom = "POINT(#{self[:lng]} #{self[:lat]})" elsif self[:type] == 'polyline' linestring = self[:path].map do |path_pt| "#{path_pt[1]} #{path_pt[0]}" end geom = "LINESTRING(#{linestring.join(', ')})" elsif self[:type] == 'polygon' linestring = self[:path][0].map do |path_pt| "#{path_pt[1]} #{path_pt[0]}" end geom = "POLYGON((#{linestring.join(', ')}))" end geom end