Autolisp: functions/methods to get WGS coordinates and station equation id?!

Autolisp: functions/methods to get WGS coordinates and station equation id?!

Buzz0m
Collaborator Collaborator
1,426 Views
12 Replies
Message 1 of 13

Autolisp: functions/methods to get WGS coordinates and station equation id?!

Buzz0m
Collaborator
Collaborator

Hi,
I just realized that with lisp you can  manipulate and analyse civil3d objects as well (yes, I'm still a discovering the world of coding). This has lead me to trying to develop routines that would replace the need for certain fairly simple dynamo scripts that I have developed.

Know I'm turning to the forums to see if somebody could confirm my suspicion OR hopefully point me in the right direction. What I (atm) need is:

  1. A function/method that would return the station equation ID [SEID] based on a raw station value or something similar. Basically I need to get a string in roughly this format <SEID>+<stationValue> (eg. 364+022.22)
  2. The latitude and longitude values of a XY point.

I have looked in the help documentation, but I haven't been able to locate what I need.
https://help.autodesk.com/view/CIV3D/2024/ENU/

 

Thanks in advance for any help!

0 Likes
Accepted solutions (2)
1,427 Views
12 Replies
Replies (12)
Message 2 of 13

hippe013
Advisor
Advisor

Basically I need to get a string in roughly this format <SEID>+<stationValue> (eg. 364+022.22)

The following two functions convert a real (double) into string in Stationing Format. One for Imperial and one for Metric. 

 

(defun real->sta (x n / pref suff str2)
  (setq	pref (fix (/ x 100.0))
	suff (- x (* 100 pref)))
  (if (<= (atoi (rtos suff 2 0)) 9)
    (setq str2 (strcat "0" (rtos suff 2 n)))
    (setq str2 (rtos suff 2 n))
    )
  (strcat (itoa pref) "+" str2)
  )


(defun real->MetricSta (x n / pref suff str2)
  (setq	pref (fix (/ x 1000.0))
	suff (- x (* 1000 pref)))
  (if (<= (atoi (rtos suff 2 0)) 9)
    (setq str2 (strcat "0" (rtos suff 2 n)))
    (setq str2 (rtos suff 2 n))
    )
  (strcat (itoa pref) "+" str2)
  )

 

Example:

(setq dist 364022.22)
(setq staStr (real->MetricSta dist 2))

!staStr 
"364+022.22"

 

0 Likes
Message 3 of 13

Buzz0m
Collaborator
Collaborator

@hippe013thank you for the code! I am afraid I explained what I need too vaguely.

The station equation system is a fairly complex and cannot be done purely with number manipulation. The station equation ID is more of an address than an actual location indicator. Eg. a location described with station equations as "364+022.22" could really be the raw station value 1220.123. And vice verse the raw station  2220.123 could be the address "365+010.542".

I think I found the appropriate help reference here:
https://help.autodesk.com/view/CIV3D/2024/ENU/?guid=04d3f51d-1907-4be4-4a53-2ee5e451f452

And I developed this to start with:

(defun c:listStationEquations (/ ssAligns )
	(princ "\nSelect Alignment: ")
	(while (not ssAligns )
		(setq ssAligns (ssget ":S" '((0 . "AECC_ALIGNMENT"))))
	)

	;;######## FOR EACH ALIGNMENT SELECTED STARTS
	(setq count (sslength ssAligns))
	(princ (strcat "\nCount of selected alignments is: " (itoa count)))
	(setq i 0)
	(while (< i count)
		(princ "\nStart of while\n")
		(setq align (ssname ssAligns i))
		(setq alignment (vlax-ename->vla-object align)) ; Get the VLA object of the alignment
		(setq alignmentName (vla-get-name alignment)) ; Get the name of the alignment

		(princ (strcat "\nTesting Current alignment: " alignmentName " and item number is " (itoa (+ i 1)) " of " (itoa count) "\n"))
		
		;;Get station equations
		; (getStationEquations align)
		
		(getStaEqs alignment)
		
	)
)


(defun getStaEqs ( alignment / staEqsCollection staEqObj staEqObjRSB randomTestValue)
	(princ "\ndebug1")
	(setq randomTestValue 100)
	; (setq staEqs (vlax-invoke-method alignment 'StationEquations))
	(setq staEqsCollection (vlax-get-property alignment 'StationEquations))
	(princ "\ndebug2")
	; (setq staEqObj (vlax-invoke-method staEqsCollection 'GetStationEquation randomTestValue))
	(setq staEqObj (vlax-get-property staEqsCollection 'GetStationEquation randomTestValue)) 
	(princ (type staEqObj))
	(princ "\ndebug3")
	(setq staEqObjRSB (vlax-get-property staEqObj 'RawStationBack))
	(princ (strcat "\nThe RawStationback for the TestStaEq is: " (rtos staEqObjRSB)))
)

 

I'm having trouble accessing the staEqscollection and the values within. The code above is just a demo/test lisp in which I'm trying to get the syntax right.

0 Likes
Message 4 of 13

Buzz0m
Collaborator
Collaborator

I did some further digging. My efforts seem to be in vain since the vla-objects I'm trying to access with lisp are not givin me the info I need. Or so it seems...

 

In the code I've revised below, when I dump the variable "staEqsCollection" on row 37 this is what I get:

"

; IAeccStationEquations: IAeccStationEquations Interface

; Property values:

; Count (RO) = 2

"

According to the help site there should be much more than just one property!?
https://help.autodesk.com/view/CIV3D/2024/ENU/?guid=2d938b34-f06a-0a7f-2123-3a2c460c7b90

 

Is there some reason why I can't access the methods and properties with lisp? And why is the "Count" property exposed but not "Item"?

 

(defun c:listStationEquations (/ ssAligns count i align alignment alignmentName)
	(princ "\nSelect Alignment: ")
	(while (not ssAligns )
		(setq ssAligns (ssget ":S" '((0 . "AECC_ALIGNMENT"))))
	)

	;;######## FOR EACH ALIGNMENT SELECTED STARTS
	(setq count (sslength ssAligns))
	(princ (strcat "\nCount of selected alignments is: " (itoa count)))
	(setq i 0)
	(while (< i count)
		(princ "\nStart of while\n")
		(setq align (ssname ssAligns i))
		(setq alignment (vlax-ename->vla-object align)) ; Get the VLA object of the alignment
		(setq alignmentName (vla-get-name alignment)) ; Get the name of the alignment

		(princ (strcat "\nTesting Current alignment: " alignmentName " and item number is " (itoa (+ i 1)) " of " (itoa count) "\n"))
		
		;;Get station equations
		; (getStationEquations align)
		
		(getStaEqs alignment)
		
	)
)


(defun getStaEqs ( alignment / staEqsCollection staEqObj nOfStaEqs staEqObjRSB randomTestValue)
	(princ "\ndebug1")
	(setq randomTestValue 100)
	(setq staEqsCollection (vlax-get-property alignment 'StationEquations))
	(princ "\ndebug2")
	
	(setq nOfStaEqs (vlax-get-property staEqsCollection 'Count))
	(princ "\ndebug20") 
	(princ (strcat "\nNum of staEqs: " (itoa nOfStaEqs)))
  (vlax-dump-object staEqsCollection) ;the properties and methods exposed do not match the help file?!
	(setq staEqObjFirst (vlax-get-property staEqsCollection 'Item 0))
	
	;(setq staEqObj (vlax-get-property staEqsCollection 'GetStationEquation randomTestValue)) 
  (setq staEqObj (vlax-invoke-method staEqsCollection 'GetStationEquation randomTestValue))
	
  ; (princ (strcat "\ntype of staEqObj: " (type staEqObj)))
	; (princ (type staEqObj))
	(princ "\ndebug3")
	(setq staEqObjRSB (vlax-get-property staEqObj 'RawStationBack))
	(princ (strcat "\nThe RawStationback for the TestStaEq is: " (rtos staEqObjRSB)))
)

 

 

 

 

0 Likes
Message 5 of 13

hippe013
Advisor
Advisor

The station equation system is a fairly complex and cannot be done purely with number manipulation. The station equation ID is more of an address than an actual location indicator.

 

No. It's not. Stations are simply distances along an alignment. A Station Equation simply resets the distance to a specified value for when it is joined with another alignment that they can share the same stationing. To obtain the station equations is rather simple. 

 

;Get the Alignment
(setq align (vlax-ename->vla-object (car (entsel "\nSelect Alignment: "))))

;Get the Station Equations Collection
(setq staEqs (vlax-get-property align 'StationEquations))

;Get a Station Equation, here I am just grabbing the first one (zero index). 
(setq staEq (vla-item staEqs 0))

 

0 Likes
Message 6 of 13

Buzz0m
Collaborator
Collaborator

Thank you for the code samples! I'll give them a go straight away! Do you @hippe013 know why the "dump" I described does not offer the same methods and properties that are described in the help?

When I described station equations as complex might that might have been an overstatement. I don't want to make this an argument about what they are and how they are used. I will however describe how the station equations are used in the market I work in to give some reference to what I am trying to achieve: In my case the station equations are used in a rail system design case. As such the rail equation "0"-station is bound to a static point which is a physical survey point. I am by no means a rail traffic system designer and I might be wrong, but the reason for using station equations is that if there is a change in the very long and old railway alignments the stationing will stay roughly the same even though the raw station has significantly changed.

What I am trying to access is the value in the "Equation" and "Raw station back" in the picture below.

Buzz0m_0-1713160038606.png

 


 

0 Likes
Message 7 of 13

Buzz0m
Collaborator
Collaborator

For anyone looking for the XY<->LatLong (WGS) conversion I used the solution below. I relied heavily upon the "photos.lsp", which I found here:
https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/using-autolisp-visual-lisp-to-geo-lo...

(defun LL->PT (LL / e ev return)
  (if (and LL
           (setq e (GeoMarker)))
    (progn
      (setq ev (vlax-ename->vla-object e))
      (vlax-put-property ev 'Longitude (rtos (car LL) 2 7))
      (vlax-put-property ev 'Latitude (rtos (cadr LL) 2 7))
      (setq return
        (list
          (getpropertyvalue e "Position/X")
          (getpropertyvalue e "Position/Y")
          0.0
        );list
      );setq
      (entdel e)
      return
    );progn
  );if
);defun

(defun PT->LL (3dpoint / e ev return)
  (if (and 3dpoint
           (setq e (GeoMarker)))
    (progn
      (setq ev (vlax-ename->vla-object e))
      (vlax-put-property ev 'Position 3dpoint)
       (setq return
        (list
          (vlax-get-property ev 'Latitude )
          (vlax-get-property ev 'Longitude)
          
        );list
      );setq
      (entdel e)
      return
    );progn
  );if
);defun

;This is needed to create a geomarker for XY-> LatLong transformation
(defun GeoMarker ( / )
  (entmakex '((0 . "POSITIONMARKER") (100 . "AcDbEntity") (100 . "AcDbGeoPositionMarker") (90 . 0) (10 0.0 0.0 0.0) (40 . 1.0)
             (1 . "") (40 . 0.5) (290 . 0) (280 . 0) (290 . 1) (101 . "Embedded Object") (100 . "AcDbEntity") (100 . "AcDbMText")
             (10 0.1 0.1 0.0) (40 . 1.0) (1 . "") (210 0.0 0.0 1.0) (11 1.0 0.0 0.0) (42 . 9761.9) (43 . 6666.67)))
);defun

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/using-autolisp-visual-lisp-to-geo-lo... 

Message 8 of 13

hippe013
Advisor
Advisor
Accepted solution

@Buzz0m wrote:

Do you @hippe013 know why the "dump" I described does not offer the same methods and properties that are described in the help?


 

The help file that you were looking at references the .NET API. While in LISP we are working with the COM API. 

;Get the Alignment
(setq align (vlax-ename->vla-object (car (entsel "\nSelect Alignment: "))))

;Get the Station Equations Collections
(setq staEqs (vlax-get-property align 'StationEquations))

;Review the Available Properties & Methods of the Station Equation Collection
(vlax-dump-object staEqs T)

; IAeccStationEquations: IAeccStationEquations Interface
; Property values:
;   Count (RO) = 2
; Methods supported:
;   Add (4)
;   Item (1)
;   Remove (1)

;Get the Station Equation by Collection Index
(setq staEq (vlax-invoke-method staEqs 'Item 0))

;Review the available Properties & Methods of the Station Equation
(vlax-dump-object staEq T)

; IAeccStationEquation: IAeccStationEquation Interface
; Property values:
;   RawStationBack = 235.098
;   StationAhead = 0.0
;   StationBack (RO) = 235.098
;   Type = 1
; No methods

;Station Equation Type
;aeccDescreasing = 2
;aeccIncreasing = 1

 

As you can see in the above example code there isn't any property for the "Equation" column of the dialog box that you posted. Even when we look at the .NET API there isn't a property for the "Equation" column. There isn't even a property for the "Comment" column. 

 

hippe013_0-1713188876661.png

It's worth noting the difference in the Enum values between the COM and .NET APIs. In the .NET API the decreasing / increasing values of StationEquationType is a value of 0 and 1 respectively, while in the COM API it is 2 and 1 respectively. 

Message 9 of 13

Buzz0m
Collaborator
Collaborator

Thank you @hippe013 for your patience with me and my newb questions! 😃

I tried scanning the lisp section in the Help site (Autolisp developer section among other) without finding a list of object specific methods and properties that are applicable for lisp or the COM api specifically.  What am I still misunderstanding!?
where in the help file should I have been able to see that the stationequations object has the property "Count (RO)" exposed but not the "GetStationEquation" method?

Where would I look for the COM api help references?
Btw why does the help file mention "item" as a property but the dump lists it as a method?


StationEquationCollection Class:

https://help.autodesk.com/view/CIV3D/2024/ENU/?guid=2d938b34-f06a-0a7f-2123-3a2c460c7b90

0 Likes
Message 10 of 13

hippe013
Advisor
Advisor

Oh, the joys of programming! 

 

Here is a link for some information about the different APIs. 

Autodesk Civil 3D Help | Autodesk Civil 3D APIs | Autodesk

 

Where would I look for the COM api help references?

 

Here is a link for more information on the COM API. It is a developer's guide and not so much a reference. 

Autodesk Civil 3D Help | Legacy COM API | Autodesk

 

Btw why does the help file mention "item" as a property but the dump lists it as a method?

 

Again, you are referring to the .NET object where "Item" is a property. In the COM API it is a method. In either API they do the same thing. They return a StationEquation object from the collection. 

The GetStationEquation method is from the .NET API and is not available in the COM API. 

 

Think of it this way. COM was the old API and then they started with the new .NET API. Some things are not exposed in the .NET API and some things are not exposed in the COM API. If you wish to program using the C# or VB languages, you can use both APIs. 

 

From the help file:

This section of the Developer's Guide contains chapters covering the legacy COM API. Where possible, the newer .NET API should be used for performance reasons. However, the .NET API does not cover all Civil 3D functionality, and you may want to use features that are only available in COM. You can access the COM API using interop - see Limitations and Using Interop.

 

I hope that this helps clarify any confusion between the two APIs. Being that you are coding in LISP you are left with using the COM API unless you want to create your own custom Lisp Functions, but that is a whole different topic. 

 

 

 

 

 

 

Message 11 of 13

Jeff_M
Consultant
Consultant

@hippe013 @Buzz0m Here is a link to the Civil 3D 2012 COM API Reference...yes, 2012 is, AFAIK, the last update for the COM API reference

Jeff_M, also a frequent Swamper
EESignature
Message 12 of 13

CodeDing
Advisor
Advisor
Accepted solution

@Buzz0m ,

The functions from the PHOTOS command are generic so that the command will work even on vanilla AutoCAD. In Map & Civil 3D we can use the (ade_ ...) functions so that we don't unnecessarily need to add a geo-marker to model space:

;; Turns a point into (long lat) point ..ONLY useable if dwg is Geo-Located.
;; pt - point, 
;; returns - point, as (Long Lat) ...since longitudes represent "x" values & Latitudes represent "y" values
(defun PT->LL (pt / )
  (ade_projsetsrc (getvar 'CGEOCS))
  (ade_projsetdest "LL84")
  (if pt
    (reverse (cdr (reverse (ade_projptforward pt))))
  );if
);defun

;; Turns many points into (long lat) points ..ONLY useable if dwg is Geo-Located.
;; pts - list, of points 
;; returns - list, as ((Long Lat) ...) ...since longitudes represent "x" values & Latitudes represent "y" values
(defun PTs->LLs (pts / )
  (ade_projsetsrc (getvar 'CGEOCS))
  (ade_projsetdest "LL84")
  (if pts
    (mapcar 'reverse
      (mapcar 'cdr
        (mapcar 'reverse
          (mapcar 'ade_projptforward pts)
        );mapcar
      );mapcar
    );mapcar
  );if
);defun

;; Turns a (long lat) into coordinates ..ONLY useable if dwg is Geo-Located.
;; pt - point as (long lat), 
;; returns - point, as (X Y) ...since longitudes represent "x" values & Latitudes represent "y" values
(defun LL->PT (LL / )
  (ade_projsetsrc (getvar 'CGEOCS))
  (ade_projsetdest "LL84")
  (if LL
    (reverse (cdr (reverse (ade_projptbackward LL))))
  );if
);defun

;; Turns a list of (longs lats) into coordinates ..ONLY useable if dwg is Geo-Located.
;; LLs - list, of points as ((long lat) (long lat) ...) 
;; returns - list of points, as ((X Y) (X Y) ...) since longitudes represent "x" values & Latitudes represent "y" values
(defun LLs->PTs (LLs / )
  (ade_projsetsrc (getvar 'CGEOCS))
  (ade_projsetdest "LL84")
  (if LLs
    (mapcar 'reverse
      (mapcar 'cdr
        (mapcar 'reverse
          (mapcar 'ade_projptbackward LLs)
        );mapcar
      );mapcar
    );mapcar
  );if
);defun

 

ADE Functions Reference:

https://documentation.help/AutoCAD-Map-3D-2009-AutoLISP/documentation.pdf 

 

[thanks for the plug to my post though 😎]

Best,

Message 13 of 13

Buzz0m
Collaborator
Collaborator

Once again, thank you @hippe013 @CodeDing and @Jeff_M for guiding/helping me!

Solution:
CodeDing's last post is the solution for the coordinate transformation
hippe013 confirms that with lisp the station equation id can not be accessed (it can't be reached with basic dynamo either so I'm assuming it is not exposed in the APIs at all).