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

SelectCrossingWindow only selects objects currently visible on the screen

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
Anonymous
2796 Views, 11 Replies

SelectCrossingWindow only selects objects currently visible on the screen

SelectCrossingWindow only selects objects currently visible on the screen.

 

Is this expected behavior?  I would prefer not to be required to zoom extents before running the command.

 

Thanks,

Jeff

Detroit, MI

11 REPLIES 11
Message 2 of 12
hgasty1001
in reply to: Anonymous

Hi,

 

Yes, it's the expected behavior (no matter if is crossing or window, fence, etc) , it's the same in Autolisp, so you have to zoom out enough to fit the objects on the screen.

 

Gaston Nunez

 

 

Message 3 of 12
Anonymous
in reply to: hgasty1001

Then is there a better method for selecting objects?

 

How is it that creating a selection set on a closed drawing works?

 

Just wondering if I'm barking up the wrong tree...

 

Thanks,

jeff

Message 4 of 12
mcicognani
in reply to: Anonymous

You can use filters using dxf properties codes. This works on database, thus selecting also objects not visible.

Something like this:

 

TypedValue[] tvs1 = new TypedValue[4] 
{ 
      new TypedValue((int)DxfCode.Operator, "<and"),
      new TypedValue((int)DxfCode.Start, "INSERT"),
      new TypedValue((int)DxfCode.LayerName, szLayerCell),
      new TypedValue((int)DxfCode.Operator, "and>")
}

PromptSelectionResult psr = doc.Editor.SelectAll(new SelectionFilter(tvsd));
if (psr.Status == PromptStatus.OK && psr.Value.Count > 0)
{

}

 

I used those in the beginning, thinking that an internal function was the fastest way to filter a database, but I soon discovered that traversing a drawing in .NET is quite fast, so recently I prefer to traverse the database by myself and filter whatever entities I need.

Something like this:

 

// get block table, here you'll find *modelspace, *paperspace and block definitions
BlockTable
 bt = (BlockTable)tr.GetObject(dwg.BlockTableId, OpenMode.ForRead); foreach (ObjectId btrId in bt) {     BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
// here you may want to filter which space you need
if (!btr.Name.StartsWith("*")) continue;
    foreach (ObjectId o in btr)     {         DBObject dbo = tr.GetObject(o, OpenMode.ForRead, true);         if (!dbo.IsErased && !dbo.IsDisposed && (dbo is Entity))         {             Entity ent = dbo as Entity;
// valid entity, check whatever you need             if (ent.LayerId == idLayerSource)             {
// open entity for change and do whatever you need                 ent.UpgradeOpen();


            }         }     } }
Message 5 of 12
Anonymous
in reply to: mcicognani

I am currently using the selection method with dxf filters and it does not select objects off screen.  I was hoping maybe I was missing a flag or option somewhere.

 

I may have to switch over to looping through the db as well.

 

Thanks everyone for the feedback,

Jeff

Message 6 of 12
mcicognani
in reply to: Anonymous

You said you were using SelectCrossWindow(), in the example reported I used SelectAll().

In my experience, SelectAll() works on the db directly and allows to select entities not visible on screen, even on hidden layers.

 

Message 7 of 12
Anonymous
in reply to: mcicognani

I finally had time to test this out and you are correct SelectAll() finctions differently than SelectCrossingWindow().  Thank you, I beleive this puts me on a better path.

 

With this new direction would you recommend I also abandon selection filters?  I was already having issues filtering for block names when the blocks were dynamic anyway.

 

If I'm already stepping through each BTR looking for criteria I could just filter there.

 

Thanks,

Jeff

Message 8 of 12
mcicognani
in reply to: Anonymous

Given that you're looking for blocks and the database provide a neat BlockTable to traverse, I'd suggest you'd go through this path, it's also a lot faster than filtering or traversing the whole database.

From BlockTable is also easy to collect the BlockReference instances, both for standard and dynamic blocks, so it seems to have lot of advantages and no downsides.

 

