Select station on Alignment

Select station on Alignment

Wittekamp
Contributor Contributor
6,478 Views
15 Replies
Message 1 of 16

Select station on Alignment

Wittekamp
Contributor
Contributor

Hi,

 

I'm trying to build an application that returns the station of an alignment on a point definied by the user.

I want the user to see where he is on the alignment before he or she defines the point.

 

This behaviour is similar to the situation when you define the start and end station for a corridor region for example. When you do that you see a red perpendicular line moving along the alignment. Left clicking on the mouse then gives you the value of the station at that point. This seems to be a standard civil way of selecting a station, but i can't find any documentation on this on how to implement this in a custom application.

 

Does anyone know the code snippet for this selectionmethod?

0 Likes
Accepted solutions (1)
6,479 Views
15 Replies
Replies (15)
Message 2 of 16

hippe013
Advisor
Advisor
Accepted solution

This might help get you going.

 

 

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.Civil.DatabaseServices
Imports Autodesk.AutoCAD.GraphicsInterface

<Assembly: CommandClass(GetType(SelectAlignmentPoint.MyCommands))> 
Namespace SelectAlignmentPoint

    
    Public Class MyCommands

        Private aDoc As Document = Application.DocumentManager.MdiActiveDocument
        Private db As Database = aDoc.Database
        Private ed As Editor = aDoc.Editor


        Private line As Line
        Private alignment As Alignment
        Private tm As TransientManager = TransientManager.CurrentTransientManager
        Private station As Double
        Private offset As Double


        <CommandMethod("SelectAlignmentPoint")> _
        Public Sub SelectAlignmentPoint()
            

            Dim optSelect As New PromptEntityOptions(vbCrLf + "Select Alignment")
            optSelect.SetRejectMessage(vbCrLf + "Must be an Alignment.")
            optSelect.AddAllowedClass(GetType(Alignment), True)

            Dim res As PromptEntityResult = ed.GetEntity(optSelect)

            If res.Status = PromptStatus.OK Then

                Using trans As Transaction = db.TransactionManager.StartTransaction
                    line = New Line
                    line.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 1)
                    tm.AddTransient(line, TransientDrawingMode.Main, 128, New IntegerCollection)
                    alignment = trans.GetObject(res.ObjectId, OpenMode.ForRead)
                    AddHandler ed.PointMonitor, AddressOf TrackMouse

                    Dim optPoint As New PromptPointOptions(vbCrLf + "Select Point: ")
                    Dim resPoint As PromptPointResult = ed.GetPoint(optPoint)
                    If resPoint.Status = PromptStatus.OK Then
                        Try
                            alignment.StationOffset(resPoint.Value.X, resPoint.Value.Y, station, offset)
                            ed.WriteMessage(vbCrLf + "Station: " + station.ToString("N2"))
                            ed.WriteMessage(vbCrLf + "Offset: " + offset.ToString("N2"))
                        Catch ex As Autodesk.Civil.PointNotOnEntityException

                        End Try
                        
                    End If
                    RemoveHandler ed.PointMonitor, AddressOf TrackMouse
                    tm.EraseTransient(line, New IntegerCollection)
                    trans.Commit()
                End Using
                line.Dispose()
                line = Nothing
            End If

        End Sub

        Private Sub TrackMouse(sender As Object, e As PointMonitorEventArgs)
            Dim mousePoint As Point3d = e.Context.RawPoint
            Dim pol As Point3d = alignment.GetClosestPointTo(mousePoint, False)
            line.StartPoint = mousePoint
            line.EndPoint = pol
            Try
                alignment.StationOffset(mousePoint.X, mousePoint.Y, station, offset)
                ed.WriteMessage(vbCr + "Station: " + station.ToString("N2") + "  |  Offset: " + offset.ToString("N2"))
            Catch ex As Autodesk.Civil.PointNotOnEntityException

            End Try
            tm.UpdateTransient(line, New IntegerCollection)
        End Sub

    End Class

End Namespace

 

Message 3 of 16

Wittekamp
Contributor
Contributor

Thank you very much! Solved it.

0 Likes
Message 4 of 16

Anonymous
Not applicable

Hello hippe013

 

