Module: SpatialFeatures::ClassMethods

Defined in:
lib/spatial_features/has_spatial_features.rb

Instance Method Summary collapse

Instance Method Details

#cached_spatial_join(other) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/spatial_features/has_spatial_features.rb', line 62

def cached_spatial_join(other)
  raise "Cannot use cached spatial join for the same class" if other.class.name == self.name

  other_column = other.class.name < self.name ? :model_a : :model_b
  self_column = other_column == :model_a ? :model_b : :model_a

  joins("INNER JOIN spatial_proximities ON spatial_proximities.#{self_column}_type = '#{self}' AND spatial_proximities.#{self_column}_id = #{table_name}.id AND spatial_proximities.#{other_column}_type = '#{other.class}' AND spatial_proximities.#{other_column}_id = '#{other.id}'")
end

#features_cache_keyObject

NOTE: features are never updated, only deleted and created, therefore we can tell if they have changed by finding the maximum id and count instead of needing timestamps



21
22
23
# File 'lib/spatial_features/has_spatial_features.rb', line 21

def features_cache_key
  "#{name}/#{Feature.where(:spatial_model_type => self).maximum(:id)}-#{Feature.where(:spatial_model_type => self).count}"
end

#intersecting(other, options = {}) ⇒ Object



25
26
27
# File 'lib/spatial_features/has_spatial_features.rb', line 25

def intersecting(other, options = {})
  within_buffer(other, 0, options)
end

#joins_features(table_alias = 'features_for') ⇒ Object



76
77
78
# File 'lib/spatial_features/has_spatial_features.rb', line 76

def joins_features(table_alias = 'features_for')
  joins(%Q(INNER JOIN features "#{table_alias}" ON "#{table_alias}".spatial_model_type = '#{name}' AND "#{table_alias}".spatial_model_id = #{table_name}.id))
end

#joins_features_for(other, table_alias = 'features_for') ⇒ Object



71
72
73
74
# File 'lib/spatial_features/has_spatial_features.rb', line 71

def joins_features_for(other, table_alias = 'features_for')
  joins_features(table_alias)
  .joins(%Q(INNER JOIN features "#{table_alias}_other" ON "#{table_alias}_other".spatial_model_type = '#{other.class.name}' AND "#{table_alias}_other".spatial_model_id = #{other.id}))
end

#linesObject



54
55
56
# File 'lib/spatial_features/has_spatial_features.rb', line 54

def lines
  Feature.lines.where(:spatial_model_type => self.class)
end

#pointsObject



58
59
60
# File 'lib/spatial_features/has_spatial_features.rb', line 58

def points
  Feature.points.where(:spatial_model_type => self.class)
end

#polygonsObject



50
51
52
# File 'lib/spatial_features/has_spatial_features.rb', line 50

def polygons
  Feature.polygons.where(:spatial_model_type => self.class)
end

#within_buffer(other, buffer_in_meters = 0, options = {}) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/spatial_features/has_spatial_features.rb', line 29

def within_buffer(other, buffer_in_meters = 0, options = {})
  raise "Can't intersect with #{other} because it does not implement has_features" unless other.has_spatial_features?

  if other.spatial_cache_for?(self, buffer_in_meters) && options[:cache] != false # CACHED
    scope = cached_spatial_join(other)
      .select("#{table_name}.*, spatial_proximities.distance_in_meters, spatial_proximities.intersection_area_in_square_meters")

    scope = scope.where("spatial_proximities.distance_in_meters <= ?", buffer_in_meters) if buffer_in_meters
  else # NON-CACHED
    scope = joins_features_for(other)
      .select("#{table_name}.*")
      .group("#{table_name}.#{primary_key}")

    scope = scope.where('ST_DWithin(features_for.geog, features_for_other.geog, ?)', buffer_in_meters) if buffer_in_meters
    scope = scope.select("MIN(ST_Distance(features_for.geog, features_for_other.geog)) AS distance_in_meters") if options[:distance]
    scope = scope.select("SUM(ST_Area(ST_Intersection(features_for.geog, features_for_other.geog))) AS intersection_area_in_square_meters") if options[:intersection_area]
  end

  return scope
end