AQGIS-Sivil3D

Corridor modelling on terrain for QGIS: typical cross sections, TIN, earthwork measurement, profiles and drawings.
Rafael Vázquez · Claude

1. What it is and what it is for

This plugin solves one concrete problem: extruding a typical cross section along an alignment, clipping it against the terrain and obtaining the resulting surface, with its measurements and its drawings. It is a Civil 3D deliberately reduced to that.

The complete workflow is:

1. You define one or more typical cross sections in the editor
2. You apply them to a line layer (a different section per run if you want)
3. The plugin clips them against any DEM and weaves the TIN
4. You get layers, earthwork volumes and, if you want, the merged terrain
5. You review the result in the profile viewer
6. You produce the drawings: plan, longitudinal, cross sections and earthworks
7. You save the whole corridor in a file to reopen it when needed

It works on QGIS 3.28 and later, including the 4.x series.

2. Installation and updating

Run instalar.bat from the project folder. It copies (or links) the plugin into the plugins folder of every QGIS profile it finds. Then, in QGIS: Plugins → Manage and install plugins → Installed, and tick AQGIS-Sivil3D.

Since version 1.0.0 the plugin is also in the official QGIS repository: Plugins → Manage and install plugins → All, search for «Sivil3D» and install it. There is no need to enable «Show also experimental plugins»: 1.0.0 was released as a stable version.

If the code lives on a network drive, Windows junctions do not accept UNC paths and the script copies the files instead of linking them. That means you have to run instalar.bat again every time the code changes, and reload the plugin (the Plugin Reloader add-on saves restarting QGIS).

Merging with the terrain needs scipy, which ships with standard QGIS installations. Without it everything else works and the merge warns instead of failing.

2.1 Language: English or Spanish

Vector → AQGIS-Sivil3D → Language / Idioma…

The whole interface comes in English (the default) or Spanish. The choice belongs to the plugin and is not tied to the QGIS interface language, so you can keep QGIS in one language and the plugin in another.

The language reaches further than the menus. It also decides:

What follows the languageDetail
the names of the generated layerscross sections, footprint, axis… or secciones, huella, eje
the point codesL_CARRIAGEWAY, AXIS, SLOPE_DAY… or I_CALZADA, EJE, TALUD_DAY
the labels printed on the drawingsthe data band, the earthwork table and the scale legend
the starting library of typical cross sectionseach language has its own, see 4.3
the thousands separator1,234.5 in English, 1.234,5 in Spanish
Changing the language needs QGIS to be restarted for the menu, the toolbar and the docked panels to come up translated; the dialogs are already translated the next time you open them. The plugin says so when you change it.

What is never translated is what gets stored: the keys of the section library, the field names of the output layers and the values written into them. That is what lets a project saved in one language be opened in the other. A corridor computed in Spanish keeps its Spanish layer names and point codes, and an English session still recognises them: it applies the right styles and the profile viewer still finds the axis.

3. The three concepts you have to understand

3.1 A typical cross section is a chain of rules, not a geometry

A section is not drawn: it is composed. Each element starts where the previous one ended and produces one or more vertices. That is what lets the same section adapt to a different terrain at every station.

Typical cross section
├─ axis        elevation (terrain | alignment Z), height difference, shift
├─ left  ────┬─ fixed[]   carriageway, shoulder, verge, kerb, ditch…
│            ├─ cut[]     applies if the terrain is ABOVE
│            └─ fill[]    applies if it is BELOW
└─ right ────┘            independent branch, same structure

The two branches are completely independent: a different slope on each side comes for free, with nothing to configure.

3.2 Each side decides on its own whether to excavate or fill

At every station and for each side separately, the plugin looks at the hinge point (the last element of fixed on that side) and compares the design elevation with the terrain one:

At the hinge pointGroup that applies
design below the terraincut
design above or equalfill

A section on a side hill comes out with one side in fill and the other in cut without touching anything.

If you leave the axis elevation on «terrain», the axis rests exactly on the DEM and there is no overall cut or fill: only what the cross slope produces. To get real excavation or filling you have three routes: a 3D alignment (axis elevation = alignment Z), a constant value of elevation, or a height difference of the axis in the editor.

6.2.0 Where the axis elevation comes from

OptionWhat it doesWhat for
from the terrain (DEM)the axis rests exactly on the DEMseeing what comes out from the platform camber alone, without excavating or filling at the axis
from the alignment Zthe geometry carries the elevationa grade line already designed, editable vertex by vertex
constant valuethe same elevation at every station: a level platforma yard, the basin of a pond, a stockpile platform, or trying out the earthworks of a grade line before designing it
offset from the terraingrade line parallel to the terrain at the given distance: positive above, negative belowa constant earthwork thickness: a pavement box, a track excavated half a metre, a bund or a levee

The last two are typed in the field next to the drop-down. The height difference of the axis defined in the section editor is added in all four cases: with an offset of −0.30 in the dialog and a height difference of −0.20 in the section, the grade line ends up 0.50 m below the terrain.

The difference between «constant value» and «offset from the terrain» is the one between a yard and a pavement box. With a constant elevation the grade line is level and the earthwork thickness changes along the axis; with an offset the thickness is constant and the grade line rises and falls with the terrain.

6.2.1 Writing the elevation into the alignment Z

Next to the field there is a Write into the layer Z button, active with the two options that carry a value. With constant value it puts that elevation in the Z of every vertex; with offset from the terrain it drapes: each vertex takes the DEM elevation at its position plus the offset. In both cases it leaves the «from the alignment Z» option selected. From then on the grade line lives in the geometry and can be edited vertex by vertex with the normal QGIS tools: this is the way to start from a level platform and then give it grades.

There is one limit that cannot be worked around: the geometry type is fixed by the layer provider. Hence two behaviours:

If the layer…What happens
already accepts Z (LineStringZ)it is edited in place: whatever Z it had is replaced and the changes are saved
is 2D (LineString)it is not touched —its provider would discard the Z on saving— and a new layer is created with the same fields and attributes, with the Z set, which is left selected as the alignment

With «selected features only» ticked, the elevation is written into those alone. The dialog warns before touching anything, and the log records how many features were modified.

When draping, if the DEM has no data at some vertex of an alignment, that alignment is left untouched and a warning is issued: better than giving it a made-up elevation.

