Good afternoon everyone.
I was fortunate enough to have some help writing the following code that sets all the ambient layers for pipes and structures to what is required for our submissions. This saves a ton of clicks when data referencing a pipe network into a drawing. The code is below:
[CommandMethod("SETSS")] public void SetSanitaryLayers() { string LaySan = "41-C-SSWR"; CivilDocument doc = Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument; Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; Database db = Application.DocumentManager.MdiActiveDocument.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { try //moved try within transaction { //Get/Set layer names for pipe ed.WriteMessage("\nPipe Object Layer Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Pipe).LayerName.ToString()); //Now change the DrawingSettings.ObjectLayerSettings doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Pipe).LayerName = LaySan; ed.WriteMessage("\nPipe Object Layer Now Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Pipe).LayerName.ToString()); //structures ed.WriteMessage("\nStructure Object Layer Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Structure).LayerName.ToString()); //Now change the DrawingSettings.ObjectLayerSettings doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Structure).LayerName = LaySan; ed.WriteMessage("\nStructure Object Layer Now Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.Structure).LayerName.ToString()); //Plan profile ed.WriteMessage("\nPipe/Structure Profile Object Layer Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeOrStructureProfile).LayerName.ToString()); //Now change the DrawingSettings.ObjectLayerSettings doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeOrStructureProfile).LayerName = LaySan; ed.WriteMessage("\nPipe/Structure Profile Object Layer Now Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeOrStructureProfile).LayerName.ToString()); //Pipe Network Section ed.WriteMessage("\nPipe Network Section Object Layer Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeNetworkSection).LayerName.ToString()); //Now change the DrawingSettings.ObjectLayerSettings doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeNetworkSection).LayerName = LaySan; ed.WriteMessage("\nPipe Network Section Object Layer Now Set to: " + doc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting (Autodesk.Civil.Settings.SettingsObjectLayerType.PipeNetworkSection).LayerName.ToString()); } catch (Exception ex) { ed.WriteMessage("\nException Message: " + ex.Message.ToString()); } tr.Commit(); //commit transaction } //end transaction }
I would like to extend this code by adding the ability to specify a pipe label style and then entering the command to label the pipes. My goal is to place this command on a tool palette to aid in the drafting of our block plan profiles. I found a couple of suggestions as visual lisp, but I would like to do this in c# and don't have the background to translate between the languages.
Thanks for all of your help.
Jason
Solved! Go to Solution.
Solved by Jeff_M. Go to Solution.
Using PromptEntityOptions with the Allowed Class set to Pipe, ed.GetEntity(), and PromptEntityResult, you could allow the user to select a pipe and Create a PipeLabel on that pipe:
PipeLabel.Create(ObjectId pipeId, double ratio, ObjectId labelStyleId)
I don't have time right now for a full example, but if you need further help just holler and I'll put something together tonight.
With this method, I'm assuming that all of the options would be coded into the routine? All of the pipe styles are already in the template. An interesting approach. I'm not near a computer now, but I will see if I can get this to work.
Thanks!
Jason
I had a bit of free time and came up with this. Use it or change as desired, but it does work to label individual pipes with a specific style and the default layer.
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using Autodesk.Civil.ApplicationServices; using Autodesk.Civil.DatabaseServices; using Autodesk.Civil.DatabaseServices.Styles; using Autodesk.Civil.Settings; namespace Civil3D_Misc_Commands.Pipes { public class LabelPipes { [CommandMethod("QxPipeLabel")] public void qxpipelabel() { string stylename = "Standard"; // replace with desired name to use. Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; Database db = doc.Database; CivilDocument civdoc = CivilApplication.ActiveDocument; ObjectId styleId = ObjectId.Null; LabelStyleCollection lblstyles = civdoc.Styles.LabelStyles.PipeLabelStyles.PlanProfileLabelStyles; //make sure the style is defined in the drawing if (lblstyles.Contains(stylename)) { //it is, so use it styleId = lblstyles[stylename]; } else { //it isn't, use the default for pipe labeling styleId = civdoc.Settings.GetSettings<SettingsCmdAddNetworkPlanLabels>().Styles.PipePlanLabelStyleId.Value; } string layername = civdoc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting(SettingsObjectLayerType.PipeLabeling).LayerName; PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect pipe to label:"); entOpts.SetRejectMessage("...not a Pipe object, try again!"); entOpts.AddAllowedClass(typeof(Pipe), true); PromptEntityResult entRes = ed.GetEntity(entOpts); using (Transaction tr = db.TransactionManager.StartTransaction()) { while (entRes.Status == PromptStatus.OK) { ObjectId lblId = PipeLabel.Create(entRes.ObjectId, 0.5, styleId); PipeLabel pipelbl = (PipeLabel)lblId.GetObject(OpenMode.ForWrite); //the Create method does not honor the ObjectLayer setting, so be sure to set the layer. pipelbl.Layer = layername; entRes = ed.GetEntity(entOpts); } tr.Commit(); } } } }
Jeff,
Thanks alot. This is what I was after. I was reviewing your code so I could better understand what was going on. I realized that I was missing a few references, so I never would have found what I was looking for. Most of the work my group does is Block Plan Profiles that are submitted to the municipality for review/approval. Can this code be made to label those parts as well. It works awesome for plan view, and it totally what I am looking for. The addition of pipes in profile would finish this off. I also didn't state that up front, sorry about that.
I looked through the Autodesk.Civil.DatabaseServices.Part class and saw a method to draw in profile, but nothing that I could label a part with. There also wasn't an object I could see in Autodesk.Civil.DatabaseServices.Pipe. (with my limited coding abilities.) Could this routine be made to label both at once, using an IF statement to tell if it's a pipe or profile pipe?
Thanks again for all of your help. I appreciate the time you are spending to help me.
Jason
@Anonymous wrote:
Jeff,
...Can this code be made to label those parts as well. ....
Jason
Yep!
public void qxpipelabel() { string stylename = "Standard"; // replace with desired name to use. Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; Database db = doc.Database; CivilDocument civdoc = CivilApplication.ActiveDocument; ObjectId styleId = ObjectId.Null; LabelStyleCollection lblstyles = civdoc.Styles.LabelStyles.PipeLabelStyles.PlanProfileLabelStyles; //make sure the style is defined in the drawing if (lblstyles.Contains(stylename)) { //it is, so use it styleId = lblstyles[stylename]; } else { //it isn't, use the default for pipe labeling styleId = civdoc.Settings.GetSettings<SettingsCmdAddNetworkPlanLabels>().Styles.PipePlanLabelStyleId.Value; } string layername = civdoc.Settings.DrawingSettings.ObjectLayerSettings.GetObjectLayerSetting(SettingsObjectLayerType.PipeLabeling).LayerName; PromptEntityOptions entOpts = new PromptEntityOptions("\nSelect pipe to label:"); entOpts.SetRejectMessage("...not a Pipe object, try again!"); entOpts.AddAllowedClass(typeof(Pipe), true); entOpts.AddAllowedClass(typeof(ProfileViewPart), true); PromptEntityResult entRes = ed.GetEntity(entOpts); using (Transaction tr = db.TransactionManager.StartTransaction()) { while (entRes.Status == PromptStatus.OK) { if (entRes.ObjectId.ObjectClass.DxfName.ToUpper().Contains("PROFILE")) { ProfileViewPart part = (ProfileViewPart)entRes.ObjectId.GetObject(OpenMode.ForRead); Pipe pipe = (Pipe)part.ModelPartId.GetObject(OpenMode.ForRead); ObjectId pvId = ObjectId.Null; foreach (ObjectId id in pipe.GetProfileViewsDisplayingMe()) { double sta = 0, off = 0; ProfileView pv = (ProfileView)id.GetObject(OpenMode.ForRead); if (pv.FindStationAndElevationAtXY(entRes.PickedPoint.X, entRes.PickedPoint.Y, ref sta, ref off)) { pvId = id; break; } } ObjectId lblId = PipeProfileLabel.Create(entRes.ObjectId, pvId, 0.5, styleId); PipeProfileLabel pipelbl = (PipeProfileLabel)lblId.GetObject(OpenMode.ForWrite); //the Create method does not honor the ObjectLayer setting, so be sure to set the layer. pipelbl.Layer = layername; } else { ObjectId lblId = PipeLabel.Create(entRes.ObjectId, 0.5, styleId); PipeLabel pipelbl = (PipeLabel)lblId.GetObject(OpenMode.ForWrite); //the Create method does not honor the ObjectLayer setting, so be sure to set the layer. pipelbl.Layer = layername; } entRes = ed.GetEntity(entOpts); } tr.Commit(); } }
That did the trick! Thank you! 😄
I noticed there was a lot more code to drill down to the profile pipe. Is that because we have to open the object container before we can check what the pipe is? That would make the most sense. The plan pipes don't require that because they are already in the drawing database, but aren't in a separate container. I get it now.
Thanks again!
Jason