urbanopt-geojson 0.2.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.github/pull_request_template.md +2 -2
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +51 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +0 -3
  7. data/LICENSE.md +1 -1
  8. data/RDOC_MAIN.md +26 -22
  9. data/README.md +2 -2
  10. data/Rakefile +2 -2
  11. data/doc_templates/LICENSE.md +1 -1
  12. data/doc_templates/copyright_erb.txt +1 -1
  13. data/doc_templates/copyright_js.txt +1 -1
  14. data/doc_templates/copyright_ruby.txt +1 -1
  15. data/docs/.vuepress/components/InnerJsonSchema.vue +7 -11
  16. data/docs/.vuepress/config.js +11 -1
  17. data/docs/.vuepress/highlight.js +1 -1
  18. data/docs/.vuepress/json-schema-deref-loader.js +22 -0
  19. data/docs/README.md +3 -4
  20. data/docs/package-lock.json +5211 -6889
  21. data/docs/package.json +12 -9
  22. data/lib/measures/.rubocop.yml +1 -1
  23. data/lib/measures/urban_geometry_creation/LICENSE.md +1 -1
  24. data/lib/measures/urban_geometry_creation/README.md +1 -1
  25. data/lib/measures/urban_geometry_creation/measure.rb +21 -4
  26. data/lib/measures/urban_geometry_creation/measure.xml +14 -19
  27. data/lib/measures/urban_geometry_creation_zoning/LICENSE.md +1 -1
  28. data/lib/measures/urban_geometry_creation_zoning/README.md +1 -1
  29. data/lib/measures/urban_geometry_creation_zoning/measure.rb +3 -3
  30. data/lib/measures/urban_geometry_creation_zoning/measure.xml +13 -18
  31. data/lib/urbanopt-geojson.rb +1 -1
  32. data/lib/urbanopt/geojson.rb +2 -1
  33. data/lib/urbanopt/geojson/building.rb +63 -10
  34. data/lib/urbanopt/geojson/derived_extension.rb +1 -1
  35. data/lib/urbanopt/geojson/district_system.rb +1 -1
  36. data/lib/urbanopt/geojson/feature.rb +117 -3
  37. data/lib/urbanopt/geojson/geo_file.rb +3 -4
  38. data/lib/urbanopt/geojson/helper.rb +46 -3
  39. data/lib/urbanopt/geojson/logging.rb +1 -1
  40. data/lib/urbanopt/geojson/mapper_classes.rb +1 -1
  41. data/lib/urbanopt/geojson/model.rb +3 -4
  42. data/lib/urbanopt/geojson/region.rb +1 -1
  43. data/lib/urbanopt/geojson/scale_area.rb +94 -0
  44. data/lib/urbanopt/geojson/schema/building_properties.json +252 -80
  45. data/lib/urbanopt/geojson/schema/electrical_connector_properties.json +9 -9
  46. data/lib/urbanopt/geojson/schema/electrical_junction_properties.json +4 -5
  47. data/lib/urbanopt/geojson/schema/thermal_connector_properties.json +1 -1
  48. data/lib/urbanopt/geojson/schema/thermal_junction_properties.json +1 -1
  49. data/lib/urbanopt/geojson/update_areas.rb +1 -1
  50. data/lib/urbanopt/geojson/validate_geojson.rb +1 -1
  51. data/lib/urbanopt/geojson/version.rb +2 -2
  52. data/lib/urbanopt/geojson/workflows/building.osw.out +4 -4
  53. data/lib/urbanopt/geojson/zoning.rb +21 -16
  54. data/urbanopt-geojson-gem.gemspec +9 -16
  55. metadata +22 -40
  56. data/lib/change_log.rb +0 -147
  57. data/lib/measures/urban_geometry_creation/tests/nrel_stm_footprints.geojson +0 -3238
  58. data/lib/measures/urban_geometry_creation/tests/shadowed_tests.rb +0 -80
  59. data/lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb +0 -139
  60. data/lib/measures/urban_geometry_creation_zoning/tests/nrel_stm_footprints.geojson +0 -3238
  61. data/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_zoning_test.rb +0 -139
@@ -10,20 +10,23 @@
10
10
  },
11
11
  "author": "Brian Schiller",
