C3D-HCWA-WATER · HCWA migration 2/5: water layers done
Split V-WATR-STRC by feature type using nearest coded COGO point: FH/WV/vault. WV within 5ft of a hydrant goes to FIRE_HYDRANT_VALVE per Rev 1.6. RPZ backflow left in place (no HCWA layer).
C# payload
// HCWA migration 2/5: WATER. V-WATR-STRC mixes hydrants/valves/vaults on one layer — HCWA
// requires each on its own. Classify each entity by the NEAREST coded COGO point (not by guess):
// FH -> FIRE_HYDRANT | WV adjacent to a FH -> FIRE_HYDRANT_VALVE (Rev 1.6) | WV -> WATER_VALVE
// VAULT COR / WATER VAULT -> WATER_VAULT | RPZ BFP -> left alone (no HCWA layer)
var bt = (BlockTable)Tx.GetObject(Db.BlockTableId, OpenMode.ForRead);
var ms = (BlockTableRecord)Tx.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
var lt = (LayerTable)Tx.GetObject(Db.LayerTableId, OpenMode.ForRead);
string[] need = { "FIRE_HYDRANT","FIRE_HYDRANT_VALVE","WATER_VALVE","WATER_VAULT","WATER_LINE",
"WATER_LINE_TEXT","WATER_VALVE_TEXT","FIRE_HYDRANT_TEXT","WATER_VAULT_TEXT" };
foreach (var n in need) if (!lt.Has(n)) { Log($"ABORT: layer '{n}' missing — run C3D-HCWALAYERS first."); return; }
// --- collect coded water points ---
var cd = CivilDoc;
var pts = new List<(uint num, string code, Point2d p)>();
foreach (ObjectId id in cd.CogoPoints) {
var cp = (Autodesk.Civil.DatabaseServices.CogoPoint)Tx.GetObject(id, OpenMode.ForRead);
var u = (cp.RawDescription ?? "").Trim().ToUpperInvariant();
if (u=="FH" || u=="WV" || u.Contains("VAULT") || u.Contains("RPZ"))
pts.Add((cp.PointNumber, u, new Point2d(cp.Easting, cp.Northing)));
}
// a WV within 5' of a FH is that hydrant's valve -> FIRE_HYDRANT_VALVE
var fh = pts.Where(x => x.code=="FH").ToList();
string ClassOf(Point2d q) {
var best = ""; double bd = double.MaxValue;
foreach (var p in pts) { double d = q.GetDistanceTo(p.p); if (d < bd) { bd = d; best = p.code; } }
if (bd > 12.0) return null; // too far from any coded point -> skip
if (best == "FH") return "FIRE_HYDRANT";
if (best == "WV") {
foreach (var h in fh) if (q.GetDistanceTo(h.p) <= 5.0) return "FIRE_HYDRANT_VALVE";
return "WATER_VALVE";
}
if (best.Contains("RPZ")) return null; // backflow: no HCWA layer, leave in place
if (best.Contains("VAULT")) return "WATER_VAULT";
return null;
}
var plan = new List<(ObjectId id, string to)>();
foreach (ObjectId id in ms) {
var o = Tx.GetObject(id, OpenMode.ForRead);
var e = o as Autodesk.AutoCAD.DatabaseServices.Entity;
if (e == null) continue;
if (e.Layer == "V-WATR-STRC") {
Point2d q;
if (o is Circle c) q = new Point2d(c.Center.X, c.Center.Y);
else if (o is Polyline pl && pl.NumberOfVertices > 0) {
double sx=0, sy=0; for (int i=0;i<pl.NumberOfVertices;i++){var v=pl.GetPoint2dAt(i); sx+=v.X; sy+=v.Y;}
q = new Point2d(sx/pl.NumberOfVertices, sy/pl.NumberOfVertices); // centroid
} else continue;
var to = ClassOf(q);
if (to != null) plan.Add((id, to));
else Log($" SKIP {o.GetType().Name} @({q.X:F1},{q.Y:F1}) — no confident code match (backflow/unknown)");
}
else if (e.Layer == "V-WATR-ALIGN" && (o is Polyline || o is Line))
plan.Add((id, "WATER_LINE"));
else if (e.Layer == "V-WATR-TEXT" && o is DBText t) {
var s = (t.TextString ?? "").ToUpperInvariant();
string to = "WATER_LINE_TEXT";
if (s.Contains(" FH") || s.Contains("FHA") || s.StartsWith("FH")) to = "FIRE_HYDRANT_TEXT";
else if (s.Contains(" WV") || s.Contains("TSV")) to = "WATER_VALVE_TEXT";
else if (s.Contains("VAULT") || s.Contains("METER") || s.Contains("BFP") || s.Contains("RPZ")) to = "WATER_VAULT_TEXT";
plan.Add((id, to));
}
}
int moved = 0; var tally = new Dictionary<string,int>();
foreach (var (id, to) in plan) {
var e = (Autodesk.AutoCAD.DatabaseServices.Entity)Tx.GetObject(id, OpenMode.ForWrite);
if (e.Layer == to) continue;
e.Layer = to;
var chk = (Autodesk.AutoCAD.DatabaseServices.Entity)Tx.GetObject(id, OpenMode.ForRead);
if (chk.Layer != to) continue;
tally[to] = tally.TryGetValue(to, out var n) ? n+1 : 1; moved++;
}
foreach (var kv in tally.OrderBy(k => k.Key)) Log($" -> {kv.Key}: {kv.Value} entities (verified)");
Log($"WATER migration: {moved} entities moved. Backflow (RPZ) intentionally left — no HCWA layer.");
Result
Log
SKIP Polyline @(2296419.2,1280017.1) — no confident code match (backflow/unknown) SKIP Circle @(2296549.9,1280052.8) — no confident code match (backflow/unknown) SKIP Circle @(2296556.1,1280062.3) — no confident code match (backflow/unknown) SKIP Circle @(2296560.0,1280062.9) — no confident code match (backflow/unknown) SKIP Circle @(2296654.3,1280077.4) — no confident code match (backflow/unknown) SKIP Circle @(2296654.8,1280082.0) — no confident code match (backflow/unknown) SKIP Circle @(2296563.1,1280064.9) — no confident code match (backflow/unknown) SKIP Circle @(2296595.4,1280069.3) — no confident code match (backflow/unknown) -> FIRE_HYDRANT: 2 entities (verified) -> FIRE_HYDRANT_TEXT: 3 entities (verified) -> FIRE_HYDRANT_VALVE: 2 entities (verified) -> WATER_LINE: 4 entities (verified) -> WATER_LINE_TEXT: 11 entities (verified) -> WATER_VALVE: 1 entities (verified) -> WATER_VALVE_TEXT: 5 entities (verified) -> WATER_VAULT: 2 entities (verified) -> WATER_VAULT_TEXT: 4 entities (verified) WATER migration: 34 entities moved. Backflow (RPZ) intentionally left — no HCWA layer.
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.