Skip to content

Commit 2b0079a

Browse files
authored
Merge branch 'develop' into patch-2
2 parents cc23308 + f0c3530 commit 2b0079a

File tree

27 files changed

+821
-413
lines changed

27 files changed

+821
-413
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- uses: actions/checkout@v5
2929

3030
- name: Prepare Python 3.10
31-
uses: actions/setup-python@v5
31+
uses: actions/setup-python@v6
3232
with:
3333
python-version: '3.10'
3434

.github/workflows/main.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
submodules: recursive
5353

5454
- name: Prepare Python 3.10
55-
uses: actions/setup-python@v5
55+
uses: actions/setup-python@v6
5656
with:
5757
python-version: '3.10'
5858

@@ -63,12 +63,12 @@ jobs:
6363
6464
# needed for MahApps XamlColorSchemeGenerator
6565
- name: Prepare .NET 3.1
66-
uses: actions/setup-dotnet@v4
66+
uses: actions/setup-dotnet@v5
6767
with:
6868
dotnet-version: 3.1.x
6969

7070
- name: Prepare .NET 8.0
71-
uses: actions/setup-dotnet@v4
71+
uses: actions/setup-dotnet@v5
7272
with:
7373
dotnet-version: 8.0.x
7474

.github/workflows/stale-issues.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
issues: write
1111
pull-requests: write
1212
steps:
13-
- uses: actions/stale@v9
13+
- uses: actions/stale@v10
1414
with:
1515
days-before-issue-stale: 60
1616
days-before-issue-close: 14

Pipfile.lock

Lines changed: 270 additions & 214 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/extensions.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,19 @@
226226
"website": "",
227227
"image": "",
228228
"dependencies": []
229+
},
230+
{
231+
"builtin": "False",
232+
"type": "extension",
233+
"rocket_mode_compatible": "False",
234+
"name": "Revitesse",
235+
"description": "A set of useful tools for eliminating redundancy.",
236+
"author": "Ramy Maher",
237+
"author_profile": "https://de.linkedin.com/in/ramyamaher",
238+
"url": "https://github.com/ramyamaher/Revitesse.git",
239+
"website": "https://revitesse.com/",
240+
"image": "",
241+
"dependencies": []
229242
}
230243
]
231244
}

extensions/pyRevitDevTools.extension/pyRevitDev.tab/Developer Tools.panel/Generate API Stubs.pushbutton/script.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,67 @@
77
from pyrevit import labs
88
from pyrevit import forms
99
from pyrevit import script
10+
from rpw.ui.forms.flexform import FlexForm, Label, Button, CheckBox
1011

1112

1213
logger = script.get_logger()
1314
output = script.get_output()
1415