12
12
  "dependencies": {
13
- "highlight.js": "^9.15.6",
14
- "json-schema-ref-parser": "^6.1.0",
13
+ "highlight.js": "^10.2.0",
14
+ "json-schema-ref-parser": "^9.0.6",
15
15
  "json-schema-view-js": "git+https://git@github.com/bgschiller/json-schema-view-js.git",
16
- "vuepress": "^0.14.10",
16
+ "vuepress": "^1.5.4",
17
17
  "webpack-dev-middleware": "^3.6.0"
18
18
  },
19
19
  "devDependencies": {
20
- "braces": ">=2.3.1",
21
- "gh-pages": "^2.0.1",
20
+ "braces": "^3.0.2",
21
+ "dot-prop": ">=5.1.1",
22
+ "gh-pages": "^3.1.0",
22
23
  "js-yaml": ">=3.13.1",
23
- "lodash": ">=4.17.12",
24
+ "lodash": ">=4.17.19",
24
25
  "lodash.template": ">=4.5.0",
25
- "mixin-deep": ">=1.3.2",
26
- "serialize-javascript": ">=2.1.1",
27
- "set-value": ">=2.0.1"
26
+ "minimist": ">=1.2.3",
27
+ "mixin-deep": "^2.0.1",
28
+ "serialize-javascript": "^5.0.1",
29
+ "set-value": "^3.0.2",
30
+ "yargs-parser": ">=18.1.1"
28
31
  }
29
32
  }
@@ -2,4 +2,4 @@ AllCops:
2
2
  Exclude:
3
3
  - 'spec/test_measures/**/*'
4
4
  inherit_from:
5
- - http://s3.amazonaws.com/openstudio-resources/styles/rubocop.yml
5
+ - http://s3.amazonaws.com/openstudio-resources/styles/rubocop_v3.yml
@@ -1,4 +1,4 @@
1
- URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
1
+ URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
2
  contributors. All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
@@ -5,7 +5,7 @@
5
5
  # UrbanGeometryCreation
6
6
 
7
7
  ## Description
8
- This measure reads an URBANopt GeoJSON and creates geometry for a particular building. Surrounding buildings are included as shading structures.
8
+ This measure reads an URBANopt GeoJSON and creates geometry for a particular building. Surrounding buildings are included as shading structures.
9
9
 
10
10
  ## Modeler Description
11
11
  This measure takes in the GeoJSON file, the feature_id of the building and the surrounding buildings as arguments and add has methods to create space types and add default construction sets.
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
4
+ # URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
5
  # contributors. All rights reserved.
4
6
  #
5
7
  # Redistribution and use in source and binary forms, with or without modification,
@@ -73,13 +75,17 @@ class UrbanGeometryCreation < OpenStudio::Measure::ModelMeasure
73
75
  surrounding_buildings.setDescription('Select which surrounding buildings to include.')
74
76
  surrounding_buildings.setDefaultValue('ShadingOnly')
75
77
  args << surrounding_buildings
78
+ # not a required argument
79
+ scale_footprint_area_by_floor_area = OpenStudio::Ruleset::OSArgument.makeBoolArgument('scale_footprint_area_by_floor_area', false)
80
+ scale_footprint_area_by_floor_area.setDisplayName('Scale Footprint Area by the Floor Area?')
81
+ scale_footprint_area_by_floor_area.setDescription('If true, the footprint area from GeoJSON will be scaled by the floor_area provided by the user in URBANopt.')
82
+ scale_footprint_area_by_floor_area.setDefaultValue(false)
83
+ args << scale_footprint_area_by_floor_area
76
84
  return args
77
85
  end
78
86
 
79
87
  # define what happens when the measure is run
80
- # rubocop:disable Metrics/AbcSize
81
88
  def run(model, runner, user_arguments)
82
- # rubocop:enable Metrics/AbcSize
83
89
  super(model, runner, user_arguments)
84
90
  # use the built-in error checking
85
91
  if !runner.validateUserArguments(arguments(model), user_arguments)
@@ -90,6 +96,7 @@ class UrbanGeometryCreation < OpenStudio::Measure::ModelMeasure
90
96
  geojson_file = runner.getStringArgumentValue('geojson_file', user_arguments)
91
97
  feature_id = runner.getStringArgumentValue('feature_id', user_arguments)
