pi-revit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/extensions/pi-revit/index.ts +239 -0
- package/package.json +28 -0
- package/scripts/build.ps1 +37 -0
- package/scripts/deploy.ps1 +99 -0
- package/scripts/revit.ps1 +112 -0
- package/scripts/setup-workspace.ps1 +53 -0
- package/scripts/uninstall.ps1 +103 -0
- package/skills/pi-revit/SKILL.md +50 -0
- package/src/Revit/Application.cs +94 -0
- package/src/Revit/BridgeServer.cs +419 -0
- package/src/Revit/CommandQueue.cs +93 -0
- package/src/Revit/RevitBridge.addin +11 -0
- package/src/Revit/RevitBridge.csproj +48 -0
- package/src/Revit/ToolRegistry.cs +109 -0
- package/src/Revit/Tools/CaptureView.cs +168 -0
- package/src/Revit/Tools/ExecuteCsharp.cs +418 -0
- package/src/Revit/Tools/ExportDocuments.cs +256 -0
- package/src/Revit/Tools/GetElementDetails.cs +318 -0
- package/src/Revit/Tools/GetElementTypes.cs +151 -0
- package/src/Revit/Tools/GetElements.cs +725 -0
- package/src/Revit/Tools/GetModelHealth.cs +191 -0
- package/src/Revit/Tools/GetModelOverview.cs +159 -0
- package/src/Revit/Tools/ManageSelection.cs +220 -0
- package/src/Revit/Tools/SearchApiDocs.cs +610 -0
- package/src/Revit/Tools/SetParameters.cs +382 -0
- package/src/Revit/Tools/ToolSupport.cs +261 -0
- package/workspace/AGENTS.md +23 -0
- package/workspace/pi-revit-global.cmd +31 -0
- package/workspace/pi-revit-here.cmd +5 -0
- package/workspace/project-AGENTS.md +8 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools
|
|
5
|
+
{
|
|
6
|
+
internal sealed class GetElementTypes : ITool
|
|
7
|
+
{
|
|
8
|
+
private const int DefaultLimit = 200;
|
|
9
|
+
private const int MaxLimit = 1000;
|
|
10
|
+
|
|
11
|
+
public string Name => "get_element_types";
|
|
12
|
+
public string Label => "Get Element Types";
|
|
13
|
+
public string Description => "List element types / family symbols (wall types, door types, ...) for a category or class: id, name, familyName, category, isFamilySymbol, optional placed-instance count per type (answers 'used vs merely loaded'). Use the ids with get_elements type_id or for type assignment.";
|
|
14
|
+
|
|
15
|
+
public object ParametersSchema => new
|
|
16
|
+
{
|
|
17
|
+
type = "object",
|
|
18
|
+
properties = new
|
|
19
|
+
{
|
|
20
|
+
category = new
|
|
21
|
+
{
|
|
22
|
+
type = "string",
|
|
23
|
+
description = "Category: BuiltInCategory enum name (e.g. OST_Walls) or display name (e.g. Walls, Doors).",
|
|
24
|
+
},
|
|
25
|
+
of_class = new
|
|
26
|
+
{
|
|
27
|
+
type = "string",
|
|
28
|
+
description = "Element type class, e.g. WallType, FloorType, FamilySymbol.",
|
|
29
|
+
},
|
|
30
|
+
name_filter = new
|
|
31
|
+
{
|
|
32
|
+
type = "string",
|
|
33
|
+
description = "Case-insensitive substring matched against type name and family name.",
|
|
34
|
+
},
|
|
35
|
+
include_instance_count = new
|
|
36
|
+
{
|
|
37
|
+
type = "boolean",
|
|
38
|
+
description = "Add the number of placed instances per type. Counts the scoped category (or the whole model without a category), so it costs one extra pass. Default false.",
|
|
39
|
+
},
|
|
40
|
+
offset = new { type = "integer", description = "Pagination offset. Default 0." },
|
|
41
|
+
limit = new { type = "integer", description = "Max types to return (1-1000). Default 200." },
|
|
42
|
+
},
|
|
43
|
+
required = Array.Empty<string>(),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
public string? PromptSnippet => "List Revit element types / family symbols with optional placed-instance counts.";
|
|
47
|
+
public IReadOnlyList<string>? PromptGuidelines => new[]
|
|
48
|
+
{
|
|
49
|
+
"Use get_element_types to discover the available types of a category; set include_instance_count to see which types are actually placed.",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
public object? Execute(JsonElement args, ToolContext context)
|
|
53
|
+
{
|
|
54
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
55
|
+
|
|
56
|
+
string? categoryInput = JsonArgs.GetString(args, "category");
|
|
57
|
+
string? classInput = JsonArgs.GetString(args, "of_class");
|
|
58
|
+
string needle = JsonArgs.GetString(args, "name_filter")?.Trim() ?? string.Empty;
|
|
59
|
+
bool includeInstanceCount = JsonArgs.GetBool(args, "include_instance_count", false);
|
|
60
|
+
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0));
|
|
61
|
+
int limit = Math.Clamp(JsonArgs.GetInt(args, "limit", DefaultLimit), 1, MaxLimit);
|
|
62
|
+
|
|
63
|
+
ElementId? categoryId = string.IsNullOrWhiteSpace(categoryInput) ? null : CategoryResolver.Resolve(doc, categoryInput);
|
|
64
|
+
Type? elementClass = string.IsNullOrWhiteSpace(classInput) ? null : ElementClassResolver.Resolve(classInput);
|
|
65
|
+
|
|
66
|
+
var collector = new FilteredElementCollector(doc);
|
|
67
|
+
if (categoryId != null)
|
|
68
|
+
collector = collector.OfCategoryId(categoryId);
|
|
69
|
+
if (elementClass != null)
|
|
70
|
+
collector = collector.OfClass(elementClass);
|
|
71
|
+
collector = collector.WhereElementIsElementType();
|
|
72
|
+
|
|
73
|
+
var types = collector
|
|
74
|
+
.OfType<ElementType>()
|
|
75
|
+
.Select(type => new { Type = type, Name = type.Name ?? string.Empty, FamilyName = SafeFamilyName(type) })
|
|
76
|
+
.Where(entry => needle.Length == 0
|
|
77
|
+
|| entry.Name.Contains(needle, StringComparison.OrdinalIgnoreCase)
|
|
78
|
+
|| entry.FamilyName.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
|
79
|
+
.OrderBy(entry => entry.FamilyName, StringComparer.OrdinalIgnoreCase)
|
|
80
|
+
.ThenBy(entry => entry.Name, StringComparer.OrdinalIgnoreCase)
|
|
81
|
+
.ToList();
|
|
82
|
+
|
|
83
|
+
Dictionary<long, int>? instanceCounts = null;
|
|
84
|
+
if (includeInstanceCount)
|
|
85
|
+
{
|
|
86
|
+
instanceCounts = new Dictionary<long, int>();
|
|
87
|
+
var instances = new FilteredElementCollector(doc);
|
|
88
|
+
if (categoryId != null)
|
|
89
|
+
instances = instances.OfCategoryId(categoryId);
|
|
90
|
+
foreach (Element element in instances.WhereElementIsNotElementType())
|
|
91
|
+
{
|
|
92
|
+
long typeIdValue = element.GetTypeId().Value;
|
|
93
|
+
if (typeIdValue < 0)
|
|
94
|
+
continue;
|
|
95
|
+
instanceCounts[typeIdValue] = instanceCounts.TryGetValue(typeIdValue, out int count) ? count + 1 : 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
int total = types.Count;
|
|
100
|
+
var window = types.Skip(offset).Take(limit).Select(entry =>
|
|
101
|
+
{
|
|
102
|
+
var row = new Dictionary<string, object?>
|
|
103
|
+
{
|
|
104
|
+
["id"] = entry.Type.Id.Value,
|
|
105
|
+
["name"] = entry.Name,
|
|
106
|
+
["familyName"] = entry.FamilyName,
|
|
107
|
+
["category"] = entry.Type.Category?.Name,
|
|
108
|
+
["isFamilySymbol"] = entry.Type is FamilySymbol,
|
|
109
|
+
};
|
|
110
|
+
if (instanceCounts != null)
|
|
111
|
+
row["instanceCount"] = instanceCounts.TryGetValue(entry.Type.Id.Value, out int count) ? count : 0;
|
|
112
|
+
return row;
|
|
113
|
+
}).ToList();
|
|
114
|
+
|
|
115
|
+
bool hasMore = offset + window.Count < total;
|
|
116
|
+
int? nextOffset = hasMore ? offset + window.Count : null;
|
|
117
|
+
|
|
118
|
+
string scope = !string.IsNullOrWhiteSpace(categoryInput) ? categoryInput.Trim()
|
|
119
|
+
: !string.IsNullOrWhiteSpace(classInput) ? classInput.Trim()
|
|
120
|
+
: "all categories";
|
|
121
|
+
string sampleText = window.Count > 0
|
|
122
|
+
? $" Sample: {string.Join(", ", window.Take(3).Select(row => $"'{row["familyName"]}: {row["name"]}' ({row["id"]})"))}."
|
|
123
|
+
: string.Empty;
|
|
124
|
+
string compact = hasMore
|
|
125
|
+
? $"element types ({scope}): {total} total, returned {window.Count} at offset {offset}, has_more (next_offset {nextOffset}).{sampleText}"
|
|
126
|
+
: $"element types ({scope}): {total} total, returned {window.Count} at offset {offset}.{sampleText}";
|
|
127
|
+
|
|
128
|
+
return new ToolOutput(new
|
|
129
|
+
{
|
|
130
|
+
total_count = total,
|
|
131
|
+
returned_count = window.Count,
|
|
132
|
+
offset,
|
|
133
|
+
has_more = hasMore,
|
|
134
|
+
next_offset = nextOffset,
|
|
135
|
+
types = window,
|
|
136
|
+
}, compact);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private static string SafeFamilyName(ElementType type)
|
|
140
|
+
{
|
|
141
|
+
try
|
|
142
|
+
{
|
|
143
|
+
return type.FamilyName ?? string.Empty;
|
|
144
|
+
}
|
|
145
|
+
catch
|
|
146
|
+
{
|
|
147
|
+
return string.Empty;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|