.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
10254 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 21 of 48

Jeff you did it a couple of times and I am sure you will do it again.

Hope  Stephen , when he gets a chance, change and update  the 25 lines of code for us as well.

 

 

Message 22 of 48

In the interests of not keeping you hanging on, here is a quick update on the solution I suggested (and answers to a few comments):

 

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

 

@CBC -  I can now repro the issue you described. Thanks for the DWG. But its been a long time since I wrote that DigSigStamp sample, so I didn't try to make it work correctly. I wrote this sample on the assumption that the blocks would have the same size/scale. (I should have documented that limitation in the readme/helpfile). The DigSigStamp sample does lots of other stuff, and doesn't address the question Janet asked, so I decided to quickly write a more concise sample to test instead. In passing, I should say that you really have to overrule a lot more than the graphics if you want everything to work correctly - grips, extents, subentity selection, explode, transformby, cloning, etc, etc. How much you have to overrule in any given case depends on what you want to achieve. That's why I said its akin to creating a custom entity - its hard to get everything to work exactly as you want it in all scenarios.

 

@Jeff - Exactly :-).

 

@ Janet - Here is a quick code snippet to show what I meant, and what Jeff expanded on. Its not perfect, because it doesn't display the geometry correctly in a UCS that isn't WCS (which probably means I need to edit the transformations I'm pushing), but it demonstrates the principle. I'm sorry, but I don't have the time to fix that now, but I'm sure you or someone else on this forum can take it forward from here. I thought you'd prefer a pointer in the right direction than no answer at all. The code overrules BlockReference to display all Lines as Circles:

 

 public class MyOverrule : DrawableOverrule
  {
    public override bool WorldDraw(Drawable drawable, WorldDraw wd)
    {
      BlockReference thisBR = drawable as BlockReference;
      wd.Geometry.PushModelTransform(thisBR.BlockTransform);
        if (null == thisBR)
        {
          return base.WorldDraw(drawable, wd);
        }
      if (null == thisBR.Database)
      {
          return base.WorldDraw(drawable, wd);
      }
     
      using (OpenCloseTransaction trans =
        thisBR.Database.TransactionManager.StartOpenCloseTransaction())
      {
        BlockTableRecord btr = trans.GetObject(thisBR.BlockTableRecord,
                                OpenMode.ForWrite) as BlockTableRecord;
        foreach(ObjectId entId in btr)
        {
          Entity ent = trans.GetObject(entId, OpenMode.ForRead) as Entity;
          Line aLine = ent as Line;
          if (null != aLine)
          {
            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);
            }
          }
          else
          {
            wd.Geometry.Draw(ent);
          }

        }
      }

      wd.Geometry.PopModelTransform();
      return true;
    }

  }

 

I'm also taking a shortcut by returning true from this function so I don't have to overrule ViewportDraw - that's something you need to fix if you want to make this function more generically correct.

Cheers,

Stephen Preston
Autodesk Developer Network
Message 23 of 48

Thanks Stephen for your concern about us. So nice of you to assign some time for us. The result of your code  is still the same as mine. Below  is your code in VB ,(I just had VB,Sorry ). I added a command for everybody's convenience to encourage people to test and I reattached the cursed  block again for ease of testing. Maybe I made a mistake in my translation so please correct me.

After running the command First Still I see the base. I thought everything would be disappeared except  the overruled lines.Second, Block could not be selected at all, third, after a regen command nothing seen on screen.

 

Public Class test2
    Friend Shared BlockOverrule1 As toverrule
    <CommandMethod("mmmm")> _
    Public Sub mmmm()
        If BlockOverrule1 Is Nothing Then
            BlockOverrule1 = New toverrule
            Overrule.AddOverrule(RXClass.GetClass(GetType(BlockReference)), BlockOverrule1, True)
            Application.DocumentManager.MdiActiveDocument.Editor.Regen()
        End If
    End Sub
    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 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

            Using trans As Transaction = thisBR.Database.TransactionManager.StartOpenCloseTransaction
                If True Then
                    Dim btr As BlockTableRecord = TryCast(trans.GetObject(thisBR.BlockTableRecord, OpenMode.ForWrite), BlockTableRecord)
                    For Each entId As ObjectId In btr
                        Dim ent As Entity = TryCast(trans.GetObject(entId, OpenMode.ForRead), Entity)
                        Dim aLine As Line = TryCast(ent, Line)
                        If aLine IsNot Nothing Then
                            Using c As New Circle()
                                c.Center = aLine.StartPoint + 0.5 * aLine.Delta
                                c.Radius = 0.5 * aLine.Length
                                c.Normal = aLine.Normal
                                c.WorldDraw(Wd)
                            End Using
                        Else
                            Wd.Geometry.Draw(ent)
                        End If
                    Next
                End If
            End Using
            Wd.Geometry.PopModelTransform()
            Return True
        End Function
    End Class
End Class

 

Message 24 of 48

Stephen,

I have been woking on getting a simplified code sample together for you (actually, I am trying to put together two examples, one based on your code, and one based on mine), but I got sidetracked with another weird bug that just reared it's ugly head, with code that I haven't changed in probably three years.  I was "This close" (Holds thumb and forefinger 1/4" apart) to submitting an ADN support request, but I fixed the problem.  I still have no idea why this problem suddenly appeared.  (It has no bearing on this thread, so I just deleted my rantings about it)

 

Stephen Preston Said:

I wrote this sample on the assumption that the blocks would have the same size/scale.

 

While I don't pretend to know all (about anything), and I certainly bow to your (and Kean's, and Fenton's) knowledge in both programming in general, and the AutoCAD API's, I am hard pressed to think of a reason why the size of the original overruled block would matter, but now that you mention it, the block I have been testing with (in my code, not with yours) is a block that is always scaled in the X-axis.

 

  It is a 3D block that is comprised of several extrusions that is created at a specific Height(Z) and Width(Y), with a 1unit length in X, then it is scaled in the X to represent the appropriate length.  I realize that this is the perfect scenario for using a Dynamic block (and I'd really like to, and also for other blocks in my program), but this is code that I wrote in (lisp ~2002, then VBA ~2005), and converted to .NET in 2007, and I just haven't had the time to learn the API for Dynamic blocks, and change tons of code to use it.

 

OK, so getting back on topic, I think the scale issue is what is causing my troubles.  I have successfully implented my hacked up version of your DigSigStamp code, on a simple uniformly scaled block, and it works fine.  But when I try to apply that same code to the X-scaled blocks I mentioned before, it does not work fine.  Then I checked (because I had not looked before) and Janet's block is Uniformly scaled at (1,1,1).  So while scale seems to be the source of my problem, it does not seem to be the source of her problem.   Could you possibly explain how Size could be a problem here?  Because I don't understand that, in terms of what I have been trying to do.  (I don't really understand why the non-uniform scale would be the source of my problem, either, since I totally wrote my code to appropriately scale the Overrule geometry based on the scale of the original block,  but in terms of this thread I'm willing to accept it and move on).

 

What I am going to do next is extract my original code to a new project and test it against uniformally, and non-uniformally scaled blocks, to see if my original code (which is just slightly different than the DigSigStamp code) works with uniformally scaled blocks.  And I'll certainly test it against Janet's sample block, too.  (I didn't do that yet, with my hacked up version of the DigSigStamp code, I should try that, too.  Like I said, I got tied up with real work stuff, where the users actually expect me to Do Something.  Damned end users.  This job would be great if it weren't for them 😉 Just Kidding, I love my job, and I have a good boss, how many people can say that!)

 

 

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

That was embarrassing. I was testing with a block without attributes for simplificy, but its the attributes that cause the problem in Janet's drawing. The fix is to also overrule the SetAttributes function. In the example code below, I'm unsetting bit 32 of the returned value from that function to stop the overruled BlockReference reporting that it has attributes. We can then draw the AttributeReferences ourselves. Here's the code (now in VB, as Janet and CBC both said they're working in VB):

 

  Public Class test2

    Friend Shared BlockOverrule1 As toverrule

    <CommandMethod("tt")> _
    Public Sub TestMethod()
      If BlockOverrule1 Is Nothing Then
        BlockOverrule1 = New toverrule
        Overrule.AddOverrule(RXClass.GetClass(GetType(BlockReference)), BlockOverrule1, True)
        Overrule.Overruling = True
      End If
      Application.DocumentManager.MdiActiveDocument.Editor.Regen()
    End Sub

 

    Public Class toverrule
      Inherits Autodesk.AutoCAD.GraphicsInterface.DrawableOverrule

      Private Shared _circle As Circle

      'Create our circle which gives for the duration of the overrule
      Public Sub New()
        _circle = New Circle(New Point3d(0.5, 0, 0), New Vector3d(0, 0, 1), 0.25)
      End Sub

      Public Overrides Function SetAttributes(ByVal drawable As Autodesk.AutoCAD.GraphicsInterface.Drawable, ByVal traits As Autodesk.AutoCAD.GraphicsInterface.DrawableTraits) As Integer
        Dim res As Integer = MyBase.SetAttributes(drawable, traits)
        'See ARX ref guide entry for "AcGiDrawable::SetAttributesFlags Enumeration"
        'Bit 32 indicates entity has attributes. If we unset that bit,
        ' then overruling blockref with attributes works fine. We do
        ' this because we're drawing the attributes ourself.
        Dim test As Integer = res And 32
        If test Then
          res = res - 32
        End If
        Return res
      End Function


      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

        Using trans As Transaction = thisBR.Database.TransactionManager.StartOpenCloseTransaction()
          Dim btr As BlockTableRecord = TryCast(trans.GetObject(thisBR.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
          For Each entId As ObjectId In btr
            Dim ent As Entity = TryCast(trans.GetObject(entId, OpenMode.ForRead), Entity)
            Dim aLine As Line = TryCast(ent, Line)
            If aLine IsNot Nothing Then
              'Calc additional transformation to push so circle is
              ' scaled to line dimensions
              Dim ECS_OriginPt As Point3d = aLine.StartPoint
              Dim ECS_XVec As Vector3d = aLine.Delta.GetNormal
              Dim ECS_ZVec As Vector3d = aLine.Normal
              Dim ECS_YVec As Vector3d = ECS_ZVec.CrossProduct(ECS_XVec)
              ' We don't want text to scale with the line length, so we calculate an 'unscaled' ECS for the text
              Dim unscaledECS_Mat As Matrix3d = Matrix3d.AlignCoordinateSystem(Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis, ECS_OriginPt, ECS_XVec, ECS_YVec, ECS_ZVec)
              ' We do want the circle and arc to scale with the line, so we calculate a 'full' (corrctly scaled) ECS
              Dim ECS_Mat As Matrix3d = Matrix3d.Scaling(aLine.Length, aLine.StartPoint) * unscaledECS_Mat
              ' Push our scaled transform
              Wd.Geometry.PushModelTransform(ECS_Mat)
              ' Draw the arc and circle
              Wd.Geometry.Draw(_circle)
              Wd.Geometry.PopModelTransform()

            Else
              If Not TypeOf ent Is AttributeDefinition Then
                Wd.Geometry.Draw(ent)
              End If
            End If
          Next

          Wd.Geometry.PopModelTransform()

          If thisBR.AttributeCollection.Count <> 0 Then
            For Each id As ObjectId In thisBR.AttributeCollection
              Dim obj As DBObject = trans.GetObject(id, OpenMode.ForRead)
              Dim ar As AttributeReference = TryCast(obj, AttributeReference)
              Wd.Geometry.Draw(ar)
            Next
          End If

          trans.Commit()
        End Using

        Return True
      End Function
    End Class
  End Class

 

I've also edited the code to use a single instance of _circle that lives for the lifetime of the overrule (instead of constantly creating a new one and displosing it), and to apply an additional model transformation to scale it to the location of the line its replacing. (I haven't added a destructor to the class to correctly Dispose _circle when the overrule is destroyed - which should be done). I've also not set any subentitytraits in the code (such as layer, color, etc).

 

Hopefully that covers what you need for your own implementation.

Cheers,

Stephen Preston
Autodesk Developer Network
Message 26 of 48

Stephen

No reason to embarrass, We all ,here, are in same the page and programmer. My personal experience ( Never a program is perfect. Always there is something to fix or add . 

 

Again thank you very much. Now it doesn't crash and I can select the block . As you mentioned before, now we have a startup Function  to work with and get ourselves familiar   with Geometry Redraw. 

I don't want to bug Stephen(I know he got other questions to answer) , if anybody else could  answer me and know Geometry redraw . But  If nobody answers me back  then Stephen it is your question . Heheheheheh. Joking.

 

 

1- Using  updated code  when I moved the block,during jigging, the block goes back to original state ( this doesn't happened in world draw)

 

2- Copying  the block , when ACAD prompts for base point , block jumps to somewhere else.

3- I don't know how to show just attributes and overruled lines and turnoff the rest of entities in block  during overruling.

 

Cheers,

Janet.

 

 

Message 27 of 48

Stephen,

Apart from problems I mentioned in my previous post after you posted the updated code . I realized the Geometry Redraw is way faster than World Redraw. I have a drawing with 1000 blocks on it.

In my way whenever user switches between layout tabs there was a lag ( because of regen ) . Now it is way faster.

Now I really need those issues to be resolved   so I can switch the whole code to Geometry. I am so excited.

Thanks

Janet.

 

Message 28 of 48
jeff
in reply to: JanetDavidson

DOH!

Good thing Tony T caught this HERE as will cause problems for me.

 

See link but as Tony explains add a Table to drawing and insert the block into table then do a QSAVE and see what happens.

You can also find your answers @ TheSwamp
Message 29 of 48
JanetDavidson
in reply to: jeff

Unfortunately  He passed away . TT  is a Fake Tony. This Group will miss him a lot.

Real Tony never wrote  more than 3 sentecnes and in 3 sentences everything is solved.

I suggest we be more patient and avoid posting unrelated posts until stephen solve this for us.

 

Janet.

 

Message 30 of 48


@JanetDavidson wrote:

Unfortunately  He passed away . TT  is a Fake Tony. This Group will miss him a lot.

 

 


OMG. Where did you hear this?  I'm sorry to hear about that.

Message 31 of 48
kdub_nz
in reply to: DiningPhilosopher


@DiningPhilosopher wrote:

@JanetDavidson wrote:

Unfortunately  He passed away . TT  is a Fake Tony. This Group will miss him a lot.

 

 


OMG. Where did you hear this?  I'm sorry to hear about that.


 

 

Hey, that's 3 sentences !

//

Everything will work just as you expect it to, unless your expectations are incorrect.

class keyThumper<T> : Lazy<T>;      another  Swamper

Message 32 of 48
JanetDavidson
in reply to: kdub_nz

His X-coworker

Message 33 of 48


@JanetDavidson wrote:

His X-coworker


And might I ask who that would be?

Message 34 of 48

That is What I been told. Sorry  Can't reveal  name here.

The fact is he couldn't tolerate to leave people unanswered. He left his name permanent here in Autodesk Forum.

I really call him Master and so much respect for him . Who doesn't use his CommandLine Class  among us?

Bet everybody use it ,and everytime it is hit , is like another blessing for him. Guess the subject of this thread is going to be changed and I would rather subject stay on overrule .

Cheers

Janet.

 

 

 

Message 35 of 48

LOL  Smiley LOL

Message 36 of 48
owenwengerd
in reply to: JanetDavidson

I'm curious how you met Tony's co-worker. I heard that Tony worked for the CIA, so do you work for the CIA as well? That must be interesting. I guess they make you use fake names. I wonder what Tony's real name was. Ah well, such a shame, we'll certainly miss him.

--
Owen Wengerd
ManuSoft
Message 37 of 48
JanetDavidson
in reply to: owenwengerd

Gentlemen, Please, Don't contaminate this thread.

CIA. That was funny.

 

 If this person is Tony why he doesn't have any solution for my problem.

Tony always had a work around for our problem. Plus where is his website?

Janet,

 

Message 38 of 48

Tony's coworker seems a bit of a stretch, as I thought he was in business for himself.  You know, CadZone.com.  But the CIA thing is completely out there.  (I mean completely unbelievable)

 

I have been unrespondant to this thread since Thursday, because I had a personal issue on Friday, and didn't make it in to work, so I couldn't test the latest solution provided by Stephen, I will be back in to work tomorrow, but I can not promise that I will be able to spend time on this issue.  I will try.

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

Hi chief, I  have  the same respect for you because of all the helps you have done for me. It was several times you rescued me. Hop you don't  .....  Like him. heehehehehehe.

 

Apart from name , that is the info I got (Don't' know right or wrong ). He used to work in AutoDesk. Then he was fired.

Don't know why but I bet because if his temper. Even in his writing you could feel that.

If that is true  it was a big loss for autodesk. Smart people could realize his positive attitude  behind his bad temper.

Why did they let him go .

But the thing is he was caring and and his intension was to teach. If somebody claims to know better than him then he would put you down like ....  . 

 

Anyways, get back to work , I tested Stephen Code. I explained what the problem is with his code  in my previous posts.

 

Thanks Chief and Stephen for all their concern again.

Regards,

Janet

 

Message 40 of 48


@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;

 

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