Thank you very much for your contribution.

 

I made some changes to the code to determine the station and elevation of a point (x, y) in a profile view. But I could not make the line move through the profile when I move the mouse, see figure below.

 

SelectProfilePoint-1.JPG

 

I appreciate if you can help me.

 

Best regards.

 

Mauro Vega

 

AutoCAD Civil 3D 2018.1

Intel Core i7-6700HQ CPU 2.6 GHZ

32 GB RAM 2133 MHz

NVIDIA Quadro M3000M

Windows 10 Pro 64 Bits

0 Likes
Message 5 of 16

Jeff_M
Consultant
Consultant
Use teh x/y that you obtain the station/elev with for the endpoint of the transient line.
Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 6 of 16

Anonymous
Not applicable

Hello Jeff_M,

 

Excuse me please.

 

I do not understand you.

 

Can you give me an example?. Because I have not been able to make the beginning of the line move through the profile, it remains at the beginning.

 

Best regards.

 

Mauro Vega

 

AutoCAD Civil 3D 2018.1

Intel Core i7-6700HQ CPU 2.6 GHZ

32 GB RAM 2133 MHz

NVIDIA Quadro M3000M

Windows 10 Pro 64 Bits

0 Likes
Message 7 of 16

hippe013
Advisor
Advisor

It would help us to help you if you posted your modified code.

0 Likes
Message 8 of 16

Anonymous
Not applicable

Hello hippe013,

 

This is the modified code.

 

    Public aDoc As Document = Application.DocumentManager.MdiActiveDocument
    Public db As Database = aDoc.Database
    Public ed As Editor = aDoc.Editor
    Public line As Line
    Public prof As ProfileView
    Public profile1 As Profile
    Public tm As TransientManager = TransientManager.CurrentTransientManager
    Public station As Double
    Public elevacion As Double

    <CommandMethod("SelectProfilePoint")>
    Public Sub SelectProfilePoint()
        
        Dim optSelect As New PromptEntityOptions(vbCrLf + "Seleccione una vista de perfil")
        optSelect.SetRejectMessage(vbCrLf + "Debe ser una vista de perfil")
        optSelect.AddAllowedClass(GetType(ProfileView), True)

        Dim optSelect2 As New PromptEntityOptions(vbCrLf + "Seleccione un perfil")
        optSelect2.SetRejectMessage(vbCrLf + "Debe ser un perfil")
        optSelect2.AddAllowedClass(GetType(Profile), True)

        Dim res As PromptEntityResult = ed.GetEntity(optSelect)
        Dim res2 As PromptEntityResult = ed.GetEntity(optSelect2)

        If res.Status = PromptStatus.OK And res2.Status = PromptStatus.OK Then

            Using trans As Transaction = db.TransactionManager.StartTransaction
                line = New Line
                line.Color = Autodesk.AutoCAD.Colors.Color.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByAci, 1)
                tm.AddTransient(line, TransientDrawingMode.Main, 128, New IntegerCollection)
                prof = trans.GetObject(res.ObjectId, OpenMode.ForRead)
                profile1 = trans.GetObject(res2.ObjectId, OpenMode.ForRead)
                AddHandler ed.PointMonitor, AddressOf TrackMouse

                Dim optPoint As New PromptPointOptions(vbCrLf + "Seleccione un punto: ")
                Dim resPoint As PromptPointResult = ed.GetPoint(optPoint)

                If resPoint.Status = PromptStatus.OK Then
                    Try
                        prof.FindStationAndElevationAtXY(resPoint.Value.X, resPoint.Value.Y, station, elevacion)
                        ed.WriteMessage(vbCrLf + "Abscisa: " + station.ToString("N2"))
                        ed.WriteMessage(vbCrLf + "Elevación: " + elevacion.ToString("N2"))
                        Dim pendiente As Double
                        pendiente = (profile1.GradeAt(station)) * 100
                        ed.WriteMessage(vbCrLf + "Pendiente: " + pendiente.ToString("N2"))
                    Catch ex As Autodesk.Civil.PointNotOnEntityException

                    End Try

                End If

                RemoveHandler ed.PointMonitor, AddressOf TrackMouse
                tm.EraseTransient(line, New IntegerCollection)
                trans.Commit()
            End Using
            line.Dispose()
            line = Nothing
        End If

    End Sub

    Private Sub TrackMouse(sender As Object, e As PointMonitorEventArgs)
        Dim mousePoint As Point3d = e.Context.RawPoint
        Dim pol As Point3d = prof.GetClosestPointTo(mousePoint, False)
        line.StartPoint = mousePoint
        line.EndPoint = pol
        Try
            prof.FindStationAndElevationAtXY(mousePoint.X, mousePoint.Y, station, elevacion)
            ed.WriteMessage(vbCr + "Abscisa: " + station.ToString("N2") + "  |  Elevación: " + elevacion.ToString("N2"))
        Catch ex As Autodesk.Civil.PointNotOnEntityException

        End Try
        tm.UpdateTransient(line, New IntegerCollection)
    End Sub

