diff --git a/helix/presenters/panel_presenter.py b/helix/presenters/panel_presenter.py index dd10bb2..349ec6f 100644 --- a/helix/presenters/panel_presenter.py +++ b/helix/presenters/panel_presenter.py @@ -1,5 +1,5 @@ import sys -from math import sqrt, atan, degrees +from math import sqrt, degrees, acos from helix.models.corner import Corner from helix.constants.global_constants import max_corner_angle import flask_featureflags as feature @@ -76,43 +76,42 @@ class ProjectPresenter(object): return result def get_corners(self, buildings): + + def angle(x1, y1, x2, y2): + # Use dotproduct to find angle between vectors + # This always returns an angle between 0, pi + numer = (x1 * x2 + y1 * y2) + denom = sqrt((x1 ** 2 + y1 ** 2) * (x2 ** 2 + y2 ** 2)) + return acos(numer / denom) + + + def cross_sign(x1, y1, x2, y2): + # True if cross is positive + # False if negative or zero + return x1 * y2 > x2 * y1 + result = [] if feature.is_active('ff_cpp'): - for building in buildings: - presentable_building = [] - result.append(presentable_building) - previous_corner = building[-1] - for i, corner in enumerate(building): - if (i+1 == len(building)): - next_corner = building[0] - else: - next_corner = building[i+1] - - #x coordinate is stored as first element of corner variable - #y coordinate is stored as second element of corner variable - corner_length_ccw = sqrt((next_corner[0] - corner[0])**2 + (next_corner[1] - corner[1])**2) - corner_length_cw = sqrt((previous_corner[0] - corner[0])**2 + (previous_corner[1] - corner[1])**2) - - k1 = float('Inf') if (corner[0]==previous_corner[0]) else (corner[1] - previous_corner[1]) / (corner[0] - previous_corner[0]) - k2 = float('Inf') if (corner[0]==next_corner[0]) else (next_corner[1] - corner[1]) / (next_corner[0] - corner[0]) + for building in buildings: + presentable_building = [] + result.append(presentable_building) + + for i in range(len(building)): + p1 = building[i] + ref = building[i - 1] + p2 = building[i - 2] + x1, y1 = p1[0] - ref[0], p1[1] - ref[1] + x2, y2 = p2[0] - ref[0], p2[1] - ref[1] - theta2 = degrees(atan(k2)) - theta1 = degrees(atan(k1)) - theta2 - - if (theta1 < 0): - if (k1 < 0 and k2 < 0): - theta1 = 360 + theta1 - elif (k1 <= 0 and k2 >= 0): - theta1 = 180 + theta1 - else: - if (k1 > 0 and k2 > 0): - theta1 = 180 + theta1 - - if (theta1 < max_corner_angle): - presentable_building.append(Corner(corner[0], corner[1], corner_length_ccw,corner_length_cw, theta1).__dict__) - - previous_corner = corner + corner_length_cw = sqrt(x2**2 + y2**2) + corner_length_ccw = sqrt(x1**2 + y1**2) + theta = degrees(angle(x1, y1, x2, y2)) + #print('Points', p1, ref, p2) + #print('Angle', theta) + if (cross_sign(x1, y1, x2, y2)) and (theta < max_corner_angle) : + #print('Inner Angle') + presentable_building.append(Corner(ref[0], ref[1], corner_length_ccw,corner_length_cw, theta).__dict__) return result def get_max_y(self,buildings, panels): diff --git a/test/helpers/panel_presenter_test.py b/test/helpers/panel_presenter_test.py index c9c47d1..0bdc08e 100644 --- a/test/helpers/panel_presenter_test.py +++ b/test/helpers/panel_presenter_test.py @@ -81,15 +81,27 @@ class PanelPresenterTest(unittest.TestCase): actual_buildings = self.subject.get_buildings(buildings,60) assert_array_equal(actual_buildings,expected_buildings) + def test_get_corners_fancy_building(self): + self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96) + buildings = [ [ [2, 5], [2, 3], [0,3], [0, 0], [2,0], [2,-3], [6,-3], [8,-1], [8,1], [6,3], [4,3], [4,5] ] ] # fancy builgin with three interior corners + expected_corners = [[ + {'length_ccw': 2.0, 'angle': 90.0, 'y': 5, 'x': 4, 'length_cw': 2.0}, + {'length_ccw': 2.0, 'angle': 90.0, 'y': 5, 'x': 2, 'length_cw': 2.0}, + {'length_ccw': 3.0, 'angle': 90.0, 'y': 3, 'x': 0, 'length_cw': 2.0}, + {'length_ccw': 2.0, 'angle': 90.0, 'y': 0, 'x': 0, 'length_cw': 3.0}, + {'length_ccw': 4.0, 'angle': 90.0, 'y': -3, 'x': 2, 'length_cw': 3.0}]] + actual_corners = self.subject.get_corners(buildings) + assert_array_equal(actual_corners,expected_corners) + #@mock.patch('flask_featureflags.is_active',side_effect=feature_is_always_active) def test_get_corners_box_building(self): self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96) buildings = [ [ [0, 0], [60, 0], [60,60], [0, 60] ] ] # big square expected_corners = [[ + {'x': 0, 'y': 60, 'length_cw': 60, 'length_ccw':60, 'angle':90}, {'x': 0, 'y': 0, 'length_cw': 60, 'length_ccw':60, 'angle':90}, {'x': 60, 'y': 0, 'length_cw': 60, 'length_ccw':60, 'angle':90}, - {'x': 60, 'y': 60, 'length_cw': 60, 'length_ccw':60, 'angle':90}, - {'x': 0, 'y': 60, 'length_cw': 60, 'length_ccw':60, 'angle':90} + {'x': 60, 'y': 60, 'length_cw': 60, 'length_ccw':60, 'angle':90} ]] actual_corners = self.subject.get_corners(buildings) assert_array_equal(actual_corners,expected_corners) @@ -99,10 +111,10 @@ class PanelPresenterTest(unittest.TestCase): self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96) buildings = [ [ [0, 0], [51.96, 30], [21.96, 81.96], [-30, 51.96] ] ] # big square expected_corners = [[ + {'x': -30, 'y': 51.96, 'length_cw': 59.998679985479676, 'length_ccw':59.99867998547968, 'angle':90}, {'x': 0, 'y': 0, 'length_cw': 59.99867998547968, 'length_ccw':59.99867998547968, 'angle':90}, {'x': 51.96, 'y': 30, 'length_cw': 59.99867998547968, 'length_ccw':59.998679985479676, 'angle':90}, - {'x': 21.96, 'y': 81.96, 'length_cw': 59.998679985479676, 'length_ccw':59.998679985479676, 'angle':90}, - {'x': -30, 'y': 51.96, 'length_cw': 59.998679985479676, 'length_ccw':59.99867998547968, 'angle':90} + {'x': 21.96, 'y': 81.96, 'length_cw': 59.998679985479676, 'length_ccw':59.998679985479676, 'angle':90.00000000000001} ]] actual_corners = self.subject.get_corners(buildings) assert_array_equal(actual_corners,expected_corners) @@ -112,10 +124,10 @@ class PanelPresenterTest(unittest.TestCase): self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96) buildings = [ [ [-3.42, 1.51], [-1.66, -1.64], [4.22, -0.87], [-0.8, 5.64]] ] expected_corners = [[ + {'x': -0.8, 'y': 5.64, 'length_cw': 8.22073597678456, 'length_ccw':4.890940604832571, 'angle':70.02691327912069}, {'x': -3.42, 'y': 1.51, 'length_cw': 4.890940604832571, 'length_ccw':3.6083375673570233, 'angle':118.41626123074676}, - {'x': -1.66, 'y': -1.64, 'length_cw': 3.6083375673570233, 'length_ccw':5.930202357424239, 'angle':111.73284308914215}, - {'x': 4.22, 'y': -0.87, 'length_cw': 5.930202357424239, 'length_ccw':8.22073597678456, 'angle':59.823982400990424}, - {'x': -0.8, 'y': 5.64, 'length_cw': 8.22073597678456, 'length_ccw':4.890940604832571, 'angle':70.02691327912069} + {'x': -1.66, 'y': -1.64, 'length_cw': 3.6083375673570233, 'length_ccw':5.930202357424239, 'angle':111.73284308914216}, + {'x': 4.22, 'y': -0.87, 'length_cw': 5.930202357424239, 'length_ccw':8.22073597678456, 'angle':59.82398240099042} ]] actual_corners = self.subject.get_corners(buildings) assert_array_equal(actual_corners,expected_corners) @@ -125,14 +137,13 @@ class PanelPresenterTest(unittest.TestCase): self.subject = ProjectPresenter(SystemType.singleTilt, ModuleType.Cell96) buildings = [ [ [-3.58, 3.32], [-0.78, -2.9], [-1.56,0.88], [0.66, -2.16], [1.5, 1.16], [2.72, 2.36], [-0.8, 5.64] ] ] expected_corners = [[ + {'x': -0.8, 'y': 5.64, 'length_cw': 4.811319985201567, 'length_ccw':3.6208838699963852, 'angle':97.17527350158385}, {'x': -3.58, 'y': 3.32, 'length_cw': 3.6208838699963852, 'length_ccw':6.821172919667115, 'angle':105.6106862572924}, - {'x': -0.78, 'y': -2.9, 'length_cw': 6.821172919667115, 'length_ccw':3.8596372886580936, 'angle':12.576112527956795}, - {'x': 0.66, 'y': -2.16, 'length_cw': 3.7643060449437424, 'length_ccw':3.424616766880639, 'angle':50.33783308603299}, - {'x': 2.72, 'y': 2.36, 'length_cw': 1.7112568480505783, 'length_ccw':4.811319985201567, 'angle':87.50512700090906}, - {'x': -0.8, 'y': 5.64, 'length_cw': 4.811319985201567, 'length_ccw':3.6208838699963852, 'angle':97.17527350158382} + {'x': -0.78, 'y': -2.9, 'length_cw': 6.821172919667115, 'length_ccw':3.8596372886580936, 'angle':12.576112527956782}, + {'x': 0.66, 'y': -2.16, 'length_cw': 3.7643060449437424, 'length_ccw':3.424616766880639, 'angle':50.337833086033}, + {'x': 2.72, 'y': 2.36, 'length_cw': 1.7112568480505783, 'length_ccw':4.811319985201567, 'angle':87.50512700090906} ]] actual_corners = self.subject.get_corners(buildings) - print(actual_corners) assert_array_equal(actual_corners,expected_corners) def test_get_max_y(self):