Author Topic: angle from vector to UCS  (Read 8440 times)

0 Members and 1 Guest are viewing this topic.

nekitip

  • Guest
angle from vector to UCS
« on: December 24, 2014, 05:05:43 AM »
I'm trying to align 2d entity between two points, and then rotate relative to points.
OR if you like - align text to a single line.
The problem is text rotation, it all works in WCS, but not in 3d UCS and suddenly I have found myself in too many if then else, so I think there must be some simple solution.
closest to my solution is http://forums.autodesk.com/t5/net/how-can-i-read-rotation-of-a-dbtext-in-the-ucs/td-p/4379988 but this results in somewhat unprecise result by about two degrees (almost always)
this code is what i have tried to do following post on this forum, and it's sort of simplified function to ilustrate my problem.
Code - vb.net: [Select]
  1. Public Shared Function getAngleToXaxe(curve As Curve) As Double
  2.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  3.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  4.             Dim ed As Editor = doc.Editor
  5.            
  6.             Dim UCS As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
  7.             Dim OcsPlane As Plane = New Plane(Point3d.Origin, UCS.Zaxis)
  8.             Dim OCS As CoordinateSystem3d = Matrix3d.PlaneToWorld(OcsPlane).CoordinateSystem3d
  9.             Dim ucsRotation As Double = OCS.Xaxis.GetAngleTo(UCS.Xaxis, UCS.Zaxis)
  10.  
  11.             Dim angleRAD As Double = curve.StartPoint.GetVectorTo(curve.EndPoint).AngleOnPlane(curve.GetPlane)
  12.  
  13.             angleRAD = angleRAD - ucsRotation
  14.             'If angleRAD > Math.PI / 2 AndAlso angleRAD < 3 * Math.PI / 2 Then angleRAD = angleRAD - Math.PI 'see if the text looks right
  15.             Return angleRAD
  16.         End Function

EDIT:
hmm.... seems to me that I would need something like: give me angle for text that is aligned to UCS XY plane projection of line
« Last Edit: December 24, 2014, 05:35:23 AM by nekitip »

nekitip

  • Guest
Re: angle from vector to UCS
« Reply #1 on: December 28, 2014, 06:12:05 AM »
So, I reworked the code a bit.
This is a working solution to get the rotation of 2d entities (text, block...) aligned to two points. This works in 2d in any UCS.
However, still not working in 3d.
On paper and mathematically, this problem looks standard, but still not able to actually get this in 3d to work in a simple manner.
So, if anyone knows...

Code - vb.net: [Select]
  1.         Public Shared Function getAngleToXaxe(startpoint As Point3d, endpoint As Point3d) As Double
  2.  
  3.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  4.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  5.             Dim ed As Editor = doc.Editor
  6.  
  7.             Dim UCS As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
  8.             Dim OcsPlane As Plane = New Plane(Point3d.Origin, UCS.Zaxis)
  9.             Dim OCS As CoordinateSystem3d = Matrix3d.PlaneToWorld(OcsPlane).CoordinateSystem3d
  10.             Dim ucsRotation As Double = OCS.Xaxis.GetAngleTo(UCS.Xaxis)
  11.  
  12.             'Dim ds = ucsRotation * 180 / Math.PI
  13.  
  14.             Dim vec1 As Vector3d = startpoint.GetVectorTo(endpoint)
  15.             Dim aa As Double = vec1.AngleOnPlane(OcsPlane)
  16.  
  17.             Dim angleRAD As Double = aa - ucsRotation
  18.             If angleRAD > Math.PI / 2 AndAlso angleRAD < 3 * Math.PI / 2 Then angleRAD = angleRAD - Math.PI
  19.  
  20.             OcsPlane.Dispose()
  21.             Return angleRAD
  22.  
  23.         End Function

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: angle from vector to UCS
« Reply #2 on: December 28, 2014, 08:16:25 AM »
Hi,

I'm not certain to understand your request, but the following code works for me to align a text to a line (or its projection on UCS XY plane).

