Jump to content

Recommended Posts

Posted

Hi there;

 

I am trying to write a rebar bill of quantity program in VB.NET and I need to compare two polylines. The polylines can be rotated in different angles, mirrored etc... What is important here is the length of the polyline segments and angles.

 

Is it possible with vb.net? If it is, where should i start from?

 

Thanks in advance.

Posted

Would not the start be making the rules of how you define a rebar or have you got that already if so post an example, then look at how you pull apart a pline to get the required result. www.Lee-mac.com has a nice pline report routine, it may give you a starting point.

Posted

I was about the compare segment lengths and internal angles but considering I am a newbie in .net, it is very hard for me. An idea came to my mind this morning: I'm gonna compare segment lengths first and after that i'm gonna compare distances between start point and end point of the polyline.

 

I don't know this method is always true but it is enough for me to compare most of the rebar shapes. I will share the code as soon as I complete it.

Posted
I was about the compare segment lengths and internal angles but considering I am a newbie in .net, it is very hard for me. An idea came to my mind this morning: I'm gonna compare segment lengths first and after that i'm gonna compare distances between start point and end point of the polyline.

 

I don't know this method is always true but it is enough for me to compare most of the rebar shapes. I will share the code as soon as I complete it.

 

I'd suggest also the following method: after checking they have the same length (oterwise they're not identical for sure) try to "overlap" polylines and look if the area between them is zero (or a very small number). if it is, then you have two identical polylines

 

in more detail, let's assume we have a polyline A and a polyline B.

I'd move A first point to overlap with B first point.

then rotate the A around its first point so as to have its second point x coordinate (or y) equal to B's second point x coordinate (or y)

now, if both polylines second points y coordinates (or x) are not the same (or their difference is not a very small number), then then you can assume that two polylines are not identical.

othewise, if both polylines second points y coordinates (or x) are the same (or their difference is a very small number) then you have to take some more steps.

make a region out of the two polylines and query its area: if it's zero (or a very small number) then you can assume that the two polylines are identical.

if the area is not zero (or it's not a very small number) you have to repeat the same "construction" after inverting the end points of one of the two polylines, and the proceed the same way

 

well I thought that could be easier. but after reading it, I'm not so sure anymore...

Posted

@RICVBA, your last sentence made me laugh so much, thank you very much :) Man I'm a real newbie in .net; I'm afraid I can't do it. Most of rebar shapes that I'm gonna compare are L and U shapes. I hope "length-distance" method will be enough for this.

Posted

I am sure in .net that you can get the co-ordinates of a pline, in lisp as a list then just compare distance pt1-pt2 of both plines. If your struggling with .net just drop back to VLisp the code examples are all done for most pline stuff. Again to quote lee-mac web site

This program provides the user with detailed information about every segment of a selected LWPolyline in the form of either an AutoCAD Table (if available), Text file, or CSV file.

Posted

Hi there;

 

This is my working code, and it seems it's running well. You can select more than two polylines but it compares two polylines at a time ( I don't know how to prevent user to select more than two polylines). I know my code is not a pro work, as I said I am a total newbie. Thanks for all the help guys.

 

