How to Trim a Line From An Ellipse (AutoCAD 2014) - vb.net

Goal
To trim a line in an ellipse that goes to it's center. The portion of the line that enters the ellipse should be trimmed off.
This is the untrimmed ellipse
This is the trimmed ellipse, the goal of this question
Attempt
CreateConveyorNameEllipse(AcadDoc)
Public Function CreateConveyorNameEllipse(ByRef AcadDoc As Document) As ObjectId
Dim returnId As ObjectId
Dim db As Database = AcadDoc.Database
Dim x As Vector3d = db.Ucsxdir
Dim y As Vector3d = db.Ucsydir
Dim normalVec As Vector3d = x.CrossProduct(y)
Dim axisvec As Vector3d = normalVec.GetNormal()
Dim CenterPoint As New Point3d(Me.StartPoint.X + 50, Me.StartPoint.Y + 40, 0)
Dim aEllipse As Ellipse
aEllipse = New Ellipse(CenterPoint, axisvec, New Vector3d(30, 0, 0), 0.35, 0, Math.PI * 2)
aEllipse.SetDatabaseDefaults()
returnId = Utils.CreateAcadObject(AcadDoc, aEllipse)
aEllipse.Dispose()
Utils.regenLayers()
Return returnId
End Function
CreateConveyorEllipseLineConnection(AcadDoc)
Public Function CreateConveyorEllipseLineConnection(ByRef AcadDoc As Document) As ObjectId
Dim returnId As ObjectId
Dim CenterPoint As New Point3d(Me.StartPoint.X + 50, Me.StartPoint.Y + 40, 0)
Dim aLine As Line
aLine = New Line(Me.StartPoint, CenterPoint)
aLine.SetDatabaseDefaults()
returnId = Utils.CreateAcadObject(AcadDoc, aLine)
aLine.Dispose()
Utils.regenLayers()
Return returnId
End Function
CreateAcadObject(AcadDoc, AcadObj)
Public Function CreateAcadObject(ByRef acDoc As Document, ByRef acObj As Object) As ObjectId
Dim objId As ObjectId
Dim acCurDb As Database = acDoc.Database 'Get the current database
Dim acBlkTbl As BlockTable
Dim acBlkTblRec As BlockTableRecord
Using lock As DocumentLock = acDoc.LockDocument
'Start a transaction
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
'Open Model space for write
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
acObj.SetDatabaseDefaults()
'Add the object to the drawing
objId = acBlkTblRec.AppendEntity(acObj)
acTrans.AddNewlyCreatedDBObject(acObj, True)
'Commit the changes and dispose of the transaction
acTrans.Commit()
End Using
End Using
Return objId
End Function
I'm not quite sure how to apply the trim to the line. I've seen some IntersectWith methods but couldn't get it to work yet. I'll be working on this meanwhile and if I find the answer I'll be sure to post it here.

You can take advantage of a few cool methods dealing with curves to handle this:
Private Shared Function TrimmedLine(line As Line, ent As Entity) As Line
If line Is Nothing Then
Throw New ArgumentNullException("line")
End If
' Original line is returned since there's nothing to break it
If ent Is Nothing Then Return line
Dim extPoints = New Point3dCollection()
Try
line.IntersectWith(ent, Intersect.ExtendArgument, extPoints, IntPtr.Zero, IntPtr.Zero)
' Original line gets returned since it doesn't intersect
If extPoints.Count = 0 Then Return line
Dim splitLines = line.GetSplitCurves(extPoints)
' Not sure when this would fail, investigate.
If splitLines.Count = 0 Then Return Nothing
' Return the outer line in this case
Return DirectCast(splitLines(0), Line)
Catch ex As Autodesk.AutoCAD.Runtime.Exception
System.Diagnostics.Debug.Write(ex.Message)
Throw
End Try
End Function

Related

Image.Save() throws GDI+ exception for image derived from bitmap