92
98
  surrounding_buildings = runner.getStringArgumentValue('surrounding_buildings', user_arguments)
99
+ scale_footprint_area_by_floor_area = runner.getBoolArgumentValue('scale_footprint_area_by_floor_area', user_arguments)
93
100
 
94
101
  default_construction_set = URBANopt::GeoJSON::Model.create_construction_set(model, runner)
95
102
 
@@ -133,7 +140,17 @@ class UrbanGeometryCreation < OpenStudio::Measure::ModelMeasure
133
140
 
134
141
  if feature.type == 'Building'
135
142
  # make requested building
136
- spaces = feature.create_building(:space_per_floor, model, @origin_lat_lon, @runner)
143
+ # pass in scaled_footprint_area (calculated from floor_area / number_of_stories)
144
+ scaled_footprint_area = 0
145
+ if scale_footprint_area_by_floor_area
146
+ building_hash = feature.to_hash
147
+ if building_hash[:number_of_stories] && building_hash[:floor_area]
148
+ scaled_footprint_area = building_hash[:floor_area].to_f / building_hash[:number_of_stories].to_f
149
+ @runner.registerInfo("Desired footprint area in ft2: #{scaled_footprint_area}")
150
+ end
151
+ end
152
+
153
+ spaces = feature.create_building(:space_per_floor, model, @origin_lat_lon, @runner, false, scaled_footprint_area)
137
154
  if spaces.nil?
138
155
  @runner.registerError("Failed to create spaces for building '#{name}'")
139
156
  return false
@@ -1,9 +1,10 @@
1
+ <?xml version="1.0"?>
1
2
  <measure>
2
3
  <schema_version>3.0</schema_version>
3
4
  <name>urban_geometry_creation</name>
4
5
  <uid>5ab85d6b-c9af-4361-8ab9-613ee99a5666</uid>
5
- <version_id>cf023329-6ef3-43b3-a316-b08fabb47cd2</version_id>
6
- <version_modified>20200327T211951Z</version_modified>
6
+ <version_id>e32672b2-91b1-4b62-9770-7712cab86004</version_id>
7
+ <version_modified>20200807T210717Z</version_modified>
7
8
  <xml_checksum>D254E772</xml_checksum>
8
9
  <class_name>UrbanGeometryCreation</class_name>
9
10
  <display_name>UrbanGeometryCreation</display_name>
@@ -46,8 +47,8 @@
46
47
  </choices>
47
48
  </argument>
48
49
  </arguments>
49
- <outputs/>
50
- <provenances/>
50
+ <outputs />
51
+ <provenances />
51
52
  <tags>
52
53
  <tag>Envelope.Form</tag>
53
54
  </tags>
@@ -102,17 +103,23 @@
102
103
  <usage_type>test</usage_type>
103
104
  <checksum>40290298</checksum>
104
105
  </file>
106
+ <file>
107
+ <filename>README.md</filename>
108
+ <filetype>md</filetype>
109
+ <usage_type>readme</usage_type>
110
+ <checksum>A09F345D</checksum>
111
+ </file>
105
112
  <file>
106
113
  <filename>shadowed_tests.rb</filename>
107
114
  <filetype>rb</filetype>
108
115
  <usage_type>test</usage_type>
109
- <checksum>861137CF</checksum>
116
+ <checksum>4E51A05C</checksum>
110
117
  </file>
111
118
  <file>
112
119
  <filename>urban_geometry_creation_test.rb</filename>
113
120
  <filetype>rb</filetype>
114
121
  <usage_type>test</usage_type>
115
- <checksum>6DED5C96</checksum>
122
+ <checksum>DDAD6BFA</checksum>
116
123
  </file>
117
124
  <file>
118
125
  <version>
@@ -123,19 +130,7 @@
123
130
  <filename>measure.rb</filename>
124
131
  <filetype>rb</filetype>
125
132
  <usage_type>script</usage_type>
126
- <checksum>1A6BAAFA</checksum>
127
- </file>
128
- <file>
129
- <filename>out.txt</filename>
130
- <filetype>txt</filetype>
131
- <usage_type>test</usage_type>
132
- <checksum>C5B18B73</checksum>
133
- </file>
134
- <file>
135
- <filename>README.md</filename>
136
- <filetype>md</filetype>
137
- <usage_type>readme</usage_type>
138
- <checksum>A09F345D</checksum>
133
+ <checksum>2F8C09F7</checksum>
139
134
  </file>
