.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

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

47 REPLIES 47
SOLVED
Reply
Message 1 of 48
JanetDavidson
10266 Views, 47 Replies

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

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

 

47 REPLIES 47
Message 41 of 48

Hello, that was good .

This is   Tony Style.

So you are still parenting us  ........ ?

But it was not 3 sentences . Hehehehehe.

Thank you very much.

 

 

Message 42 of 48

Hi DiningPhilosopher,

 

Yes - If I pushed a transformation and forgot to pop it in my code, then that would be a bug. Every push should have a matched pop. That said, quickly scanning the VB.NET code I posted, I see two pushes and two pops. Although I should really have put the last pop at the end of the function and outside the Using block. Feel free to post a corrected version of the code.

 

However, I don't agree with your opinions on Geometry.Draw and WorldDraw. I don't pretend to be an expert on the intricacies of custom entity implementation (to which overrules are closely related), and I've not touched the overrule API in about a year, but I based what I said on advice given to me by one of our senior AutoCAD software architects when I found an overrule sample I'd created for my AU2010 class was crashing in a 3D shademode. I documented that advice in the class handout. Not completely trusting my memory, I just walked across the room to talk this through with another of our architects. My questions to him (paraphrased):

 

1. Is it ok to call WorldDraw inside another entity's WorldDraw (or an Overrule)?

2. Can using Geometry.Draw on an entity you then Dispose/delete cause problems?

 

His answers (paraphrased):

 

1. Yes. We do that a lot in AutoCAD code.

2. Yes it can. It may work sometimes, or on a particular version of our graphics engine. But if you use Geometry.Draw then you should implement a way to cache the entities you used it on - until you know those graphics are no longer being cached.

 

My point was that, ideally, you should cache the entity and use Geometry.Draw - you can push additional model transformations to position and scale the entity correctly without having to edit it. If that is not possible, then you can call WorldDraw on a temporary entity instead. Using WorldDraw in this way is just like calling a utiity function to draw your graphics, although you can sometimes see different results between WorldDraw and Geometry.Draw due to how AutoCAD handles the two calls.

 

And for completeness - and not mentioned until now - a suggestion from another member of our AutoCAD development team when I asked him the same questions: He looked at me in amazement and asked "Why don't you just use the Geometry class to draw the graphics primitives directly instead of using a DB class?" Then you have the most control you possibly can.

 

I think we're in agreement on the basic point that Draw is better than WorldDraw - if its possible to use it. But as this is a cached public forum, I felt I had to respond with the above information so that readers who find this in the future can make their own decision on the best way to go. Sorry if its a bit long-winded.

 

And thank you for the bit-setting example. I knew there was a better way to achieve this, but didn't have time to refresh my rusty VB.NET binary operation knowledge to get the more succinct version.

 

PS Janet - I think this thread has become over-long and off-topic now. You may have more success getting answers to your follow-on questions if you start a fresh thread.

Cheers,

Stephen Preston
Autodesk Developer Network
Message 43 of 48


@StephenPreston wrote:

Hi DiningPhilosopher,

 

Yes - If I pushed a transformation and forgot to pop it in my code, then that would be a bug. Every push should have a matched pop. That said, quickly scanning the VB.NET code I posted, I see two pushes and two pops. Although I should really have put the last pop at the end of the function and outside the Using block. Feel free to post a corrected version of the code.

Hi Stephen. Immediately after the first call to PushModelTransform(), you exit the function if the overruled subject is not database-resident, bypassing the matching call to PopModelTransform()

 

Public Overrides Function WorldDraw(ByVal drawable As Autodesk.AutoCAD.GraphicsInterface.Drawable, ByVal Wd As Autodesk.AutoCAD.GraphicsInterface.WorldDraw) As Boolean
        Dim thisBR As BlockReference = CType(drawable, BlockReference)
        Wd.Geometry.PushModelTransform(thisBR.BlockTransform)
        If thisBR Is Nothing Then
          Return MyBase.WorldDraw(drawable, Wd)
        End If
        If thisBR.Database Is Nothing Then
          Return MyBase.WorldDraw(drawable, Wd)
        End If

 

Usually its best to wrap code that must execute once a given point is reached, in Try/Finally blocks, because then even if you return from the Try block, the code in the Finally block will still execute.


@StephenPreston wrote:

 

However, I don't agree with your opinions on Geometry.Draw and WorldDraw. I don't pretend to be an expert on the intricacies of custom entity implementation (to which overrules are closely related), and I've not touched the overrule API in about a year, but I based what I said on advice given to me by one of our senior AutoCAD software architects when I found an overrule sample I'd created for my AU2010 class was crashing in a 3D shademode. I documented that advice in the class handout. Not completely trusting my memory, I just walked across the room to talk this through with another of our architects. My questions to him (paraphrased):

 

1. Is it ok to call WorldDraw inside another entity's WorldDraw (or an Overrule)?

2. Can using Geometry.Draw on an entity you then Dispose/delete cause problems?

 

His answers (paraphrased):

 

1. Yes. We do that a lot in AutoCAD code.

