Author Topic: Accessing Visiblity properties within a dynamic block definition  (Read 6960 times)

0 Members and 1 Guest are viewing this topic.

GILESP

  • Newt
  • Posts: 42
Hiya

I'm working on a project which among other things has to determine the visibility properties of an entity within a block definition.

The task is to determine the maximum drawing extents of a block reference within modelspace, however blocks with multiple visibility states are currently showing up with greater extents due to my code not taking into account the currently selected visibility state.

what I'd like to do is pass a visibility state name to the function, and have it compare each entity it encounters with the state name, and if the entity is not visible in that state, ignore it.

This way I can pass a block name, and visibility state to the function, and it will return the maximum extents of the block in that visibility mode only.

Code fragment below of the function that calculates maximum extents,
the block argument is the block definition in the blockstable used to define the reference being processed.
SubjectDwg is a cheat that allows this script/routine to be processed as part of a batch.
the optional 'view' argument is the visibility state name of the current block reference being processed:

Has anyone got any idea how I can get the conditional statement in the code to recognize the visibility parameter of an entity?

Code: [Select]
Function GetExtents(Block As AcadBlock, SubjectDwg As AcadDocument, Optional View As String) As Double()

Dim Obj As AcadEntity
Dim MinExt(0 To 1) As Variant 'minimum bounding extents of block
Dim MaxExt(0 To 1) As Variant 'maximum bounding extents of block
Dim ObjMinExt As Variant
Dim ObjMaxExt As Variant
Dim TempArray() As Double
ReDim TempArray(0 To 3)

For Each Obj In Block
    Select Case Obj.EntityName
            Case "AcDbTable"
                'ignore
            Case "AcDbBlockReference"
                TempArray = GetExtents(SubjectDwg.Blocks.Item(Obj.Name), SubjectDwg)
            Case "AcDbPolyline", "AcDbLine", "AcDbArc", "AcDbCircle"
                If UCase(Obj.Layer) Like "CENTRELINES" Or UCase(Obj.Layer) Like "*-C" Or UCase(Obj.Layer) Like "*-CLEAR" Then
                 'ignore

                ElseIf obj.visilitystate <> View then ######################### <= this conditional statement needs to work!

                 'ignore
                Else
                    Obj.GetBoundingBox ObjMinExt, ObjMaxExt
                    If ObjMaxExt(0) > MaxExt(0) Then
                        MaxExt(0) = ObjMaxExt(0)
                    End If
                    If ObjMaxExt(1) > MaxExt(1) Then
                        MaxExt(1) = ObjMaxExt(1)
                    End If
                    If MinExt(0) > ObjMinExt(0) Then
                        MinExt(0) = ObjMinExt(0)
                    End If
                    If MinExt(1) > ObjMinExt(1) Then
                        MinExt(1) = ObjMinExt(1)
                    End If
                End If
        End Select
Next Obj
TempArray(0) = MinExt(0)
TempArray(1) = MinExt(1)
TempArray(2) = MaxExt(0)
TempArray(3) = MaxExt(1)

GetExtents = TempArray()
       
End Function

thanks

G
..END OF LINE..

n.yuan

  • Bull Frog
  • Posts: 348
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #1 on: January 11, 2017, 11:44:23 AM »
I am not sure I fully understand your question, but it seems to me that your code is logically wrong (if the AcadBlock argument in the function is not ModelSpace or PaperSpace):

1. The extents of a block definition is not necessarily the same as Block reference. For example, the block definition could have a few attribute definition with very short tag string, while the corresponding attribute reference could have very long value string, or even the block reference could have attribute reference that does not have matching attribute definition, or no attribute reference at all. This would be very likely make the extents of block reference different from the block definition. Also, you need to take it into account that the block reference could be scaled/rotated, which also result in different extents from the block definition's.

2. There is no API available to access dynamic design in block definition, so your code comment "<= this conditional statement needs to work!" is not doable.

If your goal is to know all possible extents of a dynamic BLOCK REFERENCE, it is rather simple:

1. Get a dynamic property name list available in the block reference (keep in mind, other dynamic properties rather than Visibility could also result in different extents);

2. loop through the property one by one and set it and get the extents of the block reference.

Of course, if combination of more than one dynamic properties could lead to different extents, then things are quite complicated and it would up to you to find out.

In the simple case (assume you only have one property/Visibility with a list of values), you can then do this (pseudo code):

Dim originalVal as Object
Dim propVals() As Object
Dim i as Integer
Dim j As Integer
Dim prop As AcadDynamicBlockReferenceProperty
Dim props As Variant

//Get the list of values of the property/Visibility
props=TheBlockRef.GetDynamicBlockProperties()
For i=0 To Ubound(props)
    prop=props
    If prop.PropertyName=[The target property] Then
       For j=0 To Ubound(prop.AllowedValues)
           Redim Preserve propVals(j)
           propVals(j)=prop.AllowedValues(j)
       Next
       Exit For
    End If
Next

//Loop through the priperty/visibility states
Dim state as object
For i=0 to Ubound(propVals)

    set state=propVals(i)

    '' Get the block reference's property/visibility to the value   

    '' Get block reference's extents in this state

Next



GILESP

  • Newt
  • Posts: 42
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #2 on: January 11, 2017, 12:06:53 PM »
Hi Norman,

The intention is to find the extents of the block for the currently visible state - in this case the visibility states refer to front, top, bottom and side elevations of a panel mounted control or connector, but I only need to know the extents of the front elevation for panel layout purposes.

