Copy Alignment

Hi,

I’m trying to make a copy of an offset alignment. I’ve already handled the lines and the curves between them, but I’m not sure how to deal with the spirals yet.

import clr
import traceback

clr.AddReference('ProtoGeometry')
clr.AddReference('AcMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AeccDbMgd')

import Autodesk.AutoCAD.ApplicationServices as acApp
import Autodesk.AutoCAD.DatabaseServices as db
import Autodesk.AutoCAD.Geometry as geo
import Autodesk.Civil as civil
import Autodesk.Civil.ApplicationServices as civilApp
import Autodesk.Civil.DatabaseServices as civilDb

doc = acApp.Application.DocumentManager.MdiActiveDocument
civilDoc = civilApp.CivilApplication.ActiveDocument
acDb = doc.Database

input_alignment_name = IN[0]
target_alignment = IN[1]

def to_point3d(p2d):
    return geo.Point3d(p2d.X, p2d.Y, 0)

def get_alignment_by_name(name, tr):
    alignment_ids = civilDoc.GetAlignmentIds()
    for id in alignment_ids:
        alignment = tr.GetObject(id, db.OpenMode.ForRead)
        if alignment.Name == name:
            return alignment
    return None

def clear_alignment_entities(alignment, tr):
    count = alignment.Entities.Count
    for i in reversed(range(count)):
        alignment.Entities.RemoveAt(i)

def copy_alignment_entities(source_alignment, target_alignment, tr):
    unsupported_types = []
    entityid_type_log = []

    for i in range(source_alignment.Entities.Count):
        ent = source_alignment.Entities[i]

        prev_ent = source_alignment.Entities[i - 1] if i > 0 else None
        next_ent = source_alignment.Entities[i + 1] if i < source_alignment.Entities.Count - 1 else None

        if isinstance(ent, civilDb.AlignmentLine):
            target_alignment.Entities.AddFixedLine(
                to_point3d(ent.StartPoint),
                to_point3d(ent.EndPoint)
            )

        elif isinstance(ent, civilDb.AlignmentArc):
            if isinstance(prev_ent, civilDb.AlignmentLine) and isinstance(next_ent, civilDb.AlignmentLine):
                try:
                    target_alignment.Entities.AddFixedCurve(
                        to_point3d(ent.StartPoint),
                        to_point3d(ent.EndPoint),
                        ent.Radius,
                        ent.Clockwise
                    )
                except Exception as ex:
                    unsupported_types.append(f"{ent.GetType().Name} (error: {str(ex)})")

            elif isinstance(prev_ent, civilDb.AlignmentSpiral) and isinstance(next_ent, civilDb.AlignmentSpiral):
                try:
                    prev_id = ent.EntityBefore
                    next_id = ent.EntityAfter

                    spiral1_param = prev_ent.A
                    spiral2_param = next_ent.A
                    radius = ent.Radius
                    sp_type = civilDb.SpiralParamType.AValue
                    spiral_def = prev_ent.SpiralDefinition

                    target_alignment.Entities.AddFreeSCS(
                        prev_id,
                        next_id,
                        spiral1_param,
                        spiral2_param,
                        sp_type,
                        radius,
                        spiral_def
                    )
                except Exception as ex:
                    unsupported_types.append(f"Error AddFreeSCS: {str(ex)}")

            else:
                unsupported_types.append("Arc ignored - not between tangents or spirals")

        else:
            unsupported_types.append(ent.GetType().Name)

    if unsupported_types:
        notice = "Entities not copied: " + ", ".join(set(unsupported_types))
    else:
        notice = "All entities copied successfully."

    return notice, entityid_type_log

tr = acDb.TransactionManager.StartTransaction()
try:
    original_alignment = get_alignment_by_name(input_alignment_name, tr)
    destination_alignment = tr.GetObject(target_alignment.InternalObjectId, db.OpenMode.ForWrite)

    if original_alignment and destination_alignment:
        clear_alignment_entities(destination_alignment, tr)
        notice, entity_types = copy_alignment_entities(original_alignment, destination_alignment, tr)
        OUT = f"Alignment '{destination_alignment.Name}' successfully updated.\n{notice}"
    else:
        OUT = "Original or destination alignment not found."

    tr.Commit()
except Exception as e:
    OUT = f"Error executing script:\n{traceback.format_exc()}"
finally:
    tr.Dispose()

I get the following error:
Entities not copied: AlignmentSpiral
Error AddFreeSCS: No method matches given arguments for AddFreeSCS:
(<class 'int'>, <class 'int'>, <class 'float'>, <class 'float'>, <class 'int'>, <class 'float'>, <class 'int'>)

Hi @ADemski,

Have you considered just using the Object.Copy node?

2 Likes

Hi @zachri.jensen
Unfortunately, it doesn’t work for what I need.
I need to create parallel segments of an alignment and then edit some of its parameters — for example, adjusting the lengths of the spiral sections.
If I use Civil 3D’s “Create Offset Alignment” tool, I can’t edit these parameters. Even if I change the alignment type, even if I set “Update Mode” to “Manual.”
And if I use the “Object.Copy” node on this offset alignment, it still doesn’t let me edit it.

So I thought about reading that offset alignment and then creating a new alignment identical to it, but one that I can actually edit.

try used the
[Alignment.CreateOffsetAlignment Method ]

If you create the offset alignment and then change it’s type to something else (say, Centerline), then the geometry should be editable. Is that not what you’re seeing?

What I’m saying is that even after changing to centerline, I still can’t edit it. In the image I sent, if I click on the length ‘99.365’ in the table, I can’t edit it like I would in a normal alignment.

When an offset alignment is created, all of its entities are fixed. So the parameters can be edited if the alignment type or update mode is changed, but there are no constraints between the entities. I assume that is where you’re running into issues.

So if I understand correctly, your goal is essentially to use Dynamo to create your own type of “offset alignment” that has constraints applied?

1 Like

No, my primary goal is to create an alignment that is offset from an existing one, but with editable parameters.

Civil 3D does not allow parameter editing on alignments created via the Offset Alignment command, even after changing the alignment type or its update mode.

The strategy I’m using involves generating the offset alignment initially, and then using Dynamo to replicate it by creating a new (4), independent alignment where all parameters—such as segment lengths, radii, and spiral definitions—can be modified as needed.

The offset alignment serves only as a reference or initial template (1). From it, I extract the geometry: tangents, circular curves, and spiral curves (2) (3).

Using Dynamo, I’ve successfully created a new alignment (4) and extracted the tangent, circular curve, and spiral entities. I was able to reconstruct the tangents and circular curves in the new alignment (5), but I’m currently facing difficulties when trying to add spiral curves (6).

Edits can be made, just maybe not in the way you’re looking for because all the entities are unconstrained. It seems that you’re looking to have editing capability with constraints applied between entities.

Technicalities aside, we can focus on your code :slight_smile:

The error says that the API call you’re making doesn’t match the method signature. Per the API documentation, you need to have two more parameters to specify if the curve is greater than 180d and the spiral type.