If the layer already had elevations, they are lost: the operation leaves every vertex at the same elevation. That is what is being asked for, but it is worth keeping in mind if the alignment already carried a grade line you had worked on.

The constant value is the shortcut for a level platform —a yard, the basin of a pond, a stockpile platform— and also for trying out how much earthwork a grade line would cost before having it designed: you set an elevation, compute and read the volume. The height difference of the axis is added in all cases, so with a constant elevation of 250 and a height difference of −0.5 the grade line ends up at 249.50.

3.3 The point codes are what stitch the TIN

Each element produces vertices with a code (CARRIAGEWAY, SLOPE_DAY…), to which the prefix L_ or R_ is added according to the side. The codes serve three purposes:

  1. Stitching the TIN. Between two consecutive sections the mesh is woven by pairing vertices by code, not by index, using the longest common subsequence. That is why a section with 2 benches and the next one with 3 stitch together without twisting.
  2. Naming the output feature lines (the breaklines).
  3. Keeping continuity when going from cut to fill: using the same SLOPE code in both conditional groups is what you want, and that is why validation does not flag it as a duplicate.

The vertex where the slope cuts the terrain always carries the _DAY suffix, whichever element generated it, so that the daylight line is continuous. With several chained slopes the code is that of the last one even if it was the first that cut the terrain: this way the line stays a single one and the stitching keeps its anchor when the number of segments changes from one station to the next.

4. Typical cross section editor

Vector → AQGIS-Sivil3D → Typical cross section editor…

On the left, the library of sections. In the centre, the two branches with their three groups and the ordering buttons. On the right, the parameters of the selected element. Below, the section resolved over a test hillside.

4.1 The order is the geometry

Elements are resolved in the order they are in, so Up and Down change the result. The buttons are:

ButtonWhat it does
Addmenu with the elements valid for each group; it is inserted after the selected one
Duplicatecopies the selected element right after it
Removedeletes the selected one
Up / Downmoves the element one position in the chain
copy to the other sideoverwrites the opposite branch with this one; for symmetric sections

4.2 Preview

The test hillside is configurable and is the quick way to check that the slope daylights and that the bench fits, with no need for a DEM or an alignment:

ControlWhat for
terrain (%)cross slope of the test terrain; with a high value you see the side-hill case
terrain at axis (m)terrain elevation relative to the grade line. Positive = terrain above = cut on both sides
Z exag.vertical exaggeration of the drawing
max widthmaximum half-width of the terrain search
codesshows or hides the vertex labels

Colours: brown the terrain, blue the design, ochre the cut, green the fill. A green circle is a daylight point; a red circle, a truncated slope that never reached the terrain.

4.3 Section library

The library is a JSON file that lives in the user profile (<QGIS profile>/aqgis_sivil3d/secciones_en.json), so it is not lost when the plugin is updated. It can be imported and exported to share it.

There is one library per language: secciones_en.json and secciones_es.json. They are not shared because the name of a section is its key —it is what you write in the alignment field to choose which section applies to each run— and the point codes travel to the output layer attributes. Each language therefore starts with its own catalogue, in its own language, and the first time you use a language the plugin writes it for you.

If you had a library from a version earlier than 1.4, it is picked up as the Spanish one: it was written when Spanish was the only language. The original file is not deleted.

4.4 The nine sections in the pack

SectionWhat it is
Road 1+1carriageway, shoulder and verge, with a ditch in cut and a slope in fill
Track 5 ma simple track with a ditch on both sides
Hillside platform (benched)cut with berms, for a side hill
Platform from fieldswidths and slopes read from the layer: a different section per feature
Trench 2 mbottom at an imposed elevation and side walls, for a trench or a channel
Concrete gravity damthe usual triangular profile: upstream face 0.15H:1V and downstream face 0.75H:1V
Rockfill dam with face slabupstream slope 1.25H:1V —the face slab one— and downstream shoulder 1.4H:1V with 5 m berms every 15 m of height
Embankment dam2.5H:1V slopes on both sides, with berms on the downstream shoulder
Concrete wallvertical faces; a starting point for a wall or a face slab

All nine are already in the library the first time you open it. The complete pack also travels inside the plugin, in docs/secciones_pack.json, in case it needs reimporting.

4.5 How a dam is computed

The body of a dam is raised from the terrain up to the crest, so it goes entirely in the fill group: the slope starts at the crest edge and goes down until it meets the valley. The cut group only comes in where the terrain is above the crest, that is, at the abutments.

Two things are done differently from a road:

  1. The axis elevation has to be a constant value (see 6.2.0): the crest is level. With the DEM option you would get a body that rises and falls following the terrain, which is not a dam.
  2. The alignment is drawn along the crest, from abutment to abutment.
The berms appear on their own when the dam is tall enough: with berms every 15 m, a 10 m one has none, a 40 m one has two and a 70 m one, four. Nothing to configure.

And for the basin, the reservoir capacity curve tool (see 13) gives the elevation-volume-area relationship from the DEM.

4.6 Validation warnings

The strip at the bottom warns about the problems that can be detected without terrain:

WarningWhat it means
repeated codestwo elements that can coincide in the same resolved section have the same code; the meshing will not know how to pair them
empty groupone side has cut but not fill (or the other way round): at the stations where the empty group applies, the surface will be left open
does not seek the terrainthe conditional group does not end in a slope that daylights
is not the last onean intermediate slope cannot hand over to the next (it has no segment limit, or they are benches, which do not take one); whatever comes behind will be ignored
below its limitthe maximum height of an intermediate slope cuts before its segment limit, so the hand-over would never happen

5. Element catalogue

ElementWhat it doesParametersGroups
offset_pendienteadvances a width at a given slopewidth, slope (%)all
offset_cotaadvances a width up to a height difference or an absolute elevationwidth, mode, valueall
verticalgoes up or down without advancing: kerb, wall, stepheight differenceall
cunetatriangular or trapezoidal ditch (2 or 3 vertices)depth, bottom width, inner and outer slopes, exit height differenceall
talud_daylightcontinuous slope until it cuts the terrain; goes up in cut and down in fillslope, maximum height, segment limit and how it is measuredcut, fill
talud_banquetarepeats slope + bench until it cuts the terrainslope, bench height and width, bench slope, maximum number of benches, slope of the 2nd and followingcut, fill
The element type keys stay the same in both languages (offset_pendiente, talud_daylight…): they are what is written in the section library JSON, so a library made in one language opens in the other. What is translated is the name shown in the editor.

