MLEADERSTYLE for arrowhead + dogleg.
C-ANNO
Discipline classification
- Word-boundary prefix match on network names: prefix appears as a complete alphanumeric token, separated by start/end of string or any non-alphanumeric character.
- Defaults:
STRM, Storm/SSWR, Sewer, Sanitary/WATR, Water/FM, Forcemain, Force Main. Each prefix is a comma-separated list, one discipline can match several naming conventions in one drawing (e.g. bothSTRMand24109 Storm). Override per-office insettings.json. - Catches
STRM,STRM-EX,STRM-Phase1,EX-STRM,SSWR-FM; rejectsSTRMA-EX(no boundary). - All six cross-discipline pairs detected (storm↔sewer, storm↔water, storm↔FM, sewer↔water, sewer↔FM, water↔FM). Same-discipline pairs skipped, two storm networks in one drawing each label against the sewer/water/FM, not against each other.
- Exclude networks (
ExcludeNetworksinsettings.json): a comma-separated token list; any matching network is dropped from detection entirely. Use it to keep a previous-phase or existing/reference network off the current sheet (e.g.24109skips24109 Storm).
Math & placement
- Separation = bottom-of-upper − top-of-lower, using outside-diameter on each pipe.
- Curved water/FM sampled along the actual horizontal arc using
CenterPointLocation+HorizontalRadius+ bulge, no chord fakery. - Plan label anchors at upper pipe centerline. Profile label anchors at the crossing pipe, the transverse one with the larger perpendicular offset from the alignment.
- Station is view-aware. Plan labels read the nearest Centerline-typed (road) alignment station with offset, broken onto its own line under the header so the callout stays narrow (
PIPE CROSSING:/7+50 (12.3' RT)/ separation / disciplines, 4 lines). Each profile label reads the station of that profile view's own alignment inline on the header (PIPE CROSSING: 3+21), a sewer profile shows the sewer station, a water profile the water station. - Optional callout lines (dialog toggles, independent): Northing/Easting on plan labels and/or profile labels (the crossing's plan coordinate), and a road-CL station+offset reference line (
ROAD CL 7+50 (12.3' RT), wording editable in the dialog) on utility profile labels, omitted on a road's own profile, where the header is already the road station. - Annotative MLeader: paperspace text height
0.1; AutoCAD scales for active annotation scale (1"=30', 1"=40', etc.).
Three modes
- Run (default): full reset, wipe + insert all detected crossings. First-run / major redesign.
- Refresh: update existing labels' content in place. Never adds new, never deletes orphans, your manual deletions + drag-for-readability positions stick.
- Pick: interactive, click a crossing in plan view to add one label. ESC to finish.
Prompt: Mode [RUn/REfresh/Pick] <RUn>:, capital letters mark shortcuts. Type Ru / Re / P, or pick from the menu.
Day-to-day workflow
- Run once → get the auto-batch.
- Delete false positives + clutter; drag remaining labels for readability.
- Design changes → Refresh → numbers update, positions + deletions stick.
- New pipe added → Refresh lists unlabeled crossings → Pick to add specific ones.
- Major redesign → Run again to reset.
Refresh scope: each label carries XData keyed to its crossing's plan XY, the one coordinate that survives an elevation edit, so Refresh updates both plan and profile labels in place, immune to elevation edits and text/arrow moves. Since 1.100.0 a label written by an older release (no key, and in the original block or MText+Line shape) no longer has to be re-Run: Refresh works out which crossing it belongs to, by inverting the profile view it sits in, by plan proximity, or by the pipe pair its own text names, updates it, and stamps it so every later Refresh binds it instantly. Anything it still cannot bind is listed one per line with its location and text, never just counted.
Layers (1.101): the callouts have their own layers now, C-ANNO-PIPE-XING and C-ANNO-PIPE-XING-CONF, instead of sharing the general annotation layer. Run erases prior labels BY LAYER, so a shared layer left a text-prefix check as the only thing between this tool and everyone else's annotation. Layer no longer decides what Refresh can SEE: it finds every callout whose text says PIPE CROSSING on any layer, in any of the three entity formats this tool has shipped, and consolidates them onto the configured layer. That filter was a silent correctness bug, a callout on a retired layer was never updated, never counted, never mentioned, and never replaced by Run either. A callout found on a NON-PLOTTING layer (Defpoints, or plot switched off) is moved and flagged: it is visible on screen, reads as reviewed and labeled, and is missing from every sheet issued. And if the label layer cannot be resolved the command now refuses to label rather than leaving the callouts on whatever layer happened to be current, which is how they reach Defpoints in the first place.
Dialog

VDCPIPELABEL%APPDATA%\VDC\PipeCrossings\settings.jsonWhen to use it
- Labeling utility crossings and clearances for the plan and profile sheets.
How to run it
- Run VDCPIPELABEL - the dialog carries the mode radios (Run / Refresh / Pick), the area choice (whole drawing or a window picked after OK), and every label option.
- Select the networks (or, in Pick, click the crossings - in PLAN or inside a PROFILE VIEW; a profile click creates the label there, or updates the one already there).
- Choose scope at the [Extents/Window] prompt - press Enter for the whole drawing, or type W to pick a window (handy for one sheet at a time).
- Review the plan and profile crossing labels.
Options
- Run / Refresh / Pick: label all crossings in scope, update the existing labels in place, or label only the crossings you click.
- Refresh and older labels: a label written by an earlier release carries no stamp saying which crossing it belongs to. Refresh now works that out - by inverting the profile view it sits in, by plan proximity, or by the pipe pair its own text names - updates it, and stamps it, so it rebinds instantly ever after. Anything it still cannot bind is listed with its location and text rather than counted.
- Pick in a profile view: click the crossing where you are actually looking at it. Not near a crossing in plan means the click is tested against every profile view; if it landed in one, the crossing that view draws nearest that station is the one you picked. Scoped to that view - the same crossing labeled in several views is never touched in the others.
- Scope vs detection scope: the dialog's detection scope says WHICH networks and pipe types to consider; the [Extents/Window] choice says WHERE. They stack - a crossing must pass both.
- Road CL line on profile labels: adds the nearest road centerline station + offset under the header of a utility profile label ("ROAD CL 8+35 (0.1' LT)"). The leading wording is editable - shorten it to RD or CL, or blank it for the station and offset alone.
Watch out for
- Separation reads the modeled inverts - confirm network elevations are correct.
- If you pick a Window it is a PLAN window. Profile-view labels for crossings inside it are still placed - a profile view sits outside the plan area by definition.
- The original block-with-attributes label format is the one thing Refresh still cannot rewrite: the callout lives in attributes whose tags varied between the versions that wrote them, so its colour updates but its text does not. Refresh names those labels; Run replaces them correctly.
Related: Pipe QC