You may want to traverse the db starting from ModelSpace/Paperspace if you need some hierarchy information, like blocks inside blocks or inside xrefs. In this case you may want a recursive function looking for blockreferences and step in for blocktablerecords.

I have plenty of this C# working code, let me know if you need something like this.

Message 9 of 12
Anonymous
in reply to: mcicognani

I've tried two methods.  The first was to look through the entire database for blockreferences then verify their names.  Then I modified it to this:

 

Using myTrans As Transaction = DbIn.TransactionManager.StartTransaction
                    Dim thisSpaceBTR As BlockTableRecord = DbIn.CurrentSpaceId.GetObject(OpenMode.ForRead)
                    For Each thisOID As ObjectId In thisSpaceBTR
                        Dim thisEnt As Entity = thisOID.GetObject(OpenMode.ForRead)
                        If TypeOf thisEnt Is BlockReference Then
                            Dim thisBlockRef As BlockReference = thisOID.GetObject(OpenMode.ForRead)
                            Dim thisBTR As BlockTableRecord = thisBlockRef.BlockTableRecord.GetObject(OpenMode.ForRead)
                            Dim blockName As String = Tools.Blocks.GetBlockName(thisBTR)
                            If blockName.StartsWith("Anno-Keyn-Hedr-") Or blockName.StartsWith("Anno-Keyn-Rows-") Or blockName = "Anno-Keyn-Endr" Then
                                thisBlockRef.UpgradeOpen()
                                thisBlockRef.Erase()
                            End If
                        End If
                    Next
                    myTrans.Commit()
                End Using

It only bothers with the current space.  I'd imagine this is more efficient since my current need is only for the current space.  The GetBlockName sub simply gets the effective name so that I can include dynamic blocks.

 

I originally tried to erase the BTR, but I kept receiving an exception error.  Instead I erase the blockreference and it seems to work fine.

 

My next steps are going to be to step into blocks and xrefs so I could use your help.

 

Thank you,

Jeff

Message 10 of 12
mcicognani
in reply to: Anonymous

You can erase the BlockTableRecord only if there is no BlockReference, quite understandable, I'd say...

 

If you want to recurse inside blocks or XREFs, keep in mind that a block definition and the current space (ModelSpace or PaperSpace) are just of the same type: BlockTableRecord. So you may create a recursive function that accept a BlocktableRecord to analyze, the first call would be made passing the current space and check every entity like you already do. When you find a BlockReference you can get the linked BlockTableRecord and you may call the same function recursively.

 

Something like this (sorry, just C#):

 

private void ParseBlocksDb(Database db, String szFormat, System.Data.DataTable dt, int iRound)
{
 
    Transaction tr = db.TransactionManager.StartTransaction();
 
    try
    {
        BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
        String szFilename = Path.GetFileNameWithoutExtension(db.Filename);
 
        // browse modelspace
        BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
        _ParseBlocksBtr(ms, tr, szFormat, dt, iRound, szFilename);
 
        // browse paperspace
        ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.PaperSpace], OpenMode.ForRead);
        _ParseBlocksBtr(ms, tr, szFormat, dt, iRound, szFilename);
 
    }
    catch (System.Exception ex)
    {
        MessageBox.Show("Unexpected error: " + ex.Message);
    }
    finally
    {
        tr.Dispose();
    }
}
 
private void _ParseBlocksBtr(BlockTableRecord ms, Transaction tr)
{
    int p;
 
    BlockReference br;
    BlockTableRecord btr;
 
    foreach (ObjectId o in ms)
    {
        DBObject dbo = tr.GetObject(o, OpenMode.ForRead, false);
        if ((dbo is BlockReference) && (!dbo.IsErased))
        {
            br = dbo as BlockReference;
 
            // retrieve blockdefinition, regardless if standard or dynamic
            btr = (BlockTableRecord)tr.GetObject(br.IsDynamicBlock ? br.DynamicBlockTableRecord : br.BlockTableRecord, OpenMode.ForRead);
 
// even XRefs have a BlockTableRecord, you can check the property btr.IsFromExternalReference || btr.IsFromOverlayReference

            // recurse inside block/xref, if needed             
_ParseBlocksBtr(btr, tr);

// do whatever you want with current reference

        }
    }
}

 

 

