← Inbox

C3D-0285 · 260714 Huckaby: vicinity map on 11X17 and 17X11, embedded done

Attaches 260714-vicinity.png (Google Static Maps, zoom 15 for the 31 AC parcel, coords 33.3182163,-84.4624199 from the SurveyDisco job card, PNG magic verified, saved in the job folder) as a raster above the VICINITY MAP label on both the 11X17 and 17X11 sheets, clamped inside the title block frame. Skips a sheet that already has a raster. Also stores the PNG bytes base64-chunked in an Xrecord under NOD key C3D_VICINITY_EMBED so the image can be rebuilt if the file is ever lost. Verifies placement and containment on read-back.

Script file
C3D-0285.cs
Target
260714 - 285 Huckaby Rd R2.dwg · model space
Author
claude
Approved
yes · auto-auth
Timeout
60s

C# payload

// Vicinity map onto the 11X17 and 17X11 sheets, per the vicinity-map recipe, EMBEDDED so it is
// never lost if the PNG moves.
//
// Coordinates 33.3182163,-84.4624199 came from the SurveyDisco job card's streetViewUrl (not a
// geocode). Zoom 15 rather than the recipe's fixed 16 because the parcel is 31 AC - the recipe
// lists "zoom is fixed at 16" as a known gap for exactly this case. PNG magic verified before
// saving; 54433 bytes.
//
// EMBEDDING: a RasterImage always references a RasterImageDef, which holds a file path - that is
// the "link" that breaks. AutoCAD has no true image-embed for rasters, so the durable answer is
// to keep the PNG INSIDE the job folder beside the DWG (done) and, additionally, store the image
// bytes in the drawing so it can be re-written if the file ever goes missing. The bytes go into
// an Xrecord under a named-object-dictionary key; the recovery path is documented in the recipe.
const string PNG = @"C:\Users\sanja\OneDrive\_SurveyDisco\260714 - 285 Huckaby Rd, Brooks, GA 30205, USA\260714-vicinity.png";
const string DEFNAME = "VICINITY_260714";
const double SIZE = 2.30;          // inches square - proven on 260612 and 260802
const double GAP  = 0.06;          // clearance above the label

Log("drawing: " + Db.Filename);
if (!System.IO.File.Exists(PNG)) { Log("PNG not found: " + PNG); return; }
Log(string.Format("png: {0} bytes", new System.IO.FileInfo(PNG).Length));

// ---- image dictionary + definition (shared by both sheets)
ObjectId dictId = RasterImageDef.GetImageDictionary(Db);
if (dictId.IsNull) dictId = RasterImageDef.CreateImageDictionary(Db);
var dict = (DBDictionary)Tx.GetObject(dictId, OpenMode.ForWrite);

ObjectId defId;
if (dict.Contains(DEFNAME)) {
    defId = dict.GetAt(DEFNAME);
    var d0 = (RasterImageDef)Tx.GetObject(defId, OpenMode.ForWrite);
    d0.SourceFileName = PNG;
    try { d0.Load(); } catch (System.Exception e) { Log("reload: " + e.Message); }
    Log("reused image definition " + DEFNAME);
} else {
    var d = new RasterImageDef();
    d.SourceFileName = PNG;
    d.Load();
    defId = dict.SetAt(DEFNAME, d);
    Tx.AddNewlyCreatedDBObject(d, true);
    Log("created image definition " + DEFNAME);
}
{
    var d = (RasterImageDef)Tx.GetObject(defId, OpenMode.ForRead);
    Log(string.Format("   loaded={0}  size={1}", d.IsLoaded, d.Size.ToString()));
}

var bt = (BlockTable)Tx.GetObject(Db.BlockTableId, OpenMode.ForRead);
int placed = 0;

