Non-Invasive BIM & QA Visualization with DrawableOverrule in GstarCAD .NET (dev-cookbook-21)
Use Gssoft.GstarCAD.GraphicsInterface.DrawableOverrule in C# .NET to render heatmaps, clash halos, and flow arrows over standard DWG entities without creating proxy objects.
1. Why `DrawableOverrule` Eliminates the Custom Proxy Entity Dilemma
Historically, if an ISV wanted a pipe polyline to display directional flow arrows, insulation halos, and colour-coded pressure warnings, they had to define a custom C++ `AcDbEntity` subclass. However, custom entities introduce a painful deployment burden: whenever a client or subcontractor opens that `.dwg` without the C++ Object Enabler installed, the entities degrade into static `ACAD_PROXY_ENTITY` wrappers. GstarCAD 2027's `.NET` DrawableOverrule (`Gssoft.GstarCAD.GraphicsInterface.DrawableOverrule`) solves this completely.
With `DrawableOverrule`, you store standard `Line`, `Polyline`, or `BlockReference` entities inside the AC1032 `.dwg` database alongside lightweight `XData` or `ExtensionDictionary` metadata. At runtime, your `.NET` plugin intercepts `WorldDraw()` and `ViewportDraw()` on matching entities and renders rich procedural overlays on the fly—while keeping the underlying `.dwg` 100% vanilla and proxy-free for external recipients.
2. C# .NET Implementation: XData-Filtered Acoustic & Clash Halo Overrule
The C# class below hooks `RXObject.GetClass(typeof(Polyline))`, filters solely for polylines carrying the `"GSTAR_HVAC_DUCT"` XData application tag via `SetXDataFilter()`, and draws a translucent acoustic clearance halo plus midpoint flow direction chevrons:
using System;
using Gssoft.GstarCAD.Runtime;
using Gssoft.GstarCAD.ApplicationServices;
using Gssoft.GstarCAD.DatabaseServices;
using Gssoft.GstarCAD.Geometry;
using Gssoft.GstarCAD.GraphicsInterface;
namespace GstarCadSamples.Overrules
{
public class HvacAcousticHaloOverrule : DrawableOverrule
{
public static HvacAcousticHaloOverrule Instance = new HvacAcousticHaloOverrule();
public override bool WorldDraw(Drawable drawable, WorldDraw wd)
{
// 1. Always invoke base.WorldDraw first to render the core native Polyline
bool baseResult = base.WorldDraw(drawable, wd);
if (drawable is Polyline pline && pline.NumberOfVertices >= 2)
{
short prevColor = wd.SubEntityTraits.Color;
wd.SubEntityTraits.Color = 30; // Orange warning halo (ACI 30)
// Draw midpoint flow direction chevron & clearance boundary
for (int i = 0; i < pline.NumberOfVertices - 1; i++)
{
Point3d ptStart = pline.GetPoint3dAt(i);
Point3d ptEnd = pline.GetPoint3dAt(i + 1);
Vector3d segVec = ptEnd - ptStart;
if (segVec.Length < 100.0) continue;
Point3d midPt = ptStart + (segVec * 0.5);
Vector3d dir = segVec.GetNormal();
Vector3d perp = dir.CrossProduct(Vector3d.ZAxis).GetNormal();
Point3d wing1 = midPt - (dir * 80.0) + (perp * 45.0);
Point3d wing2 = midPt - (dir * 80.0) - (perp * 45.0);
wd.Geometry.WorldLine(midPt, wing1);
wd.Geometry.WorldLine(midPt, wing2);
}
wd.SubEntityTraits.Color = prevColor;
}
return baseResult;
}
}
public class OverruleCommands
{
private static bool _isRegistered = false;
[CommandMethod("GSTAR_TOGGLE_HVAC_HALO")]
public void ToggleHvacHalo()
{
RXClass targetClass = RXObject.GetClass(typeof(Polyline));
if (!_isRegistered)
{
Overrule.AddOverrule(targetClass, HvacAcousticHaloOverrule.Instance, false);
HvacAcousticHaloOverrule.Instance.SetXDataFilter("GSTAR_HVAC_DUCT");
Overrule.Overruling = true;
_isRegistered = true;
}
else
{
Overrule.RemoveOverrule(targetClass, HvacAcousticHaloOverrule.Instance);
_isRegistered = false;
}
Application.DocumentManager.MdiActiveDocument.Editor.Regen();
}
}
}
3. Optimizing Overrule Filter Speed (`SetXDataFilter` vs. `IsApplicable`)
When `Overrule.Overruling` is active on a high-frequency class like `Polyline` or `BlockReference`, GstarCAD 2027 must evaluate whether each entity in the viewport qualifies for the overrule. Never choose `SetCustomFilter()` (`IsApplicable()` override) if a declarative filter suffices:
| Overrule Filter Method | Execution Layer | Benchmark Latency (50,000 Polylines) |
|---|---|---|
SetXDataFilter("APP_NAME") |
Native C++ Kernel RegApp Index Lookup | ~1.8 ms per full `REGEN` (Fastest) |
SetExtensionDictionaryEntryFilter("KEY") |
Native C++ Dictionary Pointer Check | ~2.4 ms per full `REGEN` |
SetCustomFilter() → IsApplicable() |
P/Invoke Marshal into Managed .NET CLR per entity | ~42.0 ms per full `REGEN` (Use only for complex geometric predicates) |
4. Viewport-Dependent Scaling (`ViewportDraw`) vs. Model-Space (`WorldDraw`)
If your custom overrule renders text badges, warning icons, or status flags that should remain a constant **18 pixels tall** on screen regardless of how far the user zooms in or out, return `false` from `WorldDraw(Drawable d, WorldDraw wd)` when `wd.RegenType != RegenType.SaveWorldDrawForProxy` and implement **`ViewportDraw(Drawable d, ViewportDraw vd)`** instead.
Inside `ViewportDraw()`, call `vd.Viewport.GetNumPixelsInUnitSquare(centerPt)` to obtain the exact device-pixel-to-drawing-unit ratio for the active viewport. Multiply your badge radius by `18.0 / pixelsPerUnit.X` so your diagnostic overlays stay crisp and legible at both `1:1` detail zoom and `1:1000` site-plan zoom.
Validate This Workflow in GstarCAD 2027
Engineered by Suzhou Gstarsoft Co., Ltd. (SSE: 688657), GstarCAD 2027 delivers 100% native AC1032 DWG binary fidelity, perpetual licensing sovereignty, and zero-day AutoCAD command parity.