SelectCrossingWindow only selects objects currently visible on the screen

SelectCrossingWindow only selects objects currently visible on the screen

Anonymous
適用対象外
3,549件の閲覧回数
11件の返信
メッセージ1/12

SelectCrossingWindow only selects objects currently visible on the screen

Anonymous
適用対象外

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

0 件のいいね
解決済み
3,550件の閲覧回数
11件の返信
返信 (11)
メッセージ2/12

hgasty1001
Advisor
Advisor

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

 

 

0 件のいいね
メッセージ3/12

Anonymous
適用対象外

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

メッセージ4/12

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();


            }         }     } }
0 件のいいね
メッセージ5/12

Anonymous
適用対象外

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

0 件のいいね
メッセージ6/12

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.

 

0 件のいいね
メッセージ7/12

Anonymous
適用対象外

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

0 件のいいね
メッセージ8/12

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.

0 件のいいね
メッセージ9/12

Anonymous
適用対象外

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

0 件のいいね
メッセージ10/12

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

        }
    }
}

 

 

0 件のいいね
メッセージ11/12

Anonymous
適用対象外

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

0 件のいいね
メッセージ12/12

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.

 

 

0 件のいいね