from enum import Enum import json from helix.constants.panel_type import PanelType from helix.functions import fequal from helix.models.coordinate import Coordinate class PanelData(Enum): Handle = 'HANDLE' Blockname = 'BLOCKNAME' Subarray = 'SUBARRAY' PanelType = 'POS' WindZone = 'WIND' Ballast = 'BAL' LinkTray = 'LT_CALCULATED' CrossTray = 'XTRAY' WindAnchor = 'ANC' SeismicAnchor = 'SEISMIC' Coordinate = 'COORDINATE' Pressure = 'PSF' Id = 'ID' PresentedLinkTray = 'LTRAY' Xcoord = 'XCOORD' Ycoord = 'YCOORD' Rotation = 'ANGLE' FuzzyWindZone = 'FUZZYWINDZONE' class PanelWarnings(Enum): MaxPsf = 'The values highlighted are panels that exceed our UL listed load limit. Please do not place panels in these areas to avoid exceeding the listed limit.' class Panel(object): def __init__(self, handle=None, blockname=None, subarray=None, panel_type=None, wind_zone=None, ballast=None, link_tray=None, cross_tray=None, wind_anchors=None, seismic_anchors=None, coordinate=None, pressure=None, id=None, presented_link_tray=None, original_coordinate=None, fuzzy_wind_zone=False, warnings=None): self.handle = handle self.blockname = blockname self.subarray = subarray self.panel_type = panel_type self.wind_zone = wind_zone self.ballast = ballast self.link_tray = link_tray self.cross_tray = cross_tray self.wind_anchors = wind_anchors self.seismic_anchors = seismic_anchors # this field after DXF parsing and before serialization into CSV contains translated coordinates (all positive) # and after deserialization from CSV contains original coordinates - same as original_coordinate field self.coordinate = coordinate self.original_coordinate = original_coordinate self.pressure = pressure self.id = id self.presented_link_tray = presented_link_tray self.fuzzy_wind_zone = fuzzy_wind_zone self.warnings = warnings or [] def merge(self, other): if not isinstance(other, self.__class__): return self d = {} for key, data in self.__dict__.items(): if data is not None: d[key] = data else: d[key] = other.__dict__.get(key) panel = Panel() panel.__dict__.update(d) return panel def is_subset(self, other): if not isinstance(other, self.__class__): return False for key, value in self.__dict__.items(): if value is None: continue if other.__dict__[key] != value: return False return True def almost_equal(self, other, decimal=6): if not isinstance(other, self.__class__): return False if self.pressure is not None and other.pressure is not None: if not fequal(self.pressure, other.pressure, delta=(10 ** (-decimal))): print("Pressures are not equal to within %d decimal places, got %f, expected %f" % (decimal, self.pressure, other.pressure)) return False elif self.pressure != other.pressure: return False for key, value in self.__dict__.items(): if key == 'pressure': continue elif other.__dict__.get(key) != value: print("Expected %s to be equal, got %s, expected %s" % (key, str(value), str(other.__dict__.get(key)))) return False return True def __deepcopy__(self, _): return Panel(handle=self.handle, blockname=self.blockname, subarray=self.subarray, panel_type=self.panel_type, wind_zone=self.wind_zone, ballast=self.ballast, link_tray=self.link_tray, cross_tray=self.cross_tray, wind_anchors=self.wind_anchors, seismic_anchors=self.seismic_anchors, coordinate=self.coordinate, original_coordinate=self.original_coordinate, pressure=self.pressure, id=self.id, presented_link_tray=self.presented_link_tray, fuzzy_wind_zone=self.fuzzy_wind_zone) def __eq__(self, other): if self is other: return True return self.almost_equal(other, decimal=3) def __repr__(self): def json_forcer(x): if isinstance(x, PanelType): return x.value if isinstance(x, Coordinate): return x.dictionary return x.__dict__ d = {key: value for (key, value) in self.__dict__.items() if value is not None} return json.dumps(d, sort_keys=True, default=json_forcer)