I have two classes: ChartObject & GrowthChartPane.
ChartObject has a method, GetChart(), that converts a bitmap to a Drawing.Image that is returned.
Public Function GetChart() As Drawing.Image
Dim chartImage As Drawing.Image
Dim gr As Graphics
Dim brush As Brush = Brushes.Blue
If m_bIsBoy Then
brush = Brushes.Red
End If
Using fs As New FileStream(m_sChartImageFileName, FileMode.Open, FileAccess.Read)
chartImage = Bitmap.FromStream(fs)
gr = Graphics.FromImage(chartImage)
End Using
For Each Point As PointObject In m_lstUpperPoints
If Not Point.IsVisible Then Continue For
Dim x As Integer = m_objUpperHorizontalAxis.ValueToPoint(Point.HorizontalValue)
Dim y As Integer = m_objUpperVerticalAxis.ValueToPoint(Point.VerticalValue)
gr.FillEllipse(brush, New RectangleF(x - 4, y - 4, 8, 8))
Next
For Each Point As PointObject In m_lstLowerPoints
If Not Point.IsVisible Then Continue For
Dim x As Integer = m_objLowerHorizontalAxis.ValueToPoint(Point.HorizontalValue)
Dim y As Integer = m_objLowerVerticalAxis.ValueToPoint(Point.VerticalValue)
gr.FillEllipse(brush, New RectangleF(x - 4, y - 4, 8, 8))
Next
DrawHeaderAndTable(gr)
Return chartImage
End Function
GrowthChartPane, when it is loading, makes a call to ChartObject.GetChart() to instantiate a Drawing.Image object. When trying to Save the image that is returned from growth chart, the exception occurs. The method is pretty big, but here is a snippet from the end where the exception is.
Dim fn As String = PediatricGrowthChartsImageHandler.GetPGCImagePath(CurrentPatient.EntityID, m_iChartTypeId)
If Not IsNothing(customDrowingChart) Then
Dim chartImage As Drawing.Image = customDrowingChart.GetChart()
hdnImgChartH.Value = chartImage.Height.ToString 'test
hdnImgChartW.Value = chartImage.Width.ToString 'test
chartImage.Save(fn, System.Drawing.Imaging.ImageFormat.Png)
chartImage.Dispose()
imgChart.ImageUrl = String.Format("PediatricGrowthChartsImageHandler.axd?PatientID={0}&PGCTypeID={1}&rnd={2}", CurrentPatient.EntityID, m_iChartTypeId, New Random().NextDouble().ToString())
Else
Chart1.SaveImage(fn, ChartImageFormat.Png)
End If
End If
If Not IsNothing(DataToBeFilled) Then DataToBeFilled.dispose()
End Sub
I have confirmed that the file does NOT exist, yet exception is still thrown on Image.Save()
I've done some research on this topic & there are so many different solutions out there, but that brought me to a concern about the stream being open.
I've read that the stream needs to be open to Save an image and that you can directly pass a stream into the Save() method, but I 'm curious about how that interaction goes between the two classes.

structure intptr cannot be indexed because it has no default property

I'm trying to convert the code snippet from this answer into a VB function and I am running into a snag that I haven't seen before.
I'm not finding enough detail on it so I'm looking for wisdom in the ether.
Private Shared Function ConvertImage(filepath As String) As String
Dim bmp As Bitmap = New Bitmap(filepath)
Dim v As Byte = &HAA
' Lock the bitmap's bits.
Dim bmpData = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format1bppIndexed)
Try
Dim pBuffer As IntPtr = bmpData.Scan0
For r As Integer = 0 To bmpData.Height Step 1
Dim row As IntPtr = pBuffer + r * bmpData.Stride
For c As Integer = 0 To bmpData.Stride Step 1
row(c) = v
Next
Next
Catch ex As Exception
Finally
bmp.UnlockBits(bmpData)
End Try
filepath = IO.Path.GetTempPath & "label.bmp"
bmp.Save(filepath)
End Function
The problem is indicated to be with row(c) = v. What do I need to do to fix this?

Retrieving all dxf values for all DBText

