Transform Coordinate Data Safely with PROJ cct
Feed cct the wrong projection and you get coordinates that look plausible but are simply wrong. It is PROJ's own four-dimensional coordinate conversion and transformation filter, built for exactly this job. The examples here convert longitude and latitude to UTM, preserve extra fields, pull coordinates out of wider records, and check a result with the inverse operation.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Check the installed command
- 2. Convert longitude and latitude to UTM
- 3. Use a file and keep the original data safe
- 4. Preserve auxiliary columns
- 5. Select coordinates from wider records
- 6. Round output only at the presentation boundary
- 7. Check a transformation with the inverse direction
- 8. Diagnose a bad result without guessing
Allow about fifteen minutes. You need the proj-bin package, a shell, and input coordinates whose order, datum and units you actually understand. These examples use PROJ 9.4.0 from proj-bin 9.4.0-1build2. No elevated privileges are needed: the commands only read standard input and write standard output unless you deliberately choose an output file.
1. Check the installed command
Confirm the binary and version first. This is an ordinary read-only check:
$ command -v cct
/usr/bin/cct
$ cct --version
cct: Rel. 9.4.0, March 1st, 2024
cct reads records from a file or standard input. Its default coordinate columns are 1, 2, 3 and 4, read as x, y, z and t. Keep two ideas separate: -c, -z and -t describe the input record, while an operator specification such as +proj=utm describes the coordinate operation itself. It is not +proj=... doing double duty as both.
Checkpoint
You have confirmed the command is PROJ 9.4.0, or recorded whatever version is actually installed on your host.
2. Convert longitude and latitude to UTM
For a first smoke test, convert longitude 12 and latitude 55 to UTM zone 32 on the GRS80 ellipsoid. The input here has only two values, so supply fixed height and time with -z 0 and -t 0:
$ printf '12 55\n' | cct -z 0 -t 0 +proj=utm +zone=32 +ellps=GRS80
691875.6321 6098907.8250 0.0000 0.0000
The first two output values are the transformed x and y coordinates; the fixed height and time come out too, so you get four values back. Here the UTM result is in metres, but that unit comes from the selected operation, not from cct itself.
Do not copy the zone, ellipsoid or axis order blindly. UTM zone 32 suits one longitude range; your real dataset may need a different zone, datum or coordinate convention entirely. Confirm those details from the dataset's own documentation before transforming production data.
Checkpoint
A successful run prints one four-value record and exits with status 0.
3. Use a file and keep the original data safe
For more than a single record, put the input in a working file and send the converted stream to a separate output file. That way you never overwrite the source while checking the result:
$ printf '12 55\n13 55\n' > coordinates.txt
$ cct -z 0 -t 0 +proj=utm +zone=32 +ellps=GRS80 coordinates.txt > coordinates-utm.txt
$ sed -n '1,2p' coordinates-utm.txt
691875.6321 6098907.8250 0.0000 0.0000
756099.6474 6098907.8250 0.0000 0.0000
That redirection is done by the shell. If you would rather cct opened the destination itself, use -o coordinates-utm.txt instead. Either way, treat an output path as a state-changing choice: an existing file can simply be replaced. Check first with test ! -e coordinates-utm.txt, or pick a new path.
Recovery
There is no built-in rollback for an overwritten output file. Recovery means restoring it from backup or regenerating it from the untouched input. Never reuse the same path for input and output until you have confirmed how your shell and this command handle that case.
4. Preserve auxiliary columns
Input records often carry values after the coordinate fields, such as an identifier or source label, and cct forwards those straight to the output. Here the height and observation time are transformed as coordinate values while the trailing label rides along unchanged:
$ printf '12 56 100 2018.0 station-A\n' | cct +proj=merc
1335833.8895 7326837.7149 100.0000 2018.0000 station-A
That is what makes plain text pipelines useful, but it does not make the input self-describing. Keep a record of the column meaning and the operation specification next to the output: nobody can look at bare numbers later and tell whether they are geographic degrees, projected metres or an ellipsoidal height.
5. Select coordinates from wider records
Use -c x,y,z,t when the four coordinate values are not sitting in columns 1 to 4. The numbers are one-based input column positions. This record has longitude in column 5, latitude in column 2, height in column 1 and time in column 4:
$ printf '0 55 0 0 12\n' | cct -c 5,2,1,4 +proj=utm +ellps=GRS80 +zone=32
833978.5569 0.0000 0.0000 0.0000 55
The output writes the transformed values back into their original positions. Column 3, unselected, stays as it was, and the trailing value keeps riding along. This example deliberately uses a synthetic record so the placement is easy to see; map the real columns from your own file before running this on anything that matters.
A common mistake is reading -c 5,2,1,4 as reordering the output. It does not: it is an input selection, taking the four values in x, y, z, t order, transforming them, then writing them back into the selected positions.
6. Round output only at the presentation boundary
Use -d when a downstream consumer needs a fixed number of decimal places:
$ printf '12 55\n' | cct -d 2 -z 0 -t 0 +proj=utm +zone=32 +ellps=GRS80
691875.63 6098907.83 0.00 0.0000
Rounding only changes the printed representation, so keep an unrounded result around for later calculations where precision matters. Two decimal places on the way out is a display choice, not a claim that the source coordinates or the transformation are accurate to that level.
7. Check a transformation with the inverse direction
Add -I to request the inverse operation. It is a good pipeline test, but it will not repair a wrong zone, datum or axis order. This command treats the sample geographic values as input to the inverse UTM operation, so its output is not simply the original pair back again:
$ printf '12 55\n' | cct -I -z 0 -t 0 +proj=utm +zone=32 +ellps=GRS80
4.5113636234 0.0004960657 0.0000 0.0000
For a meaningful round trip, transform a record, then feed the resulting four coordinate values into a second invocation with -I. Compare the final values against the original, allowing for the operation's precision and any rounding you introduced along the way. Keep the intermediate stream unrounded while you check it.
Tip
If a datum transformation needs a grid that is not installed locally, PROJ may need extra resources. The manpage documents optional remote grids activated with PROJ_NETWORK=ON. Turning that on changes the reproducibility and trust boundary of a batch job, so confirm whether the required grids are already local before relying on it, and never enable network access casually for sensitive or offline processing.
8. Diagnose a bad result without guessing
Use -v for non-essential diagnostic information, repeated as -vv or -vvv for more detail. Diagnostics go to standard error while transformed records stay on standard output, so the two streams never mix:
$ printf '12 55\n' | cct -v -z 0 -t 0 +proj=utm +zone=32 +ellps=GRS80 > result.txt
$ printf 'status=%s\n' "$?"
status=0
When a result looks wrong, check in this order:
- Input column order. Are longitude and latitude actually in the order the operation expects?
- Coordinate reference systems. Do the source and target match what you intended?
- Zone, height and time. Is the UTM zone right, and are fixed values correct for this dataset?
- Grid requirement. Does the operation need a grid you have not installed?
A successful exit status only says the command completed; it does not certify that your coordinate metadata was correct.
Checkpoint
You can reproduce the result from a saved input file and the exact operator specification, with no reliance on an interactive prompt or an undocumented default.
Done means
- Version checked. You confirmed the installed PROJ version and the input column convention.
- Operation matched to data. You selected coordinate systems, zone, datum and units that match the dataset.
- Missing values supplied. You gave fixed height and time when the input had fewer than four coordinate values.
- Source protected. You kept the source file unchanged and wrote output to a separate, inspected path.
- Result verified. You checked representative output and, where it mattered, tested a round trip with
-I. - Network status known. You know whether grid data is local and whether this job may touch the network.