Vertical curve elevation calculator
This vertical curve elevation calculator finds the profile elevation at a station measured from the beginning of a parabolic vertical curve.
Run — free
Enter the starting elevation, the signed entry and exit grades as percentages, the horizontal curve length, and the station distance. The result includes the calculated elevation, elevation change from the start, and instantaneous grade at that station. It is suitable for preliminary road, railway, path, drainage, and site-profile checks where a standard constant-rate grade transition is assumed.
Set up the curve and station consistently
Begin with the elevation at the point where the vertical curve starts, often called the PVC or beginning of vertical curve. Enter both tangent grades as signed percentages: a rising grade is positive and a falling grade is negative. For example, a grade of two percent means the profile rises two linear units for every one hundred horizontal units. Curve length and station from start must use the same horizontal unit, while the starting elevation uses the corresponding vertical unit. Feet may be used throughout, or metres may be used throughout; the equation is unit-consistent and does not convert between systems. The requested station must lie from zero through the full curve length. A station of zero returns the starting elevation and entry grade, while a station equal to the length returns the curve-end elevation and exit grade. Use station distance from the curve start, not a project-wide chainage, unless you first subtract the curve-start chainage. This distinction prevents a common and potentially large calculation error.
Understand the parabolic elevation calculation
The calculator uses the standard symmetric parabolic vertical-curve model in which grade changes at a constant rate over horizontal distance. First, the entry and exit percentages are divided by one hundred to obtain decimal slopes. At a distance x from the start, the elevation equals the starting elevation plus the entry-grade tangent rise, then plus a quadratic correction based on the grade difference and curve length. In compact form, that is start elevation plus g1 times x plus the quantity (g2 minus g1) times x squared divided by twice the curve length. The formula works for crest curves, sag curves, and transitions whose two grades have the same sign. The instantaneous grade is interpolated linearly between the entry and exit grades. This tool assumes that stations represent horizontal distance, as is customary in basic vertical alignment calculations. It does not apply arc-length correction, earth curvature, refraction, superelevation, or a nonsymmetric curve model. Keep the original design precision available when carrying the result into later computations.
Check and use the result in design work
Treat the computed elevation as one point on the proposed profile and check it against the surrounding alignment. At minimum, calculate the start and end stations as quick controls: the start should exactly reproduce the supplied starting elevation, and the grades reported at the endpoints should match the supplied entry and exit grades. For a crest curve, the grade generally decreases along the curve; for a sag curve, it generally increases. If the grades have opposite signs, the calculator can also help sample points near the high or low location, although it does not independently report the extremum station. When comparing a design profile with surveyed ground, confirm that both elevations use the same datum and that stationing uses the same origin. The calculation provides geometry, not a compliance decision. Sight distance, drainage, comfort, clearance, and agency-specific minimum K values require separate checks under the governing design standard. For construction setting-out or signed engineering documents, retain appropriate precision, verify independently, and follow the review procedures required for the project.
What you can do with it
Sample a roadway profile
Calculate proposed elevations at selected offsets along a crest or sag vertical curve for a profile table.
Check grading and drainage
Inspect elevation and instantaneous grade at a point where a path, channel, or site alignment crosses the curve.
Compare design with survey data
Generate a design elevation at a surveyed station before calculating cut, fill, or vertical deviation.
FAQ
What grade format should I enter?
Enter signed percentages. Use 2 for a two-percent rise and -1.5 for a one-and-a-half-percent fall.
Can I use feet or metres?
Yes. Use one consistent linear unit for elevation, curve length, and station distance; the output elevation uses that same unit.
Where is station zero?
Station zero is the start of the vertical curve. Convert project chainage to distance from the start before entering it.
Does this work for both crest and sag curves?
Yes. The signed entry and exit grades determine whether the parabola represents a crest, sag, or same-direction transition.
What does the API calculation cost?
Each API request starts at $0.002. The browser calculation is available without a server-side request.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/eng/vertical-curve-elevation \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"start_elevation":100,"entry_grade_percent":2,"exit_grade_percent":-1,"curve_length":200,"station_from_start":75}'const res = await fetch("https://api.kit.forhosting.com/eng/vertical-curve-elevation", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"start_elevation": 100,
"entry_grade_percent": 2,
"exit_grade_percent": -1,
"curve_length": 200,
"station_from_start": 75
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/eng/vertical-curve-elevation",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"start_elevation": 100,
"entry_grade_percent": 2,
"exit_grade_percent": -1,
"curve_length": 200,
"station_from_start": 75
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/eng/vertical-curve-elevation", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"start_elevation":100,"entry_grade_percent":2,"exit_grade_percent":-1,"curve_length":200,"station_from_start":75}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"start_elevation":100,"entry_grade_percent":2,"exit_grade_percent":-1,"curve_length":200,"station_from_start":75}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/eng/vertical-curve-elevation", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"start_elevation": 100,
"entry_grade_percent": 2,
"exit_grade_percent": -1,
"curve_length": 200,
"station_from_start": 75
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "eng.vertical_curve_elevation",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |