Create Labels for Crossing Pipes in Profile View using C#

Create Labels for Crossing Pipes in Profile View using C#

alexisgacia
Advocate Advocate
3,109 Views
20 Replies
Message 1 of 21

Create Labels for Crossing Pipes in Profile View using C#

alexisgacia
Advocate
Advocate

Hi,

 

I'm trying to create a tool to generate crossing pipe labels for the profile view. But I didn't know if there's a possibility to identify the crossing pipe in the profile view.

 

 

 

void CreateProfileViewLabel(Transaction tr, ObjectId profViewId, ObjectId PartId)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            var civdoc = CivilApplication.ActiveDocument;

            acc3db.ProfileView pview = (acc3db.ProfileView)tr.GetObject(profViewId, OpenMode.ForRead);
            var labelStyleID = civdoc.Styles.LabelSetStyles.ProfileLabelSetStyles["Standard"];
            var PipeStyleID = civdoc.Styles.PipeStyles["Crossing"];

            

            //acc3db.PipeProfileLabel.Create(PartId, profViewId, .5, labelStyleID);

            var o = tr.GetObject(PartId, OpenMode.ForWrite);
            var pv = tr.GetObject(profViewId, OpenMode.ForWrite);

            if (o is acc3db.ProfileViewPart && pv is acc3db.ProfileView)
            {
                acc3db.ProfileViewPart mPart = o as acc3db.ProfileViewPart;
                acc3db.ProfileView mPV = pv as acc3db.ProfileView;

                

                foreach (var mPipe in mPV.PipeOverrides)
                {
                    mPipe.OverrideStyleId = PipeStyleID;
                    System.Diagnostics.Debug.Print("Draw: " + mPipe.Draw.ToString());
                    
                    
                }


                acc3db.StructureProfileLabel.Create(profViewId, PartId);
            }
        }

 

 

 

Is it possible to identify the Crossing Pipes in the PipeOverrides from ProfileView?

 

Then once it is detected, it will create label with the Pipe Diameter. 

 

Thank you in advance.

3,110 Views
20 Replies
Replies (20)
Message 2 of 21

ChrisRS
Mentor
Mentor

Deleted by author.

Christopher Stevens
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature

0 Likes
Message 3 of 21

hippe013
Advisor
Advisor

The following is a quick example of labeling the structures and pipes within a ProfileView. The PipeOverride and the StructureOverride both provide properties that point back to the part (pipe or structure). I am writing in vb.net, but this can easily be converted to C#. 

 

 <CommandMethod("PvLblPipeStructs")>
Public Sub CmdPvLblPipeStructs()
   GetCurrent() 'CommandBase - Sets Private aDoc, db, and ed

   Dim opt As New PromptEntityOptions(vbCrLf & "Select ProfileView: ")
   opt.SetRejectMessage(vbCrLf & "Selected entity must be a ProfileView. Try Again")
   opt.AddAllowedClass(GetType(ProfileView), True)

   Dim res As PromptEntityResult = ed.GetEntity(opt)

   If res.Status <> PromptStatus.OK Then Exit Sub

   Using tr As Transaction = db.TransactionManager.StartTransaction
      Dim pv As ProfileView = tr.GetObject(res.ObjectId, OpenMode.ForRead)

      For Each po As PipeOverride In pv.PipeOverrides
         PipeProfileLabel.Create(po.PipeId, pv.ObjectId)
      Next

      For Each so As StructureOverride In pv.StructureOverrides
         StructureProfileLabel.Create(pv.ObjectId, so.StructId)
      Next

      tr.Commit()
   End Using
End Sub

 

It bugs me that the arguments for the two functions, PipeProfileLabel.Create and StructureProfileLabel.Create, each have two agruments, a partId (pipe or structure respectively) and a profileView ObjectId. However, they are in different order for each function. I feel the order of the arguments should be that same for both functions. That's just my two cents. 

0 Likes
Message 4 of 21

alexisgacia
Advocate
Advocate

Thank you for the reply. How would I determine the crossing pipe? My plan is to create labels for the crossing pipe.

0 Likes
Message 5 of 21

hippe013
Advisor
Advisor

Can you explain further what you mean when you say crossing pipe? If you mean a pipe that crosses the alignment and is shown in the profile view, then it is simply a pipe that when using the start and end points of the pipe you will get a positive and negative offset when using the StationOffset method of the alignment.  Or better yet, are you able to post a drawing? 

0 Likes
Message 6 of 21

hippe013
Advisor
Advisor

I drafted up a function to determine if the pipe crosses the alignment. Let me know if this what you had in mind.

 

Public Function PipeCrossesAlignment(pipeOverridePipeId As ObjectId, alignId As ObjectId) As Boolean
   Dim ret As Boolean = False

   'Get Pipe
   Dim part As ProfileViewPart = pipeOverridePipeId.GetObject(OpenMode.ForRead)
   Dim pipe As Pipe = part.ModelPartId.GetObject(OpenMode.ForRead)

   Dim sp As New Point3d(pipe.StartPoint.X, pipe.StartPoint.Y, 0)
   Dim ep As New Point3d(pipe.EndPoint.X, pipe.EndPoint.Y, 0)

   'Get Alignment
   Dim align As Alignment = alignId.GetObject(OpenMode.ForRead)

   Using line As New Line(sp, ep)
      Using pntCol As New Point3dCollection
         align.IntersectWith(line, Intersect.OnBothOperands, pntCol, IntPtr.Zero, IntPtr.Zero)
         If pntCol.Count > 0 Then
            ret = True
         End If
      End Using
   End Using

   Return ret
End Function

 

It can be used as follows: 

 

Using tr As Transaction = db.TransactionManager.StartTransaction
   Dim pv As ProfileView = tr.GetObject(res.ObjectId, OpenMode.ForRead)

   For Each po As PipeOverride In pv.PipeOverrides
      If PipeCrossesAlignment(po.PipeId, pv.AlignmentId) Then
         PipeProfileLabel.Create(po.PipeId, pv.ObjectId)
      End If
   Next

   tr.Commit()
End Using

 

0 Likes
Message 7 of 21

Jeff_M
Consultant
Consultant

