Hello,
I have to repost this because people may think, last post was answered, but it wasn't and still I am struggling and need a pro to help me here .
Have a overruled block with attribute in it , I just registered the attributes in my overrule class.
I need to overule (make it simple) just lines ( let's say make them circles) and don't want to show the attributes neither do the rest of objects in block . But if user double click on overruled block I need to show attribute tag input table (Dialog). And don't want to show other objects in block if any exists.
Below is my code and I thought solution would be easy and I have to REM ( or remove the line )
MyBase.WorldDraw(drawable, Wd).
But when I do that the block is not selectable and a regen crash the autocad . That was my story and here is the code.
I appreciate any help here. For your convenience a simple block is attached.
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
Solved! Go to Solution.
Solved by chiefbraincloud. Go to Solution.
Hi janet,
Hopefully the sample code I posted in the other thread on this topic gives you what yuo need to fix your problem.
Mine is working great now.
This is the important bit of Stephens code that you are still missing.
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: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
That was great-everything is working now , Are you Tony? hehehehhe.
Thanks chief . The other thread screwed.
The credit belongs to Stephen Preston. I was already overriding the SetAttributes function in my code, but I did not know that I needed to remove the 32 bit for blocks with attributes. That part came from Stephen, and that is the only part that was missing from my original code, to make it work.
Chief I am facing a new problem again with same overrule.
I have osnaps overrule and it works fine. But when I used distannce command and sanps to overrule block with attribute it crashes. everything else works fine while snapping to overrule block but this is something .
Do you mind to take a look at it if you have time? I can make it simple for your convenience .
Janet.
Maybe it'll never happen in your circumstance, but you should at least know that if you use the overrule Stephen posted (or any overrule targeting BlockReference for that matter), in a drawing that contains a table that has blocks containing text inserted into the table's cells, AutoCAD will crash when you save the drawing.
Hello, DP.
Thanks for all support
I did use SP's Attribute Overrides Function. It solved most of my problems. And I realized Geometry Draw acting goofy.
So I used word draw , even though Geometry draw is faster on regen.
Right now everything works fine except for Autocad Distance command. It crashes.
If you or CB can help me, I would be very grateful. Attached is block drawing file and code. Basically I replaced the lines in block with 2 polylines, the same length. Try to do a Distance between polylines. It crashes the machine.
Hope I can get help from you gentlemen again.
Thanks Janet
Janet, I don't code in VB.NET unfortunately, and can't easily test your code.
What I will tell you, is that overrules are one of the most complicated aspects of AutoCAD .NET programming, and certainly not a good vehicle for an introductory tutorial, so perhaps you've gotten the wrong impression that overrules are relatively-simple to write and debug when in fact, they are a challenge for even highly experienced AutoCAD .NET programmers.
About your code, one major problem I see by just looking at it, is that it calls Explode() on a block reference, and then returns a subset of the entities produced by Expode(), but fails to call Dispose() on the entities that aren't returned to the caller, which will likely cause AutoCAD to crash at some later point, and may very likely be what's happening to you.
Yes, I am he.
Sure, if you post a .cs file that compiles without errors I'll try it.
Hello Again DP.
After 14 hours struggling I finally converted it to C#. Now behavior is completely different. Before in VB I just had crash
on Distance Command. Now I have crash whenever I snap to block. I really hope and beg for your help Tony.
I know you always have a trick in your sleeve.
Thanks
Janet
P.S. I renamed file extension to .txt , website doens't allow extension .cs to be uploaded.
Hi Janet.
Before I even look at that code, I would ask that you fix the obvious bug and try it again.
The bug I'm referring to is the line shown in red below (I renamed the function from Go_Get_blahblahblah...). In that line of code, you're creating a new Line object, but not doing anything with it, and not disposing it, which will probably crash AutoCAD.
public static bool GetExplodedEnts( BlockReference myBlock, ref List<Entity> ListEnts ) { DBObjectCollection MyDBObjColl = new DBObjectCollection(); { myBlock.Explode( MyDBObjColl ); Line Line1 = new Line(); foreach( DBObject mydbobj in MyDBObjColl ) { if( mydbobj is Line ) { Line1 = mydbobj as Line; Autodesk.AutoCAD.DatabaseServices.Polyline MyPolyLine1 = new Autodesk.AutoCAD.DatabaseServices.Polyline(); MyPolyLine1.SetDatabaseDefaults(); MyPolyLine1.AddVertexAt( 0, new Point2d( Line1.StartPoint.X, Line1.StartPoint.Y ), 0, 200, 200 ); MyPolyLine1.AddVertexAt( 1, new Point2d( Line1.EndPoint.X + 3000, Line1.EndPoint.Y + 3000 ), 0, 200, 200 ); MyPolyLine1.Closed = true; ListEnts.Add( MyPolyLine1 ); } else { mydbobj.Dispose(); } } } return true; }
That bug is almost certain to crash AutoCAD.
Hi Janet - There's a few more problems with the code you posted, and they are also in the original VB code as well.
First, have a look at the documentation for AcGiDrawable::worldDraw() (In the native ObjectARX docs) and make note of what the return value means. Why does your WorldDraw() return false?
public override bool WorldDraw( Drawable drawable, WorldDraw Wd ) { BlockReference myBlock = drawable as BlockReference; if( ( myBlock.Database != null ) ) { List<Entity> ListEnts = new List<Entity>(); if( !GetExplodedEnts( myBlock, ListEnts ) ) { return false; } foreach( Entity Ent in ListEnts ) { Ent.WorldDraw( Wd ); Ent.Dispose(); } } // base.WorldDraw(drawable, Wd); return true; }
Next, your Go_Get_Overruled_exploded_entities_from_this_block() method misuses Try/Catch, by catching any exception that's raised, and without regards for what the exception is or what caused it, your method simply returns False. That's kind of like saying 'I don't care what went wrong, I just want it to work', but it will never work until you find out what went wrong, which that kind of mis-use of Try/Catch prevents. If there's no exception, then that same method always returns True, regardless of whether it added anything to the list or not, which is also not correct.
Lastly, your GetObjectSnapPoints() overload uses Try/Catch with an empty catch block . That's the same as using On Error Resume Next in VBA, and is something you should never do, because it simply hides exceptions from you, making it nearly impossible to debug your code. When you are writing/testing/debugging code, you can put a statement in an otherwise-empty Catch block that displays the exception that was caught, but you should never use Try/Catch with an empty catch block in production code, without being completely sure what exception will be caught.
So, as it stands your code has quite a few problems that you need to fix before I would try to run it,.
Hello DP, I really appreciate all these time you spent for teaching me(us). What you are doing here for us is like a father doing for their kids. I am/was you fan alwasy.
I did what you asked and thanks for tips. I had all those catches in my original code but they never been hit. I just removed them from this sample code to make it shorter. I put them back but they never been catch.
Regard with New LIne. You are winner . I forgot it totally. But still doesn't change anything.
I checked document and this is what it says :
A return value of Adesk::kFalse indicates that the 3D GS must
call viewportDraw() in order to obtain the complete geometry
and attribute set for this drawable.
Frankly, don't understand it . But I changed it to True as you mentioned . Nothing changed.
By the way If you want to yell at me . It is OK. I know you yell to make students learn better. I am ready.
( Reminds me those Chinese KungFu movies when the master kicks student )
So HELP
Janet.
Hi Janet,
I only looked quickly but a IntPtr has a method ToInt32().
Not sure you can use Convert.ToInt32(gsSelectionMark) try gsSelectionMark.ToInt32() instead.
Jeff,
Thanks. After I applied your advice now it acts like my VB version.
Thanks for your time to look into my problem .Still when I do a distance command it crashes.
Tony is on this as well .We are lucky. Huh!
Cheers,
Janet.
Jeff already dropped a hint about what the problem is, but I think it's better for you to learn how to find the problem yourself. So, I'll try to show you how to to do that.
One major problem with developing AutoCAD plugins in .NET is that AutoCAD does not always catch exceptions that are thrown by managed code when the managed code is called from lower-level native APIs, overrules being one such case. So, to find out if AutoCAD is crashing as a result of an exception being raised by your overridden overrule methods, you need to wrap them in a try/catch block, and display a message in the catch block, like this:
public override void GetObjectSnapPoints( Entity e, ObjectSnapModes snapMode, System.IntPtr gsSelectionMark, Point3d pickPoint, Point3d lastPoint, Matrix3d viewTransform, Point3dCollection snapPoints, IntegerCollection geometryIds, Matrix3d insertionMat ) { try { BlockReference myBlock = e as BlockReference; List<Entity> ListEnts = new List<Entity>(); if( !toverrule.GetExplodedEnts( myBlock, ListEnts ) ) { return; } foreach( Entity SubEnt in ListEnts ) { SubEnt.GetObjectSnapPoints( snapMode, gsSelectionMark.ToInt32(), pickPoint, lastPoint, viewTransform, snapPoints, geometryIds, insertionMat ); SubEnt.Dispose(); } } catch( System.Exception ex ) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage( "\n****** Exception: {0}\n\n\n", ex.ToString() ); } } // The same method, except using the try/catch diagnostics in debug builds only: public override void GetObjectSnapPoints( Entity e, ObjectSnapModes snapMode, System.IntPtr gsSelectionMark, Point3d pickPoint, Point3d lastPoint, Matrix3d viewTransform, Point3dCollection snapPoints, IntegerCollection geometryIds, Matrix3d insertionMat ) { #if DEBUG try { #endif BlockReference myBlock = e as BlockReference; List<Entity> ListEnts = new List<Entity>(); if( !toverrule.GetExplodedEnts( myBlock, ListEnts ) ) { return; } foreach( Entity SubEnt in ListEnts ) { SubEnt.GetObjectSnapPoints( snapMode, gsSelectionMark.ToInt32(), pickPoint, lastPoint, viewTransform, snapPoints, geometryIds, insertionMat ); SubEnt.Dispose(); } #if DEBUG } catch( System.Exception ex ) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage( "\n****** Exception: {0}\n\n\n", ex.ToString() ); } #endif }
If you replace your GetOsnapPoints() override with one of the two shown above, then you will see why your code is crashing. Jeff already suggested the remedy, so I'll leave the rest to you.
Tony, Thank you again for your time. VB version had only Distance Command problem. That is why I continued this thread and asked for help ,when I converted it to C# for your consideration the new bug happened ( because of my low experience in c# , and Jeff remedy put it back to state, which Distance command crashes the program ,now it behaves like VB version.
I used your suggested Function to see, if it shows the reason it crashes, when we do distance command , but still it doesn't show what is the problem is . You can try it , use the block,submitted and apply overule and try to make a distance between two new thick polylines.
originally in my code had a [ ref ] for ListEnts, which in your revised version it was removed.
Below is what I had originally
if (!toverrule.GetExplodedEnts(myBlock,ref ListEnts))
and this is your revised one
if (!toverrule.GetExplodedEnts(myBlock,ref ListEnts))
I had to put ref back to make the code work properly
Attached please find latest version including your funciton and Jeff remedy. But still crashes on Distance command between two overruled Polylines, and doesn't show what the reason is.
Thanks
Janet.
HI Janet.
You'll need to provide some details on your config where the code crashes.
First, what release of AutoCAD are you using?
Second, what running osnap modes are set, and if you're using immediate osnap, which ones are they for the first and second points?
Can't find what you're looking for? Ask the community or share your knowledge.