132 lines
5.0 KiB
Python
132 lines
5.0 KiB
Python
import sys
|
|
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
|
|
|
|
class ProjectPresenter(object):
|
|
def __init__(self, system_type, module_type):
|
|
self.offset = None
|
|
self.system_type = system_type
|
|
self.module_type = module_type
|
|
|
|
'''"This function expects coordinates to be in unit values, processed in coordinates_calculator.py" '''
|
|
def get_panel_data(self, panels, subarrays, max_y = None):
|
|
if self.offset is not None:
|
|
raise RuntimeError("ProjectPresenter panels must be computed before buildings")
|
|
|
|
table_data = []
|
|
|
|
system_constants = self.system_type.system_constants()
|
|
module_constants = self.system_type.module_constants(self.module_type)
|
|
spacing_x, spacing_y = module_constants.presenter_spacing
|
|
wind_zones = system_constants.wind_zones
|
|
|
|
for panel in panels:
|
|
subarray = [x for x in subarrays if x.subarray_number == panel.subarray][0]
|
|
origin = subarray.origin
|
|
|
|
table_data.append({
|
|
'x': (panel.coordinate.x + origin.x) * spacing_x,
|
|
'y': (panel.coordinate.y + origin.y) * spacing_y,
|
|
'width': spacing_x,
|
|
'height': spacing_y,
|
|
'data': {
|
|
'panel_id': panel.id,
|
|
'panel_type': panel.panel_type.number(),
|
|
'ballast': panel.ballast,
|
|
'wind_anchors': panel.wind_anchors,
|
|
'seismic_anchors': panel.seismic_anchors,
|
|
'wind_zones': wind_zones[panel.wind_zone],
|
|
'link_trays': panel.presented_link_tray,
|
|
'cross_trays': panel.cross_tray,
|
|
'psf': round(panel.pressure, 2),
|
|
'subarray': panel.subarray
|
|
}
|
|
})
|
|
|
|
# Move coordinates to reflect origin being at top-left
|
|
# (as per canvas) instead of bottom-left
|
|
height = max(map(lambda row: row['y'], table_data))
|
|
first_cell = min(map(lambda row: row['y'], table_data))
|
|
self.offset = height
|
|
for panel in table_data:
|
|
panel['y'] = height - panel['y'] + first_cell
|
|
|
|
return table_data
|
|
|
|
def get_buildings(self, buildings, max_y):
|
|
if self.offset is None:
|
|
self.offset = 0
|
|
|
|
module_constants = self.system_type.module_constants(self.module_type)
|
|
spacing_x, spacing_y = module_constants.presenter_spacing
|
|
# max_y = -sys.maxsize - 1 # for flipping the y coordinate
|
|
|
|
result = []
|
|
for building in buildings:
|
|
presentable_building = []
|
|
result.append(presentable_building)
|
|
# origin = self.find_origin(building)
|
|
for point in building:
|
|
point.x = point.x * spacing_x
|
|
point.y = abs((point.y * spacing_y) - max_y)
|
|
presentable_building.append(point.__dict__)
|
|
|
|
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)
|
|
|
|
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]
|
|
|
|
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):
|
|
|
|
module_constants = self.system_type.module_constants(self.module_type)
|
|
_, spacing_y = module_constants.presenter_spacing
|
|
all_y = []
|
|
|
|
if buildings is None or buildings == []: # no buildings in the file, probably CSV coordinates loaded
|
|
for panel in panels:
|
|
all_y.append(panel.coordinate.y)
|
|
|
|
for building in buildings:
|
|
for point in building:
|
|
all_y.append(point.y)
|
|
return max(all_y) * spacing_y
|
|
|