pi-revit 0.3.1 → 0.4.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/CHANGELOG.md +388 -351
- package/README.md +426 -22
- package/extensions/pi-revit/index.ts +246 -187
- package/extensions/pi-revit/instance-router.ts +86 -0
- package/extensions/pi-revit/script-library.ts +146 -0
- package/extensions/pi-revit/tool-catalog.ts +67 -0
- package/package.json +59 -59
- package/skills/pi-revit/SKILL.md +196 -32
- package/skills/pi-revit/references/model-audit-export.md +29 -0
- package/skills/pi-revit/references/room-documentation.md +28 -0
- package/src/Revit/BridgeServer.cs +87 -37
- package/src/Revit/OperationStore.cs +178 -0
- package/src/Revit/ToolRegistry.cs +57 -35
- package/src/Revit/Tools/CaptureView.cs +2 -1
- package/src/Revit/Tools/ChangeElementTypes.cs +60 -0
- package/src/Revit/Tools/CreateTags.cs +95 -0
- package/src/Revit/Tools/DeleteElements.cs +44 -0
- package/src/Revit/Tools/DocumentGuard.cs +64 -64
- package/src/Revit/Tools/ElementQueryScope.cs +27 -0
- package/src/Revit/Tools/ExecuteCsharp.cs +45 -35
- package/src/Revit/Tools/ExportDocuments.cs +121 -120
- package/src/Revit/Tools/FailureGuard.cs +26 -26
- package/src/Revit/Tools/GetElementDetails.cs +42 -12
- package/src/Revit/Tools/GetElementRelationships.cs +76 -0
- package/src/Revit/Tools/GetElements.cs +37 -23
- package/src/Revit/Tools/GetLinkedElements.cs +82 -0
- package/src/Revit/Tools/GetLinkedModels.cs +66 -0
- package/src/Revit/Tools/GetModelCoordinates.cs +49 -0
- package/src/Revit/Tools/GetModelOverview.cs +2 -2
- package/src/Revit/Tools/GetScheduleFields.cs +37 -0
- package/src/Revit/Tools/GetSchedules.cs +89 -0
- package/src/Revit/Tools/ManageElementSets.cs +106 -0
- package/src/Revit/Tools/ManageSchedules.cs +164 -0
- package/src/Revit/Tools/ManageSelection.cs +37 -36
- package/src/Revit/Tools/ManageSheetPlacements.cs +97 -0
- package/src/Revit/Tools/ManageSheets.cs +63 -0
- package/src/Revit/Tools/ManageViews.cs +100 -0
- package/src/Revit/Tools/MeasureGeometry.cs +54 -0
- package/src/Revit/Tools/ModelEditBatch.cs +102 -0
- package/src/Revit/Tools/ModelEditInputs.cs +49 -0
- package/src/Revit/Tools/OpenView.cs +2 -1
- package/src/Revit/Tools/QuerySpatialElements.cs +63 -0
- package/src/Revit/Tools/SetParameters.cs +43 -93
- package/src/Revit/Tools/SpatialBounds.cs +30 -0
- package/src/Revit/Tools/SummarizeElements.cs +87 -0
- package/src/Revit/Tools/ToolSupport.cs +1 -1
- package/src/Revit/Tools/TransformElements.cs +58 -0
- package/workspace/AGENTS.md +45 -45
|
@@ -10,7 +10,7 @@ namespace RevitBridge.Tools
|
|
|
10
10
|
|
|
11
11
|
public string Name => "get_element_details";
|
|
12
12
|
public string Label => "Get Element Details";
|
|
13
|
-
public string Description => "Inspect one or more elements by id: parameter VALUES (name, internal value, formatted displayValue, storage type, display unit where applicable, read-only/shared flags), plus optional type parameters, location (point/curve), bounding box, and materials. Internal numeric values are Revit internal units (feet-based); displayValue is formatted in the document's display units and 'unit' names that display unit.
|
|
13
|
+
public string Description => "Inspect one or more elements by id: parameter VALUES (name, internal value, formatted displayValue, storage type, display unit where applicable, read-only/shared flags), plus optional type parameters, location (point/curve), bounding box, and materials. Internal numeric values are Revit internal units (feet-based); displayValue is formatted in the document's display units and 'unit' names that display unit. Use get_elements parameter_names to project a small set of values alongside a query.";
|
|
14
14
|
|
|
15
15
|
public object ParametersSchema => new
|
|
16
16
|
{
|
|
@@ -36,7 +36,7 @@ namespace RevitBridge.Tools
|
|
|
36
36
|
properties = new
|
|
37
37
|
{
|
|
38
38
|
parameters = new { type = "boolean", description = "Instance parameter values. Default true." },
|
|
39
|
-
type_parameters = new { type = "boolean", description = "Include the element type's parameters, marked isType=true, independently of the instance parameters flag. Default false." },
|
|
39
|
+
type_parameters = new { type = "boolean", description = "Include the element type's parameters, marked isType=true, independently of the instance parameters flag. Default false." },
|
|
40
40
|
location = new { type = "boolean", description = "Location point or curve (coordinates in internal feet). Default false." },
|
|
41
41
|
bounding_box = new { type = "boolean", description = "Model bounding box min/max (internal feet). Default false." },
|
|
42
42
|
materials = new { type = "boolean", description = "Material ids/names with area/volume (internal units). Default false." },
|
|
@@ -70,9 +70,9 @@ namespace RevitBridge.Tools
|
|
|
70
70
|
JsonElement include = args.TryGetProperty("include", out var includeElement) && includeElement.ValueKind == JsonValueKind.Object
|
|
71
71
|
? includeElement
|
|
72
72
|
: default;
|
|
73
|
-
bool withParameters = JsonArgs.GetBool(include, "parameters", true);
|
|
74
|
-
bool withTypeParameters = JsonArgs.GetBool(include, "type_parameters", false);
|
|
75
|
-
bool withAnyParameters = withParameters || withTypeParameters;
|
|
73
|
+
bool withParameters = JsonArgs.GetBool(include, "parameters", true);
|
|
74
|
+
bool withTypeParameters = JsonArgs.GetBool(include, "type_parameters", false);
|
|
75
|
+
bool withAnyParameters = withParameters || withTypeParameters;
|
|
76
76
|
bool withLocation = JsonArgs.GetBool(include, "location", false);
|
|
77
77
|
bool withBoundingBox = JsonArgs.GetBool(include, "bounding_box", false);
|
|
78
78
|
bool withMaterials = JsonArgs.GetBool(include, "materials", false);
|
|
@@ -103,11 +103,11 @@ namespace RevitBridge.Tools
|
|
|
103
103
|
|
|
104
104
|
int parameterCount = 0;
|
|
105
105
|
int parameterTotal = 0;
|
|
106
|
-
if (withAnyParameters)
|
|
107
|
-
{
|
|
108
|
-
var parameters = new List<Dictionary<string, object?>>();
|
|
109
|
-
if (withParameters)
|
|
110
|
-
parameterTotal += AppendParameters(doc, element, nameFilter, isType: false, parameters);
|
|
106
|
+
if (withAnyParameters)
|
|
107
|
+
{
|
|
108
|
+
var parameters = new List<Dictionary<string, object?>>();
|
|
109
|
+
if (withParameters)
|
|
110
|
+
parameterTotal += AppendParameters(doc, element, nameFilter, isType: false, parameters);
|
|
111
111
|
if (withTypeParameters && elementType != null)
|
|
112
112
|
parameterTotal += AppendParameters(doc, elementType, nameFilter, isType: true, parameters);
|
|
113
113
|
dto["parameters"] = parameters;
|
|
@@ -124,7 +124,7 @@ namespace RevitBridge.Tools
|
|
|
124
124
|
elements.Add(dto);
|
|
125
125
|
// With a name filter active, "0 params" is ambiguous (none matched vs none
|
|
126
126
|
// exist): report matched-of-total so a localization miss is visible.
|
|
127
|
-
string paramSummary = !withAnyParameters ? string.Empty
|
|
127
|
+
string paramSummary = !withAnyParameters ? string.Empty
|
|
128
128
|
: nameFilter != null ? $", {parameterCount} of {parameterTotal} params matched parameter_names"
|
|
129
129
|
: $", {parameterCount} params";
|
|
130
130
|
compactParts.Add($"'{element.Name}' (id {id}, {element.Category?.Name ?? "no category"}{paramSummary})");
|
|
@@ -167,7 +167,37 @@ namespace RevitBridge.Tools
|
|
|
167
167
|
return total;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
internal static IReadOnlyList<object> ProjectParameters(Document doc, Element element, IReadOnlyList<string> names, bool includeType)
|
|
171
|
+
{
|
|
172
|
+
var result = new List<object>();
|
|
173
|
+
void Project(Element source, bool isType)
|
|
174
|
+
{
|
|
175
|
+
foreach (string input in names.Distinct(StringComparer.OrdinalIgnoreCase))
|
|
176
|
+
{
|
|
177
|
+
IEnumerable<Parameter> matches;
|
|
178
|
+
if (input.StartsWith("guid:", StringComparison.OrdinalIgnoreCase))
|
|
179
|
+
{
|
|
180
|
+
if (!Guid.TryParse(input[5..], out var guid)) throw new ArgumentException($"Invalid shared parameter identity: {input}");
|
|
181
|
+
var parameter = source.get_Parameter(guid);
|
|
182
|
+
matches = parameter == null ? Array.Empty<Parameter>() : new[] { parameter };
|
|
183
|
+
}
|
|
184
|
+
else if (Enum.TryParse<BuiltInParameter>(input, true, out var builtIn) && Enum.IsDefined(builtIn) && builtIn != BuiltInParameter.INVALID)
|
|
185
|
+
{
|
|
186
|
+
var parameter = source.get_Parameter(builtIn);
|
|
187
|
+
matches = parameter == null ? Array.Empty<Parameter>() : new[] { parameter };
|
|
188
|
+
}
|
|
189
|
+
else
|
|
190
|
+
matches = source.Parameters.Cast<Parameter>().Where(p => string.Equals(p.Definition?.Name, input, StringComparison.OrdinalIgnoreCase));
|
|
191
|
+
var values = matches.Select(p => DescribeParameter(doc, p, p.Definition?.Name ?? "", isType)).ToArray();
|
|
192
|
+
result.Add(new { requested = input, isType, found = values.Length > 0, ambiguous = values.Length > 1, matches = values });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
Project(element, false);
|
|
196
|
+
if (includeType && doc.GetElement(element.GetTypeId()) is { } type) Project(type, true);
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
internal static Dictionary<string, object?> DescribeParameter(Document doc, Parameter parameter, string name, bool isType)
|
|
171
201
|
{
|
|
172
202
|
bool hasValue = parameter.HasValue;
|
|
173
203
|
var row = new Dictionary<string, object?>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools;
|
|
5
|
+
|
|
6
|
+
internal sealed class GetElementRelationships : ITool
|
|
7
|
+
{
|
|
8
|
+
public string Name => "get_element_relationships";
|
|
9
|
+
public string Label => "Get Element Relationships";
|
|
10
|
+
public string Tier => "advanced";
|
|
11
|
+
public string Description => "Inspect host-document element relationships: type, level, owning view, host, family parent/subcomponents, group or assembly membership, joined geometry and logical dependents. Dependents are not a complete deletion-impact prediction. Pagination applies independently to each relationship; links are not traversed.";
|
|
12
|
+
private static readonly string[] Kinds = { "type", "level", "owner_view", "host", "parent", "subcomponents", "group", "assembly", "members", "joined", "dependents" };
|
|
13
|
+
public object ParametersSchema => new
|
|
14
|
+
{
|
|
15
|
+
type = "object",
|
|
16
|
+
properties = new
|
|
17
|
+
{
|
|
18
|
+
element_id = new { type = "integer" },
|
|
19
|
+
relationships = new { type = "array", items = new { type = "string", @enum = Kinds } },
|
|
20
|
+
offset = new { type = "integer", minimum = 0 },
|
|
21
|
+
limit = new { type = "integer", minimum = 1, maximum = 200 },
|
|
22
|
+
},
|
|
23
|
+
required = new[] { "element_id" },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
27
|
+
{
|
|
28
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
29
|
+
var id = JsonArgs.GetLong(args, "element_id") ?? throw new ArgumentException("element_id is required.");
|
|
30
|
+
var element = doc.GetElement(new ElementId(id)) ?? throw new ArgumentException("element_id does not exist in the active document.");
|
|
31
|
+
var kinds = (IReadOnlyList<string>?)JsonArgs.GetStringArray(args, "relationships") ?? Kinds;
|
|
32
|
+
if (kinds.Any(kind => !Kinds.Contains(kind))) throw new ArgumentException("Unknown relationship kind.");
|
|
33
|
+
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0));
|
|
34
|
+
int limit = Math.Clamp(JsonArgs.GetInt(args, "limit", 100), 1, 200);
|
|
35
|
+
var result = new Dictionary<string, object?>();
|
|
36
|
+
foreach (var kind in kinds.Distinct())
|
|
37
|
+
{
|
|
38
|
+
IEnumerable<ElementId> ids = kind switch
|
|
39
|
+
{
|
|
40
|
+
"type" => One(element.GetTypeId()),
|
|
41
|
+
"level" => One(element.LevelId),
|
|
42
|
+
"owner_view" => One(element.OwnerViewId),
|
|
43
|
+
"host" => One((element as FamilyInstance)?.Host?.Id),
|
|
44
|
+
"parent" => One((element as FamilyInstance)?.SuperComponent?.Id),
|
|
45
|
+
"subcomponents" => element is FamilyInstance family ? family.GetSubComponentIds() : Array.Empty<ElementId>(),
|
|
46
|
+
"group" => One(element.GroupId),
|
|
47
|
+
"assembly" => One(element.AssemblyInstanceId),
|
|
48
|
+
"members" => element is Group group ? group.GetMemberIds()
|
|
49
|
+
: element is AssemblyInstance assembly ? assembly.GetMemberIds() : Array.Empty<ElementId>(),
|
|
50
|
+
"joined" => Joined(doc, element),
|
|
51
|
+
"dependents" => element.GetDependentElements(null),
|
|
52
|
+
_ => Array.Empty<ElementId>(),
|
|
53
|
+
};
|
|
54
|
+
var all = ids.Where(x => x != ElementId.InvalidElementId).DistinctBy(x => x.Value).OrderBy(x => x.Value).ToList();
|
|
55
|
+
var rows = all.Skip(offset).Take(limit).Select(x =>
|
|
56
|
+
{
|
|
57
|
+
var related = doc.GetElement(x);
|
|
58
|
+
return new { id = x.Value, name = related?.Name, category = related?.Category?.Name, unique_id = related?.UniqueId };
|
|
59
|
+
}).ToArray();
|
|
60
|
+
result[kind] = new { total_count = all.Count, returned_count = rows.Length, offset,
|
|
61
|
+
has_more = offset + rows.Length < all.Count,
|
|
62
|
+
next_offset = offset + rows.Length < all.Count ? (int?)(offset + rows.Length) : null, elements = rows };
|
|
63
|
+
}
|
|
64
|
+
return new { document_id = DocumentGuard.GetIdentity(doc), element_id = id, relationships = result };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private static IEnumerable<ElementId> One(ElementId? id)
|
|
68
|
+
=> id == null || id == ElementId.InvalidElementId ? Array.Empty<ElementId>() : new[] { id };
|
|
69
|
+
|
|
70
|
+
private static IEnumerable<ElementId> Joined(Document doc, Element element)
|
|
71
|
+
{
|
|
72
|
+
// JoinGeometryUtils rejects family documents; surface that restriction explicitly.
|
|
73
|
+
if (doc.IsFamilyDocument) throw new ArgumentException("joined relationships require a project document. Request other relationship kinds for families.");
|
|
74
|
+
return JoinGeometryUtils.GetJoinedElements(doc, element);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -21,7 +21,7 @@ namespace RevitBridge.Tools
|
|
|
21
21
|
|
|
22
22
|
public string Name => "get_elements";
|
|
23
23
|
public string Label => "Get Elements";
|
|
24
|
-
public string Description => "Query Revit elements: scope by category (display name like 'Walls' or enum name like 'OST_Walls'), element class, level, type id, or active view; filter by parameter rules; paginate with offset/limit or just count with count_only. Returns identity fields
|
|
24
|
+
public string Description => "Query Revit elements: scope by category (display name like 'Walls' or enum name like 'OST_Walls'), element class, level, type id, or active view; filter by parameter rules; paginate with offset/limit or just count with count_only. Returns identity fields and optional parameter_names projections; include_type_parameters also reads the requested values from each type. Rules with an explicit BuiltInParameter or shared GUID can evaluate inside Revit's collector; display-name rules, regex rules, and unsupported quick filters run as a per-element scan. A display name can identify different parameters even within one category or class. Scope queries to reduce the scan, or use an explicit parameter identity when appropriate. Numeric rule values are interpreted in the document's display units for that parameter unless 'unit' is given.";
|
|
25
25
|
|
|
26
26
|
public object ParametersSchema => new
|
|
27
27
|
{
|
|
@@ -72,12 +72,18 @@ namespace RevitBridge.Tools
|
|
|
72
72
|
level = new { type = "string", description = "Only elements hosted on this level (level name or id)." },
|
|
73
73
|
type_id = new { type = "integer", description = "Only instances of this element type id (see get_element_types)." },
|
|
74
74
|
in_active_view = new { type = "boolean", description = "Only elements visible in the active view. Default false." },
|
|
75
|
-
count_only = new { type = "boolean", description = "Return only total_count, no element rows. Default false." },
|
|
75
|
+
count_only = new { type = "boolean", description = "Return only total_count, no element rows. Default false." },
|
|
76
|
+
parameter_names = new
|
|
77
|
+
{
|
|
78
|
+
type = "array", maxItems = 20, items = new { type = "string" },
|
|
79
|
+
description = "Optional parameter projections for each returned element: display names, BuiltInParameter names or guid:<GUID>. Every matching parameter is reported, including missing/ambiguous matches. Numeric values use internal units with separate display values. Ignored by count_only.",
|
|
80
|
+
},
|
|
81
|
+
include_type_parameters = new { type = "boolean", description = "Also project requested parameters from each element's type. Default false." },
|
|
76
82
|
fields = new
|
|
77
83
|
{
|
|
78
84
|
type = "array",
|
|
79
85
|
items = new { type = "string", @enum = new[] { "id", "name", "category", "typeName", "levelId" } },
|
|
80
|
-
description = "Identity fields per row; default all five. id is always included.
|
|
86
|
+
description = "Identity fields per row; default all five. id is always included. Use parameter_names for optional values alongside these fields.",
|
|
81
87
|
},
|
|
82
88
|
offset = new { type = "integer", description = "Pagination offset. Default 0." },
|
|
83
89
|
limit = new { type = "integer", description = "Max rows to return (1-1000). Default 200." },
|
|
@@ -89,7 +95,7 @@ namespace RevitBridge.Tools
|
|
|
89
95
|
public IReadOnlyList<string>? PromptGuidelines => new[]
|
|
90
96
|
{
|
|
91
97
|
"Use get_elements to list or count elements of any category or class (walls, doors, rooms, sheets, views, ...); use the returned ids with the other Revit tools.",
|
|
92
|
-
"get_elements
|
|
98
|
+
"get_elements can project up to 20 parameter_names per row; use get_element_details for full element inspection.",
|
|
93
99
|
};
|
|
94
100
|
|
|
95
101
|
public object? Execute(JsonElement args, ToolContext context)
|
|
@@ -103,7 +109,10 @@ namespace RevitBridge.Tools
|
|
|
103
109
|
|| string.Equals(JsonArgs.GetString(args, "mode"), "count", StringComparison.OrdinalIgnoreCase);
|
|
104
110
|
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0));
|
|
105
111
|
int limit = Math.Clamp(JsonArgs.GetInt(args, "limit", DefaultLimit), 1, MaxLimit);
|
|
106
|
-
var fields = ResolveFields(args);
|
|
112
|
+
var fields = ResolveFields(args);
|
|
113
|
+
var parameterNames = JsonArgs.GetStringArray(args, "parameter_names");
|
|
114
|
+
if (parameterNames?.Count > 20) throw new ArgumentException("parameter_names allows at most 20 parameter identities.");
|
|
115
|
+
bool includeTypeParameters = JsonArgs.GetBool(args, "include_type_parameters", false);
|
|
107
116
|
|
|
108
117
|
ElementId? categoryId = string.IsNullOrWhiteSpace(categoryInput) ? null : CategoryResolver.Resolve(doc, categoryInput);
|
|
109
118
|
Type? elementClass = string.IsNullOrWhiteSpace(classInput) ? null : ElementClassResolver.Resolve(classInput);
|
|
@@ -158,8 +167,13 @@ namespace RevitBridge.Tools
|
|
|
158
167
|
{
|
|
159
168
|
if (postPredicate != null && !postPredicate(element))
|
|
160
169
|
continue;
|
|
161
|
-
if (rows != null && total >= offset && rows.Count < limit)
|
|
162
|
-
|
|
170
|
+
if (rows != null && total >= offset && rows.Count < limit)
|
|
171
|
+
{
|
|
172
|
+
var row = ElementIdentity.Build(doc, element, fields);
|
|
173
|
+
if (parameterNames is { Count: > 0 })
|
|
174
|
+
row["parameters"] = GetElementDetails.ProjectParameters(doc, element, parameterNames, includeTypeParameters);
|
|
175
|
+
rows.Add(row);
|
|
176
|
+
}
|
|
163
177
|
total++;
|
|
164
178
|
}
|
|
165
179
|
|
|
@@ -292,9 +306,9 @@ namespace RevitBridge.Tools
|
|
|
292
306
|
if (rules.Count == 0)
|
|
293
307
|
return (null, null, Array.Empty<string>());
|
|
294
308
|
|
|
295
|
-
// Probe a few in-scope elements for missing-name diagnostics and to find
|
|
296
|
-
// storage/spec exemplars for explicit parameter identities. A sample must
|
|
297
|
-
// never turn a display name into an assumed globally uniform identity.
|
|
309
|
+
// Probe a few in-scope elements for missing-name diagnostics and to find
|
|
310
|
+
// storage/spec exemplars for explicit parameter identities. A sample must
|
|
311
|
+
// never turn a display name into an assumed globally uniform identity.
|
|
298
312
|
var probes = new List<Element>(ProbeSize);
|
|
299
313
|
foreach (Element element in createBaseCollector())
|
|
300
314
|
{
|
|
@@ -326,19 +340,19 @@ namespace RevitBridge.Tools
|
|
|
326
340
|
}
|
|
327
341
|
}
|
|
328
342
|
|
|
329
|
-
foreach (var rule in rules)
|
|
330
|
-
{
|
|
331
|
-
if (rule.Op is RuleOp.Regex or RuleOp.IsEmpty or RuleOp.IsNotEmpty)
|
|
332
|
-
continue; // always post-scan (missing-parameter semantics)
|
|
333
|
-
// Category/class scope and unanimous samples do not establish a
|
|
334
|
-
// uniform parameter identity across later families. Resolve display
|
|
335
|
-
// names per element; only explicit identities may use a quick rule.
|
|
336
|
-
if (rule.BuiltIn is null && rule.SharedGuid is null)
|
|
337
|
-
continue;
|
|
338
|
-
var found = probes.Select(probe => FindParameter(probe, rule)).Where(parameter => parameter != null).ToList();
|
|
339
|
-
if (found.Count == 0)
|
|
340
|
-
continue;
|
|
341
|
-
rule.QuickRule = TryBuildQuickRule(doc, rule, found[0]!);
|
|
343
|
+
foreach (var rule in rules)
|
|
344
|
+
{
|
|
345
|
+
if (rule.Op is RuleOp.Regex or RuleOp.IsEmpty or RuleOp.IsNotEmpty)
|
|
346
|
+
continue; // always post-scan (missing-parameter semantics)
|
|
347
|
+
// Category/class scope and unanimous samples do not establish a
|
|
348
|
+
// uniform parameter identity across later families. Resolve display
|
|
349
|
+
// names per element; only explicit identities may use a quick rule.
|
|
350
|
+
if (rule.BuiltIn is null && rule.SharedGuid is null)
|
|
351
|
+
continue;
|
|
352
|
+
var found = probes.Select(probe => FindParameter(probe, rule)).Where(parameter => parameter != null).ToList();
|
|
353
|
+
if (found.Count == 0)
|
|
354
|
+
continue;
|
|
355
|
+
rule.QuickRule = TryBuildQuickRule(doc, rule, found[0]!);
|
|
342
356
|
}
|
|
343
357
|
|
|
344
358
|
var quickRules = rules.Where(rule => rule.QuickRule != null).ToList();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using System.Text.Json.Nodes;
|
|
3
|
+
using Autodesk.Revit.DB;
|
|
4
|
+
|
|
5
|
+
namespace RevitBridge.Tools;
|
|
6
|
+
|
|
7
|
+
internal sealed class GetLinkedElements : ITool
|
|
8
|
+
{
|
|
9
|
+
public string Name => "get_linked_elements";
|
|
10
|
+
public string Label => "Get Linked Elements";
|
|
11
|
+
public string Tier => "advanced";
|
|
12
|
+
public string Description => "Query one loaded Revit link with get_elements filters and pagination. Use link_instance_id and expected_linked_document_id from get_linked_models. Returned element IDs belong to the linked document and cannot be passed to host write tools. Optional bounds are axis-aligned in host coordinates, in internal feet. Only direct links are supported; active-view scoping is unavailable.";
|
|
13
|
+
public object ParametersSchema
|
|
14
|
+
{
|
|
15
|
+
get
|
|
16
|
+
{
|
|
17
|
+
var schema = JsonSerializer.SerializeToNode(new GetElements().ParametersSchema)!.AsObject();
|
|
18
|
+
var properties = schema["properties"]!.AsObject();
|
|
19
|
+
properties.Remove("in_active_view");
|
|
20
|
+
properties["link_instance_id"] = new JsonObject { ["type"] = "integer" };
|
|
21
|
+
properties["expected_linked_document_id"] = new JsonObject { ["type"] = "string" };
|
|
22
|
+
properties["include_bounds"] = new JsonObject { ["type"] = "boolean" };
|
|
23
|
+
schema["required"] = new JsonArray("link_instance_id", "expected_linked_document_id");
|
|
24
|
+
return schema;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
29
|
+
{
|
|
30
|
+
var host = context.Document ?? throw new NoActiveDocumentException();
|
|
31
|
+
var id = JsonArgs.GetLong(args, "link_instance_id") ?? throw new ArgumentException("link_instance_id is required.");
|
|
32
|
+
var link = host.GetElement(new ElementId(id)) as RevitLinkInstance
|
|
33
|
+
?? throw new ArgumentException("link_instance_id is not a Revit link instance in the active host document.");
|
|
34
|
+
var linked = link.GetLinkDocument() ?? throw new ArgumentException("The link is unloaded. Load it in Revit before querying it.");
|
|
35
|
+
string identity = DocumentGuard.GetIdentity(linked);
|
|
36
|
+
if (!string.Equals(JsonArgs.GetString(args, "expected_linked_document_id"), identity, StringComparison.Ordinal))
|
|
37
|
+
throw new ArgumentException("The linked document identity is missing or stale. Read get_linked_models again.");
|
|
38
|
+
if (JsonArgs.GetBool(args, "in_active_view", false))
|
|
39
|
+
throw new ArgumentException("in_active_view is not supported for linked queries.");
|
|
40
|
+
|
|
41
|
+
var result = (ToolOutput)new GetElements().Execute(args, new ToolContext(linked, null))!;
|
|
42
|
+
var payload = JsonSerializer.SerializeToNode(result.Payload)!.AsObject();
|
|
43
|
+
payload["host_document_id"] = DocumentGuard.GetIdentity(host);
|
|
44
|
+
payload["linked_document_id"] = identity;
|
|
45
|
+
payload["link_instance_id"] = id;
|
|
46
|
+
payload["coordinate_unit"] = "ft";
|
|
47
|
+
if (payload["elements"] is JsonArray elements)
|
|
48
|
+
{
|
|
49
|
+
var transform = link.GetTotalTransform();
|
|
50
|
+
foreach (var row in elements)
|
|
51
|
+
{
|
|
52
|
+
var element = linked.GetElement(new ElementId(row!["id"]!.GetValue<long>()));
|
|
53
|
+
row["unique_id"] = element.UniqueId;
|
|
54
|
+
row["reference"] = new JsonObject
|
|
55
|
+
{
|
|
56
|
+
["host_document_id"] = DocumentGuard.GetIdentity(host),
|
|
57
|
+
["link_instance_id"] = id,
|
|
58
|
+
["linked_document_id"] = identity,
|
|
59
|
+
["element_id"] = element.Id.Value,
|
|
60
|
+
};
|
|
61
|
+
if (JsonArgs.GetBool(args, "include_bounds", false))
|
|
62
|
+
row["host_bounds"] = JsonSerializer.SerializeToNode(HostBounds(element.get_BoundingBox(null), transform));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return new ToolOutput(payload, result.CompactText);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
internal static object? HostBounds(BoundingBoxXYZ? box, Transform placement)
|
|
69
|
+
{
|
|
70
|
+
if (box == null) return null;
|
|
71
|
+
var corners = new List<XYZ>(8);
|
|
72
|
+
foreach (double x in new[] { box.Min.X, box.Max.X })
|
|
73
|
+
foreach (double y in new[] { box.Min.Y, box.Max.Y })
|
|
74
|
+
foreach (double z in new[] { box.Min.Z, box.Max.Z })
|
|
75
|
+
corners.Add(placement.OfPoint(box.Transform.OfPoint(new XYZ(x, y, z))));
|
|
76
|
+
return new
|
|
77
|
+
{
|
|
78
|
+
min = new[] { corners.Min(p => p.X), corners.Min(p => p.Y), corners.Min(p => p.Z) },
|
|
79
|
+
max = new[] { corners.Max(p => p.X), corners.Max(p => p.Y), corners.Max(p => p.Z) },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools;
|
|
5
|
+
|
|
6
|
+
internal sealed class GetLinkedModels : ITool
|
|
7
|
+
{
|
|
8
|
+
public string Name => "get_linked_models";
|
|
9
|
+
public string Label => "Get Linked Models";
|
|
10
|
+
public string Tier => "advanced";
|
|
11
|
+
public string Description => "List placed Revit links, including unloaded instances, exact linked document identities and their transforms into host coordinates. Nested links are not traversed. Coordinates and transform origins use internal feet.";
|
|
12
|
+
public object ParametersSchema => new
|
|
13
|
+
{
|
|
14
|
+
type = "object",
|
|
15
|
+
properties = new
|
|
16
|
+
{
|
|
17
|
+
offset = new { type = "integer", minimum = 0 },
|
|
18
|
+
limit = new { type = "integer", minimum = 1, maximum = 1000 },
|
|
19
|
+
},
|
|
20
|
+
required = Array.Empty<string>(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
24
|
+
{
|
|
25
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
26
|
+
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0));
|
|
27
|
+
int limit = Math.Clamp(JsonArgs.GetInt(args, "limit", 100), 1, 1000);
|
|
28
|
+
var links = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance))
|
|
29
|
+
.Cast<RevitLinkInstance>().OrderBy(x => x.Id.Value).ToList();
|
|
30
|
+
var rows = links.Skip(offset).Take(limit).Select(link =>
|
|
31
|
+
{
|
|
32
|
+
var linked = link.GetLinkDocument();
|
|
33
|
+
var transform = link.GetTotalTransform();
|
|
34
|
+
return new
|
|
35
|
+
{
|
|
36
|
+
link_instance_id = link.Id.Value,
|
|
37
|
+
unique_id = link.UniqueId,
|
|
38
|
+
name = link.Name,
|
|
39
|
+
type_id = link.GetTypeId().Value,
|
|
40
|
+
loaded = linked != null,
|
|
41
|
+
linked_document_id = linked == null ? null : DocumentGuard.GetIdentity(linked),
|
|
42
|
+
document_title = linked?.Title,
|
|
43
|
+
transform = new
|
|
44
|
+
{
|
|
45
|
+
origin = Coordinates(transform.Origin),
|
|
46
|
+
basis_x = Coordinates(transform.BasisX),
|
|
47
|
+
basis_y = Coordinates(transform.BasisY),
|
|
48
|
+
basis_z = Coordinates(transform.BasisZ),
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}).ToArray();
|
|
52
|
+
return new
|
|
53
|
+
{
|
|
54
|
+
document_id = DocumentGuard.GetIdentity(doc),
|
|
55
|
+
coordinate_unit = "ft",
|
|
56
|
+
total_count = links.Count,
|
|
57
|
+
returned_count = rows.Length,
|
|
58
|
+
offset,
|
|
59
|
+
has_more = offset + rows.Length < links.Count,
|
|
60
|
+
next_offset = offset + rows.Length < links.Count ? (int?)(offset + rows.Length) : null,
|
|
61
|
+
links = rows,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
internal static double[] Coordinates(XYZ point) => new[] { point.X, point.Y, point.Z };
|
|
66
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools;
|
|
5
|
+
|
|
6
|
+
internal sealed class GetModelCoordinates : ITool
|
|
7
|
+
{
|
|
8
|
+
public string Name => "get_model_coordinates";
|
|
9
|
+
public string Label => "Get Model Coordinates";
|
|
10
|
+
public string Tier => "advanced";
|
|
11
|
+
public string Description => "Read project/survey base points, active project location and site coordinates. Optionally report shared coordinates for up to 100 points expressed along document internal axes. Required unit applies to input points and every returned length; angles and latitude/longitude are degrees. The active location's Revit GetProjectPosition defines the shared mapping. List project locations with paging. Does not infer a GIS coordinate reference system or modify/acquire coordinates.";
|
|
12
|
+
public object ParametersSchema => new
|
|
13
|
+
{
|
|
14
|
+
type = "object", properties = new
|
|
15
|
+
{
|
|
16
|
+
unit = ModelEditInputs.LengthUnitSchema,
|
|
17
|
+
points = new { type = "array", maxItems = 100, items = ModelEditInputs.VectorSchema("Point along document internal axes, in unit.") },
|
|
18
|
+
offset = new { type = "integer", minimum = 0 }, limit = new { type = "integer", minimum = 1, maximum = 100 },
|
|
19
|
+
}, required = new[] { "unit" },
|
|
20
|
+
};
|
|
21
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
22
|
+
{
|
|
23
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
24
|
+
if (doc.IsFamilyDocument) throw new ArgumentException("Project coordinates require a project document.");
|
|
25
|
+
double scale = ModelEditInputs.LengthScale(args);
|
|
26
|
+
var active = doc.ActiveProjectLocation;
|
|
27
|
+
object Position(ProjectPosition position) => new { east_west = position.EastWest / scale, north_south = position.NorthSouth / scale, elevation = position.Elevation / scale, angle_degrees = position.Angle * 180 / Math.PI };
|
|
28
|
+
object? Base(BasePoint? point) => point == null ? null : new { id = point.Id.Value, internal_position = SpatialBounds.Coordinates(point.Position, scale), shared_position = SpatialBounds.Coordinates(point.SharedPosition, scale) };
|
|
29
|
+
var points = new List<object>();
|
|
30
|
+
if (args.TryGetProperty("points", out var values))
|
|
31
|
+
{
|
|
32
|
+
if (values.ValueKind != JsonValueKind.Array || values.GetArrayLength() > 100) throw new ArgumentException("points must be an array of at most 100 XYZ points.");
|
|
33
|
+
foreach (var value in values.EnumerateArray())
|
|
34
|
+
{
|
|
35
|
+
var wrapper = JsonSerializer.SerializeToElement(new { point = value });
|
|
36
|
+
var point = ModelEditInputs.Vector(wrapper, "point").Multiply(scale);
|
|
37
|
+
points.Add(new { internal_position = SpatialBounds.Coordinates(point, scale), shared_position = Position(active.GetProjectPosition(point)) });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
var locations = doc.ProjectLocations.Cast<ProjectLocation>().OrderBy(x => x.Id.Value).ToList();
|
|
41
|
+
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0)), limit = Math.Clamp(JsonArgs.GetInt(args, "limit", 50), 1, 100);
|
|
42
|
+
var page = locations.Skip(offset).Take(limit).Select(x => new { id = x.Id.Value, name = x.Name, active = x.Id == active.Id, internal_origin_in_shared_coordinates = Position(x.GetProjectPosition(XYZ.Zero)) }).ToArray();
|
|
43
|
+
var site = doc.SiteLocation;
|
|
44
|
+
return new { unit = JsonArgs.GetString(args, "unit"), angle_unit = "degrees", point_input_coordinates = "document_internal", active_project_location = new { id = active.Id.Value, name = active.Name },
|
|
45
|
+
project_base_point = Base(BasePoint.GetProjectBasePoint(doc)), survey_point = Base(BasePoint.GetSurveyPoint(doc)),
|
|
46
|
+
site = new { name = site.Name, latitude_degrees = site.Latitude * 180 / Math.PI, longitude_degrees = site.Longitude * 180 / Math.PI, time_zone = site.TimeZone },
|
|
47
|
+
total_locations = locations.Count, offset, next_offset = offset + page.Length < locations.Count ? (int?)(offset + page.Length) : null, locations = page, points };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -45,8 +45,8 @@ namespace RevitBridge.Tools
|
|
|
45
45
|
string? lengthUnit = DisplayUnitName(units, SpecTypeId.Length);
|
|
46
46
|
var project = new Dictionary<string, object?>
|
|
47
47
|
{
|
|
48
|
-
["title"] = doc.Title,
|
|
49
|
-
["documentId"] = DocumentGuard.GetIdentity(doc),
|
|
48
|
+
["title"] = doc.Title,
|
|
49
|
+
["documentId"] = DocumentGuard.GetIdentity(doc),
|
|
50
50
|
["name"] = info?.Name,
|
|
51
51
|
["number"] = info?.Number,
|
|
52
52
|
["clientName"] = info?.ClientName,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools;
|
|
5
|
+
|
|
6
|
+
internal sealed class GetScheduleFields : ITool
|
|
7
|
+
{
|
|
8
|
+
public string Name => "get_schedule_fields";
|
|
9
|
+
public string Label => "Get Schedule Fields";
|
|
10
|
+
public string Tier => "advanced";
|
|
11
|
+
public string Description => "List fields eligible to be added to one existing schedule, with paging and localized-name filtering. A field is identified by the pair parameter_id + field_type; negative built-in parameter IDs are valid. These identities differ from schedule-local field_id values returned by get_schedules. Existing fields are marked included. Count may appear in the returned fields; manage_schedules accepts its discovered pair or field_type Count without a parameter_id. Calculated/combined fields are not exposed here.";
|
|
12
|
+
public object ParametersSchema => new
|
|
13
|
+
{
|
|
14
|
+
type = "object", properties = new
|
|
15
|
+
{
|
|
16
|
+
schedule_id = new { type = "integer", minimum = 1 }, name_filter = new { type = "string" },
|
|
17
|
+
offset = new { type = "integer", minimum = 0 }, limit = new { type = "integer", minimum = 1, maximum = 200 },
|
|
18
|
+
}, required = new[] { "schedule_id" },
|
|
19
|
+
};
|
|
20
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
21
|
+
{
|
|
22
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
23
|
+
var schedule = doc.GetElement(new ElementId(JsonArgs.GetLong(args, "schedule_id") ?? 0)) as ViewSchedule ?? throw new ArgumentException("schedule_id is not a schedule.");
|
|
24
|
+
if (schedule.IsTemplate || schedule.IsTitleblockRevisionSchedule) throw new ArgumentException("Use a regular schedule, not a template or titleblock revision schedule.");
|
|
25
|
+
int offset = JsonArgs.GetInt(args, "offset", 0), limit = JsonArgs.GetInt(args, "limit", 100);
|
|
26
|
+
if (offset < 0 || limit is < 1 or > 200) throw new ArgumentException("Invalid paging range.");
|
|
27
|
+
string needle = JsonArgs.GetString(args, "name_filter") ?? "";
|
|
28
|
+
var definition = schedule.Definition;
|
|
29
|
+
var included = definition.GetFieldOrder().Select(id => definition.GetField(id)).Select(f => (f.ParameterId.Value, f.FieldType)).ToHashSet();
|
|
30
|
+
var fields = definition.GetSchedulableFields().Select(f => new
|
|
31
|
+
{
|
|
32
|
+
parameter_id = f.ParameterId.Value, field_type = f.FieldType.ToString(), name = f.GetName(doc), included = included.Contains((f.ParameterId.Value, f.FieldType)),
|
|
33
|
+
}).Where(f => f.name.Contains(needle, StringComparison.OrdinalIgnoreCase)).OrderBy(f => f.parameter_id).ThenBy(f => f.field_type, StringComparer.Ordinal).ToArray();
|
|
34
|
+
var page = fields.Skip(offset).Take(limit).ToArray();
|
|
35
|
+
return new { schedule_id = schedule.Id.Value, total_count = fields.Length, offset, returned_count = page.Length, next_offset = offset + page.Length < fields.Length ? (int?)(offset + page.Length) : null, fields = page };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using Autodesk.Revit.DB;
|
|
3
|
+
|
|
4
|
+
namespace RevitBridge.Tools;
|
|
5
|
+
|
|
6
|
+
internal sealed class GetSchedules : ITool
|
|
7
|
+
{
|
|
8
|
+
public string Name => "get_schedules";
|
|
9
|
+
public string Label => "Get Schedules";
|
|
10
|
+
public string Tier => "advanced";
|
|
11
|
+
public string Description => "List schedules, or read one schedule's field definitions and displayed body cells by schedule_id. Cell text uses Revit formatting and may contain group headings/totals; rows are not guaranteed to correspond to individual elements. Row and column pagination are independent. Templates and revision schedules are excluded from the list.";
|
|
12
|
+
public object ParametersSchema => new
|
|
13
|
+
{
|
|
14
|
+
type = "object",
|
|
15
|
+
properties = new
|
|
16
|
+
{
|
|
17
|
+
schedule_id = new { type = "integer" },
|
|
18
|
+
name_filter = new { type = "string" },
|
|
19
|
+
offset = new { type = "integer", minimum = 0, description = "List offset or body row offset." },
|
|
20
|
+
limit = new { type = "integer", minimum = 1, maximum = 200 },
|
|
21
|
+
column_offset = new { type = "integer", minimum = 0 },
|
|
22
|
+
column_limit = new { type = "integer", minimum = 1, maximum = 50 },
|
|
23
|
+
},
|
|
24
|
+
required = Array.Empty<string>(),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
public object Execute(JsonElement args, ToolContext context)
|
|
28
|
+
{
|
|
29
|
+
var doc = context.Document ?? throw new NoActiveDocumentException();
|
|
30
|
+
int offset = Math.Max(0, JsonArgs.GetInt(args, "offset", 0));
|
|
31
|
+
int limit = Math.Clamp(JsonArgs.GetInt(args, "limit", 50), 1, 200);
|
|
32
|
+
if (JsonArgs.GetLong(args, "schedule_id") is not { } id)
|
|
33
|
+
{
|
|
34
|
+
string needle = JsonArgs.GetString(args, "name_filter") ?? "";
|
|
35
|
+
var schedules = new FilteredElementCollector(doc).OfClass(typeof(ViewSchedule)).Cast<ViewSchedule>()
|
|
36
|
+
.Where(s => !s.IsTemplate && !s.IsTitleblockRevisionSchedule && s.Name.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
|
37
|
+
.OrderBy(s => s.Id.Value).ToList();
|
|
38
|
+
var rows = schedules.Skip(offset).Take(limit).Select(s => new
|
|
39
|
+
{
|
|
40
|
+
id = s.Id.Value, name = s.Name, unique_id = s.UniqueId,
|
|
41
|
+
category_id = s.Definition.CategoryId.Value,
|
|
42
|
+
is_itemized = s.Definition.IsItemized,
|
|
43
|
+
field_count = s.Definition.GetFieldCount(),
|
|
44
|
+
}).ToArray();
|
|
45
|
+
return new { total_count = schedules.Count, returned_count = rows.Length, offset,
|
|
46
|
+
has_more = offset + rows.Length < schedules.Count,
|
|
47
|
+
next_offset = offset + rows.Length < schedules.Count ? (int?)(offset + rows.Length) : null, schedules = rows };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
var schedule = doc.GetElement(new ElementId(id)) as ViewSchedule
|
|
51
|
+
?? throw new ArgumentException("schedule_id is not a schedule in the active document.");
|
|
52
|
+
if (schedule.IsTemplate) throw new ArgumentException("Schedule templates do not contain displayed body rows.");
|
|
53
|
+
using var table = schedule.GetTableData();
|
|
54
|
+
using var body = table.GetSectionData(SectionType.Body);
|
|
55
|
+
int columnOffset = Math.Max(0, JsonArgs.GetInt(args, "column_offset", 0));
|
|
56
|
+
int columnLimit = Math.Clamp(JsonArgs.GetInt(args, "column_limit", 50), 1, 50);
|
|
57
|
+
int columnCount = Math.Min(columnLimit, Math.Max(0, body.NumberOfColumns - columnOffset));
|
|
58
|
+
int rowCount = Math.Min(limit, Math.Max(0, body.NumberOfRows - offset));
|
|
59
|
+
var cells = Enumerable.Range(0, rowCount).Select(row => new
|
|
60
|
+
{
|
|
61
|
+
row_index = body.FirstRowNumber + offset + row,
|
|
62
|
+
cells = Enumerable.Range(0, columnCount).Select(col => schedule.GetCellText(SectionType.Body,
|
|
63
|
+
body.FirstRowNumber + offset + row, body.FirstColumnNumber + columnOffset + col)).ToArray(),
|
|
64
|
+
}).ToArray();
|
|
65
|
+
var fields = schedule.Definition.GetFieldOrder().Select(fieldId =>
|
|
66
|
+
{
|
|
67
|
+
var field = schedule.Definition.GetField(fieldId);
|
|
68
|
+
return new { field_id = fieldId.IntegerValue, parameter_id = field.ParameterId.Value,
|
|
69
|
+
name = field.GetName(), heading = field.ColumnHeading, hidden = field.IsHidden, field_type = field.FieldType.ToString(),
|
|
70
|
+
spec_type_id = field.GetSpecTypeId().TypeId, grid_width_feet = field.GridColumnWidth, sheet_width_feet = field.SheetColumnWidth,
|
|
71
|
+
can_filter_value = schedule.Definition.CanFilterByValue(fieldId), can_filter_substring = schedule.Definition.CanFilterBySubstring(fieldId) };
|
|
72
|
+
}).ToArray();
|
|
73
|
+
return new
|
|
74
|
+
{
|
|
75
|
+
schedule_id = id, name = schedule.Name, is_itemized = schedule.Definition.IsItemized, fields,
|
|
76
|
+
sort_fields = schedule.Definition.GetSortGroupFields().Select(sort => new { field_id = sort.FieldId.IntegerValue, order = sort.SortOrder.ToString(), show_header = sort.ShowHeader }).ToArray(),
|
|
77
|
+
filters = schedule.Definition.GetFilters().Select(filter => new { field_id = filter.FieldId.IntegerValue, comparison = filter.FilterType.ToString(),
|
|
78
|
+
value = filter.IsStringValue ? (object)filter.GetStringValue() : filter.IsDoubleValue ? filter.GetDoubleValue() : filter.IsIntegerValue ? filter.GetIntegerValue() : filter.IsElementIdValue ? filter.GetElementIdValue().Value : null,
|
|
79
|
+
value_unit = filter.IsDoubleValue ? "internal" : null }).ToArray(),
|
|
80
|
+
total_rows = body.NumberOfRows, total_columns = body.NumberOfColumns,
|
|
81
|
+
offset, returned_rows = rowCount,
|
|
82
|
+
next_offset = offset + rowCount < body.NumberOfRows ? (int?)(offset + rowCount) : null,
|
|
83
|
+
column_offset = columnOffset, returned_columns = columnCount,
|
|
84
|
+
first_column_index = body.FirstColumnNumber + columnOffset,
|
|
85
|
+
next_column_offset = columnOffset + columnCount < body.NumberOfColumns ? (int?)(columnOffset + columnCount) : null,
|
|
86
|
+
rows = cells,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|