<CommandMethod("POLYCOMPARE", "PLCOMP", CommandFlags.Modal + CommandFlags.UsePickSet)> _
   Public Sub PolyCompare()

       Dim doc As Document = Application.DocumentManager.MdiActiveDocument
       Dim db As Database = doc.Database
       Dim ed As Editor = doc.Editor

       Dim pline(1) As Polyline

       Dim tr As Transaction = db.TransactionManager.StartTransaction()
       Using tr
           Dim res As PromptSelectionResult = ed.GetSelection()

           If res.Status = PromptStatus.OK Then

               Dim acSSet As SelectionSet = res.Value

               Dim i As Integer = 0

               For Each obj As SelectedObject In acSSet

                   Dim ent As Entity = tr.GetObject(obj.ObjectId, OpenMode.ForWrite)

                   pline(i) = TryCast(ent, Polyline)

                   i = i + 1

               Next

               Dim result As Boolean = ComparePlines(pline(0), pline(1))

               ed.WriteMessage(vbLf & result.ToString())

           Else

               Exit Sub

           End If
       End Using

   End Sub


   Private Function ComparePlines(plComp1 As Polyline, plComp2 As Polyline) As Boolean

       'Define arrays for segment lengths
       Dim psl1(50) As Single
       Dim psl2(50) As Single

       'Define values
       Dim iNov As Integer = plComp1.NumberOfVertices
       Dim i As Integer = 0
       Dim t As Integer = iNov - 2

       'Define start to end distances
       Dim sSTE1 As Single = Math.Abs(plComp1.GetPoint2dAt(0).GetDistanceTo(plComp1.GetPoint2dAt(iNov - 1)))
       Dim sSTE2 As Single = Math.Abs(plComp2.GetPoint2dAt(0).GetDistanceTo(plComp2.GetPoint2dAt(iNov - 1)))

       'Compare number of vertices and start to end distances
       If plComp1.NumberOfVertices <> plComp2.NumberOfVertices Or sSTE1 <> sSTE2 Then

           Return False
           Exit Function

       Else

           'Get segment lengths
           While i < iNov - 1

               psl1(i) = Math.Abs(plComp1.GetPoint2dAt(i).GetDistanceTo(plComp1.GetPoint2dAt(i + 1)))
               psl2(i) = Math.Abs(plComp2.GetPoint2dAt(i).GetDistanceTo(plComp2.GetPoint2dAt(i + 1)))

               i = i + 1

           End While

           i = 0


           While i < iNov - 1

               'Compare segment lengths
               If psl1(i) <> psl2(i) Then

                   'Another compare for reversed situation
                   If psl1(i) <> psl2(t) Then

                       Return False
                       Exit Function

                   End If

               End If

               i = i + 1
               t = t - 1

           End While

           Return True

       End If

   End Function

Posted

FWIW, The prototype routine below uses some of AutoCAD’s built in functionality (Entity3d.IsEqualTo() method) to simplify the comparison process. Pick a Polyline, and all comparable polys are selected.

I haven’t done extensive testing, but it appears to work with similar LightWeightPolylines in any 3d orientation.

 

Written in C#, though should be translatable by any converter.

 

The Curve.GetGeCurve() method is a relatively new addition. I believe it is only applicable from AutoCAD 2012 on.

 

 

       [CommandMethod("MyGroup", "ComparePolys", "CompPoly", CommandFlags.Modal)]
       public void CompPolysInit()
       {
           Document doc = Application.DocumentManager.MdiActiveDocument;
           Database db = doc.Database;
           Editor ed = doc.Editor;
           
           PromptEntityOptions PEO = new PromptEntityOptions("\nSelect a Polyline: ");
           PEO.SetRejectMessage("\nCommand is only applicable to a Polyline entity! ");
           PEO.AddAllowedClass(typeof(Polyline), false);
           PromptEntityResult per = ed.GetEntity(PEO);
           if (per.Status != PromptStatus.OK) return;
           { 
               ObjectId ObjIDPoly = per.ObjectId;
               using (Transaction tr = db.TransactionManager.StartTransaction())
               {
                   Polyline PL = tr.GetObject(ObjIDPoly, OpenMode.ForRead) as Polyline;
                   if (PL == null) return;
                   CoordinateSystem3d BaseCoord = GetCoordSys(ref PL); 
                   int IsClosed = 0;
                   if (PL.Closed) IsClosed++;
                   if (PL == null) return;
                   Curve3d First = PL.GetGeCurve();
                   TypedValue[] filter = { new TypedValue(0, "LWPOLYLINE"),
                                             new TypedValue(90, PL.NumberOfVertices),
                                             new TypedValue(-4, "&="),
                                             new TypedValue(70, IsClosed)
                                 };
                   SelectionFilter selFilter = new SelectionFilter(filter);
                   PromptSelectionResult res = ed.SelectAll(selFilter);
                   ObjectId[] selSet;
                   if (res.Status == PromptStatus.OK)
                   {
                       selSet = res.Value.GetObjectIds();
                       foreach (ObjectId oid in selSet)
                       {
                           Polyline PL2 = tr.GetObject(oid, OpenMode.ForRead) as Polyline;
                           if (PL2 == null) continue;
                           Curve3d Second = PL2.GetGeCurve();
                           CoordinateSystem3d TestCS = GetCoordSys(ref PL2);
                           Matrix3d ToAlign = Matrix3d.AlignCoordinateSystem(TestCS.Origin,
                                                                               TestCS.Xaxis,
                                                                               TestCS.Yaxis,
                                                                               TestCS.Zaxis,
                                                                               BaseCoord.Origin,
                                                                               BaseCoord.Xaxis,
                                                                               BaseCoord.Yaxis,
                                                                               BaseCoord.Zaxis);
                           Second.TransformBy(ToAlign);
                           if (First.IsEqualTo(Second)) PL2.Highlight();
                           else
                           {
                               Line3d Ln = new Line3d(Second.StartPoint, BaseCoord.Xaxis);
                               Matrix3d Mirr = Matrix3d.Mirroring(Ln);
                               Second.TransformBy(Mirr);
                               if (First.IsEqualTo(Second)) PL2.Highlight();
                           }
                       }
                   }
                   tr.Commit();
               }
           }
       }



       private CoordinateSystem3d GetCoordSys(ref Polyline Poly)
       {
           Vector3d Normal = Poly.Normal;
           Vector3d FirstToSecond = Poly.StartPoint.GetVectorTo(Poly.GetPoint3dAt(1));
           Vector3d Y = Normal.CrossProduct(FirstToSecond);
           CoordinateSystem3d CS = new CoordinateSystem3d(Poly.StartPoint, FirstToSecond, Y);
           return CS;
       }

Posted

Why not just implement a simple 'Create Rebar' aspect to your application, that adds GUID-based XData to each 'rebar' being added to the Database?

 

If GUID-based is too unique, you could always specify 'product codes/types' instead.

Posted

FWIW, The prototype routine below uses some of AutoCAD’s built in functionality (Entity3d.IsEqualTo() method) to simplify the comparison process. Pick a Polyline, and all comparable polys are selected.

I haven’t done extensive testing, but it appears to work with similar LightWeightPolylines in any 3d orientation.

 

Written in C#, though should be translatable by any converter.

 

The Curve.GetGeCurve() method is a relatively new addition. I believe it is only applicable from AutoCAD 2012 on.

 

 

       [CommandMethod("MyGroup", "ComparePolys", "CompPoly", CommandFlags.Modal)]
       public void CompPolysInit()
       {
           Document doc = Application.DocumentManager.MdiActiveDocument;
           Database db = doc.Database;
           Editor ed = doc.Editor;
           
           PromptEntityOptions PEO = new PromptEntityOptions("\nSelect a Polyline: ");
           PEO.SetRejectMessage("\nCommand is only applicable to a Polyline entity! ");
           PEO.AddAllowedClass(typeof(Polyline), false);
           PromptEntityResult per = ed.GetEntity(PEO);
           if (per.Status != PromptStatus.OK) return;
           { 
               ObjectId ObjIDPoly = per.ObjectId;
               using (Transaction tr = db.TransactionManager.StartTransaction())
               {
                   Polyline PL = tr.GetObject(ObjIDPoly, OpenMode.ForRead) as Polyline;
                   if (PL == null) return;
                   CoordinateSystem3d BaseCoord = GetCoordSys(ref PL); 
                   int IsClosed = 0;
                   if (PL.Closed) IsClosed++;
                   if (PL == null) return;
                   Curve3d First = PL.GetGeCurve();
                   TypedValue[] filter = { new TypedValue(0, "LWPOLYLINE"),
                                             new TypedValue(90, PL.NumberOfVertices),
                                             new TypedValue(-4, "&="),
                                             new TypedValue(70, IsClosed)
                                 };
                   SelectionFilter selFilter = new SelectionFilter(filter);
                   PromptSelectionResult res = ed.SelectAll(selFilter);
                   ObjectId[] selSet;
                   if (res.Status == PromptStatus.OK)
                   {
                       selSet = res.Value.GetObjectIds();
                       foreach (ObjectId oid in selSet)
                       {
                           Polyline PL2 = tr.GetObject(oid, OpenMode.ForRead) as Polyline;
                           if (PL2 == null) continue;
                           Curve3d Second = PL2.GetGeCurve();
                           CoordinateSystem3d TestCS = GetCoordSys(ref PL2);
                           Matrix3d ToAlign = Matrix3d.AlignCoordinateSystem(TestCS.Origin,
                                                                               TestCS.Xaxis,
                                                                               TestCS.Yaxis,
                                                                               TestCS.Zaxis,
                                                                               BaseCoord.Origin,
                                                                               BaseCoord.Xaxis,
                                                                               BaseCoord.Yaxis,
                                                                               BaseCoord.Zaxis);
                           Second.TransformBy(ToAlign);
                           if (First.IsEqualTo(Second)) PL2.Highlight();
                           else
                           {
                               Line3d Ln = new Line3d(Second.StartPoint, BaseCoord.Xaxis);
                               Matrix3d Mirr = Matrix3d.Mirroring(Ln);
                               Second.TransformBy(Mirr);
                               if (First.IsEqualTo(Second)) PL2.Highlight();
                           }
                       }
                   }
                   tr.Commit();
               }
           }
       }



       private CoordinateSystem3d GetCoordSys(ref Polyline Poly)
       {
           Vector3d Normal = Poly.Normal;
           Vector3d FirstToSecond = Poly.StartPoint.GetVectorTo(Poly.GetPoint3dAt(1));
           Vector3d Y = Normal.CrossProduct(FirstToSecond);
           CoordinateSystem3d CS = new CoordinateSystem3d(Poly.StartPoint, FirstToSecond, Y);
           return CS;
       }

 