15-
16-
ASSMS = [
16+
RVT_ASSMS = [
1717
'RevitAPI',
18-
'RevitAPIUI',
18+
'RevitAPIUI'
19+
]
20+
DYN_ASSMS = [
21+
'DynamoServices',
22+
'DynamoCore',
23+
'DynamoApplications',
24+
'DSCoreNodes',
25+
'RevitServices',
26+
'RevitNodes',
27+
# 'ProtoGeometry',
1928
# 'UIFramework',
2029
# 'Adwindows',
30+
]
31+
PYR_ASSMS = [
2132
'pyRevitLabs.Common',
2233
'pyRevitLabs.TargetApps.Revit',
23-
'pyRevitLabs.PyRevit',
34+
'pyRevitLabs.PyRevit'
2435
]
2536

37+
def flexform_select():
38+
components = [
39+
Label('Select Assembly Group to Generate Stubs:'),
40+
CheckBox('Revit', 'Revit Assemblies', default=True),
41+
CheckBox('Dynamo', 'Dynamo Assemblies', default=False),
42+
CheckBox('pyRevit', 'pyRevit Assemblies', default=False),
43+
Button('Pick Destination Folder and Continue'),
44+
]
45+
form = FlexForm('Generate API Stubs', components)
46+
form.show()
47+
selected = []
48+
if form.values.get('Revit'):
49+
selected.extend(RVT_ASSMS)
50+
if form.values.get('Dynamo'):
51+
selected.extend(DYN_ASSMS)
52+
if form.values.get('pyRevit'):
53+
selected.extend(PYR_ASSMS)
54+
return selected
55+
56+
ASSMS = flexform_select()
57+
if not ASSMS:
58+
print("No assembly group selected. Exiting...")
59+
script.exit()
60+
2661
dest_path = forms.pick_folder()
2762

2863
if dest_path:
2964
for assm_name in ASSMS:
65+
print('Processing assembly: {}'.format(assm_name))
66+
try:
67+
load_assm = assmutils.load_asm(assm_name)
68+
print('Loaded assembly: {}'.format(assm_name))
69+
except Exception as ldEx:
70+
print('Error loading assembly {} | {}'.format(assm_name, ldEx))
3071
assm = assmutils.find_loaded_asm(assm_name)
3172
if assm:
3273
try:
@@ -37,3 +78,4 @@
3778
print('Generated stubs for %s -> %s' % (assm_name, stubs_path))
3879
except Exception as sgEx:
3980
logger.error('Failed generating stubs for %s', assm_name)
81+
Lines changed: 89 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,109 @@
11
from pyrevit import revit, script, DB
22

33
doc = revit.doc
4-
# currView = revit.active_view
5-
6-
# Get the output window
74
output = script.get_output()
85
output.close_others()
96

10-
11-
# Get Elements of the FamilyInstance Class
127
elements = (
138
DB.FilteredElementCollector(doc)
149
.OfClass(DB.FamilyInstance)
1510
.WhereElementIsNotElementType()
1611
.ToElements()
1712
)
1813

19-
grand_total = []
20-
table_data = []
21-
elements_name = []
22-
elements_count = []
23-
elements_category = []
24-
elements_type = []
14+
# Setup options for each detail level
15+
opt_coarse = DB.Options()
16+
opt_coarse.DetailLevel = DB.ViewDetailLevel.Coarse
17+
18+
opt_medium = DB.Options()
19+
opt_medium.DetailLevel = DB.ViewDetailLevel.Medium
2520

26-
opt = DB.Options()
21+
opt_fine = DB.Options()
22+
opt_fine.DetailLevel = DB.ViewDetailLevel.Fine
23+
24+
# Storage
25+
processed_types = {} # typeId: {name, coarse, medium, fine}
2726

2827
for element in elements:
29-
total_triangles = []
3028
typeId = element.GetTypeId()
31-
if typeId not in elements_type:
32-
elements_type.append(typeId)
33-
geometry_set = element.get_Geometry(opt)
34-
try:
35-
for geometry in geometry_set:
36-
if isinstance(geometry, DB.Solid) and geometry.Faces.Size > 0:
37-
nbrtriangle = sum(
38-
[
39-
f.Triangulate().NumTriangles
40-
for f in geometry.Faces
41-
if f.Triangulate() is not None
42-
]
43-
)
44-
total_triangles.append(nbrtriangle)
45-
elif isinstance(geometry, DB.GeometryInstance):
46-
for instObj in geometry.SymbolGeometry:
47-
if isinstance(instObj, DB.Solid) and instObj.Faces.Size > 0:
48-
nbrtriangle = sum(
49-
[
50-
f.Triangulate().NumTriangles
51-
for f in instObj.Faces
52-
if f.Triangulate() is not None
53-
]
54-
)
55-
total_triangles.append(nbrtriangle)
56-
else:
57-
pass
58-
geometry_set.Dispose()
59-
total_triangles = sum(total_triangles)
60-
if total_triangles != 0:
61-
elements_count.append(total_triangles)
62-
elements_name.append(
63-
output.linkify(element.Id)
64-
+ "**"
65-
+ element.Name
66-
+ "** (*Category*: "
67-
+ element.Category.Name
68-
+ ")"
69-
)
70-
grand_total.append(total_triangles)
71-
except:
72-
pass
73-
74-
# adding grand total and making a dictionary out of it
75-
elements_count.append(sum(grand_total))
76-
elements_name.append("Grand Total")
77-
my_dict = dict(zip(elements_name, elements_count))
78-
79-
# output as a table
29+
30+
if typeId not in processed_types:
31+
element_name = (
32+
output.linkify(element.Id)
33+
+ "**"
34+
+ element.Name
35+
+ "** (*Category*: "
36+
+ element.Category.Name
37+
+ ")"
38+
)
39+
40+
# Process each detail level
41+
counts = {}
42+
for level_name, opt in [
43+
("coarse", opt_coarse),
44+
("medium", opt_medium),
45+
("fine", opt_fine),
46+
]:
47+
total_triangles = []
48+
geometry_set = element.get_Geometry(opt)
49+
50+
try:
51+
for geometry in geometry_set:
52+
if isinstance(geometry, DB.Solid) and geometry.Faces.Size > 0:
53+
nbrtriangle = sum(
54+
[
55+
f.Triangulate().NumTriangles
56+
for f in geometry.Faces
57+
if f.Triangulate() is not None
58+
]
59+
)
60+
total_triangles.append(nbrtriangle)
61+
elif isinstance(geometry, DB.GeometryInstance):
62+
for instObj in geometry.SymbolGeometry:
63+
if isinstance(instObj, DB.Solid) and instObj.Faces.Size > 0:
64+
nbrtriangle = sum(
65+
[
66+
f.Triangulate().NumTriangles
67+
for f in instObj.Faces
68+
if f.Triangulate() is not None
69+
]
70+
)
71+
total_triangles.append(nbrtriangle)
72+
73+
geometry_set.Dispose()
74+
counts[level_name] = sum(total_triangles)
75+
except Exception:
76+
counts[level_name] = 0
77+
78+
# Only add if at least one level has triangles
79+
if any(counts.values()):
80+
processed_types[typeId] = {
81+
"name": element_name,
82+
"coarse": counts["coarse"],
83+
"medium": counts["medium"],
84+
"fine": counts["fine"],
85+
}
86+
87+
# Prepare table data
88+
table_data = []
89+
for type_info in processed_types.values():
90+
table_data.append(
91+
[type_info["name"], type_info["coarse"], type_info["medium"], type_info["fine"]]
92+
)
93+
94+
# Add grand totals
95+
if table_data:
96+
grand_coarse = sum([row[1] for row in table_data])
97+
grand_medium = sum([row[2] for row in table_data])
98+
grand_fine = sum([row[3] for row in table_data])
99+
100+
table_data.append(["Grand Total", grand_coarse, grand_medium, grand_fine])
101+
102+
# Sort by fine detail count (or change to coarse/medium as needed)
103+
table_data_sorted = sorted(table_data[:-1], key=lambda x: x[3]) + [table_data[-1]]
104+
80105
output.print_table(
81-
sorted(my_dict.items(), key=lambda item: item[1]),
82-
["Name", "Count"],
106+
table_data_sorted,
107+
["Name", "Coarse", "Medium", "Fine"],
83108
last_line_style="color:white;font-weight: bolder; background-color: gray;",
84109
)

extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack/Inspect.pulldown/ListFamilySizeCreator.pushbutton/ListFamilySizeCreator_script.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import math
55
import tempfile
6+
from collections import defaultdict
67
from pyrevit import revit, forms, script, DB, HOST_APP
78

89
output = script.get_output()
@@ -15,6 +16,7 @@
1516
save_as_options = DB.SaveAsOptions()
1617
save_as_options.OverwriteExistingFile = True
1718

19+
1820
def convert_size(size_bytes):
1921
if not size_bytes:
2022
return "N/A"
@@ -75,7 +77,7 @@ def print_sorted(families, group_by):
7577
key=lambda fam_item: fam_item.get(sort_by),
7678
reverse=False
7779
)
78-
80+
7981
for fam_item in sorted_families:
8082
group_by_value = fam_item[group_by]
8183
if group_by_value not in families_grouped:
@@ -86,7 +88,7 @@ def print_sorted(families, group_by):
8688
if group_by in ["Creator", "Category"]:
8789
output.print_md("---")
8890
output.print_md("## {}: {}".format(group_by, group_value))
89-
91+
9092
# Prepare table data
9193
table_data = []
9294
for fam_item in families_grouped[group_value]:
@@ -100,19 +102,21 @@ def print_sorted(families, group_by):
100102
else:
101103
row.append(str(value))
102104
table_data.append(row)
103-
105+
104106
# Print table using output.print_table()
105107
output.print_table(
106108
table_data,
107109
columns=fields_sorted
108110
)
109-
111+
110112
print_totals(families_grouped[group_value])
111113

