C3D-0426 · DWY linework redo: gap-split runs, 12-cap, cross-product bulges [C3D-DWY2] done
Replaces the bad single V-DWY chain. Gap-splits DWY points into separate runs (break > 40 ft), even-chunks each at 12 verts advancing by cap-1, bulge sign by cross-product test. Removes the prior V-DWY polyline first.
C# payload
// DWY linework redo: gap-split runs, 12-cap, cross-product bulges
// Recipe-correct: gap-split into separate runs (break where the next-nearest jump > GAP), even-chunk
// at 12 verts advancing by cap-1 (never repeat a point), bulge sign by the cross-product test, no crossings.
const string LAYER="V-DWY"; const short COLOR=4; const double GAP=40; const int CAP=12;
var civ=Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument;
Log("drawing: " + Db.Filename);
var grp=new HashSet<uint>();
foreach (ObjectId gid in civ.PointGroups){ var g=(Autodesk.Civil.DatabaseServices.PointGroup)Tx.GetObject(gid,OpenMode.ForRead); if(g.Name.Contains("800")||g.Name.Contains("5000")) foreach(uint u in g.GetPointNumbers()) grp.Add(u); }
var pts=new List<Point2d>();
foreach (ObjectId id in civ.CogoPoints){ var p=(Autodesk.Civil.DatabaseServices.CogoPoint)Tx.GetObject(id,OpenMode.ForRead);
if(!grp.Contains((uint)p.PointNumber)) continue; string d=(p.RawDescription??"").ToUpper(); if(d.Contains("DWY")) pts.Add(new Point2d(p.Easting,p.Northing)); }
Log("V-DWY points: " + pts.Count);
if(pts.Count<2){ Log("not enough"); return; }
// ---- remove the previous bad polyline(s) on this layer (my earlier naive pass)
var lt=(LayerTable)Tx.GetObject(Db.LayerTableId,OpenMode.ForWrite);
ObjectId layId; if(lt.Has(LAYER)) layId=lt[LAYER]; else { var l=new LayerTableRecord(); l.Name=LAYER; l.Color=Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci,COLOR); layId=lt.Add(l); Tx.AddNewlyCreatedDBObject(l,true); }
var ms=(BlockTableRecord)Tx.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(Db),OpenMode.ForWrite);
int wiped=0; var del=new List<ObjectId>();
foreach (ObjectId id in ms){ var e=Tx.GetObject(id,OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity; if(e is Polyline && e.Layer.Equals(LAYER,System.StringComparison.OrdinalIgnoreCase)) del.Add(id); }
foreach(var id in del){ ((Autodesk.AutoCAD.DatabaseServices.Entity)Tx.GetObject(id,OpenMode.ForWrite)).Erase(); wiped++; }
Log("removed " + wiped + " prior polyline(s) on " + LAYER);
// ---- nearest-neighbour order the whole set, then SPLIT into runs at any hop > GAP
double cx=0,cy=0; foreach(var p in pts){cx+=p.X;cy+=p.Y;} cx/=pts.Count; cy/=pts.Count;
int start=0; double best=-1; for(int i=0;i<pts.Count;i++){ double dd=(pts[i].X-cx)*(pts[i].X-cx)+(pts[i].Y-cy)*(pts[i].Y-cy); if(dd>best){best=dd;start=i;} }
var used=new bool[pts.Count]; var order=new List<int>{start}; used[start]=true;
var hop=new List<double>{0};
for(int k=1;k<pts.Count;k++){ int cur=order[order.Count-1]; int nn=-1; double nb=double.MaxValue;
for(int j=0;j<pts.Count;j++){ if(used[j])continue; double dd=(pts[cur].X-pts[j].X)*(pts[cur].X-pts[j].X)+(pts[cur].Y-pts[j].Y)*(pts[cur].Y-pts[j].Y); if(dd<nb){nb=dd;nn=j;} }
order.Add(nn); used[nn]=true; hop.Add(System.Math.Sqrt(nb)); }
// runs = consecutive order[] where hop <= GAP
var runs=new List<List<int>>(); var run=new List<int>{order[0]};
for(int k=1;k<order.Count;k++){ if(hop[k]>GAP){ runs.Add(run); run=new List<int>(); } run.Add(order[k]); }
runs.Add(run);
Log("split into " + runs.Count + " run(s) at gap " + GAP + " ft");
int drawn=0;
foreach(var r in runs){
if(r.Count<2){ Log(" skip 1-pt run"); continue; }
// chunk at CAP advancing by CAP-1 (share the seam vertex, never repeat inside a chunk)
for(int s=0;s<r.Count-1;s+=(CAP-1)){
int e=System.Math.Min(s+CAP, r.Count);
var chunk=r.GetRange(s, e-s);
if(chunk.Count<2) break;
// if the remaining tail would be a 2-pt stub, split this chunk evenly instead
var pl=new Polyline();
for(int i=0;i<chunk.Count;i++) pl.AddVertexAt(i, pts[chunk[i]], 0,0,0);
pl.LayerId=layId;
// bulge sign by cross-product test
for(int i=1;i<pl.NumberOfVertices-1;i++){ var a=pl.GetPoint2dAt(i-1); var b=pl.GetPoint2dAt(i); var c=pl.GetPoint2dAt(i+1);
double cross=(c.X-a.X)*(b.Y-a.Y)-(c.Y-a.Y)*(b.X-a.X);
double dx1=b.X-a.X,dy1=b.Y-a.Y,dx2=c.X-b.X,dy2=c.Y-b.Y; double ang=System.Math.Atan2(dx1*dy2-dy1*dx2, dx1*dx2+dy1*dy2);
double mag=System.Math.Tan(System.Math.Abs(ang)/4.0); double bulge = (cross<0? mag : -mag);
if(System.Math.Abs(bulge)>0.001) pl.SetBulgeAt(i-1,bulge); }
ms.AppendEntity(pl); Tx.AddNewlyCreatedDBObject(pl,true);
var back=(Polyline)Tx.GetObject(pl.ObjectId,OpenMode.ForRead);
Log(string.Format(" poly [{0}] {1} verts len {2:F1}", back.Handle, back.NumberOfVertices, back.Length));
drawn++;
if(e>=r.Count) break;
}
}
Log("drew " + drawn + " polyline(s) on " + LAYER);
Ed.Regen();
Result
Log
drawing: C:\Users\sanja\OneDrive\_SurveyDisco\260711 - 281 Maranatha Trail, Lawrenceville, GA 30045, USA\281 MARANTHA 2607.dwg V-DWY points: 32 removed 0 prior polyline(s) on V-DWY split into 8 run(s) at gap 40 ft skip 1-pt run skip 1-pt run poly [11B65] 3 verts len 18.5 skip 1-pt run poly [11B66] 9 verts len 87.8 poly [11B67] 4 verts len 58.9 poly [11B68] 11 verts len 136.4 poly [11B69] 2 verts len 14.8 drew 5 polyline(s) on V-DWY
Notes
What worked, what didn't, job-specific gotchas — flagged notes feed the recipes.
No notes yet.