CSV to Table

Hi All,

Is there someone who can edit the first python script so that you can preview the result before baking? similar to the 2nd python script. Thanks!

1st: Quick Bom Generation from CSV.gh (8.7 KB)
2nd:
DataGrid_test.gh (12.2 KB)

Have you asked JWalton or Florian, the respective authors of those scripts?

Quick Bom Generation from CSV.gh

"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "JWalton"
__version__ = "2019.11.28"

import rhinoscriptsyntax as rs
import Rhino
import Rhino as rc
import scriptcontext as sc
import Rhino.Geometry as rg
from operator import itemgetter


# Set the script context to the current Rhino doc
sc.doc = rc.RhinoDoc.ActiveDoc

def CSVBom():

    listA = _csv
    #a = listA
    plane=Rhino.Geometry.Plane.WorldXY
    ListTotals = []
    table = _pointFeed
    rs.EnableRedraw(False)
    ListLarge = []
    ListLen = []
    a=0



    for row  in listA:
                row = row.split(";")
                rowA = []
                for str in row:
                    str = str.replace("\n","")
                    rowA.append(str)
                rowB = []
                for aa in rowA:
                    rowB=aa.split(',')
                if len(rowB)<= len(rowA):rowB=rowA
                list=[]
                A=len(rowB)
                ListLen.append(A)
                for txt in rowB:
                    if txt :
                       test = rs.AddText(txt, plane, height=_textSize, font='Arial', font_style=0, justification=None)
                       bb = rs.BoundingBox(test, plane, in_world_coords=True)
                       if bb :
                           large =round(( bb[1].DistanceTo(bb[0])),1)
                           if large < 0: largeur=large*(-1)
                           list.append(large)
                           rs.DeleteObject(test)
                       else : 
                           large=0.0
                           list.append(large)
                    else : 
                           large=0.0
                           list.append(large)
                ListLarge.append(list)

    N = max(ListLen)
    d_max = {i: max(map(itemgetter(i), ListLarge)) for i in range(N)}
    #Largest 
    ListMax = d_max.values()
    #Layers
    rs.AddLayer("Name")
    rs.AddLayer("Detail Lines",parent="Name")
    rs.AddLayer("Texts",parent="Name")

    
    listB = _csv


    Group=rs.AddGroup()
    ListGroup = []
    H = _textSize
    font='Arial'
    count=1


    for row  in listB:
        V=0
        Y=0
        row = row.split(";")
        rowA = []
        for str in row:
            str = str.replace("\n","")
            rowA.append(str)
        rowB = []
        for aa in rowA:
            rowB=aa.split(',')
        if len(rowB)<= len(rowA):rowB=rowA
        for value in rowB:
            #text placement
            placeA= ((-H*2) - (float(count)*(H*2)))
            placeB= ((-H) - (float(count)*(H*2)))
            #rectangle
            LX = (ListMax[Y])+(H*.25+H)
            recA=rs.AddRectangle(plane,LX,H*2)
            VV=V+(LX/2)
            recA=rs.MoveObject(recA,[V,placeA,0.0])
            rs.ObjectLayer(recA,"Detail Lines")
            ListGroup.append(recA)
            #text
            txt=value
            if txt :
                txtA=rs.AddText (txt,plane,H,font,0,2 + 131072)
                txtA=rs.MoveObject(txtA,[VV,placeB,0.0])
                rs.ObjectLayer(txtA,"Texts")
                ListGroup.append(txtA)
            #new text placement
            Y=Y+1
            V=V+LX
            #New Line
        count=count+1
    ListGroup=rs.MoveObjects(ListGroup,table)
#    rs.EnableRedraw(True)
    rs.AddObjectsToGroup(ListGroup,Group)

if x:
    CSVBom()

# Then set the script context back to the Grasshopper doc
sc.doc = ghdoc

DataGrid_test.gh

"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "Florian"
__version__ = "2020.02.06"

import Rhino as rh
import scriptcontext as sc
import ghpythonlib as gh



vec = rh.Geometry.Vector3d(0,0,1)
Pl = rh.Geometry.Plane(P,vec)


# get dimstyle and change settings
ds = rh.DocObjects.DimensionStyle()


# change text properties ( a lot of options )
ds.Font = rh.DocObjects.Font(F)
ds.TextHeight = H



