pythonmatplotlibsketchup

How to plot volumes with 3D points, lines and surfaces data (.geo file)


I need to plot 3D volumes defined with their surfaces, surfaces defined with line loops, line loops defined with lines, lines defined with points.

Here is an example:

Point(1) = x1,y1,z1
Point(2) = x2,y2,z2
Point(3) = x3,y3,z3
Point(4) = x4,y4,z4
Point(5) = x5,y5,z5
Point(6) = x6,y6,z6
Point(7) = x7,y7,z7
Point(8) = x8,y8,z8
Line(1) = Point(1), Point(2)
Line(2) = Point(2), Point(3)
Line(3) = Point(3), Point(4)
Line(4) = Point(4), Point(1)
Line(5) = Point(5), Point(6)
Line(6) = Point(6), Point(7)
Line(7) = Point(7), Point(8)
Line(8) = Point(8), Point(5)
Line(9) = Point(1), Point(5)
Line(10) = Point(2), Point(6)
Line(11) = Point(3), Point(7)
Line(12) = Point(4), Point(8)
Line loop(1) = Line(1), Line(2), Line(3), Line(4)
Line loop(2) = Line(5), Line(6), Line(7), Line(8)
Line loop(3) = Line(1), Line(10), Line(-5), Line(-9)
Line loop(4) = Line(2), Line(11), Line(-6), Line(-10)
Line loop(5) = Line(3), Line(12), Line(-7), Line(-11)
Line loop(6) = Line(4), Line(9), Line(-8), Line(-12)
Surface(1) = Line Loop(1) #top
Surface(2) = Line Loop(2) #bottom
Surface(3) = Line Loop(3)
Surface(4) = Line Loop(4)
Surface(5) = Line Loop(5)
Surface(6) = Line Loop(6)
Volume(1) = Surface(1), Surface(2), Surface(3), Surface(4), Surface(5), Surface(6)

https://i.sstatic.net/qrvIC.png

I have tried matplotlib and mayavi.mlab plot functions but none worked as I hoped. I also looked for a .geo import function but didn't find one.

These files (.geo files) are exported from SketchUp (Google 3D design software) and are imported in GMesh to create a mesh. In my case I would like to plot my volumes in Python before importing it in Gmesh.

Would someone have an idea to plot this kind of data ?