Thanks for your help.

 

Best regards.

 

Mauro Vega

 

AutoCAD Civil 3D 2018.1

Intel Core i7-6700HQ CPU 2.6 GHZ

32 GB RAM 2133 MHz

NVIDIA Quadro M3000M

Windows 10 Pro 64 Bits

 

0 Likes
Message 9 of 16

Jeff_M
Consultant
Consultant

This line is not doing what you think it is...

 

Dim pol As Point3d = prof.GetClosestPointTo(mousePoint, False)

 

Remember, the profile is the 3d representation of the alignment, so when you use the getclosestpointto () method, it is doing so along the alignment. What you need to do is get the station/elev x/y from the ProfileView. Here is what I use to get the station in plan or profileview of any alignment or a given profile. It's c# and is a slightly different approach than what @hippe013 used, but hopefully you can see what I did and adapt it.

 

        static void selectProfileStation_PointMonitor(object sender, PointMonitorEventArgs e)
        {
            double sta = Double.NaN, elev = 0;
            Point3d cursorPt3d = e.Context.RawPoint;
            Point2d cursorPt = cursorPt3d.Convert2d(GeometryUtil.PlaneXY);
            double x = Double.NaN, y = Double.NaN;
            Alignment align = m_CurrentProfile.GetAlignment();
            bool lookInPlanView = true;
            string stationString = "";
            Point3d endPt = new Point3d();
            try
            {
                ViewportGeometry geom = e.Context.DrawContext.Geometry;
                foreach (ProfileView view in align.ProfileViews())
                {
                    view.FindStationAndElevationAtXY(cursorPt.X, cursorPt.Y, ref sta, ref elev);
                    var extMin = view.GeometricExtents.MinPoint;
                    var extMax = view.GeometricExtents.MaxPoint;
                    if (cursorPt.X < extMax.X && cursorPt.X > extMin.X && cursorPt.Y < extMax.Y && cursorPt.Y > extMin.Y)
                    {
                        // cursor in profile view
                        if (sta < align.StartingStation)
                            sta = align.StartingStation;
                        else if (sta > align.EndingStation)
                            sta = align.EndingStation;
                        elev = m_CurrentProfile.ElevationAt(sta);
                        view.FindXYAtStationAndElevation(sta, elev, ref x, ref y);
                        endPt = new Point3d(x, y, 0);
                        lookInPlanView = false;
                        break;
                    }
                }

                if (lookInPlanView)
                {
                    // cursor not in profile view
                    try
                    {
                        align.StationOffsetQuux(cursorPt.X, cursorPt.Y, out sta, out elev);
                    }
                    catch
                    {
                        sta = align.ClosestEndpointStationToPoint(cursorPt);
                    }
                    align.PointLocation(sta, 0, ref x, ref y);
                    endPt = new Point3d(x, y, 0);
                }
                Line line = new Line(endPt, cursorPt3d);
                line.ColorIndex = 3;
                geom.Draw(line);
                geom.DrawCircularHighlightGlyph(endPt);
                stationString = align.GetStationStringWithEquations(sta);
                e.AppendToolTipText("\nSelected Station: " + stationString);
            }
            catch { }
        }
Jeff_M, also a frequent Swamper
EESignature
Message 10 of 16

hippe013
Advisor
Advisor

