From d41f03707c82c8f7604721455174e76f6b9fca7c Mon Sep 17 00:00:00 2001 From: melnikovalex Date: Fri, 11 Oct 2019 14:59:55 +0200 Subject: [PATCH 1/4] DRY-principle optimization --- .../Copy State.pushbutton/script.py | 218 ++---------- .../Paste State.pushbutton/script.py | 311 ++++-------------- .../lib/viewport_placement_utils.py | 179 ++++++++++ 3 files changed, 279 insertions(+), 429 deletions(-) create mode 100644 extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py index 8053cbdda..51d56aeac 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py @@ -1,13 +1,11 @@ -import os -import os.path as op import pickle from pyrevit import HOST_APP -from pyrevit.framework import List -from pyrevit import revit, DB, UI + +from pyrevit import revit, DB from pyrevit import forms from pyrevit import script - +import viewport_placement_utils as vpu __doc__ = 'Copies the state of desired parameter of the active'\ ' view to memory. e.g. Visibility Graphics settings or'\ @@ -15,12 +13,7 @@ __authors__ = ['Gui Talarico', '{{author}}'] - -class Point: - def __init__(self, x, y, z): - self.x = x - self.y = y - self.z = z +logger = script.get_logger() class BasePoint: @@ -29,37 +22,6 @@ def __init__(self): self.y = 0 -class BBox: - def __init__(self): - self.minx = 0 - self.miny = 0 - self.minz = 0 - self.maxx = 0 - self.maxy = 0 - self.maxz = 0 - - -class ViewOrient: - def __init__(self): - self.eyex = 0 - self.eyey = 0 - self.eyez = 0 - self.forwardx = 0 - self.forwardy = 0 - self.forwardz = 0 - self.upx = 0 - self.upy = 0 - self.upz = 0 - - -class TransformationMatrix: - def __init__(self): - self.sourcemin = None - self.sourcemax = None - self.destmin = None - self.destmax = None - - def make_picklable_list(curve_loops): all_cloops = [] for curve_loop in curve_loops: @@ -120,7 +82,7 @@ def make_picklable_list(curve_loops): sb = av.GetSectionBox() viewOrientation = av.GetOrientation() - sbox = BBox() + sbox = vpu.BBox() sbox.minx = sb.Min.X sbox.miny = sb.Min.Y sbox.minz = sb.Min.Z @@ -128,7 +90,7 @@ def make_picklable_list(curve_loops): sbox.maxy = sb.Max.Y sbox.maxz = sb.Max.Z - vo = ViewOrient() + vo = vpu.ViewOrient() vo.eyex = viewOrientation.EyePosition.X vo.eyey = viewOrientation.EyePosition.Y vo.eyez = viewOrientation.EyePosition.Z @@ -158,159 +120,45 @@ def make_picklable_list(curve_loops): pyrevit Notice: pyrevit: repository at https://github.com/eirannejad/pyrevit """ + vport = vpu.select_viewport() + originalviewtype = '' selview = selvp = None vpboundaryoffset = 0.01 activeSheet = revit.active_view - transmatrix = TransformationMatrix() - revtransmatrix = TransformationMatrix() - - def sheet_to_view_transform(sheetcoord): - global transmatrix - newx = \ - transmatrix.destmin.X \ - + (((sheetcoord.X - transmatrix.sourcemin.X) - * (transmatrix.destmax.X - transmatrix.destmin.X)) - / (transmatrix.sourcemax.X - transmatrix.sourcemin.X)) - - newy = \ - transmatrix.destmin.Y \ - + (((sheetcoord.Y - transmatrix.sourcemin.Y) - * (transmatrix.destmax.Y - transmatrix.destmin.Y)) - / (transmatrix.sourcemax.Y - transmatrix.sourcemin.Y)) - - return DB.XYZ(newx, newy, 0.0) - - def set_tansform_matrix(selvp, selview): - # making sure the cropbox is active. - cboxactive = selview.CropBoxActive - cboxvisible = selview.CropBoxVisible - cboxannoparam = selview.get_Parameter( - DB.BuiltInParameter.VIEWER_ANNOTATION_CROP_ACTIVE - ) - - cboxannostate = cboxannoparam.AsInteger() - curviewelements = DB.FilteredElementCollector(revit.doc)\ - .OwnedByView(selview.Id)\ - .WhereElementIsNotElementType()\ - .ToElements() - - viewspecificelements = [] - for el in curviewelements: - if el.ViewSpecific \ - and not el.IsHidden(selview) \ - and el.CanBeHidden(selview) \ - and el.Category is not None: - viewspecificelements.append(el.Id) - - basepoints = DB.FilteredElementCollector(revit.doc)\ - .OfClass(DB.BasePoint)\ - .WhereElementIsNotElementType()\ - .ToElements() - - excludecategories = ['Survey Point', - 'Project Base Point'] - for el in basepoints: - if el.Category and el.Category.Name in excludecategories: - viewspecificelements.append(el.Id) - - with revit.TransactionGroup('Activate & Read Cropbox Boundary'): - with revit.Transaction('Hiding all 2d elements'): - if viewspecificelements: - try: - selview.HideElements(List[DB.ElementId](viewspecificelements)) - except Exception as e: - logger.debug(e) - - with revit.Transaction('Activate & Read Cropbox Boundary'): - selview.CropBoxActive = True - selview.CropBoxVisible = False - cboxannoparam.Set(0) - - # get view min max points in modelUCS. - modelucsx = [] - modelucsy = [] - crsm = selview.GetCropRegionShapeManager() - - cllist = crsm.GetCropShape() - if len(cllist) == 1: - cl = cllist[0] - for l in cl: - modelucsx.append(l.GetEndPoint(0).X) - modelucsy.append(l.GetEndPoint(0).Y) - cropmin = DB.XYZ(min(modelucsx), min(modelucsy), 0.0) - cropmax = DB.XYZ(max(modelucsx), max(modelucsy), 0.0) - - # get vp min max points in sheetUCS - ol = selvp.GetBoxOutline() - vptempmin = ol.MinimumPoint - vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset, - vptempmin.Y + vpboundaryoffset, 0.0) - vptempmax = ol.MaximumPoint - vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, - vptempmax.Y - vpboundaryoffset, 0.0) - - transmatrix.sourcemin = vpmin - transmatrix.sourcemax = vpmax - transmatrix.destmin = cropmin - transmatrix.destmax = cropmax - - revtransmatrix.sourcemin = cropmin - revtransmatrix.sourcemax = cropmax - revtransmatrix.destmin = vpmin - revtransmatrix.destmax = vpmax - - selview.CropBoxActive = cboxactive - selview.CropBoxVisible = cboxvisible - cboxannoparam.Set(cboxannostate) - - if viewspecificelements: - selview.UnhideElements( - List[DB.ElementId](viewspecificelements) - ) + transmatrix = vpu.TransformationMatrix() + revtransmatrix = vpu.TransformationMatrix() datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', file_ext='pym', add_cmd_name=False) - selected_ids = revit.get_selection().element_ids - - if len(selected_ids) == 1: - vport_id = selected_ids[0] - try: - vport = revit.doc.GetElement(vport_id) - except Exception: - forms.alert('Select exactly one viewport.') - - if isinstance(vport, DB.Viewport): - view = revit.doc.GetElement(vport.ViewId) - if view is not None and isinstance(view, DB.ViewPlan): - with revit.TransactionGroup('Copy Viewport Location'): - set_tansform_matrix(vport, view) - center = vport.GetBoxCenter() - modelpoint = sheet_to_view_transform(center) - center_pt = Point(center.X, center.Y, center.Z) - model_pt = Point(modelpoint.X, modelpoint.Y, modelpoint.Z) - with open(datafile, 'wb') as fp: - originalviewtype = 'ViewPlan' - pickle.dump(originalviewtype, fp) - pickle.dump(center_pt, fp) - pickle.dump(model_pt, fp) - - elif view is not None and isinstance(view, DB.ViewDrafting): - center = vport.GetBoxCenter() - center_pt = Point(center.X, center.Y, center.Z) - with open(datafile, 'wb') as fp: - originalviewtype = 'ViewDrafting' - pickle.dump(originalviewtype, fp) - pickle.dump(center_pt, fp) - else: - forms.alert('This tool only works with Plan, ' - 'RCP, and Detail views and viewports.') + view = revit.doc.GetElement(vport.ViewId) + if view is not None and isinstance(view, DB.ViewPlan): + with revit.TransactionGroup('Copy Viewport Location'): + vpu.set_tansform_matrix(vport, view) + center = vport.GetBoxCenter() + modelpoint = vpu.sheet_to_view_transform(center) + center_pt = vpu.Point(center.X, center.Y, center.Z) + model_pt = vpu.Point(modelpoint.X, modelpoint.Y, modelpoint.Z) + with open(datafile, 'wb') as fp: + originalviewtype = 'ViewPlan' + pickle.dump(originalviewtype, fp) + pickle.dump(center_pt, fp) + pickle.dump(model_pt, fp) + + elif view is not None and isinstance(view, DB.ViewDrafting): + center = vport.GetBoxCenter() + center_pt = vpu.Point(center.X, center.Y, center.Z) + with open(datafile, 'wb') as fp: + originalviewtype = 'ViewDrafting' + pickle.dump(originalviewtype, fp) + pickle.dump(center_pt, fp) else: - forms.alert('Select exactly one viewport.') + forms.alert('This tool only works with Plan, ' + 'RCP, and Detail views and viewports.') elif selected_option == 'Visibility Graphics': datafile = \ diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py index fa7dd633a..6bf310445 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py @@ -1,13 +1,10 @@ -import os -import os.path as op import pickle from pyrevit import HOST_APP -from pyrevit.framework import List -from pyrevit import revit, DB, UI +from pyrevit import revit, DB from pyrevit import forms from pyrevit import script - +import viewport_placement_utils as vpu __doc__ = 'Applies the copied state to the active view. '\ 'This works in conjunction with the Copy State tool.' @@ -15,42 +12,6 @@ logger = script.get_logger() -class Point: - def __init__(self, x, y, z): - self.x = x - self.y = y - self.z = z - - -class BasePoint: - def __init__(self): - self.x = 0 - self.y = 0 - - -class BBox: - def __init__(self): - self.minx = 0 - self.miny = 0 - self.minz = 0 - self.maxx = 0 - self.maxy = 0 - self.maxz = 0 - - -class ViewOrient: - def __init__(self): - self.eyex = 0 - self.eyey = 0 - self.eyez = 0 - self.forwardx = 0 - self.forwardy = 0 - self.forwardz = 0 - self.upx = 0 - self.upy = 0 - self.upz = 0 - - class OriginalIsViewDrafting(Exception): pass @@ -59,14 +20,6 @@ class OriginalIsViewPlan(Exception): pass -class TransformationMatrix: - def __init__(self): - self.sourcemin = None - self.sourcemax = None - self.destmin = None - self.destmax = None - - def unpickle_line_list(all_cloops_data): all_cloops = [] for cloop_lines in all_cloops_data: @@ -163,215 +116,85 @@ def unpickle_line_list(all_cloops_data): pyrevit Notice: pyrevit: repository at https://github.com/eirannejad/pyrevit """ + vport = vpu.select_viewport() + PINAFTERSET = False originalviewtype = '' selview = selvp = None vpboundaryoffset = 0.01 activeSheet = revit.uidoc.ActiveGraphicalView - transmatrix = TransformationMatrix() - revtransmatrix = TransformationMatrix() - - def sheet_to_view_transform(sheetcoord): - global transmatrix - newx = \ - transmatrix.destmin.X \ - + (((sheetcoord.X - transmatrix.sourcemin.X) - * (transmatrix.destmax.X - transmatrix.destmin.X)) - / (transmatrix.sourcemax.X - transmatrix.sourcemin.X)) - - newy = \ - transmatrix.destmin.Y \ - + (((sheetcoord.Y - transmatrix.sourcemin.Y) - * (transmatrix.destmax.Y - transmatrix.destmin.Y)) - / (transmatrix.sourcemax.Y - transmatrix.sourcemin.Y)) - - return DB.XYZ(newx, newy, 0.0) - - def view_to_sheet_transform(modelcoord): - global revtransmatrix - newx = \ - revtransmatrix.destmin.X \ - + (((modelcoord.X - revtransmatrix.sourcemin.X) - * (revtransmatrix.destmax.X - revtransmatrix.destmin.X)) - / (revtransmatrix.sourcemax.X - revtransmatrix.sourcemin.X)) - - newy = \ - revtransmatrix.destmin.Y \ - + (((modelcoord.Y - revtransmatrix.sourcemin.Y) - * (revtransmatrix.destmax.Y - revtransmatrix.destmin.Y)) - / (revtransmatrix.sourcemax.Y - revtransmatrix.sourcemin.Y)) - - return DB.XYZ(newx, newy, 0.0) - - def set_tansform_matrix(selvp, selview): - # making sure the cropbox is active. - cboxactive = selview.CropBoxActive - cboxvisible = selview.CropBoxVisible - cboxannoparam = selview.get_Parameter( - DB.BuiltInParameter.VIEWER_ANNOTATION_CROP_ACTIVE - ) - cboxannostate = cboxannoparam.AsInteger() - curviewelements = \ - DB.FilteredElementCollector(revit.doc)\ - .OwnedByView(selview.Id)\ - .WhereElementIsNotElementType()\ - .ToElements() - - viewspecificelements = [] - for el in curviewelements: - if el.ViewSpecific \ - and not el.IsHidden(selview) \ - and el.CanBeHidden(selview) \ - and el.Category is not None: - viewspecificelements.append(el.Id) - - basepoints = DB.FilteredElementCollector(revit.doc)\ - .OfClass(DB.BasePoint)\ - .WhereElementIsNotElementType()\ - .ToElements() - - excludecategories = ['Survey Point', - 'Project Base Point'] - for el in basepoints: - if el.Category and el.Category.Name in excludecategories: - viewspecificelements.append(el.Id) - - with revit.TransactionGroup('Activate & Read Cropbox Boundary'): - with revit.Transaction('Hiding all 2d elements'): - if viewspecificelements: - try: - selview.HideElements(List[DB.ElementId](viewspecificelements)) - except Exception as e: - logger.debug(e) - - with revit.Transaction('Activate & Read Cropbox Boundary'): - selview.CropBoxActive = True - selview.CropBoxVisible = False - cboxannoparam.Set(0) - - # get view min max points in modelUCS. - modelucsx = [] - modelucsy = [] - crsm = selview.GetCropRegionShapeManager() - - cllist = crsm.GetCropShape() - if len(cllist) == 1: - cl = cllist[0] - for l in cl: - modelucsx.append(l.GetEndPoint(0).X) - modelucsy.append(l.GetEndPoint(0).Y) - cropmin = DB.XYZ(min(modelucsx), min(modelucsy), 0.0) - cropmax = DB.XYZ(max(modelucsx), max(modelucsy), 0.0) - - # get vp min max points in sheetUCS - ol = selvp.GetBoxOutline() - vptempmin = ol.MinimumPoint - vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset, - vptempmin.Y + vpboundaryoffset, 0.0) - vptempmax = ol.MaximumPoint - vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, - vptempmax.Y - vpboundaryoffset, 0.0) - - transmatrix.sourcemin = vpmin - transmatrix.sourcemax = vpmax - transmatrix.destmin = cropmin - transmatrix.destmax = cropmax - - revtransmatrix.sourcemin = cropmin - revtransmatrix.sourcemax = cropmax - revtransmatrix.destmin = vpmin - revtransmatrix.destmax = vpmax - - selview.CropBoxActive = cboxactive - selview.CropBoxVisible = cboxvisible - cboxannoparam.Set(cboxannostate) - - if viewspecificelements: - selview.UnhideElements( - List[DB.ElementId](viewspecificelements) - ) + transmatrix = vpu.TransformationMatrix() + revtransmatrix = vpu.TransformationMatrix() datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', file_ext='pym', add_cmd_name=False) - - selected_ids = revit.get_selection().element_ids - - if len(selected_ids) == 1: - vport_id = selected_ids[0] - try: - vport = revit.doc.GetElement(vport_id) - except Exception: - DB.TaskDialog.Show('pyrevit', - 'Select exactly one viewport.') - - if isinstance(vport, DB.Viewport): - view = revit.doc.GetElement(vport.ViewId) - if view is not None and isinstance(view, DB.ViewPlan): - with revit.TransactionGroup('Paste Viewport Location'): - set_tansform_matrix(vport, view) - try: - with open(datafile, 'rb') as fp: - originalviewtype = pickle.load(fp) - if originalviewtype == 'ViewPlan': - savedcen_pt = pickle.load(fp) - savedmdl_pt = pickle.load(fp) - else: - raise OriginalIsViewDrafting - except IOError: - forms.alert('Could not find saved viewport ' - 'placement.\n' - 'Copy a Viewport Placement first.') - except OriginalIsViewDrafting: - forms.alert('Viewport placement info is from a ' - 'drafting view and can not ' - 'be applied here.') + + view = revit.doc.GetElement(vport.ViewId) + if view is not None and isinstance(view, DB.ViewPlan): + with revit.TransactionGroup('Paste Viewport Location'): + vpu.set_tansform_matrix(vport, view, vpboundaryoffset) + try: + with open(datafile, 'rb') as fp: + originalviewtype = pickle.load(fp) + if originalviewtype == 'ViewPlan': + savedcen_pt = pickle.load(fp) + savedmdl_pt = pickle.load(fp) else: - savedcenter_pt = DB.XYZ(savedcen_pt.x, - savedcen_pt.y, - savedcen_pt.z) - savedmodel_pt = DB.XYZ(savedmdl_pt.x, - savedmdl_pt.y, - savedmdl_pt.z) - with revit.Transaction('Apply Viewport Placement'): - center = vport.GetBoxCenter() - centerdiff = \ - view_to_sheet_transform(savedmodel_pt) - center - vport.SetBoxCenter(savedcenter_pt - centerdiff) - if PINAFTERSET: - vport.Pinned = True - - elif view is not None and isinstance(view, DB.ViewDrafting): - try: - with open(datafile, 'rb') as fp: - originalviewtype = pickle.load(fp) - if originalviewtype == 'ViewDrafting': - savedcen_pt = pickle.load(fp) - else: - raise OriginalIsViewPlan - except IOError: - forms.alert('Could not find saved viewport ' - 'placement.\n' - 'Copy a Viewport Placement first.') - except OriginalIsViewPlan: - forms.alert('Viewport placement info is from ' - 'a model view and can not be ' - 'applied here.') - else: - savedcenter_pt = DB.XYZ(savedcen_pt.x, - savedcen_pt.y, - savedcen_pt.z) - with revit.Transaction('Apply Viewport Placement'): - vport.SetBoxCenter(savedcenter_pt) - if PINAFTERSET: - vport.Pinned = True + raise OriginalIsViewDrafting + except IOError: + forms.alert('Could not find saved viewport ' + 'placement.\n' + 'Copy a Viewport Placement first.') + except OriginalIsViewDrafting: + forms.alert('Viewport placement info is from a ' + 'drafting view and can not ' + 'be applied here.') else: - forms.alert('This tool only works with Plan, ' - 'RCP, and Detail views and viewports.') + savedcenter_pt = DB.XYZ(savedcen_pt.x, + savedcen_pt.y, + savedcen_pt.z) + savedmodel_pt = DB.XYZ(savedmdl_pt.x, + savedmdl_pt.y, + savedmdl_pt.z) + with revit.Transaction('Apply Viewport Placement'): + center = vport.GetBoxCenter() + centerdiff = \ + vpu.view_to_sheet_transform(savedmodel_pt) - center + vport.SetBoxCenter(savedcenter_pt - centerdiff) + if PINAFTERSET: + vport.Pinned = True + + elif view is not None and isinstance(view, DB.ViewDrafting): + try: + with open(datafile, 'rb') as fp: + originalviewtype = pickle.load(fp) + if originalviewtype == 'ViewDrafting': + savedcen_pt = pickle.load(fp) + else: + raise OriginalIsViewPlan + except IOError: + forms.alert('Could not find saved viewport ' + 'placement.\n' + 'Copy a Viewport Placement first.') + except OriginalIsViewPlan: + forms.alert('Viewport placement info is from ' + 'a model view and can not be ' + 'applied here.') + else: + savedcenter_pt = DB.XYZ(savedcen_pt.x, + savedcen_pt.y, + savedcen_pt.z) + with revit.Transaction('Apply Viewport Placement'): + vport.SetBoxCenter(savedcenter_pt) + if PINAFTERSET: + vport.Pinned = True else: - forms.alert('Select exactly one viewport.') + forms.alert('This tool only works with Plan, ' + 'RCP, and Detail views and viewports.') + elif selected_switch == 'Visibility Graphics': datafile = \ diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py new file mode 100644 index 000000000..206037d81 --- /dev/null +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py @@ -0,0 +1,179 @@ +from pyrevit import revit, script, forms, DB +from pyrevit.framework import List + +logger = script.get_logger() + +class Point: + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + +class BBox: + def __init__(self): + self.minx = 0 + self.miny = 0 + self.minz = 0 + self.maxx = 0 + self.maxy = 0 + self.maxz = 0 + + +class ViewOrient: + def __init__(self): + self.eyex = 0 + self.eyey = 0 + self.eyez = 0 + self.forwardx = 0 + self.forwardy = 0 + self.forwardz = 0 + self.upx = 0 + self.upy = 0 + self.upz = 0 + + + +class TransformationMatrix: + def __init__(self): + self.sourcemin = None + self.sourcemax = None + self.destmin = None + self.destmax = None + + +def sheet_to_view_transform(sheetcoord): + global transmatrix + newx = \ + transmatrix.destmin.X \ + + (((sheetcoord.X - transmatrix.sourcemin.X) + * (transmatrix.destmax.X - transmatrix.destmin.X)) + / (transmatrix.sourcemax.X - transmatrix.sourcemin.X)) + + newy = \ + transmatrix.destmin.Y \ + + (((sheetcoord.Y - transmatrix.sourcemin.Y) + * (transmatrix.destmax.Y - transmatrix.destmin.Y)) + / (transmatrix.sourcemax.Y - transmatrix.sourcemin.Y)) + + return DB.XYZ(newx, newy, 0.0) + + +def view_to_sheet_transform(modelcoord): + global revtransmatrix + newx = \ + revtransmatrix.destmin.X \ + + (((modelcoord.X - revtransmatrix.sourcemin.X) + * (revtransmatrix.destmax.X - revtransmatrix.destmin.X)) + / (revtransmatrix.sourcemax.X - revtransmatrix.sourcemin.X)) + + newy = \ + revtransmatrix.destmin.Y \ + + (((modelcoord.Y - revtransmatrix.sourcemin.Y) + * (revtransmatrix.destmax.Y - revtransmatrix.destmin.Y)) + / (revtransmatrix.sourcemax.Y - revtransmatrix.sourcemin.Y)) + + return DB.XYZ(newx, newy, 0.0) + + +def set_tansform_matrix(selvp, selview, vpboundaryoffset): + # making sure the cropbox is active. + cboxactive = selview.CropBoxActive + cboxvisible = selview.CropBoxVisible + cboxannoparam = selview.get_Parameter( + DB.BuiltInParameter.VIEWER_ANNOTATION_CROP_ACTIVE + ) + cboxannostate = cboxannoparam.AsInteger() + curviewelements = \ + DB.FilteredElementCollector(revit.doc)\ + .OwnedByView(selview.Id)\ + .WhereElementIsNotElementType()\ + .ToElements() + + viewspecificelements = [] + for el in curviewelements: + if el.ViewSpecific \ + and not el.IsHidden(selview) \ + and el.CanBeHidden(selview) \ + and el.Category is not None: + viewspecificelements.append(el.Id) + + basepoints = DB.FilteredElementCollector(revit.doc)\ + .OfClass(DB.BasePoint)\ + .WhereElementIsNotElementType()\ + .ToElements() + + excludecategories = ['Survey Point', + 'Project Base Point'] + for el in basepoints: + if el.Category and el.Category.Name in excludecategories: + viewspecificelements.append(el.Id) + + with revit.TransactionGroup('Activate & Read Cropbox Boundary'): + with revit.Transaction('Hiding all 2d elements'): + if viewspecificelements: + try: + selview.HideElements(List[DB.ElementId](viewspecificelements)) + except Exception as e: + logger.debug(e) + + with revit.Transaction('Activate & Read Cropbox Boundary'): + selview.CropBoxActive = True + selview.CropBoxVisible = False + cboxannoparam.Set(0) + + # get view min max points in modelUCS. + modelucsx = [] + modelucsy = [] + crsm = selview.GetCropRegionShapeManager() + + cllist = crsm.GetCropShape() + if len(cllist) == 1: + cl = cllist[0] + for l in cl: + modelucsx.append(l.GetEndPoint(0).X) + modelucsy.append(l.GetEndPoint(0).Y) + cropmin = DB.XYZ(min(modelucsx), min(modelucsy), 0.0) + cropmax = DB.XYZ(max(modelucsx), max(modelucsy), 0.0) + + # get vp min max points in sheetUCS + ol = selvp.GetBoxOutline() + vptempmin = ol.MinimumPoint + vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset, + vptempmin.Y + vpboundaryoffset, 0.0) + vptempmax = ol.MaximumPoint + vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, + vptempmax.Y - vpboundaryoffset, 0.0) + + transmatrix.sourcemin = vpmin + transmatrix.sourcemax = vpmax + transmatrix.destmin = cropmin + transmatrix.destmax = cropmax + + revtransmatrix.sourcemin = cropmin + revtransmatrix.sourcemax = cropmax + revtransmatrix.destmin = vpmin + revtransmatrix.destmax = vpmax + + selview.CropBoxActive = cboxactive + selview.CropBoxVisible = cboxvisible + cboxannoparam.Set(cboxannostate) + + if viewspecificelements: + selview.UnhideElements(List[DB.ElementId](viewspecificelements)) + + +def select_viewport(): + vport = None + selected_ids = revit.get_selection().element_ids + if selected_ids: + vport_id = selected_ids[0] + try: + vport = revit.doc.GetElement(vport_id) + except: + pass + if not isinstance(vport_id, DB.Viewport): + vport = None + if not vport: + forms.alert('Select exactly one viewport.', exitscript=True) + return vport \ No newline at end of file From ab488170423e8906141eeb646f6057b7e1bc723a Mon Sep 17 00:00:00 2001 From: melnikovalex Date: Fri, 11 Oct 2019 15:48:49 +0200 Subject: [PATCH 2/4] Reduce redundant methods --- .../Copy State.pushbutton/script.py | 6 +- .../Paste State.pushbutton/script.py | 6 +- .../lib/viewport_placement_utils.py | 68 +++++++------------ 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py index 51d56aeac..1ba9e4bac 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py @@ -127,8 +127,6 @@ def make_picklable_list(curve_loops): selview = selvp = None vpboundaryoffset = 0.01 activeSheet = revit.active_view - transmatrix = vpu.TransformationMatrix() - revtransmatrix = vpu.TransformationMatrix() datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', @@ -138,9 +136,9 @@ def make_picklable_list(curve_loops): view = revit.doc.GetElement(vport.ViewId) if view is not None and isinstance(view, DB.ViewPlan): with revit.TransactionGroup('Copy Viewport Location'): - vpu.set_tansform_matrix(vport, view) + transmatrix = vpu.set_tansform_matrix(vport, view, vpboundaryoffset) center = vport.GetBoxCenter() - modelpoint = vpu.sheet_to_view_transform(center) + modelpoint = vpu.transform_by_matrix(center, transmatrix) center_pt = vpu.Point(center.X, center.Y, center.Z) model_pt = vpu.Point(modelpoint.X, modelpoint.Y, modelpoint.Z) with open(datafile, 'wb') as fp: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py index 6bf310445..997e68040 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py @@ -124,8 +124,6 @@ def unpickle_line_list(all_cloops_data): selview = selvp = None vpboundaryoffset = 0.01 activeSheet = revit.uidoc.ActiveGraphicalView - transmatrix = vpu.TransformationMatrix() - revtransmatrix = vpu.TransformationMatrix() datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', @@ -135,7 +133,7 @@ def unpickle_line_list(all_cloops_data): view = revit.doc.GetElement(vport.ViewId) if view is not None and isinstance(view, DB.ViewPlan): with revit.TransactionGroup('Paste Viewport Location'): - vpu.set_tansform_matrix(vport, view, vpboundaryoffset) + revtransmatrix = vpu.set_tansform_matrix(vport, view, vpboundaryoffset, reverse=True) try: with open(datafile, 'rb') as fp: originalviewtype = pickle.load(fp) @@ -162,7 +160,7 @@ def unpickle_line_list(all_cloops_data): with revit.Transaction('Apply Viewport Placement'): center = vport.GetBoxCenter() centerdiff = \ - vpu.view_to_sheet_transform(savedmodel_pt) - center + vpu.transform_by_matrix(savedmodel_pt, revtransmatrix) - center vport.SetBoxCenter(savedcenter_pt - centerdiff) if PINAFTERSET: vport.Pinned = True diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py index 206037d81..7c4081a6c 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py @@ -42,41 +42,24 @@ def __init__(self): self.destmax = None -def sheet_to_view_transform(sheetcoord): - global transmatrix +def transform_by_matrix(coord, transmatrix): newx = \ transmatrix.destmin.X \ - + (((sheetcoord.X - transmatrix.sourcemin.X) + + (((coord.X - transmatrix.sourcemin.X) * (transmatrix.destmax.X - transmatrix.destmin.X)) / (transmatrix.sourcemax.X - transmatrix.sourcemin.X)) newy = \ transmatrix.destmin.Y \ - + (((sheetcoord.Y - transmatrix.sourcemin.Y) + + (((coord.Y - transmatrix.sourcemin.Y) * (transmatrix.destmax.Y - transmatrix.destmin.Y)) / (transmatrix.sourcemax.Y - transmatrix.sourcemin.Y)) return DB.XYZ(newx, newy, 0.0) -def view_to_sheet_transform(modelcoord): - global revtransmatrix - newx = \ - revtransmatrix.destmin.X \ - + (((modelcoord.X - revtransmatrix.sourcemin.X) - * (revtransmatrix.destmax.X - revtransmatrix.destmin.X)) - / (revtransmatrix.sourcemax.X - revtransmatrix.sourcemin.X)) - - newy = \ - revtransmatrix.destmin.Y \ - + (((modelcoord.Y - revtransmatrix.sourcemin.Y) - * (revtransmatrix.destmax.Y - revtransmatrix.destmin.Y)) - / (revtransmatrix.sourcemax.Y - revtransmatrix.sourcemin.Y)) - - return DB.XYZ(newx, newy, 0.0) - - -def set_tansform_matrix(selvp, selview, vpboundaryoffset): +def set_tansform_matrix(selvp, selview, vpboundaryoffset, reverse=False): + transmatrix = TransformationMatrix() # making sure the cropbox is active. cboxactive = selview.CropBoxActive cboxvisible = selview.CropBoxVisible @@ -145,15 +128,10 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset): vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, vptempmax.Y - vpboundaryoffset, 0.0) - transmatrix.sourcemin = vpmin - transmatrix.sourcemax = vpmax - transmatrix.destmin = cropmin - transmatrix.destmax = cropmax - - revtransmatrix.sourcemin = cropmin - revtransmatrix.sourcemax = cropmax - revtransmatrix.destmin = vpmin - revtransmatrix.destmax = vpmax + transmatrix.sourcemin = cropmin if reverse else vpmin + transmatrix.sourcemax = cropmax if reverse else vpmax + transmatrix.destmin = vpmin if reverse else cropmin + transmatrix.destmax = vpmax if reverse else cropmax selview.CropBoxActive = cboxactive selview.CropBoxVisible = cboxvisible @@ -161,19 +139,25 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset): if viewspecificelements: selview.UnhideElements(List[DB.ElementId](viewspecificelements)) - + return transmatrix def select_viewport(): vport = None - selected_ids = revit.get_selection().element_ids - if selected_ids: - vport_id = selected_ids[0] - try: - vport = revit.doc.GetElement(vport_id) - except: - pass - if not isinstance(vport_id, DB.Viewport): - vport = None + selected_els = revit.get_selection().elements + if selected_els and isinstance(selected_els[0], DB.Viewport): + vport = selected_els[0] if not vport: forms.alert('Select exactly one viewport.', exitscript=True) - return vport \ No newline at end of file + return vport + + +def get_title_block_placement(sheet): + # get all title blocks on the sheet + cl = DB.FilteredElementCollector(revit.doc, sheet.Id). \ + WhereElementIsNotElementType(). \ + OfCategory(DB.BuiltInCategory.OST_TitleBlocks) + title_blocks = cl.ToElements() + if len(title_blocks) != 1: + return + + return title_blocks[0].Location.Point From 4b5d288aeee16b48e7ecf42fdbb42779f1275f4b Mon Sep 17 00:00:00 2001 From: melnikovalex Date: Mon, 14 Oct 2019 12:21:37 +0200 Subject: [PATCH 3/4] Support sheets with shifted title block location --- .../Copy State.pushbutton/script.py | 30 ++-- .../Paste State.pushbutton/script.py | 35 +++-- .../lib/viewport_placement_utils.py | 145 ++++++++++-------- 3 files changed, 119 insertions(+), 91 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py index 1ba9e4bac..5dc20177c 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py @@ -112,7 +112,7 @@ def make_picklable_list(curve_loops): """ Copyright (c) 2016 Gui Talarico - CopyPasteViewportPlacemenet + CopyPasteViewportPlacement Copy and paste the placement of viewports across sheets github.com/gtalarico @@ -124,20 +124,20 @@ def make_picklable_list(curve_loops): originalviewtype = '' - selview = selvp = None - vpboundaryoffset = 0.01 - activeSheet = revit.active_view - datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', file_ext='pym', add_cmd_name=False) view = revit.doc.GetElement(vport.ViewId) - if view is not None and isinstance(view, DB.ViewPlan): + if isinstance(view, DB.ViewPlan): + with revit.DryTransaction('Activate & Read Cropbox Boundary'): + transmatrix = vpu.set_tansform_matrix(vport, view) with revit.TransactionGroup('Copy Viewport Location'): - transmatrix = vpu.set_tansform_matrix(vport, view, vpboundaryoffset) - center = vport.GetBoxCenter() + title_block_pt = vpu.get_title_block_placement_by_vp(vport) + # Vport center on a sheet (sheet UCS) + center = vport.GetBoxCenter() - title_block_pt + # Vport center on a sheet (model UCS) modelpoint = vpu.transform_by_matrix(center, transmatrix) center_pt = vpu.Point(center.X, center.Y, center.Z) model_pt = vpu.Point(modelpoint.X, modelpoint.Y, modelpoint.Z) @@ -147,16 +147,13 @@ def make_picklable_list(curve_loops): pickle.dump(center_pt, fp) pickle.dump(model_pt, fp) - elif view is not None and isinstance(view, DB.ViewDrafting): + elif isinstance(view, DB.ViewDrafting): center = vport.GetBoxCenter() center_pt = vpu.Point(center.X, center.Y, center.Z) with open(datafile, 'wb') as fp: originalviewtype = 'ViewDrafting' pickle.dump(originalviewtype, fp) pickle.dump(center_pt, fp) - else: - forms.alert('This tool only works with Plan, ' - 'RCP, and Detail views and viewports.') elif selected_option == 'Visibility Graphics': datafile = \ @@ -176,7 +173,12 @@ def make_picklable_list(curve_loops): file_ext='pym', add_cmd_name=False) - av = revit.active_view + selected_els = revit.get_selection().elements + if selected_els and isinstance(selected_els[0], DB.Viewport): + vport = selected_els[0] + av = revit.doc.GetElement(vport.ViewId) + else: + av = revit.activeview # FIXME crsm = av.GetCropRegionShapeManager() crsm_valid = False @@ -194,3 +196,5 @@ def make_picklable_list(curve_loops): if curve_loops: pickle.dump(make_picklable_list(curve_loops), f) + else: + logger.error("Crop regions is not valid") \ No newline at end of file diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py index 997e68040..8fcaeb828 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py @@ -108,7 +108,7 @@ def unpickle_line_list(all_cloops_data): """ Copyright (c) 2016 Gui Talarico - CopyPasteViewportPlacemenet + CopyPasteViewportPlacement Copy and paste the placement of viewports across sheets github.com/gtalarico @@ -121,19 +121,16 @@ def unpickle_line_list(all_cloops_data): PINAFTERSET = False originalviewtype = '' - selview = selvp = None - vpboundaryoffset = 0.01 - activeSheet = revit.uidoc.ActiveGraphicalView - datafile = \ script.get_document_data_file(file_id='SaveViewportLocation', file_ext='pym', add_cmd_name=False) view = revit.doc.GetElement(vport.ViewId) - if view is not None and isinstance(view, DB.ViewPlan): + if isinstance(view, DB.ViewPlan): + with revit.DryTransaction('Activate & Read Cropbox Boundary'): + revtransmatrix = vpu.set_tansform_matrix(vport, view, reverse=True) with revit.TransactionGroup('Paste Viewport Location'): - revtransmatrix = vpu.set_tansform_matrix(vport, view, vpboundaryoffset, reverse=True) try: with open(datafile, 'rb') as fp: originalviewtype = pickle.load(fp) @@ -151,21 +148,24 @@ def unpickle_line_list(all_cloops_data): 'drafting view and can not ' 'be applied here.') else: + title_block_pt = vpu.get_title_block_placement_by_vp(vport) savedcenter_pt = DB.XYZ(savedcen_pt.x, savedcen_pt.y, - savedcen_pt.z) + savedcen_pt.z) + title_block_pt savedmodel_pt = DB.XYZ(savedmdl_pt.x, savedmdl_pt.y, savedmdl_pt.z) with revit.Transaction('Apply Viewport Placement'): + # target vp center (sheet UCS) center = vport.GetBoxCenter() + # source vp center (sheet UCS) - target center centerdiff = \ vpu.transform_by_matrix(savedmodel_pt, revtransmatrix) - center - vport.SetBoxCenter(savedcenter_pt - centerdiff) + vport.SetBoxCenter(savedcenter_pt) if PINAFTERSET: vport.Pinned = True - elif view is not None and isinstance(view, DB.ViewDrafting): + elif isinstance(view, DB.ViewDrafting): try: with open(datafile, 'rb') as fp: originalviewtype = pickle.load(fp) @@ -189,10 +189,6 @@ def unpickle_line_list(all_cloops_data): vport.SetBoxCenter(savedcenter_pt) if PINAFTERSET: vport.Pinned = True - else: - forms.alert('This tool only works with Plan, ' - 'RCP, and Detail views and viewports.') - elif selected_switch == 'Visibility Graphics': datafile = \ @@ -217,14 +213,19 @@ def unpickle_line_list(all_cloops_data): script.get_document_data_file(file_id='SaveCropRegionState', file_ext='pym', add_cmd_name=False) - + selected_els = revit.get_selection().elements + if selected_els and isinstance(selected_els[0], DB.Viewport): + vport = selected_els[0] + av = revit.doc.GetElement(vport.ViewId) + else: + av = revit.activeview # FIXME try: f = open(datafile, 'r') cloops_data = pickle.load(f) f.close() with revit.Transaction('Paste Crop Region'): - revit.active_view.CropBoxVisible = True - crsm = revit.active_view.GetCropRegionShapeManager() + av.CropBoxVisible = True # FIXME + crsm = av.GetCropRegionShapeManager() # FIXME all_cloops = unpickle_line_list(cloops_data) for cloop in all_cloops: if HOST_APP.is_newer_than(2015): diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py index 7c4081a6c..0d6d55524 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py @@ -58,15 +58,16 @@ def transform_by_matrix(coord, transmatrix): return DB.XYZ(newx, newy, 0.0) -def set_tansform_matrix(selvp, selview, vpboundaryoffset, reverse=False): +def set_tansform_matrix(selvp, selview, vpboundaryoffset=0, reverse=False): + # TODO support alignment by project basepoint, not by cropbox + # TODO support sections + # TODO allow to run with view activated instead of viewport selected + # TODO paste on many views at once transmatrix = TransformationMatrix() # making sure the cropbox is active. - cboxactive = selview.CropBoxActive - cboxvisible = selview.CropBoxVisible cboxannoparam = selview.get_Parameter( DB.BuiltInParameter.VIEWER_ANNOTATION_CROP_ACTIVE ) - cboxannostate = cboxannoparam.AsInteger() curviewelements = \ DB.FilteredElementCollector(revit.doc)\ .OwnedByView(selview.Id)\ @@ -78,67 +79,75 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset, reverse=False): if el.ViewSpecific \ and not el.IsHidden(selview) \ and el.CanBeHidden(selview) \ - and el.Category is not None: + and el.Category: viewspecificelements.append(el.Id) - basepoints = DB.FilteredElementCollector(revit.doc)\ - .OfClass(DB.BasePoint)\ - .WhereElementIsNotElementType()\ + hide_elements_categories = [ + DB.BuiltInCategory.OST_SharedBasePoint, + DB.BuiltInCategory.OST_ProjectBasePoint, + DB.BuiltInCategory.OST_Viewers, + DB.BuiltInCategory.OST_ReferenceLines, + DB.BuiltInCategory.OST_Grids, + DB.BuiltInCategory.OST_Elev + ] + hide_elements_filters = [] + for cat in hide_elements_categories: + hide_elements_filters.append(DB.ElementCategoryFilter(cat)) + + hide_elements_filter = DB.LogicalOrFilter(hide_elements_filters) + hide_elements = DB.FilteredElementCollector(revit.doc) \ + .WherePasses(hide_elements_filter) \ + .WhereElementIsNotElementType() \ .ToElements() - - excludecategories = ['Survey Point', - 'Project Base Point'] - for el in basepoints: - if el.Category and el.Category.Name in excludecategories: + for el in hide_elements: + if el.Category\ + and not el.IsHidden(selview) \ + and el.CanBeHidden(selview): + print("hide", el.Category.Name) viewspecificelements.append(el.Id) - with revit.TransactionGroup('Activate & Read Cropbox Boundary'): - with revit.Transaction('Hiding all 2d elements'): - if viewspecificelements: - try: - selview.HideElements(List[DB.ElementId](viewspecificelements)) - except Exception as e: - logger.debug(e) - - with revit.Transaction('Activate & Read Cropbox Boundary'): - selview.CropBoxActive = True - selview.CropBoxVisible = False - cboxannoparam.Set(0) - - # get view min max points in modelUCS. - modelucsx = [] - modelucsy = [] - crsm = selview.GetCropRegionShapeManager() - - cllist = crsm.GetCropShape() - if len(cllist) == 1: - cl = cllist[0] - for l in cl: - modelucsx.append(l.GetEndPoint(0).X) - modelucsy.append(l.GetEndPoint(0).Y) - cropmin = DB.XYZ(min(modelucsx), min(modelucsy), 0.0) - cropmax = DB.XYZ(max(modelucsx), max(modelucsy), 0.0) - - # get vp min max points in sheetUCS - ol = selvp.GetBoxOutline() - vptempmin = ol.MinimumPoint - vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset, - vptempmin.Y + vpboundaryoffset, 0.0) - vptempmax = ol.MaximumPoint - vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, - vptempmax.Y - vpboundaryoffset, 0.0) - - transmatrix.sourcemin = cropmin if reverse else vpmin - transmatrix.sourcemax = cropmax if reverse else vpmax - transmatrix.destmin = vpmin if reverse else cropmin - transmatrix.destmax = vpmax if reverse else cropmax - - selview.CropBoxActive = cboxactive - selview.CropBoxVisible = cboxvisible - cboxannoparam.Set(cboxannostate) - - if viewspecificelements: - selview.UnhideElements(List[DB.ElementId](viewspecificelements)) + + if viewspecificelements: + try: + selview.HideElements(List[DB.ElementId](viewspecificelements)) + except Exception as e: + logger.debug(e) + + selview.CropBoxActive = True + selview.CropBoxVisible = False + if not cboxannoparam.IsReadOnly: + cboxannoparam.Set(0) + + # get view min max points in modelUCS. + modelucsx = [] + modelucsy = [] + crsm = selview.GetCropRegionShapeManager() + + cllist = crsm.GetCropShape() + if len(cllist) == 1: + cl = cllist[0] + for l in cl: + modelucsx.append(l.GetEndPoint(0).X) + modelucsy.append(l.GetEndPoint(0).Y) + cropmin = DB.XYZ(min(modelucsx), min(modelucsy), 0.0) + cropmax = DB.XYZ(max(modelucsx), max(modelucsy), 0.0) + + # get vp min max points in sheetUCS + ol = selvp.GetBoxOutline() + vptempmin = ol.MinimumPoint # in viewport units + vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset , + vptempmin.Y + vpboundaryoffset, + 0.0) + vptempmax = ol.MaximumPoint + vpmax = DB.XYZ(vptempmax.X - vpboundaryoffset, + vptempmax.Y - vpboundaryoffset, + 0.0) + + transmatrix.sourcemin = cropmin if reverse else vpmin + transmatrix.sourcemax = cropmax if reverse else vpmax + transmatrix.destmin = vpmin if reverse else cropmin + transmatrix.destmax = vpmax if reverse else cropmax + return transmatrix def select_viewport(): @@ -148,12 +157,26 @@ def select_viewport(): vport = selected_els[0] if not vport: forms.alert('Select exactly one viewport.', exitscript=True) + + view = revit.doc.GetElement(vport.ViewId) + if not view and not(isinstance(view, DB.ViewPlan) or isinstance(view, DB.ViewDrafting)): + forms.alert('This tool only works with Plan, ' + 'RCP, and Detail views and viewports.', exitscript=True) return vport +def get_title_block_placement_by_vp(viewport): + title_block_pt = None + if viewport.SheetId and viewport.SheetId != DB.ElementId.InvalidElementId: + title_block_pt = get_title_block_placement( + viewport.Document.GetElement(viewport.SheetId)) + if not title_block_pt: + title_block_pt = DB.XYZ.Zero + return title_block_pt + def get_title_block_placement(sheet): # get all title blocks on the sheet - cl = DB.FilteredElementCollector(revit.doc, sheet.Id). \ + cl = DB.FilteredElementCollector(sheet.Document, sheet.Id). \ WhereElementIsNotElementType(). \ OfCategory(DB.BuiltInCategory.OST_TitleBlocks) title_blocks = cl.ToElements() From b2fca81185c66ba6f148591415240aa16bc3b2ab Mon Sep 17 00:00:00 2001 From: melnikovalex Date: Mon, 14 Oct 2019 17:55:39 +0200 Subject: [PATCH 4/4] Copy viewport position by Project Base Point --- .../Copy State.pushbutton/script.py | 39 +++++++----- .../Paste State.pushbutton/script.py | 63 ++++++++++--------- .../lib/viewport_placement_utils.py | 58 +++++++++++++++-- 3 files changed, 110 insertions(+), 50 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py index 5dc20177c..767582bc1 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Copy State.pushbutton/script.py @@ -1,7 +1,5 @@ import pickle -from pyrevit import HOST_APP - from pyrevit import revit, DB from pyrevit import forms from pyrevit import script @@ -131,8 +129,23 @@ def make_picklable_list(curve_loops): view = revit.doc.GetElement(vport.ViewId) if isinstance(view, DB.ViewPlan): + # TODO ask use to choose a mode + # if SectionBoxes either None + # and CropRegions (and SectionBoxes) are not identical + # and ViewNormal are identical + # (optional) if difference between CropRegions is too big + # TODO use LeftTop alignment by default, + # choose CropBox alignment (LeftTop, RightTop etc.) + use_base_point = forms.CommandSwitchWindow.show( + ['Crop Box','Project Base Point'], + message='Select alignment' + ) == 'Project Base Point' with revit.DryTransaction('Activate & Read Cropbox Boundary'): transmatrix = vpu.set_tansform_matrix(vport, view) + if use_base_point: + crop_region_curves = vpu.get_crop_region(view) + else: + crop_region_curves = None with revit.TransactionGroup('Copy Viewport Location'): title_block_pt = vpu.get_title_block_placement_by_vp(vport) # Vport center on a sheet (sheet UCS) @@ -146,6 +159,10 @@ def make_picklable_list(curve_loops): pickle.dump(originalviewtype, fp) pickle.dump(center_pt, fp) pickle.dump(model_pt, fp) + if crop_region_curves: + pickle.dump(make_picklable_list(crop_region_curves), fp) + else: + pickle.dump(None, fp) elif isinstance(view, DB.ViewDrafting): center = vport.GetBoxCenter() @@ -179,22 +196,10 @@ def make_picklable_list(curve_loops): av = revit.doc.GetElement(vport.ViewId) else: av = revit.activeview # FIXME - crsm = av.GetCropRegionShapeManager() + curve_loops = vpu.get_crop_region(av) - crsm_valid = False - if HOST_APP.is_newer_than(2015): - crsm_valid = crsm.CanHaveShape - else: - crsm_valid = crsm.Valid - - if crsm_valid: + if curve_loops: with open(datafile, 'w') as f: - if HOST_APP.is_newer_than(2015): - curve_loops = list(crsm.GetCropShape()) - else: - curve_loops = [crsm.GetCropRegionShape()] - - if curve_loops: - pickle.dump(make_picklable_list(curve_loops), f) + pickle.dump(make_picklable_list(curve_loops), f) else: logger.error("Crop regions is not valid") \ No newline at end of file diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py index 8fcaeb828..1b3f7617f 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/Paste State.pushbutton/script.py @@ -1,6 +1,5 @@ import pickle -from pyrevit import HOST_APP from pyrevit import revit, DB from pyrevit import forms from pyrevit import script @@ -128,26 +127,35 @@ def unpickle_line_list(all_cloops_data): view = revit.doc.GetElement(vport.ViewId) if isinstance(view, DB.ViewPlan): - with revit.DryTransaction('Activate & Read Cropbox Boundary'): - revtransmatrix = vpu.set_tansform_matrix(vport, view, reverse=True) - with revit.TransactionGroup('Paste Viewport Location'): - try: - with open(datafile, 'rb') as fp: - originalviewtype = pickle.load(fp) - if originalviewtype == 'ViewPlan': - savedcen_pt = pickle.load(fp) - savedmdl_pt = pickle.load(fp) - else: - raise OriginalIsViewDrafting - except IOError: - forms.alert('Could not find saved viewport ' - 'placement.\n' - 'Copy a Viewport Placement first.') - except OriginalIsViewDrafting: - forms.alert('Viewport placement info is from a ' - 'drafting view and can not ' - 'be applied here.') - else: + try: + with open(datafile, 'rb') as fp: + originalviewtype = pickle.load(fp) + if originalviewtype == 'ViewPlan': + savedcen_pt = pickle.load(fp) + savedmdl_pt = pickle.load(fp) + crop_region_saved = pickle.load(fp) + else: + raise OriginalIsViewDrafting + except IOError: + forms.alert('Could not find saved viewport ' + 'placement.\n' + 'Copy a Viewport Placement first.') + except OriginalIsViewDrafting: + forms.alert('Viewport placement info is from a ' + 'drafting view and can not ' + 'be applied here.') + else: + with revit.TransactionGroup('Paste Viewport Location'): + crop_active_saved = view.CropBoxActive + if crop_region_saved: + with revit.Transaction('Temporary set saved crop region'): + view.CropBoxActive = True + crop_region_relevant = vpu.get_crop_region(view) + vpu.set_crop_region(view, unpickle_line_list(crop_region_saved)) + else: + crop_region_relevant = None + with revit.DryTransaction('Activate & Read Cropbox Boundary'): + revtransmatrix = vpu.set_tansform_matrix(vport, view, reverse=True) title_block_pt = vpu.get_title_block_placement_by_vp(vport) savedcenter_pt = DB.XYZ(savedcen_pt.x, savedcen_pt.y, @@ -155,6 +163,7 @@ def unpickle_line_list(all_cloops_data): savedmodel_pt = DB.XYZ(savedmdl_pt.x, savedmdl_pt.y, savedmdl_pt.z) + with revit.Transaction('Apply Viewport Placement'): # target vp center (sheet UCS) center = vport.GetBoxCenter() @@ -164,6 +173,10 @@ def unpickle_line_list(all_cloops_data): vport.SetBoxCenter(savedcenter_pt) if PINAFTERSET: vport.Pinned = True + if crop_region_relevant: + with revit.Transaction('Recover crop region'): + view.CropBoxActive = crop_active_saved + vpu.set_crop_region(view, crop_region_relevant) elif isinstance(view, DB.ViewDrafting): try: @@ -224,14 +237,8 @@ def unpickle_line_list(all_cloops_data): cloops_data = pickle.load(f) f.close() with revit.Transaction('Paste Crop Region'): - av.CropBoxVisible = True # FIXME - crsm = av.GetCropRegionShapeManager() # FIXME all_cloops = unpickle_line_list(cloops_data) - for cloop in all_cloops: - if HOST_APP.is_newer_than(2015): - crsm.SetCropShape(cloop) - else: - crsm.SetCropRegionShape(cloop) + vpu.set_crop_region(av, all_cloops) revit.uidoc.RefreshActiveView() except Exception: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py index 0d6d55524..2eb242036 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/memo.stack/lib/viewport_placement_utils.py @@ -1,5 +1,6 @@ from pyrevit import revit, script, forms, DB from pyrevit.framework import List +from pyrevit import HOST_APP logger = script.get_logger() @@ -58,12 +59,12 @@ def transform_by_matrix(coord, transmatrix): return DB.XYZ(newx, newy, 0.0) -def set_tansform_matrix(selvp, selview, vpboundaryoffset=0, reverse=False): - # TODO support alignment by project basepoint, not by cropbox +def set_tansform_matrix(selvp, selview, vpboundaryoffset=0.1, reverse=False): # TODO support sections # TODO allow to run with view activated instead of viewport selected # TODO paste on many views at once transmatrix = TransformationMatrix() + # making sure the cropbox is active. cboxannoparam = selview.get_Parameter( DB.BuiltInParameter.VIEWER_ANNOTATION_CROP_ACTIVE @@ -103,7 +104,6 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset=0, reverse=False): if el.Category\ and not el.IsHidden(selview) \ and el.CanBeHidden(selview): - print("hide", el.Category.Name) viewspecificelements.append(el.Id) @@ -135,7 +135,7 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset=0, reverse=False): # get vp min max points in sheetUCS ol = selvp.GetBoxOutline() vptempmin = ol.MinimumPoint # in viewport units - vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset , + vpmin = DB.XYZ(vptempmin.X + vpboundaryoffset, vptempmin.Y + vpboundaryoffset, 0.0) vptempmax = ol.MaximumPoint @@ -147,7 +147,6 @@ def set_tansform_matrix(selvp, selview, vpboundaryoffset=0, reverse=False): transmatrix.sourcemax = cropmax if reverse else vpmax transmatrix.destmin = vpmin if reverse else cropmin transmatrix.destmax = vpmax if reverse else cropmax - return transmatrix def select_viewport(): @@ -184,3 +183,52 @@ def get_title_block_placement(sheet): return return title_blocks[0].Location.Point + + +def get_crop_region(view): + crsm = view.GetCropRegionShapeManager() + if HOST_APP.is_newer_than(2015): + crsm_valid = crsm.CanHaveShape + else: + crsm_valid = crsm.Valid + + if crsm_valid: + if HOST_APP.is_newer_than(2015): + curve_loops = list(crsm.GetCropShape()) + else: + curve_loops = [crsm.GetCropRegionShape()] + + if curve_loops: + return curve_loops + + +def set_crop_region(view, curve_loops): + crop_active_saved = view.CropBoxActive + view.CropBoxActive = True + crsm = view.GetCropRegionShapeManager() # FIXME + for cloop in curve_loops: + if HOST_APP.is_newer_than(2015): + crsm.SetCropShape(cloop) + else: + crsm.SetCropRegionShape(cloop) + view.CropBoxActive = crop_active_saved + + +def view_plane(view): + return DB.Plane.CreateByOriginAndBasis(view.Origin, view.RightDirection, view.UpDirection) + + +def project_to_viewport(xyz, view): + plane = view_plane(view) + uv, dist = plane.Project(xyz) + return uv + + +def project_to_world(uv, view): + plane = view_plane(view) + trf = DB.Transform.Identity + trf.BasisX = plane.XVec + trf.BasisY = plane.YVec + trf.BasisZ = plane.Normal + trf.Origin = plane.Origin + return trf.OfPoint(DB.XYZ(uv.U, uv.V, 0))