Block Manager -> ERROR No geometry found

Hi,

i thought this was solved but this is still happening to v6 and v7 I constantly get those entries in the block manager:

I reported this long time ago here.

@pascal @stevebaer I don’t know who notify about it. Can you mark the appropriate person to this?

Hello - please post a file that has some of these, or send to tech@mcneel.com, with a link back here in your comments. I see, on the linked topic’s private comments, that the developer tried to reproduce this and could not.

-Pascal

Recording from V7 (V6 behaves identical)

Files (when file is opened again those error gain numbers and behaves like empty InstanceDefinitions)


That horribly bloats the file as each deleted block leaves this mess

V6 File block_bug_v6.3dm (75.4 KB)
V7 File block_bug_v7.3dm (59.1 KB)

Hello - does this happen if you disable Octane and VRay in Options > Plug-ins page, then close and re-open Rhino?

-Pascal

Yup. Turned them off relaunched rhino and block_bug_v7_no_engines.3dm (48.8 KB)

I’ll try in safe mode also in a sec.
Safe is ok - actually thats caused by my plugin :sweat_smile: But this never happens in v5 only in v6 and v7

@pascal i spotted the issue this starts happening after calling this method Rhino.RhinoDoc.ActiveDoc.InstanceDefinitions.Compact(true);

I guess this now should be moved to the developer category as this is programming related issue.
@dale do you see any particular thing why Compact() triggers such issue? This one is called in
Rhino.Commands.Command.EndCommand with if (e.CommandEnglishName == "BlockManager") some code and then idefTable.Compact(true) - and as i said v5 doesn’t suffer cause of this only v6 and v7

Ok. So far i checked that it doesn’t matter when i call Compact(true) it always create the same problem it can be anywhere it causes alwyas the same highly undesired side effect.

Below is enough to start this happening.

from scriptcontext import doc
 
if __name__ == "__main__":
    doc.InstanceDefinitions.Compact(True)
1 Like

@dale i also found out that Rhino.RhinoDoc.ActiveDoc.InstanceDefinitions.Purge(idefIndex); suffers from the same side effect.

In particular in such order:

iDefTable.Delete(i, false, true);
iDefTable.Purge(i);

Hi @D-W,

Can you provide a model and source code, that I can run here, that repeat the issue you are seeing?

Thanks,

– Dale

Hi @dale,

Sure. Here you are. Open this file(v7) bm_bug_recreate.3dm (272.5 KB) then run this code bm_recreate_code.py (115 Bytes) and open BlockManager and you should see this:

Exactly same procedure open 3dm run this code bm_recreate_code_2.py (111 Bytes) and open BlockManager and you should see the same as above.

As a sidenote its weird that when i delete idef from idefTable i need to purge it - otherwise next time when i will want to create idef which have the same one as deleted one i will get notice that such block alread exists.

I was able to track this down and fix it. The problem is with the call to ‘doc.InstanceDefinitions.Compact’ which was deleting instance definition geometry but accidentally clearing the definitions’ IsDeleted flag. The BlockManager was reporting exactly what was happening, there was an instance definition in the table with no geometry.

The following code works around the issue.

from scriptcontext import doc

doc.InstanceDefinitions.Delete(0,True,False)
doc.InstanceDefinitions.Compact(True)
doc.InstanceDefinitions.Delete(0,True,False)
doc.Views.Redraw()

This issue was reported as RH-64200 and there is a fix pending for Rhino 7.6.

1 Like

Hi @JohnM,

as @D-W mentions, the issue also occurs at doc.InstanceDefinitions.Purge(). Issue RH-64200 does not seem to address that.

Do you have a workaround for that as well?

my version:

Version 7 SR16
(7.16.22067.13001, 2022-03-08)
Commercial

Hi @timcastelijn,

Can you provide us a simple way of repeating this?

Thanks,

– Dale

hi @dale ,

thanks for your response. Steps to reproduce:

  1. open “main_test_file.3dm”
  2. run script below to:
    1. embed all linked blocks in model
    2. make all blocks ‘linked’ again
  3. open ‘_BlockManager’ to see the ‘ERROR …’

I expect sc.doc.InstanceDefinitions.Purge() function inside unembedBlocks() to completely remove the block definition, but it seems some data is not deleted

best regards,
Tim

Main_test_file.3dm (154.4 KB)
D_2nd_level_reference.3dm (383.9 KB)
D_referenced_detail.3dm (156.6 KB)
$_block_with_ref.3dm (156.6 KB)

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
from collections import OrderedDict
import re