Message 11 of 12
Anonymous
in reply to: mcicognani

I have re-written the remainder of my code to completely abandon the concept of selection sets and I am relying solely on stepping through the BTRs.  I have also adopted the idea of passing along the transaction to use only one per command - very efficient.  I have considered trying this in the past, but your example showed me it is possible.  Lastly, I am using bounds of blockrefs to establich location - giving me the ability to concentrate on a particular area defined like a window.

 

It is going well, with one exception.  It ignores xrefs.  No errors, just seems to disregard them.  Here is where I am at:

 

VB.NET

Sub DeepDive(ByVal TransIn As Transaction, ByVal BTRin As BlockTableRecord, Optional ByVal windowPt1 As Point3d = Nothing, Optional ByVal windowPt2 As Point3d = Nothing)
        For Each thisOID As ObjectId In BTRin
            Dim thisEnt As Entity = thisOID.GetObject(OpenMode.ForRead)
            If TypeOf thisEnt Is BlockReference Then
                Dim thisBlockRef As BlockReference = DirectCast(TransIn.GetObject(thisOID, OpenMode.ForRead), BlockReference)
                Dim thisBTR As BlockTableRecord = DirectCast(TransIn.GetObject(thisBlockRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)

                'If a window is provided make sure the block is within it...
                If windowPt1 <> Nothing And windowPt2 <> Nothing Then
                    If Tools.IsWithin(thisBlockRef.Bounds.Value.MinPoint, windowPt1, windowPt2) And Tools.IsWithin(thisBlockRef.Bounds.Value.MaxPoint, windowPt1, windowPt2) Then
                        'Check for KN data
                        gatherKNdata(thisBlockRef, thisBTR)
                        'Then dive inside to look for more blockrefs
                        DeepDive(TransIn, thisBTR)
                    End If
                Else
                    'If no window is provided everything is allowed...
                    'Check for KN data
                    gatherKNdata(thisBlockRef, thisBTR)
                    'Then dive inside to look for more blockrefs
                    DeepDive(TransIn, thisBTR)
                End If
            ElseIf TypeOf thisEnt Is Viewport Then
                Dim myVP As Viewport = DirectCast(TransIn.GetObject(thisOID, OpenMode.ForRead), Viewport)

                'If a window is provided make sure the block is within it...
                If windowPt1 <> Nothing And windowPt2 <> Nothing Then
                    'If any of the viewports four corners are within the drawing area, include it
                    If Tools.IsWithin(myVP.Bounds.Value.MinPoint, windowPt1, windowPt2) Or _
                        Tools.IsWithin(myVP.Bounds.Value.MaxPoint, windowPt1, windowPt2) Or _
                        Tools.IsWithin(New Point3d(myVP.Bounds.Value.MinPoint.X, myVP.Bounds.Value.MaxPoint.Y, 0), windowPt1, windowPt2) Or _
                        Tools.IsWithin(New Point3d(myVP.Bounds.Value.MaxPoint.X, myVP.Bounds.Value.MinPoint.Y, 0), windowPt1, windowPt2) Then

                        Dim scaleFactor As Double = myVP.ViewHeight / myVP.Height
                        Dim myVPviewLL As New Point3d(myVP.ViewCenter.X - ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y - (myVP.ViewHeight / 2), 0)
                        Dim myVPviewUR As New Point3d(myVP.ViewCenter.X + ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y + (myVP.ViewHeight / 2), 0)
                        Dim myVPviewUL As New Point3d(myVP.ViewCenter.X - ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y + (myVP.ViewHeight / 2), 0)
                        Dim myVPviewLR As New Point3d(myVP.ViewCenter.X + ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y - (myVP.ViewHeight / 2), 0)

                        Dim myBT As BlockTable = DirectCast(TransIn.GetObject(HostApplicationServices.WorkingDatabase.BlockTableId, OpenMode.ForRead), BlockTable)
                        Dim msBTR As BlockTableRecord = DirectCast(TransIn.GetObject(myBT(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord)

                        DeepDive(TransIn, msBTR, myVPviewLL, myVPviewUR)
                    End If
                End If
            End If
        Next
    End Sub

 

C#

private void DeepDive(Transaction TransIn, BlockTableRecord BTRin, Point3d windowPt1 = null, Point3d windowPt2 = null)
{
	foreach (ObjectId thisOID in BTRin) {
		Entity thisEnt = thisOID.GetObject(OpenMode.ForRead);
		if (thisEnt is BlockReference) {
			BlockReference thisBlockRef = (BlockReference)TransIn.GetObject(thisOID, OpenMode.ForRead);
			BlockTableRecord thisBTR = (BlockTableRecord)TransIn.GetObject(thisBlockRef.BlockTableRecord, OpenMode.ForRead);

			//If a window is provided make sure the block is within it...
			if (windowPt1 != null & windowPt2 != null) {
				if (Tools.IsWithin(thisBlockRef.Bounds.Value.MinPoint, windowPt1, windowPt2) & Tools.IsWithin(thisBlockRef.Bounds.Value.MaxPoint, windowPt1, windowPt2)) {
					//Check for KN data
					gatherKNdata(thisBlockRef, thisBTR);
					//Then dive inside to look for more blockrefs
					DeepDive(TransIn, thisBTR);
				}
			} else {
				//If no window is provided everything is allowed...
				//Check for KN data
				gatherKNdata(thisBlockRef, thisBTR);
				//Then dive inside to look for more blockrefs
				DeepDive(TransIn, thisBTR);
			}
		} else if (thisEnt is Viewport) {
			Viewport myVP = (Viewport)TransIn.GetObject(thisOID, OpenMode.ForRead);

			//If a window is provided make sure the block is within it...
			if (windowPt1 != null & windowPt2 != null) {
				//If any of the viewports four corners are within the drawing area, include it

				if (Tools.IsWithin(myVP.Bounds.Value.MinPoint, windowPt1, windowPt2) | Tools.IsWithin(myVP.Bounds.Value.MaxPoint, windowPt1, windowPt2) | Tools.IsWithin(new Point3d(myVP.Bounds.Value.MinPoint.X, myVP.Bounds.Value.MaxPoint.Y, 0), windowPt1, windowPt2) | Tools.IsWithin(new Point3d(myVP.Bounds.Value.MaxPoint.X, myVP.Bounds.Value.MinPoint.Y, 0), windowPt1, windowPt2)) {
					double scaleFactor = myVP.ViewHeight / myVP.Height;
					Point3d myVPviewLL = new Point3d(myVP.ViewCenter.X - ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y - (myVP.ViewHeight / 2), 0);
					Point3d myVPviewUR = new Point3d(myVP.ViewCenter.X + ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y + (myVP.ViewHeight / 2), 0);
					Point3d myVPviewUL = new Point3d(myVP.ViewCenter.X - ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y + (myVP.ViewHeight / 2), 0);
					Point3d myVPviewLR = new Point3d(myVP.ViewCenter.X + ((myVP.Width * scaleFactor) / 2), myVP.ViewCenter.Y - (myVP.ViewHeight / 2), 0);

					BlockTable myBT = (BlockTable)TransIn.GetObject(HostApplicationServices.WorkingDatabase.BlockTableId, OpenMode.ForRead);
					BlockTableRecord msBTR = (BlockTableRecord)TransIn.GetObject(myBT(BlockTableRecord.ModelSpace), OpenMode.ForRead);

					DeepDive(TransIn, msBTR, myVPviewLL, myVPviewUR);
				}
			}
		}
	}
}

 

 

Your example leads me to believe that you can step into an xref just like a block - even though it is technically another DB.  Am I approaching this incorrectly?

 

Thanks,

Jeff

Message 12 of 12
Anonymous
in reply to: Anonymous

I figured it out!  It really is recognizing xrefs.  It was my own windowing that was skipping it.

 

Thank you mcicognani for all your help.

 

 

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