Module: SpatialFeatures::ClassMethods

Defined in:
lib/spatial_features/has_spatial_features.rb

Instance Method Summary collapse

Instance Method Details

#cached_spatial_join(other) ⇒ Object



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

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



78
79
80
# File 'lib/spatial_features/has_spatial_features.rb', line 78

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



73
74
75
76
# File 'lib/spatial_features/has_spatial_features.rb', line 73

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



56
57
58
# File 'lib/spatial_features/has_spatial_features.rb', line 56

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

#pointsObject



60
61
62
# File 'lib/spatial_features/has_spatial_features.rb', line 60

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

#polygonsObject



52
53
54
# File 'lib/spatial_features/has_spatial_features.rb', line 52

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
49
50
# 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 options[:cache] != false # CACHED
      return all.extending(UncachedRelation) unless other.spatial_cache_for?(self, buffer_in_meters) # Don't use the cache if it doesn't exist

    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.geom, features_for_other.geom, ?)', buffer_in_meters) if buffer_in_meters
    scope = scope.select("MIN(ST_Distance(features_for.geom, features_for_other.geom)) AS distance_in_meters") if options[:distance]
    scope = scope.select("SUM(ST_Area(ST_Intersection(features_for.geom, features_for_other.geom))) AS intersection_area_in_square_meters") if options[:intersection_area]
  end

  return scope
end