140
135
  </files>
141
136
  </measure>
@@ -1,4 +1,4 @@
1
- URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
1
+ URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
2
  contributors. All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
@@ -5,7 +5,7 @@
5
5
  # UrbanGeometryCreationZoning
6
6
 
7
7
  ## Description
8
- This measure reads an URBANopt GeoJSON and creates geometry with zoning for a particular building. Surrounding buildings are included as shading structures.
8
+ This measure reads an URBANopt GeoJSON and creates geometry with zoning for a particular building. Surrounding buildings are included as shading structures.
9
9
 
10
10
  ## Modeler Description
11
11
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
4
+ # URBANopt™, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
5
  # contributors. All rights reserved.
4
6
  #
5
7
  # Redistribution and use in source and binary forms, with or without modification,
@@ -81,9 +83,7 @@ class UrbanGeometryCreationZoning < OpenStudio::Measure::ModelMeasure
81
83
  end
82
84
 
83
85
  # define what happens when the measure is run
84
- # rubocop:disable Metrics/AbcSize
85
86
  def run(model, runner, user_arguments)
86
- # rubocop:enable Metrics/AbcSize
87
87
  super(model, runner, user_arguments)
88
88
  # use the built-in error checking
89
89
  if !runner.validateUserArguments(arguments(model), user_arguments)
@@ -1,9 +1,10 @@
1
+ <?xml version="1.0"?>
1
2
  <measure>
2
3
  <schema_version>3.0</schema_version>
3
4
  <name>urban_geometry_creation_zoning</name>
4
5
  <uid>96ea1317-76ac-4670-b51d-71ee3f4fdd65</uid>
5
- <version_id>5109b19e-6300-4068-900e-8a989b9762c8</version_id>
6
- <version_modified>20200327T211951Z</version_modified>
6
+ <version_id>884d6eb0-6517-40dc-96ca-ac4db7c2ad7d</version_id>
7
+ <version_modified>20200807T210718Z</version_modified>
7
8
  <xml_checksum>D254E772</xml_checksum>
8
9
  <class_name>UrbanGeometryCreationZoning</class_name>
9
10
  <display_name>UrbanGeometryCreationZoning</display_name>
@@ -46,8 +47,8 @@
46
47
  </choices>
47
48
  </argument>
48
49
  </arguments>
49
- <outputs/>
50
- <provenances/>
50
+ <outputs />
51
+ <provenances />
51
52
  <tags>
52
53
  <tag>Envelope.Form</tag>
53
54
  </tags>
@@ -102,6 +103,12 @@
102
103
  <usage_type>license</usage_type>
103
104
  <checksum>EA283B74</checksum>
104
105
  </file>
106
+ <file>
107
+ <filename>README.md</filename>
108
+ <filetype>md</filetype>
109
+ <usage_type>readme</usage_type>
110
+ <checksum>0458EE16</checksum>
111
+ </file>
105
112
  <file>
106
113
  <version>
107
114
  <software_program>OpenStudio</software_program>
@@ -111,25 +118,13 @@
111
118
  <filename>measure.rb</filename>
112
119
  <filetype>rb</filetype>
113
120
  <usage_type>script</usage_type>
114
- <checksum>EF1B3E84</checksum>
115
- </file>
116
- <file>
117
- <filename>out.txt</filename>
118
- <filetype>txt</filetype>
119
- <usage_type>test</usage_type>
120
- <checksum>7FAF05F3</checksum>
121
+ <checksum>2505C43D</checksum>
121
122
  </file>
122
123
  <file>
123
124
  <filename>urban_geometry_creation_zoning_test.rb</filename>
124
125
  <filetype>rb</filetype>
125
126
  <usage_type>test</usage_type>
126
- <checksum>60BFE46B</checksum>
127
- </file>
128
- <file>
129
- <filename>README.md</filename>
130
- <filetype>md</filetype>
131
- <usage_type>readme</usage_type>
132
- <checksum>0458EE16</checksum>
127
+ <checksum>986CB63E</checksum>
133
128
  </file>
