urbanopt-geojson 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.rakeTasks +7 -0
- data/.rdoc_options +43 -0
- data/.rspec +2 -0
- data/.rubocop.yml +10 -0
- data/.travis.yml +35 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +27 -0
- data/Jenkinsfile +10 -0
- data/LICENSE.md +27 -0
- data/RDOC_MAIN.md +48 -0
- data/README.md +40 -0
- data/Rakefile +45 -0
- data/deploy_docs.sh +4 -0
- data/doc_templates/LICENSE.md +27 -0
- data/doc_templates/README.md.erb +42 -0
- data/doc_templates/copyright_erb.txt +31 -0
- data/doc_templates/copyright_js.txt +4 -0
- data/doc_templates/copyright_ruby.txt +29 -0
- data/docs/.gitignore +3 -0
- data/docs/.vuepress/components/BuildingProperties.vue +12 -0
- data/docs/.vuepress/components/DistrictSystemProperties.vue +12 -0
- data/docs/.vuepress/components/ElectricalConnectorProperties.vue +12 -0
- data/docs/.vuepress/components/ElectricalJunctionProperties.vue +12 -0
- data/docs/.vuepress/components/InnerJsonSchema.vue +80 -0
- data/docs/.vuepress/components/JsonSchema.vue +12 -0
- data/docs/.vuepress/components/RegionProperties.vue +12 -0
- data/docs/.vuepress/components/SiteProperties.vue +12 -0
- data/docs/.vuepress/components/StaticLink.vue +8 -0
- data/docs/.vuepress/components/ThermalConnectorProperties.vue +12 -0
- data/docs/.vuepress/components/ThermalJunctionProperties.vue +12 -0
- data/docs/.vuepress/config.js +22 -0
- data/docs/.vuepress/highlight.js +8 -0
- data/docs/.vuepress/public/custom_rdoc_styles.css +64 -0
- data/docs/.vuepress/utils.js +17 -0
- data/docs/README.md +30 -0
- data/docs/doc/created.rid +0 -0
- data/docs/package-lock.json +11771 -0
- data/docs/package.json +22 -0
- data/docs/schemas/building-properties.md +3 -0
- data/docs/schemas/district-system-properties.md +3 -0
- data/docs/schemas/electrical-connector-properties.md +3 -0
- data/docs/schemas/electrical-junction-properties.md +3 -0
- data/docs/schemas/region-properties.md +3 -0
- data/docs/schemas/site-properties.md +3 -0
- data/docs/schemas/thermal-connector-properties.md +3 -0
- data/docs/schemas/thermal-junction-properties.md +3 -0
- data/lib/measures/.rubocop.yml +5 -0
- data/lib/measures/urban_geometry_creation/LICENSE.md +27 -0
- data/lib/measures/urban_geometry_creation/README.md +48 -0
- data/lib/measures/urban_geometry_creation/README.md.erb +42 -0
- data/lib/measures/urban_geometry_creation/measure.rb +199 -0
- data/lib/measures/urban_geometry_creation/measure.xml +139 -0
- data/lib/measures/urban_geometry_creation/tests/nrel_stm_footprints.geojson +3238 -0
- data/lib/measures/urban_geometry_creation/tests/shadowed_tests.rb +80 -0
- data/lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb +143 -0
- data/lib/measures/urban_geometry_creation_zoning/LICENSE.md +27 -0
- data/lib/measures/urban_geometry_creation_zoning/README.md +48 -0
- data/lib/measures/urban_geometry_creation_zoning/README.md.erb +42 -0
- data/lib/measures/urban_geometry_creation_zoning/measure.rb +203 -0
- data/lib/measures/urban_geometry_creation_zoning/measure.xml +133 -0
- data/lib/measures/urban_geometry_creation_zoning/tests/nrel_stm_footprints.geojson +3238 -0
- data/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_test.rb +143 -0
- data/lib/urbanopt/geojson.rb +41 -0
- data/lib/urbanopt/geojson/building.rb +341 -0
- data/lib/urbanopt/geojson/district_system.rb +53 -0
- data/lib/urbanopt/geojson/extension.rb +63 -0
- data/lib/urbanopt/geojson/feature.rb +206 -0
- data/lib/urbanopt/geojson/geo_file.rb +154 -0
- data/lib/urbanopt/geojson/helper.rb +340 -0
- data/lib/urbanopt/geojson/logging.rb +46 -0
- data/lib/urbanopt/geojson/mapper_classes.rb +85 -0
- data/lib/urbanopt/geojson/model.rb +133 -0
- data/lib/urbanopt/geojson/region.rb +55 -0
- data/lib/urbanopt/geojson/schema/building_properties.json +358 -0
- data/lib/urbanopt/geojson/schema/district_system_properties.json +137 -0
- data/lib/urbanopt/geojson/schema/electrical_connector_properties.json +77 -0
- data/lib/urbanopt/geojson/schema/electrical_junction_properties.json +64 -0
- data/lib/urbanopt/geojson/schema/geojson_schema.json +323 -0
- data/lib/urbanopt/geojson/schema/region_properties.json +93 -0
- data/lib/urbanopt/geojson/schema/site_properties.json +87 -0
- data/lib/urbanopt/geojson/schema/thermal_connector_properties.json +107 -0
- data/lib/urbanopt/geojson/schema/thermal_junction_properties.json +83 -0
- data/lib/urbanopt/geojson/update_areas.rb +102 -0
- data/lib/urbanopt/geojson/validate_geojson.rb +147 -0
- data/lib/urbanopt/geojson/version.rb +35 -0
- data/lib/urbanopt/geojson/workflows/building.osw +187 -0
- data/lib/urbanopt/geojson/workflows/building.osw.out +2806 -0
- data/lib/urbanopt/geojson/workflows/district_system.osw +84 -0
- data/lib/urbanopt/geojson/workflows/district_system.osw.out +646 -0
- data/lib/urbanopt/geojson/zoning.rb +134 -0
- data/package-lock.json +3 -0
- data/urbanopt-geojson-gem.gemspec +39 -0
- metadata +238 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'urbanopt/geojson/feature'
|
32
|
+
|
33
|
+
module URBANopt
|
34
|
+
module GeoJSON # :nodoc: all
|
35
|
+
class DistrictSystem < Feature
|
36
|
+
def initialize(feature)
|
37
|
+
super(feature)
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Used to describe the feature type using the base method from the Feature class.
|
42
|
+
def feature_type
|
43
|
+
'District System'
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns the district system properties schema.
|
48
|
+
def schema_file
|
49
|
+
return File.join(File.dirname(__FILE__), 'schema', 'district_system_properties.json')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'urbanopt/geojson/version'
|
32
|
+
require 'openstudio/extension'
|
33
|
+
|
34
|
+
module URBANopt
|
35
|
+
module GeoJSON
|
36
|
+
class Extension < OpenStudio::Extension::Extension
|
37
|
+
def initialize # :nodoc:
|
38
|
+
@root_dir = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Returns the absolute path of the measures or returns nil, in case no measures are
|
43
|
+
# added. It can be used while configuring OSWs.
|
44
|
+
def measures_dir
|
45
|
+
return File.absolute_path(File.join(@root_dir, 'lib/measures'))
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# The directory containign relevant files such as weather data, design days, etc.
|
50
|
+
# The method returns nil if no files are present. It is used while configuring OSWs.
|
51
|
+
def files_dir
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# The directory containing common files like copyright and license notices which are used to update measures and other code.
|
56
|
+
# This method will only be applied to measures in the current repository and
|
57
|
+
# returns the absolute path of the +doc_templates_dir+ or nil if there is none.
|
58
|
+
def doc_templates_dir
|
59
|
+
return File.absolute_path(File.join(@root_dir, 'doc_templates'))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'urbanopt/core/feature'
|
32
|
+
|
33
|
+
module URBANopt
|
34
|
+
module GeoJSON
|
35
|
+
class Feature < URBANopt::Core::Feature
|
36
|
+
attr_reader :feature_json
|
37
|
+
|
38
|
+
@@feature_schema = {}
|
39
|
+
@@schema_file_lock = Mutex.new
|
40
|
+
|
41
|
+
##
|
42
|
+
# Used to validate the feature using the validate_feat method.
|
43
|
+
def initialize(feature)
|
44
|
+
@feature_json = validate_feat(feature)
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing(name, *args, &blk)
|
48
|
+
if @feature_json[:properties].keys.map(&:to_sym).include? name.to_sym
|
49
|
+
return @feature_json[:properties][name.to_sym]
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns the id of the feature.
|
57
|
+
|
58
|
+
def id
|
59
|
+
return @feature_json[:properties][:id]
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Returns the name of the feature.
|
64
|
+
|
65
|
+
def name
|
66
|
+
return @feature_json[:properties][:name]
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Raises an error if the +feature_type+ is not specified the the Feature's class.
|
71
|
+
|
72
|
+
def feature_type
|
73
|
+
raise 'feature_type not implemented for Feature, override in your class'
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Raises an error if the +schema_file+ is not specified the the Feature's class.
|
78
|
+
|
79
|
+
def schema_file
|
80
|
+
raise 'schema_file not implemented for Feature, override in your class'
|
81
|
+
end
|
82
|
+
|
83
|
+
def schema
|
84
|
+
if @@feature_schema[feature_type].nil?
|
85
|
+
@@schema_file_lock.synchronize do
|
86
|
+
File.open(schema_file, 'r') do |file|
|
87
|
+
@@feature_schema[feature_type] = JSON.parse(file.read, symbolize_names: true)
|
88
|
+
|
89
|
+
# Allows additional properties.
|
90
|
+
@@feature_schema[feature_type][:additionalProperties] = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
return @@feature_schema[feature_type]
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Returns coordinate with the minimum longitute and latitude within a given +building_json+ .
|
100
|
+
def get_min_lon_lat
|
101
|
+
min_lon = Float::MAX
|
102
|
+
min_lat = Float::MAX
|
103
|
+
multi_polygons = get_multi_polygons
|
104
|
+
multi_polygons.each do |multi_polygon|
|
105
|
+
multi_polygon.each do |polygon|
|
106
|
+
polygon.each do |point|
|
107
|
+
min_lon = point[0] if point[0] < min_lon
|
108
|
+
min_lat = point[1] if point[1] < min_lat
|
109
|
+
end
|
110
|
+
break
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return [min_lon, min_lat]
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Returns MultiPolygon coordinates (coordinate pairs in double nested Array)
|
118
|
+
# [Parameters]
|
119
|
+
# +json+
|
120
|
+
#
|
121
|
+
# For example:
|
122
|
+
#
|
123
|
+
# polygon = {
|
124
|
+
# 'geometry': {
|
125
|
+
# 'type': 'Polygon',
|
126
|
+
# 'coordinates': [
|
127
|
+
# [
|
128
|
+
# [0, 5],
|
129
|
+
# [5, 5],
|
130
|
+
# [5, 0]
|
131
|
+
# ]
|
132
|
+
# ]
|
133
|
+
# }
|
134
|
+
# }
|
135
|
+
def get_multi_polygons(json = @feature_json)
|
136
|
+
geometry_type = json[:geometry][:type]
|
137
|
+
multi_polygons = []
|
138
|
+
if geometry_type == 'Polygon'
|
139
|
+
polygons = json[:geometry][:coordinates]
|
140
|
+
multi_polygons = [polygons]
|
141
|
+
elsif geometry_type == 'MultiPolygon'
|
142
|
+
multi_polygons = json[:geometry][:coordinates]
|
143
|
+
end
|
144
|
+
return multi_polygons
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Returns instance of OpenStudio::PointLatLon for latitude and longitude of feature.
|
149
|
+
#
|
150
|
+
# [Parameters]
|
151
|
+
# * +runner+ - An instance of +Openstudio::Measure::OSRunner+ for the measure run.
|
152
|
+
def create_origin_lat_lon(runner)
|
153
|
+
min_lon_lat = get_min_lon_lat
|
154
|
+
min_lon = min_lon_lat[0]
|
155
|
+
min_lat = min_lon_lat[1]
|
156
|
+
|
157
|
+
if min_lon == Float::MAX || min_lat == Float::MAX
|
158
|
+
runner.registerError('Could not determine min_lat and min_lon')
|
159
|
+
return false
|
160
|
+
else
|
161
|
+
runner.registerInfo("Min_lat = #{min_lat}, min_lon = #{min_lon}")
|
162
|
+
end
|
163
|
+
|
164
|
+
return OpenStudio::PointLatLon.new(min_lat, min_lon, 0)
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
##
|
170
|
+
# Used to validate the feature by checking +feature_id+ , +geometry+, +properties+
|
171
|
+
# and +geometry_type+ .
|
172
|
+
|
173
|
+
def validate_feat(feature) #:doc:
|
174
|
+
if feature.nil? || feature.empty?
|
175
|
+
raise("Feature '#{feature_id}' could not be found")
|
176
|
+
return false
|
177
|
+
end
|
178
|
+
|
179
|
+
if feature[:geometry].nil?
|
180
|
+
raise("No geometry found in '#{feature}'")
|
181
|
+
return false
|
182
|
+
end
|
183
|
+
|
184
|
+
if feature[:properties].nil?
|
185
|
+
raise("No properties found in '#{feature}'")
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
|
189
|
+
errors = JSON::Validator.fully_validate(schema, feature[:properties])
|
190
|
+
if !errors.empty?
|
191
|
+
raise("Invalid properties for '#{feature}'\n #{errors.join('\n ')}")
|
192
|
+
return false
|
193
|
+
end
|
194
|
+
|
195
|
+
geometry_type = feature[:geometry][:type]
|
196
|
+
if geometry_type == 'Polygon'
|
197
|
+
elsif geometry_type == 'MultiPolygon'
|
198
|
+
else
|
199
|
+
raise("Unknown geometry type '#{geometry_type}'")
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
return feature
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'json-schema'
|
32
|
+
require 'urbanopt/core/feature_file'
|
33
|
+
require 'urbanopt/geojson/building'
|
34
|
+
require 'urbanopt/geojson/district_system'
|
35
|
+
require 'urbanopt/geojson/logging'
|
36
|
+
require 'json'
|
37
|
+
|
38
|
+
module URBANopt
|
39
|
+
module GeoJSON
|
40
|
+
class GeoFile < URBANopt::Core::FeatureFile
|
41
|
+
@@geojson_schema = nil
|
42
|
+
@@schema_file_lock = Mutex.new
|
43
|
+
|
44
|
+
##
|
45
|
+
# Raises an error in case the GeoJSON file is not valid.
|
46
|
+
#
|
47
|
+
# [Parameters]
|
48
|
+
#
|
49
|
+
# * +data+ - _Type:Hash_ Contains the GeoJSON.
|
50
|
+
def initialize(data, path = nil)
|
51
|
+
@path = path
|
52
|
+
@geojson = data
|
53
|
+
if !valid?
|
54
|
+
raise 'GeoJSON file does not adhere to schema'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# [Parameters]
|
60
|
+
#
|
61
|
+
# Used to check the GeoJSON file path.
|
62
|
+
# * +path+ - _Type:String_ - GeoJSON file path.
|
63
|
+
def self.from_file(path)
|
64
|
+
if path.nil? || path.empty?
|
65
|
+
raise "GeoJSON file '#{path}' could not be found"
|
66
|
+
end
|
67
|
+
|
68
|
+
if !File.exist?(path)
|
69
|
+
raise "GeoJSON file '#{path}' does not exist"
|
70
|
+
end
|
71
|
+
|
72
|
+
geojson = JSON.parse(
|
73
|
+
File.open(path, 'r', &:read),
|
74
|
+
symbolize_names: true
|
75
|
+
)
|
76
|
+
return new(geojson, path)
|
77
|
+
end
|
78
|
+
|
79
|
+
def json
|
80
|
+
@geojson
|
81
|
+
end
|
82
|
+
|
83
|
+
attr_reader :path
|
84
|
+
|
85
|
+
##
|
86
|
+
# This method loops through all the features in the GeoJSON file, creates new
|
87
|
+
# Buildings or District Systems based on the feature type, and returns the features.
|
88
|
+
#
|
89
|
+
def features
|
90
|
+
result = []
|
91
|
+
@geojson[:features].each do |f|
|
92
|
+
if f[:properties] && f[:properties][:type] == 'Building'
|
93
|
+
result << URBANopt::GeoJSON::Building.new(f)
|
94
|
+
elsif f[:properties] && f[:properties][:type] == 'District System'
|
95
|
+
result << URBANopt::GeoJSON::DistrictSystem.new(f)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return result
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Returns feature object by feature_id from specified GeoJSON file and creates a
|
103
|
+
# new +URBANopt::GeoJSON::Building+ or +URBANopt::GeoJSON::DistrictSystem+ based on the
|
104
|
+
# feature type.
|
105
|
+
#
|
106
|
+
# [Parameters]
|
107
|
+
# * +feature_id+ - _Type:String/Number_ - Id affiliated with feature object.
|
108
|
+
def get_feature_by_id(feature_id)
|
109
|
+
@geojson[:features].each do |f|
|
110
|
+
if f[:properties] && f[:properties][:id] == feature_id
|
111
|
+
if f[:properties][:type] == 'Building'
|
112
|
+
return URBANopt::GeoJSON::Building.new(f)
|
113
|
+
elsif f[:properties] && f[:properties][:type] == 'District System'
|
114
|
+
return URBANopt::GeoJSON::DistrictSystem.new(f)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns the file path for the +geojson_schema.json+ .
|
123
|
+
def schema_file
|
124
|
+
return File.join(File.dirname(__FILE__), 'schema', 'geojson_schema.json')
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Returns the +geojson_schema+ .
|
129
|
+
def schema
|
130
|
+
if @@geojson_schema.nil?
|
131
|
+
@@schema_file_lock.synchronize do
|
132
|
+
File.open(schema_file, 'r') do |file|
|
133
|
+
@@geojson_schema = JSON.parse(file.read, symbolize_names: true)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
return @@geojson_schema
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Validates the GeoJSON file against the schema.
|
143
|
+
def valid?
|
144
|
+
return JSON::Validator.validate(schema, @geojson)
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Returns detailed validation results.
|
149
|
+
def validation_errors
|
150
|
+
return JSON::Validator.fully_validate(schema, @geojson)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|