spatial_features 3.4.8 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -3
- data/app/models/abstract_feature.rb +2 -14
- data/app/models/feature.rb +0 -2
- data/lib/spatial_features/has_spatial_features/feature_import.rb +12 -2
- data/lib/spatial_features/has_spatial_features/queued_spatial_processing.rb +6 -5
- data/lib/spatial_features/importers/base.rb +3 -3
- data/lib/spatial_features/importers/kml.rb +3 -3
- data/lib/spatial_features/importers/shapefile.rb +1 -2
- data/lib/spatial_features/version.rb +1 -1
- metadata +28 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c477982103b4f48e410ff562a0bf0e16ec24e4cd3b42584aa5015cde9d380264
|
4
|
+
data.tar.gz: 9982438597418015427e05f060ac060f2a3ab803930c06d8a5e9a7578153129f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4aa2e8cdb7a59b4bf113489055c0d3018b3fb01ce5e18d6a03ec77d865e177b84231715abab3c410d5aba837db2fc0f0ebf2dd6ab70d5892567aaeda7b6e4e0a
|
7
|
+
data.tar.gz: 9a823d0703242fff4b790428b531a52d6017aa28e5922d87052066ff72e8056fa841825566e4feb0d48f10b238ca0be5570393ffe126108cf8c057efac3dbfba
|
data/README.md
CHANGED
@@ -106,7 +106,8 @@ Person.new(:features => [Feature.new(:geog => 'some binary PostGIS Geography str
|
|
106
106
|
### Import
|
107
107
|
|
108
108
|
You can specify multiple import sources for geometry. Each key is a method that returns the data for the Importer, and
|
109
|
-
each value is the Importer to use to parse the data.
|
109
|
+
each value is the Importer to use to parse the data. Options can be passed in place of the Importer name, but must still
|
110
|
+
include a `name` key with the name of the importer. See each Importer for more details.
|
110
111
|
```ruby
|
111
112
|
def ImageImporter
|
112
113
|
def self.call(feature, image_paths)
|
@@ -117,8 +118,11 @@ def ImageImporter
|
|
117
118
|
end
|
118
119
|
|
119
120
|
class Location < ActiveRecord::Base
|
120
|
-
has_spatial_features :
|
121
|
-
:
|
121
|
+
has_spatial_features :image_handlers => ['ImageImporter'],
|
122
|
+
:import => {
|
123
|
+
:remote_kml_url => { :name => 'KMLFile', :feature_name => lambda {|source_feature| source_feature.metadata['shapeID'] },
|
124
|
+
:file => 'File', :geojson => 'ESRIGeoJSON' }
|
125
|
+
}
|
122
126
|
|
123
127
|
def remote_kml_url
|
124
128
|
"www.test.com/kml/#{id}.kml"
|
@@ -200,6 +204,23 @@ add_index :features, :source_identifier
|
|
200
204
|
MyModel.update_features!(:force => true) # Force an `update_features!` will populate the source_identifier column.
|
201
205
|
```
|
202
206
|
|
207
|
+
## Upgrading From 3.4 to 3.5
|
208
|
+
The gem now relies on virtual columns to set a number of derived column values.
|
209
|
+
```ruby
|
210
|
+
change_table :features do |t|
|
211
|
+
t.remove :tilegeom, :feature_type, :centroid, :area, :north, :east, :south, :west
|
212
|
+
|
213
|
+
t.virtual :tilegeom, :type => 'geometry(Geometry,3857)', as: "ST_Transform(geom, 3857)", stored: true, :index => { :using => :gist }
|
214
|
+
t.virtual :feature_type, :type => :string, as: "CASE GeometryType(geog) WHEN 'POLYGON' THEN 'polygon' WHEN 'MULTIPOLYGON' THEN 'polygon' WHEN 'GEOMETRYCOLLECTION' THEN 'polygon' WHEN 'LINESTRING' THEN 'line' WHEN 'MULTILINESTRING' THEN 'line' WHEN 'POINT' THEN 'point' WHEN 'MULTIPOINT' THEN 'point' END", stored: true, :index => true
|
215
|
+
t.virtual :centroid, :type => :geography, as: "ST_PointOnSurface(geog::geometry)", stored: true
|
216
|
+
t.virtual :area, :type => :decimal, as: "ST_Area(geog)", stored: true
|
217
|
+
t.virtual :north, :type => :decimal, as: "ST_YMax(geog::geometry)", stored: true
|
218
|
+
t.virtual :east, :type => :decimal, as: "ST_XMax(geog::geometry)", stored: true
|
219
|
+
t.virtual :south, :type => :decimal, as: "ST_YMin(geog::geometry)", stored: true
|
220
|
+
t.virtual :west, :type => :decimal, as: "ST_XMin(geog::geometry)", stored: true
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
203
224
|
## Testing
|
204
225
|
|
205
226
|
Create a postgres database:
|
@@ -13,7 +13,6 @@ class AbstractFeature < ActiveRecord::Base
|
|
13
13
|
|
14
14
|
FEATURE_TYPES = %w(polygon point line)
|
15
15
|
|
16
|
-
before_validation :sanitize_feature_type
|
17
16
|
validates_presence_of :geog
|
18
17
|
validate :validate_geometry, if: :will_save_change_to_geog?
|
19
18
|
before_save :sanitize, if: :will_save_change_to_geog?
|
@@ -113,13 +112,7 @@ class AbstractFeature < ActiveRecord::Base
|
|
113
112
|
|
114
113
|
def self.cache_derivatives(options = {})
|
115
114
|
update_all <<-SQL.squish
|
116
|
-
geom = ST_Transform(geog::geometry, #{detect_srid('geom')})
|
117
|
-
north = ST_YMax(geog::geometry),
|
118
|
-
east = ST_XMax(geog::geometry),
|
119
|
-
south = ST_YMin(geog::geometry),
|
120
|
-
west = ST_XMin(geog::geometry),
|
121
|
-
area = ST_Area(geog),
|
122
|
-
centroid = ST_PointOnSurface(geog::geometry)
|
115
|
+
geom = ST_Transform(geog::geometry, #{detect_srid('geom')})
|
123
116
|
SQL
|
124
117
|
|
125
118
|
invalid('geom').update_all <<-SQL.squish
|
@@ -127,8 +120,7 @@ class AbstractFeature < ActiveRecord::Base
|
|
127
120
|
SQL
|
128
121
|
|
129
122
|
update_all <<-SQL.squish
|
130
|
-
geom_lowres = ST_SimplifyPreserveTopology(geom, #{options.fetch(:lowres_simplification, lowres_simplification)})
|
131
|
-
tilegeom = ST_Transform(geom, 3857)
|
123
|
+
geom_lowres = ST_SimplifyPreserveTopology(geom, #{options.fetch(:lowres_simplification, lowres_simplification)})
|
132
124
|
SQL
|
133
125
|
|
134
126
|
invalid('geom_lowres').update_all <<-SQL.squish
|
@@ -286,10 +278,6 @@ class AbstractFeature < ActiveRecord::Base
|
|
286
278
|
return error.fetch('invalid_geometry_message') if error
|
287
279
|
end
|
288
280
|
|
289
|
-
def sanitize_feature_type
|
290
|
-
self.feature_type = FEATURE_TYPES.find {|type| self.feature_type.to_s.strip.downcase.include?(type) }
|
291
|
-
end
|
292
|
-
|
293
281
|
def sanitize_input_for_sql(input)
|
294
282
|
self.class.send(:sanitize_sql_for_conditions, input)
|
295
283
|
end
|
data/app/models/feature.rb
CHANGED
@@ -11,8 +11,6 @@ class Feature < AbstractFeature
|
|
11
11
|
|
12
12
|
scope :source_identifier, lambda {|source_identifier| where(:source_identifier => source_identifier) if source_identifier.present? }
|
13
13
|
|
14
|
-
validates_inclusion_of :feature_type, :in => FEATURE_TYPES
|
15
|
-
|
16
14
|
before_save :truncate_name
|
17
15
|
|
18
16
|
after_save :refresh_aggregate, if: :automatically_refresh_aggregate?
|
@@ -88,10 +88,20 @@ module SpatialFeatures
|
|
88
88
|
private
|
89
89
|
|
90
90
|
def spatial_feature_imports(import_options, make_valid, tmpdir)
|
91
|
-
import_options.flat_map do |data_method,
|
91
|
+
import_options.flat_map do |data_method, configuration|
|
92
|
+
case configuration
|
93
|
+
when Hash
|
94
|
+
importer_name = configuration.fetch(:name)
|
95
|
+
options = configuration.except(:name)
|
96
|
+
else
|
97
|
+
importer_name = configuration
|
98
|
+
options = {}
|
99
|
+
end
|
100
|
+
|
92
101
|
Array.wrap(send(data_method)).flat_map do |data|
|
93
102
|
next unless data.present?
|
94
|
-
|
103
|
+
|
104
|
+
spatial_importer_from_name(importer_name).create_all(data, **options, :make_valid => make_valid, :tmpdir => tmpdir)
|
95
105
|
end
|
96
106
|
end.compact
|
97
107
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module SpatialFeatures
|
2
2
|
module QueuedSpatialProcessing
|
3
3
|
extend ActiveSupport::Concern
|
4
|
+
mattr_accessor :priority_offset, default: 0 # Offsets the queued priority of spatial tasks. Lower numbers run with higher priority
|
4
5
|
|
5
6
|
def self.update_cached_status(record, method_name, state)
|
6
7
|
return unless record.has_attribute?(:spatial_processing_status_cache)
|
@@ -11,12 +12,12 @@ module SpatialFeatures
|
|
11
12
|
record.update_column(:spatial_processing_status_cache, cache) if record.will_save_change_to_spatial_processing_status_cache?
|
12
13
|
end
|
13
14
|
|
14
|
-
def queue_update_spatial_cache(*args, **kwargs)
|
15
|
-
queue_spatial_task('update_spatial_cache', *args, **kwargs)
|
15
|
+
def queue_update_spatial_cache(*args, priority: priority_offset + 1, **kwargs)
|
16
|
+
queue_spatial_task('update_spatial_cache', *args, priority:, **kwargs)
|
16
17
|
end
|
17
18
|
|
18
|
-
def delay_update_features!(*args, **kwargs)
|
19
|
-
queue_spatial_task('update_features!', *args, **kwargs)
|
19
|
+
def delay_update_features!(*args, priority: priority_offset + 0, **kwargs)
|
20
|
+
queue_spatial_task('update_features!', *args, priority:, **kwargs)
|
20
21
|
end
|
21
22
|
|
22
23
|
def updating_features?(**options)
|
@@ -77,7 +78,7 @@ module SpatialFeatures
|
|
77
78
|
|
78
79
|
def queue_spatial_task(method_name, *args, priority: 1, **kwargs)
|
79
80
|
# NOTE: We pass kwargs as an arg because Delayed::Job does not support separation of positional and keyword arguments in Ruby 3.0. Instead we perform manual extraction in `perform`.
|
80
|
-
Delayed::Job.enqueue SpatialProcessingJob.new(self, method_name, *args, kwargs), :queue => spatial_processing_queue_name + method_name, :
|
81
|
+
Delayed::Job.enqueue SpatialProcessingJob.new(self, method_name, *args, kwargs), :queue => spatial_processing_queue_name + method_name, priority:
|
81
82
|
end
|
82
83
|
|
83
84
|
def spatial_processing_queue_name
|
@@ -6,12 +6,13 @@ module SpatialFeatures
|
|
6
6
|
attr_reader :errors
|
7
7
|
attr_accessor :source_identifier # An identifier for the source of the features. Used to differentiate groups of features on the spatial model.
|
8
8
|
|
9
|
-
def initialize(data, make_valid: false, tmpdir: nil, source_identifier: nil)
|
9
|
+
def initialize(data, make_valid: false, tmpdir: nil, source_identifier: nil, feature_name: ->(record) { record.name })
|
10
10
|
@make_valid = make_valid
|
11
11
|
@data = data
|
12
12
|
@errors = []
|
13
13
|
@tmpdir = tmpdir
|
14
14
|
@source_identifier = source_identifier
|
15
|
+
@feature_name = feature_name
|
15
16
|
end
|
16
17
|
|
17
18
|
def features
|
@@ -51,13 +52,12 @@ module SpatialFeatures
|
|
51
52
|
def build_feature(record)
|
52
53
|
importable_image_paths = record.importable_image_paths if record.respond_to?(:importable_image_paths)
|
53
54
|
Feature.new do |feature|
|
54
|
-
feature.name = record.name
|
55
55
|
feature.metadata = record.metadata
|
56
|
-
feature.feature_type = record.feature_type
|
57
56
|
feature.geog = record.geog
|
58
57
|
feature.importable_image_paths = importable_image_paths
|
59
58
|
feature.make_valid = @make_valid
|
60
59
|
feature.source_identifier = source_identifier
|
60
|
+
feature.name = @feature_name.is_a?(Proc) ? @feature_name.call(record) : @feature_name
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -22,9 +22,9 @@ module SpatialFeatures
|
|
22
22
|
def each_record(&block)
|
23
23
|
{'Polygon' => 'POLYGON', 'LineString' => 'LINE', 'Point' => 'POINT'}.each do |kml_type, sql_type|
|
24
24
|
kml_document.css(kml_type).each do |feature|
|
25
|
-
if placemark = feature.ancestors('Placemark').first
|
26
|
-
name = placemark.css('name').text
|
25
|
+
if (placemark = feature.ancestors('Placemark').first)
|
27
26
|
metadata = extract_metadata(placemark)
|
27
|
+
name = placemark.css('name').text
|
28
28
|
else
|
29
29
|
metadata = {}
|
30
30
|
end
|
@@ -36,7 +36,7 @@ module SpatialFeatures
|
|
36
36
|
|
37
37
|
importable_image_paths = images_from_metadata(metadata)
|
38
38
|
|
39
|
-
yield OpenStruct.new(:
|
39
|
+
yield OpenStruct.new(:geog => geog, :name => name, :metadata => metadata, :importable_image_paths => importable_image_paths)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -6,7 +6,6 @@ module SpatialFeatures
|
|
6
6
|
class Shapefile < Base
|
7
7
|
class_attribute :default_proj4_projection
|
8
8
|
|
9
|
-
FEATURE_TYPE_FOR_DIMENSION = { 0 => 'point', 1 => 'line', 2 => 'polygon' }.freeze
|
10
9
|
PROJ4_4326 = '+proj=longlat +datum=WGS84 +no_defs'.freeze
|
11
10
|
|
12
11
|
def initialize(data, proj4: nil, **options)
|
@@ -46,7 +45,7 @@ module SpatialFeatures
|
|
46
45
|
def data_from_record(record, proj4 = nil)
|
47
46
|
geometry = record.geometry
|
48
47
|
wkt = geometry.as_text
|
49
|
-
data = { :metadata => record.attributes
|
48
|
+
data = { :metadata => record.attributes }
|
50
49
|
|
51
50
|
if proj4 == PROJ4_4326
|
52
51
|
data[:geog] = wkt
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spatial_features
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Wallace
|
8
8
|
- Nicholas Jakobsen
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -51,14 +51,14 @@ dependencies:
|
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.1'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
61
|
+
version: '3.1'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rgeo-geojson
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,6 +101,26 @@ dependencies:
|
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: rails
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '7'
|
111
|
+
- - "<"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '8'
|
114
|
+
type: :development
|
115
|
+
prerelease: false
|
116
|
+
version_requirements: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '7'
|
121
|
+
- - "<"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '8'
|
104
124
|
- !ruby/object:Gem::Dependency
|
105
125
|
name: pg
|
106
126
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,7 +208,7 @@ homepage: https://github.com/culturecode/spatial_features
|
|
188
208
|
licenses:
|
189
209
|
- MIT
|
190
210
|
metadata: {}
|
191
|
-
post_install_message:
|
211
|
+
post_install_message:
|
192
212
|
rdoc_options: []
|
193
213
|
require_paths:
|
194
214
|
- lib
|
@@ -203,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
223
|
- !ruby/object:Gem::Version
|
204
224
|
version: '0'
|
205
225
|
requirements: []
|
206
|
-
rubygems_version: 3.
|
207
|
-
signing_key:
|
226
|
+
rubygems_version: 3.5.1
|
227
|
+
signing_key:
|
208
228
|
specification_version: 4
|
209
229
|
summary: Adds spatial methods to a model.
|
210
230
|
test_files: []
|