134
129
  </files>
135
130
  </measure>
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -39,3 +39,4 @@ require 'urbanopt/geojson/zoning'
39
39
  require 'urbanopt/geojson/model'
40
40
  require 'urbanopt/geojson/derived_extension'
41
41
  require 'urbanopt/geojson/logging'
42
+ require 'urbanopt/geojson/scale_area'
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -87,9 +87,11 @@ module URBANopt
87
87
  # * +origin_lat_lon+ - _Type:Float_ - An instance of +OpenStudio::PointLatLon+ indicating the latitude and longitude of the origin.
88
88
  # * +runner+ - _Type:String_ - An instance of +OpenStudio::Measure::OSRunner+ for the measure run.
89
89
  # * +zoning+ - _Type:Boolean_ - Value is +true+ if utilizing detailed zoning, else
90
- # +false+. Zoning is set to False by default.
90
+ # +false+ Zoning is set to False by default.
91
+ # * +scaled_footprint_area+ - Used to scale the footprint area using the floor area. 0 by
92
+ # default (no scaling).
91
93
  # * +other_building+ - _Type:URBANopt::GeoJSON::Feature - Optional, allow the user to pass in a different building to process. This is used for creating the other buildings for shading.
92
- def create_building(create_method, model, origin_lat_lon, runner, zoning = false, other_building = @feature_json)
94
+ def create_building(create_method, model, origin_lat_lon, runner, zoning = false, scaled_footprint_area = 0, other_building = @feature_json)
93
95
  number_of_stories = other_building[:properties][:number_of_stories]
94
96
  number_of_stories_above_ground = other_building[:properties][:number_of_stories_above_ground]
95
97
  number_of_stories_below_ground = other_building[:properties][:number_of_stories_below_ground]
@@ -128,7 +130,7 @@ module URBANopt
128
130
  spaces = []
129
131
  if create_method == :space_per_floor || create_method == :spaces_per_floor
130
132
  (-number_of_stories_below_ground + 1..number_of_stories_above_ground).each do |story_number|
131
- new_spaces = create_space_per_floor(story_number, floor_to_floor_height, model, origin_lat_lon, runner, zoning)
133
+ new_spaces = create_space_per_floor(story_number, floor_to_floor_height, model, origin_lat_lon, runner, zoning, scaled_footprint_area)
132
134
  spaces.concat(new_spaces)
133
135
  end
134
136
  elsif create_method == :space_per_building
@@ -248,9 +250,50 @@ module URBANopt
248
250
  end
249
251
 
250
252
  ##
251
- # Convert to a Hash equivalent for JSON serialization
253
+ # Used to calculate the perimeter from the floor polygon of a Feature. Returns the perimeter
254
+ # value.
255
+ #
256
+ # [Parameters]
257
+ # * +feature+ - An instance of URBANopt::GeoJSON::Feature
258
+ #
259
+ def calculate_perimeter(feature)
260
+ model = OpenStudio::Model::Model.new
261
+ runner = OpenStudio::Measure::OSRunner.new(OpenStudio::WorkflowJSON.new)
262
+ origin_lat_lon = nil
263
+ origin_lat_lon = feature.create_origin_lat_lon(runner)
264
+ spaces = feature.create_building(:space_per_building, model, origin_lat_lon, runner)
265
+ surfaces = spaces[0].surfaces
266
+ ground_surface = nil
267
+ surfaces.each do |surface|
268
+ boundary_condition = surface.outsideBoundaryCondition
269
+ if boundary_condition == 'Ground'
270
+ ground_surface = surface
271
+ end
272
+ end
273
+ vertices = ground_surface.vertices
274
+ n = vertices.size
275
+ perimeter = 0
276
+ for i in (0..n - 1) do i
277
+ vertex_1 = nil
278
+ vertex_2 = nil
279
+ if i == n - 1
280
+ vertex_1 = vertices[n - 1]
281
+ vertex_2 = vertices[0]
282
+ else
283
+ vertex_1 = vertices[i]
284
+ vertex_2 = vertices[i + 1]
285
+ end
286
+ length = OpenStudio::Vector3d.new(vertex_2 - vertex_1).length
287
+ perimeter += length
288
+ end
289
+ perimeter = OpenStudio.convert(perimeter, 'm', 'ft').get
290
+ perimeter = perimeter.round(4)
291
+ return perimeter
292
+ end
293
+
252
294
  ##
