C3D-0151 · As-built labels at 0.08 (sidewalk, wall, conc, fence) [ASBUILT-LABELS] done
Labels each as-built polyline at height 0.08 with the feature name taken from its layer - SIDEWALK, WALL, CONC, FENCE - placed at the polyline midpoint and rotated to the tangent there, flipped where it would read upside-down. Each label sits on the same layer as the feature it names. Idempotent: an identical label within 1 ft is skipped.
C# payload
// As-built feature labels at height 0.08 - sidewalk, wall, concrete pad, fence.
//
// One label per polyline, placed at the polyline's own MIDPOINT and rotated to its tangent there,
// flipped if it would read upside-down. Each label goes on the layer of the feature it names, so
// it inherits that feature's visibility.
//
// Labels are derived from the LAYER of each polyline, not guessed - the layer already says what
// the feature is. Idempotent: an existing label with the same text within 1 ft is skipped.
const double H = 0.08;
var ms = (BlockTableRecord)Tx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(Db), OpenMode.ForWrite);
var names = new Dictionary<string,string>();
names["SS-V-ROAD-EPVM"] = "SIDEWALK";
names["V-STRC-WALL"] = "WALL";
names["X-DRIV-CONC"] = "CONC";
names["SS-X-FENCE"] = "FENCE";
// what is already labelled
var existing = new List<Tuple<string,Point3d>>();
foreach (ObjectId id in ms) {
var mt0 = Tx.GetObject(id, OpenMode.ForRead) as MText;
if (mt0 == null || mt0.IsErased) continue;
existing.Add(Tuple.Create(mt0.Contents.Trim().ToUpper(), mt0.Location));
}
var todo = new List<ObjectId>();
foreach (ObjectId id in ms) {
var pl = Tx.GetObject(id, OpenMode.ForRead) as Polyline;
if (pl == null || pl.IsErased) continue;
if (!names.ContainsKey(pl.Layer)) continue;
todo.Add(id);
}
Log("candidate polylines: " + todo.Count);
int made = 0, skipped = 0;
foreach (ObjectId id in todo) {
var pl = (Polyline)Tx.GetObject(id, OpenMode.ForRead);
string txt = names[pl.Layer];
Point3d mid; double rot = 0;
try {
mid = pl.GetPointAtDist(pl.Length / 2.0);
var d = pl.GetFirstDerivative(mid);
rot = Math.Atan2(d.Y, d.X) * 180.0 / Math.PI;
} catch { mid = pl.StartPoint; }
if (rot > 90 || rot <= -90) rot -= 180;
bool dup = false;
foreach (var e in existing)
if (e.Item1 == txt && e.Item2.DistanceTo(mid) < 1.0) { dup = true; break; }
if (dup) { skipped++; Log(" " + txt + " on " + pl.Layer + " already labelled - skipped"); continue; }
var mt = new MText {
Location = mid,
Contents = txt,
TextHeight = H,
Rotation = rot * Math.PI / 180.0,
Attachment = AttachmentPoint.BottomCenter,
};
mt.Layer = pl.Layer;
ms.AppendEntity(mt);
Tx.AddNewlyCreatedDBObject(mt, true);
existing.Add(Tuple.Create(txt, mid));
made++;
Log(String.Format(" \"{0}\" on {1,-18} at {2:F2},{3:F2} rot={4:F1} h={5}",
txt, pl.Layer, mid.X, mid.Y, rot, H));
}
Log("");
Log("labels created: " + made + " skipped: " + skipped);
int n = 0;
foreach (ObjectId id in ms) {
var mt = Tx.GetObject(id, OpenMode.ForRead) as MText;
if (mt == null || mt.IsErased) continue;
if (Math.Abs(mt.TextHeight - H) < 1e-6) n++;
}
Log("MText at height " + H + " in model space: " + n + " (verified)");
Ed.Regen();
Result
Log
candidate polylines: 9 "WALL" on V-STRC-WALL at 2238240.08,1325110.00 rot=-21.0 h=0.08 "CONC" on X-DRIV-CONC at 2238210.22,1325139.07 rot=-23.3 h=0.08 "CONC" on X-DRIV-CONC at 2238187.40,1325151.58 rot=-291.1 h=0.08 "CONC" on X-DRIV-CONC at 2238230.95,1325139.79 rot=-22.2 h=0.08 "CONC" on X-DRIV-CONC at 2238260.85,1325122.44 rot=-293.9 h=0.08 "CONC" on X-DRIV-CONC at 2238275.24,1325161.02 rot=-23.9 h=0.08 "SIDEWALK" on SS-V-ROAD-EPVM at 2238232.65,1325138.60 rot=-23.5 h=0.08 "WALL" on V-STRC-WALL at 2238239.63,1325109.33 rot=-21.0 h=0.08 "FENCE" on SS-X-FENCE at 2238320.85,1325110.30 rot=-329.9 h=0.08 labels created: 9 skipped: 0 MText at height 0.08 in model space: 9 (verified)
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.