__author__ = "guev"
__version__ = "2021.03.09"

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

rs.EnableRedraw(False)

#defining transformation XForm
XY = Rhino.Geometry.Plane.WorldXY
toXY = Rhino.Geometry.Transform.PlanarProjection(XY)

#getting all document objects
sc.doc = Rhino.RhinoDoc.ActiveDoc
table = sc.doc.Objects
blocktable = sc.doc.InstanceDefinitions

#setting object types
InstRef = Rhino.DocObjects.ObjectType.InstanceReference
InstDef = Rhino.DocObjects.ObjectType.InstanceDefinition
ExtrusionType = Rhino.DocObjects.ObjectType.Extrusion
SurfaceType = Rhino.DocObjects.ObjectType.Surface

#flattening INSTANCE DEFINITIONS (referenced geometry as I understand it)
def flatten_InstDef(objDef):

    ObjDefIndex = objDef.Index
    Subobjects = objDef.GetObjects()
    NewObjects = []
    Attributes = []

    if Subobjects:
        for obj in Subobjects:
            ObjType = obj.ObjectType
            ObjAttributes = obj.Attributes
            if ObjType == InstRef:
                flatten_InstRef(obj)
            else :
                objtemp = obj.Geometry.Duplicate()
                objtemp = flatten_geometry(objtemp)
                NewObjects.append(objtemp)
                Attributes.append(ObjAttributes)

    sc.doc.InstanceDefinitions.ModifyGeometry(ObjDefIndex,NewObjects,Attributes)

#flattening INSTANCE REFERENCES (blocks using the definitions from above)
def flatten_InstRef(objRef):
    
    #instance reference insertion point moved to XY plane
    ObjRefID = objRef.Id
    up = -1 * (objRef.InsertionPoint.Z)
    moveUp = Rhino.Geometry.Transform.Translation(0,0,up)
    table.Transform(ObjRefID,moveUp,True)
    
    #forcing flattening of instance defintion - redondant
    #objDef = objRef.InstanceDefinition
    #flatten_InstDef(objDef)
    
    #flattening all subobjects
    Subobjects = objRef.GetSubObjects()
    if Subobjects:
        for obj in Subobjects:
            flatten_obj(obj)

#flattening objects
def flatten_obj(obj):

    ObjType = obj.ObjectType
    ObjID = obj.Id

    if ObjType == InstRef:
        flatten_InstRef(obj)
        return None
    elif ObjType == InstDef:
        flatten_InstDef(obj)
        return None
    elif ObjType == ExtrusionType or ObjType == SurfaceType:
        obj = obj.Geometry.ToBrep()

    table.Transform(ObjID,toXY,True)

#flattening pure geometry
def flatten_geometry(obj):
    
    ObjType = obj.ObjectType
    
    if ObjType == ExtrusionType or ObjType == SurfaceType:
        obj = obj.ToBrep()

    obj.Transform(toXY)
    return obj

# going through all instance definitions and objects

for b in blocktable:
    flatten_InstDef(b)

for o in table:
    flatten_obj(o)

rs.EnableRedraw(True)
