Access to Civil 3D Objects via Object DBX?

Access to Civil 3D Objects via Object DBX?

CodeDing
Advisor Advisor
1,063 Views
4 Replies
Message 1 of 5

Access to Civil 3D Objects via Object DBX?

CodeDing
Advisor
Advisor

Hey all,

 

Anyone know of a way (or if it's even possible) to access Civil 3D objects (specifically TIN Surfaces) via Object DBX? (So I do not have to open the DWG file)

 

I know we can get the IAxDbDocument like this, but it does not give access to C3D objects:

(setq acadDBX (vlax-create-object (strcat "ObjectDBX.AxDbDocument." (substr (getvar 'acadver) 1 2))))
(vla-open acadDBX "C:\\users\\me\\test.dwg")
(vlax-dump-object acadDBX t)
(vlax-release-object acadDBX)

 

; IAxDbDocument: IAxDbDocument Interface
; Property values:
;   Application (RO) = Class not registered
;   Blocks (RO) = #<VLA-OBJECT IAcadBlocks 0000021fdf99bec8>
;   Database (RO) = #<VLA-OBJECT IAcadDatabase 0000021ff4ae8428>
;   Dictionaries (RO) = #<VLA-OBJECT IAcadDictionaries 0000021fdf99c198>
;   DimStyles (RO) = #<VLA-OBJECT IAcadDimStyles 0000021fdf99bf58>
;   ElevationModelSpace = 0.0
;   ElevationPaperSpace = 0.0
;   Groups (RO) = #<VLA-OBJECT IAcadGroups 0000021fdf99bfe8>
;   Layers (RO) = #<VLA-OBJECT IAcadLayers 0000021fdf99c468>
;   Layouts (RO) = #<VLA-OBJECT IAcadLayouts 0000021fdf99b388>
;   Limits = (0.0 0.0 12.0 9.0)
;   Linetypes (RO) = #<VLA-OBJECT IAcadLineTypes 0000021fdf99b9b8>
;   Materials (RO) = #<VLA-OBJECT IAcadMaterials 0000021fdf99a218>
;   ModelSpace (RO) = #<VLA-OBJECT IAcadModelSpace 0000021fb21d1e68>
;   Name = "C:\\users\\me\\test.dwg"
;   PaperSpace (RO) = #<VLA-OBJECT IAcadPaperSpace 0000021fb21d20e8>
;   PlotConfigurations (RO) = #<VLA-OBJECT IAcadPlotConfigurations 0000021fdf99bad8>
;   Preferences (RO) = #<VLA-OBJECT IAcadDatabasePreferences 0000021fe51624e8>
;   RegisteredApplications (RO) = #<VLA-OBJECT IAcadRegisteredApplications 0000021fdf99a578>
;   SectionManager (RO) = Exception occurred
;   SummaryInfo (RO) = #<VLA-OBJECT IAcadSummaryInfo 0000021ff4ae7ed8>
;   TextStyles (RO) = #<VLA-OBJECT IAcadTextStyles 0000021fdf99b028>
;   UserCoordinateSystems (RO) = #<VLA-OBJECT IAcadUCSs 0000021fdf99b0b8>
;   Viewports (RO) = #<VLA-OBJECT IAcadViewports 0000021fdf99b148>
;   Views (RO) = #<VLA-OBJECT IAcadViews 0000021fdf99b4a8>
; Methods supported:
;   CopyObjects (3)
;   DxfIn (2)
;   DxfOut (3)
;   HandleToObject (1)
;   ObjectIdToObject (1)
;   Open (2)
;   Save ()
;   SaveAs (2)

 

Any help is appreciated!

Best,

~DD

0 Likes
Accepted solutions (2)
1,064 Views
4 Replies
Replies (4)
Message 2 of 5

BlackBox_
Advisor
Advisor
Accepted solution

In your DBX document, what happens if you iterate the ModelSpace block entities, filtering for the desired ObjectName(s)?


"How we think determines what we do, and what we do determines what we get."

Sincpac C3D ~ Autodesk Exchange Apps

Message 3 of 5

Jeff_M
Consultant
Consultant

@CodeDing it has been 15, or so, years since I attempted this. I am not seeing anything in my old lisp code snips suggesting that I ever succeeded. This may be due to that was about when I started mingling heavily into the .NET API and found it is very easy to access the C3D objects in an external database.

Jeff_M, also a frequent Swamper
EESignature
Message 4 of 5

CodeDing
Advisor
Advisor

Yeah, turns out the surface objects exist and can be accessed via model space 🤕

0 Likes
Message 5 of 5

CodeDing
Advisor
Advisor
Accepted solution

For any future wanderers,

 

My goal was to extract the Latitudes and Longitudes of any existing surfaces in some external drawings.

That can be quite a nuisance because you need to be sure a coordinate system is assigned within the source drawing (hopefully whoever assigned it made sure it was the right one and scaled if necessary).

 

This code opens a DBX document, ensures that is has a coordinate system, retrieves the coordinate system ID, gets the borders of all surfaces (sometimes surface can have multiple borders), then attempts to turn the border coordinates into Latitudes/Longitudes (this is only possible if you have the coordinate system id in your current coordinate system database file (.cs file)).

 

Best of luck, it's not the cleanest code, but it gets it done.

 

EDIT:

FYI, the (alx-parse-xml2lisp ...) function is from some custom functions [ALx Functions] I made a while back:

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/autolisp-extended-alx-functions/m-p/... 

...it parses XML to Lisp, so I can retrieve items easier; HOWEVER, I have not created a new version for AutoCAD 2025+ yet. So ALX functions currently do not work with 2025+

 

;; Gets surface borders of all surfaces in doc
;; doc - vla-obj, the DBX document
;; returns - list, of all surfaces and borders in x/y, like:
;; (
;;   ("Surface1"
;;     ((<x> <y>) (<x> <y>) ...)
;;     ((<x> <y>) (<x> <y>) ...)
;;     ...
;;   )
;;   ("Surface2"
;;     ((<x> <y>) (<x> <y>) ...)
;;     ((<x> <y>) (<x> <y>) ...)
;;     ...
;;   )
;; )
(defun GetSurfaces (doc / ms cnt n surfs borders return)
  (setq ms (vlax-get doc 'ModelSpace))
  (if (and (not (zerop (setq cnt (vlax-get ms 'Count))))
           (progn (setq n -1)
                  (repeat cnt
                    (if (eq "AeccDbSurfaceTin" (vlax-get (setq item (vlax-invoke ms 'Item (setq n (1+ n)))) 'ObjectName))
                      (setq surfs (cons item surfs))
                    );if
                    surfs
                  );repeat
           );progn
      );and
    (progn
      (foreach surf surfs
        (setq borders (vlax-invoke surf 'ExtractBorder 1))
        (setq return
          (cons
            (cons (vlax-get surf 'Name)
                  (mapcar
                    '(lambda (b / coords coordList)
                      (setq coords (vlax-get b 'Coordinates))
                      (while coords
                        (setq coordList
                          (cons (list (car coords) (cadr coords)) coordList)
                        );setq
                        (setq coords (cdddr coords))
                      );while
                      (reverse coordList)
                    );lambda
                    borders
                  );mapcar
            );cons
            return
          );cons
        );setq
      );foreach
      return
    );progn
  );if
);defun

;; Ensures DBX doc has coordinate system, retrieves name if so
;; doc - vla-obj, DBX document
;; returns - string, of coordinate system ID
(defun GetCoordSys (doc / ms ed geoData MultiAssoc xml csData)
  (setq ms (vlax-get doc 'ModelSpace))
  (setq ed (vlax-invoke ms 'GetExtensionDictionary))
  (if (not
        (vl-catch-all-error-p
          (setq geoData
            (vl-catch-all-apply 'vlax-invoke (list ed 'GetObject "ACAD_GEOGRAPHICDATA"))
          )
        )
      )
    (progn
      (setq MultiAssoc (lambda (k l / i) (if (setq i (assoc k l)) (cons (cdr i) (MultiAssoc k (cdr (member i l)))))))
      (setq geoData (entget (vlax-vla-object->ename geoData)))
      (setq xml (strcat (apply 'strcat (MultiAssoc 303 geoData)) (cdr (assoc 301 (reverse geoData)))))
      (setq csData (alx-parse-xml2lisp xml))
      (cdr (assoc "Name" (cdr (assoc "ProjectedCoordinateSystem" (cdr (assoc "Dictionary" csData))))))
    );progn
  );if
);defun

;; MAIN FUNCTION
;; Retrieves Border from all TIN surfaces inside provided dwg file
;; filename - string, of full file path
;; returns - list, of all boundaries in lat/long (surfaces can have multiple), like:
;; (
;;   ("Surface1"
;;     ((<lon> <lat>) (<lon> <lat>) ...)
;;     ((<lon> <lat>) (<lon> <lat>) ...)
;;     ...
;;   )
;;   ("Surface2"
;;     ((<lon> <lat>) (<lon> <lat>) ...)
;;     ((<lon> <lat>) (<lon> <lat>) ...)
;;     ...
;;   )
;; )
(defun GetSurfBndyLatLonFromClosedDWG (filePath / ReleaseDBX doc cs)
  (defun ReleaseDBX ( / )
    (if doc (vlax-release-object doc))
  )
  ;; check exists
  (if (null (setq filePath (findfile filePath)))
    (progn (prompt (strcat "\nerror: bad filePath: " filePath)) (exit))
  );if
  ;; open dbx doc
  (setq doc (vlax-create-object (strcat "ObjectDBX.AxDbDocument." (substr (getvar 'acadver) 1 2))))
  (vla-open doc filePath)
  ;; ensure coordinate system for lat/longs
  (if (null (setq cs (GetCoordSys doc)))
    (progn
      (prompt (strcat "\nerror: no Coordinate System assigned within doc: " filePath))
      (ReleaseDBX)
      (exit)
    );progn
  );if
  ;; ensure surfaces exist
  (if (null (setq surfaces (GetSurfaces doc)))
    (progn
      (prompt (strcat "\nerror: no TIN surfaces within doc: " filePath))
      (ReleaseDBX)
      (exit)
    );progn
  );if
  (ReleaseDBX)
  ;; try to convert to lat/longs
  (if (and (ade_projsetsrc cs) (ade_projsetdest "LL84"))
    (progn
      (mapcar
       '(lambda (s / )
          (cons (car s)
            (mapcar
             '(lambda (b / )
                (mapcar 'ade_projptforward b)
              );lambda
              (cdr s)
            );mapcar
          );cons
        );lambda
        surfaces
      );mapcar
    );progn
  ;else
    (prompt (strcat "\nerror: current Coordinate System database does not contain: " cs))
  );if
);defun

Best,

~DD

0 Likes