I’m trying to obtain the layer, location, value, height, width and style for each DBText value in the current open drawing. So far I've only been able to get objectIDs.
Function SelectAllText(dbIn As Database) As ObjectIdCollection
Using doclock = Application.DocumentManager.MdiActiveDocument.LockDocument
Dim retIDs As New ObjectIdCollection
Using tr As Transaction = dbIn.TransactionManager.StartTransaction
Dim bt As BlockTable = dbIn.BlockTableId.GetObject(OpenMode.ForRead)
For Each btrID As ObjectId In bt
Dim btr As BlockTableRecord = TryCast(tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord)
For Each TRefID As ObjectId In btr
Dim te = TryCast(tr.GetObject(TRefID, OpenMode.ForRead), DBText),
tid = te.ObjectId
retIDs.Add(tid)
Next
Next
End Using
Return retIDs
End Using
End Function
The approache you proposed should work, basically in the same way: iterating through the Database>BlockTable>BlockTableRecord(ModelSpace)>All Entities.
With the ObjectId of each DBText you can:
Dim acText as DBText = tr.GetObject(dbTextId, OpenMode.ForRead)
Dim positionPoint as Point3d = acText.Position
Dim height as Double = acText.Height
Dim content as String = acText.TextString

finding the intersection point of a circle with a line in autocad customization using vb.net

For my autocad customization, I need to find the intersection point of a circle with a line. Below is my code but it does not return me any intersection point.
There will always be at least one intersection point because of constraints imposed on my problem. But, I really cant get that intersection point.Can someone help me show the way to achieving what I want to do?
Imports System
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.ApplicationServices.DocumentExtension
Namespace sweeping
Public Class intersecting
<CommandMethod("ITSSPS")>
Public Shared Sub SweepAlongPath()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Using tr As Transaction = db.TransactionManager.StartTransaction()
'getting point1
Dim ppo1 As PromptPointOptions = New PromptPointOptions(vbLf & "choose/click the centre of the first circle:")
Dim ppr1 As PromptPointResult = doc.Editor.GetPoint(ppo1)
Dim pt1 As Point3d = ppr1.Value
If ppr1.Status = PromptStatus.Cancel Then Exit Sub
Dim pdo11 As PromptDoubleOptions = New PromptDoubleOptions(vbLf & "The radius of the first cycle? Type 5 as 5.0")
Dim pdr11 As PromptDoubleResult = doc.Editor.GetDouble(pdo11)
Dim pd11 As Double = pdr11.Value
If pdr11.Status = PromptStatus.Cancel Then Exit Sub
Dim pdo12 As PromptDoubleOptions = New PromptDoubleOptions(vbLf & "What about the height? Type 5 as 5.0")
Dim pdr12 As PromptDoubleResult = doc.Editor.GetDouble(pdo12)
Dim pd12 As Double = pdr12.Value
If pdr12.Status = PromptStatus.Cancel Then Exit Sub
'getting point2
Dim ppo2 As PromptPointOptions = New PromptPointOptions(vbLf & "choose/click the centre of the second circle:")
Dim ppr2 As PromptPointResult = doc.Editor.GetPoint(ppo2)
Dim pt2 As Point3d = ppr2.Value
If ppr2.Status = PromptStatus.Cancel Then Exit Sub
Dim pdo21 As PromptDoubleOptions = New PromptDoubleOptions(vbLf & "The radius of the second cycle? Type 5 as 5.0")
Dim pdr21 As PromptDoubleResult = doc.Editor.GetDouble(pdo21)
Dim pd21 As Double = pdr21.Value
If pdr21.Status = PromptStatus.Cancel Then Exit Sub
Dim pdo22 As PromptDoubleOptions = New PromptDoubleOptions(vbLf & "What about the height? Type 5 as 5.0")
Dim pdr22 As PromptDoubleResult = doc.Editor.GetDouble(pdo22)
Dim pd22 As Double = pdr22.Value
If pdr22.Status = PromptStatus.Cancel Then Exit Sub
Dim line12 As Line = New Line(pt1, pt2)
Dim Cir1, Cir2 As Circle
Cir1 = New Circle() : Cir1.Center = pt1 : Cir1.Normal = New Vector3d(0, 0, 1) : Cir1.Radius = pd11
Cir2 = New Circle() : Cir2.Center = pt2 : Cir2.Normal = New Vector3d(0, 0, 1) : Cir2.Radius = pd21
Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
Dim Cir11 As Entity = DirectCast(Cir1, Entity)
Dim line121 As Entity = DirectCast(line12, Entity)
btr.AppendEntity(Cir11)
tr.AddNewlyCreatedDBObject(Cir11, True)
btr.AppendEntity(line121)
tr.AddNewlyCreatedDBObject(line121, True)
Dim its3dpts As Point3dCollection = New Point3dCollection()
line121.IntersectWith(Cir11, Intersect.OnBothOperands, its3dpts, IntPtr.Zero, IntPtr.Zero)
For Each pt3d As Point3d In its3dpts
Dim ptt As Point3d = pt3d
Dim Cir3 As Circle = New Circle()
Cir3.Center = ptt : Cir3.Normal = New Vector3d(0, 0, 1) : Cir3.Radius = 450
ed.WriteMessage(pt3d.ToString)
btr.AppendEntity(Cir3)
tr.AddNewlyCreatedDBObject(Cir3, True)
Next
tr.Commit()
End Using
End Sub
End Class
End Namespace
Thanks a million to whoever helps me.
This call to IntersectWith should work. I tried here and it's working fine. Are you sure the Circle and the Line really intersect?
Below is my testing code:
[CommandMethod("findIntersect")]
public static void CmdFindIntersect()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ObjectId lineId = ed.GetEntity("Select line: ").ObjectId; // not safe, test only
ObjectId circleId = ed.GetEntity("Select circle: ").ObjectId; // not safe, test only
Database db = Application.DocumentManager.MdiActiveDocument.Database;
using (Transaction trans = db.TransactionManager.StartTransaction())
{
Line l = trans.GetObject(lineId, OpenMode.ForRead) as Line;
Circle c = trans.GetObject(circleId, OpenMode.ForRead) as Circle;
Point3dCollection intersectionPoints = new Point3dCollection();
l.IntersectWith(c, Intersect.OnBothOperands, intersectionPoints, IntPtr.Zero, IntPtr.Zero);
trans.Commit();
ed.WriteMessage("{0} intersection(s) found", intersectionPoints.Count);
}
}

