Module: SpatialFeatures::ClassMethods

Defined in:
lib/spatial_features/has_spatial_features.rb

Instance Method Summary collapse

Instance Method Details

#cached_spatial_join(other) ⇒ Object



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

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
24
# File 'lib/spatial_features/has_spatial_features.rb', line 21

def features_cache_key
    max_id, count = Feature.where(:spatial_model_type => self).pluck("MAX(id), COUNT(*)").first
  "#{name}/#{max_id}-#{count}"
end

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



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

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

#joins_features(table_alias = 'features_for') ⇒ Object



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

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



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

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



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

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

#pointsObject



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

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

#polygonsObject



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

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

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



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

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