The last two seek the terrain, and the last element of a conditional group has to be one of them for the surface to close. With talud_banqueta, the number of benches is decided by the terrain at each station, not by you.

5.1 A slope with two or more gradients

An intermediate talud_daylight is also valid, and that is how a slope that changes gradient is defined: 1:1 up to 2 m of height and 1:1.5 from there on, for example. You put two slopes in a row and give the first a segment limit of 2 m:

The break is a normal vertex: it anchors the TIN stitching and comes out as a feature line (the change-of-slope line), but it is not part of the daylight line. It appears only at the stations where that segment did not reach the terrain, just like the benches.

Its code is numbered automatically: SLOPE_Q1, SLOPE_Q2… That is why the slopes of a chain can all be called the same, and in fact that is what you want: they share the code of the daylight vertex, so the toe or crest line comes out in one piece, and their breaks do not get confused with each other because they are numbered. Validation does not flag a repeated code between chained slopes of the same group as a duplicate.

5.2 Benches, catch ditches and anything else in between

Behind a slope there can be any element, not just another slope: a bench (Offset with slope with a slope of 0 or a slight adverse slope), a catch ditch, a vertical segment… and then another slope. They alternate as many times as needed, and the last one in the chain is the one with no segment limit, so that it closes.

This is how a tall embankment is defined giving each segment its own slope, its own height and its own bench, which is what a real case usually asks for. The Benched slope element always repeats the same [slope + bench] pair; by hand you get control segment by segment, at the price of writing several elements.

Inside the chain, every element stops if it reaches the terrain, not only the slopes. A 15 m bench against a rising hillside meets it halfway, and the section closes there. The vertex carries the group's daylight code, like any other closure.

In front of the first slope this does not happen: there the elements are a continuation of the platform and are always drawn. That is what lets the ditch of the road and track templates —which is the first element of the cut group— keep working the same way, and stops a shallow cut from closing at the ditch without reaching the slope.

The limit is measured by elevation (vertical height of the segment) or horizontally (distance covered), as you choose. More than two slopes can be chained; the last one is the one with no limit. Two details:

5.3 How values are written

TypeHow it is written
lengthsmetres: 3.5 or 3,5 (the comma works)
slopesin % with a sign: -2, -2%. Positive = rises away from the axis, so a camber of -2% falls outwards on both sides
side slopesV:H, the usual notation: 1:1.5 is gentle, 1:0.5 steep. 66% and a bare number (1.5 = 1:1.5) also work. Always positive: the slope is a magnitude and the direction is decided by the group (up in cut, down in fill)
optional slopeempty or 0 means «inherit the previous element's»
If you need a segment that goes against its group —down in cut, or up in fill—, it is not a negative slope: it is an Offset with slope, whose slope does carry a sign. And inside a chain it also seeks the terrain (see 5.2), so it daylights just like a slope. A negative side slope raises an error on purpose, so as not to do the opposite of what is written.

5.4 Dynamic parameters

Any parameter also accepts two forms that are resolved once per feature of the alignment:

FormExampleWhen
field reference@widthone value per run, read from the alignment layer
QGIS expression=if("rock" = 1, '1:0.5', '1:1.5')logic per run

In the editor, the test values box lets you preview a section with dynamic parameters: width=7, cut_slope=1:1. Anything not given uses the parameter's default.

6. Computing the corridor

Vector → AQGIS-Sivil3D → Extrude typical cross section (corridor)…

6.1 Inputs

FieldWhat it is
Alignmentsline layer. Each feature is an independent corridor, and so is each part of a multiline
selected features onlyprocesses only the selected features
Terrain (DEM)any raster GDAL can read (GeoTIFF, ASC, IMG, DEM, HGT, VRT…) or a mesh layer. It can be in another reference system: it is transformed
Section libraryJSON file; the button opens the editor
Field with the sectiontext column whose value is the exact name of the section that applies to that run. Empty = default section
Default sectionthe one used when there is no field or it comes empty
Axis elevationfour options, see 6.2.0
The section field is not a numeric identifier: it is the name as it appears in the library, and the comparison is case, space and accent sensitive. To avoid fighting typos, use a Value map in the layer form, or rename the sections to something short. If the name does not exist, the run is skipped and the log tells you which names are valid.

6.2 Options

OptionWhat it does
Station intervalspacing of the sections along the axis
Station at every vertexleave it on. At a vertex the section is placed on the bisector of the angle; without a station there, the mesh opens up on the outside of the curve
Start stationstation value at the beginning of each run
Labelled station intervalhow often stations are labelled (100 m by default). It is independent of the computation step: you can compute every 5 m and label every 100. With 0 the stations layer is not created
Sampling stephow often the DEM is queried when seeking the cut. 0 = automatic from the resolution
Maximum half-widthmaximum distance at which the terrain is sought. If a slope does not cut within it, it is marked as truncated

6.3 Details that affect the result

DEM sampling. It is interpolated bilinearly between the centres of the four neighbouring pixels, the pixel value is not taken. With pixel values, the search for the cut jumps and the daylight line comes out saw-toothed. Reading goes through cached tiles, because each bisection is about 40 samples.

Tight curves. On the inside of a curve the normals converge and beyond a certain distance from the axis the adjacent sections cross. The plugin computes that distance per station and warns if the section width exceeds it: reduce the station interval or smooth the alignment. It does not fix it on its own.

NoData. If the axis falls on NoData, the section is discarded. If it is the slope that enters NoData, a warning is issued and it is truncated.

7. Merging with the base terrain

With the option on, the output TIN also includes the original terrain around the corridor, stitched to the daylight line, so that a single continuous surface is obtained.

How it works: the terrain is sampled on a grid, the nodes that fall inside the corridor footprint are discarded (and those too close to the edge, which would only give sliver triangles), the densified footprint with the corridor elevations is added —those are the seam nodes— and it is triangulated. Then the triangles whose centroid falls inside the footprint are thrown away.