253
- # - Exclude attributes with nil values.
295
+ # Convert to a Hash equivalent for JSON serialization.
296
+ # Excludes attributes with nil value.
254
297
  ##
255
298
  def to_hash
256
299
  result = {}
@@ -354,10 +397,18 @@ module URBANopt
354
397
  # * +zoning+ - _Type:Boolean_ - Value is +true+ if utilizing detailed zoning, else
355
398
  # +false+. Zoning is set to False by default.
356
399
  # rubocop:disable Style/CommentedKeyword
357
- def create_space_per_floor(story_number, floor_to_floor_height, model, origin_lat_lon, runner, zoning = false) #:doc:
400
+ def create_space_per_floor(story_number, floor_to_floor_height, model, origin_lat_lon, runner, zoning = false, scaled_footprint_area) #:doc:
358
401
  # rubocop:enable Style/CommentedKeyword
359
- geometry = @feature_json[:geometry]
360
- properties = @feature_json[:properties]
402
+ begin
403
+ if other_building
404
+ geometry = other_building[:geometry]
405
+ properties = other_building[:properties]
406
+ else
407
+ geometry = @feature_json[:geometry]
408
+ properties = @feature_json[:properties]
409
+ end
410
+ rescue StandardError
411
+ end
361
412
  floor_prints = []
362
413
  multi_polygons = get_multi_polygons
363
414
  multi_polygons.each do |multi_polygon|
@@ -366,7 +417,7 @@ module URBANopt
366
417
  end
367
418
  multi_polygon.each do |polygon|
368
419
  elevation = (story_number - 1) * floor_to_floor_height
369
- floor_print = URBANopt::GeoJSON::Helper.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning)
420
+ floor_print = URBANopt::GeoJSON::Helper.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning, scaled_footprint_area)
370
421
  if floor_print
371
422
  if zoning
372
423
  this_floor_prints = URBANopt::GeoJSON::Zoning.divide_floor_print(floor_print, 4.0, runner)
@@ -402,6 +453,8 @@ module URBANopt
402
453
 
403
454
  building_story = OpenStudio::Model::BuildingStory.new(model)
404
455
  building_story.setName("Building Story #{story_number}")
456
+ building_story.setNominalZCoordinate(story_number * floor_to_floor_height)
457
+ building_story.setNominalFloortoFloorHeight(floor_to_floor_height)
405
458
  spaces.each do |space|
406
459
  space.setBuildingStory(building_story)
407
460
  thermal_zone = OpenStudio::Model::ThermalZone.new(model)
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -1,5 +1,5 @@
1
1
  # *********************************************************************************
2
- # URBANopt, Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
2
+ # URBANopt (tm), Copyright (c) 2019-2020, Alliance for Sustainable Energy, LLC, and other
3
3
  # contributors. All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without modification,
@@ -47,9 +47,8 @@ module URBANopt
47
47
  # rubocop:disable Style/MethodMissing
48
48
  def method_missing(name, *args, &blk)
49
49
  # rubocop:enable Style/MethodMissing
50
- # rubocop:disable Style/GuardClause
51
50
  if @feature_json[:properties].keys.map(&:to_sym).include? name.to_sym
52
- # rubocop:enable Style/GuardClause
51
+
53
52
  return @feature_json[:properties][name.to_sym]
54
53
  else
55
54
  super
@@ -99,6 +98,89 @@ module URBANopt
99
98
  return @@feature_schema[feature_type]
100
99
  end
101
100
 