Are you thinking something like this?

 

 

 

 Private Sub TrackMouse(sender As Object, e As PointMonitorEventArgs)
       
            Dim polX As Double
            Dim polY As Double

            Dim mousePoint As Point3d = e.Context.RawPoint


            Try

                prof.FindStationAndElevationAtXY(mousePoint.X, mousePoint.Y, station, elevacion)
                Dim elevOnProfile As Double = profile1.ElevationAt(station)
                prof.FindXYAtStationAndElevation(station, elevOnProfile, polX, polY)
                line.StartPoint = mousePoint
                line.EndPoint = New Point3d(polX, polY, 0)
                ed.WriteMessage(vbCr + "Abscisa: " + station.ToString("N2") + "  |  Elevación: " + elevacion.ToString("N2"))
            Catch ex As Autodesk.Civil.PointNotOnEntityException

            Catch ex As System.ArgumentException

            End Try
            tm.UpdateTransient(line, New IntegerCollection)
        End Sub
Message 11 of 16

Anonymous
Not applicable

Hello @hippe013

 

Thanks for your help.

 

I modified the code as follows:

 

Private Sub TrackMouse(sender As Object, e As PointMonitorEventArgs)

        Dim polX As Double
        Dim polY As Double
        Dim dX As Double
        Dim dY As Double
        Dim elevOnProfile As Double
        Dim mousePoint As Point3d = e.Context.RawPoint

        Try

            prof.FindStationAndElevationAtXY(mousePoint.X, mousePoint.Y, station, elevacion)

            Select Case prof.ElevationRangeMode
                Case ElevationRangeType.Automatic
                    prof.UpgradeOpen()
                    prof.ElevationRangeMode = ElevationRangeType.UserSpecified
                    prof.FindXYAtStationAndElevation(prof.StationStart, prof.ElevationMin, dX, dY)
                    elevOnProfile = prof.ElevationMin
                Case ElevationRangeType.UserSpecified
                    prof.FindXYAtStationAndElevation(prof.StationStart, prof.ElevationMin, dX, dY)
                    elevOnProfile = prof.ElevationMin
            End Select

            'Dim elevOnProfile As Double = profile1.ElevationAt(station)
            prof.FindXYAtStationAndElevation(station, elevOnProfile, polX, polY)
            line.StartPoint = mousePoint
            line.EndPoint = New Point3d(polX, polY, 0)
            ed.WriteMessage(vbCr + "Abscisa: " + station.ToString("N2") + "  |  Elevación: " + elevacion.ToString("N2"))
        Catch ex As Autodesk.Civil.PointNotOnEntityException

        Catch ex As System.ArgumentException

        End Try
        tm.UpdateTransient(line, New IntegerCollection)

    End Sub

The code works if the profile is not split.

 

Is it possible to determine the starting point of each split region ?.

 

Best regards.

 

Mauro Vega

0 Likes
Message 12 of 16

Anonymous
Not applicable

Hello @Jeff_M

 

Thanks for your help.

 

Excuse me please, I do not know the following statements in visual basic .net:

 

"GeometryUtil"
"StationOffsetQuux"
"ClosestEndpointStationToPoint"
"DrawCircularHighlightGlyph"

 

Best regards.

 

Mauro Vega

0 Likes
Message 13 of 16

Jeff_M
Consultant
Consultant

Mauro, those are other tools written in house to perform tasks. You can probably figure out what they do, but I cannot post all of these. I posted the code just to show what we do to get the station of an alignment in either plan or profile. It wasn't meant to be used as is, sorry.

Jeff_M, also a frequent Swamper
EESignature
Message 14 of 16

Anonymous
Not applicable

Hi @Jeff_M

 

Ok, I understand.

 

I appreciate your help. You're very kind.

 

Best regards,

 

Mauro Vega

0 Likes
Message 15 of 16

Kélcyo
Advocate
Advocate

Could you provide a more complete code example? the topic got confusing when mixing alignment and profile samples...

0 Likes
Message 16 of 16

Jeff_M
Consultant
Consultant

@Kélcyo what are you wanting to do? @hippe013 provided VB.NET code that is pretty complete.

Jeff_M, also a frequent Swamper
EESignature