@hippe013 This works for most crossing pipes (I came up with essentially the same thing in c# as an extension method for profileview) however it does not account for pipes that cross the alignment at a slight angle. Say you have a pipe which is 300' long and starts at 2' left and ed at 5' right. This will typically just be shown as a 'normal' pipe in profile, not a crossing pipe. I started working on a change to my code to have the extension method include an argument for the minimum angle to use to define a pipe as a crossing, but ran out of time to complete it. Perhaps I can get back to it this evening.

Jeff_M, also a frequent Swamper
EESignature
Message 8 of 21

hippe013
Advisor
Advisor

@Jeff_M I am a little confused. What, precisely, defines a crossing pipe? Are you saying that if the pipe, more or less, runs with the profile / alignment direction, that you would want to exclude that as a crossing pipe? Where my definition (according to the code) would be anything that actually cross the alignment centerline.  

0 Likes
Message 9 of 21

Jeff_M
Consultant
Consultant

@hippe013 Yes, it doesn't occur often, but it does occur. In this screenshot, the sewer line crosses over the centerline of an arced alignment. However, it should not, and does not, display as a crossing pipe in profile.

2023-01-23_9-12-59.png

Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 10 of 21

hippe013
Advisor
Advisor

Okay, I think I get it now. For a crossing pipe you will apply a pipe style different from that of  a pipe that is running along the alignment. Correct? I can see where my code would then falsely identify a crossing pipe that is actually going along the alignment. 

Message 11 of 21

Jeff_M
Consultant
Consultant
Yes, exactly! Another case may be where a road crosses over a small drainage swale which is picked up with a culvert which runs askew to the alignment at a 45 degree angle. This would likely also be shown as the full pipe vs a crossing style.
Jeff_M, also a frequent Swamper
EESignature
Message 12 of 21

alexisgacia
Advocate
Advocate

In my sample drawing. They have different alignments but a similar style that they used. I was thinking to check the distance of the start point and end point of the pipe to the alignment to determine the crossing pipe. But I don't know if that is reliable to distinguish the crossing pipe.

alexisgacia_0-1674538512817.png

 

0 Likes
Message 13 of 21

pozhidaevdn
Advocate
Advocate

Hello @hippe013,

In your code you are using 

 PipeProfileLabel.Create

This command creates a label of PlanProfile style

For Civil 3D PlanProfile and CrossingProfile is a different style types.

 

So if you'll try to create a label with this method and with styleId from CrossingProfileLabels:

civilDoc.Styles.LabelStyles.PipeLabelStyles.CrossProfileLabelStyles

You will get error: "Value does not fall within the expected range"

 

Is there any way to create a label with a style from CrossProfileLabelStyles?

 

Ps. For tests i created two label via Civil commands and then i picked them in selection set to check their type so:

Label with PlanProfileLabelStyle - goes to PipeProfileLabel class

 

So if you try to create a lable with styleId from CrossingProfileLabels:

civilDoc.Styles.LabelStyles.PipeLabelStyles.CrossProfileLabelStyles

You will get error: "Value does not fall within the expected range"

 

Is there any way to create a label with a style from CrossProfileLabelStyles?

 

Ps. For tests i created two label via Civil commands and then i picked them in selection set to check their type.

So:

Label with PlanProfileLabelStyle - goes to PipeProfileLabel class

Label with CrossProfileLabelStyle - goes to Label class

PipeProfileLabel has a nice .Create Method, but Label Class has basic .Create method with (intPtr,bool)

Pss. i'm using 2021 version of Civil 3D

0 Likes
Message 14 of 21

hippe013
Advisor
Advisor

@pozhidaevdn The code I've posted above is simply example code for the purpose of seeking out a solution to the OP's original question. It is NOT production code. If you read through the thread you will see that we were attempting to identify which parts are considered crossing pipes and therefor should be labeled accordingly.  I have not found a way to label crossing parts in the profileview nor have I figuered out what Civil 3d uses to determine what should be considered crossing part.

0 Likes
Message 15 of 21

Jeff_M
Consultant
Consultant

@pozhidaevdn As of C3D 2024 the PipeCrossingProfile label has not been fully exposed in the .NET API. Therefor we cannot create a label of this type at this time.

Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 16 of 21

jklinkeB8EEG
Contributor
Contributor

You gentlemen seem to understand pipe/structure profile labels quite well.  Can you shed some light on moving and or setting location for PipeProfileLabels and StructureProfileLabels, please.  I just don’t think I understand the grips and snaps etc.  My goal is to programmatically modify the label locations on the profile to be staggered.  See the example in the following thread.  Any help would be greatly appreciated. https://www.theswamp.org/index.php?topic=58697.msg616987#msg616987

0 Likes
Message 18 of 21

jklinkeB8EEG
Contributor
Contributor

StructureLabelGraphics.png

I'm sorry, but I really want to recreate the above programmatically.  Plus I'm just not understanding how to use the DraggedOffset function either.  I am either not smart enough, or just can't seem to grasp how to use the help functions and know how to apply them.  I can see from above your DraggedOffset as a Vector3d, but I don't know how to modify or set.  I'm really just a Civil Engineer Hacker and I just can't understand how you guys get anything from the help files. I would not be able to accomplish the above goal without adding vertexes and manipulating the label structure so any guidance on the aspects of leader locations or whatever it takes to replicate the above would be appreciated!

 

0 Likes
Message 19 of 21

Jeff_M
Consultant
Consultant

@jklinkeB8EEG John, I'm afraid that what you are wanting to do is not quite possible with the current state of the API. You CAN set the LabelLocation (The DraggedOffset has been deprecated) but I am not seeing any way to add/remove vertices in the leader. Also, as with manually dragging the label, the attachment point of the leader is at the center of the structure, not the top or bottom as the label is originally placed.

        [CommandMethod("DragStructureProfileLabel")]
        public void Dragstructureprofilelabel()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            var db = doc.Database;
            var prEnt = new PromptEntityOptions("\nSelect StructureProfileLabel to drag:");
            prEnt.SetRejectMessage("..not a correct label type, try again.");
            prEnt.AddAllowedClass(typeof(StructureProfileLabel), true);
            var selEnt = ed.GetEntity(prEnt);
            if (selEnt.Status != PromptStatus.OK)
                return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                var lbl = (StructureProfileLabel)tr.GetObject(selEnt.ObjectId, OpenMode.ForWrite);
                lbl.ResetLocation();
                lbl.LabelLocation = lbl.LabelLocation.TransformBy(Matrix3d.Displacement(new Vector3d(0, -15.0, 0.0)));
                //try to add a vertex by using a second move, doesn't work
                lbl.LabelLocation = lbl.LabelLocation.TransformBy(Matrix3d.Displacement(new Vector3d(10, 0.0, 0.0)));
                tr.Commit();
            }
        }

 

Jeff_M, also a frequent Swamper
EESignature
Message 20 of 21

jklinkeB8EEG
Contributor
Contributor
Thank you so much for looking into this. With how these labels need to be adjusted/staggard so many times, I would have thought this would be something we could modify. How do people accomplish stacking labels like these?
0 Likes