C3D-0078 · READ-ONLY: verify the main run lengths, slopes and inverts [VERIFY-MAIN-RUN] done
For each pair along A16-A14-A12-A10-A9-A6-A5-A4-A3-A2-A1-384, reads the joining line true length, its length and slope labels, and the invert out/in from the manhole notes drawn at each end, then recomputes the slope from drop over true length so the labelled value can be checked independently. No changes.
C# payload
// READ-ONLY. Full verification pass on the MAIN RUN:
// A16 - A14 - A12 - A10 - A9 - A6 - A5 - A4 - A3 - A2 - A1 - MH384
//
// For each consecutive pair: find the SEWER_LINE line joining them, read its TRUE length, read
// the length label and the slope label sitting on it, and read the manhole notes at both ends so
// INVERT OUT (upstream) and INVERT IN (downstream) can be pulled from what is actually drawn.
//
// Everything comes from the drawing. Nothing is computed from a remembered table, so the slope
// arithmetic can be checked independently against what is labelled. 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 + ">"; } };
// --- points by manhole name ---
var mh = new Dictionary<string, double[]>(); // "A16" -> {x,y}
foreach (ObjectId id in ms) {
var cp = Tx.GetObject(id, OpenMode.ForRead) as CogoPoint;
if (cp == null) continue;
string d = (safe(() => cp.RawDescription ?? "")).Trim().ToUpper();
if (d.StartsWith("SSMH ")) {
string nm = d.Substring(5).Trim();
if (nm == "MAIN") nm = "384";
if (!mh.ContainsKey(nm)) mh[nm] = new double[] { cp.Easting, cp.Northing };
}
}
// --- lines ---
var lines = new List<object[]>();
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 });
}
// --- labels, assigned to nearest line ---
var lenLbl = new Dictionary<string,string>();
var pctLbl = new Dictionary<string,string>();
foreach (ObjectId id in ms) {
var mt = Tx.GetObject(id, OpenMode.ForRead) as MText;
if (mt == null || safe(() => mt.Layer) != "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, 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 dd=Math.Sqrt((lx-px)*(lx-px)+(ly-py)*(ly-py));
if (dd<bd) { bd=dd; best=(string)L[0]; }
}
if (best == null || bd > 40.0) continue;
string c = mt.Contents.Trim();
if (c.IndexOf('%') >= 0) pctLbl[best] = c;
else lenLbl[best] = c;
}
// --- manhole notes: parse RIM / IN / OUT out of the SEWER_MANHOLE_TEXT MText ---
var note = new Dictionary<string,string[]>(); // "A16" -> {rim,in,out}
foreach (ObjectId id in ms) {
var mt = Tx.GetObject(id, OpenMode.ForRead) as MText;
if (mt == null || safe(() => mt.Layer) != "SEWER_MANHOLE_TEXT") continue;
string raw = mt.Contents.Replace(@"\P", "\n");
var ls = raw.Split('\n');
if (ls.Length < 4) continue;
string head = ls[0].Trim().ToUpper(); // "MH A16" or "TEST MH"
string nm = head.StartsWith("MH") ? head.Substring(2).Trim() : head;
string rim = "", inv = "", outv = "";
foreach (var l in ls) {
string s = l.Trim().ToUpper();
if (s.StartsWith("RIM")) rim = s.Substring(3).Trim();
else if (s.StartsWith("OUT")) outv = s.Substring(3).Trim();
else if (s.StartsWith("IN")) inv = s.Substring(2).Trim();
}
if (nm.Length > 0 && !note.ContainsKey(nm)) note[nm] = new string[] { rim, inv, outv };
}
string[] RUN = new string[] { "A16","A14","A12","A10","A9","A6","A5","A4","A3","A2","A1","384" };
Log("UP DOWN HANDLE TRUE_LEN LEN_LABEL SLOPE_LBL INV_OUT(up) INV_IN(dn) DROP CALC_SLOPE");
for (int i = 0; i + 1 < RUN.Length; i++) {
string a = RUN[i], b = RUN[i+1];
if (!mh.ContainsKey(a) || !mh.ContainsKey(b)) { Log(String.Format("{0,-5} {1,-6} -- point missing --", a, b)); continue; }
double[] pa = mh[a], pb = mh[b];
string h = "(none)"; double trueLen = 0;
foreach (var L in lines) {
double x1=(double)L[1], y1=(double)L[2], x2=(double)L[3], y2=(double)L[4];
bool fwd = Math.Abs(x1-pa[0])<1.0 && Math.Abs(y1-pa[1])<1.0 && Math.Abs(x2-pb[0])<1.0 && Math.Abs(y2-pb[1])<1.0;
bool rev = Math.Abs(x1-pb[0])<1.0 && Math.Abs(y1-pb[1])<1.0 && Math.Abs(x2-pa[0])<1.0 && Math.Abs(y2-pa[1])<1.0;
if (fwd || rev) { h = (string)L[0]; trueLen = (double)L[5]; break; }
}
string ll = lenLbl.ContainsKey(h) ? lenLbl[h] : "-";
string sl = pctLbl.ContainsKey(h) ? pctLbl[h] : "-";
string io = note.ContainsKey(a) ? note[a][2] : "?";
string ii = note.ContainsKey(b) ? note[b][1] : "?";
string drop = "-", calc = "-";
double dOut, dIn;
if (Double.TryParse(io, out dOut) && Double.TryParse(ii, out dIn) && trueLen > 0) {
double dr = dOut - dIn;
drop = dr.ToString("F2");
calc = (dr / trueLen * 100.0).ToString("F2") + "%";
}
Log(String.Format("{0,-5} {1,-6} {2,-8} {3,8:F2} {4,-10} {5,-10} {6,-12} {7,-12} {8,-7} {9}",
a, b, h, trueLen, ll, sl, io, ii, drop, calc));
}
Result
Log
UP DOWN HANDLE TRUE_LEN LEN_LABEL SLOPE_LBL INV_OUT(up) INV_IN(dn) DROP CALC_SLOPE A16 A14 2EC86 132.52 132.52' 15.79% ? 722.02 - - A14 A12 2EC87 133.21 133.21' 2.81% 721.82 718.08 3.74 2.81% A12 A10 2EC89 86.31 86.31' 2.25% 717.88 717.37 0.51 0.59% A10 A9 2EC8A 30.97 30.97' 8.89% 717.17 714.42 2.75 8.88% A9 A6 2EC8B 133.46 133.46' 1.29% 714.22 712.49 1.73 1.30% A6 A5 2EC8C 80.46 80.46' 15.60% 712.49 699.94 12.55 15.60% A5 A4 2EC8D 161.58 161.58' 12.37% 699.56 679.57 19.99 12.37% A4 A3 2EC8E 359.02 359.02' 1.16% 677.97 673.80 4.17 1.16% A3 A2 2EC8F 80.02 80.02' 0.50% 673.74 673.34 0.40 0.50% A2 A1 2EC90 155.37 155.37' 0.60% 673.34 672.41 0.93 0.60% A1 384 2EC91 19.54 19.54' 2.41% 672.31 671.84 0.47 2.41%
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.