OptionWhat it does
Terrain cellgrid step. 0 = the DEM resolution
Margin aroundhow much terrain is included beyond the footprint

If the requested cell would give an unmanageable grid, it is enlarged and a warning is issued, instead of exhausting the memory. The result has no gaps or overlaps: in the tests, the sum of the triangle areas matches the complete rectangle.

8. Output layers

They all come out inside a group called <alignment>-corridor, ordered for drawing and with symbology applied. Each computation creates a new group (… (2), (3)…) so that alternatives can be compared.

LayerGeometryContent
stationsPointZround stations with P.K. (1+250), distance and angle; label rotated and offset from the axis
pointsPointZevery vertex, with code, offset and elevation
feature linesLineStringZone per code, plus DAYLIGHT_IZQ and DAYLIGHT_DER
cross sectionsLineStringZone per station: mode of each side, widths, cut/fill depth, cut and fill areas, warnings
axisLineStringZthe axis with a road symbol: the line on which the stations are labelled
footprintPolygonZplan outline of each run
TINPolygonZone polygon per triangle, with zona, espesor, area, elevations and slope in %
earthworkstableearthwork volumes between sections
2DM mesh.2dm fileloaded as a native mesh layer: contours, 3D view, mesh calculations
The layer names follow the plugin language, but the field names do not: they stay as they are so that expressions, styles and scripts keep working whichever language the corridor was computed in. And a corridor computed in Spanish keeps its Spanish layer names; opened in an English session it is still recognised and styled correctly.

8.1 Cut and fill colours

The TIN comes out categorised by the zona field:

zonaColourWhat it is
desmonteochrethe design is below the terrain: excavation needed
terraplengreenthe design is above: filling needed
a cotagreystrip next to the daylight, practically on the terrain
terreno naturaltanuntouched terrain, in the merged mesh

The classification is done triangle by triangle comparing its mean elevation with the terrain one under its centroid. The espesor field stores the signed height difference (negative excavates, positive fills), so the colour can also be graduated by earthwork thickness. They are the same colours as the editor preview.

9. Earthwork measurement

The cut and fill areas of each section are obtained by integrating between the design line and the terrain one, splitting at the crossings: it is not an estimate, it is the exact area of the polygons you see shaded.

The volumes go by average end areas:

V = (A1 + A2) / 2 · L

which is the design convention and the one to use if the numbers have to match a measurement done by hand. There is also the prismoidal method, which damps the bias at the change from cut to fill, where one of the two areas is zero.

The mass haul diagram is the cumulative net volume, with a configurable bulking factor: 1.0 means that one cubic metre excavated fills one cubic metre; 0.9, that only 90 % is usable.

On a vertical segment (kerb, wall) the profile has two elevations at the same abscissa. If that is ignored, the integration goes from the entry elevation to the other side of the step and the area is falsified. The plugin keeps both.

The measurement comes out in two places: the cross sections layer carries cota_roja, area_des and area_ter per station, and the earthworks table carries, for each run between consecutive sections, the areas, the cut and fill volumes, the net and the cumulative.

10. Profile viewer

Vector → AQGIS-Sivil3D → Corridor profiles

Dockable panel with three views of the computed corridor:

ViewWhat it shows
Longitudinal profilegrade line against terrain along the axis, with cut and fill shaded and the stations marked
Section at the current stationthe cross section with its codes, its cut/fill depth and its areas
Mass haul diagramcumulative net volume

10.1 Controls

ControlWhat it does
Alignmentschecklist of all the alignments of all the corridors in the session: you tick the ones you want to see at once, and they can be sorted by name or by date. See 10.2
◀ Sta ▶navigates the stations; the drop-down lets you jump to a specific one
vert. exag.vertical exaggeration of the longitudinal. Without it the grade line would be a horizontal stroke
codesvertex labels on the section
click on the mapenables a tool that jumps to the station nearest to the clicked point
Export…saves the current view as a PNG

Navigation is synchronised with the map both ways: as you move through the stations the section is highlighted on the map with a rubber band, and clicking on the map (with the box ticked) jumps to the nearest station. You can also click directly on the longitudinal profile to go to that station.

10.2 Seeing several alignments at once

The Alignments box is the same widget in the viewer and in the drawings dialog. It lists one row per alignment (one per feature of the alignment layer) of each corridor in the session, with its own colour and a checkbox:

ConceptWhat it means
checked (box)enters the combined drawing: it appears on the longitudinal profile and on the mass haul diagram, overlaid and dashed in its colour, and it appears in the drawings
main (drop-down at the top)rules where only one fits: the cross section, the station navigation and, in the drawings, the layout that defines the plan sheets. It is drawn with a solid line and gives the title

The All / None / This one only buttons are shortcuts. Highlighting a row of the list also makes it the main one, and the other way round. The main one need not be checked: you can compare two alignments on the longitudinal while looking at the section of a third.

The Order drop-down sorts the list by creation date (oldest corridors first, which is the order in which they were computed) or by name, alphabetically. With many alternatives in the session, alphabetical is the one that lets you find one by its name. Reordering changes nothing else: the colour of each alignment does not depend on its position in the list, so one that is drawn does not change colour when reordering, nor is anything you had ticked lost.

When the viewer opens no alignment comes out checked, except those of the layer that is active in the layers panel, which come out checked on their own. With several corridors in the session, drawing them all at once leaves the longitudinal unreadable; you tick what you want to compare. In the drawings dialog they do all come out checked: there, wanting the complete set is the normal case.
The main one is a drop-down and not «the row that happens to be selected» on purpose: what goes into the drawings depends on it, and that cannot be hidden in a detail of a list selection.
With several checked, the status bar gives the total cut and fill of all of them and, in addition, the net of each one, which is the comparison you are after when putting two alternatives together.

In the drawings the criterion is the same, but each drawing does what makes sense with several alignments:

It is decided by the Drawing set drop-down, which is at the top of the dialog because it rules over the three drawings (see 11.3):

DrawingA single set, that of the main one (default)A set per alignment
Cross sectionsthe cuts of the main one, and only those. The others appear as a trace on those very cutting planesall the sections on the same sheet, with fid n in front of the station: two 0+000 stations of different axes would be indistinguishable
Longitudinalthat of the main one. The others appear where they cut its vertical planeone strip per alignment, one after another, with its label in the title
Planone set of sheets framed and rotated on the main oneeach alignment generates its own sheets
Earthworksthat of the main oneone table per alignment. Measuring different runs together would invent a volume between the end of one and the beginning of the next

