diff --git a/CHANGELOG.md b/CHANGELOG.md index 9379c26..10f4dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # URBANopt GeoJSON Gem +## Version 0.11.2 +* Allow null for some optional fields by @vtnate in https://github.com/urbanopt/urbanopt-geojson-gem/pull/273 +* Added UO-ResStock connection variable to the site properties schema by @rawadelkontar in https://github.com/urbanopt/urbanopt-geojson-gem/pull/270 + + +**Full Changelog**: https://github.com/urbanopt/urbanopt-geojson-gem/compare/v0.11.1...v0.11.2 + ## Version 0.11.1 Date Range: 01/09/24 diff --git a/LICENSE.md b/LICENSE.md index ff1cffc..30c4553 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -URBANopt (tm), Copyright (c) 2019-2023, Alliance for Sustainable Energy, LLC, and other +URBANopt (tm), Copyright (c) 2019-2024, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/lib/measures/urban_geometry_creation/LICENSE.md b/lib/measures/urban_geometry_creation/LICENSE.md index ff1cffc..30c4553 100644 --- a/lib/measures/urban_geometry_creation/LICENSE.md +++ b/lib/measures/urban_geometry_creation/LICENSE.md @@ -1,4 +1,4 @@ -URBANopt (tm), Copyright (c) 2019-2023, Alliance for Sustainable Energy, LLC, and other +URBANopt (tm), Copyright (c) 2019-2024, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/lib/measures/urban_geometry_creation/measure.rb b/lib/measures/urban_geometry_creation/measure.rb index 2df83b5..a6f9cf8 100644 --- a/lib/measures/urban_geometry_creation/measure.rb +++ b/lib/measures/urban_geometry_creation/measure.rb @@ -121,7 +121,7 @@ def run(model, runner, user_arguments) if scale_footprint_area_by_floor_area building_hash = feature.to_hash if building_hash[:number_of_stories] && building_hash[:floor_area] - scaled_footprint_area = building_hash[:floor_area].to_f / building_hash[:number_of_stories].to_f + scaled_footprint_area = building_hash[:floor_area].to_f / building_hash[:number_of_stories] @runner.registerInfo("Desired footprint area in ft2: #{scaled_footprint_area}") end end diff --git a/lib/measures/urban_geometry_creation/measure.xml b/lib/measures/urban_geometry_creation/measure.xml index c7aa7cd..c7dea7e 100644 --- a/lib/measures/urban_geometry_creation/measure.xml +++ b/lib/measures/urban_geometry_creation/measure.xml @@ -3,8 +3,8 @@ 3.1 urban_geometry_creation 5ab85d6b-c9af-4361-8ab9-613ee99a5666 - 583499fb-4275-4787-9168-e3383dca0fc6 - 2023-11-20T17:10:01Z + 114e5a3f-0e66-47f2-aa96-299f71b4ef0f + 2024-06-25T21:15:26Z D254E772 UrbanGeometryCreation UrbanGeometryCreation @@ -108,7 +108,7 @@ LICENSE.md md license - 9A4578CE + 3C275955 README.md diff --git a/lib/measures/urban_geometry_creation_zoning/LICENSE.md b/lib/measures/urban_geometry_creation_zoning/LICENSE.md index ff1cffc..30c4553 100644 --- a/lib/measures/urban_geometry_creation_zoning/LICENSE.md +++ b/lib/measures/urban_geometry_creation_zoning/LICENSE.md @@ -1,4 +1,4 @@ -URBANopt (tm), Copyright (c) 2019-2023, Alliance for Sustainable Energy, LLC, and other +URBANopt (tm), Copyright (c) 2019-2024, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/lib/measures/urban_geometry_creation_zoning/measure.rb b/lib/measures/urban_geometry_creation_zoning/measure.rb index 7748237..4679ba3 100644 --- a/lib/measures/urban_geometry_creation_zoning/measure.rb +++ b/lib/measures/urban_geometry_creation_zoning/measure.rb @@ -110,7 +110,8 @@ def run(model, runner, user_arguments) @runner.registerWarning("Surface elevation not set for building '#{name}'") end - if feature.type == 'Building' + case feature.type + when 'Building' # make requested building, zoning is set to true spaces = feature.create_building(:spaces_per_floor, model, @origin_lat_lon, @runner, true) if spaces.nil? || spaces.empty? @@ -157,7 +158,7 @@ def run(model, runner, user_arguments) URBANopt::GeoJSON::Helper.convert_to_shading_surface_group(space) end - elsif feature.type == 'District System' + when 'District System' district_system_type = feature[:properties][:district_system_type] if district_system_type == 'Community Photovoltaic' shading_surfaces = URBANopt::GeoJSON::Helper.create_photovoltaics(feature, 0, model, @origin_lat_lon, @runner) diff --git a/lib/measures/urban_geometry_creation_zoning/measure.xml b/lib/measures/urban_geometry_creation_zoning/measure.xml index 287ed9d..9476c7e 100644 --- a/lib/measures/urban_geometry_creation_zoning/measure.xml +++ b/lib/measures/urban_geometry_creation_zoning/measure.xml @@ -3,8 +3,8 @@ 3.1 urban_geometry_creation_zoning 96ea1317-76ac-4670-b51d-71ee3f4fdd65 - 4d47bb3f-6e49-4309-a4e0-5f2c3748b947 - 2023-11-20T17:10:01Z + 8b2f1d05-725a-4f06-bcac-1fb685f12f89 + 2024-06-25T21:15:28Z D254E772 UrbanGeometryCreationZoning UrbanGeometryCreationZoning @@ -89,7 +89,7 @@ LICENSE.md md license - 9A4578CE + 3C275955 README.md diff --git a/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_zoning_test.rb b/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_zoning_test.rb index 0686ee7..59600fd 100644 --- a/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_zoning_test.rb +++ b/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_zoning_test.rb @@ -8,7 +8,7 @@ require 'openstudio' require 'openstudio/ruleset/ShowRunnerOutput' require 'minitest/autorun' -require_relative '../measure.rb' +require_relative '../measure' require 'fileutils' class UrbanGeometryCreationZoningTest < MiniTest::Test diff --git a/lib/urbanopt/geojson/building.rb b/lib/urbanopt/geojson/building.rb index f1dcf8b..b879d21 100644 --- a/lib/urbanopt/geojson/building.rb +++ b/lib/urbanopt/geojson/building.rb @@ -103,12 +103,13 @@ def create_building(create_method, model, origin_lat_lon, runner, zoning = false end spaces = [] - if create_method == :space_per_floor || create_method == :spaces_per_floor + case create_method + when :space_per_floor, :spaces_per_floor (-number_of_stories_below_ground + 1..number_of_stories_above_ground).each do |story_number| new_spaces = create_space_per_floor(story_number, floor_to_floor_height, model, origin_lat_lon, runner, zoning, scaled_footprint_area) spaces.concat(new_spaces) end - elsif create_method == :space_per_building + when :space_per_building spaces = create_space_per_building(-number_of_stories_below_ground * floor_to_floor_height, number_of_stories_above_ground * floor_to_floor_height, model, origin_lat_lon, runner, zoning, other_building) end return spaces @@ -417,10 +418,8 @@ def create_space_per_floor(story_number, floor_to_floor_height, model, origin_la space = space.get space.setName("Building Story #{story_number} Space") space.surfaces.each do |surface| - if surface.surfaceType == 'Wall' - if story_number < 1 - surface.setOutsideBoundaryCondition('Ground') - end + if surface.surfaceType == 'Wall' && (story_number < 1) + surface.setOutsideBoundaryCondition('Ground') end end spaces << space diff --git a/lib/urbanopt/geojson/district_system.rb b/lib/urbanopt/geojson/district_system.rb index ac4e8b2..a285422 100644 --- a/lib/urbanopt/geojson/district_system.rb +++ b/lib/urbanopt/geojson/district_system.rb @@ -8,10 +8,6 @@ module URBANopt module GeoJSON # :nodoc: all class DistrictSystem < Feature - def initialize(feature) - super(feature) - end - ## # Used to describe the feature type using the base method from the Feature class. def feature_type diff --git a/lib/urbanopt/geojson/feature.rb b/lib/urbanopt/geojson/feature.rb index 484f912..f7fcc3e 100644 --- a/lib/urbanopt/geojson/feature.rb +++ b/lib/urbanopt/geojson/feature.rb @@ -19,9 +19,7 @@ def initialize(feature) @feature_json = validate_feat(feature) end - # rubocop:disable Style/MethodMissing def method_missing(name, *args, &blk) - # rubocop:enable Style/MethodMissing if @feature_json[:properties].keys.map(&:to_sym).include? name.to_sym return @feature_json[:properties][name.to_sym] @@ -196,10 +194,11 @@ def get_min_lon_lat def get_multi_polygons(json = @feature_json) geometry_type = json[:geometry][:type] multi_polygons = [] - if geometry_type == 'Polygon' + case geometry_type + when 'Polygon' polygons = json[:geometry][:coordinates] multi_polygons = [polygons] - elsif geometry_type == 'MultiPolygon' + when 'MultiPolygon' multi_polygons = json[:geometry][:coordinates] end return multi_polygons @@ -256,8 +255,7 @@ def find_feature_center(vertices) central_latitude = Math.atan2(z, central_square_root) [central_longitude * 180 / Math::PI, - central_latitude * 180 / Math::PI] - + central_latitude * 180 / Math::PI] end private @@ -292,8 +290,9 @@ def validate_feat(feature) #:doc: end geometry_type = feature[:geometry][:type] - if geometry_type == 'Polygon' - elsif geometry_type == 'MultiPolygon' + case geometry_type + when 'Polygon' + when 'MultiPolygon' else raise("Unknown geometry type '#{geometry_type}'") return false diff --git a/lib/urbanopt/geojson/geo_file.rb b/lib/urbanopt/geojson/geo_file.rb index f5b9e22..72a067e 100644 --- a/lib/urbanopt/geojson/geo_file.rb +++ b/lib/urbanopt/geojson/geo_file.rb @@ -47,7 +47,6 @@ def self.from_file(path) symbolize_names: true ) - # validate geojson file against schema geojson_errors = validate(@@geojson_schema, geojson_file) unless geojson_errors.empty? @@ -83,6 +82,7 @@ def self.from_file(path) if feature[:properties][:name].nil? raise('No name found for Building Feature') end + if feature[:properties][:number_of_stories].nil? @@logger.warn("Number of stories is required to calculate shading using the UrbanGeometryCreation measure.\n" \ "Not validating #{feature[:properties][:id]} against schema and ignoring in shading calculations") @@ -96,6 +96,7 @@ def self.from_file(path) if feature[:properties][:name].nil? raise('No name found for Building Feature') end + @@logger.warn("OS-HPXML files may not conform to schema, which is usually ok.\n" \ "Not validating #{feature[:properties][:id]} against schema") # Else validate for all required properties in the schema @@ -203,12 +204,10 @@ def merge_site_properties(feature) ] add_props.each do |prop| - if project.key?(prop[:site]) && project[prop[:site]] - # property exists in site - if !feature[:properties].key?(prop[:feature]) || feature[:properties][prop[:feature]].nil? || feature[:properties][prop[:feature]].to_s.empty? - # property does not exist in feature or is nil: add site property (don't overwrite) - feature[:properties][prop[:feature]] = project[prop[:site]] - end + # property exists in site + if project.key?(prop[:site]) && project[prop[:site]] && (!feature[:properties].key?(prop[:feature]) || feature[:properties][prop[:feature]].nil? || feature[:properties][prop[:feature]].to_s.empty?) + # property does not exist in feature or is nil: add site property (don't overwrite) + feature[:properties][prop[:feature]] = project[prop[:site]] end end @@ -229,7 +228,7 @@ def self.get_geojson_schema(strict) result = nil if @@geojson_schema.nil? @@schema_file_lock.synchronize do - File.open(File.dirname(__FILE__) + '/schema/geojson_schema.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/geojson_schema.json") do |f| result = JSON.parse(f.read, symbolize_names: true) end end @@ -239,7 +238,7 @@ def self.get_geojson_schema(strict) def self.get_building_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/building_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/building_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -252,7 +251,7 @@ def self.get_building_schema(strict) def self.get_district_system_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/district_system_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/district_system_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -265,7 +264,7 @@ def self.get_district_system_schema(strict) def self.get_region_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/region_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/region_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -278,7 +277,7 @@ def self.get_region_schema(strict) def self.get_site_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/site_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/site_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -291,7 +290,7 @@ def self.get_site_schema(strict) def self.get_electrical_connector_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/electrical_connector_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/electrical_connector_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -304,7 +303,7 @@ def self.get_electrical_connector_schema(strict) def self.get_electrical_junction_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/electrical_junction_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/electrical_junction_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -317,7 +316,7 @@ def self.get_electrical_junction_schema(strict) def self.get_thermal_connector_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/thermal_connector_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/thermal_connector_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -330,7 +329,7 @@ def self.get_thermal_connector_schema(strict) def self.get_thermal_junction_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/schema/thermal_junction_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/schema/thermal_junction_properties.json") do |f| result = JSON.parse(f.read) end if strict diff --git a/lib/urbanopt/geojson/helper.rb b/lib/urbanopt/geojson/helper.rb index 4e4212a..0bf8e64 100644 --- a/lib/urbanopt/geojson/helper.rb +++ b/lib/urbanopt/geojson/helper.rb @@ -242,6 +242,7 @@ def self.process_other_buildings(building, other_building_type, other_buildings, other_buildings[:features].each do |other_building| other_id = other_building[:properties][:id] next if other_id == building.id + # Consider building, if other building type is ShadingOnly and other id is not equal to building id if other_building_type == 'ShadingOnly' && other_id != building.id # Checks if any building point is shaded by any other building point. @@ -277,6 +278,7 @@ def self.process_other_buildings(building, other_building_type, other_buildings, runner.registerInfo("Feature #{other_building[:properties][:id]} is acting as shading object for #{building.id}") end next unless shadowed + new_building = building.create_other_building(:space_per_building, model, origin_lat_lon, runner, zoning, 0, other_building) if new_building.nil? || new_building.empty? runner.registerWarning("Failed to create spaces for other building '#{name}'") @@ -321,6 +323,7 @@ def self.is_shadowed(potentially_shaded, potential_shader, origin_lat_lon) if is_shaded(min_pair[:building_point], min_pair[:other_building_point], origin_lat_lon) return true end + return false end @@ -339,7 +342,8 @@ def self.is_shaded(building_point, other_building_point, origin_lat_lon) if distance < 1 return true end - elevation_angle = 2.5 #not sure of best value maybe allow as project level argument + + elevation_angle = 2.5 # not sure of best value maybe allow as project level argument height = vector.z apparent_angle_rad = Math.atan2(height, distance) apparent_angle = OpenStudio.radToDeg(apparent_angle_rad) @@ -351,9 +355,9 @@ def self.is_shaded(building_point, other_building_point, origin_lat_lon) return result end - class << self - private :is_shaded - end - end - end + class << self + private :is_shaded end + end + end +end diff --git a/lib/urbanopt/geojson/logging.rb b/lib/urbanopt/geojson/logging.rb index 209f035..0cbdeed 100644 --- a/lib/urbanopt/geojson/logging.rb +++ b/lib/urbanopt/geojson/logging.rb @@ -7,7 +7,7 @@ module URBANopt module GeoJSON - @@logger = Logger.new(STDERR) + @@logger = Logger.new($stderr) @@logger.progname = 'URBANopt::GeoJSON' def self.logger diff --git a/lib/urbanopt/geojson/mapper_classes.rb b/lib/urbanopt/geojson/mapper_classes.rb index 5addf53..08dddc7 100644 --- a/lib/urbanopt/geojson/mapper_classes.rb +++ b/lib/urbanopt/geojson/mapper_classes.rb @@ -46,15 +46,16 @@ def create_osw(scenario, feature_id, feature_name) feature_file = scenario.feature_file feature = feature_file.get_feature_by_id(feature_id) raise "Cannot find feature '#{feature_id}' in '#{scenario.geometry_file}'" if feature.nil? + # deep clone of @@osw before we configure it #:nodoc: osw = Marshal.load(Marshal.dump(@@osw)) osw[:name] = feature_name osw[:description] = feature_name - end + end # rubocop:disable Lint/ReturnInVoidContext return osw - # rubocop:enable Lint/ReturnInVoidContext - end + # rubocop:enable Lint/ReturnInVoidContext + end end end end diff --git a/lib/urbanopt/geojson/model.rb b/lib/urbanopt/geojson/model.rb index 9c15a39..6a71e16 100644 --- a/lib/urbanopt/geojson/model.rb +++ b/lib/urbanopt/geojson/model.rb @@ -75,6 +75,7 @@ def self.transfer_prev_model_data(model, space_types) stories.each_index do |i| space_type = space_types[i] next if space_type.nil? + stories[i].spaces.each do |space| space.setSpaceType(space_type) end diff --git a/lib/urbanopt/geojson/region.rb b/lib/urbanopt/geojson/region.rb index 46e8712..c154985 100644 --- a/lib/urbanopt/geojson/region.rb +++ b/lib/urbanopt/geojson/region.rb @@ -10,9 +10,6 @@ module GeoJSON class Region < Feature ## # Used to initialize the feature. This method is inherited from the Feature class. - def initialize(feature) - super(feature) - end ## # Used to describe the Region feature type using the base method from the Feature class. diff --git a/lib/urbanopt/geojson/scale_area.rb b/lib/urbanopt/geojson/scale_area.rb index c337198..efc240b 100644 --- a/lib/urbanopt/geojson/scale_area.rb +++ b/lib/urbanopt/geojson/scale_area.rb @@ -30,6 +30,7 @@ def initialize(vertices, desired_area, runner, eps) @vertices = vertices @centroid = OpenStudio.getCentroid(vertices) raise "Cannot compute centroid for '#{vertices}'" if @centroid.empty? + @centroid = @centroid.get @desired_area = desired_area @new_vertices = vertices @@ -41,15 +42,7 @@ def initialize(vertices, desired_area, runner, eps) @eps = eps end - attr_reader :zero - - attr_reader :one - - attr_reader :two - - attr_reader :ten - - attr_reader :eps + attr_reader :zero, :one, :two, :ten, :eps, :new_vertices ## # Used to determine new scaled vertices, by iteratively passing in the perimeter distance to @@ -59,12 +52,11 @@ def values(x) @new_vertices = URBANopt::GeoJSON::Zoning.divide_floor_print(@vertices, x[0].to_f, @runner, scale = true) new_area = OpenStudio.getArea(@new_vertices) raise "Cannot compute area for '#{@new_vertices}'" if new_area.empty? + new_area = new_area.get return [new_area - @desired_area] end - - attr_reader :new_vertices - end # ScaleArea - end # GeoJSON -end # URBANopt + end + end +end diff --git a/lib/urbanopt/geojson/update_areas.rb b/lib/urbanopt/geojson/update_areas.rb index 6e6ceb5..ff78a58 100644 --- a/lib/urbanopt/geojson/update_areas.rb +++ b/lib/urbanopt/geojson/update_areas.rb @@ -25,10 +25,11 @@ # end multi_polygons = nil - if geometry[:type] == 'Polygon' + case geometry[:type] + when 'Polygon' polygons = geometry[:coordinates] multi_polygons = [polygons] - elsif geometry[:type] == 'MultiPolygon' + when 'MultiPolygon' multi_polygons = geometry[:coordinates] end diff --git a/lib/urbanopt/geojson/validate_geojson.rb b/lib/urbanopt/geojson/validate_geojson.rb index 0a79984..fbababd 100644 --- a/lib/urbanopt/geojson/validate_geojson.rb +++ b/lib/urbanopt/geojson/validate_geojson.rb @@ -8,7 +8,7 @@ def get_building_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/../schema/building_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/../schema/building_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -21,7 +21,7 @@ def get_building_schema(strict) def get_taxlot_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/../schema/taxlot_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/../schema/taxlot_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -34,7 +34,7 @@ def get_taxlot_schema(strict) def get_district_system_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/../schema/district_system_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/../schema/district_system_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -47,7 +47,7 @@ def get_district_system_schema(strict) def get_region_schema(strict) result = nil - File.open(File.dirname(__FILE__) + '/../schema/region_properties.json') do |f| + File.open("#{File.dirname(__FILE__)}/../schema/region_properties.json") do |f| result = JSON.parse(f.read) end if strict @@ -95,13 +95,14 @@ def validate(schema, data) type = data['type'] errors = [] - if /building/i.match(type) + case type + when /building/i errors = validate(building_schema, data) - elsif /district system/i.match(type) + when /district system/i errors = validate(district_system_schema, data) - elsif /taxlot/i.match(type) + when /taxlot/i errors = validate(taxlot_schema, data) - elsif /region/i.match(type) + when /region/i errors = validate(region_schema, data) else raise("Unknown type: '#{type}'") diff --git a/lib/urbanopt/geojson/version.rb b/lib/urbanopt/geojson/version.rb index e3a2f33..526b834 100644 --- a/lib/urbanopt/geojson/version.rb +++ b/lib/urbanopt/geojson/version.rb @@ -5,6 +5,6 @@ module URBANopt module GeoJSON - VERSION = '0.11.1'.freeze + VERSION = '0.11.2'.freeze end end diff --git a/lib/urbanopt/geojson/zoning.rb b/lib/urbanopt/geojson/zoning.rb index 268da19..c8e0162 100644 --- a/lib/urbanopt/geojson/zoning.rb +++ b/lib/urbanopt/geojson/zoning.rb @@ -28,11 +28,12 @@ def self.divide_floor_print(floor_print, perimeter_depth, runner, scale = false) vertex_1 = nil vertex_2 = nil vertex_3 = nil - if i == 0 + case i + when 0 vertex_1 = vertices[n - 1] vertex_2 = vertices[i] vertex_3 = vertices[i + 1] - elsif i == (n - 1) + when n - 1 vertex_1 = vertices[i - 1] vertex_2 = vertices[i] vertex_3 = vertices[0]