C3D-MATCHLBL3 · Match bearings to A/B by insertion pt (read-only) done
Dense-sample tract boundaries; assign each bearing label by its INSERTION point (not extents); drop SS-0-FRAME paperspace labels.
C# payload
// READ-ONLY: robust label->tract matching.
// - Build dense sample-point sets along A boundary (Parcel, exploded incl. arcs sampled) and B (polyline).
// - For each candidate bearing label use its INSERTION point (MText.Location / DBText.Position /
// label.LabelLocation), NOT GeometricExtents. Skip paperspace/frame labels (layer SS-0-FRAME).
// - Assign to nearest tract if within 60'; report handle, layer, type, 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;
var ptsA = new List<Point2d>();
var ptsB = new List<Point2d>();
void SampleLine(List<Point2d> into, Point3d a, Point3d b, int n=20)
{ for(int i=0;i<=n;i++){ double t=i/(double)n; into.Add(new Point2d(a.X+(b.X-a.X)*t, a.Y+(b.Y-a.Y)*t)); } }
void SampleArc(List<Point2d> into, Arc ar, int n=24)
{ for(int i=0;i<=n;i++){ double ang=ar.StartAngle+(ar.TotalAngle)*(i/(double)n); into.Add(new Point2d(ar.Center.X+ar.Radius*Math.Cos(ang), ar.Center.Y+ar.Radius*Math.Sin(ang))); } }
using (var tr = db.TransactionManager.StartTransaction())
{
var ms = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
// B polyline
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++){ SampleLine(ptsB, pl.GetPoint3dAt(i), pl.GetPoint3dAt((i+1)%n)); } }
}
// A parcel exploded (lines + arcs)
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 col=new DBObjectCollection();
try{ p.Explode(col);}catch{}
foreach(Autodesk.AutoCAD.DatabaseServices.DBObject o in col)
{
if(o is Line l) SampleLine(ptsA,l.StartPoint,l.EndPoint);
else if(o is Arc ar) SampleArc(ptsA,ar);
else if(o is Polyline pp){ int n=pp.NumberOfVertices; for(int i=0;i<n-1;i++) SampleLine(ptsA,pp.GetPoint3dAt(i),pp.GetPoint3dAt(i+1)); }
}
}
}
Log($"sampleA={ptsA.Count} sampleB={ptsB.Count}");
double NearA(Point2d p)=> ptsA.Count>0?ptsA.Min(q=>p.GetDistanceTo(q)):9e9;
double NearB(Point2d p)=> ptsB.Count>0?ptsB.Min(q=>p.GetDistanceTo(q)):9e9;
int aN=0,bN=0,un=0;
var aH=new List<string>(); var bH=new List<string>();
foreach (ObjectId id in ms)
{
var e = tr.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
if(e==null) continue;
if(string.Equals(e.Layer,"SS-0-FRAME",StringComparison.OrdinalIgnoreCase)) continue; // frame/paperspace
string tn=e.GetType().Name;
Point2d? loc=null;
if(e is MText m){ var u=m.Text; if(!(u.Contains("°")||u.Contains("\""))) continue; loc=new Point2d(m.Location.X,m.Location.Y); }
else if(e is DBText t){ var u=t.TextString; if(!(u.Contains("°")||u.Contains("\""))) continue; loc=new Point2d(t.Position.X,t.Position.Y); }
else if(tn=="GeneralSegmentLabel" || tn=="NoteLabel"){
try{ var lbl=(Label)e; loc=new Point2d(lbl.LabelLocation.X, lbl.LabelLocation.Y); }catch{ continue; }
} else continue;
var pt=loc.Value;
double dA=NearA(pt), dB=NearB(pt);
if(Math.Min(dA,dB)>60){ un++; continue; }
if(dA<=dB){ aN++; aH.Add($"{tn}:{e.Handle}@{e.Layer}(d{dA:0})"); }
else { bN++; bH.Add($"{tn}:{e.Handle}@{e.Layer}(d{dB:0})"); }
}
Log($"ASSIGNED A={aN} B={bN} none={un}");
Log("A LABELS:"); foreach(var h in aH) Log($" {h}");
Log("B LABELS:"); foreach(var h in bH) Log($" {h}");
tr.Commit();
}
Result
Log
sampleA=63 sampleB=168 ASSIGNED A=0 B=1 none=3 A LABELS: B LABELS: GeneralSegmentLabel:20BA6@C-ANNO(d46)
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.