And in all three, with the Others box ticked, the other corridors are drawn where they cross or run close. See 11.4.

11. Automatic drawings

Vector → AQGIS-Sivil3D → Generate drawings…

11.1 How they are made (and why this way)

QGIS has no layout item that draws profiles, and assembling hundreds of layout polylines is not viable. So «drawing on the sheet» is turned into «generating geometry»: a paper-space drawing layer where X and Y are millimetres of paper and each section is translated to its cell of a grid. The drawing is nothing more than a map framed on that layer.

Advantages: it is symbolised with QGIS like any other layer, the atlas paginates on its own, DXF export comes for free and the scales stay explicit.

Two decisions make the drawing dimensionable. The framing is 1:1: the map shows as many units as its frame measures in millimetres, because if the drawing were fitted to the frame the labelled scale would stop being true. And the scale is standard: the largest of 1:50, 1:100, 1:125, 1:200, 1:250, 1:500, 1:1000, 1:2000 in which all the sections fit is chosen, a single one for the whole sheet.

11.2 The four drawings

DrawingHow it is generated
Plan by sheetslayer of sheet rectangles along the axis, used as the atlas coverage: one page per sheet, with the map rotated according to the rotacion field so that the axis comes out horizontal, and a configurable overlap between sheets
Longitudinal profilepaper space at independent H and V scales (1:1000 and 1:100 by default) with the data band underneath: station, ground level, design level and cut/fill depth, with the values rotated. It is paginated into strips: the sheet is cut when the width runs out or when the height no longer fits
Cross sectionsgrid of n×m sections per sheet. The cells are sized to fill the paper you choose
Earthworksclosing sheet with the table of volumes per run and the summary of totals. It paginates on its own if it does not fit, and the totals always go on the last one

11.3 With several alignments: which drawing set comes out

A drawing is that of one axis: its cross sections are the cuts of its route and its longitudinal is its vertical plane. With several alignments checked you have to say whether you want a single project or several, and that is what the Drawing set drop-down is about, at the top of the dialog next to the list of alignments:

ModeWhat it doesWhen
A single set, that of the main alignmentcross sections, longitudinal and plan sheets of the main one. The others do not bring their own set: they appear where they cut those planes, dashedalignments that run together: a road and its diversion, two carriageways, a slip road
A complete set per alignmenteach one generates its cross sections, its longitudinal and its sheets, one after another and numbered continuouslyalignments far apart or that are different works, each needing its own framing
With two parallel axes 40 m apart, the «per alignment» mode generates twice as many plan sheets, and each pair overlaps by more than 70 %: they are the same sheets repeated. On the cross sections you get the same mixture: two different sets of cuts, one from each axis, on the same sheet. That is why the default mode is the main one's.

11.4 The other corridors in the drawing

With the Others box ticked (it is on by default), the drawing of one alignment also shows the rest:

DrawingWhat you see
Cross sectionsthe trace of the other corridor on that very cutting plane. It is computed by cutting the section plane with the other's feature lines (carriageway edge, shoulder, toe of slope…), so it is literally its section there
Longitudinalthe intersection of the other corridors with the vertical plane that runs along the main one. An alignment that crosses it appears only in that stretch —what it measures across at the crossing—, with its elevation, so you can see where it goes: above or below. One that runs parallel and does not cut it does not appear
Planthey always appear, because the map draws their layers

The other traces are drawn dashed and in purple, so that they are not confused with the design being dimensioned, and they are clipped to the frame of the cell: a corridor passing 40 m away from a drawing that spans 15 cannot end up painted over the title block. If it does not fit, it is not shown.

The cut is made against the two families of lines of the other surface: the longitudinal ones (the feature lines) and its own sections. Both are needed: with nearly parallel alignments the plane crosses the longitudinal ones, and with two that meet at a right angle the opposite happens —the other's longitudinal lines are parallel to the plane and never touch it—.

The same thing is visible in the profile viewer: the cross section draws the other checked alignments that cross its plane, each in its colour and dashed. It looks up to three times the section width, and never less than 50 m.

11.5 Which layers appear in the plan

The Drawing layers box lists the project layers that can go to the map and lets you tick the ones you really want. By default the corridor outputs (TIN, footprint, axis, feature lines, cross sections, stations) and the alignment are ticked; the rest of the project —cadastre, orthophotos, working layers— is left out.

The buttons are All, None and Corridor only. Paper-space drawing layers are not even listed: their coordinates are millimetres and on the map they would appear hundreds of kilometres away.

All the project layers used to go to the drawing. In a real project that gives an unreadable sheet and a very slow export.

11.6 Why a longitudinal sheet does not fill the paper

The longitudinal profile sheets are cut for two reasons: because the paper width runs out or because the height no longer fits. The second one is what throws you: you choose A3 and get strips that take up half of it.

With A3 landscape and margins, about 366 mm of usable width and 221 mm of drawing height are left. At a horizontal scale of 1:1000, 366 m of axis fit per sheet; at a vertical scale of 1:100, 22 m of height fit. If the terrain rises more than 22 m in less than 366 m —a grade above 6 %—, the height rules and the sheet is cut earlier:

Vertical scaleHeight that fitsWidth used
1:10022.1 m71 %
1:20044.2 m98 %

It is not a fault: if the drawing does not fit vertically, it has to be split. The fix is to lower the vertical scale (1:200, 1:250) or raise the horizontal one. The log says so when generating, with the scale that would fill the sheet.

11.7 Dialog options

GroupOptions
Which drawingschecked alignments and which is the main one, drawing set (11.3), Others box (11.4), title and .qpt template
Cross sectionspaper, columns and rows of the grid, scale (or automatic) and earthwork sheet
Longitudinalpaper, H and V scales, and how often a data band column is placed
Planpaper, scale, overlap between sheets and which project layers reach the map (11.5)
Exportoutput folder and formats: PDF and DXF
The title block is not programmed. If you give a .qpt template, it is loaded and the plugin only fills its variables (@corredor_titulo, @corredor_subtitulo, @corredor_papel), respecting its page size and using its map item. That way you keep control of the corporate format.
The background raster box is off on purpose: a greyscale DEM covers the whole drawing. Only turn it on if what is loaded is an orthophoto or a hillshade.

