Author Topic: polyline area  (Read 7564 times)

0 Members and 1 Guest are viewing this topic.

nekitip

  • Guest
polyline area
« on: December 19, 2014, 08:39:01 AM »
I wander if someone has some GetArea function for polylines?
Or at least idea?

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #1 on: December 19, 2014, 09:05:39 AM »
Polylines are derived from the Curve object which has the Area property. What are you wanting your GetArea() to do different than the Area property?

nekitip

  • Guest
Re: polyline area
« Reply #2 on: December 19, 2014, 09:12:01 AM »
Because Curve.Area in .NET is not showing correct values.
You can check yourself.
Values are correct only for simple polylines.

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #3 on: December 19, 2014, 09:42:56 AM »
Can you give an example?

nekitip

  • Guest
Re: polyline area
« Reply #4 on: December 19, 2014, 10:11:05 AM »
try to draw number 8 using single polyline
and try this simple code
Code - vb.net: [Select]
  1. Imports System
  2. Imports Autodesk.AutoCAD.Runtime
  3. Imports Autodesk.AutoCAD.ApplicationServices
  4. Imports Autodesk.AutoCAD.DatabaseServices
  5. Imports Autodesk.AutoCAD.Geometry
  6. Imports Autodesk.AutoCAD.EditorInput
  7.  
  8. Imports System.ComponentModel
  9. Imports System.Collections.Specialized
  10. Imports System.Collections.ObjectModel
  11. Imports System.Linq
  12.  
  13. <Assembly: CommandClass(GetType(tmpdel.MyCommands))>
  14. <Assembly: ExtensionApplication(GetType(tmpdel.MyPlugin))>
  15.  
  16.  
  17. Namespace tmpdel
  18.     Public Class MyPlugin
  19.         Implements IExtensionApplication
  20.         Public Sub Initialize() Implements IExtensionApplication.Initialize
  21.         End Sub
  22.         Public Sub Terminate() Implements IExtensionApplication.Terminate
  23.         End Sub
  24.     End Class
  25.  
  26.     Public Class MyCommands
  27.      
  28.         <CommandMethod("mytest")> _
  29.         Public Sub MyCommand()
  30.             showA(pickPoly)
  31.         End Sub
  32.  
  33.         Public Sub showA(oid As ObjectId)
  34.             Dim area As Double
  35.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  36.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  37.             Using trans As OpenCloseTransaction = db.TransactionManager.StartOpenCloseTransaction()
  38.                 Dim pol As Polyline = trans.GetObject(oid, OpenMode.ForRead)
  39.                 area = pol.Area
  40.                 trans.Commit()
  41.             End Using
  42.             MsgBox(area.ToString)
  43.         End Sub
  44.  
  45.         Public Function pickPoly() As ObjectId
  46.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  47.             Dim doc As Document = Application.DocumentManager.GetDocument(db)
  48.             Dim ed As Editor = doc.Editor
  49.             Dim peo As PromptEntityOptions = New PromptEntityOptions("\nSelect a polyline: ")
  50.             peo.SetRejectMessage("Selected object is not a polyline.")
  51.             peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline), True)
  52.             Dim per As PromptEntityResult = ed.GetEntity(peo)
  53.             If per.Status = PromptStatus.OK Then
  54.                 Return per.ObjectId
  55.             End If
  56.         End Function
  57.     End Class
  58. End Namespace

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #5 on: December 19, 2014, 10:34:11 AM »
OK, I do see that the Area property is incorrect for self intersecting polylines. Off to see what I can come up with.

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #6 on: December 19, 2014, 11:10:59 AM »
Using the Area property from the COM object returns the correct value. This extension method (in c#, sorry, not a VB person) works and does not require the COM libraries to be referenced (i.e. I used late binding)
Code - C#: [Select]
  1.         public static double GetArea(this Polyline pline)
  2.         {
  3.             object pl = pline.AcadObject;
  4.             return (double)pl.GetType().InvokeMember("Area", System.Reflection.BindingFlags.GetProperty, null, pl, null);
  5.         }
  6.  

nekitip

  • Guest
Re: polyline area
« Reply #7 on: December 19, 2014, 11:46:29 AM »
well this is insane
Yes Jeff, I've done quick test and your solution works, I think! Thank you!!!
I spent afternoon trying different hacks with using offsets and finding inner loops... because of this. So you are a savior!

Just how they get away with this things?

P.S.
Since I never use COM inside .NET, is there anything i should know about this specific implementation. Like disposing or so?
I assume that everything is fine, since pline is here received from transaction, so transaction will take care but...

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #8 on: December 19, 2014, 12:07:10 PM »
I've never done anything special with the ACAD object. COM pretty much takes care of itself.

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: polyline area
« Reply #9 on: December 19, 2014, 01:15:33 PM »
Shorthand version

Code - C#: [Select]
  1.         public static double GetArea(this Polyline pline)
  2.         {
  3.             dynamic pl = pline.AcadObject;
  4.             return (double)pl.Area;
  5.         }
Revit 2019, AMEP 2019 64bit Win 10

Jeff_M

  • King Gator
  • Posts: 4095
  • C3D user & customizer
Re: polyline area
« Reply #10 on: December 19, 2014, 04:27:46 PM »
Man, I still work with older versions enough that I never remember about that dynamic object...almost takes the fun out of figuring this stuff out :-)

