Streamlining Corridor Workflows With Dynamo For Civil 3D
Streamlining Corridor Workflows With Dynamo For Civil 3D
Learning Objectives
• Learn how to use Dynamo for Civil 3D to manipulate subassemblies and corridors.
• Learn how to use the Python node to interact with corridors using the Civil 3D .NET
API.
• Learn how to create corridor transitions with Dynamo for Civil 3D
• Discover workflows that improve efficiency when working with corridors.
Description
Corridors are a crucial aspect of many Civil 3D models, but they can sometimes be time
consuming to create, modify, and manage. This class will explore how Dynamo for Civil 3D can
be used to improve efficiency in all aspects of corridor design and management. This class will
cover workflows for corridor creation, corridor geometry manipulation, subassembly
management, quantification, and style management. We’ll explore how to use the Python node
to interact with corridors using the Civil 3D .NET API, expanding upon the functionality of
existing nodes. Learn how to best use Dynamo to streamline your workflows and processes
when working with corridors in Civil 3D.
Speaker(s)
As BIM Development Lead at AtkinsRealis, I bring expertise in information management, ISO
19650 standards and various software to the table. As a Civil 3D SME a large part of my role is
being responsible for Civil 3D, Infraworks & Navisworks standardization across our UK
transportation business being responsible for things like template production, standards,
guidance and training rollout. I believe in staying on the cutting-edge of technology, continually
seeking out new ways to drive process improvement. I've always been fascinated with the
power of technology and its ability to make a real difference in the world. I have a passion for
automating processes through Dynamo & .NET programming.
Before we begin
This class is going to focus on some very specific Dynamo for Civil 3D workflows around
corridors. The workflows I explore in this class are intended to allow you to become more
efficient in how you build and manage corridors and corridor code set styles. In doing so we will
cover some workflows around:
• Dynamo basics
• A full breakdown of the C3D & ACAD APIs
• Non-Corridor related Dynamo workflows
This class unfortunately won’t be covering Dynamo basics. It is assumed you already have a
basic understanding of Dynamo & Dynamo for Civil 3D. If you don’t, there are some fantastic AU
classes, The newly created Civil 3D Dynamo primer and of course the Dynamo forum.
• Dynamo primer - recently updated for Civil 3D! - Dynamo for Civil 3D - Dynamo
(dynamobim.org)
• Getting Started with Dynamo for Civil 3D: A Beginner’s Guide | Autodesk University
• Latest Civil3D topics - Dynamo (dynamobim.com)
Pre-Requisites
• All demonstrations conducted in C3D 2024.0, Dynamo Core 2.17.0.3472 & Dynamo for
Civil 3D 2.17.0.342
• Camber Package https://github.com/mzjensen/Camber
• Civil 3D Toolkit
Creating Corridors with Dynamo
Despite recent improvements in Civil 3D the default tools for corridor creation sometimes feel
clunky, particularly in scenarios where the creation of multiple corridors or baselines are
required in bulk. To create a baseline and corridor from a polyline or featureline using “out of the
box” Civil 3D the process requires a minimum of 20 clicks and 3 separate commands. We are
also unable to create multiple corridors at once. This can make corridor creation for kerbed
islands, car park (parking lots) kerbs, duct runs, barriers etc. time consuming. There is also
currently no support for adding multiple featurelines to a corridor as baselines.
Whilst this workflow is not intended for modeling corridors that represent new sections of
highway with more complex geometry it is particularly useful for:
Assembly to use
The first step in creating our alignments that form our corridor baselines is to check
whether the selected objects are feature lines or polylines. If the objects selected are
Featurelines we create polylines from the featureline objects to allow us to create
alignments further downstream in our graph.
We use the Object.Type node to check if the object type of the selected object is a
polyline or a FeatureLine, If the object is a Featureline we obtain its Dynamo geometry
before creating polyline geometry in the DWG from the Dynamo polycurve. We then
obtain the object handle and use the DocumentExtensions.ObjectByHandle node to
convert the “Object” to a “Polyline”.
Should the selected object already be a polyline this is passed directly to the false input
of the If node.
Next, we can create alignments from the list of polylines from the output of the If node.
We utilize AlignmentExtensions.CreateAlignmentByPolyline. We also build our
alignment names and layer names using a series of code blocks and our input prefixes.
We then create a surface profile using the specified surface for the entire length of each
alignment using AlignmentExtensions.AddProfileBySurface. We construct the profile
name and layer name using the name of the alignment and some code blocks.
We then create a new profile linking the elevation at the start of the surface profile to the
elevation at the end of the surface profile. This is achieved by firstly creating an empty profile
using AlignmentExtensions.AddProfileByName then adding PVIs to the empty profile using
the start and end stations and elevations of the previously created surface profile.
Before the final step of creating corridors, adding baselines, and adding regions we
need to consider whether each Poyline/Featureline should be used to create a separate
corridor or if a single corridor is to be created with multiple baselines. When the Create
Multiple corridor Boolean input is set to true a list of unique strings is created to be used
as corridor names. This is done by counting the number of baselines then using the
range node and a code block to construct a corridor name based on the input prefix. In
a scenario where the multiple corridors Boolean is set to false a single corridor name is
passed through the If node.
Now the baselines have been created and our corridor name list constructed we can
create our corridors. The first step in this process if to use the If node to determine
which vertical baseline to use. When the Use Design Profile input is set to true the
profile which was created by joining the start and end elevations of the surface profile is
used. If the Use Design Profile input is set to false, the surface profile is used.
With the 2023 of Civil 3D a new feature was introduced that allowed us to create transitions by
modifying subassembly parameters over station ranges. Ie. No need for targets or splitting of
regions. More information on the new corridor transition tool can be found at (1149) Model Civil
3D Corridor Transitions Using Any Subassembly - YouTube.
The 2024 release of Civil 3D then introduced an API for corridor transitions which in turn allows
us to interact with these objects using Dynamo.
By creating these transition sets using Dynamo we can move towards designing certain features
with using only a series of inputs. Standard Dynamo graphs can be setup and deployed for
modelling things like:
When initially placing a Python node in Dynamo the following default boilerplate code is
contained in the node. This code provides us with a “template” for which we can create
our corridor transition.
• Lines 2, 3 & 4 are importing the Python engine, common language runtime and
traceback.
• Lines 7 – 12 are adding the AutoCAD and Civil 3D API reference to the common
language runtime – The yellow text are the names of the .dlls located in C:\Program
Files\Autodesk\AutoCAD 2024
• Lines 15 – 23 import the Autocad & Civil 3D namespaces
• Lines 28 & 29 are obtaining the active Civil 3D drawing and the active drawings editor
and storing these in their respective variables.
• In the above example we have also added a Try block at line 35 to handle errors. All
code within the try block will be monitored for exceptions (errors) if an error is
encountered the code inside the Except block at line 42 is executed, in this case that
means writing the error to the Python node output.
Once the relevant references are loaded, we can begin to create our code. We are firstly going
to assign the inputs we pass to the Python node to variables in our Python script as follows:
The IN Variable stores all the input to the python node. We can access and assign these values
to variables in our Python script using the index that corresponds to the input displayed on the
Python node.
Defining a Function
Next, we are going to define our CreateCorridorTransition function. By placing our core code
within a function, we are creating a re-usable block of code that performs a specific task, in this
case creating our corridor transition set. By utilizing a function, we can ensure our Python script
better handles list input.
When defining the function, we can also specify the parameters/arguments. These are values
we pass to the function when it’s called later in our code. Essentially these parameters allow us
to pass input data to the function which are then used inside the function.
Once the function is defined, we can move on to the contents of the function and our core code.
When we work with the Civil 3D or AutoCAD APIs we use the following workflow:
After obtaining the active document (which we stored earlier in the adoc variable) we lock the
document. Locking the document before making changes to the drawing database ensures that
no other changes to the database can be made whilst our code executes.
Opening a transaction is always recommended as it allows us to safely make changes to the
drawing database. Once we reach the bottom of our code we then commit the transaction and
any changes we made to the database in our transaction.
To lock the document, obtain the database and open the transaction we do the following (this is
also how the Python node boilerplate code is setup)
As we are passing the corridor to the Python node using the output of the Select Object
node we must first “unwrap” the corridor object. This is because the underlying API
corridor object is wrapped by the Dynamo object we see in the output of the Select
Object node.
Autodesk.Civil.DatabaseServices.Corridor
To unwrap this object in Python we can use the InternalObjectId property. This allows
us to obtain the ObjectId of the underlying corridor in the drawing database. After
obtaining the corridors ObjectId we can then open the corridor object for write (we are
making changes to the corridor by introducing the transition) and store this in the corr
variable.
TOP TIP! – The InernalObjectId property can be used with a wide range of objects.
Not just corridors!
Creating the Transition Set
Now that we have obtained and opened the corridor API object we can create the
transition set as follows
• Line 49 obtains the first baseline in the corridor using the Corridor.Baselines Property
and stores it in the baselines variable. Note in this example the first baseline is obtained
for simplicity’s sake. In practice it is best to pass the desired baseline as an input
• Line 51 obtains the first baseline region in the baseline using the
Baseline.BaselineRegions Property and stores it in the blregion variable. Note in this
example the first baseline region is obtained for simplicity’s sake. In practice it is best to
pass the desired baseline region as an input
• Line 54 obtains any existing transitions associated with the baseline using the
Baseline.getTransitions Method and stores them in the exTransets variable
• Line 56 initializes a new variable called transet and sets its value to None
Next, we need to check if transition set with the specified name already exists. We do this by:
• Using a for loop we can iterate through the existing transition sets in the exTransets
variable. For each extranset in the exTransets list we:
1. Get the name of the current exTranset and store it in the exTransetName variable.
2. Checks if the exTransetName is equal to the name of the transition set we wish to
create stored in the transetname variable.
3. If the names match, We assign the exTranset to the transet variable and then break
out of the loop.
• On line 64 we can use an if statement that checks whether the transet variable is empty.
If the transet variable is empty this means no existing transition set with the specified
name exists and the transition set needs to be created
• On line 66 the transition set is then created using the CorridorTransitionSet Constructor
Constructor. We pass the name of the transition set, baseline region, subassembly name
and name type as parameters. The CorridorTransitionNameType.SubassemblyName
tells Civil 3D to use the subassembly name rather than subassembly class name.
Now that we have created the transition set, we need to add transition information to the
transition set, including, the subassembly parameter to transition, start and end stations, start
and end parameter values & the transition type. We can do this as follows:
• Line 68 initializes a new variable called transet and sets its value to None
• The CorridorTransition object which we created on line 71 and assigned to the transinfo
variable has a series of read and write (get and set) properties listed in the API
documentation. Autodesk Civil 3D Help | CorridorTransition Class | Autodesk. By setting
these values we pass into our function we can form the transition geometry.
• We do this in lines 74 to 78 setting start station, end station, start value for the parameter
and end value for the subassembly parameter. We also specify the transition type to be
used in line 78. Ie. Linear, BayTaper, Parabolic etc.
Next, we need to apply the transition to the baseline and commit the transaction. We do so as
follows.
To “use” our code we need to call the function we just created with the inputs we passed into the
Python node. This can be achieved with a simple while loop.
• Corridor
• Name of the transition region (containing the morphing subassembly)
• Baseline name
• Name of the subassembly we wish to transition from (initial shape)
• Name of the subassembly we wish to transition to (final shape)
• Name of the Assembly containing the morphing subassembly
• Name of the Morphing subassembly
We then obtain the assembly and morphing subassembly by name and clean the list. Which
then allows us to initially set all the parameters to zero to ensure all values are overwritten
further downstream in our graph. We do this using the
Subassembly.SetParamaterValueByName node, constructing a list of our parameter names in
a code block.
Reading The Values For the Morphing Subassembly Input Parameters via Python
Now that we have completed the necessary preparation in our Dynamo graph we can read the
offsets to each point in the necessary applied subassembly in the regions before and after our
transition. We do this by obtaining the applied subassembly from the applied assembly at the
relevant station in the corridor (last station of region for initial shape, first station of region for
final shape).
Once we obtain the appliedsubassembly we use the AppliedSubassembly.Points Property to
obtain the collection of points belonging to the subassembly.
We can then iterate through the points and use the
CalculatedPoint.StationOffsetElevationToSubassembly Property. This returns the x offset as the
Y component of the point returned by the property and the y offset as the z component returned
by the property. The reason for the misalignment between the value and the point component
which stores the value is due to the x component of the returned point being used for the station
of the point relative to the baseline – think of the point returned by this property as simply being
a placeholder for 3 different values and not point coordinates.
The first step is to assign our inputs to variables and initialize our lists.
• Lines 26 to 30 assign the input to the python node, including corridor, baseline region
name, initially and final subassembly names and the baseline name to variables
• Lines 31 to 34 initialize empty list variables to store our output
• Lines 37 & 38 obtain the active DWG and the document editor
• Line 40 locks the document to only allow input from our script.
• Line 41 obtains the drawing database.
• Line 42 starts a transaction.
• Line 45 unwraps the Dynamo corridor object obtaining the underlying ObjectId before
opening the corridor object for write and assigning it to the corr variable.
• Lines 46 obtains the baselines associated with the corridor using the Corridor.Baselines
Property. We can then obtain a specific baseline in the collection of baselines returned
by this property using the square brackets. We use the blName variable inside these
square brackets to obtain the baseline in the collection with the specified name.
• Line 46 then obtain the BaselineRegions associated with the specified baseline.
• Line 48 then counts the number of baseline regions in the collection.
• Line 49 uses an if statement to check if the number of baseline regions is greater than 0.
If there are no baseline regions the else statement on line 61 tells the script to output
“No regions in baseline” in line 62.
• Line 51 initiates a loop using the for keyword to iterate through the collection of
baselineregions. It uses the enumerate function to keep track of the iteration by
assigning the index to i and the baseline region to blr in each iteration.
• Line 52 checks if the current baseline region's name matches the name of the transition
region.
• If a match is found, line 54 stores the matching baseline region in the blregiontrans
variable.
• Line 55 stores the loop index in the index variable.
• Line 57 attempts to get the baseline region before the transition region (blrbefore) if the
current index is greater than 0.
• Line 59 attempts to get the baseline region after the transition region (blrafter) if the
current index is less than the total number of baseline regions minus 1.
• On Line 60 the loop breaks when a match is found, and the desired baseline regions are
obtained.
Now that we have obtain the relevant baseline regions, we can get the applied subassembly
at the last station of the region containing the shape we wish to transition from and calculate
the offset to each point on the subassembly.
• Line 66 obtains the collection of applied assemblies in the region before the transition
region using BaselineRegion.AppliedAssemblies Property and assigns it to the variable
AppliedAssembliesFirst
• Line 67 counts the number of items in the AppliedAssembliesFirst collection and
stores the count in the variable AppliedAssembliesFirstCount.
• Line 69 checks if there are applied assemblies in the region before the transition. If
AppliedAssembliesFirstCount is greater than 0, it proceeds to retrieve the last applied
assembly. If not, it sets the OUT variable to "No applied assembly in baseline region."
• Line 76 gets the applied subassemblies at the last applied assembly using
AppliedAssembly.GetAppliedSubassemblies Method and assigns them to the variable
AppSubassembliesLast.
• Line 78 initializes a loop that iterates through the AppSubassembliesLast collection to
search for a specific subassembly with the name initSaName. It does this by opening
each applied subassembly In the collection for read and checking its name property. If
the name matches the initial subassembly name It sets the variable
Appliedsubassembly to the found subassembly.
• Line 88 retrieves the points of the applied subassembly (Appliedsubassembly) and
stores them in the sapointsbefore variable.
• In Lines 90-93 A loop iterates through sapointsbefore and extracts the x offset (y
component) and y offset (z component) from the subassembly insertion to each
subassembly point using CalculatedPoint.StationOffsetElevationToSubassembly
Property. These values are appended to the lists sapointsoffsetinitialx and
sapointsoffsetinitialy. A dictionary initdict is then constructed, which stores the x and y
offset to each point in the subassembly.
This process is also repeated for the region after the transition region. Ie. The region
containing the final shape geometry we wish to transition to.
• Line 96 obtains the collection of applied assemblies in the region after the transition
region using BaselineRegion.AppliedAssemblies Property and assigns it to the variable
AppliedAssembliesAfter
• Line 97 counts the number of items in the AppliedAssembliesAfter collection and
stores the count in the variable AppliedAssembliesAfterCount.
• Line 99 checks if there are applied assemblies in the region after the transition. If
AppliedAssembliesAfterCount is greater than 0, it proceeds to retrieve the first applied
assembly. If not, it sets the OUT variable to "No applied assembly in baseline region."
• Line 105 gets the applied subassemblies at the first applied assembly using
AppliedAssembly.GetAppliedSubassemblies and assigns them to the variable
AppSubassembliesFirst.
• Line 107 initializes a loop that iterates through the AppSubassembliesFirst collection to
search for a specific subassembly with the name finalSaName. It does this by opening
each applied subassembly In the collection for read and checking its name property. If
the name matches the initial subassembly name It sets the variable
Appliedsubassembly to the found subassembly.
• Line 117 retrieves the points of the applied subassembly (Appliedsubassembly) and
stores them in the sapointsafter variable.
• In Lines 118-121 A loop iterates through sapointsafter and extracts the x offset (y
component) and y offset (z component) from the subassembly insertion to each
subassembly point using CalculatedPoint.StationOffsetElevationToSubassembly
Property . These values are appended to the lists sapointsoffsetfinalx and
sapointsoffsetfinaly. A dictionary finaldict is then constructed, which stores the x and y
offset to each point in the subassembly.
• Finally, the transaction is committed and the 2 dictionaries containing the offsets to each
point are assigned to the Python node output
The order of the offsets is in the same order as the subassembly points eg. P1, P2,
P3…P10… Bear this in mind if you intend to use this with custom subassemblies.
Once we have obtained our values using Python, we can clean up the data in our Dynamo
graph.
The Dictionary.ValueAtKey node is used to obtain separate lists of X and Y offsets for both
the start and end shape of the transition. Because the subassembly is on the left side the X
outputs are negative values. As the morphing subassembly parameters expect a positive
value me multiple each item in the list by -1.
Finally, we se the parameters on the morphing subassembly using the
Subassembly.SetParameterValueByName node. Passing the names of the morphing
subassembly parameters and the parameter values from the previous nodes.
Note that both lists are counted. This is to deal with scenarios where the initial and final
subassemblies may have a different number of points. In this case we transition from a shape
with 8 points to 6 points. This means we must drop the final 2 parameter names from the
parameter name list to prevent unexpected behavior.
After the parameter values have been set the corridor can be rebuilt manually or by using the
Corridor.Rebuild node to create the transition geometry in our corridor!
Extracting & Visualizing Corridor Quantities with Dynamo & PowerBI
Dynamo is not only useful for creating and manipulating Civil 3D objects but is an extremely
useful tool for obtaining data from Civil 3D models efficiently. The data we can extract using
Dynamo for Civil 3D can be extremely useful for a multitude of downstream activities. In this
example we will focus on extracting and using that data to visualize our corridor quantities in
PowerBI.
How do we do it?
In the above dashboard all the visualizations are produced by consuming an Excel report
produced by Dynamo.
Making full use of custom subassembly codes and code set styles
To extract as much data as possible from our corridors the value of point, link & shape codes
and how we define these in our custom subassemblies should not be underestimated!
Shape Codes
When defining shape codes in my custom pavement subassembly I make heavy use of input
parameters to derive the shape codes for each pavement layer. This allows us to incorporate
pavement course, pavement type & pavement PSV into our shape codes – Which becomes
extremely useful for quantifying pavement volumes of each course, type & PSV downstream!
The above image shows how input parameters can be utilized to apply a level of automation to
our subassembly shape codes.
Point Codes
Similarly kerb types are applied to the kerb point code to allow us to obtain lengths of different
kerb types downstream from the coded corridor featureline.
• We then filter the list of applied subassemblies to only include a specified subassembly.
In this case “ATK_Pavement”
• We then separate left and right sided subassemblies into separate lists
• We then filter the parameters to obtain the value of the crossfall output parameter before
multiplying the values by 100 to obtain a slope %.
Exporting the Data to Excel
After we have extracted all the necessary data from our corridors, we can tidy the data and use
the Data.ExportToExcel node to write the data to Excel. In the graph the Overwrite parameter
is set to true. This ensures that any existing data in the Excel output is removed to avoid
skewing the PowerBI visuals.
It’s also important to note that because we are overwriting the data the heading of each column
needs to be added to the lists using the List.AddItemToFront nodes.
This process is repeated for the featureline lengths, shape volumes, and cut and fill volumes.
Excel Output
Once the data is exported it is contained within 4 separate sheets. Featurelines, Shapes,
Surface Volumes & Lane slope.
Visualising the Data in PowerBi
We can then start to transform this data in the transform data window in PowerBI. In the below
example we run through the steps organize the data to produce a visual detailing pavement
make up volumes.
Visualize More Data!
In this example we have only scratched the surface in terms of what data we can extract using
Dynamo and visualize with PowerBI. Use your own models to extract the likes of offsets to
FeatureLines, Number of corridor sections, Style info, surface points – The list goes on!
Managing Corridor Code Set Styles with Dynamo
The missing filter, sort & import functionality I have just described may not seem that beneficial
initially. But in times where efficiency is everything, we want to utilize code set styles to
automate corridor display for downstream tasks such as drawing production, setting out, GIS
extraction etc. Essentially ensuring our corridors are driving all our outputs eliminating the need
to export separate xrefs.
To accomplish this, templates tend to require a lot of subassembly codes and code set styles.
My Civil 3D template currently in use in our UK Highways business contains over 600 codes in
each code set style across 19 code set styles. It’s when dealing with these codes set styles
that having the ability to bulk import, sort & filter becomes extremely useful.
Combining Dynamo & Excel to Make Code Set Styles More Manageable
By utilizing Dynamo we can write our code set styles to Excel, Make any necessary
amendments such as adding codes or changing styles and descriptions before reading the
updated code set style back into our DWG. This also means we can keep up to date records of
exactly what our code set styles are doing. The high-level process is as follows:
By combining the Style nodes in the camber package and some brief Python we can make the
above possible. We use 2 Dynamo graphs – One to write code set styles & the other to read
code set style info back into the DWG.
We can then filter to obtain point codes (Marker type) by using the String.Contains node and
filtering the list by the returned Boolean variables. This then allows us to obtain each code, it’s
description, code style, label style, feature line style name, pay items and classification.
We can then write this data to a “Point” sheet in Excel.
We repeat this process for link codes writing these to a “Link” sheet.
I can not only use this Excel sheet to quickly search and sort my code set style but any number
of codes can be added, added or amended. In this scenario I have added 2-point codes and set
their styles and descriptions. I have also changed the styles of 2 existing codes.
Reading Code Set Style Changes Back into Civil 3D
After making the necessary changes we can use the read code set styles graph to update the
code set style in Civil 3D.
We first read the Point codes and obtain each code and its styles, description etc.
We then add any new codes to the code set style setting a default marker style. We then use
[passthrough,waitfor][0] inside a code block. This tells Dynamo to wait for the output of the
CodeSetStyle.AddPointItemNode before passing through the code set style to the rest of the
graph. This ensures that any new codes are added before we attempt to change their styles.
We then filter out any codes that are not present in the Excel input.
The passthrough,waitfor code block is then utilized again to wait for the output of the
List.Flatten node before setting Desription, Label Style & pay items. Errors in these nodes are
expected for blank items as these will return null. However, any non-blank items will be set as
intended.
To set the featureline style we need to get the FeaturelineStyle API Object. We do this using a
short Python script.
• Lines 26-28 assigns the input to the python node(code set style name, Code, Feature
line style name) to variables.
• Line 29 initializes the output variable
• Line 38 obtains the code set style collection in the current document and iterates through
each id in the code set style collection
• Line 40 opens the code set style for write
• Line 42 obtains the code set style name
• Line 44 uses an if statement to find the code set style with the same name as the
specified input.
• Line 46 gets the item in the code set style by it’s code and stores it in the cssitem
variable using the CodeSetStyle.GetItemBy.
• Line 48 Sets the featureline style to the featureline style with the specified name.
• Line 49 appends the code set style item to the output list.
The marker style is also set using a short Python script. The python logic is the same as
setting the feature line style except the CodeStyleName property on line 48 is used to set
the marker style.
Packages
• Camber (with thanks to Zachri Jensen) - GitHub - mzjensen/Camber: An open-source
Dynamo package for Civil 3D.
• Civil 3D Toolkit
• Monocle – useful for tidying graphs etc.
Other resources
The Dynamo primer – Recently updated for Civil 3D! Dynamo for Civil 3D - Dynamo
(dynamobim.org)
Dynamo Forum Latest Civil3D topics - Dynamo (dynamobim.com)
Civil 3D API Documentation Autodesk Civil 3D Help | Autodesk.Civil.DatabaseServices
Namespace | Autodesk
Corridor Transitions
More information on the new corridor transition feature that was introduced into Civil 3D 2023
and utilized in this class can be found at Model Civil 3D Corridor Transitions Using Any
Subassembly - YouTube & Autodesk Civil 3D Help | About Corridor Transitions | Autodesk
Contact Me
LinkedIn - Elliot Grubb | LinkedIn
Email – [email protected]