DisplayConduit - DrawForeground - Exploded Block - Z-Fighting?


I’m working on a Display Conduit script in Python 3 that works for block instances as well.

My issue is that I can get the Block nested geometry to show in the conduit but it is not drawing in the foreground like the rest of my object types.

You can see that Meshes (M), Breps (B), and Curves (C) are all showing correctly but the BI (exploded breps, curves, etc.) are having z.fighting issues with the parent/non-exploded block.

Thank you all for any guidance you can provide!

Here’s the code, it’s a hybrid of the C# @menno provided here and the explode block sample code that @dale provided [here] adapted for Python 3(RhinoCommon nested instances - #2 by dale):

Rhino Test File:
test_file.3dm (3.4 MB)

Python Code:

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
from System.Drawing import Color

class PreviewAttributes:
    def __init__(self):
        self.ObjectColor = Color.Black
        self.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
        self.WireDensity = 1
        self.LayerIndex = -1
        self.CurveThickness = 5
        self.PointStyle = Rhino.Display.PointStyle.ControlPoint
        self.PointPixels = 3
        self.TextColor = Color.White

    def Selected():
        attr = PreviewAttributes()
        attr.ObjectColor = Color.BlueViolet  # Default is Color.Yellow
        attr.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
        attr.TextColor = Color.Black
        return attr

    def New():
        attr = PreviewAttributes()
        attr.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromLayer
        attr.LayerIndex = sc.doc.Layers.CurrentLayer.LayerIndex
        return attr

    def Warning():
        attr = PreviewAttributes()
        attr.ObjectColor = Color.Red
        attr.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
        attr.TextColor = Color.White
        return attr

class PreviewDisplayConduit(Rhino.Display.DisplayConduit):
    def __init__(self):
        super(PreviewDisplayConduit, self).__init__()
        self._objects = {}
        self._exploded_geometries = []

    def AddObject(self, obj, attributes):
        if obj:
            self._objects[obj] = attributes

    def ClearObjects(self):

    def DrawForeground(self, e):
        for obj, attr in self._objects.items():
            color = attr.ObjectColor
            material = Rhino.Display.DisplayMaterial(color)
            if attr.ColorSource == Rhino.DocObjects.ObjectColorSource.ColorFromLayer:
                layer = sc.doc.Layers[attr.LayerIndex]
                color = layer.Color

            if isinstance(obj, Rhino.Geometry.Curve):
                e.Display.DrawCurve(obj, color, attr.CurveThickness)
            elif isinstance(obj, Rhino.Geometry.Brep):
                e.Display.DrawBrepShaded(obj, material)
                # e.Display.DrawBrepWires(obj, color, attr.WireDensity)
            elif isinstance(obj, Rhino.Geometry.Point):
                e.Display.DrawPoint(obj.Location, attr.PointStyle, attr.PointPixels, color)
            elif isinstance(obj, Rhino.Geometry.Mesh):
                e.Display.DrawMeshWires(obj, color)
            elif isinstance(obj, Rhino.Geometry.TextDot):
                e.Display.DrawDot(obj.Point, obj.Text, color, attr.TextColor)
            elif isinstance(obj, Rhino.Geometry.InstanceReferenceGeometry):
                # Explode Block Geometry Here
                self.ExplodeBlockHelper(e, obj, attr, Rhino.Geometry.Transform.Identity)
                Rhino.RhinoApp.WriteLine("Obj Type Is: " + str(obj))
        # Draw exploded geometries after processing all objects
        for geom, attr in self._exploded_geometries:
            color = attr.ObjectColor
            material = Rhino.Display.DisplayMaterial(color)
            if attr.ColorSource == Rhino.DocObjects.ObjectColorSource.ColorFromLayer:
                layer = sc.doc.Layers[attr.LayerIndex]
                color = layer.Color

            if isinstance(geom, Rhino.Geometry.Curve):
                e.Display.DrawCurve(geom, color, attr.CurveThickness)
            elif isinstance(geom, Rhino.Geometry.Brep):
                e.Display.DrawBrepShaded(geom, material)
            elif isinstance(geom, Rhino.Geometry.Point):
                e.Display.DrawPoint(geom.Location, attr.PointStyle, attr.PointPixels, color)
            elif isinstance(geom, Rhino.Geometry.Mesh):
                e.Display.DrawMeshWires(geom, color)
            elif isinstance(geom, Rhino.Geometry.TextDot):
                e.Display.DrawDot(geom.Point, geom.Text, color, attr.TextColor)

    def ExplodeBlockHelper(self, e, iref, attr, xform):
        idef = sc.doc.InstanceDefinitions.FindId(iref.ParentIdefId)
        if idef is None:
            return False

        xform = xform * iref.Xform
        do_xform = xform.IsValid and not xform.Equals(Rhino.Geometry.Transform.Identity)

        objects = idef.GetObjects()
        for obj in objects:
            if obj is None:

            if isinstance(obj, Rhino.DocObjects.InstanceObject):
                # Explode any nested instances...
                self.ExplodeBlockHelper(e, obj.Geometry, attr, xform)

            geom = obj.Geometry.Duplicate()
            if do_xform:
                if xform.SimilarityType == Rhino.Geometry.TransformSimilarityType.NotSimilarity:
                    if not geom.MakeDeformable() and isinstance(geom, Rhino.Geometry.Curve):
                        geom = geom.ToNurbsCurve()

                if not geom.Transform(xform):

                if xform.SimilarityType == Rhino.Geometry.TransformSimilarityType.OrientationReversing:
                    if isinstance(geom, Rhino.Geometry.Brep):
                    elif isinstance(geom, Rhino.Geometry.Mesh):
                        geom.Flip(True, True, True)

            self._exploded_geometries.append((geom, attr))

    def CalculateBoundingBox(self, e):
        bbox = Rhino.Geometry.BoundingBox()
        for obj in self._objects.keys():

def PreviewObjects():
    selected_objects = rs.GetObjects("Select objects to preview")
    if not selected_objects:

    conduit = PreviewDisplayConduit()
    attr = PreviewAttributes.Selected()

    for obj_id in selected_objects:
        rhino_obj = rs.coercegeometry(obj_id)
        conduit.AddObject(rhino_obj, attr)

    conduit.Enabled = True

    rs.GetString("Press Enter to end preview")
    conduit.Enabled = False

if __name__ == "__main__":