Hello,
I started this post within the generic AutoCAD forum but as suggested I have moved it here (old thread here).
What I want to do is create a command whereby the user would click a block, and it would search for a polyline within a given area and then draw a new 3D polyline between the block insertion point and the perpendicular point of the existing polyline.
I've attached a very basic before/after which also hopefully demonstrates what I'm talking about.
To explain further, my block will have a z level of 0 and be placed adjacent to 'Polyline A' which will have a varying z level. So the command would need to first search for Polyline A within a pre-determined area, before drawing a new 3D polyline to connect the block to Polyline A.
Any help would be appreciated.
Cheers
Matt
Solved! Go to Solution.
Solved by kean_walmsley. Go to Solution.
Hello Matt,
I'm unfortunately still not fully clear on the problem, but I think it's safe that we can break the problem down into a few steps:
I noticed in the original thread that the choice of language isn't yet set in stone. If I were to try this, myself, I'd probably use .NET: mainly because of familiarity but also because of the geometry-related functions you have easier access to. You could do it in LISP, but it would personally take me longer.
I hope this is of some help... if I could get a better understanding of the exact problem, I might even be able to put together a quick blog post about it.
Kean
Hi Kean,
Thanks so much for your reply.
I apologise for the lack of clarity in my description; hopefully if I provide some context it may clear things up.
I am designing a highway drainage system, and will be running a main carrier pipe along the length of the highway (which is the long polyline in the drawing).
Into this pipe will be a number of gully pots ( replicated by a block with insertion point) and are running adjacent to the pipe alebit at a different z-level.
If I didn't have the use of a tool/script, I would have to go through each block and draw a 3d poline between the insertion pipe of the block and a perpendicular point on the main polyline (or pipe).
Since there will be 100's of blocks across my proposal, I would like to create a command where I could choose the main polyline, then choose the blocks and the connection polylines would be drawn automatically. Perhaps I was trying to run before I could even walk, as such maybe we could remove the search function and simply have the user define the polyline with which to connect to.
Does this make things any clearer?
Cheers
Matt
Hi Matt,
Thanks for the clarification - that helps me a lot.
Yes, absolutely - the very first step should probably be to select a polyline and a block and then create the line between the two. Then you can add the search piece once that's working properly.
I'm a bit tied up for the next 10 days or so, but this is an interesting problem to look at. It might actually be easier than I think: GetClosestPointTo() on the polyline might just give the answer... (this is .NET rather than LISP, using the geometry library.)
I'll see whether I sneak some time to take a look at this over the coming days.
Cheers,
Kean
Hi Kean,
Excellent! As I say I am quite the novice with coding but I will go away and do some research on .net and see what I can come up with.
Please don't let this distract you from your work but any help would be greatly appreciated.
Thanks very much
Matt
Here's a basic command to get you started... (apologies to all for posting C# code in the LISP forum)
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; namespace ConnectBlockToPolyline { public class Commands { [CommandMethod("B2P")] public static void Block2Polyline() { var doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; var db = doc.Database; var ed = doc.Editor; // Get the block to connect var peo = new PromptEntityOptions("\nSelect the block"); peo.SetRejectMessage("\nMust be a block."); peo.AddAllowedClass(typeof(BlockReference), false); var per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; var brId = per.ObjectId; var peo2 = new PromptEntityOptions("\nSelect the curve"); peo2.SetRejectMessage("\nMust be a curve."); peo2.AddAllowedClass(typeof(Curve), false); var per2 = ed.GetEntity(peo2); if (per2.Status != PromptStatus.OK) return; var cId = per2.ObjectId; using (var tr = doc.TransactionManager.StartTransaction()) { var br = tr.GetObject(brId, OpenMode.ForRead) as BlockReference; if (br != null) { var btr = tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite ) as BlockTableRecord; if (btr != null) { var c = tr.GetObject(cId, OpenMode.ForRead) as Curve; if (c != null) { var pt = c.GetClosestPointTo(br.Position, false); var ln = new Line(br.Position, pt); btr.AppendEntity(ln); tr.AddNewlyCreatedDBObject(ln, true); } } } tr.Commit(); } } } }
Here's the first post in the series... I'll post the follow-up on Monday:
Kean
Many thanks for your assistance, Kean.
I've just seen your second post on the topic and it has been of great help, not only with the highway design but also in getting to grips with the language in general.
Thanks again.
Matt
Hi,
I was tweaking the code to insert a 3D polyline rather than a line which worked absolutely fine. I then tweaked it slightly to insert the 3D polyline at a certain distance below the insertion point of the block. The 3dpointcollection part now looks like:
var pts = new Point3dCollection(); foreach (ObjectId id in refIds) { var br = tr.GetObject(id, OpenMode.ForRead) as BlockReference; Point3d pt3 = new Point3d(br.Position.X, br.Position.Y, br.Position.Z); pts.Add(pt3); };
If I write "br.Position.Z - 0.6" it correctly starts the 3D polyline 0.6m below the insertion point. However I would eventually like the user to be able to specify the vertical offset, rather than a fixed 0.6.
So far I have written the following such that the user can select depth of two choices, but I can't get a way of changing the 'gdchkstring' into a double so it can be subtracted from the block x position:
var gd = new PromptKeywordOptions("\nSelect gully depth to invert"); gd.AllowNone = true; gd.Keywords.Add("0.6"); gd.Keywords.Add("0.75"); gd.Keywords.Default = ("0.6"); var gdchk = ed.GetKeywords(gd); if (gdchk.Status != PromptStatus.OK) return; string gdchkdstring = gdchk.ToString();
Any help would be appreciated.
Cheers
Matt
Hi Matt,
If you want to convert a string to a double, try double.Parse(str). That said, you'd probably be better off using GetDouble(), unless you want to restrict to a set of options.
The other way to do it would be to present a set of options in a list, such as this:
1. 0.6
2. 0.75
And then use GetInteger() to get one of the items. This would work well if you have a long list of possible options, but want to make sure they choose from a list.
I hope this helps,
Kean
Can't find what you're looking for? Ask the community or share your knowledge.