LL = [] #TextEntity_Width_Collumn
LLS = [] #TextEntity_Collumn
BB = [] #TextEntity_BoundingBox_Column
BHeight = [] #TextEntity_Height_All
for i in range(0,T.BranchCount):
    B = [] # TextEntity_BoundingBox
    BB.append(B) 
    L = [] # TextEntity_Width
    LL.append(L)
    LS = [] # TextEntity 
    LLS.append(LS)
    for j in T.Branch(i):
        Te = rh.Geometry.TextEntity
        te = Te.Create(j,Pl,ds,False,0,0)
        
        LS.append(te)
        L.append(te.TextModelWidth)
        Bounding_Box = te.GetBoundingBox(True)
        B.append(Bounding_Box)
        BHeight.append(abs(Bounding_Box.Min.Y-Bounding_Box.Max.Y))


# Get TextEntity_BoundingBox_with max width and inflate them with max height
LB = [] # TextEntity_BoundingBox with max width and height inflated
for e,i in enumerate(LL):
    ind = i.index(max(i)) #index with max Textentity_BoundingBox_Width
    BB_Max_W_H = BB[e][ind]
    Max_Width_Height = abs(abs(BB_Max_W_H.Min.Y-BB_Max_W_H.Max.Y)-max(BHeight))/2
    Width = abs(BB_Max_W_H.Min.X-BB_Max_W_H.Max.X)
    BB_Max_W_H.Inflate(0,Max_Width_Height,0)
    LB.append(BB_Max_W_H)


# inflate TransB
for i in LB:
    widthB = abs(i.Min.X-i.Max.X)
    i.Inflate(widthB*0.05,0,0)
    tr = rh.Geometry.Transform.Translation(widthB*0.05,0,0)
    i.Transform(tr)





FirstP = LB[0].GetCorners()[1]
counter = 0
TransB = []
Transf = []
TransB.append(LB[0])
def TransBox(FirstP,counter):
    if counter < len(LB)-1:
        counter = counter + 1
        Vec = rh.Geometry.Vector3d(0,0,1)
        PlaneTo = rh.Geometry.Plane(FirstP,Vec)
        B = LB[counter]
        PlaneFrom = rh.Geometry.Plane(B.Min,Vec)
        Trans = rh.Geometry.Transform.PlaneToPlane(PlaneFrom,PlaneTo)
        bbtr = Trans.TransformBoundingBox(LB[counter])
        NextP = bbtr.GetCorners()[1]
        TransB.append(bbtr)
        Transf.append(Trans)
        return TransBox(NextP,counter)
    else:
        return False

TransBox(FirstP,counter)







# get longest BranchList
ListLenght = []
for i in range(0,T.BranchCount):
     ListLenght.append(len(T.Branch(i)))


# Create Transform for Bounding_Box_Grid
BBox_Height = rh.Geometry.Transform.Translation(0,TransB[0].Min.Y-TransB[0].Max.Y,0)
count = 0
TransBB = []
TransBB.append(BBox_Height)
def TransB_to_grid(BBox_Height,TransBB,count):
    if count <  max(ListLenght)-2:
        count = count + 1
        TransBB.append(TransBB[-1]*BBox_Height)
        return TransB_to_grid(BBox_Height,TransBB,count)
    else:
        return False

TransB_to_grid(BBox_Height,TransBB,count)





# Create Bounding_Box_Grid
B_Grid = []
for i in TransB:
    Grid = []
    Grid.append(i)
    B_Grid.append(Grid)
    for j in TransBB:
        Grid.append(j.TransformBoundingBox(i))


# Create Union BoundingBox from BoundingBoxGrid

UB_Grid = rh.Geometry.BoundingBox.Unset
for i in B_Grid:
    for j in i:
        UB_Grid.Union(j)





# Move TextEntity to BoundingBoxGrid
Vec = rh.Geometry.Vector3d(0,0,1)
for e,i in enumerate(B_Grid):
    for ee,ii in enumerate(i):
        # Get transform TextEntityBoundingBox to gridBox
        Planefrom = rh.Geometry.Plane(BB[e][ee].Min,Vec)
        Planeto = rh.Geometry.Plane(ii.Min,Vec)
        trans = rh.Geometry.Transform.PlaneToPlane(Planefrom,Planeto)
        LLS[e][ee].Transform(trans,ds)



# left top corner
CLT = UB_Grid.GetCorners()[3]
LT = rh.Geometry.Transform.PlaneToPlane(rh.Geometry.Plane(CLT,Vec),Pl)


# left bottom corner
CLB = UB_Grid.GetCorners()[0]
LB = rh.Geometry.Transform.PlaneToPlane(rh.Geometry.Plane(CLB,Vec),Pl)