Code - C#: [Select]
  1.         [CommandMethod("test")]
  2.         public void test()
  3.         {
  4.             var doc = Application.DocumentManager.MdiActiveDocument;
  5.             var db = doc.Database;
  6.             var ed = doc.Editor;
  7.  
  8.             var peo = new PromptEntityOptions("\nSelect Line: ");
  9.             peo.SetRejectMessage("Only a Line.");
  10.             peo.AddAllowedClass(typeof(Line), true);
  11.             var per = ed.GetEntity(peo);
  12.             if (per.Status != PromptStatus.OK) return;
  13.  
  14.             var normal = ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis;
  15.  
  16.             using (Transaction tr = db.TransactionManager.StartTransaction())
  17.             {
  18.                 var space = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  19.                 var line = (Line)tr.GetObject(per.ObjectId, OpenMode.ForRead);
  20.                 var text = new DBText();
  21.                 text.TextString = "this is a test";
  22.                 text.Rotation = GetRotation(line.StartPoint.GetVectorTo(line.EndPoint), normal);
  23.                 text.Normal = normal;
  24.                 text.Position = line.StartPoint;
  25.                 space.AppendEntity(text);
  26.                 tr.AddNewlyCreatedDBObject(text, true);
  27.                 tr.Commit();
  28.             }
  29.         }
  30.  
  31.         public double GetRotation(Vector3d vector, Vector3d normal)
  32.         {
  33.             var plane = new Plane(Point3d.Origin, normal);
  34.             var ocsXAxis = Vector3d.XAxis.TransformBy(Matrix3d.PlaneToWorld(plane));
  35.             return ocsXAxis.GetAngleTo(vector.ProjectTo(normal, normal), normal);
  36.         }
« Last Edit: December 28, 2014, 09:11:15 AM by gile »
Speaking English as a French Frog

nekitip

  • Guest
Re: angle from vector to UCS
« Reply #3 on: December 28, 2014, 10:29:01 AM »
Thank you Gile for your anwser, your help is always appriciated.
Short:
The idea is that user will see text appear to be aligned to line in current UCS

Longer:
Not that I really need this, just thought it would look nice to have it, and also, puzzles me a lot why I can't think of what's wrong, and here is what it is:
To get a rotation angle for a new 2d entity (block, text, mtext...) in a way that ent creation plane is always UCS XY (this is, I think, always the case), and rotation so when looking from that same UCS XY plane (PLAN command) looks like text is parallel to projection of 3d object (line). Or if you like - if line is 3d object, when looked at 2d UCS XY plane, text will look aligned. Your solution (if I converted it to VB.NET right, also has some issues, though different then mine). Please, take a look at image.

On this test, a line 10,10 rectancle is drawn. All in 2d. When Line is given 10,10,10 on endpoint, command TEST is no longer aligning text this way.

Mine routine works in this case (any object 3d or 2d), but kind of sticks to WCS
I think yours work as long line inquired is in the same plane XY plane as UCS.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: angle from vector to UCS
« Reply #4 on: December 28, 2014, 11:19:42 AM »
Hi,

I edited the upper code after you copied it.

Look at the GetRotation() method last line. It have to be:
Code - C#: [Select]
  1. return ocsXAxis.GetAngleTo(vector.ProjectTo(normal, normal), normal);
instead of:
Code - C#: [Select]
  1. return ocsXAxis.GetAngleTo(vector, normal);
Speaking English as a French Frog

nekitip

  • Guest
Re: angle from vector to UCS
« Reply #5 on: December 28, 2014, 11:33:51 AM »
Wow, that's it!  :-)
Also, is plane in need of disposing? For example, vectors, points don't have dispose method, but plane have.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: angle from vector to UCS
« Reply #6 on: December 28, 2014, 11:48:20 AM »
Also, is plane in need of disposing? For example, vectors, points don't have dispose method, but plane have.

You can Dispose the Plane, but as far as I know, this is not mandatory as a Plane is a geometric object (like a Vector or a Point) which cannot be Database resident.
Speaking English as a French Frog

nekitip

  • Guest
Re: angle from vector to UCS
« Reply #7 on: December 28, 2014, 12:30:39 PM »
I'll share a chunk of my code with what Gile posted (a bit modified)
Code allows to enter text next to curve, in the midpoint, and also, if you have a polyline, then in the middle of the middle segment of polyline.
The idea is for everyone to contribute.

TODO:
-choose if align 2d entity (mtext) to object using UCS.Z as normal
-two more types of polyline
-allow 2d object to be a block with attribute
-allow 2d objects to be on each segment (not really important for this sample)
-decoupling and flexible code