def getBlockParameters(blockInstanceName):
    """
    function to get parameters stored in blockDescription. This is file specific information and equal for
    all block instances from the same definition

    Args:
        blockInstanceName: name of a blockdefinition in the file

    Returns: dict

    """
    blockDescription = rs.BlockDescription(blockInstanceName)

    params = OrderedDict()
    if blockDescription:

        m = re.findall('#TNM_(.+?)=(.*);', blockDescription)

        if m:
            for parameter in m:

                try:
                    value = json.loads(parameter[1])
                except:
                    value = parameter[1]

                params[parameter[0]] = value

    return params


def updateBlockParameters(blockInstanceName, params):
    """
    function to store/update parameters in blockDescription. This is file specific information and equal for
    all block instances from the same definition

    Args:
        blockInstanceName: name of a blockdefinition in the file
        params: dict containing key, value pairs

    Returns: None

    """
    oldParams = getBlockParameters(blockInstanceName)

    newParams = oldParams

    for k, v in params.items():
        newParams[k] = v

    blockDescription = ""
    for key, value in newParams.items():

        if isinstance(value, dict):
            value = json.dumps(dict, ensure_ascii=False)

        if value == None:
            value = ''
        new = '#TNM_%s=%s;\n' % (key, value)
        blockDescription += new

    rs.BlockDescription(blockInstanceName, blockDescription)


def relinkBlockFromFile(idef):
    """
    function to reload block from file, regardless wether file was changed in the meantime

    Args:
        idef: InstanceDefinition

    Returns: None
    """
    params = getBlockParameters(idef.Name)
    blockPath = params.get('blockPath')
    
    # change the source archive to read contents from the file 
    updateType = Rhino.DocObjects.InstanceDefinitionUpdateType.Linked
    sc.doc.ActiveDoc.InstanceDefinitions.ModifySourceArchive(idef.Index, blockPath, updateType, True)
    idef.LayerStyle = Rhino.DocObjects.InstanceDefinitionLayerStyle.Active


def embedBlockInModel(blockName):
    """
    function to embed block in model

    Args:
        blockName: string, block definition name

    Returns: None
    """
    
    # store filename in TNM_blockparameters (or BlockAttributes)
    filename = rs.BlockPath(blockName)
    updateBlockParameters(blockName, {'blockPath': filename})

    #embed the block 
    result = rs.Command('_NoEcho !_-BlockManager Properties "' + blockName + '" UpdateType Embedded _enter _enter',
                        False)


def embedBlocks():
    """
    function to embed all block definitions (direct or referenced) into model

    Args:
        blockNames: list of blockdefinition names to embed

    Returns: None
    """
    for idef in sc.doc.ActiveDoc.InstanceDefinitions.GetList(True):
        if not idef.Name:
            continue


            
        updateBlockParameters(idef.Name, {'isReference':  rs.IsBlockReference(idef.Name)})
        embedBlockInModel(idef.Name)


def unembedBlocks():
    """
    function to unembed all block definitions embedded by embedBlocks() 
    and reload block objects from file

    Args:
        blockNames: list of blockdefinition names to embed

    Returns: None
    """
    
    #first purge all blocks that were embedded by embedBlocks()
    for idef in sc.doc.ActiveDoc.InstanceDefinitions.GetList(True):
        if not idef.Name:
            continue
            
        
        params = getBlockParameters(idef.Name)
        isReference = params.get('isReference')
        
        # print 'beforepurge', idef.Name, isReference, idef.IsReference, idef.IsTenuous
        if isReference != 'False':
            sc.doc.InstanceDefinitions.Purge(idef.Index)
            sc.doc.InstanceDefinitions.Compact(True)
            sc.doc.InstanceDefinitions.Purge(idef.Index)
            sc.doc.Views.Redraw()
    
    # for the remaining blockDefinitions, discard the embedded geometry and reload the file geometry
    for idef in sc.doc.ActiveDoc.InstanceDefinitions.GetList(True):
        if not idef.Name:
            continue
        params = getBlockParameters(idef.Name)
        isReference = params.get('isReference')

        if isReference == 'False':
            relinkBlockFromFile(idef)
                
    

embedBlocks()
unembedBlocks()    

# print all current blockNames
for item in rs.BlockNames():
    print item
    

Hi @timcastelijn,

This is where the script goes sideways:

 sc.doc.InstanceDefinitions.Purge(idef.Index)
 sc.doc.InstanceDefinitions.Compact(True)
 sc.doc.InstanceDefinitions.Purge(idef.Index)

If you check the return value, you’ll see that the call to Purge fails because there are still instance references in the document. Delete all these first before purging. InstanceDefinition.GetReferences will get you all the references. Also, you shouldn’t need to call Compact.

– Dale