114+
112115
# main logic
113116
# ask use to choose sort option
114-
sort_by = forms.CommandSwitchWindow.show(FIELDS,
115-
message='Sorting options:',
117+
sort_by = forms.CommandSwitchWindow.show(
118+
FIELDS,
119+
message="Sorting options:",
116120
)
117121
if not sort_by:
118122
script.exit()
@@ -131,12 +135,6 @@ def print_sorted(families, group_by):
131135
.ToElements()
132136

133137
# Create a dictionary to count instances per family
134-
family_instance_counts = {}
135-
for instance in all_family_instances:
136-
try:
137-
if instance.Symbol:
138-
family_name = instance.Symbol.Family.Name
139-
family_instance_counts[family_name] = \
140138
family_instance_counts = defaultdict(int)
141139
for instance in all_family_instances:
142140
try:
@@ -172,10 +170,10 @@ def print_sorted(families, group_by):
172170
fam.Id).Creator
173171
if fam_path and os.path.exists(fam_path):
174172
fam_size = os.path.getsize(fam_path)
175-
173+
176174
# Get instance count for this family
177175
fam_count = family_instance_counts.get(fam.Name, 0)
178-
176+
179177
all_family_items.append({"Size": fam_size,
180178
"Creator": fam_creator,
181179
"Category": fam_category,

0 commit comments

Comments
 (0)