Jump to content

Ghosting a polyline being drawn


dbroada

Recommended Posts

I am drawing a polyline with VB.Net using a modification of fixo's routine (his first post in this thread http://www.cadtutor.net/forum/showthread.php?78728-3d-points-amp-2d-polylines ). It suits my needs nicely except I can only see an elastic line from the last point clicked to where my next point will be. Is there a way of leaving a line from all the previous points?

 

The only thing I can think of doing is setting a "mark", drawing lines as I go along and then undo back to the mark. However, I haven't looked at coding that yet.

 

Have you other ideas?

Edited by dbroada
"vb.net" added
Link to comment
Share on other sites

  • Replies 24
  • Created
  • Last Reply

Top Posters In This Topic

  • dbroada

    8

  • Tyke

    5

  • BlackBox

    5

  • ReMark

    4

Does it have to be a line that you leave? You just need a visual reminder of where you were previously right? And does this reminder have to be permanent?

Link to comment
Share on other sites

I probably should have mentioned that this is being done in VB.Net. I want a visual clue left to show where the polyline will be until the polyline is drawn. Once the polyline shape has been determined the marker should be erased.

Link to comment
Share on other sites

I have considered that (we must be the same age) and immediately forgot about it. Age again I think. I was going to keep that up my sleeve hoping something "nicer" comes along but now I test it in 2013, its not there.

Link to comment
Share on other sites

BUMP!

 

While BLIPMODE will give me a clue, does anyone know if there a programatic way of laying down a line or pline which is then erased when I add the final pline?

Link to comment
Share on other sites

This blog post uses an interesting variation for ghosting via Overrules:

 

http://drive-cad-with-code.blogspot.com/2011/01/mimicking-autocads-area-command-with_21.html

 

I utilized the mechanics to create a similar process for a program shown in action here:

 

http://screencast.com/t/SAqWNXpN3L

 

See where I select the points for the “Variable Quad”.

Link to comment
Share on other sites

Sean, yes that first one would be very nice - but I'm too new to VB.Net to translate it today. :( I'll look again when I have more time and see if I can get it to work. In the meantime, blipmode here I come.

Link to comment
Share on other sites

  • 3 months later...
Sean, yes that first one would be very nice - but I'm too new to VB.Net to translate it today. :( I'll look again when I have more time and see if I can get it to work. In the meantime, blipmode here I come.

 

Dave, did you ever get time to do this in VB? It would appear to be just what I need too.

 

B

Link to comment
Share on other sites

... but I'm too new to VB.Net to translate it today. :(

 

... So new, in fact, that you could easily start learning C#, methinks. :beer:

 

Another option (as you are using .NET [aka CLR]), is to compile the C# code into an assembly, which you load into your VB.NET projects as reference(s)... This gives you the ability to reference any Type (Class), Property, Method, or Event you'd need from the source, without converting, nor learning C# (which I do highly recommend).

 

In any event, my friend(s)... Here's the C# code Sean was kind enough to link previously, converted from C# to VB.NET using DeveloperFusion (so you may need to fix some errors, etc.)... You can remove the length of some of those calls by removing the Namespace qualification (with an additional Imports statement, etc.) as well, if you like....

 

 

 

Class "MyNewAreaCmd":

 

Imports System.Collections.Generic

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.DatabaseServices

