.NET

Reply
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 1 of 48 (6,375 Views)
Accepted Solution

Overrule a specific subentity in block and not showing the Base.

6375 Views, 47 Replies
08-11-2012 08:30 PM

Hello,

Facing a new problem. Planning to overrule some of subentities in a block. Let's make it simple . All lines and attributes in block should be circles and original block should not be seen. I came up with below code.

The code reacts differently if  I remove

MyBase.WorldDraw(drawable, Wd)

and my goal is not to show the real block. Just showing whatever is overruled.

Could somebody help me please

 

Thanks.

Janet.

 

 

Public Class toverrule
        Inherits Autodesk.AutoCAD.GraphicsInterface.DrawableOverrule
        Public Overrides Function WorldDraw(ByVal drawable As Autodesk.AutoCAD.GraphicsInterface.Drawable, ByVal Wd As Autodesk.AutoCAD.GraphicsInterface.WorldDraw) As Boolean
            Dim myBlock As BlockReference = CType(drawable, BlockReference)

            If Not myBlock.Database Is Nothing Then

                Dim ListEnts As New List(Of Entity)
                Dim MyDBObjColl As DBObjectCollection = New DBObjectCollection()

                myBlock.Explode(MyDBObjColl)

                Dim myline As New Line

                For Each mydbobj As DBObject In MyDBObjColl
                    If TypeOf mydbobj Is Line Then
                        myline = TryCast(mydbobj, Line)
                        Dim mycircle As New Circle
                        mycircle.Radius = myline.Length
                        mycircle.Center = myline.StartPoint
                        ListEnts.Add(mycircle)
                    ElseIf TypeOf mydbobj Is AttributeDefinition Then
                        Dim mycircle As New Circle
                        mycircle.Radius = myline.Length / 2
                        mycircle.Center = myline.StartPoint
                        ListEnts.Add(mycircle)
                    End If
                Next
                For Each Ent As Entity In ListEnts
                    Ent.WorldDraw(Wd)
                    Ent.Dispose()
                Next
                MyBase.WorldDraw(drawable, Wd)
            End If
            Return True
        End Function
    End Class

 


StephenPreston wrote:

 

@DiningPhilosopher - Using Geometry.Draw() and then Disposing of the Entity will normally work fine in a 2D shademode. But it normally crashes in a 3D shademode. But don't take my word for it - try it - if you can't make it crash, then by all means disregard my advice.

 

 


 

Hi. No need to try it, I've had production code running in the field for years that would be crashing routinely if what you say above were true. The geometry generated by Geometry.Draw() has no dependence on the in-memory object passed as the parameter. It is like a rubber-stamp and can be used and discarded immediately.

 

Also, in the code you posted, you seem to be contradicting your claim:

 

using (Circle c = new Circle())
{
c.Center = aLine.StartPoint+ 0.5*aLine.Delta;
c.Radius = 0.5* aLine.Length;
c.Normal = aLine.Normal;
c.WorldDraw(wd);
}

 

The same code from which the above excerpt was taken also has some other major problems.

 

First, you're not supposed to call Drawable.WorldDraw() directly on a Drawable, that is what Geometry.Draw() is for, and the reason is because Geometry.Draw() properly caches the generated graphics. 

Also, that same code has a serious bug, which is that corrupts the transformation stack becase you call PushModelTransform() and exit the method without calling PopModelTransform().

And, one more minor point: Here are three equally-correct ways to turn off or 'unset' a bit or flag in a binary-encoded number representing  a set of flags (e.g., the result of SetAttributes()) in VB.NET:

 

