From fd3df5f51418e876a04281ae8a8035fe171e0349 Mon Sep 17 00:00:00 2001 From: Symon Kipkemei <85394343+symonkipkemei@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:39:55 +0300 Subject: [PATCH] 004 Refactoring --- lib/_create/_coordinate.py | 3 +- lib/_create/_errorhandler.py | 36 ++++--- lib/_create/_forms.py | 35 ++++-- lib/_create/_parts.py | 16 +-- lib/_create/_transactions.py | 101 ++++++++---------- .../AutoParts.pushbutton/script.py | 4 +- .../MultiParts.pushbutton/script.py | 20 ++-- .../SinglePart.pushbutton/script.py | 27 +++-- .../SplitPart.pushbutton/script.py | 10 +- .../Panelized.pushbutton/script.py | 4 +- .../Unpanelized.pushbutton/script.py | 2 +- 11 files changed, 149 insertions(+), 109 deletions(-) diff --git a/lib/_create/_coordinate.py b/lib/_create/_coordinate.py index b2e9f34..e80184f 100644 --- a/lib/_create/_coordinate.py +++ b/lib/_create/_coordinate.py @@ -14,6 +14,7 @@ from _create import _transactions as a from _create import _test as t +from _create import _errorhandler as eh # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VARIABLES @@ -53,7 +54,7 @@ def determine_x_plane(wall_id): else: # the wall curve is neither on x or y axis - x_axis = None + raise eh.XYAxisPlaneNotEstablishedError return x_axis diff --git a/lib/_create/_errorhandler.py b/lib/_create/_errorhandler.py index 3ca78da..ebd6263 100644 --- a/lib/_create/_errorhandler.py +++ b/lib/_create/_errorhandler.py @@ -32,30 +32,40 @@ def PreprocessFailures(self, failuresAccessor): return FailureProcessingResult.Continue -# catch instances where parts are less than 4' -class CannotPanelizeError(Exception): +class CentreIndexError(Exception): + """ + Catch error: Centre index of the part could not be established correctly + """ pass -# Cannot split the panel into equal parts -class CannotSplitPanelError(Exception): - pass - - -# catch variable distance cannot be found +# catch variable distance cannot be found class VariableDistanceNotFoundError(Exception): + """ + Catch error: variable distance cannot be found + """ pass # catch reveal not selected error -class RevealNotSelectedError(Exception): +class RevealNotCreatedError(Exception): + """ + Catch error: reveal not selected error + """ pass -# catch elements that are Null in value -class NoneError(Exception): +# Error occured deleteing elements +class DeleteElementsError(Exception): + """ + Catch error: reveal not selected error + """ pass -# catches walls that are non-othogonal -class TransactionError(Exception): +# catch instances where parts/walls are not along a x or y axis +class XYAxisPlaneNotEstablishedError(Exception): + """ + Catch error: parts/walls are not along a X or Y axis + """ pass + diff --git a/lib/_create/_forms.py b/lib/_create/_forms.py index 3da724d..0e180d1 100644 --- a/lib/_create/_forms.py +++ b/lib/_create/_forms.py @@ -33,17 +33,24 @@ # ________________________________________________________________________________________________ -def display_form(data, header, table_name, last_line_color='color:red;'): +def form_display_table(data, header, table_name, last_line_color='color:red;'): + """ + Display takeoff table + :param data: data to be displayed + :param header: header + :param table_name: table name + :param last_line_color: Last line color + :return: None + """ output = script.get_output() output.center() output.add_style('body { color: blue; }') output.make_bar_chart(version=None) - tt = output.print_table(table_data=data, title=table_name, columns=header, last_line_style=last_line_color) + output.print_table(table_data=data, title=table_name, columns=header, last_line_style=last_line_color) - # 'color:red;' -def single_digit_value(): +def form_estimated_cost(): while True: cost_per_sf = forms.ask_for_string(default='0', prompt='Enter estimated cost per square feet (USD):', title='Panel Material take off') @@ -57,7 +64,12 @@ def single_digit_value(): return cost_per_sf -def displacement_distance_form(): +def form_displacement_distance(): + """ + User input form for selecting distance from edge of openings parameter + + :return:float option + """ while True: d_distance = forms.ask_for_string(default='0.5', prompt='Enter displacement distance from edges of openings:', title='Panelization') @@ -71,7 +83,12 @@ def displacement_distance_form(): return float(d_distance) -def select_part_type(): +def form_select_part_type(): + """ + User input form for selecting parts for take off + :return: String Option + """ + # user sets cost per m2 and selects which pane to establish cost ops = ['External Parts', 'Internal Parts', 'External and Internal Parts'] user_choice = forms.SelectFromList.show(ops, button_name='Select Option', @@ -80,7 +97,11 @@ def select_part_type(): return user_choice -def switch_option(): +def form_switch_panelization_direction(): + ''' + User input form for switching panelization direction + :return: Bool option + ''' ans = forms.ask_for_one_item(['L to R', 'R to L'], default='L to R', prompt='(L)eft to (R)ight [default] or (R)ight to (L)eft :', title='Panelization Direction') if ans == "L to R": diff --git a/lib/_create/_parts.py b/lib/_create/_parts.py index 81ce2f0..4802b54 100644 --- a/lib/_create/_parts.py +++ b/lib/_create/_parts.py @@ -278,16 +278,18 @@ def get_reveal_indexes(left_edge, right_edge, out_ranges, exterior=True): # determine reveals required to panelize part while True: + reveal_edge_width = 0.078125 # subtracted 15/16"from panel to allow it cut at 2' if exterior: # panelization is left to right, the left edge reduces towards the right edge left_edge -= panelling_distance # skipping the out range if there is a window left_edge = o.check_out_range(left_edge, out_ranges, exterior=True) - # remaining length established, will determine when panelization is complete ( < 4 script breaks) - reveal_edge_width = 0.078125 - rem_length = left_edge - (right_edge - reveal_edge_width) + # the new left edge appended to the list reveal_indexes.append(left_edge) + # remaining length established,this will determine when panelization is complete ( < 4 script breaks) + rem_length = left_edge - (right_edge - reveal_edge_width) + if rem_length < 4.0000: if rem_length < minimum_panel: # remove the last record on list to allow for further splitting @@ -299,7 +301,6 @@ def get_reveal_indexes(left_edge, right_edge, out_ranges, exterior=True): # the part left behind is determined part_left_behind = left_edge - right_edge # determine the remainder left edge position - reveal_edge_width = 0.078125 # subtracted 15/16"from panel to allow it cut at 2' # what remains after setting aside minimum panel rem = part_left_behind - (minimum_panel - reveal_edge_width) # position the new left edge @@ -314,8 +315,12 @@ def get_reveal_indexes(left_edge, right_edge, out_ranges, exterior=True): right_edge += panelling_distance # panelization is right to left, the right edge increases towards the left edge # skipping the out range if there is a window right_edge = o.check_out_range(right_edge, out_ranges, exterior=False) - rem_length = left_edge - right_edge + reveal_indexes.append(right_edge) + + # reveal edge width subtracted from the right edge , to factor a 4' panel + rem_length = left_edge - (right_edge - reveal_edge_width) + if rem_length < 4.0000: if rem_length < minimum_panel: # remove the last record on list to allow for further splitting @@ -323,7 +328,6 @@ def get_reveal_indexes(left_edge, right_edge, out_ranges, exterior=True): if len(reveal_indexes) != 0: right_edge = reveal_indexes[-1] # the right edge becomes the last item on list part_left_behind = left_edge - right_edge - reveal_edge_width = 0.078125 # subtracted from panel to allow it cut at 2' rem = part_left_behind - (minimum_panel - reveal_edge_width) right_edge += rem reveal_indexes.append(right_edge) diff --git a/lib/_create/_transactions.py b/lib/_create/_transactions.py index a36a2ed..78518f6 100644 --- a/lib/_create/_transactions.py +++ b/lib/_create/_transactions.py @@ -8,6 +8,7 @@ from Autodesk.Revit.DB.Structure import StructuralType from Autodesk.Revit.UI.Selection import ObjectType import clr + clr.AddReference("System") from _create import _parts as p from _create import _test as tt @@ -39,28 +40,23 @@ def auto_place_reveal(__title__, host_wall_id, lap_type_id, variable_distance, s :return: A wall sweep """ with Transaction(doc, __title__) as t: - try: - t.Start("01. PlacingReveal") - # Provides access to option to control how failures should be handled by end of transaction. - options = t.GetFailureHandlingOptions() + t.Start("01. PlacingReveal") + # Provides access to option to control how failures should be handled by end of transaction. + options = t.GetFailureHandlingOptions() - # deletes warnings captured - failureProcessor = eh.WarningSwallower() + # deletes warnings captured + failureProcessor = eh.WarningSwallower() - # sets how failures should be handled during transaction - options.SetFailuresPreprocessor(failureProcessor) - t.SetFailureHandlingOptions(options) + # sets how failures should be handled during transaction + options.SetFailuresPreprocessor(failureProcessor) + t.SetFailureHandlingOptions(options) - reveal = p.create_reveal(host_wall_id, lap_type_id, variable_distance, side_of_wall) - status = t.Commit() + reveal = p.create_reveal(host_wall_id, lap_type_id, variable_distance, side_of_wall) - if status != TransactionStatus.Committed: - # if transaction has not been committed, this would result to an error. - print("The transaction has not been committed") + status = t.Commit() - except Exception as e: - print ('The following error has occurred on Transaction 03. Panelize parts : {}'.format(e)) - reveal = None + if status != TransactionStatus.Committed: + raise eh.RevealNotCreatedError return reveal @@ -72,34 +68,32 @@ def get_reveal_coordinate_at_0(__title__, part): :param part: Part to be panelized """ + + # project parameters host_wall_id = p.get_host_wall_id(part) host_wall_type_id = p.get_host_wall_type_id(host_wall_id) layer_index = p.get_layer_index(part) lap_type_id, side_of_wall, exterior = p.get_wall_sweep_parameters(layer_index, host_wall_type_id) x_axis_plane = c.determine_x_plane(host_wall_id) - # establish the length of part - length_before_reveal = p.get_part_length(part) + # set variable distance at 3, most parts are cut with reveals at a distance from the path curve origin,0 . + # Thus, coordinates of the reveal can be established - # determine the reveal that cuts through the part, the script will continue until the correct reveal is found, - # a reveal that does not cut through the part will not give us it's coordinates - - # reveal 1 plane coordinate variable_distance = 3 while True: reveal_1 = auto_place_reveal(__title__, host_wall_id, lap_type_id, variable_distance, side_of_wall) - if reveal_1 is None: - raise eh.VariableDistanceNotFoundError - length_after_reveal = p.get_part_length(part) - # print (variable_distance) if c.get_bounding_box_center(reveal_1) is not None: - break - elif length_before_reveal != length_after_reveal: - break + break # script breaks once coordinates are established + + # if the coordinates are not established, the script deletes the reveal and before looping to + # the next at an adjusted distance delete_element(__title__, reveal_1.Id) + variable_distance += 3 + if variable_distance > 100: + # the script has to break , the reveal coordinates could not be established. raise eh.VariableDistanceNotFoundError reveal_xyz_coordinates_1 = c.get_bounding_box_center(reveal_1) @@ -108,10 +102,7 @@ def get_reveal_coordinate_at_0(__title__, part): # create snd wall sweep, this will help establish the reveal at 0 move_distance = 0.166667 # 1/4", small distance to ensure part is cut reveal_2 = auto_place_reveal(__title__, host_wall_id, lap_type_id, variable_distance + move_distance, - side_of_wall) - - if reveal_2 is None: - raise eh.VariableDistanceNotFoundError + side_of_wall) # reveal 2 plane coordinate reveal_xyz_coordinates_2 = c.get_bounding_box_center(reveal_2) @@ -143,29 +134,26 @@ def auto_panel(__title__, host_wall_id, lap_type_id, reveal_indexes, side_of_wal :return: None """ - try: - with Transaction(doc, __title__) as t: - t.Start("03. Panelize parts") - # Provides access to option to control how failures should be handled by end of transaction. - options = t.GetFailureHandlingOptions() - - # deletes warnings captured - failureProcessor = eh.WarningSwallower() + with Transaction(doc, __title__) as t: + t.Start("03. Panelize parts") + # Provides access to option to control how failures should be handled by end of transaction. + options = t.GetFailureHandlingOptions() - # sets how failures should be handled during transaction - options.SetFailuresPreprocessor(failureProcessor) - t.SetFailureHandlingOptions(options) + # deletes warnings captured + failureProcessor = eh.WarningSwallower() - for reveal_index in reveal_indexes: - wall_sweep = p.create_reveal(host_wall_id, lap_type_id, reveal_index, side_of_wall) - status = t.Commit() + # sets how failures should be handled during transaction + options.SetFailuresPreprocessor(failureProcessor) + t.SetFailureHandlingOptions(options) - if status != TransactionStatus.Committed: - # if transaction has not been committed, this would result to an error - print("The transaction has not been committed") + for reveal_index in reveal_indexes: + wall_sweep = p.create_reveal(host_wall_id, lap_type_id, reveal_index, side_of_wall) + status = t.Commit() - except Exception as e: - print ('The following error has occurred on Transaction 03. Panelize parts : {}'.format(e)) + if status != TransactionStatus.Committed: + # if transaction has not been committed.Raise an error, the cause is that the centre index for + # the part could not be established correctly generating a wrong set of reveal indexes outside the panel + raise eh.CentreIndexError def auto_parts(__title__, part, displacement_distance, switch_option, multiple=True): @@ -233,13 +221,18 @@ def delete_element(__title__, *args): """ with Transaction(doc, __title__) as t: t.Start("02. Delete reveals") + options = t.GetFailureHandlingOptions() failureProcessor = eh.WarningSwallower() options.SetFailuresPreprocessor(failureProcessor) t.SetFailureHandlingOptions(options) for element_id in args: doc.Delete(element_id) - t.Commit() + status = t.Commit() + + if status != TransactionStatus.Committed: + # if transaction has not been rollback. Could not therefore delete elements + raise eh.DeleteElementsError # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> GRAPHICS TRANSACTIONS diff --git a/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py b/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py index 45a4021..ec6607d 100644 --- a/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py +++ b/panelization.tab/panelize.panel/AutoParts.pushbutton/script.py @@ -47,8 +47,8 @@ def main(): underpanelized, panalized, non_panelized_parts = g.sort_parts_by_length(all_parts) if len(non_panelized_parts) != 0: - switch_option = f.switch_option() - displacement_distance = f.displacement_distance_form() + switch_option = f.form_switch_panelization_direction() + displacement_distance = f.form_displacement_distance() for part in non_panelized_parts: try: a.auto_parts(__title__, part, displacement_distance, switch_option, multiple=True) diff --git a/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py b/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py index 996e99e..cd294d8 100644 --- a/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py +++ b/panelization.tab/panelize.panel/MultiParts.pushbutton/script.py @@ -24,7 +24,7 @@ from _create import _transactions as a from _create import _parts as p from _create import _errorhandler as eh -from _create import _forms as f +from _create import _forms as f from pyrevit import forms # VARIABLES @@ -42,22 +42,24 @@ def main(): parts = p.select_parts() - switch_option = f.switch_option() - displacement_distance = f.displacement_distance_form() + switch_option = f.form_switch_panelization_direction() + displacement_distance = f.form_displacement_distance() for part in parts: try: a.auto_parts(__title__, part, displacement_distance, switch_option, multiple=True) - except eh.CannotPanelizeError: - forms.alert('Select a Part to Panelize') - except eh.CannotSplitPanelError: + except eh.RevealNotCreatedError: + forms.alert('Reveal at coordinate 0 could not be created') + except eh.CentreIndexError: 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 eh.DeleteElementsError: + forms.alert('Error occurred. Could not delete reveals') + except eh.XYAxisPlaneNotEstablishedError: + forms.alert('Could not Panelize. Selected Part not on X or Y axis') except Exception: pass + if __name__ == "__main__": main() diff --git a/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py b/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py index 06084bb..8c25175 100644 --- a/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py +++ b/panelization.tab/panelize.panel/SinglePart.pushbutton/script.py @@ -22,10 +22,10 @@ from _create import _errorhandler as eh from _create import _forms as f import clr + clr.AddReference("System") from pyrevit import forms - # VARIABLES app = __revit__.Application # represents the Revit Autodesk Application doc = __revit__.ActiveUIDocument.Document # obj used to create new instances of elements within the active project @@ -40,23 +40,28 @@ def main(): try: part = g.select_part() - switch_option = f.switch_option() - displacement_distance = f.displacement_distance_form() + # switch direction of panelization + switch_option = f.form_switch_panelization_direction() + displacement_distance = f.form_displacement_distance() + a.auto_parts(__title__, part, displacement_distance, switch_option, multiple=True) - a.auto_parts(__title__, part, displacement_distance,switch_option, multiple=True) - except eh.CannotPanelizeError: - forms.alert('Select a Part to Panelize') - except eh.CannotSplitPanelError: + except eh.RevealNotCreatedError: + forms.alert('Reveal at coordinate 0 could not be created') + + except eh.CentreIndexError: 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 eh.XYAxisPlaneNotEstablishedError: + forms.alert('Could not Panelize. Selected Part not on X or Y axis') - except Exception: - forms.alert("Error occurred.Could not panelize selected Part.") + except eh.DeleteElementsError: + forms.alert('Error occurred. Could not delete reveals') + """except Exception: + forms.alert("Error occurred.Could not panelize selected Part.")""" if __name__ == "__main__": diff --git a/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py b/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py index 978825a..ee7ade5 100644 --- a/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py +++ b/panelization.tab/panelize.panel/SplitPart.pushbutton/script.py @@ -47,10 +47,14 @@ def main(): except eh.VariableDistanceNotFoundError: forms.alert("The variable distance could not be established") - + except eh.RevealNotCreatedError: + forms.alert('Reveal at coordinate 0 could not be created') + except eh.DeleteElementsError: + forms.alert('Error occurred. Could not delete reveals') + except eh.XYAxisPlaneNotEstablishedError: + forms.alert('Could not Panelize. Selected Part not on X or Y axis') except Exception: - forms.alert("Error occurred.Could not panelize") - + forms.alert("Error occurred.Could not split part") if __name__ == "__main__": main() diff --git a/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py b/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py index 3dbe7ee..9e45256 100644 --- a/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py +++ b/panelization.tab/takeoff.panel/Panelized.pushbutton/script.py @@ -151,7 +151,7 @@ def main(): selected_parts = underpanalized + panelized if len(selected_parts) != 0: - cost_per_sf = float(f.single_digit_value()) + cost_per_sf = float(f.form_estimated_cost()) # filter to parts that have been panelized parts_data = get_parts_data(selected_parts) @@ -164,7 +164,7 @@ def main(): "TOTAL AREA(SF)", "COST PER SF (USD)", " COST(USD)"] - f.display_form(final_data, header, "Parts Material Takeoff" + "-" + user_choice) + f.form_display_table(final_data, header, "Parts Material Takeoff" + "-" + user_choice) if len(unpanalized) != 0: g.highlight_unpanelized_underpanelized_parts(__title__) diff --git a/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py b/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py index b065b63..f43d895 100644 --- a/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py +++ b/panelization.tab/takeoff.panel/Unpanelized.pushbutton/script.py @@ -92,7 +92,7 @@ def main(): # 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;') + f.form_display_table(parts_data, header, "Unpanelized parts", last_line_color='color:blue;') else: forms.alert("Congratulations! All parts have been panelized")