the way this also may be done (and not the way i choose) is by exploding polyline to dbobjectcollection, then for each of objects find..., but what if polyline is made of polyline (have not tried this approach)

I hope this will help all of us.

(note, the best .net code converter I found here http://converter.telerik.com/)

Code - vb.net: [Select]
  1. <CommandMethod("test")> _
  2.         Public Sub test()
  3.             Dim doc = Application.DocumentManager.MdiActiveDocument
  4.             Dim db = doc.Database
  5.             Dim ed = doc.Editor
  6.  
  7.             Dim peo = New PromptEntityOptions(vbLf & "Select Line: ")
  8.             peo.SetRejectMessage("Only a Line.")
  9.             peo.AddAllowedClass(GetType(Line), True)
  10.             peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline), True) 'sometimes, namespace colision (DatabaseServices and GraphicsInterface)
  11.             Dim per = ed.GetEntity(peo)
  12.             If per.Status <> PromptStatus.OK Then
  13.                 Return
  14.             End If
  15.  
  16.             insertText(per.ObjectId, True, 1, "test")
  17.         End Sub
  18.  
  19.  
  20.         Public Shared Sub insertText(oid As ObjectId, aligntoUCS As Boolean, objecttype As Integer, text As String)
  21.  
  22.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  23.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  24.             Dim ed As Editor = doc.Editor
  25.             Dim ucs As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
  26.             Dim plane As Plane = New Plane(Point3d.Origin, ucs.Zaxis)
  27.             Dim normal As Vector3d = ucs.Zaxis
  28.  
  29.             Using l As DocumentLock = doc.LockDocument()
  30.                 Using trans As Transaction = db.TransactionManager.StartTransaction()
  31.                     Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  32.                     Dim curentBtrID As ObjectId = db.CurrentSpaceId
  33.                     Dim btr As BlockTableRecord = trans.GetObject(curentBtrID, OpenMode.ForWrite)
  34.  
  35.                     Dim ent As Entity = trans.GetObject(oid, OpenMode.ForRead)
  36.  
  37.                     Using acText As MText = New MText() 'new object, use using?
  38.                         'http://stackoverflow.com/questions/20201600/autocad-undefined-shape-style-dialog-crashes
  39.                         acText.SetDatabaseDefaults()
  40.                         acText.Contents = text
  41.                         Dim insPoint3d As Point3d = getInsPoint(ent, objecttype)
  42.                         acText.Location = insPoint3d
  43.                         acText.Attachment = AttachmentPoint.BottomCenter
  44.  
  45.                         If objecttype = 1 Then
  46.                             Dim curve As Curve = DirectCast(ent, Curve)
  47.  
  48.                             'find rotation of segment where point is, and in midpoint of this segment, rotate text
  49.                             'rotate based on previus and next segment point
  50.                             If curve.GetRXClass = acbusiness.plineType Then
  51.                                 Dim pline As Autodesk.AutoCAD.DatabaseServices.Polyline = DirectCast(curve, Autodesk.AutoCAD.DatabaseServices.Polyline)
  52.  
  53.                                 For i = 0 To pline.NumberOfVertices - 1
  54.                                     Dim segpar As Double
  55.  
  56.                                     If pline.OnSegmentAt(i, insPoint3d.Convert2d(plane), segpar) Then
  57.                                         Dim midpoint As Point3d = pline.GetPointAtParameter(i + 0.5)
  58.                                         Dim pstart As Point3d = pline.GetPointAtParameter(i)
  59.                                         Dim pend As Point3d = pline.GetPointAtParameter(i + 1)
  60.  
  61.                                         ''rotation angle for text
  62.                                         acText.Location = midpoint
  63.                                         If aligntoUCS Then
  64.                                             acText.Rotation = getAngleToXaxe(pstart, pend, normal)
  65.                                         Else
  66.                                             'TODO align to 3d object, and a plane with normal of UCS.Z
  67.                                         End If
  68.                                         Exit For
  69.                                     End If
  70.                                 Next
  71.  
  72.                                 'two more types of polyline
  73.  
  74.                             ElseIf curve.GetRXClass = RXClass.GetClass(GetType(Polyline2d)) Then
  75.                                 Dim p2d As Polyline2d = DirectCast(curve, Polyline2d)
  76.                                 'Use foreach to get each contained vertex
  77.                                 For Each vId As ObjectId In p2d
  78.                                     Dim v2d As Vertex2d = trans.GetObject(vId, OpenMode.ForRead)
  79.                                     ed.WriteMessage(vbLf + v2d.Position.ToString())
  80.                                 Next
  81.  
  82.                             ElseIf curve.GetRXClass = RXClass.GetClass(GetType(Polyline3d)) Then
  83.                                 'If an old-style, 3D polyline
  84.                                 Dim p3d As Polyline3d = DirectCast(curve, Polyline3d)
  85.                                 'Use foreach to get each contained vertex
  86.                                 For Each vId As ObjectId In p3d
  87.                                     Dim v3d As PolylineVertex3d = trans.GetObject(vId, OpenMode.ForRead)
  88.                                     ed.WriteMessage(vbLf + v3d.Position.ToString())
  89.                                 Next
  90.  
  91.                             Else
  92.                                 acText.Rotation = getAngleToXaxe(curve.StartPoint, curve.EndPoint, normal)
  93.                             End If
  94.  
  95.                         End If
  96.                         btr.AppendEntity(acText)
  97.                         trans.AddNewlyCreatedDBObject(acText, True)
  98.                     End Using
  99.  
  100.                     plane.Dispose()
  101.                     trans.Commit()
  102.                 End Using
  103.             End Using
  104.             Autodesk.AutoCAD.ApplicationServices.Application.UpdateScreen()
  105.         End Sub
  106.  
  107.         Public Shared Function getAngleToXaxe(startpoint As Point3d, endpoint As Point3d, normal As Vector3d) As Double
  108.             Dim vector As Vector3d = startpoint.GetVectorTo(endpoint)
  109.             Dim plane = New Plane(Point3d.Origin, normal)
  110.             Dim ocsXAxis = Vector3d.XAxis.TransformBy(Matrix3d.PlaneToWorld(plane))
  111.             'to look little better, maybe option not to do it here
  112.             Dim angleRAD As Double = ocsXAxis.GetAngleTo(vector.ProjectTo(normal, normal), normal)
  113.             If angleRAD > Math.PI / 2 AndAlso angleRAD < 3 * Math.PI / 2 Then angleRAD = angleRAD - Math.PI
  114.             Return angleRAD
  115.         End Function
  116.  
  117.         Public Shared Function getInsPoint(ent As Entity, entclass As Integer) As Point3d
  118.             Select Case entclass
  119.                 Case 1
  120.                     Dim c As Curve = DirectCast(ent, Curve)
  121.                     If c.StartPoint = c.EndPoint Then
  122.                         Return c.StartPoint
  123.                     End If
  124.                     Dim d1 As Double = c.GetDistanceAtParameter(c.StartParam)
  125.                     Dim d2 As Double = c.GetDistanceAtParameter(c.EndParam)
  126.                     Dim r As Point3d = c.GetPointAtDist(d1 + ((d2 - d1) / 2.0))
  127.                     Return r
  128.                 Case 2
  129.                     Dim h As Hatch = DirectCast(ent, Hatch)
  130.                     Dim x As Double = (h.Bounds.Value.MaxPoint.X + h.Bounds.Value.MinPoint.X) / 2
  131.                     Dim y As Double = (h.Bounds.Value.MaxPoint.Y + h.Bounds.Value.MinPoint.Y) / 2
  132.                     Dim z As Double = (h.Bounds.Value.MaxPoint.Z + h.Bounds.Value.MinPoint.Z) / 2
  133.  
  134.                     Dim rp As New Point3d(x, y, z)
  135.                     Return rp
  136.             End Select
  137.  
  138.         End Function
  139.  

