I can't seem to access the profile information i need. I need a routine to insert a block with an attribute in plan view along a centerline alignment displaying the profile elevation for that station along that alignment.
LISP if possible (may wish to modify for own needs in future). Willing to pay a little if working appropriately (using C3d 2011).
Thanks a mill for anyone kind enough to help!
Solved! Go to Solution.
Solved by Jeff_M. Go to Solution.
Solved by brianchapmandesign. Go to Solution.
Sounds like you could do that with station labels. You could create a style that has a block and will desplay profile information of an attached profile. Then in the alignment labels dialog, set it to places at a set interval.
The alignment labels already have this built in. There are two things that you could do:
1. Use the profile geometry point labels. These will label profile points in plan for the vertical curves
2. Use the "reference text" option in any of the other labels to add information about a profile in the label
I don't think there is any need for custom programming. (in addition, LISP is not the best choice of programming languages for Civil 3D).
Cheers,
Peter Funk
Autodesk, Inc.
TGood point. All I really need is the ability to extract the coordinate of the origin point/insertion point of the label with the expression / reference, and the ability to extract the elevation so I can use them (this is important for quick grading, checks, etc.)
With blocks I'd do this via entget, etc, but not sure how to access the same info with styles. Anyone know?
THANKS!!!!
Hey Jeff,
I ya... I need the elevation string for use in other code I already have in place. The coordinate of the insertion point for the label, also for use in other code.
Fake lisp sample:
(setq something (* somenumberichoose elevationfromlabelwithexpression))
(setq somethingelse (getdist coordinatefromstylewithexpression to someotherpointipick))
etc...
man you work late... sign of times ?
If you are just looking to label the alignment with profile information then you should really look at the label styles are thare built into Civil 3D. If you are looking to do more than just label the alignment, then you should really look at something other than lisp to work in. The information that you are looking for is not stored in the dxf codes (entget) so LISP on its on is out.
If you really want to work with the Civil 3D data, I would suggest getting a copy of Microsoft VB.NET Express Edition (free download) and start working in VB.NET. Every bit of our API development work is on the .NET API. We do little with COM and nothing with LISP.
While you can do some great things with LISP it really is a non starter for Civil 3D.
Peter Funk
Autodesk, Inc.
Thanks Pete... that's what I needed to know... I was beatin' my head against the wall trying to figure out why I couldn't simply get the elevation and insertion point.
Thanks!
If you must use lisp to deal with existing lisp libraries like I have had to, this pretty much works. Insert real symbols for anything in <> as they are just descriptions.
(vlax-invoke-method (list <alignment-object> "StationOffset" ptx pty 'sta 'off))
(setq elev (vlax-invoke-method (list <profile-object> "ElevationAt" sta)))
get your alignment object and profile object how you would normally get a vla-object (easiest way is vlax-ename->vla-object)
But the best way for future proofing as Peter has mentioned, if its possible in your system, is to make a lisp-function in .net and set your input/output resbuffs as you require.
While this will work for any properties that are exposed to COM, we stopped writting the COM API a few releases ago so the access you'll have will be limited. All the new APIs are written in .NET.
Cheers,
Peter Funk
Autodesk, Inc.
Thanks... should head me in the direction I wanted to go. Thanks for the help! RE:.Net... I'll see... maybe someday. Unfortunately, it seems to me, there are no resources available for beginners wanting to learn .NET specifically for civil 3d. Everything I've seen, one has to have a decent understanding of .NET already.
@bcinnv wrote:
...., there are no resources available for beginners wanting to learn .NET specifically for civil 3d. Everything I've seen, one has to have a decent understanding of .NET already.
Resources to jump start the learning process:
http://www.quuxsoft.com/SincpacC3D_source.aspx (uses C# and is for use with C3D)
http://blog.civil3dreminders.com/2010/05/sincpac-c3d-source-code.html (Christopher preferes VB.NET)
This forum, ask questions!
For Autocad specific .NET: http://forums.autodesk.com/t5/NET/bd-p/152
Some real nice & helpful folks can be found at www.theswamp.org where there are .NET specific and "Land Lubber" forums.
And I am living proof you don't have to have a decent understanding of .NET already. 4 years ago I knew absolutely nothing about it. Now I know enough to not get so confused ... but I can write some meaningful and very powerful commands now that I couldn't even dream of doing in lisp (I came from lisp myself). I chose to go the C# route, as it is easier for me to look at vs the VB code, although they are similar enough you should get to the point that you can at least figure out what each is doing regardless of the one you choose to learn.
Thanks Jeff! I hope to get a grip on it soon.
With the info provided earlier, and some code from a generous unknown author on http://cadpanacea.com I mixed up the following to snag the profile / alignment info I needed... it's pretty messy (as I just cut / paisted info I needed)... but its works with 2008 C3d...have to wait 'til tomorrow to test on 11 at work.
(defun c:test ()
(vl-load-com)
(setq sel (entsel "\nSelect Alignment: "))
(setq sel2 (entsel "\nSelect Profile: "))
(setq ent (car sel))
(setq lst (entget ent))
(if (eq "AECC_ALIGNMENT" (cdr (assoc 0 lst)))
(setq obj (vlax-ename->vla-object ent)))
(setq ent2 (car sel2))
(setq lst2 (entget ent2))
(setq obj2 (vlax-ename->vla-object ent2))
(if obj
(progn
(setq nam (vlax-get-property obj 'Name))
(setq sta1 (vlax-get-property obj 'StartingStation))
(setq sta2 (vlax-get-property obj 'EndingStation))
(setq sta 100.0 off 10.0)
(vlax-invoke-method obj 'PointLocation sta off 'x 'y)
(entmake (list (cons 0 "POINT")(cons 10 (list x y))))
(setq pt1 (getpoint "\nSelect point: "))
(vlax-invoke-method obj 'StationOffset (car pt1) (cadr pt1) 'sta 'off)
(setq elev (vlax-invoke-method obj2 "ElevationAt" sta))
(alert (strcat
"The Elevation is "
(rtos elev 2 2)
"\nThe Station is "
(rtos sta 2 2)
"\nThe Offset is "
(rtos off 2 2)))
)
)
(princ));;;
There are two other sources for information that you may want to look into when the .Net day comes for you. For example, Autodesk now has a Civil 3D API blog.
http://civilizeddevelopment.typepad.com/
Although currently it may be a bit much to follow for the beginner I would definitely bookmark this for future reference.
Also, there have been quite a few basic tutorial posts made at http://civil3d.com
Check out:
http://www.civil3d.com/category/civil3dcom/api/
http://www.civil3d.com/category/civil3dcom/programming/
In fact, there is a five part series showing how to get started there. The posts are as follows:
http://www.civil3d.com/2009/04/working-with-civil3d-2010-managed-net-api-101-1/
http://www.civil3d.com/2009/04/working-with-civil3d-2010-managed-net-api-101-2/
http://www.civil3d.com/2009/04/working-with-civil3d-2010-managed-net-api-101-3/
http://www.civil3d.com/2009/04/working-with-civil3d-2010-managed-net-api-101-4/
http://www.civil3d.com/2009/05/working-with-civil3d-2010-managed-net-api-101-5/
HTH
So I took your guys advice and dove into vb.net. It's not that difficult, for very basic stuff, such as "Hello World", and make a layer. But I'm finding it incredibaly complicated to come up with the station for an alignment via a point I pick on screen, and the profile elevation associated with it. Could you guys toss me a bone?
If you are able to get the alignment object and get the user picked point, then you can use the following method.
Dim sta As Double Dim offs As Double align.StationOffset(pickedPoint.X, pickedPoint.Y, Sta, offs)
The pickedPoint is what the user picked (a Point3D or Point2D object depending upon your needs).
The align object is the alignment object that you have gotten.
What is returned is through a referenced parameter (which is kind of weird way to work this but...). Thus the variable sta will contain the double representing the station of the picked point.
If you need help getting the alignment object or the picked point, just let us know.
--Disclaimer--
This obviously does not account for any adjustments to the northing/easting... 🙂
That's incredible... how easy you make that look. I have been way off track, and sadly yes, need help getting the point, and alignment. Believe for point it would be:
Dim pt As Object
pt = AcadDoc.Utility.GetPoint(, "Pick point:")
correct? Which would change "pickedPoint" in your code to pt.x, and pt.y?
Probably way off, but you won't believe how far off I've been.
Don't know how to get alignment.
I have a working example, but it's written in C#. I'm not sure it would help or confuse you even more. Before I post it, have you gone through any of the .NET Labs or ObjectARX dotnet code samples? Knowing how to work with Autocad documents, objects, etc., is extremely important to being able to use the Civil3D API's.
You can use a C# to VB.NET converter that should do a decent job of getting this into something you can use. Here's one: http://www.developerfusion.com/tools/convert/csharp-to-vb/
using System; using System.Collections.Generic; using System.Text; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using Autodesk.Civil.ApplicationServices; using Autodesk.Civil.Land.DatabaseServices; namespace API_Test { public class GetStaOffElev { [CommandMethod("GetStaOffElev")] public void getstaoffelevcommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; CivilDocument civdoc = CivilApplication.ActiveDocument; Editor ed = doc.Editor; Alignment alignment = null; Profile profile = null; using (Transaction tr = db.TransactionManager.StartTransaction()) { if (!getalignment(tr, ed, ref alignment)) return; if (!getprofile(tr, ed, ref profile, alignment)) return; Point3d pt = getpoint(ed); if (pt.X == 0 && pt.Y == 0) return; double station = -999999; double offset = -999999; double elev = -999999; try { alignment.StationOffset(pt.X, pt.Y, ref station, ref offset); } catch { ed.WriteMessage("\nSelected point not adjacent to alignment."); return; } try { elev = profile.ElevationAt(station); } catch { ed.WriteMessage("\nSelected Point not found along chosen profile."); } ed.WriteMessage("\nStation: {0} \nOffset: {1} \nProfile Elevation: {2}", new object[]{station.ToString("0+00.00"), offset.ToString("0.00"), elev.ToString("0.00")}); tr.Commit(); } } private Point3d getpoint(Editor ed) { Point3d pt = new Point3d(); PromptPointOptions pOpts = new PromptPointOptions("\nPick point to query for Station, Offset and Elevation: "); PromptPointResult ptRes = ed.GetPoint(pOpts); if (ptRes.Status == PromptStatus.OK) pt = ptRes.Value; return pt; } private bool getalignment(Transaction tr, Editor ed, ref Alignment alignment) { PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect alignment or [T]ype name: "); //entOpts.Keywords.Add("Type"); //uncomment once code updated to allow entering the name entOpts.AppendKeywordsToMessage = false; entOpts.SetRejectMessage("...not an Alignment, try again."); entOpts.AddAllowedClass(typeof(Alignment),true); PromptEntityResult alignRes = ed.GetEntity(entOpts); if (!(alignRes.Status == PromptStatus.Keyword || alignRes.Status == PromptStatus.OK)) return false; switch (alignRes.Status) { case PromptStatus.Keyword: { alignment = getalignbyname(); if (alignment == null) return false; break; } case PromptStatus.OK: { alignment = (Alignment)tr.GetObject(alignRes.ObjectId, OpenMode.ForRead); break; } } if (alignment != null) return true; else return false; } private Alignment getalignbyname() { //TO DO: Implement this throw new NotImplementedException(); } private bool getprofile(Transaction tr, Editor ed, ref Profile profile, Alignment alignment) { PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect Profile or [T]ype name: "); //entOpts.Keywords.Add("Type"); //uncomment once code updated to allow entering the name entOpts.AppendKeywordsToMessage = false; entOpts.SetRejectMessage("...not a Profile, try again."); entOpts.AddAllowedClass(typeof(Profile),true); PromptEntityResult profRes = ed.GetEntity(entOpts); if (!(profRes.Status == PromptStatus.Keyword || profRes.Status == PromptStatus.OK)) return false; switch (profRes.Status) { case PromptStatus.Keyword: { profile = getprofilebyname(); if (profile == null) return false; break; } case PromptStatus.OK: { profile = (Profile)tr.GetObject(profRes.ObjectId, OpenMode.ForRead); break; } } if (profile != null) return true; else return false; } private Profile getprofilebyname() { //TO DO: Implement this throw new NotImplementedException(); } } }
That's a negative. I can't seem to get past the "Hello World" and making layers, both of which, so far, I'd prefer to do in Autolisp (though running the .dll seems lightning fast). I look at the materails you guys posted but it's too far. Should I start with objectarx? Not sure where to go next.
My primary objective for even trying to pick up .net is simply to find or create a routine to list the station for the selected point, and the elevation of the profile associated with it, as noted, only because I'm afraid the vlisp solution I came up with might eventually become obsolete, or eventually not work (if it doesn't already).
Any help, direction, is extremely appreciated!
THANKS!