C3D-0074 · READ-ONLY: current labels against true line lengths [LBL-VS-LENGTH] done
Reads every SEWER_LINE line with its measured length and assigns each SEWER_LINE_TEXT label to its nearest line, reporting the labels as they read now (the user has edited some), including the slope labels. No changes.
C# payload
// READ-ONLY. For every sewer line: its true length, and the labels currently sitting on it.
// The user has edited labels since they were placed, so read them fresh - do not reuse the
// values from the placement ticket.
//
// Each SEWER_LINE_TEXT MText is assigned to the nearest line by perpendicular distance to that
// line's midpoint region, then reported under that line. Both the length label and the slope
// label (the one containing '%') are surfaced so either can be checked.
// Nothing is modified.
var ms = (BlockTableRecord)Tx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(Db), OpenMode.ForRead);
Func<Func<string>, string> safe = f => { try { return f(); } catch (System.Exception ex) { return "<" + ex.GetType().Name + ">"; } };
// 1) the lines
var lines = new List<object[]>(); // handle, x1,y1, x2,y2, length
foreach (ObjectId id in ms) {
var o = Tx.GetObject(id, OpenMode.ForRead);
var ent = o as Autodesk.AutoCAD.DatabaseServices.Entity;
if (ent == null || safe(() => ent.Layer) != "SEWER_LINE") continue;
var ln = o as Line;
if (ln == null) continue;
lines.Add(new object[] { o.Handle.ToString(), ln.StartPoint.X, ln.StartPoint.Y,
ln.EndPoint.X, ln.EndPoint.Y, ln.Length });
}
// 2) every label on the text layers, assigned to its closest line
var labels = new Dictionary<string, List<string>>();
int stray = 0;
foreach (ObjectId id in ms) {
var o = Tx.GetObject(id, OpenMode.ForRead);
var mt = o as MText;
if (mt == null) continue;
string lay = safe(() => mt.Layer);
if (lay != "SEWER_LINE_TEXT") continue;
double lx = mt.Location.X, ly = mt.Location.Y;
string best = null; double bd = 1e18;
foreach (var L in lines) {
double x1 = (double)L[1], y1 = (double)L[2], x2 = (double)L[3], y2 = (double)L[4];
double vx = x2 - x1, vy = y2 - y1;
double len2 = vx*vx + vy*vy;
double t = len2 > 0 ? ((lx-x1)*vx + (ly-y1)*vy) / len2 : 0.0;
if (t < 0) t = 0; if (t > 1) t = 1;
double px = x1 + t*vx, py = y1 + t*vy;
double d = Math.Sqrt((lx-px)*(lx-px) + (ly-py)*(ly-py));
if (d < bd) { bd = d; best = (string)L[0]; }
}
string txt = mt.Contents.Replace(@"\P", " ").Trim();
if (best == null || bd > 40.0) { stray++; Log(" STRAY LABEL [" + o.Handle + "] \"" + txt + "\" nearest " + best + " at " + bd.ToString("F1") + "ft"); continue; }
if (!labels.ContainsKey(best)) labels[best] = new List<string>();
labels[best].Add(txt + " (" + bd.ToString("F1") + "ft off)");
}
Log("");
Log("=== SEWER LINES: true length + current labels ===");
lines.Sort((a,b) => String.Compare((string)a[0], (string)b[0]));
foreach (var L in lines) {
string h = (string)L[0];
Log("");
Log(String.Format("[{0}] LENGTH = {1:F2}", h, (double)L[5]));
if (!labels.ContainsKey(h)) { Log(" (no labels)"); continue; }
foreach (var s in labels[h]) Log(" " + s);
}
Log("");
Log("lines=" + lines.Count + " stray labels=" + stray);
Result
Log
=== SEWER LINES: true length + current labels ===
[2E95F] LENGTH = 12.07
12.07' (2.0ft off)
[2EC86] LENGTH = 132.52
131.42' (2.0ft off)
15.79% (3.2ft off)
[2EC87] LENGTH = 133.21
133.04' (2.0ft off)
N/A (3.2ft off)
[2EC88] LENGTH = 55.14
55.11' (2.0ft off)
N/A (3.2ft off)
[2EC89] LENGTH = 86.31
86.31' (6.4ft off)
0.59% (3.2ft off)
2.25% (1.1ft off)
[2EC8A] LENGTH = 30.97
30.96' (2.0ft off)
6.98% (3.2ft off)
[2EC8B] LENGTH = 133.46
133.45' (1.7ft off)
1.29% (4.6ft off)
[2EC8C] LENGTH = 80.46
80.39' (6.4ft off)
15.60% (3.2ft off)
[2EC8D] LENGTH = 161.58
161.58' (2.0ft off)
12.37% (3.2ft off)
[2EC8E] LENGTH = 359.02
358.92' (2.0ft off)
1.16% (3.2ft off)
[2EC8F] LENGTH = 80.02
79.84' (2.0ft off)
0.50% (3.2ft off)
[2EC90] LENGTH = 155.37
155.36' (2.0ft off)
0.60% (3.2ft off)
[2EC91] LENGTH = 19.54
19.53' (2.0ft off)
2.41% (3.2ft off)
[2EC92] LENGTH = 8.66
8.66' (2.0ft off)
lines=14 stray labels=0Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.