Solution

  • After few days of works, I got the answer, for displaying edges from a .geo file:

    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    import matplotlib.pyplot as plt
    import os
    from os import system
    from numpy import array, argsort, sqrt, unique, linspace
    fig = plt.figure ()
    ax = fig.add_subplot (1, 1, 1, projection = '3d', aspect = 1)
    
    ## Name of GEO file
    fileName = "vfv8_fusion.geo"
    
    ## Reading GEO file
    with open(fileName) as f:
      lineList = f.readlines()
    
    V,P,L,LL,PS,SL = [],[],[],[],[],[]
    e1,f1 = [],[]
    
    ## Separation of variables (points, lines, loop lines, plane surface, surface loop, volumes)
    for ii in range(len(lineList)):
    
        if lineList[ii][0:5]=="Point":  
            a1 = lineList[ii]
            a2 = a1.split('{')
            a3 = a2[1].split('}')
            a4 = a3[0].split(',')
            coord = [float(a4[0]),float(a4[1]),float(a4[2])]
            P.append(coord)
    
        if lineList[ii][0:5]=="Line(":
            b1 = lineList[ii]
            b2 = b1.split('{ ')
            b3 = b2[1].split(' }')
            b4 = b3[0].split(',')
            points_to_line = [int(float(b4[0])),int(float(b4[1]))]
            L.append(points_to_line)      
    
        if lineList[ii][0:9]=="Line Loop": 
            c1 = lineList[ii]
            c2 = c1.split('{')
            c3 = c2[1].split('}')
            c4 = c3[0].split(',')
            line_to_lineloop = []
            for jj in range(len(c4)):
                line_to_lineloop.append(int(float(c4[jj])))
            LL.append(line_to_lineloop)      
    
        if lineList[ii][0:13]=="Plane Surface":
            d1 = lineList[ii]
            d2 = d1.split('{')
            d3 = d2[1].split('}')
            d4 = d3[0].split(',')
            lineloop_to_planesurface = []
            for jj in range(len(d4)):
                lineloop_to_planesurface.append(int(float(d4[jj])))
            PS.append(lineloop_to_planesurface)   
    
        if lineList[ii][0:12]=="Surface Loop":
            e1.append(lineList[ii])
            e2 = e1[-1].split('{')
            e3 = e2[1].split('}')
            e4 = e3[0].split(',')
            planesurface_to_surfaceloop = []
            for jj in range(len(e4)):
                planesurface_to_surfaceloop.append(int(float(e4[jj])))
            SL.append(planesurface_to_surfaceloop)   
    
        if lineList[ii][0:6]=="Volume":
            f1.append(lineList[ii])
            f2 = f1[-1].split('{')
            f3 = f2[1].split('}')
            f4 = f3[0].split(',')
            surfaceloop_to_volume = []
            for jj in range(len(f4)):
                surfaceloop_to_volume.append(int(float(f4[jj])))
            V.append(surfaceloop_to_volume)   
    
    
    nb_points,nb_line,nb_lineloop,nb_planesurface,nb_surfaceloop,nb_volume = len(P),len(L),len(LL),len(PS),len(SL),len(V)
    
    ## Rewriting the list of lines with the coordinates of the points
    ## line1 = [point1, point2] becomes line1 = [[x1,y1,z1],[x2,y2,z2]]
    
    L_P = [[]]*len(L)
    for ii in range(len(L)):
        L_P[ii] = [[]]*len(L[ii])
        for jj in range(len(L[ii])):
            L_P[ii][jj] = P[L[ii][jj]-1]
    
    
    liste = [[]]*len(V)
    
    
    ## Rearrangement
    
    
    for ii in range(len(V)):#for each volume
        listlignes = []
        Vn = V[ii]#the corresponding surface loop list is retrieved
    
        for jj in range(len(Vn)):#for each surface loop in the volume
    
            Vnj = Vn[jj]
    
            SLn = SL[Vnj-1]#we get the list of the corresponding surface plane list
    
            for kk in range(len(SLn)):#for each plane surface
    
                SLnk = SLn[kk]
    
                PSn = PS[SLnk-1]#we get the list of the corresponding line loops
    
                for mm in range(len(PSn)):#for each ligne loop
    
                    PSnm = PSn[mm]
    
                    LLn = LL[PSnm-1]#we get the correspondign list of lines
    
                    for nn in range(len(LLn)):#for each line
    
                        LLnn = abs(LLn[nn])
    
                        Ln = L_P[LLnn-1]#we get the coordinates of the corresponding points
    
                        listlignes.append(Ln)#points are stored 2 by 2 (line by line)
    
    
        liste[ii] = listlignes#all lines are stored for each volume
    
    ## Definition of the limits of the graphic reference mark
    minX,maxX,minY,maxY,minZ,maxZ = 0,0,0,0,0,0
    for ii in range(len(P)):
        if P[ii][0]>maxX:
            maxX = P[ii][0]
        if P[ii][1]>maxY:
            maxY = P[ii][1]
        if P[ii][2]>maxZ:
            maxZ = P[ii][2]
        if P[ii][0]<minX:
            minX = P[ii][0]
        if P[ii][1]<minY:
            minY = P[ii][1]
        if P[ii][2]<minZ:
            minZ = P[ii][2]
    MAX = max(maxX,maxY,maxZ)
    MIN = min(minX,minY,minZ)
    
    ## Colors list
    colors_list = [[0,255,255], #aqua
                   [227,207,87], #banana
                   [0,0,255],#blue
                   [138,43,226], #blueviolet
                   [255,64,64], #brown1
                   [152,245,255], #cadetblue1
                   [255,97,3], #cadmiumorange
                   [127,255,0], #chartreuse1
                   [61,89,171], #cobalt
                   [0,100,0],   #darkgreen
                   [153,50,204], #darkorchid
                   [155,205,155], #darkseagreen3
                   [255,20,147], #deeppink1
                   [28,134,238], #dodgerblue2
                   [255,48,48], #firebrick1
                   [34,139,34], #forestgreen
                   [112,112,112], #gray44
                   [255,105,108], #hotpink
                   [238,99,99], #indianred2
                   [173,216,230], #lightblue
                   [255,255,0]] #yellow1           
    
    ## Normalization of RGB values
    colors_list_RBG = colors_list
    for ii in range(len(colors_list)):
        colors_list_RBG[ii][0] = float(colors_list[ii][0])/255
        colors_list_RBG[ii][1] = float(colors_list[ii][1])/255
        colors_list_RBG[ii][2] = float(colors_list[ii][2])/255
    
    ## We store the volumes we want to display   
    for ii in range(len(liste)):
        poly2 = Line3DCollection(liste[ii],colors=colors_list_RBG[ii])
        ax.add_collection3d(poly2)
    
    ax.set_xlim(MIN,MAX)
    ax.set_ylim(MIN,MAX)
    ax.set_zlim(MIN,MAX)
    
    ## Display
    plt.show ()