From 4e3c77ad6168699e9e0dfdca26308ed2af8dbfb8 Mon Sep 17 00:00:00 2001 From: Symon Kipkemei <85394343+symonkipkemei@users.noreply.github.com> Date: Tue, 19 Sep 2023 19:10:30 +0300 Subject: [PATCH] 004.Refactoring --- lib/_create/_errorhandler.py | 4 + lib/_create/_openings.py | 22 ++++- lib/_create/_parts.py | 46 +++++++++- .../AutoParts.pushbutton/script.py | 29 ++++--- .../MultiParts.pushbutton/script.py | 3 + .../SinglePart.pushbutton/script.py | 7 +- .../SplitPart.pushbutton/script.py | 4 +- .../select.panel/Reveals.pushbutton/script.py | 26 ++++++ .../Panelized.pushbutton/script.py | 15 +++- .../Unpanelized.pushbutton/script.py | 30 ++++--- .../test.panel/test.pushbutton/icon.png | Bin 1561 -> 0 bytes .../test.panel/test.pushbutton/script.py | 80 ------------------ 12 files changed, 155 insertions(+), 111 deletions(-) delete mode 100644 panelization.tab/test.panel/test.pushbutton/icon.png delete mode 100644 panelization.tab/test.panel/test.pushbutton/script.py diff --git a/lib/_create/_errorhandler.py b/lib/_create/_errorhandler.py index 8070c7b..3ca78da 100644 --- a/lib/_create/_errorhandler.py +++ b/lib/_create/_errorhandler.py @@ -55,3 +55,7 @@ class RevealNotSelectedError(Exception): # catch elements that are Null in value class NoneError(Exception): pass + +# catches walls that are non-othogonal +class TransactionError(Exception): + pass diff --git a/lib/_create/_openings.py b/lib/_create/_openings.py index 781a2d8..7a10f0a 100644 --- a/lib/_create/_openings.py +++ b/lib/_create/_openings.py @@ -17,7 +17,6 @@ from _create import _parts as g from _create import _coordinate as c - from pyrevit import forms # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VARIABLES @@ -33,6 +32,25 @@ active_level = doc.ActiveView.GenLevel +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> GET WIDTH +def get_fenestration_width(fenestration_id): + """ + Establish the width of the window + :param fenestration_id: window/door id + :return: the width + """ + # establish the width of the window + fenestration = doc.GetElement(fenestration_id) + fenestration_type = fenestration.Symbol + width = fenestration_type.get_Parameter(BuiltInParameter.DOOR_WIDTH).AsDouble() + + # interchangeably the width can be 0 but rough width has dimensions + if width == 0: + width = fenestration_type.get_Parameter(BuiltInParameter.FAMILY_ROUGH_WIDTH_PARAM).AsDouble() + + return width + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> GET COORDINATES def get_fenestration_xyz_centre(fenestration_id): @@ -130,7 +148,7 @@ def get_fenestration_out_range(fenestration_left_index, fenestration_right_index # window width fenestration_width = fenestration_left_index - fenestration_right_index - displacement = cc.check_displacement_distance(displacement, fenestration_width) + displacement = check_displacement_distance(displacement, fenestration_width) # window left edge left_box_range_1 = fenestration_left_index - displacement diff --git a/lib/_create/_parts.py b/lib/_create/_parts.py index e2197cc..81ce2f0 100644 --- a/lib/_create/_parts.py +++ b/lib/_create/_parts.py @@ -371,7 +371,7 @@ def sort_parts_by_side(parts): host_wall_id = get_host_wall_id(part) host_wall_type_id = get_host_wall_type_id(host_wall_id) layer_index = get_layer_index(part) - lap_type_id, side_of_wall, exterior = get_wallsweep_parameters(layer_index, host_wall_type_id) + lap_type_id, side_of_wall, exterior = get_wall_sweep_parameters(layer_index, host_wall_type_id) if exterior == True: exterior_parts.append(part) @@ -446,3 +446,47 @@ def switch_directions(exterior, switch_direction=False): exterior = exterior return exterior + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> HIGHLIGHT FUNCTIONS + +def highlight_unpanelized_underpanelized_parts(__title__): + """Color code unpanelized parts and underpanleized parts for ease of identification + :param __title__: + :return: graphics_settings_unpanelized, graphics_settings_underpanelized + """ + + # select all parts + parts = select_all_parts() + exterior_parts, interior_parts = sort_parts_by_side(parts) + filtered_parts = exterior_parts + interior_parts + underpanalized, panelized, unpanelized = sort_parts_by_length(filtered_parts) + + solid_fill_id = ElementId(20) + + # color codes - unpanelized + graphics_settings_unpanelized = OverrideGraphicSettings() + graphics_settings_unpanelized.SetSurfaceForegroundPatternId(solid_fill_id) + clr_bytes_a = [255, 99, 71] + color_unpanelized_a = Color(clr_bytes_a[0], clr_bytes_a[1], clr_bytes_a[2]) + graphics_settings_unpanelized.SetSurfaceForegroundPatternColor(color_unpanelized_a) + + # color codes - underpanelized + graphics_settings_underpanelized = OverrideGraphicSettings() + graphics_settings_underpanelized.SetSurfaceForegroundPatternId(solid_fill_id) + clr_bytes_b = [251, 191, 0] + color_underpanelized_b = Color(clr_bytes_b[0], clr_bytes_b[1], clr_bytes_b[2]) + graphics_settings_underpanelized.SetSurfaceForegroundPatternColor(color_underpanelized_b) + + with Transaction(doc, __title__) as t: + t.Start() + if len(unpanelized) != 0: + for part in unpanelized: + active_view.SetElementOverrides(part.Id, graphics_settings_unpanelized) + if len(underpanalized) != 0: + for part in underpanalized: + active_view.SetElementOverrides(part.Id, graphics_settings_underpanelized) + + t.Commit() + + return graphics_settings_unpanelized, graphics_settings_underpanelized diff --git a/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py b/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py index 2c923f3..45a4021 100644 --- a/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py +++ b/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py @@ -23,9 +23,9 @@ clr.AddReference("System") from _create import _transactions as a from _create import _parts as g -from _create import _checks as cc -from _create import _forms as f -from _create import _errorhandler as eh +from _create import _forms as f +from _create import _errorhandler as eh +from pyrevit import forms # VARIABLES ################################################################################################################################ @@ -44,19 +44,22 @@ def main(): exterior_parts, interior_parts = g.sort_parts_by_side(selected_parts) all_parts = exterior_parts + interior_parts - #all_parts = cc.check_if_host_wall_edited(all_parts) underpanelized, panalized, non_panelized_parts = g.sort_parts_by_length(all_parts) - switch_option = f.switch_option() - displacement_distance = f.displacement_distance_form() - for part in non_panelized_parts: - try: - a.auto_parts(__title__, part, displacement_distance, switch_option, multiple=True) - except Exception: - pass - g.highlight_unpanelized_underpanelized_parts(__title__) + if len(non_panelized_parts) != 0: + switch_option = f.switch_option() + displacement_distance = f.displacement_distance_form() + for part in non_panelized_parts: + try: + a.auto_parts(__title__, part, displacement_distance, switch_option, multiple=True) + except Exception: + pass + + g.highlight_unpanelized_underpanelized_parts(__title__) + + else: + forms.alert("There are no non-panelized parts") if __name__ == "__main__": - # print(get_part_length(496067)) main() diff --git a/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py b/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py index 6f26f0a..996e99e 100644 --- a/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py +++ b/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py @@ -53,6 +53,9 @@ def main(): forms.alert("Centre Index could not be established") except eh.VariableDistanceNotFoundError: forms.alert("The variable distance could not be established") + except eh.TransactionError: + forms.alert("Transaction Error occurred") + except Exception: pass diff --git a/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py b/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py index 8690433..06084bb 100644 --- a/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py +++ b/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py @@ -51,8 +51,11 @@ def main(): except eh.VariableDistanceNotFoundError: forms.alert("The variable distance could not be established") - #except Exception: - #forms.alert("Error occurred.Could not panelize") + except eh.TransactionError: + forms.alert("Transaction Error occurred") + + except Exception: + forms.alert("Error occurred.Could not panelize selected Part.") diff --git a/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py b/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py index 9247ce6..978825a 100644 --- a/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py +++ b/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py @@ -41,9 +41,9 @@ def main(): lap_type_id, side_of_wall, exterior = p.get_wall_sweep_parameters(layer_index, host_wall_type_id) reveal_plane_coordinate_0 = t.get_reveal_coordinate_at_0(__title__, part) - distance = p.get_part_centre_index(part, reveal_plane_coordinate_0) + centre_index = p.get_part_centre_index(part, reveal_plane_coordinate_0) - t.auto_place_reveal(__title__, host_wall_id, lap_type_id, distance, side_of_wall) + t.auto_place_reveal(__title__, host_wall_id, lap_type_id, centre_index, side_of_wall) except eh.VariableDistanceNotFoundError: forms.alert("The variable distance could not be established") diff --git a/panelization.tab/select.panel/Reveals.pushbutton/script.py b/panelization.tab/select.panel/Reveals.pushbutton/script.py index 29cc8f4..7c758f8 100644 --- a/panelization.tab/select.panel/Reveals.pushbutton/script.py +++ b/panelization.tab/select.panel/Reveals.pushbutton/script.py @@ -57,6 +57,10 @@ def AllowReference(self, refer, point): # select a reveal def select_reveal(): + """ + Selects a reveal + :return: + """ reveal_filter = RevealSelectionFilter() reference = uidoc.Selection.PickObject(ObjectType.Element, reveal_filter) reveal = uidoc.Document.GetElement(reference) @@ -70,12 +74,22 @@ def select_reveal(): def get_wall_side(reveal): + """ + Determine the wall side of the reveal + :param reveal: reveal + :return: wall side + """ wall_sweep_info = reveal.GetWallSweepInfo() wall_side = wall_sweep_info.WallSide return wall_side def get_host_wall_id(reveal): + """ + Abstract the host wall id of a selected reveal + :param reveal: Reveal + :return: host wall Element Id + """ host_ids = reveal.GetHostIds() host_id = host_ids[0] @@ -86,6 +100,10 @@ def get_host_wall_id(reveal): def select_all_reveals(): + """ + Select all reveals in a project + :return: + """ all_reveals = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Reveals). \ WhereElementIsNotElementType().ToElements() @@ -93,6 +111,13 @@ def select_all_reveals(): def get_filtered_reveals(reference_host_id, reference_wall_side, all_reveals): + """ + Filter reveals based on the host wall and the wall side + :param reference_host_id: + :param reference_wall_side: + :param all_reveals: + :return: + """ filtered_reveals = [] for reveal in all_reveals: wall_side = get_wall_side(reveal) @@ -105,6 +130,7 @@ def get_filtered_reveals(reference_host_id, reference_wall_side, all_reveals): def display_selected_reveals(filtered_reveals): + """Display all selected reveals""" uidoc.Selection.SetElementIds(filtered_reveals) diff --git a/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py b/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py index a629e74..3dbe7ee 100644 --- a/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py +++ b/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py @@ -45,6 +45,7 @@ def get_parts_data(filtered_parts): + """Abstract parts data : height,length, thickness, volume, base level and area""" parts_data = {} for part in filtered_parts: @@ -66,6 +67,11 @@ def get_parts_data(filtered_parts): def get_parts_type_data(parts_data): + """Aggregate parts data of similar length and height + :param parts_data: + :return: + """ + data = {} for part_data in parts_data.values(): # the default type default_part_type = part_data[0] @@ -82,6 +88,7 @@ def get_parts_type_data(parts_data): def get_summary_data(parts_data, parts_type_data, cost_per_sf): + """Sum up parts data into total panels, area and cost""" final_data = [] sum_panels = 0 sum_area = 0 @@ -108,6 +115,12 @@ def get_summary_data(parts_data, parts_type_data, cost_per_sf): def user_filters_part_type(exterior_parts,interior_parts): + """ + Alllow user to select which parts to be filtered. + :param exterior_parts: interior parts + :param interior_parts: exterior parts + :return: selected parts , user choice + """ # user selects which parts for take off ops = ['External Parts', 'Internal Parts', 'External and Internal Parts'] @@ -158,7 +171,7 @@ def main(): forms.alert("Highlighted parts (red) have not been panelized") else: - forms.alert("Congratualtions! All parts have been panelized") + forms.alert("CongratuLations! All parts have been panelized") else: diff --git a/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py b/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py index b97b828..b065b63 100644 --- a/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py +++ b/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py @@ -24,9 +24,7 @@ from Autodesk.Revit.DB import View from _create import _transactions as a from _create import _parts as g - from _create import _forms as f -from _create import _checks as c from pyrevit import forms import clr @@ -47,6 +45,10 @@ # check if a panel is less than 4' and filtered, remove filter def get_unpanelized_parts(): + """ + Select all parts and filter to unpanelized parts + :return: unpanelized parts + """ # select interior and exterior parts parts = g.select_all_parts() exterior_parts, interior_parts = g.sort_parts_by_side(parts) @@ -62,33 +64,41 @@ def get_unpanelized_parts(): def get_unpanalized_parts_data(unpanelized_parts): + """Abstract unpanelized parts data from the model""" parts_data = [] + count = 0 for part in unpanelized_parts: + count += 1 part_id = part.Id height = part.get_Parameter(BuiltInParameter.DPART_HEIGHT_COMPUTED).AsValueString() length = part.get_Parameter(BuiltInParameter.DPART_LENGTH_COMPUTED).AsValueString() base_level = part.get_Parameter(BuiltInParameter.DPART_BASE_LEVEL).AsDouble() - data = [part_id, height, length, base_level] + data = [count, part_id, height, length, base_level] parts_data.append(data) return parts_data - - def main(): parts = get_unpanelized_parts() - parts_data = get_unpanalized_parts_data(parts) + if len(parts) != 0: + parts_data = get_unpanalized_parts_data(parts) + + g.highlight_unpanelized_underpanelized_parts(__title__) + + # display panels data + header = ["COUNT", "PART ID", "HEIGHT(F)", "LENGTH(F)", "BASE LEVEL"] + + f.display_form(parts_data, header, "Unpanelized parts", last_line_color='color:blue;') - g.highlight_unpanelized_underpanelized_parts(__title__) + else: + forms.alert("Congratulations! All parts have been panelized") - # display panels data - header = ["PART ID", "HEIGHT(F)", "LENGTH(F)", "BASE LEVEL"] - f.display_form(parts_data, header, "Unpanelized parts", last_line_color='color:blue;') + if __name__ == "__main__": diff --git a/panelization.tab/test.panel/test.pushbutton/icon.png b/panelization.tab/test.panel/test.pushbutton/icon.png deleted file mode 100644 index 69b3f151891a173d138b1badc077df0176704919..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1561 zcmV+!2Il#RP)F415@F?_rbnQNO4UK}YexI2wKj3`? zB?%I-W?*KN`k-s*n{8p3Mpy+UHEU2L^&kOBf+U%ZVSsU%G6Ub)^BL^f`#j`&%AkJl ze(3D^eEnL>iFPwfz9k?JL0O8&Co1f+q^N&N3R^V`_U51?jDd^8u(b3K^bZU}eZ&6s zYaQL6ZYuP6Kl?*e*rhBNt06#%PiY6Yn?13@UC{mE)%Bp~dAtx=S^`ug5`jEV`T8|{ zoTspA`&pRGF4EN4qC^8mc5VqAYD|-_Wu|&#Y#Jj`V%qQ-iv(^oGQlH<2Wox ziW;@vc~v(KFUbUQHZYPd?CBiwwa6@DLSgV5!Z zG3|C2=^e*+-pK@l&yTNzuNSX9XlygK{nVjG$j&KT10$>Bj)G!j22_-k!EDd*9XoBh z+FS8}|G5w5n(_+EZ9~s=AJ_Y2+}|fSsAjBUW+Vaw{npFPptuTB0s~*C{b+MS?L$v@ zA2TwAt!8C=RDpNt1zb_}VJgwih8*HIUTiR?&T6;7yCg;Z6&s7=uHAtPCCQUrEoLqG zS>Rogtlq)KF6>aio$Q5?HZw#17I>FAM#t*RS8pGI<~?{bdI|Sn*2Way5pso z{V*RZI2j1S*i}^v(=#_|G|Z(}mO~J{bq%V@D`P@Q3m{E(yLA|L2VAr0TN7i@ z()LJl`I$^8}Gi&*S8D43B?MGj0KX)T2bn)hN0p2EWsck(bPbxdaBM6 z3<46hFM9|G2f@||2%qmmG|CYB1FaDd`)64i0pV-fs}T@q0GXq;EPgysYgzULzLD0l zlCzd2C9u|Y@32H`S)A37IaFrg%9ja9)P4vAgoD6q zG-UB_i9S;gr#$Gimc^0hX)ViHYgztGoc3B-%kuB=eXL}yWuY?;2+!Zk(g;YHtM6rH zqKtMPMyhcM7|CXqzhi!*IKsX4zmWe=|wqMrrzl-U; zUl#5t7o5Isd!RLoPWv6@%sm&Ug4emul$GTWOif;eN^d2Mb{ugw5ZpR7-ZrtgsiY%z zCEZ;c6UJ{Jzp6h@l-0ik-jxX(DNmelbwQdcl5{AF+PC=(LdRQXcQG>@2jkwFg6C}D zjKn-S!BLjgJJ@zC;Et&oBoc{4B9TZW5{X12kw_#Gi9{ligiZPnf6PXXkoa3H00000 LNkvXXu0mjf>`v8~ diff --git a/panelization.tab/test.panel/test.pushbutton/script.py b/panelization.tab/test.panel/test.pushbutton/script.py deleted file mode 100644 index 197c586..0000000 --- a/panelization.tab/test.panel/test.pushbutton/script.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import division - -# METADATA - -__title__ = "Test" - -__doc__ = """Version 1.3 -Date = 09.06.2023 -___________________________________________________________ -Description: - -This tool will test the out ranges position of windows - -___________________________________________________________ -How-to: --> Click on the button --> Select a Part -___________________________________________________________ -last update: -- [01.07.2023] - 1.3 RELEASE - -___________________________________________________________ -To do: --> Allow the user to set a constrain of the smallest panel size -___________________________________________________________ -Author: Symon Kipkemei - -""" - -__author__ = "Symon Kipkemei" -__helpurl__ = "https://www.linkedin.com/in/symon-kipkemei/" - -__highlight__ = 'new' - -__min_revit_ver__ = 2020 -__max_revit_ver__ = 2023 - -# IMPORTS -######################################################################################################################## - -from Autodesk.Revit.DB import * -from Autodesk.Revit.DB import Structure -from Autodesk.Revit.UI.Selection import ObjectType -import clr - -clr.AddReference("System") - -from _create import _transactions as a -from _create import _parts as g -from _create import _coordinate as c -from _create import _openings as o -from _create import _test as t -from _create import _forms as ff - -from _create import _testpyrevit as tp - -# VARIABLES -######################################################################################################################## - -# __revit__ used to create an instance -app = __revit__.Application # represents the Revit Autodesk Application -doc = __revit__.ActiveUIDocument.Document # obj used to create new instances of elements within the active project -uidoc = __revit__.ActiveUIDocument # obj that represent the current active project - -# create -active_view = doc.ActiveView -active_level = doc.ActiveView.GenLevel - - -# ________________________________________________________________________________________________TESTS - - -if __name__ == "__main__": - # test window index - #t.test_centre_window_index(__title__, window_option=False) - #t.test_fenestration_edges(__title__, window_option=False) - #t.test_out_ranges(__title__, 0.5, window_option=True) - #g.remove_graphics(__title__) - ff.switch_option() -