How to Draw Horizontal Ellipse (AutoCAD 2014)

Goal
To create an Ellipse in AutoCAD 2014 with the possibility of rotating it horizontally (as seen in the red rectangle below).
Attempt
I was able to create the Ellipse but I cannot seem to find how to rotate it horizontally.
CreateEllipse(AcadDoc)
Public Function CreateEllipse(ByRef AcadDoc As Document) As ObjectId
Dim returnId As ObjectId
Dim db As Database = AcadDoc.Database
Dim x As Vector3d = db.Ucsxdir
Dim y As Vector3d = db.Ucsydir
Dim normalVec As Vector3d = x.CrossProduct(y)
Dim axisvec As Vector3d = normalVec.GetNormal()
Dim CenterPoint As New Point3d(Me.StartPoint.X + 50, Me.StartPoint.Y + 40, 0)
Dim aEllipse As New Ellipse(CenterPoint, axisvec, New Vector3d(0, 20, 0), 0.5, 0, Math.PI * 2)
returnId = Utils.CreateAcadObject(AcadDoc, aEllipse)
aEllipse.Dispose()
Utils.regenLayers()
Return returnId
End Function
Utils.CreateAcadObject(AcadDoc, aEllipse)
Public Function CreateAcadObject(ByRef acDoc As Document, ByRef acObj As Object) As ObjectId
Dim objId As ObjectId
Dim acCurDb As Database = acDoc.Database 'Get the current database
Dim acBlkTbl As BlockTable
Dim acBlkTblRec As BlockTableRecord
Using lock As DocumentLock = acDoc.LockDocument
'Start a transaction
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
'Open Model space for write
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
acObj.SetDatabaseDefaults()
'Add the object to the drawing
objId = acBlkTblRec.AppendEntity(acObj)
acTrans.AddNewlyCreatedDBObject(acObj, True)
'Commit the changes and dispose of the transaction
acTrans.Commit()
End Using
End Using
Return objId
End Function
This is the result I get:
I'll keep trying to figure it out and I'll post my answer when I end up doing so.
On the line where you create the ellipse:
Dim aEllipse As New Ellipse(CenterPoint, axisvec, New Vector3d(0, 20, 0), 0.5, 0, Math.PI * 2)
You need to change the coordinates of the major axis like this:
Dim aEllipse As New Ellipse(CenterPoint, axisvec, New Vector3d(20, 0, 0), 0.5, 0, Math.PI * 2)