Namespace AreaCommand
Public Class MyNewAreaCmd
	Private _dwg As Document
	Private _editor As Editor

	Private _area As Double = 0.0
	Private _perimeter As Double = 0.0

	Private _pline As Autodesk.AutoCAD.DatabaseServices.Polyline = Nothing

	Private _points As List
	Private _pickDone As Boolean

	Private _color As Integer = 1

	Public Sub New(dwg As Document)
		_dwg = dwg
		_editor = _dwg.Editor
	End Sub

	Public ReadOnly Property Area() As Double
		Get
			Return _area
		End Get
	End Property

	Public ReadOnly Property Perimeter() As Double
		Get
			Return _perimeter
		End Get
	End Property

	Public Function GetArea() As Boolean
		_pline = Nothing

		'Pick first point
		Dim pt1 As Point3d
		If Not GetFirstPoint(pt1) Then
			Return False
		End If

		'Pick second point
		Dim pt2 As Point3d
		If Not GetSecondPoint(pt1, pt2) Then
			Return False
		End If

		_pickDone = False

		_points = New List()
		_points.Add(New Point2d(pt1.X, pt1.Y))
		_points.Add(New Point2d(pt2.X, pt2.Y))

		Try
			'Enable custom Overrule
			MyPolylineOverrule.Instance.StartOverrule(_points, _color)

			'Handling mouse cursor moving during picking
			_editor.PointMonitor += New PointMonitorEventHandler(AddressOf _editor_PointMonitor)

			While True
				If Not PickNextPoint() Then
					Exit While
				End If
			End While

			If _pline IsNot Nothing AndAlso _pickDone Then
				Calculate()
			End If
		Catch
			Throw
		Finally
			ClearTransientGraphics()

			'Remove PointMonitor handler
			_editor.PointMonitor -= New PointMonitorEventHandler(AddressOf _editor_PointMonitor)

			'Disbale custom Overrule
			MyPolylineOverrule.Instance.EndOverrule()
		End Try

		Return _pickDone
	End Function

	#Region "private methods"

	Private Sub Calculate()
		Dim p As New Autodesk.AutoCAD.DatabaseServices.Polyline(_points.Count)
		For i As Integer = 0 To _points.Count - 1
			p.AddVertexAt(i, _points(i), 0.0, 0.0, 0.0)
		Next

		p.Closed = True

		_area = p.Area
		_perimeter = p.Length

		p.Dispose()
	End Sub

	Private Function GetFirstPoint(ByRef pt As Point3d) As Boolean
		pt = New Point3d()

		While True
			Dim opt As New PromptPointOptions(vbLf & "Pick first corner: ")

			opt.Keywords.Add("Background")
			opt.AppendKeywordsToMessage = True

			Dim res As PromptPointResult = _editor.GetPoint(opt)

			If res.Status = PromptStatus.OK Then
				pt = res.Value
				Return True
			ElseIf res.Status = PromptStatus.Keyword Then
				Dim intOpt As New PromptIntegerOptions(vbLf & "Enter color number (1 to 7): ")
				intOpt.AllowNegative = False
				intOpt.AllowZero = False
				intOpt.AllowArbitraryInput = False
				intOpt.UseDefaultValue = True
				intOpt.DefaultValue = 1

				Dim intRes As PromptIntegerResult = _editor.GetInteger(intOpt)

				If intRes.Status = PromptStatus.OK Then
					_color = intRes.Value
				End If
			Else
				Return False
			End If
		End While
	End Function

	Private Function GetSecondPoint(basePt As Point3d, ByRef pt As Point3d) As Boolean
		pt = New Point3d()

		Dim opt As New PromptPointOptions(vbLf & "Pick next corner: ")
		opt.UseBasePoint = True
		opt.BasePoint = basePt
		Dim res As PromptPointResult = _editor.GetPoint(opt)

		If res.Status = PromptStatus.OK Then
			pt = res.Value
			Return True
		Else
			Return False
		End If
	End Function

	Private Function PickNextPoint() As Boolean
		Dim opt As New PromptPointOptions(vbLf & "Pick next corner: ")
		If _points.Count > 2 Then
			opt.Keywords.Add("Undo")
			opt.Keywords.Add("Total")
			opt.Keywords.[Default] = "Total"
			opt.AppendKeywordsToMessage = True
			opt.AllowArbitraryInput = False
		End If

		Dim res As PromptPointResult = _editor.GetPoint(opt)

		If res.Status = PromptStatus.OK Then
			_points.Add(New Point2d(res.Value.X, res.Value.Y))
			Return True
		ElseIf res.Status = PromptStatus.Keyword Then
			If res.StringResult = "Undo" Then
				If _points.Count > 2 Then
					_points.RemoveAt(_points.Count - 1)
				End If
				Return True
			Else
				_pickDone = True
				Return False
			End If
		Else
			_pickDone = False
			Return False
		End If
	End Function

	Private Sub ClearTransientGraphics()
		If _pline IsNot Nothing Then
			TransientManager.CurrentTransientManager.EraseTransients(TransientDrawingMode.DirectTopmost, 128, New IntegerCollection())

			_pline.Dispose()
			_pline = Nothing
		End If
	End Sub

	Private Sub _editor_PointMonitor(sender As Object, e As PointMonitorEventArgs)
		ClearTransientGraphics()

		'Get mouse cursor location
		Dim pt As New Point2d(e.Context.RawPoint.X, e.Context.RawPoint.Y)

		_pline = New Autodesk.AutoCAD.DatabaseServices.Polyline(_points.Count + 1)

		For i As Integer = 0 To _points.Count - 1
			_pline.AddVertexAt(i, _points(i), 0.0, 0.0, 0.0)
		Next

		_pline.AddVertexAt(_points.Count, pt, 0.0, 0.0, 0.0)
		_pline.Closed = True

		TransientManager.CurrentTransientManager.AddTransient(_pline, TransientDrawingMode.DirectTopmost, 128, New IntegerCollection())
	End Sub

	#End Region
