PDF Export¶
TunnelCAD exports cross-sections and reports to PDF through a layout-driven engine. A layout is an ICAD Paper Space drawing — authored in ICAD itself — that carries tagged viewports, text, and rectangles. At plot time, TunnelCAD walks each tagged entity, invokes a matching data provider, and produces a PDF page through ICAD’s plot pipeline.
Note
Single-section + batch (multi-page) PDF export are both shipping. Multi-section sheet booklets aren’t part of the PDF engine — when you need a multi-section sheet layout, use the Section DXF Atlas export (right-click a tunnel → Export Sections to DXF… → atlas mode) instead. The analytics, template, and volume PDF exports are planned to migrate to the layout engine in a future release.
Quick start¶
Open a project and select a section.
Choose File → Export Section to PDF… or click the Export PDF button on the Sections toolbar.
Pick a layout (every new project starts with a seeded
section-A4default).Pick an output filename.
Click OK.
Architecture¶
Four components separate cleanly:
Component |
Unit |
Responsibility |
|---|---|---|
Storage |
|
Layouts + assets live as XML subtrees inside the |
Layout executor |
|
Loads a layout, walks tagged entities, calls providers, plots via ICAD |
Provider registry |
|
|
ICAD plot bridge |
|
Thin |
Layouts¶
A layout is a regular ICAD drawing authored in Paper Space. Entities can be tagged with two reserved attributes on any TDrawObject:
provider— the provider kind (e.g.SECTION_VIEW,TEXT,DR_TABLE)providerArgs—key=val;key=valargument string parsed byTArgMap
Untagged entities pass through as static layout content (title block lines, borders, company text).
Layouts live inside the .tun project as <Layout>…</Layout> nodes under a <Layouts> subtree. Binary assets (logos, photos) live as base64-encoded <Asset> nodes under <Assets>. New projects are seeded with a default section-A4 layout on creation.
Built-in providers¶
Provider |
Role |
Target |
Purpose |
|---|---|---|---|
|
paper |
text entity |
Substitute |
|
model |
viewport |
Draw all section line data into model space on layers named |
|
paper |
rectangle |
Draw DR min/max/avg/std table (placeholder until analytics integration in Plan 3) |
|
paper |
rectangle |
Concentric deviation polar grid + data polyline (placeholder as above) |
|
paper |
rectangle |
Insert a project asset (PNG / JPEG / BMP) at the slot rectangle as an embedded |
|
paper |
rectangle |
Chainage bar with one grey tick per section in the alignment plus a red tick at the current section |
Layout TEXT placeholder fields¶
Layout text entities tagged with the TEXT provider can substitute project values either inline as %FIELD% tokens or whole-text via the field= argument. All numeric fields default to the project’s unit settings (Tunnel Settings → Units); override decimals or format with fmt= on the slot’s args.
No-argument fields¶
Field |
Source |
Default format |
|---|---|---|
|
Project name |
string |
|
Active alignment name |
string |
|
Section station |
|
|
Section name |
string |
|
Section template name |
string |
|
Layout pagination |
integer |
|
Alignment world coordinates at the station |
project |
|
Alignment elevation |
project |
|
Alignment bearing at the station |
project |
|
Vertical gradient at the station, percent |
project |
|
Horizontal radius at the station |
project |
|
Alignment chainage range |
project |
|
End − start chainage |
project |
|
1-based index in the alignment / total sections |
integer |
|
Total measured points on the section (sum across all line definitions) |
integer |
|
|
|
|
Project file path; literal |
string |
Parameterised fields (field= mode only)¶
These cannot be used inline as %FIELD%; set them via field= with the companion arg.
Field |
Required arg |
Description |
|---|---|---|
|
|
Cross-section area (m²) for the named volume definition at the current section. |
|
|
Without |
For cumulative or total volume across the whole alignment, use the Mass Table dialog (right-click a volume definition → Mass Table…). The dialog computes both values and exports them to CSV / XLSX / PDF.
Tagging a text entity — step by step¶
Two modes, picked per text entity:
Mode |
When to use |
|---|---|
Inline |
The entity’s existing text body holds a sentence with one or more |
Whole-text |
The entity should be replaced entirely by one resolved value (with optional |
1. Drop the text in the layout¶
Open the layout in the layout editor (paper-space tab on the Sections workspace).
Use the standard CAD Text tool to place a text entity where you want the label. Type the default body — this is what shows in the layout when no project is loaded, and (in inline mode) it’s also the template the provider rewrites.
2. Tag it as TEXT¶
Select the text entity on the paper canvas.
In the right-side Provider Palette panel, click
TEXT. The palette’s args form below the provider list switches to the TEXT schema (six widgets:field,fmt,prefix,suffix,vol,line).Configure the args (next section).
Click Tag Selected. The entity now carries
Provider=TEXTand the serialized args string. The Outline panel shows it; the Property Inspector has both rows.
To re-edit a tag later, select the entity again — the palette auto-loads its current Provider + args. Change values, click Tag Selected to save.
3. Configure the args form¶
The args form widgets:
Widget |
Type |
Effect |
|---|---|---|
|
dropdown of every supported field |
Empty → inline |
|
text box |
Optional override for numeric formatting. Examples: |
|
text box |
Prepended to the resolved value. Only honoured in |
|
text box |
Appended to the resolved value. Only honoured in |
|
text box |
The volume-definition name. Required when |
|
text box |
The line-definition name. Optional when |
4. Worked examples¶
These are the most common patterns. The “ProviderArgs” column shows the serialized form the editor stores under the hood (key=val;key=val); in normal use you fill in widgets, you don’t type the string.
Inline mode — leave field empty¶
Type the tokens directly into the entity’s text body. Tokens are uppercase and surrounded by %.
Entity text body |
ProviderArgs |
Resolved output (sample) |
|---|---|---|
|
(empty) |
|
|
(empty) |
|
|
(empty) |
|
|
(empty) |
|
|
(empty) |
|
|
(empty) |
|
The entity’s body is the template. Any text outside %…% is preserved literally.
Whole-text mode — set field to a token name¶
The entity’s existing text body is discarded and replaced by prefix + resolved + suffix.
|
Other args |
Resolved output |
Use for |
|---|---|---|---|
|
(none) |
|
A station label that is just the station, no surrounding sentence. |
|
|
|
Same, with caption + unit. |
|
(none) |
|
Default project units (gradians here). |
|
|
|
Override decimals; the angular unit and |
|
|
|
Horizontal radius label. |
|
|
|
Custom date format. |
|
|
|
Per-section excavation area. |
|
|
|
Same with full caption. |
|
(none) |
|
Total points on the section. |
|
|
|
Just the Crown line’s points. |
|
|
|
Caption + unit. |
When you need multiple parameterised values on one label¶
You can’t write %AREA[Excavation]% inline (parameterised tokens are field-mode only). To show, e.g., excavation and lining areas on the same drawing, drop two text entities side by side:
Entity A:
field=AREA,vol=Excavation,prefix=Excavation:,suffix= m²Entity B:
field=AREA,vol=Lining,prefix=Lining:,suffix= m²
5. Troubleshooting¶
Symptom |
Cause |
Fix |
|---|---|---|
The token shows up literally as |
Inline mode but the token is misspelled, lower-case, or uses an unsupported name |
Tokens are uppercase and must match the supported list. The PDF export emits a warning diagnostic listing the offending field. |
Field-mode entity shows the original text instead of the resolved value |
|
Set the |
|
|
Switch to |
Empty text where you expected an area / radius / bearing |
The alignment has no engine geometry yet, or |
Import the alignment geometry; verify the volume-definition name in Tunnel Settings → Volumes. |
|
|
Change Tunnel Settings → Units → Angular Unit if you want degrees / DMS / radians instead of gradians. |
Tagging an IMAGE entity — step by step¶
The IMAGE provider drops a project-embedded raster (logo, photo, scan) into the slot rectangle.
1. Register the image as a project asset¶
Images live in the project’s Assets collection — named binary blobs serialized inside the .tun file, so the layout travels with the project.
Open the asset manager from one of:
Ribbon File → Manage Project Assets…
Right-click the project root in the Project Tree → Manage Project Assets…
Click Add… → pick a PNG / JPEG / BMP file.
The MIME type is auto-detected from the file extension.
The asset name defaults to the filename stem (e.g.
company_logo.png→ asset namecompany_logo).On a name collision the dialog prompts Replace / Rename / Cancel.
The list view shows every registered asset with name, MIME type, and size in KB. Rename and Remove operate on the selected row.
Close the dialog. Save the project (the assets are embedded as base64 in the
.tun).
2. Drop a placeholder rectangle in the layout¶
In the layout editor, draw a regular CAD rectangle where the image should appear. The IMAGE provider sizes the bitmap to the rectangle’s bounds (no scaling preserves aspect — make the rectangle the intended display size).
3. Tag the rectangle as IMAGE¶
Select the rectangle.
In the Provider Palette, click
IMAGE. The args form has one widget:asset.Type the asset name you registered in step 1 (e.g.
company_logo) — case-insensitive.Click Tag Selected.
The rectangle now resolves to your bitmap on the next plot. The bottom-left of the rectangle becomes the bottom-left of the image; the rectangle’s width and height become the image’s world width and height.
4. Worked examples¶
ProviderArgs |
Effect |
|---|---|
|
Inserts the asset named |
|
Warning — |
|
Warning — |
If the asset’s MIME isn’t one of image/png / image/jpeg / image/bmp, the provider draws the placeholder rectangle and emits a unsupported MIME type diagnostic.
Editing layouts on the Sections tab¶
Layouts are paper-space tabs on the existing Sections tab workspace. Model space holds the current section’s geometry (auto-updated as you navigate); paper tabs compose the PDF output.
Open a project. The Sections tab shows the current section in model space. A Layouts side panel docks on the right.
Layouts → New Layout… creates an empty paper tab; Layouts → Load Layout… loads a dormant layout already in the project.
Flip to the paper tab on the workspace tab strip. The side panel’s palette + args form become active.
Draw entities on the paper tab with standard CAD tools, or click Insert on the palette to drop a default-sized placeholder. Tag existing entities via Tag Selected.
Fill in provider arguments in the schema-driven form. Insert and Tag Selected both read the current args.
The side panel’s Outline lists every tagged entity. The loaded-layouts list lets you unload without going through the menu.
Navigate to another section — tagged entities on every loaded paper tab re-resolve automatically (live WYSIWYG). The viewport auto-frames the new model geometry.
Layouts → Export Section to PDF… (or
TUNPDF) plots the active paper tab. Layouts → Batch Export PDF… (orTUNPDFBATCH) plots a station range as a single multi-page PDF.The Property Inspector shows
ProviderandProviderArgsrows for any selected entity — edit tags there too.Save the project — loaded layouts capture their live state into their
IQMLBlobs; dormant layouts pass through unchanged.
Known limitations¶
DR data (for
DR_TABLEandPOLAR_CHART) is not wired. Radial deviations come from the analytics engine; Plan 3 will integrate them. For now both providers emit a warning and draw a placeholder frame.No ICAD command-registry integration yet.
TUNPDF/TUNPDFBATCH/TUNLAYOUT*are plain procedures invoked from menu items; typing them at the command line isn’t wired until TunnelCAD adopts ICAD’s command registry.Sheet sets / per-section booklet output are out of scope. Use the Section DXF Atlas export (right-click a tunnel → Export Sections to DXF… → atlas mode) when you need a multi-section sheet layout.
Verifying the editor (manual smoke test)¶
After building TunnelCAD locally:
Open TunnelCAD, create a new project → Sections tab active, Layouts side panel visible, no layouts loaded.
Layouts → New Layout… → type a name → empty paper tab appears on the workspace tab strip.
Flip to the paper tab. Click
DR_TABLEin the palette → click Insert → a rectangle appears tagged withDR_TABLE. The outline lists it. The inspector showsProvider=DR_TABLE.Navigate to a section that has data → the DR_TABLE rectangle refreshes (placeholder content until Plan 3 wires analytics).
Layouts → Export Section to PDF… → pick an output path → a valid single-page PDF is produced.
Layouts → Batch Export PDF… → pick the loaded layout + a station range → a multi-page PDF is produced.
Save project, close, reopen → the layout is present in the loader picker (dormant). Layouts → Load Layout… restores it with the same content.
Commands¶
TUNPDF— plot the active paper tab on the Sections workspace to PDF. Wired asExecuteTunPDFCommand(Owner, Project, Section, Session)inPrint/UCmdTunPDF.pas.TUNPDFBATCH— plot a station range as a single multi-page PDF. Wired asExecuteTunPDFBatch(Owner, Project, Session, Navigate)inPrint/UCmdLayouts.pas.TUNLAYOUTLOAD/TUNLAYOUTUNLOAD/TUNLAYOUTNEW/TUNLAYOUTDELETE/TUNLAYOUTIMPORT/TUNLAYOUTEXPORT— the load/unload lifecycle.
Extending the engine¶
To add a new provider — for example, a custom chart type:
Create a new
Print/UProviderX.pasunit implementingIProvider(name, role,Resolve(Ctx, Slot, Canvas, Args, Result, LayoutName)).Call
RegisterProvider(TProviderX.Create)— usually from aRegisterProviderXprocedure invoked at app startup.Author a layout in ICAD with a tagged entity using your new provider name and args.
That’s it — the engine picks it up automatically.
See Print/UProviderText.pas and Print/UProviderSectionView.pas for worked examples of paper-role and model-role providers respectively.
Design documents¶
Spec:
docs/superpowers/specs/2026-04-18-tunnel-pdf-export-design.mdPlan 1:
docs/superpowers/plans/2026-04-18-tunnel-pdf-export-plan-1-engine-skeleton.mdLayout Editor:
docs/superpowers/plans/2026-04-18-tunnel-layout-editor-plan.md