12. Vertical alignment editor

Vector → AQGIS-Sivil3D → Vertical alignment editor

It is the longitudinal profile in digitizing mode: the grade line is drawn with the mouse over the terrain, with the same tools used to digitize in plan view, and when finished it is written into the alignment Z. From there the corridor is computed with axis elevation = alignment Z (see 6.2.0), so this editor is the missing piece for designing in elevation without leaving QGIS.

12.1 Getting started

ControlWhat it does
Alignmentline layer the grade line is designed on. On opening, the active layer is chosen, or the first one that is not an output of the corridor itself (the axis, the cross sections and the feature lines are outputs, not alignments)
Runthe feature (and the part, if it is a multiline) being edited; each run has its own grade line
DEMraster or mesh the terrain profile comes from. It is optional: without it you can draw blind, but you cannot see what against
exag.vertical exaggeration of the view. Without it a 3 % grade line is a horizontal stroke
Fitfits the view again after zooming or panning
From the terrainstarts a grade line hugging the terrain with the number of vertices you give: the usual starting point
From the layer Zreads the grade line the geometry already has, vertex by vertex. Choosing a run with Z does it automatically

The view is handled like any other drawing: wheel to zoom around the cursor and middle button dragging to pan.

12.2 How it is handled: two modes and a few actions

The first thing to be clear about is that the bar has two different things:

What they areHow they behave
Move, Insert, Deletemodesthey stay active until you change tool
Straight, Arc, Bézier, NURBS, + controlone-shot actionsthey change the segment and control returns to Move on its own, which is what you want to do next: drag the handles

The actions can be used in two ways: with a segment already selected (they apply when you press the button, and that is it) or with nothing selected (they stay armed and apply to the segment clicked next). Below the bar there is a label that says at each moment what is expected of you.

12.3 What can be dragged

WhatAppearanceWhat it does
Vertexwhite square (orange when selected)dragged in station and in elevation; it is a vertex of the grade line
Handlepurple circle, joined by a dashed lineshapes the curved segment. The arc has one and passes exactly through it; the Bézier has two and approaches without reaching them; the NURBS has as many as you add

When you hover over it, what can be grabbed is surrounded by a circle, and the segment under the cursor is marked in bold. If nothing is highlighted, there is nothing to grab there.

12.4 Several vertices at once

The grade line is an elevation law independent of the plan: its vertices have nothing to do with those of the alignment polyline. Even so it can have quite a few, and raising or lowering a whole stretch one by one would distort the grades along the way. That is why several can be grabbed:

GestureWhat it does
Ctrl (or Shift) + clickadds or removes that vertex from the group
dragging from empty spaceopens a selection window; on release the vertices that fell inside are added
Ctrl+A / All buttonselects them all
Esc / None buttonclears the selection
dragging a vertex of the groupmoves all of them by the same increment, so the stretch rises or falls without distorting
Deldeletes all the selected ones (never leaves fewer than two)

The group's vertices are painted orange, and the top left shows how many are grabbed.

12.5 Simplify: the grade line does not inherit the plan vertices

An alignment can have hundreds of vertices, and if the grade line is already written in its Z it will be densified as well. Reading that vertex by vertex would give a grade line of three hundred nodes that nobody can handle.

That is why, when reading the layer Z, it is simplified with the tol. field at the bottom (tolerance in metres of elevation): it keeps the vertices that really define the grade line, guaranteeing that at no point does it depart more than that tolerance from the original. With 0 they are all read. The Simplify… button does the same on the grade line being edited.

With 0.05 m, an alignment of 250 vertices usually comes down to 15 or 20, and the largest departure from the original grade line is 4 cm. When simplifying, the segments become straight again: the handles of a curve do not survive one of its ends disappearing.
Pressing the button of the type the segment already has does not touch it: if it put the handles back on the chord, you would lose the shape you have just given it. To start from scratch on that segment, set it to Straight and convert it again.

12.6 Shortcuts

GestureWhat it does
double clickinserts a vertex there, with any tool active
right button on a vertexremoves it, as in QGIS digitizing
Delremoves the selected vertex
Escgoes back to Move mode
wheelzoom around the cursor
middle button draggingpans the view
Fitframes everything again

12.7 The short route

  1. Choose the alignment and the DEM: the terrain profile appears.
  2. From the terrain with 4 or 5 vertices: you already have a starting grade line.
  3. Drag the squares until you like the grade line, watching the cut and fill shading.
  4. If some stretch asks for a curve: click the segment (it gets highlighted), press Arc, Bézier or NURBS, and drag the circles.
  5. If it is a road grade line, better leave it straight and put vertical curves with their K at the vertices (12.8): that is how it is designed and how it is checked.
  6. Finish off the numbers in the table and press Apply to the layer Z.

12.8 Vertical curves (L and K)

Besides the segment types —which are those of plan digitizing— each inner vertex accepts a vertical curve: the good old symmetric parabola that rounds the corner between two straights. It is the tool actually used when designing a road and it has no equivalent in plan.

It is defined in two ways: by writing its length L in the corresponding column of the table, or by writing its K and pressing Apply K. K is the metres of curve per 1 % of grade change, which is how it comes in the standards; the editor computes L = K · |Δ grade in %| and the other way round.

RuleWhy
only at inner verticesat the ends there are no two grades to join
only between two straightson a Bézier or a NURBS what rules are the handles; the curve is ignored and a warning is issued
cannot exceed the available tangentotherwise it would eat the neighbouring vertex. It is trimmed to what fits and a warning is issued
if there is no grade change, there is no curvea parabola of zero curvature is the straight itself

In the view, the vertical curve is labelled with its L and its K, and its two ends are marked with a small circle: that is where the curve begins and ends.

12.9 Drawing settings

SettingEffect
snap to the terrainthe vertex being moved sticks to the terrain elevation. Handy to start and to force a level crossing
m Stathe abscissa is rounded to multiples of that value (25 m, 50 m…)
m elevationthe elevation is rounded to multiples of that value (0.10 m, 0.50 m…)