I understand your argument with regard to the attributes - however in this instance attributes are irrelevant, though I didn't state that in the original question. Scaling shouldn't be applied in the intended usage, and rotation is allowed for in another part of the code.

The code as it's currently written (i.e. without my commented line) will already return all possible extents as it ignores visibility parameters, but due to the dynamic nature of the blocks, it is throwing up false values as it's getting the extents of a view/orientation that isn't needed.

Your point no2 is a disappointment, as it means a pretty major rethink of this project, perhaps to find a way of interrogating the block reference rather than the definition -or by using the anonymous blocks that Autocad creates to represent dynamic block references..? 

back to the drawing board I think.. :(
..END OF LINE..

GILESP

  • Newt
  • Posts: 42
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #3 on: April 26, 2018, 08:33:51 AM »
Update:

After leaving the problem for a while, I revisited it from a different angle.

The goal is to find the max and min extents of a block, so with that in mind I decided that exploding the block reference will resolve down the visibility states and discard any invisible geometry, this can then be assessed in a conventional manner.  As the explode method leaves the original block unaffected, it is then simple to delete the new exploded objects once they've been interrogated.
..END OF LINE..

Dlanor

  • Bull Frog
  • Posts: 263
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #4 on: April 26, 2018, 01:06:43 PM »
Update:

After leaving the problem for a while, I revisited it from a different angle.

The goal is to find the max and min extents of a block, so with that in mind I decided that exploding the block reference will resolve down the visibility states and discard any invisible geometry, this can then be assessed in a conventional manner.  As the explode method leaves the original block unaffected, it is then simple to delete the new exploded objects once they've been interrogated.

You can used GetBoundingBox Method to find the extents of a block, but once again you are going to hit a problem with dynamic blocks; if an element has a "move", "stretch", "scale".........etc dynamic property. The bounding box will be different for each block reference even though it is based on the same block definition.

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #5 on: May 11, 2018, 01:40:14 PM »
Take a look at the anonymous BlockTableRecord (ABTR) associated with each BlockReference
There is no need to interact with any of the dynamic block API

The ABTR holds a copy of all the block entites and you can review them for their visibility property.

pseudo:
Code: [Select]
get block references
get block definition (regardless of dynamic or other)
go through the entities getting visibility and grow your bounding box
-skip non constant attributes

transform bounding box by block ref transform
go through attribute collection, grow bounding box for each visible attribute
~et voila~

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Accessing Visiblity properties within a dynamic block definition
« Reply #6 on: May 11, 2018, 02:14:28 PM »
just for fun, here's a c# implementation, I didn't test it with attributes. I only tested it with visibility and that works fine. Enjoy!

Code - C#: [Select]
  1.         [CommandMethod("getbrExtents")]
  2.         public void getBlockRefExtents()
  3.         {
  4.             var doc = Application.DocumentManager.MdiActiveDocument;
  5.             var ed = doc.Editor;
  6.             var db = doc.Database;
  7.             var peo = new PromptEntityOptions("\nSelect block reference");
  8.             peo.SetRejectMessage("\nNot a block reference");
  9.             peo.AddAllowedClass(typeof(BlockReference), true);
  10.             var pr = ed.GetEntity(peo);
  11.             if (pr.Status != PromptStatus.OK) return;
  12.             using (var tr = db.TransactionManager.StartTransaction())
  13.             {
  14.                 var br = (BlockReference)tr.GetObject(pr.ObjectId, OpenMode.ForRead);
  15.                 ed.WriteMessage("\n got extents: {0}", GetBlockExtents(br));
  16.             }
  17.         }
  18.         public Extents3d GetBlockExtents(BlockReference br)
  19.         {
  20.             using (var tr = br.Database.TransactionManager.StartTransaction())
  21.             {
  22.                 HashSet<Extents3d> extents = new HashSet<Extents3d>();
  23.                 var btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);
  24.                 foreach (ObjectId id in btr)
  25.                 {
  26.                     var ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
  27.                     if (id.ObjectClass == RXObject.GetClass(typeof(AttributeDefinition)))
  28.                     {
  29.                         var ad = (AttributeDefinition)ent;
  30.                         if (ad.Constant && ad.Visible)
  31.                             extents.Add(ad.GeometricExtents);
  32.                     }
  33.                     else if (ent.Visible)
  34.                     {
  35.                         extents.Add(ent.GeometricExtents);
  36.                     }
  37.                 }
  38.                 foreach (ObjectId id in br.AttributeCollection)
  39.                 {
  40.                     var ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
  41.                     if (ent.Visible)
  42.                     {
  43.                         extents.Add(ent.GeometricExtents);
  44.                     }
  45.                 }
  46.                 var minX = extents.Min(e => e.MinPoint.X);
  47.                 var minY = extents.Min(e => e.MinPoint.Y);
  48.                 var minZ = extents.Min(e => e.MinPoint.Z);
  49.                 var maxX = extents.Max(e => e.MaxPoint.X);
  50.                 var maxY = extents.Max(e => e.MaxPoint.Y);
  51.                 var maxZ = extents.Max(e => e.MaxPoint.Z);
  52.                 tr.Commit();
  53.                 var brextents = new Extents3d(new Point3d(minX, minY, minZ), new Point3d(maxX, maxY, maxZ));
  54.                 brextents.TransformBy(br.BlockTransform);
  55.                 return brextents;
  56.             }
  57.         }