End Class
End Namespace

 

 

 

Class "MyPolylineOverrule":

 

Imports System.Collections.Generic

Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.Runtime


Namespace AreaCommand
Public Class MyPolylineOverrule
	Inherits DrawableOverrule
	Private Shared _instance As MyPolylineOverrule = Nothing
	Private _existingOverrulling As Boolean
	Private _color As Integer = 1

	Private _points As List = Nothing

	Public Shared ReadOnly Property Instance() As MyPolylineOverrule
		Get
			If _instance Is Nothing Then
				_instance = New MyPolylineOverrule()
			End If
			Return _instance
		End Get
	End Property

	Public Property Color() As Integer
		Get
			Return _color
		End Get
		Set
			_color = value
		End Set
	End Property

	Public Sub StartOverrule(points As List)
		_points = points

		_existingOverrulling = Overruling

		'Add the custom overrule
		AddOverrule(RXObject.GetClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline)), Me, False)

		'Use custom filter, implemented in IsApplicable() method
		SetCustomFilter()

		'Make sure Overrule is enabled
		Overruling = True
	End Sub

	Public Sub StartOverrule(points As List, color As Integer)
		_color = color

		_points = points

		_existingOverrulling = Overruling

		'Add the custom overrule
		AddOverrule(RXObject.GetClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline)), Me, False)

		'Use custom filter, implemented in IsApplicable() method
		SetCustomFilter()

		'Make sure Overrule is enabled
		Overruling = True
	End Sub

	Public Sub EndOverrule()
		'Remove this custom Overrule
		RemoveOverrule(RXObject.GetClass(GetType(Autodesk.AutoCAD.DatabaseServices.Polyline)), Me)

		'restore to previous Overrule status (enabled or disabled)
		Overruling = _existingOverrulling
	End Sub

	Public Overrides Function WorldDraw(drawable As Drawable, wd As WorldDraw) As Boolean
		Dim pts As New Point3dCollection()
		For i As Integer = 0 To _points.Count - 1
			pts.Add(New Point3d(_points(i).X, _points(i).Y, 0.0))
		Next

		wd.SubEntityTraits.FillType = FillType.FillAlways
		wd.SubEntityTraits.Color = Convert.ToInt16(_color)

		wd.Geometry.Polygon(pts)

		Return MyBase.WorldDraw(drawable, wd)
	End Function

	Public Overrides Function IsApplicable(overruledSubject As Autodesk.AutoCAD.Runtime.RXObject) As Boolean
		Dim pl As Autodesk.AutoCAD.DatabaseServices.Polyline = TryCast(overruledSubject, Autodesk.AutoCAD.DatabaseServices.Polyline)

		If pl IsNot Nothing Then
			'Only apply this overrule to the polyline
			'that has not been added to working database
			'e.g. created for the Transient Graphics
			If pl.Database Is Nothing Then
				Return True
			Else
				Return False
			End If
		Else
			Return False
		End If
	End Function
End Class
End Namespace

 

 

 

Command class "MyCommands":

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput

<Assembly: CommandClass(GetType(AreaCommand.MyCommands))>

Namespace AreaCommand
Public Class MyCommands
	<CommandMethod("MyNewArea")> _
	Public Shared Sub GetNewArea()
		Dim dwg As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
		Dim ed As Editor = dwg.Editor

		Dim cmd As New MyNewAreaCmd(dwg)

		If cmd.GetArea() Then
			ed.WriteMessage(vbLf & "Area = {0}", cmd.Area)
			ed.WriteMessage(vbLf & "Perimeter = {0}", cmd.Perimeter)
		Else
			ed.WriteMessage(vbLf & "*Cancelled*")
		End If
	End Sub
End Class
End Namespace

Link to comment
Share on other sites

Thanks for that RM, but unlike Dave I'm an old dog who finds it difficult to change his ways. I'll stick with VB.

 

Since I posted I found the following in the Civil 3D Help. I haven't tested it yet but it looks promising, I just need to modify the code to allow more than five Points to be selected. Perhaps I can test it tomorrow.

 

 

Calculate a Defined AreaArea (.NET)

 

 