2. Yes it can. It may work sometimes, or on a particular version of our graphics engine. But if you use Geometry.Draw then you should implement a way to cache the entities you used it on - until you know those graphics are no longer being cached.

 

My point was that, ideally, you should cache the entity and use Geometry.Draw - you can push additional model transformations to position and scale the entity correctly without having to edit it. If that is not possible, then you can call WorldDraw on a temporary entity instead. Using WorldDraw in this way is just like calling a utiity function to draw your graphics, although you can sometimes see different results between WorldDraw and Geometry.Draw due to how AutoCAD handles the two calls.

About WorldDraw() verses Geometry.Draw(), I'll just refer you to the native ObjectARX docs for the latter, which discuss that very topic. About disposing non-persistent entities after passing them to Geometry.Draw(), I have yet to see a failure result from that, having used that pattern extensively, especially with 3D objects that would be somewhere between extremely difficult and impossible to draw manually via calls to the Geometry class's primitive drawing methods. Of course, it all depends on what you're doing. For a simple educational example that draws a few lines or what have you, you can say that it may be easier to use primitive drawing. In the real world, things are rarely  that simple.

 

BTW Stephen, If I recall correctly, the code from one of your AU classes published a few years back (dealing with overrules, but don't know if it's the one you mention above) creates new DBObjects and passes them to Draw(), but fails to call Dispose() on them afterwards, and of course, that could explain the fatal error.


@StephenPreston wrote:

 

 

And for completeness - and not mentioned until now - a suggestion from another member of our AutoCAD development team when I asked him the same questions: He looked at me in amazement and asked "Why don't you just use the Geometry class to draw the graphics primitives directly instead of using a DB class?" Then you have the most control you possibly can.

 

I think we're in agreement on the basic point that Draw is better than WorldDraw - if its possible to use it. But as this is a cached public forum, I felt I had to respond with the above information so that readers who find this in the future can make their own decision on the best way to go. Sorry if its a bit long-winded.

 

And thank you for the bit-setting example. I knew there was a better way to achieve this, but didn't have time to refresh my rusty VB.NET binary operation knowledge to get the more succinct version.

 

PS Janet - I think this thread has become over-long and off-topic now. You may have more success getting answers to your follow-on questions if you start a fresh thread.


Lastly, about the general approach you've chosen as a solution to Janet's problem, and for the benefit of those learning about overrules, there's no need to overrule BlockReference and manualy draw its entire contents in order to selectively affect the drawing of a select few nested entities of a specific type. That can be done from overrules targeting the runtime classes of those nested entities whose graphics you need to control, and the overrule will be called for every instance of a block reference whose definition contains entities which the overrule(s) target. For example, to overrule the display of only Circle entities that are nested in a specific block, you just read the BlockId property of each Circle from the overrule's WorldDraw, open the BlockTableRecord it references, and see if it is the block you want to affect, and if it is, then do your thing.

 

 

Message 44 of 48

I'll just refer you to the native ObjectARX docs for the latter, which discuss that very topic. About disposing non-persistent entities after passing them to Geometry.Draw(),

 

I wouldn't rely on those docs as gospel, someone once told me...

 

there's no need to overrule BlockReference and manualy draw its entire contents in order to selectively affect the drawing of a select few nested entities of a specific type.

 

You evidently failed to grasp that the ENTIRE problem here was that Janet did not want to draw ANY of the original block.  She only wanted to overrule certain items, yes, but in order to cause the remainder of the block to NOT be drawn, she had to overrule the block.

Dave O.                                                                  Sig-Logos32.png
Message 45 of 48


@chiefbraincloud wrote:

I'll just refer you to the native ObjectARX docs for the latter, which discuss that very topic. About disposing non-persistent entities after passing them to Geometry.Draw(),

 

I wouldn't rely on those docs as gospel, someone once told me... 


I never rely on the docs as gospel, I rely on what I learn by experimenting and testing, and in this particular case, I did quite a bit of that and I'm confident that the referenced docs are accurate. 


@chiefbraincloud wrote:

 

there's no need to overrule BlockReference and manualy draw its entire contents in order to selectively affect the drawing of a select few nested entities of a specific type.

 

You evidently failed to grasp that the ENTIRE problem here was that Janet did not want to draw ANY of the original block.  She only wanted to overrule certain items, yes, but in order to cause the remainder of the block to NOT be drawn, she had to overrule the block.


No, I think I did grasp the ENTIRE problem. I didn't say that you don't need to overrule block references, what I said was that there is no need to manually draw the block's entities using Geometry.Draw() or as Stephen prefers, WorldDraw(). 

 

Supressing the display of all but certain entities is easily accomplished by overruling the Entity class. But the problem is that you don't want an overrule on that class running all the time, so you overrule BlockReference, and when its WorldDraw() is called with a block reference that you want to alter, just before you call the WorldDraw() method of the block reference Overrule's base class, you add another overrule to the Entity class. Then you supermessage the WorldDraw() of the block reference overrule's base class (which is where WorldDraw() is called on each entity in the block, along with attributes), and as soon as the call to base.WorldDraw() returns, you immediately remove the overrule on the Entity class, so that it's only applied to entities nested in insertions of blocks that you want to affect, and is otherwise not overruling anything and not impacting regen performance. To supress the display of an entity, the overrule on the Entity class can override SetAttributes() and add to its result, the flag indicating the entity is invisible.

