C3D-MATCHLBL2 · Match bearing labels to TRACT A/B v2 (read-only) done
DBObject ambiguity fixed. Assign each bearing label to its tract segment.
C# payload
// READ-ONLY: match each bearing label to the tract boundary it annotates.
// Build A and B boundary segment lists (A = Parcel segments; B = Polyline segments).
// For every bearing-type label (GeneralSegmentLabel/NoteLabel + MText/DBText with bearing chars),
// find the nearest boundary segment across A and B; assign to that tract if within ~15'. Report each
// label: handle, type, layer, assigned tract, distance.
using System;
using System.Linq;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.Civil.ApplicationServices;
using Autodesk.Civil.DatabaseServices;
var db = Db;
// collect boundary segments as (p1,p2) for A and B
var segA = new List<(Point3d a, Point3d b)>();
var segB = new List<(Point3d a, Point3d b)>();
using (var tr = db.TransactionManager.StartTransaction())
{
var ms = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
// B: polyline on SS-BOUNDARY TRACT B
foreach (ObjectId id in ms)
{
var e = tr.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
if (e is Polyline pl && string.Equals(e.Layer,"SS-BOUNDARY TRACT B",StringComparison.OrdinalIgnoreCase))
{
int n = pl.NumberOfVertices;
for (int i=0;i<n;i++){ var p1=pl.GetPoint3dAt(i); var p2=pl.GetPoint3dAt((i+1)%n); segB.Add((p1,p2)); }
}
}
// A: Parcel on SS-BOUNDARY TRACT A — explode to component curves for segment geometry.
var cdoc = CivilDocument.GetCivilDocument(db);
foreach (ObjectId sid in cdoc.GetSiteIds())
{
var site=(Site)tr.GetObject(sid,OpenMode.ForRead);
foreach (ObjectId pid in site.GetParcelIds())
{
var p=(Parcel)tr.GetObject(pid,OpenMode.ForRead);
if (!string.Equals(p.Layer,"SS-BOUNDARY TRACT A",StringComparison.OrdinalIgnoreCase)) continue;
var dbo = new DBObjectCollection();
try { p.Explode(dbo); } catch (System.Exception ex) { Log($"parcel A explode note: {ex.Message}"); }
foreach (Autodesk.AutoCAD.DatabaseServices.DBObject o in dbo)
{
if (o is Line l) segA.Add((l.StartPoint, l.EndPoint));
else if (o is Arc ar) { segA.Add((ar.StartPoint, ar.EndPoint)); }
else if (o is Polyline pp){ int n=pp.NumberOfVertices; for(int i=0;i<n-1;i++) segA.Add((pp.GetPoint3dAt(i),pp.GetPoint3dAt(i+1))); }
}
}
}
Log($"segA(Parcel)={segA.Count} segB(Polyline)={segB.Count}");
double DistToSeg(Point3d pt, Point3d a, Point3d b)
{
var ab=b-a; double len2=ab.LengthSqrd; if(len2==0) return pt.DistanceTo(a);
double t=((pt-a).DotProduct(ab))/len2; t=Math.Max(0,Math.Min(1,t));
var proj=a+ab*t; return pt.DistanceTo(proj);
}
int aN=0,bN=0,un=0;
foreach (ObjectId id in ms)
{
var e = tr.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
if (e==null) continue;
string tn=e.GetType().Name;
bool cand = tn=="GeneralSegmentLabel" || tn=="NoteLabel";
string s=null; if(e is MText m) s=m.Text; else if(e is DBText t) s=t.TextString;
if((tn=="MText"||tn=="DBText") && s!=null && (s.Contains("°")||s.Contains("\""))) cand=true;
if(!cand) continue;
Point3d pos; try{ var ex=e.GeometricExtents; pos=new Point3d((ex.MinPoint.X+ex.MaxPoint.X)/2,(ex.MinPoint.Y+ex.MaxPoint.Y)/2,0);}catch{continue;}
double dA=segA.Count>0?segA.Min(sg=>DistToSeg(pos,sg.a,sg.b)):9e9;
double dB=segB.Count>0?segB.Min(sg=>DistToSeg(pos,sg.a,sg.b)):9e9;
string who; double d;
if(Math.Min(dA,dB)>40){ who="(none)"; d=Math.Min(dA,dB); un++; }
else if(dA<=dB){ who="A"; d=dA; aN++; } else { who="B"; d=dB; bN++; }
Log($" {tn} h={e.Handle} layer='{e.Layer}' -> {who} (d={d:0.0}')");
}
Log($"ASSIGNED: A={aN} B={bN} none={un}");
tr.Commit();
}
Result
Log
segA(Parcel)=3 segB(Polyline)=8 GeneralSegmentLabel h=20BA6 layer='C-ANNO' -> (none) (d=238.7') MText h=20CB7 layer='C-ANNO' -> (none) (d=1002.3') MText h=20CB8 layer='C-ANNO' -> (none) (d=834.3') GeneralSegmentLabel h=20DF9 layer='SS-0-FRAME' -> (none) (d=2542201.8') GeneralSegmentLabel h=20DFA layer='SS-0-FRAME' -> (none) (d=2542201.8') GeneralSegmentLabel h=20E03 layer='SS-0-FRAME' -> (none) (d=2542201.8') MText h=20F28 layer='SS-0-FRAME' -> (none) (d=1373.6') MText h=20F29 layer='SS-0-FRAME' -> (none) (d=1523.3') MText h=20F2A layer='SS-0-FRAME' -> (none) (d=1623.2') MText h=20F2B layer='SS-0-FRAME' -> (none) (d=1723.2') MText h=20F2C layer='SS-0-FRAME' -> (none) (d=1822.9') MText h=20F2D layer='SS-0-FRAME' -> (none) (d=1921.8') MText h=20F2E layer='SS-0-FRAME' -> (none) (d=1985.5') MText h=20F2F layer='SS-0-FRAME' -> (none) (d=1965.2') MText h=20F30 layer='SS-0-FRAME' -> (none) (d=1745.9') MText h=20F31 layer='SS-0-FRAME' -> (none) (d=1438.1') MText h=20F32 layer='SS-0-FRAME' -> (none) (d=1204.7') MText h=20F33 layer='SS-0-FRAME' -> (none) (d=1317.1') MText h=20F34 layer='SS-0-FRAME' -> (none) (d=1433.9') MText h=20F35 layer='SS-0-FRAME' -> (none) (d=1448.7') MText h=20F36 layer='SS-0-FRAME' -> (none) (d=1418.2') MText h=20F37 layer='SS-0-FRAME' -> (none) (d=1350.6') MText h=20F38 layer='SS-0-FRAME' -> (none) (d=1335.1') MText h=20F39 layer='SS-0-FRAME' -> (none) (d=1358.7') MText h=20F3A layer='SS-0-FRAME' -> (none) (d=1321.5') GeneralSegmentLabel h=20FB8 layer='SS-0-FRAME' -> (none) (d=2542201.8') GeneralSegmentLabel h=20FB9 layer='SS-0-FRAME' -> (none) (d=2542201.8') GeneralSegmentLabel h=20FBA layer='SS-0-FRAME' -> (none) (d=2542201.8') GeneralSegmentLabel h=2109C layer='C-ANNO' -> (none) (d=207.6') ASSIGNED: A=0 B=0 none=29
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.