101
+ ##
102
+ # Used to calculate the aspect ratio for a given floor polygon.
103
+ #
104
+ def calculate_aspect_ratio
105
+ multi_polygons = get_multi_polygons(@feature_json)
106
+ rad_per_deg = 0.017453293
107
+
108
+ multi_polygons.each do |multi_polygon|
109
+ if multi_polygon.size > 1
110
+ runner.registerWarning('Ignoring holes in polygon')
111
+ end
112
+ multi_polygon.each do |polygon|
113
+ n = polygon.size
114
+ length = 0
115
+ north = 0
116
+ east = 0
117
+ south = 0
118
+ west = 0
119
+ aspect_ratio = 0
120
+
121
+ for i in (0..n - 2) do i
122
+ vertex_1 = nil
123
+ vertex_2 = nil
124
+ if i == n - 2
125
+ vertex_1 = polygon[n - 2]
126
+ vertex_2 = polygon[0]
127
+ else
128
+ vertex_1 = polygon[i]
129
+ vertex_2 = polygon[i + 1]
130
+ end
131
+ x_1 = vertex_1[0]
132
+ y_1 = vertex_1[1]
133
+ x_2 = vertex_2[0]
134
+ y_2 = vertex_2[1]
135
+
136
+ dist = (x_2 - x_1)**2 + (y_2 - y_1)**2
137
+
138
+ length = Math.sqrt(dist)
139
+
140
+ # delta latitude
141
+ dlat = x_2 - x_1
142
+ # delta longitude
143
+ dlon = y_2 - y_1
144
+
145
+ # convert radian to degree
146
+ sin_angle = Math.asin(dlon / length) * (1 / rad_per_deg)
147
+ sin_angle = sin_angle.round(4)
148
+
149
+ cos_angle = Math.acos(dlat / length) * (1 / rad_per_deg)
150
+ cos_angle = cos_angle.round(4)
151
+
152
+ if cos_angle >= 45 && cos_angle <= 135 && sin_angle >= 45 && sin_angle <= 90
153
+ north += length
154
+ elsif cos_angle >= 0 && cos_angle < 45 && sin_angle > -45 && sin_angle < 45
155
+ east += length
156
+ elsif cos_angle >= 45 && cos_angle <= 135 && sin_angle >= -90 && sin_angle <= -45
157
+ south += length
158
+ elsif cos_angle > 135 && cos_angle <= 180 && sin_angle > -45 && sin_angle < 45
159
+ west += length
160
+ end
161
+
162
+ if east + west != 0
163
+ aspect_ratio = (north + south) / (east + west)
164
+ else
165
+ aspect_ratio = 1
166
+ end
167
+
168
+ end
169
+
170
+ aspect_ratio = aspect_ratio.round(4)
171
+ return aspect_ratio
172
+ end
173
+ end
174
+ end
175
+
176
+ ##
177
+ # Used to calculate the perimeter multiplier given the aspect ratio, original perimeter and area.
178
+ def get_perimeter_multiplier(area, aspect_ratio, perimeter_original)
179
+ perimeter_new = 2 * (Math.sqrt(area * aspect_ratio) + Math.sqrt(area / aspect_ratio))
180
+ perimeter_ratio = perimeter_original / perimeter_new
181
+ return perimeter_ratio
182
+ end
183
+
102
184
  ##
103
185
  # Returns coordinate with the minimum longitute and latitude within a given +building_json+ .
104
186
  def get_min_lon_lat
@@ -168,6 +250,38 @@ module URBANopt
168
250
  return OpenStudio::PointLatLon.new(min_lat, min_lon, 0)
169
251
  end
170
252
 
253
+ ##
254
+ # Used to determine the centroid for the feature's coordinates.
255
+ #
256
+ # [Parameters]
257
+ # * +vertices+ - The first set polygon vertices in the array of feature coordinates.
258
+ def find_feature_center(vertices)
259
+ number_of_locations = vertices.length
260
+
261
+ return vertices.first if number_of_locations == 1
262
+
263
+ x = y = z = 0.0
264
+ vertices.each do |station|
265
+ latitude = station[0] * Math::PI / 180
266
+ longitude = station[1] * Math::PI / 180
267
+
268
+ x += Math.cos(latitude) * Math.cos(longitude)
269
+ y += Math.cos(latitude) * Math.sin(longitude)
270
+ z += Math.sin(latitude)
271
+ end
272
+
273
+ x /= number_of_locations
274
+ y /= number_of_locations
275
+ z /= number_of_locations
276
+
277
+ central_longitude = Math.atan2(y, x)
278
+ central_square_root = Math.sqrt(x * x + y * y)
279
+ central_latitude = Math.atan2(z, central_square_root)
280
+
281
+ [central_latitude * 180 / Math::PI,
282
+ central_longitude * 180 / Math::PI]
283
+ end
284
+
171
285
  private
172
286
 
173
287
  ##