Module: SpatialFeatures::InstanceMethods

Defined in:
lib/spatial_features/has_spatial_features.rb

Instance Method Summary collapse

Instance Method Details

#acts_like_spatial_features?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/spatial_features/has_spatial_features.rb', line 184

def acts_like_spatial_features?
  true
end

#aggregate_featuresObject

Scope to perform SQL-only calculations on a record’s aggregate feature. This avoids loading the large data payload if all that is needed is metadata



272
273
274
# File 'lib/spatial_features/has_spatial_features.rb', line 272

def aggregate_features
  self.class.where(id: id).aggregate_features
end

#boundsObject



225
226
227
228
229
230
231
232
233
234
235
# File 'lib/spatial_features/has_spatial_features.rb', line 225

def bounds
  @bounds ||=
    if has_attribute?(:north) && has_attribute?(:east) && has_attribute?(:south) && has_attribute?(:west)
      slice(:north, :east, :south, :west).with_indifferent_access.transform_values!(&:to_f)
    elsif association(:aggregate_feature).loaded?
      # Aggregate features can be very large and take a while to load. Avoid loading one just to load the bounds.
      aggregate_feature&.bounds
    else
      aggregate_features.bounds
    end
end

#features?Boolean

Returns:

  • (Boolean)


213
214
215
216
217
218
219
# File 'lib/spatial_features/has_spatial_features.rb', line 213

def features?
  if features.loaded?
    features.present?
  else
    features.exists?
  end
end

#features_area_in_square_metersObject



246
247
248
249
250
251
# File 'lib/spatial_features/has_spatial_features.rb', line 246

def features_area_in_square_meters
  @features_area_in_square_meters ||= area if has_attribute?(:area) # Calculated area column
  @features_area_in_square_meters ||= features_area if has_attribute?(:features_area) # Cached area column
  @features_area_in_square_meters ||= aggregate_feature&.area if association(:aggregate_feature).loaded?
  @features_area_in_square_meters ||= aggregate_features.pluck(:area).first
end

#features_cache_keyObject



188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/spatial_features/has_spatial_features.rb', line 188

def features_cache_key
  fck =
    if has_spatial_features_hash?
      features_hash
    elsif association(:aggregate_feature).loaded?
      aggregate_feature.cache_key
    else
      aggregate_features.cache_key
    end

  "#{self.class.name}/#{id}-#{fck}"
end

#intersects?(other) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/spatial_features/has_spatial_features.rb', line 221

def intersects?(other)
  self.class.unscoped { self.class.intersecting(other).exists?(id) }
end

#lines?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/spatial_features/has_spatial_features.rb', line 205

def lines?
  !features.lines.empty?
end

#points?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/spatial_features/has_spatial_features.rb', line 209

def points?
  !features.points.empty?
end

#polygons?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/spatial_features/has_spatial_features.rb', line 201

def polygons?
  !features.polygons.empty?
end

#spatial_cache_for?(other, buffer_in_meters) ⇒ Boolean

Returns:

  • (Boolean)


259
260
261
262
263
264
265
266
267
268
269
# File 'lib/spatial_features/has_spatial_features.rb', line 259

def spatial_cache_for?(other, buffer_in_meters)
  if cache = spatial_caches.between(self, Utils.class_of(other)).first
    return cache.intersection_cache_distance.nil? if buffer_in_meters.nil? # cache must be total if no buffer_in_meters
    return false if cache.stale? # cache must be for current features
    return true if cache.intersection_cache_distance.nil? # always good if cache is total

    return buffer_in_meters <= cache.intersection_cache_distance
  else
    return false
  end
end

#total_intersection_area_in_square_meters(other) ⇒ Object



253
254
255
256
257
# File 'lib/spatial_features/has_spatial_features.rb', line 253

def total_intersection_area_in_square_meters(other)
  other = other.intersecting(self) unless other.is_a?(ActiveRecord::Base)
  return features.area if spatial_cache_for?(other, 0) && SpatialProximity.between(self, other).where('intersection_area_in_square_meters >= ?', features.area).exists?
  return features.total_intersection_area_in_square_meters(other.features)
end

#total_intersection_area_percentage(klass) ⇒ Object



237
238
239
240
241
242
243
244
# File 'lib/spatial_features/has_spatial_features.rb', line 237

def total_intersection_area_percentage(klass)
  total_area = features_area_in_square_meters

  return if total_area.nil?
  return 0.0 if total_area.zero?

  ((total_intersection_area_in_square_meters(klass) / total_area) * 100).round(1)
end