Takeoff Formulas

The complete formula reference for table takeoffs — the four measures, filters, comparisons, deductions, and arithmetic.

Introduction

A takeoff formula answers one question about your markups: how much of this is there? You write it into a table cell, and the table recomputes it from the current markups every time it opens.

Every formula is a measure wrapped around a filter:

area(ext-wall)
│    │
│    └── the filter — which markups to include
└─────── the measure — what to read off them

That is the whole shape. Everything below is a longer answer to "what can go inside the parentheses".

What a cell accepts

A measure cell takes three kinds of entry, and it works out which one you meant:

You typeYou get
4500A pinned number. It stays put and stops following the markups.
4500 LSA lump sum with a unit — for scope you are not marking up.
area(ext-wall)A live takeoff that recomputes from your markups.

Typing a formula into a pinned cell makes it live again.


The four measures

MeasureReadsImperialMetric
count(…)Every matching markup is oneEAEA
length(…)Path length — the perimeter for closed shapesLFm
area(…)Enclosed areaSF
volume(…)Area × the markup's depth propertyCY

The measure is a lens, not a property of the markup. The same rectangle counts as 1 EA in a count cell, gives its perimeter in a length cell, and gives width × height in an area cell — you choose what to read off it.

A markup whose geometry cannot answer the question — the length of a point, the area of an open line, the volume of a markup with no depth — is left out of that cell and reported as an exclusion. It is never quietly counted as zero.

Pages with no scale set are excluded from totals for the same reason: there is no honest way to add feet to paper inches.


Filters

Everything inside the parentheses is the filter. There is no where keyword — conditions simply sit in the parentheses, joined by operators.

Naming what to measure

A bare word is a tag or a preset name:

count(receptacle)
area(ext-wall)

Preset names work by assignment: any markup wearing the Exterior Wall preset matches ext-wall, and so does a markup wearing a preset nested inside it. You never have to tag things twice.

Matching ignores case and punctuation — Exterior Wall, exterior-wall and exterior_wall are all the same name. But you cannot type a space. Write a multi-word preset with a hyphen or underscore:

area(exterior-wall)     ✅
area(exterior wall)     ❌ unexpected "wall" after filter

Combining conditions

OperatorMeansExample
&Andarea(ext-wall & rated)
, or |Orcount(window, door)
!Notcount(door & !temporary)
( )Groupingarea(wall & (rated, fire-wall))

Comparing a property

Beyond tags, you can filter on the values your markups carry:

area(window & u_value<=0.3)
count(door & element_type=A)
length(pipe & size>=4 & size<=12)

The comparisons are =, <= and >=. That is the complete list:

  • Bare < and > are rejected — write <= or >=
  • There is no != — write !key=value instead
  • There is no == — one equals sign is the comparison

A name on the left of a comparison means one of your markup's properties, with five exceptions that refer to the markup itself:

Reserved nameCompares against
typeThe tool that drew it (rectangle, polyline, measurement…)
pageThe sheet number
statusThe markup's status
labelThe markup's label
originWhere the markup came from
count(type=rectangle)
count(page>=2 & status=approved)

Anything else — element_type, u_value, finish — reads from the markup's properties. Nested properties use a dot: spec.size=3068.

tag= does not do what it looks like. tag is not one of the reserved names, so count(tag=window) looks for a property called "tag" and finds nothing. Tags are always written as bare words: count(window).

Quoting values

Values only need quotes when they contain a space or one of , & ! ( ) < > = " ':

count(door & finish=oak)              ✅ no quotes needed
count(door & finish="Type X")         ✅ quotes for the space
count(door & size="3'-0\"")           ✅ escape a quote with \

Either "double" or 'single' quotes work.


Deducting openings

Subtract one measure from another to net out openings. Both sides must be the same measure:

area(ext-wall) - area(window, door)
area(slab) - area(opening)

Deductions are tracked separately from the gross, so a cell can always show you what it took off and why.

One thing to watch: area(a) - (area(b) - area(c)) adds c back, exactly as the parentheses say. Chain your deductions instead of nesting them.


Arithmetic

Formulas take +, -, *, /, parentheses and plain numbers:

(area(ext-wall) - area(window)) * 1.1     10% waste
area(slab) / 9                            SF to SY
count(fixture) * 1.15

