| name | c3d-quantity-takeoff |
| description | QTO criteria, pay items, material computation, earthwork volumes, reports |
Civil 3D Quantity Takeoff
Use this skill when working with quantity takeoff (QTO) - computing material volumes, assigning pay items, defining QTO criteria, generating quantity reports, or calculating earthwork cut/fill volumes.
Quantity Takeoff Overview
Quantity takeoff in Civil 3D connects design objects to cost estimation:
- QTO Criteria = rules mapping corridor shapes/surfaces to material definitions
- Material Lists = computed volumes per sample line group from corridor cross-sections
- Pay Items = cost line items (from .csv pay item files) assigned to Civil 3D objects
- Quantity Reports = XML-based summary or detailed reports of pay item quantities
QTO Criteria and Material Lists
Loading QTO Criteria into a Sample Line Group
Material computation starts by importing QTO criteria into a sample line group. The criteria define which corridor shapes and surfaces produce material volumes.
CivilDocument doc = CivilApplication.ActiveDocument;
SampleLineGroup slg = ts.GetObject(slgId, OpenMode.ForWrite) as SampleLineGroup;
QTOMaterialListCollection materialLists = slg.MaterialLists;
QTOCriteriaNameMapping nameMapping = new QTOCriteriaNameMapping();
materialLists.ImportCriteria(materialLists, nameMapping);
Reading Material Lists
SampleLineGroup slg = ts.GetObject(slgId, OpenMode.ForRead) as SampleLineGroup;
QTOMaterialListCollection materialLists = slg.MaterialLists;
foreach (QTOMaterialList matList in materialLists)
{
ed.WriteMessage("Material list: {0}\n", matList.Name);
foreach (QTOMaterial material in matList)
{
ed.WriteMessage(" Material: {0}\n", material.Name);
QTOMaterialSubcriteriaCollection subcriteria = material.Subcriteria;
foreach (QTOMaterialSubcriteria sub in subcriteria)
{
ed.WriteMessage(" Subcriteria: {0}\n", sub.Name);
}
}
}
Material Sections per Sample Line
Each sample line can return a material section containing computed areas at that station.
SampleLine sl = ts.GetObject(slId, OpenMode.ForRead) as SampleLine;
ObjectId materialSectionId = sl.GetMaterialSectionId();
QTO Material Class Hierarchy
SampleLineGroup
└── MaterialLists (QTOMaterialListCollection)
└── QTOMaterialList
└── QTOMaterial
├── Name — material name (e.g., "Earthwork", "Pavement")
├── Subcriteria (QTOMaterialSubcriteriaCollection)
│ └── QTOMaterialSubcriteria
│ └── QTOMaterialItem (surface or shape reference)
└── QuantityTakeoffResult — computed volume/area results
Earthwork Volume Computation
Volume Surfaces (Cut/Fill Between Two Surfaces)
The most common earthwork calculation compares an existing ground surface to a proposed design surface.
ObjectId volSurfaceId = TinVolumeSurface.Create(
"EW - Cut-Fill",
existingGroundId,
proposedSurfaceId,
surfaceStyleId);
TinVolumeSurface volSurface =
ts.GetObject(volSurfaceId, OpenMode.ForWrite) as TinVolumeSurface;
volSurface.CutFactor = 1.0;
volSurface.FillFactor = 1.20;
VolumeSurfaceProperties volProps = volSurface.GetVolumeProperties();
ed.WriteMessage("Cut: {0:F2} cu.yd.\n", volProps.AdjustedCutVolume);
ed.WriteMessage("Fill: {0:F2} cu.yd.\n", volProps.AdjustedFillVolume);
ed.WriteMessage("Net: {0:F2} cu.yd.\n", volProps.AdjustedNetVolume);
Bounded Volumes (Within a Polygon Region)
Calculate cut/fill within a specific area boundary on any surface.
CivSurface oSurface = ts.GetObject(surfaceId, OpenMode.ForRead) as CivSurface;
Point3dCollection polygon = new Point3dCollection();
polygon.Add(new Point3d(1000, 2000, 0));
polygon.Add(new Point3d(1200, 2000, 0));
polygon.Add(new Point3d(1200, 2200, 0));
polygon.Add(new Point3d(1000, 2200, 0));
SurfaceVolumeInfo volInfo = oSurface.GetBoundedVolumes(polygon, datumElevation: 100.0);
ed.WriteMessage("Cut: {0:F2}, Fill: {1:F2}, Net: {2:F2}\n",
volInfo.Cut, volInfo.Fill, volInfo.Net);
Grid Volume Surface
For regular-grid earthwork computations:
ObjectId gridVolId = GridVolumeSurface.Create(
"Grid EW Volume",
existingGridId,
proposedGridId,
spacingX: 10.0,
spacingY: 10.0,
orientation: 0.0,
surfaceStyleId);
Generating Quantity Reports
XML Report Generation
QTOGenerateDetail detail = new QTOGenerateDetail();
string xmlReport = GenerateXMLReport(detail);
string outputPath = @"C:\Reports\quantities.html";
string xslPath = @"C:\Program Files\Autodesk\AutoCAD 2026\C3D\Quantity Takeoff\xsl\QuantitySummary.xsl";
TransformXMLReport(xmlReport, xslPath, outputPath);
Sample Line Group Quantity Report
SampleLineGroup slg = ts.GetObject(slgId, OpenMode.ForRead) as SampleLineGroup;
slg.ReportQuantities();
Pay Items
Pay Item File Structure
Pay item data is stored in CSV files with item numbers, descriptions, units, and unit prices. Civil 3D loads these through the QTO Manager. A categorization XML file groups pay items into logical categories.
Pay Item Files:
PayItems_2026.csv — item number, description, unit, price
Categories_2026.xml — categorization of pay items into groups
Formulas.xml — quantity computation formulas
Assigning Pay Items to Objects
Pay items are assigned to Civil 3D objects through the QTO Manager or programmatically. Once assigned, the object's quantity (length, area, volume, count) is associated with the pay item for reporting.
Corridor corridor = ts.GetObject(corridorId, OpenMode.ForRead) as Corridor;
ObjectId codeSetId = corridor.CodeSetStyleId;
Reading Pay Item Assignments
CivilDocument doc = CivilApplication.ActiveDocument;
Corridor Material Volumes via Solids Export
An alternative approach to material computation exports corridor solids, which carry all property set data including baseline info and stations.
Corridor corridor = ts.GetObject(corridorId, OpenMode.ForWrite) as Corridor;
ExportCorridorSolidsParams solidParams = new ExportCorridorSolidsParams();
ObjectIdCollection solidIds = corridor.ExportSolids(solidParams, db);
Region-Level Solid Export
BaselineRegion region = corridor.Baselines[0].BaselineRegions[0];
ObjectIdCollection regionSolids = region.ExportSolids(
solidParams,
region.StartStation,
region.EndStation,
db);
Surface-to-Surface Volume (Without Volume Surface)
For quick volume checks without creating a persistent volume surface, use TIN surface solid creation methods.
TinSurface tinSurface = ts.GetObject(surfaceId, OpenMode.ForRead) as TinSurface;
ObjectIdCollection solidIds = tinSurface.CreateSolidsAtSurface(
bottomSurfaceId, "V-EARTHWORK", penIndex: 1);
ObjectIdCollection depthSolids = tinSurface.CreateSolidsAtDepth(
depth: 2.0, "V-SUBBASE", penIndex: 2);
ObjectIdCollection elevSolids = tinSurface.CreateSolidsAtFixedElevation(
elevation: 95.0, "V-EXCAVATION", penIndex: 3);
Gotchas
-
Material computation requires sample lines. You cannot compute corridor material volumes without first creating a sample line group along the alignment. The sample lines define the cross-section stations where areas are calculated and volumes interpolated.
-
QTOMaterialListCollection.ImportCriteria requires two arguments. The API reference may show only one parameter, but the actual method requires both the QTOMaterialListCollection and a QTOCriteriaNameMapping object that maps criteria names to drawing surface/shape names.
-
Volume surface factors are multiplicative, not additive. A FillFactor of 1.20 means 120% of the raw fill volume (20% swell), not an additional 0.20 added to each measurement.
-
GetGeneralProperties() on volume surfaces is expensive. Call once and cache the result rather than querying repeatedly in a loop.
-
Corridor cut/fill volume computation requires COM. The managed .NET API does not expose a direct method on CorridorSurface to compute cut/fill between a corridor surface and a reference surface. Use volume surfaces or export solids instead.
-
Pay item assignments use external CSV files. The pay item database is not stored in the drawing; it is loaded from external .csv files. Changes to the pay item file affect all drawings referencing it.
-
Report generation does not support selection extents. GenerateXMLReport() does not support Sheet and Selection Extent scope or reporting for selected pay items only with station/offset data.
-
Rebuild surface before querying volumes. If the base or comparison surface has been modified, the volume surface must be rebuilt before GetVolumeProperties() returns accurate results.
Related Skills
c3d-corridors -- Corridor objects whose shapes and surfaces feed material computation
c3d-surfaces -- TIN/Grid/Volume surfaces used for earthwork cut/fill calculations
c3d-profiles -- Profile data along alignments used in cross-section volume analysis
c3d-root-objects -- CivilDocument access to surface collections and settings
c3d-mass-haul -- Mass haul diagrams derived from material list volumes