The table on the right is the other half of the editor: station, elevation and L are typed in, and the segment type, the K and the grade are read. It is how a grade line is finished off when it is nearly there: with the mouse you look for the shape and with the numbers you close it.

12.10 What is shown in plan

While editing, the map highlights the alignment of the run with a rubber band and marks with a cross the point the mouse is over and the selected vertex. The readout at the top of the view gives, for the cursor position, station, elevation, terrain elevation and cut/fill depth. Cut and fill are shaded in the same colours as the rest of the plugin (ochre and green), so you can see at a glance which part of the grade line excavates and which part fills.

12.11 Apply to the layer Z

Apply to the layer Z writes the grade line into the geometry of the run being edited:

The step field is the densification: besides the vertices the alignment already has, points are inserted at that step and at the singular points of the grade line (vertices and ends of each vertical curve). It is needed because a parabola between two vertices 300 m apart would be lost if only its ends were written. With a step of 0 only the existing vertices are written.

Before applying, the editor checks the grade line and warns about what a designer would want to know: grades above 12 %, vertical curves that do not fit, abscissas that do not increase and curves that fold back on themselves. You can apply anyway: it is a warning, not a prohibition.

12.12 Limits

13. Reservoir capacity curve (elevation-volume)

Vector → AQGIS-Sivil3D → Reservoir capacity curve

Characteristic curve of a reservoir or pond from the DEM of its basin: for each elevation, the stored volume and the flooded area.

13.1 What is computed

For a water level e:

It is the usual computation, but solved by histogram accumulation: each cell is classified once according to the elevation from which it starts counting, and two cumulative sums give the complete curve. The result is exact and the cost does not depend on the number of elevations, so a basin of several GB with a 10 cm step comes out in a single pass. The DEM is read in blocks, through GDAL when it is a file and through the QGIS provider when it is not.

13.2 Inputs

