Skip to content

Commit 6b96175

Browse files
authored
Merge pull request #2915 from Wurschdhaud/minor-fixes
chore: tools Minor fixes
2 parents 6815e41 + 20cab30 commit 6b96175

File tree

7 files changed

+92
-60
lines changed
  • extensions/pyRevitTools.extension/pyRevit.tab
    • Analysis.panel/Tools.stack/Inspect.pulldown/Count Faces.pushbutton
    • Modify.panel/3D.pulldown
    • Selection.panel/select.stack/Select.pulldown/Select All Objects Passing Filter.pushbutton
    • Toggles.panel/toggles2.stack/SectionBox.pushbutton

7 files changed

+92
-60
lines changed

extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack/Inspect.pulldown/Count Faces.pushbutton/script.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
output = script.get_output()
66
output.close_others()
77

8-
elements = (
9-
DB.FilteredElementCollector(doc)
10-
.OfClass(DB.FamilyInstance)
11-
.WhereElementIsNotElementType()
12-
.ToElements()
13-
)
8+
elements = revit.query.get_elements_by_class(DB.FamilyInstance, doc=doc)
149

1510
# Storage
1611
processed_types = {} # typeId: {name, coarse, medium, fine}

extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/3D.pulldown/Measure.pushbutton/measure3d.xaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818

1919
<Separator Margin="0,5"/>
2020

21-
<TextBlock x:Name="dx_text" Text="ΔX: -" Margin="0,5,0,2" TextAlignment="Right" FontWeight="SemiBold"/>
22-
<TextBlock x:Name="dy_text" Text="ΔY: -" Margin="0,2" TextAlignment="Right" FontWeight="SemiBold"/>
23-
<TextBlock x:Name="dz_text" Text="ΔZ: -" Margin="0,2" TextAlignment="Right" FontWeight="SemiBold"/>
24-
<TextBlock x:Name="diagonal_text" Text="Diagonal: -" Margin="0,2" TextAlignment="Right" FontWeight="Bold" FontSize="14"/>
21+
<TextBlock x:Name="dx_text" Margin="0,5,0,2" TextAlignment="Right" FontFamily="Consolas" FontWeight="SemiBold"/>
22+
<TextBlock x:Name="dy_text" Margin="0,2" TextAlignment="Right" FontFamily="Consolas" FontWeight="SemiBold"/>
23+
<TextBlock x:Name="dz_text" Margin="0,2" TextAlignment="Right" FontFamily="Consolas" FontWeight="SemiBold"/>
24+
<TextBlock x:Name="diagonal_text" Margin="0,2" TextAlignment="Right" FontWeight="Bold" FontSize="14"/>
25+
<TextBlock x:Name="slope_text" Margin="0,2" TextAlignment="Right" FontFamily="Consolas" FontWeight="SemiBold"/>
2526
<TextBlock x:Name="project_unit_text" Text="" Visibility="Collapsed" Foreground="Red" FontWeight="Bold" Margin="0,5,0,2"/>
2627
</StackPanel>
2728
</GroupBox>

extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/3D.pulldown/Measure.pushbutton/script.py

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
from collections import deque
3-
from pyrevit import HOST_APP, revit, forms, script, traceback
3+
from math import pi, atan, sqrt
4+
from pyrevit import HOST_APP, revit, forms, script
45
from pyrevit import UI, DB
56
from pyrevit.framework import System
67
from Autodesk.Revit.Exceptions import InvalidOperationException
@@ -9,13 +10,22 @@
910

1011
doc = HOST_APP.doc
1112
uidoc = revit.uidoc
13+
# Length
1214
length_format_options = doc.GetUnits().GetFormatOptions(DB.SpecTypeId.Length)
1315
length_unit = length_format_options.GetUnitTypeId()
1416
length_unit_label = DB.LabelUtils.GetLabelForUnit(length_unit)
1517
length_unit_symbol = length_format_options.GetSymbolTypeId()
1618
length_unit_symbol_label = None
1719
if not length_unit_symbol.Empty():
1820
length_unit_symbol_label = DB.LabelUtils.GetLabelForSymbol(length_unit_symbol)
21+
# Slope
22+
slope_format_options = doc.GetUnits().GetFormatOptions(DB.SpecTypeId.Slope)
23+
slope_unit = slope_format_options.GetUnitTypeId()
24+
slope_unit_label = DB.LabelUtils.GetLabelForUnit(slope_unit)
25+
slope_unit_symbol = slope_format_options.GetSymbolTypeId()
26+
slope_unit_symbol_label = None
27+
if not slope_unit_symbol.Empty():
28+
slope_unit_symbol_label = DB.LabelUtils.GetLabelForSymbol(slope_unit_symbol)
1929

