| name | c3d-corridors |
| description | Corridors, baselines, regions, assemblies, subassemblies, corridor surfaces |
Civil 3D Corridors
Use this skill when working with corridors - creating, listing, accessing baselines, assemblies, feature lines, corridor surfaces, and styles.
Corridor Overview
A corridor represents a path (road, trail, railroad). Its geometry is defined by:
- Baseline = alignment (horizontal) + profile (vertical) = 3D centerline
- Assemblies = cross-sectional shapes placed at stations along baselines
- Feature lines = connecting common points in assemblies along the baseline
- Corridor surfaces = surfaces representing the finished roadway
Creating Corridors
CivilDocument doc = CivilApplication.ActiveDocument;
ObjectId corridorId = doc.CorridorCollection.Add("My Corridor");
ObjectId corridorId2 = doc.CorridorCollection.Add(
"Road Corridor",
"Centerline",
alignmentId,
profileId);
ObjectId corridorId3 = doc.CorridorCollection.Add(
"Full Corridor",
"Centerline",
alignmentId,
profileId,
"Region 1",
assemblyId);
ObjectId corridorId4 = doc.CorridorCollection.Add(
"FL Corridor",
"Baseline",
featureLineId);
doc.CorridorCollection.RebuildAll();
Listing Corridors
CivilDocument doc = CivilApplication.ActiveDocument;
foreach (ObjectId objId in doc.CorridorCollection)
{
Corridor corridor = ts.GetObject(objId, OpenMode.ForRead) as Corridor;
ed.WriteMessage("Corridor: {0}, Max triangle side: {1}\n",
corridor.Name, corridor.MaximumTriangleSideLength);
}
Corridor Properties and Methods
Corridor corridor = ts.GetObject(corridorId, OpenMode.ForWrite) as Corridor;
bool outOfDate = corridor.IsOutOfDate;
corridor.RebuildAutomatic = true;
corridor.Rebuild();
corridor.CodeSetStyleId = newCodeSetStyleId;
corridor.CodeSetStyleName = "My Code Set Style";
corridor.MaximumTriangleSideLength = 50.0;
corridor.RegionLockMode = CorridorRegionLockType.LockAllRegions;
string[] pointCodes = corridor.GetPointCodes();
string[] linkCodes = corridor.GetLinkCodes();
string[] shapeCodes = corridor.GetShapeCodes();
SubassemblyTargetInfoCollection targets = corridor.GetTargets();
corridor.SetTargets(targets);
ExportCorridorSolidsParams solidParams = new ExportCorridorSolidsParams();
ObjectIdCollection solidIds = corridor.ExportSolids(solidParams, db);
ObjectId pointGroupId = corridor.ExportFeatureLinesAsCogoPoints(
"Corridor Points", codes);
Corridor Ambient Settings
SettingsCorridor corridorSettings =
doc.Settings.GetFeatureSettings<SettingsCorridor>() as SettingsCorridor;
corridorSettings.NameFormat.Corridor.Value =
"Corridor <[Next Counter(CP)]> (<[Corridor First Assembly(CP)]>)";
corridorSettings.Styles.Alignment.Value = alignmentStyleName;
Name Format Property Fields
| Format | Available Fields |
|---|
| Corridor | <[Corridor First Assembly(CP)]>, <[Corridor First Baseline(CP)]>, <[Corridor First Profile(CP)]>, <[Next Counter(CP)]> |
| Corridor Surface | <[Corridor Name(CP)]>, <[Next Corridor Surface Counter(CP)]> |
| Profile From Feature Line | <[Next Counter(CP)]> |
| Alignment From Feature Line | <[Corridor Baseline Name(CP)]>, <[Corridor Feature Code(CP)]>, <[Corridor Name(CP)]>, <[Next Counter(CP)]>, <[Profile Type]> |
Baselines
A baseline = alignment + profile. A corridor can have multiple baselines (e.g., for intersections).
Reading Baselines
foreach (Baseline baseline in corridor.Baselines)
{
Alignment align = ts.GetObject(baseline.AlignmentId, OpenMode.ForRead) as Alignment;
Profile profile = ts.GetObject(baseline.ProfileId, OpenMode.ForRead) as Profile;
ed.WriteMessage("Baseline - Alignment: {0}, Profile: {1}\n",
align.Name, profile.Name);
ed.WriteMessage(" Start: {0}, End: {1}\n",
baseline.StartStation, baseline.EndStation);
}
Adding and Removing Baselines
Corridor corridor = ts.GetObject(corridorId, OpenMode.ForWrite) as Corridor;
Baseline newBaseline = corridor.Baselines.Add(
"Second Baseline", alignmentId, profileId);
Baseline newBaseline2 = corridor.Baselines.Add(
"Third Baseline", "Alignment - (2)", "Profile - (1)");
Baseline flBaseline = corridor.Baselines.Add(
"FL Baseline", featureLineId);
corridor.Baselines.Remove(newBaseline);
corridor.Baselines.Remove("Third Baseline");
corridor.Baselines.RemoveAt(0);
Baseline bl = corridor.Baselines[0];
Baseline bl2 = corridor.Baselines["Centerline"];
Baseline Regions
Each baseline has regions, each with its own assembly (cross-section shape).
Reading Regions
foreach (BaselineRegion region in baseline.BaselineRegions)
{
ed.WriteMessage("Region: {0}, Start {1}, End {2}\n",
region.Name, region.StartStation, region.EndStation);
}
Creating and Modifying Regions
BaselineRegion newRegion = baseline.BaselineRegions.Add(
"Region 1", assemblyId, 0.0, 500.0);
BaselineRegion newRegion2 = baseline.BaselineRegions.Add(
"Region 2", "Assembly - (1)");
newRegion.StartStation = 100.0;
newRegion.EndStation = 400.0;
newRegion.AssemblyId = differentAssemblyId;
newRegion.Name = "Modified Region";
BaselineRegion secondHalf = newRegion.Split(250.0);
newRegion.Match(sourceRegion, RegionMatchType.All);
newRegion.Merge(firstRegion, lastRegion);
baseline.BaselineRegions.Remove(newRegion);
baseline.BaselineRegions.Remove("Region 2");
baseline.BaselineRegions.RemoveAt(0);
SubassemblyTargetInfoCollection regionTargets = newRegion.GetTargets();
newRegion.SetTargets(regionTargets);
ObjectIdCollection solids = newRegion.ExportSolids(
solidParams, startStation, endStation, targetDb);
Stations in Regions
double[] stations = region.SortedStations();
double midStation = region.StartStation +
((region.EndStation - region.StartStation) / 2);
region.AddStation(midStation, "New Station");
region.DeleteStation(region.StartStation);
double[] addedStations = region.AdditionalStations();
region.ClearAdditionalStations();
OverriddenStationInfo[] overridden = region.GetOverriddenStations();
region.RemoveOverriddenStation(150.0);
Offset Baselines
Secondary baselines offset from the main baseline within a region:
foreach (BaseBaseline ob in region.OffsetBaselines)
{
switch (ob.BaselineType)
{
case CorridorBaselineType.OffsetBaseline:
OffsetBaseline offb = (OffsetBaseline)ob;
var startOffset = offb.GetOffsetElevationFromMainBaselineStation(
offb.StartStationOnMainBaseline);
break;
case CorridorBaselineType.HardcodedOffsetBaseline:
HardcodedOffsetBaseline hob = (HardcodedOffsetBaseline)ob;
break;
}
}
Assemblies
An assembly defines the cross-section template used along a corridor baseline.
Creating Assemblies
CivilDocument doc = CivilApplication.ActiveDocument;
ObjectId assemblyId = doc.AssemblyCollection.Add(
"My Assembly",
AssemblyType.Other,
new Point3d(0, 0, 0));
ObjectId assemblyId2 = doc.AssemblyCollection.Add(
"Styled Assembly",
AssemblyType.Other,
new Point3d(100, 0, 0),
assemblyStyleId,
codeSetStyleId);
ObjectId imported = doc.AssemblyCollection.ImportAssembly(
"Imported Assembly",
sourceDatabase,
"Source Assembly Name",
new Point3d(200, 0, 0));
ObjectId fromCatalog = doc.AssemblyCollection.ImportAssembly(
"Catalog Assembly",
@"C:\path\to\catalog.atc",
itemId,
new Point3d(300, 0, 0));
Modifying Assemblies
Assembly assembly = ts.GetObject(assemblyId, OpenMode.ForWrite) as Assembly;
assembly.Location = new Point3d(50, 50, 0);
assembly.Type = AssemblyType.Other;
assembly.CodeSetStyleId = newCodeSetStyleId;
AssemblyGroup group = assembly.AddSubassembly(subassemblyId);
assembly.AddSubassembly(subassemblyId, hookPoint);
assembly.ReplaceSubassembly(newSubassemblyId, targetSubassemblyId);
assembly.InsertSubassemblyBefore(newSubassemblyId, targetSubassemblyId);
assembly.InsertSubassemblyAfter(newSubassemblyId, hookPoint);
AssemblyGroup copiedGroup = assembly.CopySubassembly(sourceSubassemblyId);
ObjectId copiedId = assembly.CopySubassembly(sourceSubassemblyId, hookPoint);
AssemblyGroup mirroredGroup = assembly.MirrorSubassembly(sourceSubassemblyId);
ObjectId mirroredId = assembly.MirrorSubassembly(sourceSubassemblyId, hookPoint);
AssemblyGroupCollection groups = assembly.Groups;
string[] offsetNames = assembly.GetOffsetBaselineNames();
Applied Assemblies (Corridor Results)
When an assembly is placed along a corridor, it becomes an AppliedAssembly containing CalculatedShape, CalculatedLink, and CalculatedPoint.
foreach (AppliedAssembly appliedAsm in region.AppliedAssemblies)
{
ed.WriteMessage("Assembly - Shapes: {0}, Links: {1}, Points: {2}\n",
appliedAsm.Shapes.Count, appliedAsm.Links.Count, appliedAsm.Points.Count);
foreach (CalculatedPoint point in appliedAsm.Points)
{
ed.WriteMessage(" Point: Station {0}, Offset {1}, Elev {2}\n",
point.StationOffsetElevationToBaseline.X,
point.StationOffsetElevationToBaseline.Y,
point.StationOffsetElevationToBaseline.Z);
}
}
Applied Subassemblies
foreach (AppliedSubassembly appliedSub in appliedAsm.GetAppliedSubassemblies())
{
ed.WriteMessage("Subassembly origin: Station {0}, Offset {1}, Elev {2}\n",
appliedSub.OriginStationOffsetElevationToBaseline.X,
appliedSub.OriginStationOffsetElevationToBaseline.Y,
appliedSub.OriginStationOffsetElevationToBaseline.Z);
Subassembly sub = ts.GetObject(appliedSub.SubassemblyId,
OpenMode.ForRead) as Subassembly;
ed.WriteMessage(" Template: {0}\n", sub.Name);
}
Calculated Elements Structure
AppliedAssembly
+-- Shapes (CalculatedShape)
| +-- Links (collection of CalculatedLink)
+-- Links (CalculatedLink)
| +-- Points (collection of CalculatedPoint)
+-- Points (CalculatedPoint)
| +-- StationOffsetElevationToBaseline (Point3d: X=station, Y=offset, Z=elevation)
| +-- CorridorCodes (string[])
+-- AppliedSubassemblies
+-- (each has its own Shapes, Links, Points)
Feature Lines
Feature lines connect related points (sharing a common code) along the baseline.
Along Main Baseline
foreach (FeatureLineCollection flCol in
baseline.MainBaselineFeatureLines.FeatureLineCollectionMap)
{
foreach (FeatureLine fl in flCol)
{
ed.WriteMessage("Feature line code: {0}\n", fl.CodeName);
foreach (FeatureLinePoint flPoint in fl.FeatureLinePoints)
{
ed.WriteMessage(" Point: {0}, {1}, {2}\n",
flPoint.XYZ.X, flPoint.XYZ.Y, flPoint.XYZ.Z);
}
}
}
Along Offset Baselines
foreach (BaselineFeatureLines bfl in baseline.OffsetBaselineFeatureLinesCol)
{
foreach (FeatureLineCollection flCol in bfl.FeatureLineCollectionMap)
{
foreach (FeatureLine fl in flCol)
{
ed.WriteMessage("Offset feature line: {0}\n", fl.CodeName);
}
}
}
Offset baselines also have RelatedOffsetBaselineFeatureLines for direct access.
Corridor Surfaces
Reading Corridor Surfaces
foreach (CorridorSurface cSurface in corridor.CorridorSurfaces)
{
ed.WriteMessage("Surface: {0}\n", cSurface.Name);
string[] pointCodes = cSurface.PointCodes();
foreach (string code in pointCodes)
ed.WriteMessage(" Code: {0}\n", code);
}
Creating and Managing Corridor Surfaces
Corridor corridor = ts.GetObject(corridorId, OpenMode.ForWrite) as Corridor;
CorridorSurface newSurface = corridor.CorridorSurfaces.Add("Top Surface");
CorridorSurface styledSurface = corridor.CorridorSurfaces.Add(
"Datum Surface", surfaceStyleId);
newSurface.AddLinkCode("Top", true);
newSurface.AddLinkCode("Datum", false);
newSurface.AddFeatureLineCode("Top");
newSurface.RemoveLinkCode("Datum");
newSurface.RemoveFeatureLineCode("Top");
bool isBreak = newSurface.IsLinkCodeAsBreakLine("Top");
newSurface.SetLinkCodeAsBreakLine("Top", true);
string[] linkCodes = newSurface.LinkCodes();
string[] featureCodes = newSurface.FeatureLineCodes();
newSurface.Name = "Renamed Surface";
newSurface.Description = "Top of corridor";
newSurface.SurfaceStyleId = surfaceStyleId;
newSurface.RenderMaterialId = materialId;
newSurface.OverhangCorrection = OverhangCorrectionType.None;
newSurface.IsBuild = true;
ObjectId tinSurfaceId = newSurface.SurfaceId;
double elev = newSurface.FindElevationAtXY(1000.0, 2000.0);
Point3dCollection samples = newSurface.GetSampleElevations(
startX, startY, endX, endY);
corridor.CorridorSurfaces.Remove("Top Surface");
corridor.CorridorSurfaces.RemoveAt(0);
Surface Boundaries
CorridorSurfaceBoundaryCollection boundaries = cSurface.Boundaries;
CorridorSurfaceBoundary extentsBoundary =
boundaries.AddCorridorExtentsBoundary("Extents");
CorridorSurfaceBoundary flBoundary =
boundaries.Add("Daylight Boundary", "Daylight");
CorridorSurfaceBoundary polyBoundary =
boundaries.Add("Custom Boundary", polylineId);
Point3dCollection pts = new Point3dCollection();
pts.Add(new Point3d(0, 0, 0));
pts.Add(new Point3d(100, 0, 0));
pts.Add(new Point3d(100, 50, 0));
CorridorSurfaceBoundary ptsBoundary =
boundaries.Add("Points Boundary", pts);
flBoundary.BoundaryType = CorridorSurfaceBoundaryType.OutsideBoundary;
foreach (CorridorSurfaceBoundary boundary in boundaries)
{
string type = boundary.BoundaryType ==
CorridorSurfaceBoundaryType.InsideBoundary ? "Inner" : "Outer";
ed.WriteMessage(" {0} Boundary: {1}\n", type, boundary.Name);
Point3d[] points = boundary.PolygonPoints();
ed.WriteMessage(" Points: {0}\n", points.Length);
foreach (FeatureLineComponent flc in boundary.FeatureLineComponents)
{
ed.WriteMessage(" Code: {0}, Start: {1}, End: {2}\n",
flc.FeatureLine.CodeName,
flc.StartStation, flc.EndStation);
}
}
boundaries.Remove("Custom Boundary");
boundaries.RemoveAt(0);
Surface Masks
CorridorSurfaceMaskCollection masks = cSurface.Masks;
CorridorSurfaceMask flMask = masks.Add("Median Mask", "Median");
CorridorSurfaceMask polyMask = masks.Add("Custom Mask", polylineId);
CorridorSurfaceMask ptsMask = masks.Add("Points Mask", pointCollection);
masks.Remove("Median Mask");
masks.RemoveAt(0);
Styles
Assembly Style
ObjectId styleId = doc.Styles.AssemblyStyles.Add("My Assembly Style");
AssemblyStyle style = ts.GetObject(styleId, OpenMode.ForWrite) as AssemblyStyle;
ObjectId markerId = style.MarkerStyleAtMainBaselineId;
MarkerStyle marker = ts.GetObject(markerId, OpenMode.ForWrite) as MarkerStyle;
marker.CustomMarkerStyle = CustomMarkerType.CustomMarkerX;
Link Style
ObjectId linkStyleId = doc.Styles.LinkStyles.Add("My Link Style");
LinkStyle linkStyle = ts.GetObject(linkStyleId, OpenMode.ForWrite) as LinkStyle;
linkStyle.LinkDisplayStylePlan.Color = Color.FromColorIndex(ColorMethod.ByAci, 80);
Shape Style
ObjectId shapeStyleId = doc.Styles.ShapeStyles.Add("My Shape Style");
ShapeStyle shapeStyle = ts.GetObject(shapeStyleId, OpenMode.ForWrite) as ShapeStyle;
shapeStyle.AreaFillDisplayStylePlan.Color = Color.FromColorIndex(ColorMethod.ByAci, 50);
shapeStyle.BorderDisplayStylePlan.Color = Color.FromColorIndex(ColorMethod.ByAci, 30);
Code Set Styles (Roadway Style Sets)
Maps corridor codes to link/shape styles:
ObjectId cssId = doc.Styles.CodeSetStyles.Add("My Style Set");
CodeSetStyle css = ts.GetObject(cssId, OpenMode.ForWrite) as CodeSetStyle;
css.Add("TOP", doc.Styles.LinkStyles["My Link Style"]);
css.Add("BASE", doc.Styles.ShapeStyles["My Shape Style"]);
ObjectId currentId = CodeSetStyle.GetCurrentStyleSetId();
corridor.CodeSetStyleId = cssId;
corridor.CodeSetStyleName = "My Style Set";
Gotchas
These are the most common pitfalls when working with corridors in the .NET API:
Feature line polyline creation requires COM. The .NET API provides no method to create a corridor feature line from a polyline. Use the COM interface IAeccLandFeatureLine.AddFromPolyline() instead. The managed CorridorFeatureLine class only supports reading feature lines and exporting them (to polyline, grading feature line, alignment, or profile).
Cut/fill volume computation requires COM. CorridorSurface exposes no managed method to compute cut/fill volumes between a corridor surface and a reference surface. Use COM API to access volume computation.
Offset baselines require COM. There is no managed API method to create offset baselines on a corridor. You can read existing offset baselines via region.OffsetBaselines and cast to OffsetBaseline or HardcodedOffsetBaseline, but creation must go through COM.
.NET API Limitations Summary
| Feature | Supported? |
|---|
| Create corridors | Yes |
| List/read corridors | Yes |
| Rebuild corridors | Yes |
| Add/remove baselines | Yes |
| Create/modify regions | Yes |
| Split/match/merge regions | Yes |
| Create/modify assemblies | Yes |
| Import assemblies | Yes |
| Add/delete stations | Yes |
| Read feature lines | Yes |
| Create feature lines from polylines | No (use COM) |
| Create/modify corridor surfaces | Yes |
| Add/remove boundaries | Yes |
| Add/remove masks | Yes |
| Query surface elevations | Yes |
| Export solids | Yes |
| Get/set targets | Yes |
| Set CodeSetStyle on corridor | Yes |
| Create offset baselines | No (use COM) |
| Compute cut/fill | No (use COM) |
| Create/modify styles | Yes |
Related Skills
c3d-alignments — Alignments used as corridor baselines
c3d-profiles — Profiles used as corridor baselines
c3d-surfaces — Surface objects vs corridor surfaces
c3d-custom-subassemblies — Creating custom subassembly code
c3d-subassembly-patterns — Stock-subassembly pattern catalog and DrawImplement recipes
c3d-superelevation — Superelevation data consumed by corridor subassemblies
c3d-intersections — Intersection objects that split corridor regions
c3d-mass-haul — Mass haul diagrams from corridor earthwork volumes