And to avoid any confusion coming out of what I just described, here's a (completely untested) snippet:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;

namespace Examples
{
   // Overrule on BlockReference that supresses display of 
   // everything but circles, only for insertions of the block
   // whose name is passed in the argument to the constructor:

   class CustomBlockReferenceOverrule : DrawableOverrule
   {
      // pass the name of the block whose contents are to
      // be overruled (for simplification purposes, we don't
      // care about dynamic blocks here):

      public CustomBlockReferenceOverrule( string blockname )
      {
         this.target = blockname.ToUpper();
         AddOverrule( RXClass.GetClass( typeof( BlockReference ) ), this, true );
      }

      // only insertions of this block are affected:
      string target = ""; 

      public override bool WorldDraw( Drawable drawable, WorldDraw wd )
      {
         BlockReference subject = drawable as BlockReference;
         if( subject != null && target == subject.Name.ToUpper() )
         {
            // TODO: Add desired graphics for block reference here
            
            // here, overruling of all entites starts
            using( new ShowOnlyNestedCirclesOverrule() )
            {
               return base.WorldDraw( drawable, wd );
               
            } // here, overruling of all entities stops
         }
         else return base.WorldDraw( drawable, wd );
      }

      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            RemoveOverrule( RXClass.GetClass( typeof( BlockReference ) ), this );
         }
         base.Dispose( disposing );
      }

   }

   // an overrule targeting Entity, that supresses the display 
   // of everything except circles (for example). You can also
   // restrict this to specific entities using any of the means 
   // that Overrule provides for filtering, to minimize calls 
   // to SetAttributes(), WorldDraw() and the resulting overhead.

   class ShowOnlyNestedCirclesOverrule : DrawableOverrule
   {
      public ShowOnlyNestedCirclesOverrule()
      {
         AddOverrule( RXClass.GetClass( typeof( Entity ) ), this, true );
      }

      // This will only be called for circles because the
      // override for SetAttributes() below sets everything
      // else to invisible:
      
      public override bool WorldDraw( Drawable drawable, WorldDraw wd )
      {
         // TODO: replace/add additional graphics here:
         
         // Or, draw the circle:
         return base.WorldDraw( drawable, wd ); 
      }
      
      /// this tells the graphics system that the entity is invisible
      /// and that it shouldn't try to draw it:
      
      public override SetAttributes( Drawable drawable, DrawableTraits traits )
      {
         int flags = base.SetAttributes( drawable, traits );
         if( drawable is Circle )
           return flags
         else
           return ( flags | 16 );       // kIsInvisible;
      }

      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            RemoveOverrule( RXClass.GetClass( typeof( Entity ) ), this );
         }
         base.Dispose( disposing );
      }
   }
}

 

 

Message 46 of 48

Code description is like a teaching  class (video Clip)  and works like a charm  , Build anything you like on top of this class, based on your need.  Believe me this is thoughtful.

 

Thanks again  All  .

DiningPhilosopher

Your registration Date is unique , Like your Code Woman Wink

 

Janet,

 

Message 47 of 48

Hi DP,

 

You're right about that PushModelTransform location. That was a silly mistake. Thank you for pointing it out.

 

I've said what needed to be said about WorldDraw vs Geometry.Draw in my previous post:

 

  • When using Geometry.Draw, you should cache the entities you're drawing.
  • There should be no problem calling WorldDraw on a temporary entity.
  • You get the most control (although possibly at the expense of extra effort) by drawing your graphics using raw geometry.

 

I have no strong opinion on anything else covered in this thread.

 

The readers of this thread can make their own implementation decisions based on the information presented. I'll just add that pointing to a bug in my AU 2009 class samples is something of an ad hominem argument - and merely demonstrates that I had a bug in that sample (which I didn't notice at the time because I was only testing in a 2D shademode). The bug was corrected in my AU 2010 class for the reasons already stated. My general view is that there are normally several valid ways to solve any given coding problem, and arguing about which is 'best' in such situations is a fruitless exercise. But I do also take the approach that if a senior colleague in the AutoCAD engineering team tells me something is a bad idea, then I stop doing it - especially when that advice is backed up by my own observations.

 

I think Janet now has all the information she needs (and then some) to solve her specific problem - which was my reason for contributing to this topic in the first place. Therefore, I'll now retire from this thread. If anyone would like to discuss anything further with me offline, then they are very welcome to email me at my Autodesk email address or via the forum mail system.

 

Good luck with the rest of your implementation, Janet.

 

Cheers,

Stephen Preston
Autodesk Developer Network
Message 48 of 48

Stephen , DP, Chief.

I am good and my boss is happy with me. Thank you all.

 

Stephen. everybody knows you in our small professional group. If you didn't participate in this thread I wouldn't get my answer at all. Look at the number of participants. It was all because of you.

Thanks gentlemen. All of you are my heros.

Good result.

Janet.

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost