.NET

Reply
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 21 of 48 (529 Views)

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

08-16-2012 12:51 PM in reply to: chiefbraincloud

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.

 

 

Board Manager
StephenPreston
Posts: 385
Registered: ‎05-22-2006
Message 22 of 48 (517 Views)

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

08-16-2012 02:35 PM in reply to: JanetDavidson

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
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 23 of 48 (497 Views)

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

08-16-2012 05:02 PM in reply to: JanetDavidson

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

 

*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 24 of 48 (471 Views)

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

08-16-2012 11:37 PM in reply to: StephenPreston

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 :smileywink: Just Kidding, I love my job, and I have a good boss, how many people can say that!)

 

 

Dave O.                                                                  Sig-Logos32.png
Board Manager
StephenPreston
Posts: 385
Registered: ‎05-22-2006
Message 25 of 48 (457 Views)

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

08-17-2012 08:58 AM in reply to: chiefbraincloud

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::smileyfrustrated:etAttributesFlags 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
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 26 of 48 (447 Views)

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

08-17-2012 10:31 AM in reply to: StephenPreston

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.

 

 

Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 27 of 48 (439 Views)

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

08-17-2012 12:07 PM in reply to: StephenPreston

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.

 

Valued Mentor
jeff
Posts: 330
Registered: ‎05-12-2009
Message 28 of 48 (419 Views)

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

08-18-2012 02:21 AM 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
Distinguished Contributor
JanetDavidson
Posts: 139
Registered: ‎08-23-2011
Message 29 of 48 (415 Views)

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

08-18-2012 08:33 AM 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.

 

Valued Mentor
DiningPhilosopher
Posts: 370
Registered: ‎05-06-2012
Message 30 of 48 (388 Views)

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

08-18-2012 03:15 PM in reply to: JanetDavidson

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.

Need installation help?

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