kunekainen Posted December 22, 2014 Posted December 22, 2014 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. Quote
BIGAL Posted December 23, 2014 Posted December 23, 2014 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. Quote
kunekainen Posted December 23, 2014 Author Posted December 23, 2014 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. Quote
RICVBA Posted December 23, 2014 Posted December 23, 2014 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... Quote
kunekainen Posted December 23, 2014 Author Posted December 23, 2014 @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. Quote
BIGAL Posted December 23, 2014 Posted December 23, 2014 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. Quote
kunekainen Posted December 23, 2014 Author Posted December 23, 2014 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 Quote
SEANT Posted December 24, 2014 Posted December 24, 2014 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; } Quote
kunekainen Posted December 24, 2014 Author Posted December 24, 2014 Thanks SEANT, I'm gonna try it soon. Quote
BlackBox Posted December 26, 2014 Posted December 26, 2014 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. Quote
BlackBox Posted December 26, 2014 Posted December 26, 2014 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(); //... Quote
kunekainen Posted December 26, 2014 Author Posted December 26, 2014 @Blackbox; Rebars could be already drawn by another user with standard polyline command. So my application must compare them with their geometry. Quote
SEANT Posted December 26, 2014 Posted December 26, 2014 . . . . 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. Quote
BlackBox Posted December 27, 2014 Posted December 27, 2014 @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 Quote
BlackBox Posted December 27, 2014 Posted December 27, 2014 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. Quote
SEANT Posted December 28, 2014 Posted December 28, 2014 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 Quote
BlackBox Posted December 28, 2014 Posted December 28, 2014 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. Happy New Year, Sean! Quote
SEANT Posted December 28, 2014 Posted December 28, 2014 Damn, sounds like "Life" kick a little bit of your butt going into the new year. Hopefully it all works out in the end. Quote
BlackBox Posted December 28, 2014 Posted December 28, 2014 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. Cheers Quote
Recommended Posts
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.