nekitip

  • Guest
Re: polyline area
« Reply #11 on: December 19, 2014, 05:39:25 PM »
i was searching trough various functions in ac and found this
Code - vb.net: [Select]
  1. Dim curve As Curve = trans.GetObject(oid, OpenMode.ForRead)
  2. Dim cge As Curve3d = curve.GetGeCurve()
  3. Dim ci As New CurveCurveIntersector3d(cge, cge, curve.GetPlane.Normal)
  4. Dim iii As Integer = ci.NumberOfIntersectionPoints()
  5. Dim area= cge.GetArea(curve.StartParam, curve.EndParam)

now, it seems to count intersections right, but area is wrong here. But I've never seen this function before, maybe I'm using it wrong. If anyone has idea?
I have also found that COM solution does have some problems when used with overrule... nothing that cant be hangled though, but... how about this curve3d way?

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: polyline area
« Reply #12 on: December 19, 2014, 05:58:10 PM »

This extension method (in c#, sorry, not a VB person) works and < ... >


That's one of the 5 things you never need to apologise for Jeff .

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

nekitip

  • Guest
Re: polyline area
« Reply #13 on: December 20, 2014, 04:30:51 AM »
Since COM is a bit slower, how about this way to get area out of curves?
Code - vb.net: [Select]
  1. Imports System
  2. Imports Autodesk.AutoCAD.Runtime
  3. Imports Autodesk.AutoCAD.ApplicationServices
  4. Imports Autodesk.AutoCAD.DatabaseServices
  5. Imports Autodesk.AutoCAD.Geometry
  6. Imports Autodesk.AutoCAD.EditorInput
  7.  
  8. Imports System.ComponentModel
  9. Imports System.Collections.Specialized
  10. Imports System.Collections.ObjectModel
  11. Imports System.Linq
  12.  
  13. <Assembly: CommandClass(GetType(tmpdel.MyCommands))>
  14. <Assembly: ExtensionApplication(GetType(tmpdel.MyPlugin))>
  15.  
  16.  
  17. Namespace tmpdel
  18.     Public Class MyPlugin
  19.         Implements IExtensionApplication
  20.         Public Sub Initialize() Implements IExtensionApplication.Initialize
  21.         End Sub
  22.         Public Sub Terminate() Implements IExtensionApplication.Terminate
  23.         End Sub
  24.     End Class
  25.  
  26.     Public Class MyCommands
  27.  
  28.        
  29.         <CommandMethod("mytest2")> _
  30.         Public Sub MyCommand2()
  31.             showA(pickCurve) 'make sure you pick curve
  32.         End Sub
  33.  
  34.  
  35. ' this is found online test from one on developers. dont work well
  36. 'http://adndevblog.typepad.com/autocad/2012/05/how-to-detect-if-a-polyline-is-self-intersecting.html
  37.         <CommandMethod("SelfIntersectPline")> _
  38.         Public Shared Sub SelfIntersectPline()
  39.  
  40.             Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  41.             Dim db As Database = doc.Database
  42.             Dim ed As Editor = doc.Editor
  43.  
  44.             Dim peo As New PromptEntityOptions(vbLf & "Select Polyline: ")
  45.  
  46.             peo.SetRejectMessage(vbLf & "Must be a Polyline...")
  47.             peo.AddAllowedClass(GetType(Polyline), True)
  48.  
  49.             Dim per As PromptEntityResult = ed.GetEntity(peo)
  50.  
  51.             If per.Status <> PromptStatus.OK Then
  52.                 Return
  53.             End If
  54.  
  55.             Using Tx As Transaction = db.TransactionManager.StartTransaction()
  56.                 Dim polyline As Polyline = TryCast(per.ObjectId.GetObject(OpenMode.ForRead), Polyline)
  57.  
  58.                 Dim entities As New DBObjectCollection()
  59.                 polyline.Explode(entities)
  60.  
  61.                 For i As Integer = 0 To entities.Count - 1
  62.                     For j As Integer = i + 1 To entities.Count - 1
  63.                         Dim curve1 As Curve = TryCast(entities(i), Curve)
  64.                         Dim curve2 As Curve = TryCast(entities(j), Curve)
  65.  
  66.                         Dim points As New Point3dCollection()
  67.                         curve1.IntersectWith(curve2, Intersect.OnBothOperands, points, IntPtr.Zero, IntPtr.Zero)
  68.  
  69.                         For Each point As Point3d In points
  70.                             ' Make a check to skip the start/end points
  71.                             ' since they are connected vertices
  72.                             If point = curve1.StartPoint OrElse point = curve1.EndPoint Then
  73.                                 If point = curve2.StartPoint OrElse point = curve2.EndPoint Then
  74.                                     ' If two consecutive segments, then skip
  75.                                     If j = i + 1 Then
  76.                                         Continue For
  77.                                     End If
  78.                                 End If
  79.                             End If
  80.  
  81.                             ed.WriteMessage(vbLf & " - Intersection point: " + point.ToString())
  82.                         Next
  83.                     Next
  84.  
  85.                     ' Need to be disposed explicitely
  86.                     ' since entities are not DB resident
  87.                     entities(i).Dispose()
  88.                 Next
  89.             End Using
  90.         End Sub
  91. '----------------------end of developers part
  92.  
  93.  
  94.         Public Shared Function GetAreaCom(curve As Curve) As Double
  95.             Dim pl = curve.AcadObject
  96.             Return DirectCast(pl.Area, Double)
  97.         End Function        
  98.  
  99.         Public Sub showA(oid As ObjectId)
  100.             Dim area As Double
  101.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  102.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  103.             Using trans As OpenCloseTransaction = db.TransactionManager.StartOpenCloseTransaction()
  104.  
  105.                 Dim curve As Curve = trans.GetObject(oid, OpenMode.ForRead)
  106.                 'polyline area shows wrong value for self intersected polyline, however COM shows right, but slower
  107.                 If curve.GetRXClass.IsDerivedFrom(RXClass.GetClass(GetType(Xline))) Then
  108.                     area = 0
  109.                 Else
  110.                     If curve.GetRXClass = RXClass.GetClass(GetType(Polyline)) Then
  111.                         Dim cge As Curve3d = curve.GetGeCurve()
  112.                         Dim ci As New CurveCurveIntersector3d(cge, cge, curve.GetPlane.Normal)
  113.                        
  114.                         If ci.NumberOfIntersectionPoints() > 0 Or Not curve.Closed Then
  115.                             MsgBox("self-intersect or not closed")
  116.                             area = GetAreaCom(curve)
  117.                         Else
  118.                             area = curve.Area
  119.                         End If
  120.                         'this would be nice, but dont work
  121.                         '_area = cge.GetArea(curve.StartParam, curve.EndParam)
  122.                         cge.Dispose()
  123.                         ci.Dispose()
  124.                     Else
  125.                         area = curve.Area
  126.                     End If
  127.                 End If
  128.                 trans.Commit()
  129.             End Using
  130.             MsgBox(area.ToString)
  131.         End Sub        
  132.  
  133.         Public Function pickCurve() As ObjectId
  134.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  135.             Dim doc As Document = Application.DocumentManager.GetDocument(db)
  136.             Dim ed As Editor = doc.Editor
  137.             Dim peo As PromptEntityOptions = New PromptEntityOptions("Select a curve: ")
  138.             peo.SetRejectMessage("Selected object is not a curve.")
  139.             peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.Curve), False)
  140.             Dim per As PromptEntityResult = ed.GetEntity(peo)
  141.             If per.Status = PromptStatus.OK Then
  142.                 Return per.ObjectId
  143.             End If
  144.         End Function      
  145.     End Class
  146. End Namespace

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: polyline area
« Reply #14 on: December 22, 2014, 07:43:40 AM »
How much slower is using the dynamic version?
Revit 2019, AMEP 2019 64bit Win 10