Neat idea, Seant (as usual!); if I were to nitpick, there's no need for the second call to:

 

//...
                   Polyline PL = tr.GetObject(ObjIDPoly, OpenMode.ForRead) as Polyline;
                   [color="blue"]if (PL == null) return;[/color]
                   CoordinateSystem3d BaseCoord = GetCoordSys(ref PL); 
                   int IsClosed = 0;
                   if (PL.Closed) IsClosed++;
                  [color="red"] if (PL == null) return;[/color]
                   Curve3d First = PL.GetGeCurve();
//...

Posted

@Blackbox; Rebars could be already drawn by another user with standard polyline command. So my application must compare them with their geometry.

Posted
. . . . if I were to nitpick, there's no need for the second call.

 

 

 

 

Ah yes, quite redundant on my part. If I had to make an excuse, I'd say it was shoddy proofreading due to the stress of the holidays. :)

Posted
@Blackbox; Rebars could be already drawn by another user with standard polyline command. So my application must compare them with their geometry.

 

I'm not suggesting the method I posit would preclude the need to process existing poly line entities; instead I'm suggesting a means by which that you can implement event-driven systems that automagically identifies the Arc, Line, Polyline, etc. associated with your custom .NET app, and allows for Object pricier event to filter for which entities need to be 'modified' automagically following any user edit (ie, STRETCH, EXTEND, etc).

 

You'd still want to implement a CommandMethod Method in order to allow user to manually process as desired.

 

Cheers

Posted
Ah yes, quite redundant on my part. If I had to make an excuse, I'd say it was shoddy proofreading due to the stress of the holidays. :)

 

 

I'm sorry to hear that someone who so often volunteers their expertise to help others is experiencing stress this Christmas & New Year; as a much wiser man than I once said "this too shall pass."

 

Cheers, my friend. :beer:

Posted

Thanks BB. Though I should admit that the holidays do not stress the system significantly more than any other time of the year. Similarly, shoddy proofreading on my part remains rather constant from one season to the next.

 

 

Kick butt in the new year,

Sean

Posted

Life has a funny way of always keeping it interesting - as a personal example, my paid off SUV that didn't even have 100K miles, was just totaled out due to this, and so I now have +/- 7 days to buy or lease a new vehicle. o:)

 

Happy New Year, Sean!

Posted

Damn, sounds like "Life" kick a little bit of your butt going into the new year. Hopefully it all works out in the end.

Posted
Damn, sounds like "Life" kick a little bit of your butt going into the new year. Hopefully it all works out in the end.

 

Thanks, Sean - Life never fails to remind me to appreciate what I have, that's for sure. :beer:

 

Cheers

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...