← Inbox

C3D-CURBNORM · Normalize curb layer to Polylines done

Converts the mixed Line/Polyline3d content on SS-V-ROAD-CURB into joined 2D Polylines (chains Lines end-to-end, flattens Polyline3d). Skips <3ft noise and >500ft boundary lines. Prep for the 0.5/2.0ft curb offsets.

Script file
C3D-CURBNORM.cs
Target
active document · model space
Author
claude
Approved
yes · auto-auth
Timeout
60s

C# payload

// STEP 1 of curb work: normalize SS-V-ROAD-CURB to Polylines.
// The layer currently holds a mix of Line / Polyline / Polyline3d. Convert Lines and
// Polyline3d into joined 2D Polylines so the next step (0.5' and 2.0' offsets toward the
// road) has one consistent entity type to work with.
// Chains Lines end-to-end into runs; flattens Polyline3d to Polyline at its average Z.
// Skips runs shorter than 3ft (survey noise) and longer than 500ft (site boundary lines,
// not curb). Leaves existing Polylines alone.
// Host owns Tx/ModelSpace - no using/Commit here.
const string LAYER = "SS-V-ROAD-CURB";
const double MINLEN = 3.0, MAXLEN = 500.0, TOL = 0.02;

var lineIds = new List<ObjectId>();
var p3Ids   = new List<ObjectId>();
foreach (ObjectId id in ModelSpace)
{
    var e = Tx.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
    if (e == null || e.Layer != LAYER) continue;
    if (e is Line) lineIds.Add(id);
    else if (e is Polyline3d) p3Ids.Add(id);
}
Log($"Found {lineIds.Count} Lines, {p3Ids.Count} Polyline3d on '{LAYER}'.");

// ---- chain Lines into runs ----
var segs = new List<(Point2d a, Point2d b, ObjectId id, double len)>();
foreach (var id in lineIds)
{
    var ln = (Line)Tx.GetObject(id, OpenMode.ForRead);
    segs.Add((new Point2d(ln.StartPoint.X, ln.StartPoint.Y),
              new Point2d(ln.EndPoint.X,   ln.EndPoint.Y), id, ln.Length));
}
bool Near(Point2d p, Point2d q) => p.GetDistanceTo(q) < TOL;

var used = new bool[segs.Count];
var runs = new List<List<Point2d>>();
var consumed = new List<ObjectId>();
for (int i = 0; i < segs.Count; i++)
{
    if (used[i]) continue;
    used[i] = true;
    var run = new List<Point2d> { segs[i].a, segs[i].b };
    var mine = new List<ObjectId> { segs[i].id };
    bool grew = true;
    while (grew)
    {
        grew = false;
        for (int j = 0; j < segs.Count; j++)
        {
            if (used[j]) continue;
            if (Near(segs[j].a, run[run.Count-1]))      { run.Add(segs[j].b);    used[j]=true; mine.Add(segs[j].id); grew=true; }
            else if (Near(segs[j].b, run[run.Count-1])) { run.Add(segs[j].a);    used[j]=true; mine.Add(segs[j].id); grew=true; }
            else if (Near(segs[j].a, run[0]))           { run.Insert(0,segs[j].b); used[j]=true; mine.Add(segs[j].id); grew=true; }
            else if (Near(segs[j].b, run[0]))           { run.Insert(0,segs[j].a); used[j]=true; mine.Add(segs[j].id); grew=true; }
        }
    }
    double L = 0;
    for (int k = 1; k < run.Count; k++) L += run[k].GetDistanceTo(run[k-1]);
    if (L < MINLEN || L > MAXLEN) { Log($"  skip run {run.Count}v {L:F1}ft (outside {MINLEN}-{MAXLEN})"); continue; }
    runs.Add(run);
    consumed.AddRange(mine);
}

int made = 0;
foreach (var run in runs)
{
    var pl = new Polyline();
    for (int i = 0; i < run.Count; i++) pl.AddVertexAt(i, run[i], 0, 0, 0);
    pl.Layer = LAYER;
    ModelSpace.AppendEntity(pl);
    Tx.AddNewlyCreatedDBObject(pl, true);
    made++;
}
foreach (var id in consumed)
{
    var w = (Autodesk.AutoCAD.DatabaseServices.Entity)Tx.GetObject(id, OpenMode.ForWrite);
    w.Erase();
}
Log($"Lines -> {made} Polylines (consumed {consumed.Count} Lines).");

// ---- flatten Polyline3d to Polyline ----
int conv = 0;
foreach (var id in p3Ids)
{
    var p3 = (Polyline3d)Tx.GetObject(id, OpenMode.ForRead);
    var vs = new List<Point3d>();
    foreach (ObjectId vid in p3)
    {
        var v = Tx.GetObject(vid, OpenMode.ForRead) as PolylineVertex3d;
        if (v != null) vs.Add(v.Position);
    }
    if (vs.Count < 2) continue;
    double L = 0;
    for (int i = 1; i < vs.Count; i++) L += vs[i].DistanceTo(vs[i-1]);
    if (L < MINLEN || L > MAXLEN) continue;

    var pl = new Polyline();
    for (int i = 0; i < vs.Count; i++) pl.AddVertexAt(i, new Point2d(vs[i].X, vs[i].Y), 0, 0, 0);
    double z = 0; foreach (var v in vs) z += v.Z; pl.Elevation = z / vs.Count;
    pl.Layer = LAYER;
    ModelSpace.AppendEntity(pl);
    Tx.AddNewlyCreatedDBObject(pl, true);
    var w = (Autodesk.AutoCAD.DatabaseServices.Entity)Tx.GetObject(id, OpenMode.ForWrite);
    w.Erase();
    conv++;
}
Log($"Polyline3d -> {conv} Polylines.");

int total = 0;
foreach (ObjectId id in ModelSpace)
{
    var e = Tx.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
    if (e != null && e.Layer == LAYER && e is Polyline) total++;
}
Log($"'{LAYER}' now has {total} Polylines.");

Result

Status
success
Drawing file
C:\Users\sanja\OneDrive\_SurveyDisco\260709 - 1512 Bass Rd, Macon, GA 31210, USA\260709 - 1512 Bass Rd.dwg
Message
Executed C3D-CURBNORM (0 entities touched).
Entities
Duration
392 ms
Civil 3D
25.0.0.0

Log

Found 126 Lines, 25 Polyline3d on 'SS-V-ROAD-CURB'.
  skip run 2v 770.8ft (outside 3-500)
  skip run 2v 773.4ft (outside 3-500)
  skip run 2v 1.6ft (outside 3-500)
  skip run 2v 1.0ft (outside 3-500)
  skip run 2v 1.0ft (outside 3-500)
  skip run 2v 0.7ft (outside 3-500)
  skip run 2v 0.0ft (outside 3-500)
Lines -> 21 Polylines (consumed 119 Lines).
Polyline3d -> 25 Polylines.
'SS-V-ROAD-CURB' now has 63 Polylines.

Notes

What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.

No notes yet.