If the area you want to calculate is based on user specified points, you might consider creating an in memory object such as a lightweight polyline, and then query of the area of the object before discarding it. The following steps explain how you might accomplish this:

 

1. Use the GetPoint method in a loop to obtain the pointsfrom the user.

2. Create a lightweight polyline from thepoints provided by the user. Create a new Polyline object. Specify the numberof vertices and the points they should be at.

3. Use the Area property to obtain the area of the newly created polyline.

4. Dispose of the polyline using its Dispose method.

 

Calculate the area defined by points entered from the user

 

 

This example prompts the user to enter five points. A polyline is then created out of the points entered. The polyline is closed, and the area of the polyline is displayed in a message box. Since the polyline is not added to a block, it needs to be disposed before the command ends.

 

VB.NET

[color=black][font=Courier New]Imports Autodesk.AutoCAD.ApplicationServices[/font][/color]

[color=black][font=Courier New]Imports Autodesk.AutoCAD.DatabaseServices[/font][/color]

[color=black][font=Courier New]Imports Autodesk.AutoCAD.Geometry[/font][/color]

[color=black][font=Courier New]Imports Autodesk.AutoCAD.EditorInput[/font][/color]

[color=black][font=Courier New]Imports Autodesk.AutoCAD.Runtime[/font][/color]



[color=black][font=Courier New]<CommandMethod("CalculateDefinedArea")> _[/font][/color]

[color=black][font=Courier New]Public Sub CalculateDefinedArea()[/font][/color]

[color=black][font=Courier New]  '' Prompt the user for 5points[/font][/color]

[color=black][font=Courier New]Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument[/font][/color]



[color=black][font=Courier New]DimpPtRes As PromptPointResult[/font][/color]

[color=black][font=Courier New]  Dim colPt AsPoint2dCollection = New Point2dCollection[/font][/color]

[color=black][font=Courier New]  Dim pPtOpts AsPromptPointOptions = New PromptPointOptions("")[/font][/color]



[color=black][font=Courier New]  '' Prompt for the firstpoint[/font][/color]

[color=black][font=Courier New]  pPtOpts.Message = vbLf& "Specify first point: "[/font][/color]

[color=black][font=Courier New]  pPtRes =acDoc.Editor.GetPoint(pPtOpts)[/font][/color]

[color=black][font=Courier New]  colPt.Add(NewPoint2d(pPtRes.Value.X, pPtRes.Value.Y))[/font][/color]



[color=black][font=Courier New]  '' Exit if the userpresses ESC or cancels the command[/font][/color]

[color=black][font=Courier New]  If pPtRes.Status =PromptStatus.Cancel Then Exit Sub[/font][/color]



[color=black][font=Courier New]  Dim nCounter As Integer =1[/font][/color]



[color=black][font=Courier New]  While (nCounter <= 4)[/font][/color]

[color=black][font=Courier New]      '' Prompt for the nextpoints[/font][/color]

[color=black][font=Courier New]      Select Case nCounter[/font][/color]

[color=black][font=Courier New]          Case 1[/font][/color]

[color=black][font=Courier New]              pPtOpts.Message= vbLf & "Specify second point: "[/font][/color]

[color=black][font=Courier New]          Case 2[/font][/color]

[color=black][font=Courier New]              pPtOpts.Message= vbLf & "Specify third point: "[/font][/color]

[color=black][font=Courier New]          Case 3[/font][/color]

[color=black][font=Courier New]              pPtOpts.Message= vbLf & "Specify fourth point: "[/font][/color]

[color=black][font=Courier New]Case 4[/font][/color]

[color=black][font=Courier New]              pPtOpts.Message= vbLf & "Specify fifth point: "[/font][/color]

[color=black][font=Courier New]      End Select[/font][/color]



[color=black][font=Courier New]      '' Use the previouspoint as the base point[/font][/color]

[color=black][font=Courier New]      pPtOpts.UseBasePoint =True[/font][/color]

[color=black][font=Courier New]      pPtOpts.BasePoint =pPtRes.Value[/font][/color]



[color=black][font=Courier New]      pPtRes =acDoc.Editor.GetPoint(pPtOpts)[/font][/color]

[color=black][font=Courier New]      colPt.Add(NewPoint2d(pPtRes.Value.X, pPtRes.Value.Y))[/font][/color]



[color=black][font=Courier New]      If pPtRes.Status =PromptStatus.Cancel Then Exit Sub[/font][/color]



[color=black][font=Courier New]      '' Increment thecounter[/font][/color]

[color=black][font=Courier New]      nCounter = nCounter +1[/font][/color]