# right top corner
CRT = UB_Grid.GetCorners()[2]
RT = rh.Geometry.Transform.PlaneToPlane(rh.Geometry.Plane(CRT,Vec),Pl)

# right bottom corner
CRB = UB_Grid.GetCorners()[1]
RB = rh.Geometry.Transform.PlaneToPlane(rh.Geometry.Plane(CRB,Vec),Pl)



for e,i in enumerate(B_Grid):
    for ee,ii in enumerate(i):
        if C == 'LeftTop':
            LLS[e][ee].Transform(LT,ds)
            ii.Transform(LT)
        elif C == C == 'LeftBottom':
            LLS[e][ee].Transform(LB,ds)
            ii.Transform(LB)
        elif C == C == 'RightTop':
            LLS[e][ee].Transform(RT,ds)
            ii.Transform(RT)
        elif C == C == 'RightBottom':
            LLS[e][ee].Transform(RB,ds)
            ii.Transform(RB)







# create TextEntity Surface 
TextS = []
for e,i in enumerate(LLS):
    TextSS = []
    TextS.append(TextSS)
    for j in i:
        TextSS.append(j.CreateSurfaces(ds,0,0))



# BoundingBox_Grid to Rectangle Grid
Rect_Grid = []
for i in B_Grid:
    Grid = []
    Rect_Grid.append(Grid)
    for j in i:
        Grid.append(rh.Geometry.Rectangle3d(Pl,j.Min,j.Max))



L = []
L.append(LLS)
L.append(B_Grid)




# TextSurface and Rectangles into DataTrees
S = gh.treehelpers.list_to_tree(TextS)
G = gh.treehelpers.list_to_tree(Rect_Grid)



# textentity rectangle
#box = rh.Geometry.Rectangle3d(P,bb.Min,bb.Max)

# bake text with same settings like textentity to get rhinotext object
if Bake:
    sc.doc = rh.RhinoDoc.ActiveDoc
    for e,i in enumerate(LLS):
        for ee,j in enumerate(i):
            rh.RhinoDoc.ActiveDoc.Objects.AddText(j.Text,j.Plane,j.TextHeight,F,False,False)
            rh.RhinoDoc.ActiveDoc.Objects.AddRectangle(Rect_Grid[e][ee])
    sc.doc = ghdoc

#rh.Display.DisplayPipeline.DrawBox()

Hi @James_Parrott ,

Thank you for posting the codes itself. I already asked the author from this forum

but no reply from him yet.

Great. It’s good to check. Who owns the first file by the way?

To get a “preview” in Grasshopper, the things to be previewed just need to be sent to a global variable, and an output param of the same name added to the Python component. The component in the second file has output params called S and G, that’s all that’s needed for a “preview” (outputting objects into Grasshopper from GhPython).

The complicated part is the first script does everything to the Rhino document on the fly, with rhinoscriptsyntax targetting Rhino:

But the second uses Rhino Common and targets Grasshopper (ghdoc) for most of it, only switching the context to Rhino.RhinoDoc.ActiveDoc at the end if Bake.

So it might not take long at all to make the basic refactor above, but more is needed to guarantee it will all work as wished, i.e. testing it. The results of each individual modifications to the Rhino document (every call to rs.Addsomething and rs.Movesomething) need to be checked that they both work and produce the same change in the different Grasshopper context, and then baked afterwards.

I am definitely able to do this. However from experience, adapting code to run in a different context to the only context it was originally written and tested for, can quickly get fiddly. It can be quicker to rewrite it entirely. So this might only take an hour at best, but at worst it could require two days.

1 Like

Hi @James_Parrott ,

Sorry for bothering you with this one. I have little to no knowledege about python or other coding. It will be great and very helpful not only for me but to others also if you will be able to do it.

Regarding the first file, it is from this link from @Rickson if im not mistaken:

1 Like

I had some time to check this scripts and I added Text Size and Text Alignment options to the DataGrid_test.gh definition.

DataGrid.gh (14.5 KB)

Will be good if the Python script have an option to output Text entities to be able to edit the text in Rhino.

Made some additional progress. Found a way to generate and bake Text entities using the Elefront components, however looks like there is a bug into the Define Text Object component because the justification and font size do not override the default style at bake time. I can see on the viewport the justification and font size changes but at bake time will reset everything to the values inherited from the default Dimension Style used.

DataGrid_Elefront.gh (24.6 KB)