2030
# Global variables
2131
measure_window = None
@@ -34,29 +44,46 @@
3444

3545
WINDOW_POSITION = "measure_window_pos"
3646

47+
3748
def calculate_distances(point1, point2):
38-
"""Calculate dx, dy, dz and diagonal distance between two points.
49+
"""Calculate dx, dy, dz, diagonal distance, and slope angle between two points.
3950
4051
Args:
4152
point1 (DB.XYZ): First point
4253
point2 (DB.XYZ): Second point
4354
4455
Returns:
45-
tuple: (dx, dy, dz, diagonal) all in internal units (feet)
56+
tuple: (dx, dy, dz, diagonal, slope) all in internal units (feet, rad)
4657
"""
4758
dx = abs(point2.X - point1.X)
4859
dy = abs(point2.Y - point1.Y)
4960
dz = abs(point2.Z - point1.Z)
5061
diagonal = point1.DistanceTo(point2)
5162

52-
return dx, dy, dz, diagonal
63+
horizontal = sqrt(dx ** 2 + dy ** 2)
64+
65+
if horizontal == 0:
66+
slope = pi / 2.0 # 90 degrees (vertical)
67+
else:
68+
slope = atan(dz / horizontal)
69+
70+
return dx, dy, dz, diagonal, slope
5371

5472

55-
def format_distance(value_in_feet):
73+
def format_distance(value_internal):
5674
return DB.UnitFormatUtils.Format(
5775
doc.GetUnits(),
5876
DB.SpecTypeId.Length,
59-
value_in_feet,
77+
value_internal,
78+
False,
79+
)
80+
81+
82+
def format_slope(value_internal):
83+
return DB.UnitFormatUtils.Format(
84+
doc.GetUnits(),
85+
DB.SpecTypeId.Slope,
86+
value_internal,
6087
False,
6188
)
6289

@@ -148,7 +175,7 @@ def validate_3d_view():
148175
forms.alert(
149176
"Please activate a 3D view before using the 3D Measure tool.",
150177
title="3D View Required",
151-
exitscript=True
178+
exitscript=True,
152179
)
153180
return False
154181
return True
@@ -159,7 +186,7 @@ def perform_measurement():
159186
# Add 3D view validation
160187
if not validate_3d_view():
161188
return
162-
189+
163190
try:
164191
with forms.WarningBar(title="Pick first point"):
165192
point1 = revit.pick_elementpoint(world=True)
@@ -180,26 +207,32 @@ def perform_measurement():
180207
dc3d_server.meshes = existing_meshes + new_meshes
181208
uidoc.RefreshActiveView()
182209

183-
dx, dy, dz, diagonal = calculate_distances(point1, point2)
210+
dx, dy, dz, diagonal, slope = calculate_distances(point1, point2)
184211

185212
measure_window.point1_text.Text = "Point 1: {}".format(format_point(point1))
186213
measure_window.point2_text.Text = "Point 2: {}".format(format_point(point2))
187-
measure_window.dx_text.Text = "ΔX: {}".format(format_distance(dx))
188-
measure_window.dy_text.Text = "ΔY: {}".format(format_distance(dy))
189-
measure_window.dz_text.Text = "ΔZ: {}".format(format_distance(dz))
214+
measure_window.dx_text.Text = "ΔX: {:>15}".format(format_distance(dx))
215+
measure_window.dy_text.Text = "ΔY: {:>15}".format(format_distance(dy))
216+
measure_window.dz_text.Text = "ΔZ: {:>15}".format(format_distance(dz))
190217
measure_window.diagonal_text.Text = "Diagonal: {}".format(
191218
format_distance(diagonal)
192219
)
220+
measure_window.slope_text.Text = "Slope: {}".format(format_slope(slope))
193221

194222
# Add to history
195-
history_entry = "Measurement {}:\n P1: {}\n P2: {}\n ΔX: {}\n ΔY: {}\n ΔZ: {}\n Diagonal: {}\n".format(
196-
len(measurement_history) + 1,
197-
format_point(point1),
198-
format_point(point2),
199-
format_distance(dx),
200-
format_distance(dy),
201-
format_distance(dz),
202-
format_distance(diagonal),
223+
history_entry = (
224+
"Measurement {}:\n P1: {}\n P2: {}\n "
225+
"ΔX: {:>15}\n ΔY: {:>15}\n ΔZ: {:>15}\n "
226+
"Diagonal: {}\n Slope: {}".format(
227+
len(measurement_history) + 1,
228+
format_point(point1),
229+
format_point(point2),
230+
format_distance(dx),
231+
format_distance(dy),
232+
format_distance(dz),
233+
format_distance(diagonal),
234+
format_slope(slope),
235+
)
203236
)
204237
measurement_history.append(history_entry)
205238

@@ -214,13 +247,15 @@ def perform_measurement():
214247
logger.error("InvalidOperationException during measurement: {}".format(ex))
215248
forms.alert(
216249
"Measurement cancelled due to invalid operation. Please try again.",
217-
title="Measurement Error"
250+
title="Measurement Error",
218251
)
219252
except Exception as ex:
220-
logger.error("Error during measurement: {}\n{}".format(ex, traceback.format_exc()))
253+
logger.exception(
254+
"Error during measurement: {}".format(ex)
255+
)
221256
forms.alert(
222257
"An unexpected error occurred during measurement. Check the log for details.",
223-
title="Measurement Error"
258+
title="Measurement Error",
224259
)
225260

226261

@@ -253,6 +288,7 @@ def __init__(self, xaml_file_name):
253288
self.dy_text.Text = "ΔY: -"
254289
self.dz_text.Text = "ΔZ: -"
255290
self.diagonal_text.Text = "Diagonal: -"
291+
self.slope_text.Text = "Slope: -"
256292
self.history_text.Text = "No measurements yet"
257293

258294
if not length_unit_symbol_label:
@@ -261,48 +297,53 @@ def __init__(self, xaml_file_name):
261297
"Length Units (adjust in Project Units): \n" + length_unit_label
262298
)
263299
self.Height = self.Height + 20
300+
if not slope_unit_symbol_label:
301+
self.show_element(self.project_unit_text)
302+
self.project_unit_text.Text = self.project_unit_text.Text + (
303+
"\nSlope Units (adjust in Project Units): \n" + slope_unit_label
304+
)
305+
self.Height = self.Height + 20
264306

265307
# Handle window close event
266308
self.Closed += self.window_closed
267309

268310
try:
269311
pos = script.load_data(WINDOW_POSITION, this_project=False)
270312
all_bounds = [s.WorkingArea for s in System.Windows.Forms.Screen.AllScreens]
271-
x, y = pos['Left'], pos['Top']
313+
x, y = pos["Left"], pos["Top"]
272314
visible = any(
273-
(b.Left <= x <= b.Right and b.Top <= y <= b.Bottom)
274-
for b in all_bounds
315+
(b.Left <= x <= b.Right and b.Top <= y <= b.Bottom) for b in all_bounds
275316
)
276317
if not visible:
277318
raise Exception
278319
self.WindowStartupLocation = System.Windows.WindowStartupLocation.Manual
279-
self.Left = pos.get('Left', 200)
280-
self.Top = pos.get('Top', 150)
320+
self.Left = pos.get("Left", 200)
321+
self.Top = pos.get("Top", 150)
281322
except Exception:
282-
self.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen
323+
self.WindowStartupLocation = (
324+
System.Windows.WindowStartupLocation.CenterScreen
325+
)
283326

284327
self.Show()
285-
328+
286329
# Automatically start the first measurement
287330
measure_handler_event.Raise()
288331

289332
def window_closed(self, sender, args):
290333
"""Handle window close event - copy history to clipboard, cleanup DC3D server and visual aids."""
291334
global dc3d_server
292-
new_pos = {'Left': self.Left, 'Top': self.Top}
335+
new_pos = {"Left": self.Left, "Top": self.Top}
293336
script.store_data(WINDOW_POSITION, new_pos, this_project=False)
294-
337+
295338
# Copy measurement history to clipboard before cleanup
296339
try:
297340
if measurement_history:
298341
history_text = "\n".join(measurement_history)
299342
script.clipboard_copy(history_text)
300-
logger.info("Measurement history copied to clipboard")
301-
else:
302-
logger.info("No measurements to copy to clipboard")
343+
forms.toast("Measurements copied to Clipboard!", title="Measure 3D")
303344
except Exception as ex:
304345
logger.error("Error copying to clipboard: {}".format(ex))
305-
346+
306347
try:
307348
# Delete all visual aids
308349
if dc3d_server:

extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/3D.pulldown/Orient Section Box To Face.pushbutton/script.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def orientsectionbox(view):
3333
element,
3434
include_invisible=True,
3535
compute_references=True,
36-
detail_level=curview.DetailLevel
36+
detail_level=view.DetailLevel
3737
)
3838

3939
solids = [g for g in geom_objs if isinstance(g, DB.Solid) and g.Faces.Size > 0]

extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/3D.pulldown/Orient View To Face.pushbutton/script.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def reorient(view):
3030
element,
3131
include_invisible=True,
3232
compute_references=True,
33-
detail_level=curview.DetailLevel
33+
detail_level=view.DetailLevel
3434
)
3535

3636
solids = [g for g in geom_objs if isinstance(g, DB.Solid) and g.Faces.Size > 0]

extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/select.stack/Select.pulldown/Select All Objects Passing Filter.pushbutton/script.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
only_current_view = my_config.get_option("only_current_view", True)
1212
reverse_filter = my_config.get_option("reverse_filter", False)
1313

14-
filters = list(DB.FilteredElementCollector(doc).OfClass(DB.ParameterFilterElement))
14+
filters = list(revit.query.get_elements_by_class(DB.ParameterFilterElement, doc=doc))
1515

1616
if not filters:
1717
forms.alert("No Filters found", exitscript=True)
@@ -56,4 +56,5 @@
5656
if exclude_nested and isinstance(el, DB.FamilyInstance) and el.SuperComponent:
5757
continue
5858
element_ids.append(el.Id)
59-
uidoc.Selection.SetElementIds(List[DB.ElementId](element_ids))
59+
60+
revit.get_selection().set_to(element_ids)

extensions/pyRevitTools.extension/pyRevit.tab/Toggles.panel/toggles2.stack/SectionBox.pushbutton/script.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"""Toggles visibility of section box in current 3D view"""
22

3-
import pickle
4-
53
from pyrevit import framework
64
from pyrevit import revit, DB, script
75
from pyrevit.compat import get_elementid_value_func
@@ -11,7 +9,7 @@
119
active_view_id_value = get_elementid_value(active_view.Id)
1210

1311
logger = script.get_logger()
14-
datafile = script.get_document_data_file("SectionBox", "pym")
12+
DATA_SLOTNAME = "SectionBox"
1513

1614
my_config = script.get_config()
1715
scope = my_config.get_option("scope", "Visibility")
@@ -50,21 +48,17 @@ def toggle_sectionbox_active():
5048
logger.error("Not a 3D view. Operation canceled.")
5149
return
5250

53-
sectionbox_active_state = active_view.IsSectionBoxActive
54-
5551
try:
56-
with open(datafile, "rb") as f:
57-
view_boxes = pickle.load(f)
52+
view_boxes = script.load_data(DATA_SLOTNAME)
5853
except Exception:
5954
view_boxes = {}
6055

61-
if sectionbox_active_state:
56+
if active_view.IsSectionBoxActive:
6257
try:
6358
sectionbox = active_view.GetSectionBox()
6459
if sectionbox:
6560
view_boxes[active_view_id_value] = revit.serialize(sectionbox)
66-
with open(datafile, "wb") as f:
67-
pickle.dump(view_boxes, f)
61+
script.store_data(DATA_SLOTNAME, view_boxes)
6862
active_view.IsSectionBoxActive = False
6963
except Exception as e:
7064
logger.error("Error saving section box: {}".format(e))

0 commit comments

Comments
 (0)