[color=black][font=Courier New]  End While[/font][/color]



[color=black][font=Courier New]  '' Create a polyline with5 points[/font][/color]

[color=black][font=Courier New]  Using acPoly As Polyline =New Polyline()[/font][/color]

[color=black][font=Courier New]      acPoly.AddVertexAt(0,colPt(0), 0, 0, 0)[/font][/color]

[color=black][font=Courier New]      acPoly.AddVertexAt(1, colPt(1), 0, 0, 0)[/font][/color]

[color=black][font=Courier New]      acPoly.AddVertexAt(2,colPt(2), 0, 0, 0)[/font][/color]

[color=black][font=Courier New]      acPoly.AddVertexAt(3,colPt(3), 0, 0, 0)[/font][/color]

[color=black][font=Courier New]      acPoly.AddVertexAt(4,colPt(4), 0, 0, 0)[/font][/color]



[color=black][font=Courier New]      '' Close the polyline[/font][/color]

[color=black][font=Courier New]      acPoly.Closed = True[/font][/color]



[color=black][font=Courier New]      '' Query the area ofthe polyline[/font][/color]

[color=black][font=Courier New]     Application.ShowAlertDialog("Area of polyline: " & _[/font][/color]

[color=black][font=Courier New]                                  acPoly.Area.ToString())[/font][/color]



[color=black][font=Courier New]      '' Dispose of thepolyline[/font][/color]

[color=black][font=Courier New]End Using[/font][/color]

[color=black][font=Courier New]End Sub[/font][/color]

 

Link to comment
Share on other sites

Thanks for that RM.

 

Since I posted I found the following in the Civil 3D Help. I haven't tested it yet but it looks promising, I just need to modify the code to allow more than five Points to be selected. Perhaps I can test it tomorrow.

 

You're welcome :)

 

Civil 3D is a beast... It's hard enough just trying to keep track of all of the API changes in AutoCAD, let alone gigantic verticals such as Civil 3D. Since you mentioned it though, and you're working with .NET, you might find the "Snoop Civil 3D" plug-in Augusto released at DevBlog to be useful (it's akin to MgdDbg for AutoCAD [which I also have an Autoloader .bundle for here], just without Civil 3D-specific Event monitoring)... For whatever reason, they've not provided an Autoloader plug-in, so I did in this post. There's a few posts before the one I've linked here that will provide additional information.

 

Let me know if you have any comment/questions about using it.

 

Cheers :beer:

Link to comment
Share on other sites

You're welcome :)

 

Civil 3D is a beast... It's hard enough just trying to keep track of all of the API changes in AutoCAD, let alone gigantic verticals such as Civil 3D. Since you mentioned it though, and you're working with .NET, you might find the "Snoop Civil 3D" plug-in Augusto released at DevBlog to be useful (it's akin to MgdDbg for AutoCAD [which I also have an Autoloader .bundle for here], just without Civil 3D-specific Event monitoring)... For whatever reason, they've not provided an Autoloader plug-in, so I did in this post. There's a few posts before the one I've linked here that will provide additional information.

 

Let me know if you have any comment/questions about using it.

 

Cheers :beer:

 

I edited my post since you replied.

 

I'm done for today and I'm now sitting in the living room after a delicious evening meal and have a a bottle of very good red wine that I'm sharing with the Little Lady.

 

Thanks for the advice, it will be looked at when the effects of the wine have worn off. :beer:

Link to comment
Share on other sites

... unlike Dave I'm an old dog who finds it difficult to change his ways. I'll stick with VB.

 

.... You wouldn't want to know when I graduated High School then. :P :rofl:

 

 

 

You and the little lady have a lovely evening. :beer:

Link to comment
Share on other sites

.... You wouldn't want to know when I graduated High School then. :P :rofl:

I bet I was already in retirement by then! About 8 years ago?;) :roll:

 

You and the little lady have a lovely evening. :beer:

We did, thanks.:thumbsup:

Link to comment
Share on other sites

I bet I was already in retirement by then! About 8 years ago?;) :roll:

 

[stuartVoice]

 

I don't wanna say!

 

[/stuartVoice]

 

images?q=tbn:ANd9GcRY3BMY1c2wB2zUn5ZsL9s4Ir8jPqwLZrcWwudghSbYfWiUwOIkxw

 

 

 

 

Hooray SNL (Saturday Night Live) Mad TV skits!

Edited by BlackBox
Ehhhehehehehe
Link to comment
Share on other sites

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...