foreach (ObjectId btrId in bt) {
    var rec0 = (BlockTableRecord)Tx.GetObject(btrId, OpenMode.ForRead);
    if (!rec0.IsLayout) continue;
    var lay = (Layout)Tx.GetObject(rec0.LayoutId, OpenMode.ForRead);
    if (lay.LayoutName != "11X17" && lay.LayoutName != "17X11") continue;

    // already has a raster? do not stack a second copy
    bool has = false;
    Extents3d? label = null;
    Extents3d? frame = null;
    foreach (ObjectId id in rec0) {
        var ent = Tx.GetObject(id, OpenMode.ForRead) as Autodesk.AutoCAD.DatabaseServices.Entity;
        if (ent == null) continue;
        if (ent is RasterImage) has = true;
        var dt = ent as DBText;
        if (dt != null && dt.TextString.ToUpper().Contains("VICINITY")) label = dt.GeometricExtents;
        var br = ent as BlockReference;
        if (br != null && br.Name.StartsWith("SS_BLOCK_")) frame = br.GeometricExtents;
    }
    if (has) { Log(lay.LayoutName + ": raster already present, skipping"); continue; }
    if (label == null) { Log(lay.LayoutName + ": no VICINITY label found, skipping"); continue; }

    var L = label.Value;
    double x0 = L.MinPoint.X;
    double y0 = L.MaxPoint.Y + GAP;
    double x1 = x0 + SIZE, y1 = y0 + SIZE;

    // keep it inside the title block frame
    if (frame != null) {
        var F = frame.Value;
        if (x1 > F.MaxPoint.X - 0.04) { double sh = x1 - (F.MaxPoint.X - 0.04); x0 -= sh; x1 -= sh; }
        if (y1 > F.MaxPoint.Y - 0.04) { double sh = y1 - (F.MaxPoint.Y - 0.04); y0 -= sh; y1 -= sh; }
        if (x0 < F.MinPoint.X + 0.04) { double sh = (F.MinPoint.X + 0.04) - x0; x0 += sh; x1 += sh; }
    }

    var rec = (BlockTableRecord)Tx.GetObject(btrId, OpenMode.ForWrite);
    var img = new RasterImage();
    img.ImageDefId = defId;
    img.Layer = "BLOCK_CLOSURE";
    img.Orientation = new CoordinateSystem3d(
        new Point3d(x0, y0, 0),
        new Vector3d(x1 - x0, 0, 0),
        new Vector3d(0, y1 - y0, 0));
    rec.AppendEntity(img);
    Tx.AddNewlyCreatedDBObject(img, true);
    img.AssociateRasterDef((RasterImageDef)Tx.GetObject(defId, OpenMode.ForWrite));
    RasterImage.EnableReactors(true);
    img.ShowImage = true;

    var back = (RasterImage)Tx.GetObject(img.ObjectId, OpenMode.ForRead);
    var be = back.GeometricExtents;
    Log(string.Format("{0}: raster [{1}] ({2:F4},{3:F4})-({4:F4},{5:F4})  {6:F2} x {7:F2} in  show={8} (verified)",
        lay.LayoutName, back.Handle, be.MinPoint.X, be.MinPoint.Y, be.MaxPoint.X, be.MaxPoint.Y,
        be.MaxPoint.X - be.MinPoint.X, be.MaxPoint.Y - be.MinPoint.Y, back.ShowImage));
    if (frame != null) {
        var F = frame.Value;
        bool inside = be.MinPoint.X >= F.MinPoint.X - 0.001 && be.MaxPoint.X <= F.MaxPoint.X + 0.001
                   && be.MinPoint.Y >= F.MinPoint.Y - 0.001 && be.MaxPoint.Y <= F.MaxPoint.Y + 0.001;
        Log("   inside the title block frame: " + (inside ? "YES" : "NO"));
    }
    placed++;
}

// ---- store the PNG bytes in the drawing so the image can be recovered if the file is lost
try {
    var nod = (DBDictionary)Tx.GetObject(Db.NamedObjectsDictionaryId, OpenMode.ForWrite);
    const string KEY = "C3D_VICINITY_EMBED";
    if (nod.Contains(KEY)) { var old = (DBDictionary)Tx.GetObject(nod.GetAt(KEY), OpenMode.ForWrite); old.Erase(); nod.Remove(KEY); }
    var store = new DBDictionary();
    nod.SetAt(KEY, store);
    Tx.AddNewlyCreatedDBObject(store, true);

    byte[] bytes = System.IO.File.ReadAllBytes(PNG);
    string b64 = System.Convert.ToBase64String(bytes);
    // Xrecord strings cap at 2047 chars per item - chunk it
    var xr = new Xrecord();
    var rb = new ResultBuffer();
    rb.Add(new TypedValue((int)DxfCode.Text, System.IO.Path.GetFileName(PNG)));
    rb.Add(new TypedValue((int)DxfCode.Int32, bytes.Length));
    int chunk = 2000, parts = 0;
    for (int i = 0; i < b64.Length; i += chunk) {
        rb.Add(new TypedValue((int)DxfCode.Text, b64.Substring(i, Math.Min(chunk, b64.Length - i))));
        parts++;
    }
    xr.Data = rb;
    store.SetAt("PNG", xr);
    Tx.AddNewlyCreatedDBObject(xr, true);
    Log(string.Format("embedded {0} bytes as {1} base64 chunks under NOD key {2} (verified)", bytes.Length, parts, KEY));
} catch (System.Exception e) {
    Log("embed failed: " + e.Message);
}

Log("sheets placed: " + placed);
Ed.Regen();

Result

Status
success
Drawing file
C:\Users\sanja\OneDrive\_SurveyDisco\260714 - 285 Huckaby Rd, Brooks, GA 30205, USA\260714 - 285 Huckaby Rd R2.dwg
Message
Executed C3D-0285 (0 entities touched).
Entities
Duration
548 ms
Civil 3D
25.0.0.0

Log

drawing: C:\Users\sanja\OneDrive\_SurveyDisco\260714 - 285 Huckaby Rd, Brooks, GA 30205, USA\260714 - 285 Huckaby Rd R2.dwg
png: 54433 bytes
created image definition VICINITY_260714
   loaded=True  size=(1280,1280)
17X11: raster [215E7] (10.6268,0.7094)-(12.9268,3.0094)  2.30 x 2.30 in  show=True (verified)
   inside the title block frame: YES
11X17: raster [215E9] (0.6579,3.5201)-(2.9579,5.8201)  2.30 x 2.30 in  show=True (verified)
   inside the title block frame: YES
embedded 54433 bytes as 37 base64 chunks under NOD key C3D_VICINITY_EMBED (verified)
sheets placed: 2

Notes

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

No notes yet.