from math import pi, cos, sin import unittest from unittest.mock import MagicMock from nose.tools import eq_ from helix.Services.dxf_helper import DXFHelper from helix.constants.module_type_constants.dual_tilt_96_cell_constants import DualTilt96CellConstants from helix.constants.panel_type import PanelType from helix.constants.system_type import SystemType from helix.models.coordinate import Coordinate from helix.models.dxf.dxf_error import DXFError from helix.models.dxf.graph_direction import GraphDirection from helix.models.dxf.graph_node import GraphNode from helix.models.dxf.polygon import Polygon from helix.models.panel import Panel from helix.models.subarray import Subarray class DXFHelperTest(unittest.TestCase): def setUp(self): self.subject = DXFHelper() def test_generate_panels(self): modules = [ Polygon(points=[(-2319.403, 687.080), (-2367.852, 648.146), (-2397.356, 684.863), (-2348.907, 723.792)]), Polygon(points=[(-2270.9747, 726.000), (-2319.419, 687.063), (-2348.923, 723.780), (-2300.478, 762.709)]) ] translated_modules = [ Polygon(points=[(77.953, 38.933), (29.504, 0.0), (0.0, 36.717), (48.449, 75.646)]), Polygon(points=[(126.382, 77.850), (77.937, 38.917), (48.433, 75.634), (96.878, 114.563)]) ] panels = self.subject.generate_panels(modules, translated_modules) expected = [ Panel(id=1, coordinate=Coordinate(38.977, 37.824, 38.78204144530477), original_coordinate=Coordinate(-2358.3795, 685.970, 38.78204144530477)), Panel(id=2, coordinate=Coordinate(87.407, 76.741, 38.78435126730565), original_coordinate=Coordinate(-2309.949, 724.888, 38.78435126730565)) ] eq_(panels, expected) def test_should_consolidate_modules_returns_false_for_single_tilt(self): eq_(self.subject.should_consolidate_modules(None, SystemType.singleTilt, None), False) def test_should_consolidate_modules_returns_true_for_dual_tilt_that_are_not_consolidated(self): modules = [ Polygon(points=[(-5.17655, -38.8958), (-7.73719, -34.4719), (-4.81221, -32.7789), (-2.25157, -37.2028)]), Polygon(points=[(-2.25157, -37.2028), (-5.17655, -38.8958), (1.04417, -35.2963), (-1.88081, -36.9894)]), ] eq_(self.subject.should_consolidate_modules(modules, SystemType.dualTilt, DualTilt96CellConstants()), True) def test_should_consolidate_modules_returns_false_for_dual_tilt_that_are_consolidated(self): modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (103.732, 38.937), (55.28, 0.0)]), ] eq_(self.subject.should_consolidate_modules(modules, SystemType.dualTilt, DualTilt96CellConstants()), False) def test_consolidate_dual_tilt_modules(self): modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (76.091, 73.338), (27.634, 34.401)]), Polygon(points=[(103.732, 38.937), (55.28, 0.0), (27.642, 34.393), (76.098, 73.331)]), ] expected_modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (103.732, 38.937), (55.28, 0.0)]), ] module_format = None panels = self.subject.consolidate_dual_tilt_modules(modules, SystemType.dualTilt, module_format) eq_(panels, expected_modules) def test_consolidate_dual_tilt_modules_does_nothing_if_given_single_tilt_modules(self): modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (76.091, 73.338), (27.634, 34.401)]), Polygon(points=[(103.732, 38.937), (55.28, 0.0), (27.642, 34.393), (76.098, 73.331)]), ] expected_modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (76.091, 73.338), (27.634, 34.401)]), Polygon(points=[(103.732, 38.937), (55.28, 0.0), (27.642, 34.393), (76.098, 73.331)]), ] module_format = None panels = self.subject.consolidate_dual_tilt_modules(modules, SystemType.singleTilt, module_format) eq_(panels, expected_modules) def test_consolidates_dual_tilt_modules_throws_if_given_dual_tilt_but_unpairable_modules(self): modules = [ Polygon(points=[(0.0, 68.795), (48.453, 107.732), (76.091, 73.338), (27.634, 34.401)]), Polygon(points=[(1103.732, 38.937), (155.28, 0.0), (127.642, 34.393), (176.098, 73.331)]), ] try: module_format = None self.subject.consolidate_dual_tilt_modules(modules, SystemType.dualTilt, module_format) assert False except DXFError as error: eq_(error.message, "Error - not a dual tilt file, or invalid dual tilt design.") def test_generate_polygons(self): lines = [ MagicMock(start=(-589.128, 174.518), end=(-601.434, 164.629)), MagicMock(start=(-601.434, 164.629), end=(-608.928, 173.955)), MagicMock(start=(-608.928, 173.955), end=(-596.622, 183.843)), MagicMock(start=(-596.622, 183.843), end=(-589.128, 174.518)) ] polygons = self.subject.generate_polygons(lines) expected = [Polygon(points=[(-589.128, 174.518), (-601.434, 164.629), (-608.928, 173.955), (-596.622, 183.843)])] eq_(polygons, expected) def test_generate_polygons_seperate_point(self): lines = [ MagicMock(start=(-589.128, 174.518), end=(-601.434, 164.629)), MagicMock(start=(-601.434, 164.629), end=(-608.928, 173.955)), MagicMock(start=(1, 2), end=(3, 4)), MagicMock(start=(-608.928, 173.955), end=(-596.622, 183.843)), MagicMock(start=(-596.622, 183.843), end=(-589.128, 174.518)) ] polygons = self.subject.generate_polygons(lines) expected = [ Polygon(points=[(-589.128, 174.518), (-601.434, 164.629), (-608.928, 173.955)]), Polygon(points=[(1, 2), (3, 4)]), Polygon(points=[(-608.928, 173.955), (-596.622, 183.843), (-589.128, 174.518)]) ] eq_(polygons, expected) def test_build_polygons(self): entities = [ MagicMock(layer='Modules', start=(-589.128, 174.518), end=(-601.434, 164.629)), MagicMock(layer='Modules', start=(-601.434, 164.629), end=(-608.928, 173.955)), MagicMock(layer='Modules', start=(-608.928, 173.955), end=(-596.622, 183.843)), MagicMock(layer='Modules', start=(-596.622, 183.843), end=(-589.128, 174.518)), MagicMock(layer='Buildings', start=(-576.827, 184.403), end=(-589.132, 174.514)), MagicMock(layer='Buildings', start=(-589.132, 174.514), end=(-596.626, 183.84)), MagicMock(layer='Buildings', start=(-596.626, 183.84), end=(-584.321, 193.728)), MagicMock(layer='Buildings', start=(-584.321, 193.728), end=(-576.827, 184.403)), ] polygons = self.subject.build_polygons(entities) inches_per_feet = 12 buildings = [Polygon(points=[(inches_per_feet * -576.827, inches_per_feet * 184.403), (inches_per_feet * -589.132, inches_per_feet * 174.514), (inches_per_feet * -596.626, inches_per_feet * 183.84), (inches_per_feet * -584.321, inches_per_feet * 193.728)])] modules = [Polygon(points=[(inches_per_feet * -589.128, inches_per_feet * 174.518), (inches_per_feet * -601.434, inches_per_feet * 164.629), (inches_per_feet * -608.928, inches_per_feet * 173.955), (inches_per_feet * -596.622, inches_per_feet * 183.843)])] expected = (buildings, modules) eq_(polygons, expected) def test_translate_towards_origin(self): buildings = [Polygon(points=[(-576.827, 184.403), (-589.132, 174.514), (-596.626, 183.84), (-584.321, 193.728)])] modules = [Polygon(points=[(-589.128, 174.518), (-601.434, 164.629), (-608.928, 173.955), (-596.622, 183.843)])] expected_buildings = [Polygon(points=[(32.101, 19.774), (19.796, 9.885), (12.302, 19.211), (24.607, 29.099)])] expected_modules = [Polygon(points=[(19.8, 9.889), (7.494, 0), (0, 9.326), (12.306, 19.214)])] eq_(self.subject.translate_towards_origin(buildings, modules), (expected_buildings, expected_modules)) def test_get_polygons_counterclockwise(self): polygons = [Polygon(points=[(0, 0), (0, 1), (1, 1), (1, 0)]), Polygon(points=[(0, 0), (0, 2), (2, 2), (2, 0)]), Polygon(points=[(0, 0), (2, 0), (2, 2), (0, 2)])] expected_polygons = [Polygon(points=[(1, 0), (1, 1), (0, 1), (0, 0)]), Polygon(points=[(2, 0), (2, 2), (0, 2), (0, 0)]), Polygon(points=[(0, 0), (2, 0), (2, 2), (0, 2)])] eq_(self.subject.get_polygons_counterclockwise(polygons), expected_polygons) def test_build_node_graph(self): panels = [ Panel(coordinate=Coordinate(10, 0, rotation=0)), Panel(coordinate=Coordinate(20, 0, rotation=0)), Panel(coordinate=Coordinate(10, 20, rotation=0)), Panel(coordinate=Coordinate(20, 20, rotation=0)) ] node_graph = self.subject.build_node_graph(panels, (10, 10)) node_a = GraphNode(Panel(coordinate=Coordinate(10, 0, rotation=0)), 10, 10) node_b = GraphNode(Panel(coordinate=Coordinate(20, 0, rotation=0)), 10, 10) node_c = GraphNode(Panel(coordinate=Coordinate(10, 20, rotation=0)), 10, 10) node_d = GraphNode(Panel(coordinate=Coordinate(20, 20, rotation=0)), 10, 10) node_a.add_neighbor(node_b, GraphDirection.East) node_c.add_neighbor(node_d, GraphDirection.East) expected = [node_a, node_b, node_c, node_d] eq_(node_graph, expected) def test_build_node_graph_weird_case(self): panels = [ Panel(coordinate=Coordinate(38.04431188249998, 857.508730771, -51.21962134154259)), Panel(coordinate=Coordinate(86.50299946749976, 896.449696681, -51.21563589970276)) ] node_graph = self.subject.build_node_graph(panels, (88.24, 62.16)) node_a = GraphNode(Panel(coordinate=Coordinate(38.04431188249998, 857.508730771, -51.21962134154259)), 88.24, 62.16) node_b = GraphNode(Panel(coordinate=Coordinate(86.50299946749976, 896.449696681, -51.21563589970276)), 88.24, 62.16) node_a.add_neighbor(node_b, GraphDirection.North) eq_(node_graph, [node_a, node_b]) def test_build_node_graph_throws_dxf_validation_error_if_there_are_panels_with_no_neighbors(self): panels = [ Panel(coordinate=Coordinate(10, 0, rotation=0)), Panel(coordinate=Coordinate(20, 0, rotation=0)), Panel(coordinate=Coordinate(100, 200, rotation=0)) ] try: self.subject.build_node_graph(panels, (10, 10)) assert False except DXFError as error: eq_(error.message, "Error - invalid module spacing. Please check to make sure the correct system type and panel spacing are present") def test_detect_subarrays(self): node_a = GraphNode(Panel(coordinate=Coordinate(1, 0, rotation=0)), 1, 1) node_b = GraphNode(Panel(coordinate=Coordinate(2, 0, rotation=0)), 1, 1) node_c = GraphNode(Panel(coordinate=Coordinate(1, 2, rotation=0)), 1, 1) node_a.add_neighbor(node_b, GraphDirection.East) nodes = [node_a, node_b, node_c] panels = [node.panel for node in nodes] subarrays = self.subject.detect_subarrays(nodes, panels) expected = [ Subarray(subarray_number=1, start_row=0, size=2), Subarray(subarray_number=2, start_row=2, size=1) ] eq_(subarrays, expected) def test_throws_dxf_validation_error_if_blows_stack_during_subarray_detection(self): nodes = [] for i in range(3000): nodes.append(GraphNode(Panel(coordinate=Coordinate(i, 0)), i, 0)) for i in range(1, 3000): node_a = nodes[i - 1] node = nodes[i] node.add_neighbor(node_a, GraphDirection.East) panels = [node.panel for node in nodes] try: subarrays = self.subject.detect_subarrays(nodes, panels) eq_(len(subarrays), 0) except DXFError as error: eq_(error.message, "Array size is too big. Max is 150' by 150'.") def test_detect_panel_types(self): node_0_0 = GraphNode(Panel(coordinate=Coordinate(0, 0, rotation=0)), 1, 1) node_1_0 = GraphNode(Panel(coordinate=Coordinate(1, 0, rotation=0)), 1, 1) node_2_0 = GraphNode(Panel(coordinate=Coordinate(2, 0, rotation=0)), 1, 1) node_3_0 = GraphNode(Panel(coordinate=Coordinate(3, 0, rotation=0)), 1, 1) node_0_1 = GraphNode(Panel(coordinate=Coordinate(0, 1, rotation=0)), 1, 1) node_1_1 = GraphNode(Panel(coordinate=Coordinate(1, 1, rotation=0)), 1, 1) node_2_1 = GraphNode(Panel(coordinate=Coordinate(2, 1, rotation=0)), 1, 1) node_3_1 = GraphNode(Panel(coordinate=Coordinate(3, 1, rotation=0)), 1, 1) node_0_2 = GraphNode(Panel(coordinate=Coordinate(0, 2, rotation=0)), 1, 1) node_1_2 = GraphNode(Panel(coordinate=Coordinate(1, 2, rotation=0)), 1, 1) node_2_2 = GraphNode(Panel(coordinate=Coordinate(2, 2, rotation=0)), 1, 1) node_0_0.add_neighbor(node_0_1, GraphDirection.North) node_0_0.add_neighbor(node_1_1, GraphDirection.NorthEast) node_0_0.add_neighbor(node_1_0, GraphDirection.East) node_2_0.add_neighbor(node_1_0, GraphDirection.West) node_2_0.add_neighbor(node_1_1, GraphDirection.NorthWest) node_2_0.add_neighbor(node_2_1, GraphDirection.North) node_2_0.add_neighbor(node_3_1, GraphDirection.NorthEast) node_2_0.add_neighbor(node_3_0, GraphDirection.East) node_1_1.add_neighbor(node_0_1, GraphDirection.West) node_1_1.add_neighbor(node_1_0, GraphDirection.South) node_1_1.add_neighbor(node_1_2, GraphDirection.North) node_1_1.add_neighbor(node_2_1, GraphDirection.East) node_3_1.add_neighbor(node_2_1, GraphDirection.West) node_0_2.add_neighbor(node_0_1, GraphDirection.South) node_0_2.add_neighbor(node_1_1, GraphDirection.SouthEast) node_0_2.add_neighbor(node_1_2, GraphDirection.East) node_2_2.add_neighbor(node_1_2, GraphDirection.West) node_2_2.add_neighbor(node_1_1, GraphDirection.SouthWest) node_2_2.add_neighbor(node_2_1, GraphDirection.South) node_2_2.add_neighbor(node_3_1, GraphDirection.SouthEast) nodes = [ node_0_0, node_1_0, node_2_0, node_3_0, node_0_1, node_1_1, node_2_1, node_3_1, node_0_2, node_1_2, node_2_2 ] self.subject.detect_panel_types(nodes) def assert_has_type(node, panel_type): eq_(node.panel.panel_type, panel_type) assert_has_type(node_0_0, PanelType.Corner) assert_has_type(node_1_0, PanelType.NorthSouth) assert_has_type(node_2_0, PanelType.NorthSouth) assert_has_type(node_3_0, PanelType.Corner) assert_has_type(node_0_1, PanelType.EastWest) assert_has_type(node_1_1, PanelType.Middle) assert_has_type(node_2_1, PanelType.Middle) assert_has_type(node_3_1, PanelType.Corner) assert_has_type(node_0_2, PanelType.Corner) assert_has_type(node_1_2, PanelType.NorthSouth) assert_has_type(node_2_2, PanelType.Corner) def test_detect_dual_tilt_wind_zones_simple_rectangle_mid_lb(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] l_b = 0.55 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 0) assert_has_wind_zone(panel_1_0, 1) assert_has_wind_zone(panel_2_0, 1) assert_has_wind_zone(panel_3_0, 0) assert_has_wind_zone(panel_0_1, 1) assert_has_wind_zone(panel_1_1, 2) assert_has_wind_zone(panel_2_1, 2) assert_has_wind_zone(panel_3_1, 1) assert_has_wind_zone(panel_0_2, 0) assert_has_wind_zone(panel_1_2, 1) assert_has_wind_zone(panel_2_2, 1) def test_detect_dual_tilt_wind_zones_simple_rectangle_high_lb(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) l_b = 1 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) assert_has_wind_zone(panel_0_0, 0) assert_has_wind_zone(panel_1_0, 0) assert_has_wind_zone(panel_2_0, 0) assert_has_wind_zone(panel_3_0, 0) assert_has_wind_zone(panel_0_1, 0) assert_has_wind_zone(panel_1_1, 1) assert_has_wind_zone(panel_2_1, 1) assert_has_wind_zone(panel_3_1, 0) assert_has_wind_zone(panel_0_2, 0) assert_has_wind_zone(panel_1_2, 0) assert_has_wind_zone(panel_2_2, 0) def test_detect_dual_tilt_wind_zones_simple_rectangle_low_lb(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) l_b = 0.3 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 1) assert_has_wind_zone(panel_1_0, 2) assert_has_wind_zone(panel_2_0, 2) assert_has_wind_zone(panel_3_0, 1) assert_has_wind_zone(panel_0_1, 2) assert_has_wind_zone(panel_1_1, 3) assert_has_wind_zone(panel_2_1, 3) assert_has_wind_zone(panel_3_1, 2) assert_has_wind_zone(panel_0_2, 1) assert_has_wind_zone(panel_1_2, 2) assert_has_wind_zone(panel_2_2, 2) # try again with a lower l_B l_b = 0.3 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 1) assert_has_wind_zone(panel_1_0, 2) assert_has_wind_zone(panel_2_0, 2) assert_has_wind_zone(panel_3_0, 1) assert_has_wind_zone(panel_0_1, 2) assert_has_wind_zone(panel_1_1, 3) assert_has_wind_zone(panel_2_1, 3) assert_has_wind_zone(panel_3_1, 2) assert_has_wind_zone(panel_0_2, 1) assert_has_wind_zone(panel_1_2, 2) assert_has_wind_zone(panel_2_2, 2) def test_detect_dual_tilt_wind_zones_simple_rectangle_very_low_lb(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) l_b = 0.2 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 2) assert_has_wind_zone(panel_1_0, 3) assert_has_wind_zone(panel_2_0, 3) assert_has_wind_zone(panel_3_0, 2) assert_has_wind_zone(panel_0_1, 3) assert_has_wind_zone(panel_1_1, 4) assert_has_wind_zone(panel_2_1, 4) assert_has_wind_zone(panel_3_1, 3) assert_has_wind_zone(panel_0_2, 2) assert_has_wind_zone(panel_1_2, 3) assert_has_wind_zone(panel_2_2, 3) # try again with a lower l_B l_b = 0.3 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 1) assert_has_wind_zone(panel_1_0, 2) assert_has_wind_zone(panel_2_0, 2) assert_has_wind_zone(panel_3_0, 1) assert_has_wind_zone(panel_0_1, 2) assert_has_wind_zone(panel_1_1, 3) assert_has_wind_zone(panel_2_1, 3) assert_has_wind_zone(panel_3_1, 2) assert_has_wind_zone(panel_0_2, 1) assert_has_wind_zone(panel_1_2, 2) assert_has_wind_zone(panel_2_2, 2) def test_detect_single_tilt_wind_zones_simple_rectangle_mid_lb(self): system_type = SystemType.singleTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panel_3_2 = Panel(coordinate=Coordinate(3, 2, rotation=0), id='3_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_3_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] l_b = 0.55 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): assert wind_zone == panel.wind_zone, "Expected panel to be in wind_zone %d, got %d" % (wind_zone, panel.wind_zone) eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 8) assert_has_wind_zone(panel_1_0, 7) assert_has_wind_zone(panel_2_0, 7) assert_has_wind_zone(panel_3_0, 8) assert_has_wind_zone(panel_0_1, 9) assert_has_wind_zone(panel_1_1, 2) assert_has_wind_zone(panel_2_1, 2) assert_has_wind_zone(panel_3_1, 9) assert_has_wind_zone(panel_0_2, 0) assert_has_wind_zone(panel_1_2, 2) assert_has_wind_zone(panel_2_2, 2) assert_has_wind_zone(panel_3_2, 0) def test_detect_single_tilt_wind_zones_simple_rectangle_low_lb(self): system_type = SystemType.singleTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panel_3_2 = Panel(coordinate=Coordinate(3, 2, rotation=0), id='3_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_3_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] buildings = [ Polygon(points=[ (-0.5, -0.5), (3.5, -0.5), (3.5, 2.5), (-0.5, 2.5) ]) ] l_b = 0.35 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): assert wind_zone == panel.wind_zone, "Expected panel to be in wind_zone %d, got %d" % (wind_zone, panel.wind_zone) eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E, 5 is F, 6 is G, 7 is H, 8 is I, 9 is J, 10 is K # A, I, H, B, J, C, E, F, G, D, K (order of most uplift force assert_has_wind_zone(panel_0_0, 9) assert_has_wind_zone(panel_1_0, 4) assert_has_wind_zone(panel_2_0, 4) assert_has_wind_zone(panel_3_0, 9) assert_has_wind_zone(panel_0_1, 2) assert_has_wind_zone(panel_1_1, 5) assert_has_wind_zone(panel_2_1, 5) assert_has_wind_zone(panel_3_1, 2) assert_has_wind_zone(panel_0_2, 0) assert_has_wind_zone(panel_1_2, 3) assert_has_wind_zone(panel_2_2, 3) assert_has_wind_zone(panel_3_2, 0) def test_detect_dual_tilt_wind_zones_10_gon_building(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] points = [] radius = 3 building_vertices = 10 for step in range(building_vertices, 0, -1): # create a 10-gon angle = (2 * pi / building_vertices) * step x = radius * sin(angle) y = radius * cos(angle) points.append((x, y)) buildings = [Polygon(points=points)] l_b = 2 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): eq_(panel.wind_zone, wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 4) assert_has_wind_zone(panel_1_0, 4) assert_has_wind_zone(panel_2_0, 4) assert_has_wind_zone(panel_3_0, 4) assert_has_wind_zone(panel_0_1, 4) assert_has_wind_zone(panel_1_1, 4) assert_has_wind_zone(panel_2_1, 4) assert_has_wind_zone(panel_3_1, 4) assert_has_wind_zone(panel_0_2, 4) assert_has_wind_zone(panel_1_2, 4) assert_has_wind_zone(panel_2_2, 4) def test_detect_dual_tilt_wind_zones_hexagon_building(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] points = [] radius = 4 building_vertices = 6 for step in range(building_vertices, 0, -1): # create a 10-gon angle = (2 * pi / building_vertices) * step x = radius * sin(angle) y = radius * cos(angle) points.append((x + 1, y + 1)) buildings = [Polygon(points=points)] l_b = 1 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): assert panel.wind_zone == wind_zone, "expected panel to be in wind zone %d, got %d" % (wind_zone, panel.wind_zone) # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 1) assert_has_wind_zone(panel_1_0, 2) assert_has_wind_zone(panel_2_0, 1) assert_has_wind_zone(panel_3_0, 1) assert_has_wind_zone(panel_0_1, 2) assert_has_wind_zone(panel_1_1, 2) assert_has_wind_zone(panel_2_1, 2) assert_has_wind_zone(panel_3_1, 1) assert_has_wind_zone(panel_0_2, 1) assert_has_wind_zone(panel_1_2, 2) assert_has_wind_zone(panel_2_2, 1) def test_detect_dual_tilt_wind_zones_triangle_building(self): system_type = SystemType.dualTilt panel_0_0 = Panel(coordinate=Coordinate(0, 0, rotation=0), id='0_0') panel_1_0 = Panel(coordinate=Coordinate(1, 0, rotation=0), id='1_0') panel_2_0 = Panel(coordinate=Coordinate(2, 0, rotation=0), id='2_0') panel_3_0 = Panel(coordinate=Coordinate(3, 0, rotation=0), id='3_0') panel_0_1 = Panel(coordinate=Coordinate(0, 1, rotation=0), id='0_1') panel_1_1 = Panel(coordinate=Coordinate(1, 1, rotation=0), id='1_1') panel_2_1 = Panel(coordinate=Coordinate(2, 1, rotation=0), id='2_1') panel_3_1 = Panel(coordinate=Coordinate(3, 1, rotation=0), id='3_1') panel_0_2 = Panel(coordinate=Coordinate(0, 2, rotation=0), id='0_2') panel_1_2 = Panel(coordinate=Coordinate(1, 2, rotation=0), id='1_2') panel_2_2 = Panel(coordinate=Coordinate(2, 2, rotation=0), id='2_2') panels = [ panel_0_2, panel_1_2, panel_2_2, panel_0_1, panel_1_1, panel_2_1, panel_3_1, panel_0_0, panel_1_0, panel_2_0, panel_3_0, ] sorted_panels = sorted(panels, key=lambda x: x.id) modules = [Polygon(points=[(p.coordinate.x, p.coordinate.y)]) for p in sorted_panels] points = [] radius = 4 building_vertices = 3 for step in range(building_vertices, 0, -1): # create a 10-gon angle = (2 * pi / building_vertices) * step x = radius * sin(angle) y = radius * cos(angle) points.append((x + 1, y + 1)) buildings = [Polygon(points=points)] l_b = 1 self.subject.detect_wind_zones(panels, buildings, modules, l_b, system_type) def assert_has_wind_zone(panel, wind_zone): assert panel.wind_zone == wind_zone, "expected panel to be in wind zone %d, got %d" % (wind_zone, panel.wind_zone) assert panel.fuzzy_wind_zone, "expected panel to be in a fuzzy wind zone" # 0 is A, 1 is B, 2 is C, 3 is D, 4 is E assert_has_wind_zone(panel_0_0, 1) assert_has_wind_zone(panel_1_0, 1) assert_has_wind_zone(panel_2_0, 1) assert_has_wind_zone(panel_3_0, 0) assert_has_wind_zone(panel_0_1, 1) assert_has_wind_zone(panel_1_1, 2) assert_has_wind_zone(panel_2_1, 1) assert_has_wind_zone(panel_3_1, 1) assert_has_wind_zone(panel_0_2, 1) assert_has_wind_zone(panel_1_2, 1) assert_has_wind_zone(panel_2_2, 1) def test_compute_corner_directions(self): data = [ { 'building_points': [(0, 0), (10, 0), (10, 10), (0, 10)], 'expected_corner_dirs': [(False, False), (False, True), (True, True), (True, False)] }, { 'building_points': [(0, 0), (10, 0), (2, 10)], 'expected_corner_dirs': [(False, False), (False, True), (True, False)] }, { 'building_points': [(0, 0), (10, 0), (7, 10)], 'expected_corner_dirs': [(False, False), (False, True), (True, True)] }, { 'building_points': [(0, 0), (10, 0), (7, 2)], 'expected_corner_dirs': [(False, False), (False, True), (True, False)] }, { 'building_points': [(0, 0), (3, -10), (10, 0)], 'expected_corner_dirs': [(True, False), (False, False), (True, True)] }, { 'building_points': [(-1, -1), (1, 4), (0, 10)], 'expected_corner_dirs': [(False, False), (False, True), (True, False)] }, { 'building_points': [(1, -1), (0, 10), (-1, 4)], 'expected_corner_dirs': [(False, True), (True, True), (False, False)] }, { 'building_points': [(0, 1), (4, 0), (8, 2)], 'expected_corner_dirs': [(True, False), (False, True), (True, True)] }, { 'building_points': [(0, 2), (4, 0), (8, 1)], 'expected_corner_dirs': [(True, False), (False, False), (True, True)] } ] for item in data: building = item['building_points'] expected = item['expected_corner_dirs'] corners = [] for i in range(len(building)): corners.append((building[i - 1], building[i], building[(i + 1) % len(building)])) for expected, (prev, vertex, next) in zip(expected, corners): print('given:', self.subject.compute_corner_directions(vertex, prev, next, 0)) assert self.subject.compute_corner_directions(vertex, prev, next, 0) == expected