Multiplying and dividing change the kind on purpose: area ÷ length gives a length, area × a number stays an area.

Adding unlike quantities

You can add square feet to linear feet. It is usually a modelling mistake — and sometimes exactly the job:

area(facade) / 1.333 + length(facade)     furring at 16" o.c., plus the trim run

What it costs is the unit, not the number. Nothing here can work out what SF + LF is measured in, so the cell computes the figure, shows an amber units? marker, and stays out of the quantity totals rather than joining the wrong one.

The same happens whenever the arithmetic lands somewhere no takeoff unit answers to, like area(a) * area(b).

Naming the unit yourself

Click the units? marker and pick one. That's the whole fix — the unit is set on that row, and the marker goes away.

You can label a cell whose formula compiles cleanly too, for the cases where the formula gets the unit wrong:

FormulaDerivesActually is
area(paving) / 9SFSY — a bare 9 carries no units for the formula to see
area(facade) / 1.333 + length(facade)nothingLF
area(gwb) * 1.05SFSF — leave it alone

A named unit is a label, not a conversion: the number stays exactly what it was. It belongs to the row, not the column, because a formula belongs to a row — labelling one row never relabels the row beside it. A fanned row's buckets all wear it, since they are slices of the same formula.


Column formulas

A formula column is the other kind of formula, and it works on your other columns rather than on markups:

Quantity * Unit price
(Material + Labor) * 1.15

You write the headings you see, exactly as they read on the sheet — spaces and punctuation included, so Sub-total * Waste % names two columns rather than a subtraction. Case does not matter, suggestions complete as you type, and a formula naming a column that does not exist cannot be saved.

Renaming a column rewrites nothing: every formula using it simply reads back under the new heading. That is also why two columns on one table cannot share a heading — name a second one "Cost" and it saves as "Cost 2", so a formula always says which one it means.

Anything blank stays blank: if a row has no Unit price, its total is empty rather than wrong. Dividing by zero gives a blank cell for the same reason.


Recipes

To getWrite
Count of a presetcount(receptacle)
Wall area net of openingsarea(ext-wall) - area(window, door)
Only one sheetcount(door & page=3)
Everything except one tagcount(door & !temporary)
Either of two tagscount(window, louver)
A numeric rangelength(pipe & size>=4 & size<=12)
Excavation volumevolume(footing) — needs a depth on each markup
Add wastearea(gwb) * 1.05
Convert SF to SYarea(paving) / 9 — then label the cell SY
A field rate plus an edge runarea(f) / 1.333 + length(f) — then label it LF

The warnings on a cell

A takeoff is dangerous when it is quietly wrong, so a cell says what is wrong with its formula rather than leaving you a plausible number. Four small markers can appear beside a quantity, and hovering any of them explains it.

MarkerWhat happened
name? (amber)The formula compiles, but it names a tag, a property or a value that does not exist anywhere in this version. The cell holds a real number — usually 0 — and that number is almost certainly wrong. Where the miss looks like a near-match, the tooltip suggests the name you probably meant.
units? (amber)The number is exact, but nothing here can say what it is measured in — the formula adds unlike quantities, or lands outside the four measures. It carries no unit and reaches no quantity total until you say what it is. Click the marker to pick one.
formula? (red)The expression does not parse. The cell stays empty however much gets drawn. The tooltip carries the compiler's own complaint.
math? (red)Every markup resolved and the arithmetic still has no answer — a division by zero, or a result too large to hold.

The same check runs while you type, so the warning appears next to the field before you ever commit the cell.

name? is deliberately quiet in two cases, because in both of them silence is the honest answer:

  • A range. size>=4 is not checked against the sizes anyone has drawn — the endpoint of a range need not exist.
  • A key with no value list. Continuous fields (a depth, a free label) carry too many distinct values to enumerate, so any value compares clean.

When a cell comes back empty

A cell with no warning on it and an empty or zero value is nearly always one of these:

  1. A filter nothing satisfies yet. Every name is real; no markup carries all of them at once. This is a legitimate zero.
  2. A field that holds no value. A field defined as a checkbox is a flag — it marks membership but stores nothing, so field=something can never match it. Check the field's type in the console; retype it to Text, Number or Select if it should carry a value.
  3. An uncalibrated page. Set the scale and the quantities appear.
  4. A volume with no depth. volume(…) needs a depth on each markup.