InputWhat it is
Basin DEMany raster QGIS can read
Clip with a polygonoptional: polygon layer to clip the DEM with, to evaluate only inside. It accepts «selected features only» and reprojects the polygon to the DEM system if needed
Elevations to computeby default from the raster minimum to its maximum (or the clip's, if any). The range can also be set by hand: for example from the bottom to the crest elevation
Stepinterval between elevations. 0.10 m is the usual one

13.3 Outputs

OutputWhen
CSV of the curvealways. Five columns: elevation, volume in hm³, area in ha, volume in m³ and area in m². With «;» as separator and a decimal comma, so that Excel in Spanish opens it without touching anything
PNG of the chartalways. The two panels as they appear, drawn at 1800 × 1200
Clipped DEM loaded and styledonly if it was clipped. That is what distinguishes the two ways of using the tool

With the folder given and the box ticked, the CSV and the PNG are written when the computation finishes; the Save CSV and Save PNG buttons let you choose the place by hand. The clip files carry the -basin suffix so as not to overwrite those of the complete DEM.

13.4 The water surface style

The clipped DEM is loaded with a blue ramp in interpolated pseudocolor: dark blue at the bottom and light blue, increasingly transparent, towards the shore, so that where the depth is small the terrain underneath shows through. The ramp is stretched between the minimum and maximum elevation of the clip, so the same style works for a pond 3 m deep and for a reservoir 60 m deep with nothing to change. The value 0 is left transparent, because in a clip it is a hole and not an elevation.

13.5 Reading the curve

Moving the mouse over the chart reads the elevation, volume and area of each point; clicking pins an elevation, which stays drawn with its label. The two panels share the elevation axis and have their own scale: they are two different magnitudes, hm³ and ha, and a double Y axis would force you to look at two scales to read a single point.

13.6 Things worth knowing

14. Saving and recovering a corridor

Corridor file → Export corridor to file… and Import corridor from file… (a single toolbar button with a drop-down; in the menu they are two separate entries)

The output layers are in memory: they are lost when QGIS closes. Exporting writes two sibling files:

FileWhat it carries
<name>.gpkgall the layers of the group, each with its style inside and its original name. Open format: it opens in any GIS and in CAD
<name>.corredor.jsonthe resolved sections: terrain line, axis elevation and codes of each vertex

The JSON is what the GeoPackage cannot store and without which nothing but the drawing is recovered. With it, on import the whole corridor comes back and you can use the profile viewer, measure and generate drawings without the DEM and without recomputing.

To export, select the corridor group in the layers panel. If you only want the drawing, the .gpkg on its own will do; importing it without the JSON warns that the viewer will have no data.

A corridor exported from a session in one language can be imported in the other: the layers keep the names they were given, and the plugin recognises them anyway, applying the right styles and finding the axis.

15. Several corridors at once

Each computation and each import is registered as an independent alternative, with the group name (axis-corridor, axis-corridor (2)…). They do not overwrite each other, so they can be compared.

The Alignments box of the profile panel and of the drawings dialog lists the alignments of all the alternatives together, so there is no need to pick one and discard the rest: you tick the ones you want to compare, whether from the same corridor or from different ones. See 10.2.

15.1 Corridors survive closing QGIS

A computed corridor is more than its layers: the resolved sections —what the profile viewer and the drawing generator need— live in memory and are not in any layer. So that they are not lost on closing, the plugin saves and recovers them on its own by two routes:

RouteWhen
<project>.sivil3d.jsonon saving the project it is written alongside it, and on opening it is read. It is the normal route: just save the project as usual
<package>.corredor.jsonif the project has layers coming from a GeoPackage exported with the packaging tool (see 14), its sibling JSON is read too. It works even if the project has never been saved, and it is what recovers a colleague's corridor

Recovery is attempted on opening the project and also on opening the viewer or the drawings dialog, in case you have just loaded a GeoPackage by hand. What was computed in the working session always takes precedence over what was recovered, which is older.

Only what is still loaded in the layers panel is recovered. Either of the two tests will do: that its layer group is there —which is the normal case when reopening a project, because the alignments may not have been saved in it— or that its alignment layer is there, which is the test when it has just been computed and no group has been loaded yet. If neither remains, nothing of the corridor is left in the project and it is not offered: deleting a corridor's layer group is the way to remove it from the viewer and the drawings. They used to be offered anyway, and old alignments appeared that led nowhere.

If you open a project saved with an earlier version of the plugin, the tools will still find nothing: that project does not carry the corridors file. Recompute it once and save the project; from then on it travels with it.

16. From Processing

The aqgis:corredor algorithm is in the Toolbox, provider AQGIS-Sivil3D, group Corridor. It is meant for models, batch processes and the console:

import processing
processing.run("aqgis:corredor", {
    "DIRECTRICES": line_layer,
    "DEM": dem_layer,
    "LIBRERIA": r"C:\...\secciones_en.json",
    "CAMPO_SECCION": "section",
    "SECCION_DEFECTO": "Road 1+1",
    "PASO_PK": 10.0,
    "INCLUIR_VERTICES": True,
    "COTA_EJE": 0,            # 0 = from the DEM, 1 = from the alignment Z
    "INTERVALO_PK": 100.0,
    "FUSIONAR": True,
    "CELDA_FUSION": 0.0,      # 0 = DEM resolution
    "HOLGURA": 50.0,
    "GRUPO": "",              # empty = <alignment>-corridor
    "OUT_TIN": "TEMPORARY_OUTPUT",
    "OUT_SECCIONES": "TEMPORARY_OUTPUT",
    "OUT_LINEAS": "TEMPORARY_OUTPUT",
    "OUT_HUELLA": "TEMPORARY_OUTPUT",
    "OUT_EJE": "TEMPORARY_OUTPUT",
    "OUT_PK": "TEMPORARY_OUTPUT",
    "OUT_2DM": r"C:\...\corridor.2dm",
})
The parameter names (DIRECTRICES, PASO_PK…) do not change with the language: they are the algorithm's API and changing them would break the models and scripts that already use it. What is translated is the label shown in the dialog. The SECCION_DEFECTO value does depend on the language, because it is the name of a section in the library.

The fine parameters (sampling step, maximum half-width, start station, DEM band, elevation factor and offset, merge extent, library as JSON and layer group) are under Advanced.

17. Warnings and common problems

SymptomCause and fix
«slope 1:X does not cut the terrain within N m»the slope does not daylight within the maximum half-width. Typical case: a 1:2 fill on a 50 % hillside is parallel to the terrain and never cuts. Change the slope or widen the half-width
«N stations in a curve where adjacent sections cross»curve too tight for the section width. Reduce the station interval or smooth the alignment
«the terrain has no data… (NoData)»the DEM does not cover that area, or there is a hole. Extend the DEM or fill the hole
«unknown section '…'; skipped»the value of the section field does not match any name in the library. The log lists the valid ones
«uses fields that do not exist in the layer»a section with @field parameters is applied to a layer that does not have those fields
«empty group… the surface will be left open»the cut or fill group is missing on one side. If you really want that side to always be of one type, put the same slope in both groups
no triangle is generatedthe DEM does not cover the alignments, or they are in incompatible reference systems
the merge warns that scipy is missinginstall scipy in the QGIS Python; the rest of the plugin works without it
the longitudinal profile does not fitreduce the horizontal scale or let it paginate: it is split into strips automatically
the viewer opens without drawing anythingthat is normal: no alignment comes out checked except those of the active layer. Tick in the Alignments box the ones you want to see, or press All
«'…' is dropped: neither its layer group nor its alignment layer are still loaded»that corridor is in the session file but nothing of it is left in the project, so it is not offered. If you want it back, load its layers again (or its exported GeoPackage); if not, there is nothing to do
alignments that used to appear are missingthat corridor's layers have been removed from the project. Deleting its layer group is the way to withdraw it from the viewer and the drawings
«cannot be negative; the slope is a magnitude»you have written a signed side slope, e.g. -66%. The direction is decided by the group. If you want to go the other way, use Offset with slope (see 5.3)
a bench is cut short of its widthit has reached the terrain. Inside the chain that seeks the terrain, every element stops at it (see 5.2). If you do not want it there, put it in front of the first slope
«repeated codes»two elements that coincide in the same section have the same code and the meshing will not know how to pair them. Note: between chained slopes of the same group repeating the code is fine, and no warning is issued
after changing the language the menu is still in the old onerestart QGIS. The menu, the toolbar and the docked panels are built when the plugin loads; the dialogs are already translated the next time you open them
after changing the language the section library looks emptyeach language has its own library (see 4.3). The first time you use a language its starting catalogue is written; if you had sections of your own in the other language, export them and import them here

18. What this plugin does not do

19. For whoever maintains the code

The separation is deliberate: core/ is pure Python and imports nothing from QGIS, so all the delicate geometry (the TIN stitching, the daylight search, the measurements, the paper space) can be tested without opening QGIS. gis/ is what talks to QGIS; ui/, the interface; processing/, the algorithm; i18n/, the language catalogue.

python -m unittest aqgis_sivil3d.tests.test_core \
                   aqgis_sivil3d.tests.test_medicion \
                   aqgis_sivil3d.tests.test_paperspace \
                   aqgis_sivil3d.tests.test_i18n

Those of the QGIS layer need the QGIS Python: aqgis_sivil3d.tests.test_gis. Among them there are two guards worth not removing: one checks that no PyQt5 APIs removed in PyQt6 are left (exec_, QRegExp…), and another that there are no unscoped Qt enums outside ui/qtcompat.py. They are faults that do not show on import, only when you press the button.

On texts: the literal in the code goes in English, which is the original language, and it is translated with t(). What is stored —internal keys, field names, the section library format— is never translated. test_i18n checks that the format placeholders of the Spanish catalogue match those of the original, because a mismatched one would leave the string unformatted on screen.

20. Authorship and licence

Written by Rafael Vázquez with Claude (Anthropic). Version 1.4.1.

It is distributed as free software under the GNU General Public Licence, version 3 or later (GPL v3+). Anyone can use it, study it, modify it and redistribute it, but with one condition that makes it the most restrictive of the free licences: whoever distributes the plugin, or a modified version of it, has to do so under this same licence and hand over the source code. Nobody can close it or integrate it into a proprietary product. It is delivered without warranty of any kind.

The full text is in the LICENSE file that accompanies the plugin, and also at gnu.org/licenses.

It is the same family of licence as QGIS, which is GPL v2 or later, so the plugin and the program that hosts it are compatible. A QGIS plugin is Python code and is distributed as such: whoever installs it has the code in front of them. The GPL is what guarantees that it stays free for everyone who receives it.