nekitip

  • Guest
Re: angle from vector to UCS
« Reply #8 on: January 25, 2015, 06:11:17 PM »
Ok, I have done some job.
still don't know if text insertion is good (alignement), but here is what I find out.
-seems to be that there is no need to matrix transformations to get angle of vectors
-text and mtext are using different rotations
-a lot of code that can be put as extension, but don't know if it is easier to reuse it and understand it this way

Here is what needs to be done:
-insert block sub
-position centroid (to place text in the middle of)
-text object aligned on planar object (text normal not ucs normal)
-find places where precision might get into way (to find out insertion points) to get error values

Here is the code for now.
Whoever is willing to contribute, please feel free.

EDIT:
i have added a lot of code, and this is almost complerte solution
still I have my worries, and some of them and things to look at are:
-is it possible that polyline contains point or something else that pops up when you explode it and is not curve (other then line, arc, circle)?
-midpoint routine, is it safe for precission problems? (I'm thinking about hidden tolerance issues that I have not even looked at)
-regioncentroid, this is kind of my approach, and i've seen some variant with getting centroid from arch. Is there a better way?
-cleaner close region code in getpolycentroid (not sure if polyline.close method is good in this scenario since it may change user object, and we just want to inform)

other than that, whoever is willing to contribute, here are two more things to (easily) do, since problem of rotation is more or less solved.
TODO: insert block instead of DBTEXT od MTEXT
TODO: text aligned 3D to object (plane is a polyline plane, don't know what to do with line)
TODO: my worries of wrongly disposed objects are hounting me, don't know if this code is safe

EDIT 2
in toMostReadable, added case where text is exactly vertical.

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("test")> _
  29.         Public Sub test()
  30.  
  31.             Dim oid As ObjectId = pickCurve()
  32.             If Not oid.IsNull Then
  33.                 insertTextToObject.insertNextTo(oid, insertTextToObject.rotate2d.Centroid, 1, "test")
  34.             End If
  35.         End Sub
  36.  
  37.         Public Function pickCurve() As ObjectId
  38.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  39.             Dim doc As Document = Application.DocumentManager.GetDocument(db)
  40.             Dim ed As Editor = doc.Editor
  41.             Dim peo As PromptEntityOptions = New PromptEntityOptions("Select a curve: ")
  42.             peo.SetRejectMessage("Selected object is not a curve.")
  43.             'peo.AddAllowedClass(GetType(Line), True)
  44.             peo.AddAllowedClass(GetType(Autodesk.AutoCAD.DatabaseServices.Curve), False)
  45.             Dim per As PromptEntityResult = ed.GetEntity(peo)
  46.             If per.Status = PromptStatus.OK Then
  47.                 Return per.ObjectId
  48.             End If
  49.         End Function
  50.  
  51.     End Class
  52.     Public Class insertTextToObject
  53.  
  54.         Public Enum rotate2d
  55.             No = 0
  56.             Aligned = 1
  57.             Aligned3D = 2
  58.             Centroid = 3
  59.         End Enum
  60.  
  61.         Private Class insParameters
  62.             Private _point As Point3d
  63.             Private _angle As Double
  64.             Public Property point As Point3d
  65.                 Get
  66.                     Return _point
  67.                 End Get
  68.                 Set(value As Point3d)
  69.                     _point = value
  70.                 End Set
  71.             End Property
  72.             Public Property angle As Double
  73.                 Get
  74.                     Return _angle
  75.                 End Get
  76.                 Set(value As Double)
  77.                     _angle = value
  78.                 End Set
  79.             End Property
  80.         End Class
  81.  
  82.         Public Shared Sub insertNextTo(oid As ObjectId, rotatePolicy As rotate2d, objecttype As Integer, text As String)
  83.  
  84.             Dim db As Database = HostApplicationServices.WorkingDatabase()
  85.             Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.GetDocument(db)
  86.             Dim ed As Editor = doc.Editor
  87.             Dim ucs As CoordinateSystem3d = ed.CurrentUserCoordinateSystem.CoordinateSystem3d
  88.             Dim normal As Vector3d = ucs.Zaxis
  89.  
  90.             Using l As DocumentLock = doc.LockDocument()
  91.                 Using trans As Transaction = db.TransactionManager.StartTransaction()
  92.                     Dim bt As BlockTable = trans.GetObject(db.BlockTableId, OpenMode.ForRead)
  93.                     Dim curentBtrID As ObjectId = db.CurrentSpaceId
  94.                     Dim btr As BlockTableRecord = trans.GetObject(curentBtrID, OpenMode.ForWrite)
  95.  
  96.                     'TODO for each in a list of objects loop may start here
  97.                     Dim ent As Entity = trans.GetObject(oid, OpenMode.ForRead)
  98.                     Dim inspars As New insParameters
  99.                     If objecttype = 1 Then
  100.                         Dim curve As Curve = DirectCast(ent, Curve)
  101.                         inspars = getCurveInsPars(rotatePolicy, curve, normal)
  102.                     End If
  103.                     'some different type of object
  104.                     If objecttype = 2 Then
  105.                         inspars.point = getBoxCenterPoint3d(ent)
  106.                     End If
  107.  
  108.                     'MTEXT is expecting UCS relative angle, but DBTEXT is expecting WCS
  109.                     insertText(btr, trans, inspars.point, toMostReadable(inspars.angle, ucs, False), text, normal)
  110.                     insertMText(btr, trans, inspars.point, toMostReadable(inspars.angle, ucs, True), text, normal)
  111.                     'TODO:insertBlock
  112.  
  113.                     'end of for each loop
  114.                     trans.Commit()
  115.                 End Using
  116.             End Using
  117.  
  118.             Autodesk.AutoCAD.ApplicationServices.Application.UpdateScreen()
  119.         End Sub
  120.  
  121.         Public Shared Sub insertText(btr As BlockTableRecord, trans As Transaction, insPoint3d As Point3d, rotation As Double, text As String, normal As Vector3d)
  122.             Using acText As DBText = New DBText() 'new object, use using?
  123.                 acText.Normal = normal
  124.                 acText.TextString = text
  125.                 acText.Rotation = rotation
  126.                 acText.Justify = AttachmentPoint.BottomCenter
  127.                 acText.AlignmentPoint = insPoint3d
  128.                 btr.AppendEntity(acText)
  129.                 trans.AddNewlyCreatedDBObject(acText, True)
  130.             End Using
  131.         End Sub
  132.  
  133.         Public Shared Sub insertMText(btr As BlockTableRecord, trans As Transaction, insPoint3d As Point3d, rotation As Double, text As String, normal As Vector3d)
  134.             Using acText As MText = New MText() 'new object, use using?
  135.                 'http://stackoverflow.com/questions/20201600/autocad-undefined-shape-style-dialog-crashes
  136.                 acText.Normal = normal
  137.                 acText.Contents = text
  138.                 acText.Rotation = rotation
  139.                 acText.Attachment = AttachmentPoint.BottomCenter
  140.                 acText.Location = insPoint3d
  141.                 btr.AppendEntity(acText)
  142.                 trans.AddNewlyCreatedDBObject(acText, True)
  143.             End Using
  144.         End Sub
  145.  
  146.  
  147.         Private Shared Function getCurveInsPars(rotate As rotate2d, curve As Curve, normal As Vector3d) As insParameters
  148.  
  149.             Dim plineType As RXClass = RXClass.GetClass(GetType(Polyline))
  150.             Dim plineType2d As RXClass = RXClass.GetClass(GetType(Polyline2d))
  151.             Dim plineType3d As RXClass = RXClass.GetClass(GetType(Polyline3d))
  152.             Dim curveType As RXClass = RXClass.GetClass(GetType(Curve))
  153.  
  154.             curveType = curve.GetRXClass
  155.             Dim inspars As New insParameters
  156.             inspars.point = getCurveMidpoint(curve)
  157.  
  158.             Select Case rotate
  159.                 Case rotate2d.No
  160.                     inspars.angle = 0
  161.                 Case rotate2d.Aligned
  162.                     If curveType = plineType Or curveType = plineType2d Or curveType = plineType3d Then
  163.                         'we bet everything is OK and point is on Polyline for sure.
  164.                         Dim segment As Curve = tryGetOnPolySegment(curve, inspars.point)
  165.                         If segment IsNot Nothing Then
  166.                             inspars.point = getCurveMidpoint(segment)
  167.                             inspars.angle = getAngleToXaxe(segment.StartPoint, segment.EndPoint, normal)
  168.                         End If
  169.                         segment.Dispose()
  170.                     Else
  171.                         inspars.angle = getAngleToXaxe(curve.StartPoint, curve.EndPoint, normal)
  172.                     End If
  173.                 Case rotate2d.Aligned3D
  174.                     'TODO
  175.                     inspars.angle = 0
  176.  
  177.                 Case rotate2d.Centroid
  178.                     inspars.angle = 0
  179.                     inspars.point = getPolyCentroid(curve)
  180.             End Select
  181.  
  182.             Return inspars
  183.         End Function
  184.  
  185.         Public Shared Function getCurveMidpoint(curve As Curve) As Point3d
  186.             If curve.StartPoint = curve.EndPoint Then
  187.                 Return curve.StartPoint
  188.             End If
  189.             Dim d1 As Double = curve.GetDistanceAtParameter(curve.StartParam)
  190.             Dim d2 As Double = curve.GetDistanceAtParameter(curve.EndParam)
  191.             Return curve.GetPointAtDist(d1 + ((d2 - d1) / 2))
  192.         End Function
  193.  
  194.         Public Shared Function getRegionCentroid(region As Region) As Point3d
  195.             Dim centroidPt As Point3d
  196.             Dim solidPlus As New Solid3d()
  197.             Dim solidMinus As New Solid3d()
  198.             solidPlus.Extrude(region, 1, 0)
  199.             solidMinus.Extrude(region, -1, 0)
  200.             Dim connectline As New Line(solidPlus.MassProperties.Centroid, solidMinus.MassProperties.Centroid)
  201.             centroidPt = connectline.GetPointAtParameter(0.5)
  202.             connectline.Dispose()
  203.             solidPlus.Dispose()
  204.             solidMinus.Dispose()
  205.             Return centroidPt
  206.         End Function
  207.  
  208.         ''' <summary>
  209.         ''' Return centroid of polyline (if possible for polyline to convert to region).
  210.         ''' If not (polyline is selfintersecting), return center of the polyline bounding box.
  211.         ''' </summary>
  212.         ''' <param name="curve">Polyline from which to create region and.</param>
  213.         ''' <returns></returns>
  214.         ''' <remarks></remarks>
  215.         Public Shared Function getPolyCentroid(curve As Curve) As Point3d
  216.             'it is expected that point is on curve, and curve is type of polyline, or polyline2d, or polyline3d
  217.             Dim centroidPt As Point3d
  218.             Dim dbobjects As New DBObjectCollection
  219.             Dim tmpclosingling As New Line
  220.             dbobjects.Add(curve)
  221.             'curve.Explode(dbobjects)
  222.             If curve.Closed = False Then
  223.                 'do not change user elements and add temp line to try to create region (otherwise fails if not closed)
  224.                 'now only selfintersected polylines produce errors
  225.                 tmpclosingling.StartPoint = curve.StartPoint
  226.                 tmpclosingling.EndPoint = curve.EndPoint
  227.                 dbobjects.Add(tmpclosingling)
  228.             End If
  229.             Try
  230.                 Dim r As Region = Region.CreateFromCurves(dbobjects)(0)
  231.                 centroidPt = getRegionCentroid(r)
  232.                 r.Dispose()
  233.             Catch
  234.                 'polyline is selfintersected
  235.                 centroidPt = getBoxCenterPoint3d(curve)
  236.             End Try
  237.             tmpclosingling.Dispose()
  238.             dbobjects.Remove(curve)
  239.             dbobjects.Dispose()
  240.             Return centroidPt
  241.         End Function
  242.  
  243.         Public Shared Function getBoxCenterPoint3d(ent As Entity) As Point3d
  244.             Dim x As Double = (ent.Bounds.Value.MaxPoint.X + ent.Bounds.Value.MinPoint.X) / 2
  245.             Dim y As Double = (ent.Bounds.Value.MaxPoint.Y + ent.Bounds.Value.MinPoint.Y) / 2
  246.             Dim z As Double = (ent.Bounds.Value.MaxPoint.Z + ent.Bounds.Value.MinPoint.Z) / 2
  247.             Return New Point3d(x, y, z)
  248.         End Function
  249.  
  250.         'rotation helpers
  251.  
  252.         ''' <summary>
  253.         ''' Returns angle of vector between two points and X axe on a plain defined with normal.
  254.         ''' </summary>
  255.         ''' <param name="startpoint">First point of directional vector</param>
  256.         ''' <param name="endpoint">Second point of directional vector</param>
  257.         ''' <param name="normal">Plane normal</param>
  258.         ''' <returns>Angle to X axe, relative to WCS</returns>
  259.         ''' <remarks>Some objects use this angle, some UCS relative angle</remarks>
  260.         Public Shared Function getAngleToXaxe(startpoint As Point3d, endpoint As Point3d, normal As Vector3d) As Double
  261.             Dim vector As Vector3d = startpoint.GetVectorTo(endpoint)
  262.             Return getAngleToXaxe(vector, normal)
  263.         End Function
  264.  
  265.         ''' <summary>
  266.         ''' Returns angle of vector and X axe on a plain defined with normal.
  267.         ''' </summary>
  268.         ''' <param name="vector">Directional vector</param>
  269.         ''' <param name="normal">Plane normal</param>
  270.         ''' <returns>Angle to X axe, relative to WCS</returns>
  271.         ''' <remarks>Some objects use this angle, some UCS relative angle</remarks>
  272.         Public Shared Function getAngleToXaxe(vector As Vector3d, normal As Vector3d) As Double
  273.             Dim ocsplane = New Plane(Point3d.Origin, normal)    'zaxis
  274.             Return vector.AngleOnPlane(ocsplane)                'angle looked from plane normal down
  275.         End Function
  276.  
  277.         ''' <summary>
  278.         ''' Returns CCW angle between UCS and WCS X axe,
  279.         ''' rotation looking from top op zaxis to plane.
  280.         ''' </summary>
  281.         ''' <param name="ucs">Any UCS</param>
  282.         ''' <returns>CCW Angle beteen Wcs and Ucs X axe.</returns>
  283.         ''' <remarks></remarks>
  284.         Public Shared Function getUcsAngleX(ucs As CoordinateSystem3d)
  285.             Return ucs.Xaxis.AngleOnPlane(New Plane(Point3d.Origin, ucs.Zaxis)) 'rotation looking from top op zaxis to plane
  286.         End Function
  287.  
  288.         ''' <summary>
  289.         ''' Text should be written to be able to be read from the bottom of paper of from the right side of paper.
  290.         ''' This means mostly text is up or left.
  291.         ''' </summary>
  292.         ''' <param name="angleRAD">Angle in WCS</param>
  293.         ''' <param name="ucs">Any UCS</param>
  294.         ''' <param name="relativeToUcs">Zero angle is 0 WCS or 0 UCS</param>
  295.         ''' <returns></returns>
  296.         ''' <remarks></remarks>
  297.         Public Shared Function toMostReadable(angleRAD As Double, ucs As CoordinateSystem3d, relativeToUcs As Boolean) As Double
  298.             'will return most readable rotation to text
  299.             'for wcs rotation angle, add ucsangle after this process (DBtext), else relative to ucs (Mtext)
  300.             Dim ucsAngle As Double = getUcsAngleX(ucs)
  301.             angleRAD = angleRAD - ucsAngle
  302.             If angleRAD > Math.PI / 2 AndAlso angleRAD <= 3 * Math.PI / 2 Then angleRAD = angleRAD - Math.PI
  303.             If relativeToUcs Then
  304.                 Return angleRAD
  305.             Else
  306.                 Return angleRAD + ucsAngle
  307.             End If
  308.         End Function
  309.  
  310.         ''' <summary>
  311.         ''' Returns polyline segment over point for any sort of polyline (polyline, poly2d, poly3d).
  312.         ''' Must
  313.         ''' </summary>
  314.         ''' <param name="curve">Any of the three types of polyline, but no other types of curve.</param>
  315.         ''' <param name="point">Point over segment</param>
  316.         ''' <returns>New Curve, non DB (ObjectID=Null). Should be disposed or added to DB.</returns>
  317.         ''' <remarks></remarks>
  318.         Public Shared Function tryGetOnPolySegment(curve As Curve, point As Point3d) As Curve
  319.             'it is expected that point is for sure somewhere on curve, and curve is type of polyline, or polyline2d, or polyline3d
  320.             Dim curveType = RXClass.GetClass(GetType(Curve))
  321.             Dim dbobjects As New DBObjectCollection
  322.  
  323.             curve.Explode(dbobjects)
  324.             For Each o As DBObject In dbobjects
  325.                 If o.GetRXClass.IsDerivedFrom(curveType) Then
  326.                     Dim segment As Curve = DirectCast(o, Curve)
  327.                     Dim segmentGE As Curve3d = segment.GetGeCurve()
  328.                     If segmentGE.IsOn(point) Then
  329.                         dbobjects.Remove(segment)
  330.                         segmentGE.Dispose()
  331.                         dbobjects.Dispose()
  332.                         Return segment
  333.                     End If
  334.                     segmentGE.Dispose()
  335.                     segment.Dispose()
  336.                 End If
  337.             Next
  338.             'should never execute, because point is for sure on some segment
  339.             dbobjects.Dispose()
  340.             Return Nothing
  341.         End Function
  342.  
  343.     End Class
  344. End Namespace
  345.  
« Last Edit: January 28, 2015, 06:08:23 AM by nekitip »