urbanopt-geojson 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rakeTasks +7 -0
  4. data/.rdoc_options +43 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +10 -0
  7. data/.travis.yml +35 -0
  8. data/CHANGELOG.md +5 -0
  9. data/Gemfile +27 -0
  10. data/Jenkinsfile +10 -0
  11. data/LICENSE.md +27 -0
  12. data/RDOC_MAIN.md +48 -0
  13. data/README.md +40 -0
  14. data/Rakefile +45 -0
  15. data/deploy_docs.sh +4 -0
  16. data/doc_templates/LICENSE.md +27 -0
  17. data/doc_templates/README.md.erb +42 -0
  18. data/doc_templates/copyright_erb.txt +31 -0
  19. data/doc_templates/copyright_js.txt +4 -0
  20. data/doc_templates/copyright_ruby.txt +29 -0
  21. data/docs/.gitignore +3 -0
  22. data/docs/.vuepress/components/BuildingProperties.vue +12 -0
  23. data/docs/.vuepress/components/DistrictSystemProperties.vue +12 -0
  24. data/docs/.vuepress/components/ElectricalConnectorProperties.vue +12 -0
  25. data/docs/.vuepress/components/ElectricalJunctionProperties.vue +12 -0
  26. data/docs/.vuepress/components/InnerJsonSchema.vue +80 -0
  27. data/docs/.vuepress/components/JsonSchema.vue +12 -0
  28. data/docs/.vuepress/components/RegionProperties.vue +12 -0
  29. data/docs/.vuepress/components/SiteProperties.vue +12 -0
  30. data/docs/.vuepress/components/StaticLink.vue +8 -0
  31. data/docs/.vuepress/components/ThermalConnectorProperties.vue +12 -0
  32. data/docs/.vuepress/components/ThermalJunctionProperties.vue +12 -0
  33. data/docs/.vuepress/config.js +22 -0
  34. data/docs/.vuepress/highlight.js +8 -0
  35. data/docs/.vuepress/public/custom_rdoc_styles.css +64 -0
  36. data/docs/.vuepress/utils.js +17 -0
  37. data/docs/README.md +30 -0
  38. data/docs/doc/created.rid +0 -0
  39. data/docs/package-lock.json +11771 -0
  40. data/docs/package.json +22 -0
  41. data/docs/schemas/building-properties.md +3 -0
  42. data/docs/schemas/district-system-properties.md +3 -0
  43. data/docs/schemas/electrical-connector-properties.md +3 -0
  44. data/docs/schemas/electrical-junction-properties.md +3 -0
  45. data/docs/schemas/region-properties.md +3 -0
  46. data/docs/schemas/site-properties.md +3 -0
  47. data/docs/schemas/thermal-connector-properties.md +3 -0
  48. data/docs/schemas/thermal-junction-properties.md +3 -0
  49. data/lib/measures/.rubocop.yml +5 -0
  50. data/lib/measures/urban_geometry_creation/LICENSE.md +27 -0
  51. data/lib/measures/urban_geometry_creation/README.md +48 -0
  52. data/lib/measures/urban_geometry_creation/README.md.erb +42 -0
  53. data/lib/measures/urban_geometry_creation/measure.rb +199 -0
  54. data/lib/measures/urban_geometry_creation/measure.xml +139 -0
  55. data/lib/measures/urban_geometry_creation/tests/nrel_stm_footprints.geojson +3238 -0
  56. data/lib/measures/urban_geometry_creation/tests/shadowed_tests.rb +80 -0
  57. data/lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb +143 -0
  58. data/lib/measures/urban_geometry_creation_zoning/LICENSE.md +27 -0
  59. data/lib/measures/urban_geometry_creation_zoning/README.md +48 -0
  60. data/lib/measures/urban_geometry_creation_zoning/README.md.erb +42 -0
  61. data/lib/measures/urban_geometry_creation_zoning/measure.rb +203 -0
  62. data/lib/measures/urban_geometry_creation_zoning/measure.xml +133 -0
  63. data/lib/measures/urban_geometry_creation_zoning/tests/nrel_stm_footprints.geojson +3238 -0
  64. data/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_test.rb +143 -0
  65. data/lib/urbanopt/geojson.rb +41 -0
  66. data/lib/urbanopt/geojson/building.rb +341 -0
  67. data/lib/urbanopt/geojson/district_system.rb +53 -0
  68. data/lib/urbanopt/geojson/extension.rb +63 -0
  69. data/lib/urbanopt/geojson/feature.rb +206 -0
  70. data/lib/urbanopt/geojson/geo_file.rb +154 -0
  71. data/lib/urbanopt/geojson/helper.rb +340 -0
  72. data/lib/urbanopt/geojson/logging.rb +46 -0
  73. data/lib/urbanopt/geojson/mapper_classes.rb +85 -0
  74. data/lib/urbanopt/geojson/model.rb +133 -0
  75. data/lib/urbanopt/geojson/region.rb +55 -0
  76. data/lib/urbanopt/geojson/schema/building_properties.json +358 -0
  77. data/lib/urbanopt/geojson/schema/district_system_properties.json +137 -0
  78. data/lib/urbanopt/geojson/schema/electrical_connector_properties.json +77 -0
  79. data/lib/urbanopt/geojson/schema/electrical_junction_properties.json +64 -0
  80. data/lib/urbanopt/geojson/schema/geojson_schema.json +323 -0
  81. data/lib/urbanopt/geojson/schema/region_properties.json +93 -0
  82. data/lib/urbanopt/geojson/schema/site_properties.json +87 -0
  83. data/lib/urbanopt/geojson/schema/thermal_connector_properties.json +107 -0
  84. data/lib/urbanopt/geojson/schema/thermal_junction_properties.json +83 -0
  85. data/lib/urbanopt/geojson/update_areas.rb +102 -0
  86. data/lib/urbanopt/geojson/validate_geojson.rb +147 -0
  87. data/lib/urbanopt/geojson/version.rb +35 -0
  88. data/lib/urbanopt/geojson/workflows/building.osw +187 -0
  89. data/lib/urbanopt/geojson/workflows/building.osw.out +2806 -0
  90. data/lib/urbanopt/geojson/workflows/district_system.osw +84 -0
  91. data/lib/urbanopt/geojson/workflows/district_system.osw.out +646 -0
  92. data/lib/urbanopt/geojson/zoning.rb +134 -0
  93. data/package-lock.json +3 -0
  94. data/urbanopt-geojson-gem.gemspec +39 -0
  95. 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