' Three correct ways to turn off or 'unset' a bit
' or flag in a binary-encoded ordinal number:
Dim x As Integer = 4906 x &= Not 32 x = x & Not 32 x = x And Not 32 ' In C#: int x = 4096 x &= ~ 32; x = x & ~ 32;

 

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 2 of 48 (6,367 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-12-2012 01:14 AM in reply to: JanetDavidson

Hell friend,

Try this out, just grabbed from docs example,

change accordingly to your subentity types

 

' (C) Copyright 2002-2009 by Autodesk, Inc. 
'
' Permission to use, copy, modify, and distribute this software in
' object code form for any purpose and without fee is hereby granted, 
' provided that the above copyright notice appears in all copies and 
' that both that copyright notice and the limited warranty and
' restricted rights notice below appear in all supporting 
' documentation.
'
' AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 
' AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
' MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC. 
' DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
' UNINTERRUPTED OR ERROR FREE.
'
' Use, duplication, or disclosure by the U.S. Government is subject to 
' restrictions set forth in FAR 52.227-19 (Commercial Computer
' Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
' (Rights in Technical Data and Computer Software), as applicable.
'
Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput

' This line is not mandatory, but improves loading performances
<Assembly: CommandClass(GetType(MyFirstOverrule_VB.MyCommands))> 

Namespace MyFirstOverrule_VB

    'This is our custom DrawableOverrule class.
    'In this case we're just overruling WorldDraw
    Public Class MyDrawOverrule
        Inherits Autodesk.AutoCAD.GraphicsInterface.DrawableOverrule


        Public Overrides Function WorldDraw(ByVal drawable As Autodesk.AutoCAD.GraphicsInterface.Drawable, ByVal wd As Autodesk.AutoCAD.GraphicsInterface.WorldDraw) As Boolean
            'Cast Drawable to Line so we can access its methods and properties
            Dim thisLine As Line = drawable
            'Draw some graphics primitives
            wd.Geometry.Circle(thisLine.StartPoint + 0.5 * thisLine.Delta, thisLine.Length / 2, thisLine.Normal)
            'In this case we don't want the line to draw itself, nor do we want ViewportDraw called
            ' Return True
            Return MyBase.WorldDraw(drawable, wd)
        End Function

    End Class



    Public Class myCommands

        'Shared member variable to store our Overrule instance
        Private Shared mDrawOverrule As MyDrawOverrule

        ' expired by Barbara Hun:
        ' http://adndevblog.typepad.com/autocad/2012/05/get-block-that-entities-are-included-in.html#tpe-actio...
        <CommandMethod("tg")> _
        Public Shared Sub getBlockNameFromItsSubentity()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument

            Dim ed As Editor = doc.Editor

            Dim db As Database = doc.Database

            Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem

            Dim pno As New PromptNestedEntityOptions(vbLf & "Select a Line inside the Block: ")

            Dim nres As PromptNestedEntityResult = ed.GetNestedEntity(pno)

            If nres.Status <> PromptStatus.OK Then
                ed.WriteMessage(vbLf & "Entsel failed")
                Return
            End If

            Try
                Dim tr As Transaction = db.TransactionManager.StartTransaction()

                Using tr
                    Dim pickPt As Point3d = nres.PickedPoint.TransformBy(ucs)

                    ed.WriteMessage(vbLf & "Picked point is {0}", pickPt)

                    Dim selId As ObjectId = nres.ObjectId

                    Dim objIds As New List(Of ObjectId)(nres.GetContainers())

                    ' Reverse the "containers" list

                    ' Now append the selected entity

                    objIds.Add(selId)

                    objIds.Reverse()

                    ' Retrieve the sub-entity path for this entity

                    Dim subEnt As New SubentityId(SubentityType.Null, 0)

                    Dim path As New FullSubentityPath(objIds.ToArray(), subEnt)

                    ' Open the outermost container, relying on the open

                    ' transaction...

                    Dim pSubEnt As Entity = TryCast(tr.GetObject(objIds(0), OpenMode.ForRead, False), Entity)

                    ' Output the class name of the sub entity

                    ed.WriteMessage(vbLf & "The sub entity is of type {0}", pSubEnt.GetType().Name)
                    ''-----------------------------------------------------------------------------''
                    If TypeOf pSubEnt Is Line Then
                        If mDrawOverrule Is Nothing Then
                            mDrawOverrule = New MyDrawOverrule
                            ' Overrule.AddOverrule(RXObject.GetClass(GetType(Line)), mDrawOverrule, False)
                            Overrule.AddOverrule(RXObject.GetClass(GetType(Line)), mDrawOverrule, False)
                        End If

                        'Toggle Overruling on/off
                        Overrule.Overruling = Not Overrule.Overruling
                        'Regen is required to update changes on screen.
                        Application.DocumentManager.MdiActiveDocument.Editor.Regen()
                    End If
                    ''-----------------------------------------------------------------------------''
                    '' Commented code block:

                    ' Get the object id of the owner block

                    'Dim mainId As ObjectId = pSubEnt.OwnerId

                    'Dim pOwner As DBObject = TryCast(tr.GetObject(mainId, OpenMode.ForRead, False), DBObject)

                    '' Output the class name of the owner block


                    'ed.WriteMessage(vbLf & "The owner is of type {0}", pOwner.GetType().Name)

                    'Dim pBlkName As String = String.Empty

                    '' Output the information of the block definition

                    'Dim pBTR As BlockTableRecord = TryCast(pOwner, BlockTableRecord)

                    'If pBTR IsNot Nothing Then

                    '    pBlkName = pBTR.Name



                    '    ed.WriteMessage(vbLf & "Block Record name is {0}", pBlkName)
                    'End If
                    'Dim pBref As BlockReference = TryCast(pOwner, BlockReference)

                    'If pBref IsNot Nothing Then
                    '    pOwner = TryCast(tr.GetObject(pBref.BlockTableRecord, OpenMode.ForRead, False), BlockTableRecord)

                    '    If pBref.IsDynamicBlock Then
                    '        pBTR = TryCast(tr.GetObject(pBref.DynamicBlockTableRecord, OpenMode.ForRead, False), BlockTableRecord)

                    '        pBlkName = pBTR.Name
                    '    Else
                    '        pBlkName = pBref.Name
                    '    End If


                    '    ed.WriteMessage(vbLf & "Block Reference name is {0}", pBlkName)
                    'End If
                    tr.Commit()
                End Using
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                ed.WriteMessage((vbLf + ex.Message & vbLf) + ex.StackTrace)

            Finally
            End Try
        End Sub
    End Class

End Namespace

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 3 of 48 (6,357 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-12-2012 08:07 AM in reply to: Hallex

Note in addition about your code above:

AttributeDefinition is part of BlockTablerecord (Block Definition)

it not belongs to BlockReference

 

~'J'~

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 4 of 48 (6,352 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-12-2012 08:56 AM in reply to: Hallex

Thanks Hallex for your effort to hep but  it is not what I asked

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 5 of 48 (6,344 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-12-2012 10:42 AM in reply to: JanetDavidson

Ok ignore my previous code,

try this one instead

 

    <CommandMethod("OST")> _
    Public Sub TestBlockTransient()
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        
        Dim opt As New PromptEntityOptions(vbLf & "Select an attributed block instance: ")

        Dim res As PromptEntityResult = ed.GetEntity(opt)

        If res.Status <> PromptStatus.OK Then
            ed.WriteMessage(vbLf + "Nothing selected!")
            Return
        End If

        Try

            Using tr As Transaction = db.TransactionManager.StartTransaction

                Dim obj As DBObject = DirectCast(tr.GetObject(res.ObjectId, OpenMode.ForRead), DBObject)

                Dim bref As BlockReference = TryCast(obj, BlockReference)

                If bref Is Nothing Then

                    Return
               
                End If

                bref.UpgradeOpen()
                Dim expobjs As New DBObjectCollection
                bref.Explode(expobjs)
                bref.Visible = False

                For Each item As DBObject In expobjs
                    If TypeOf item Is AttributeDefinition Then
                        
                        Dim attdef As AttributeDefinition = TryCast(item, AttributeDefinition)

                        If attdef IsNot Nothing Then
                            If Not attdef.IsWriteEnabled Then attdef.UpgradeOpen()
                            attdef.ColorIndex = 1


                            Dim ints As New IntegerCollection
                            GraphicsInterface.TransientManager.CurrentTransientManager.AddTransient(TryCast(attdef, GraphicsInterface.Drawable), GraphicsInterface.TransientDrawingMode.DirectShortTerm, 0, ints)
                            attdef.Visible = False
                        End If
                    Else
                     
                    End If
                Next
         
                '  tr.Commit() 'don't commit it
            End Using
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            ed.WriteMessage(ex.StackTrace)
        Finally
            GraphicsInterface.TransientManager.CurrentTransientManager.Dispose()
        End Try

    End Sub

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 6 of 48 (6,282 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-14-2012 03:34 PM in reply to: JanetDavidson

I am getting some pretty bizarre behavior here as well.

 

I did not have a DrawableOverrule operating on BlockReferences in my code, but I did have one that overruled lines with a certain XData.  (It was really silly code, written as a test case)

 

That code, taken from an example I got (I don't recall where), worked great, did not display the original line, but did properly display my alternate geometry.  Even while zooming or grip editing the line.

 

The code I have returns False from the WorldDraw override (without calling Mybase.WorldDraw) and I thought returning true might be the problem, so I just copied the code from that test overrule into a new class in my "Real" overrules that work on a blockreference, added the overrule to my collection, and tested it.

 

I have since looked up the worldraw method in the ARX help files, and the return value probably should be true, because according to the docs, returning false is telling the graphics system that it must call ViewportDraw to obtain the complete geometry.

 

For what it is worth, my line overrule works fine either way, and does not draw the original line.  It is the call to MyBase.WorldDraw which is supposed to draw the original, unoverruled object, so skipping that call should make it not draw the original block, which is how my original code is working when overruling a Line, but when I switch that code to overrule a Block, Returning false works fine, except it draws the original block (I believe that is happening in the ViewportDraw method).  Returning true doesn't draw the original block, but everything else goes wacky.

 

It is doing really wierd stuff.  Returning false from my WorldDraw override cause correct drawing of my Alternate geometry, along with the original block geometry (not like it works with Line).  Returning True causes it to NOT draw the original Block Geometry, but it also sort of goes berzerk as far as drawing my alternate geometry, occasionally even failing to draw other blocks it is not supposed to be overruling.

 

This is all very bizarre, and  Ihave not yet discovered a solution that works properly.  (except the one where it draws the original block geometry as well as my alternate geometry.)

 

I have now downloaded the DigSigStamp plugin of the month from Autodesk Labs, written by Stephen Preston, and his plugin is doing the same thing as mine (as in, the wierd behavior).

 

I think you picked a winner here.  I have no idea what is going on, but seeing as how code written by the man himself is doing the same thing as mine, I'm thinking there may be some kind of corruption in my AutoCAD install, or my drawing (created new scratch drawing, still does it), or just a bug in AutoCAD.

 

But none of that really makes sense to me, because it would mean that you have to have the same corruption as me, or that the bug has gone unnoticed by everyone else until now (running AutoCAD 2012).

 

My tests have now even gone beyond the bizarre, and running the DigSigStamp plugin is now causing regular geometry such as rectangles to disappear, and they can't be selected by crossing window, but I can select them by ctrl-A or Qselect, at which point I can see the grips but nothing else.  Then I drag one of the grips, and the geometry reappers (same with the overruled block).  Do a regen and it disappears again.

 

I'm stumped... I've tried every combination of thins I can think of, and if I return true and don't call MyBase.WorldDraw, evrything is wonky.  If I return False or if I call MyBase.WorldDraw, everything works fine, but the original block is drawn.  I have no idea why this is behaving any differently for a Block as opposed to a line.

Dave O.                                                                  Sig-Logos32.png
Board Manager
StephenPreston
Posts: 383
Registered: ‎05-22-2006
Message 7 of 48 (6,276 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-14-2012 05:31 PM in reply to: chiefbraincloud

Hi CBC,

 

Would you mind telling me what I need to do to reproduce the weird behaviour in DigSigStamp, so I can take a look.

 

(Not happy if I overlooked some crazy weird stuff :smileysad:).

 

 

Cheers,

Stephen Preston
Autodesk Developer Network
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 8 of 48 (6,262 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-14-2012 07:16 PM in reply to: StephenPreston

Hi Stephen,

Thanks for looking into problem.

Draw a circle , one line and one attribute .

Then make a block of these 3 objects. Try to overrule  the line in block . But we don't want to see the rest of  Base( which is Circle and Attribute). After code executed do a Regen or try to select the block or copy.

Hope I explained properly and this is what you asked for to help us .

Janet.

 

 

*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 9 of 48 (6,251 Views)

Re: DrawOverrule a BlockReference without showing the base block geometry

08-14-2012 10:15 PM in reply to: JanetDavidson

Janet, you said:

"Try to overrule  the line in block"

 

That is not exactly what I have been trying to do, nor is it exactly what your example code is doing, and also it is not what you should be trying to do, based on my perception of your goal (I'm not trying to be contradictory, or argumentative.  I just want everything to be clear, since it seems you have identified, and brought to my attention, a potentially serious problem with applying a DrawOverrule to a BlockRefrence).  In fact I just changed the Subject Line of my reply to reflect that.

 

Your code, and my attempts, are overruling the Block itself (I can't really tell how you are constructing and applying the overrule, because you did not include that code, but I can tell from this line "Dim myBlock As BlockReference = CType(drawable, BlockReference)"  that you are applying it to the BlockReference, not the Line inside the block, and I believe that is as it should be.  If you just overrule the line inside the block, that will not give you the means to prevent the rest of the block geometry from showing.  (which is actually the only part of this exercise I can not seem to get to work as I think it should).

 

Please see my next post, which is primarily directed at Stephen, but has a couple of questions for you, too, at the end.  (I already composed it, and thankfully predicted that the forum was going to error out because it took so long to write, so I copied it to a text editor and I can just paste it back in.)

Dave O.                                                                  Sig-Logos32.png
*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 10 of 48 (6,246 Views)

Re: Overrule a specific subentity in block and not showing the Base.

08-14-2012 10:27 PM in reply to: StephenPreston

Janet, can you fill me in as to what your hardware setup is?
And could you also weigh in on whether my experience is similar to yours, or if you see something different? (see particularly the paragraph I highlighted in Blue)

 

Stephen,


I couldn't possibly believe that you had overlooked this problem, at this point.  For me, it is as plain as day and there has been only one test performed (out of ~50+, probably 45+ on my code, and 6 or 7 on yours) where it worked as expected (see next paragraph).  All I did was run the program as designed, using your sample blocks as the replacement blocks, and, at first, I used Janets sample block as the block to replace.  Then, (because Janets block seems scaled for Metric, and the Geometry is very far from the Origin when using Imperial units) I tried using my companies standard drawing stamp block as the block to replace.  Both tests (repeated several times) produced the same (or very similar) behavior as I was experiencing with my own code.

Possibly the wierdest thing that happened was that when I ran your code, inside the example drawing that is provided with the source code, in the demo directory (with my cohort standing over my shoulder watching, while I tried to demonstrate the problem), it seemed to work just fine, but if I created a brand new clean drawing, and inserted your drawing into it, just to use the blocks you had in there, it acted just like my stuff.  I did not think to try out My code inside your sample drawing, I'll try that tommorrow, too.

My code replaces the block geometry with some arcs and a polyline, instead of replacing one block with another block.  When I run your code, I see nothing at all until I do a Select All, and drag the grip, then the geometry shows up as it should.  And when I run my code, at first I see the arcs, but not the polyline.  The objects are unselectable, either by clicking with the cursor over one of the arcs I can see (which works when my overrule is acting on lines instead of Blocks), or by using a window or crossing over the area where the block should be (also the case when running your code).  But if I use Qselect to select the blocks by name, or Ctrl-A to select all, I see the grips, and if I drag one of the grips, the arcs and polyline (or your block) show up as they should.  Then If I select a different object and drag a grip, the object that was just showing correctly goes back to just showing some arcs.  If I do a regen or regenall, they disappear completely.  I have even had blocks which do contain my Xdata Filter, but are excluded from the overrule by blockname in the WorldDraw override, disappear, and I have had lines and polylines, which are not overruled AT ALL disappear, under seemingly random situations.  I can reproduce the behavior, but it seems to happen some of the time, but not all of the time.  (That is both with your code, and mine).  Also (quite minor compared to the overall problem) I noticed that even when the geometry is showing correctly, after dragging a grip, the objects are not highlighted, even though they are selected, and the grips are showing.  That is also something that works correctly when I overrule a Line instead of a Block.

My code has a few minor differences in the structure, compared to your DigSigStamp code, but ulimately does the same thing, and the important bits (the WorldDraw override) are the same, except I'm drawing simple geometry in place of the block instead of replacing one block with another.  I made no changes to the DigSigStamp code, but I did build the Source myself, and loaded that, in debug mode, instead of loading the .DLL that is pre-built in the download (one more thing I could test)

I am of the impression the problem lies in some sort of corruption (either Cad install, or drawing, like I mentioned above, but I'm leaning away from that now), or that there may be an issue with my video card or it's drivers.

I am on a WinXP 32 bit, Dell T3400 (Intel Dual Core 2.8? GHz, 4 GB RAM) with a NVidia QuadroFX 3700 video card (1 GB DDR3, I think, I am at home right now), and an 80 GB Hard drive stuffed to the max.  Stuffed to the point that I don't have room to install AutoCAD 2013 unless I uninstall one of my Revit versions, or one of my AutoCAD versions.

The machine is almost 4 years old now, and the video card has been a good card in the past, but I killed one of them (swapped another in from an identical machine, of the same age), then I had some driver issues with that one, and swapped to a different identical machine, of the same age.  So maybe I am having driver issues again, or maybe I am just hard on video cards, but I do have options to test this behavior on some older (actually really old) Gateways with GeForce cards or some newer Dells with  Win7 64 bit and (I can't remember the exact model, but I think it is an ATI card of comparable specs to the QuadroFX 3700, and on the Autodesk Approved list)

I plan on doing some more testing tomorrow on those different setups (and the couple of other ideas I had while writing this Novel) and see if I can still reproduce the problem, plus check on the latest drivers for my NVidea card, and see what that does (I know I updated them a few months ago).  NVidea also has an AutoCAD Performance Driver for that card, and I don't think I have it installed, so I'll try that, too.

Dave O.                                                                  Sig-Logos32.png
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.