Approximating to a grid


#1

Hi, this is my fist post here, and I’m a newcomer to rhino too.

I hope someone can help me out. I’ve got a model of some terrain made up of various surfaces and I want to use this to populate a list representing an x,y grid with height values, I’m using python to script this.

As I see it, the way to achieve this would be to set up a couple of a nested for loops to draw out a regular field of vertical lines and record the intersection point of each line.

Does this seem like a sensible way to do things? If so, what function do I need to use to check the intersection?

I hope I’ve made sense, let me know if you need me to go into any more details. Thanks.


#2

Hi Andrew,

Could you attach that terrain model please?
Thank you.


#3

I might just create a grid of points and project those to the surface(s) using ProjectPointToSurface or ProjectPointToMesh if it’s meshes.

–Mitch


#4

Here’s the model - contors.3dm (12.0 MB).

I’m studying architecture and this was put together by one of my fellow students who is far more proficient with rhino than I am. It’s not really mine to share, but I can’t see that posting it here will cause any problems. Thanks.


#5

That seems rather simpler than what I was proposing. I’ll give it a go and see what happens. Cheers.


#6

Here is a simple example with Mitch’s method - by using ProjectPointToSurface function. Please download both .3dm and .py files. Make sure your “pedestal” Layer is turned off before running the script, otherwise you will have labels on the bottom of your pedestal too.
Two additional layers gets created, one for the projected points, one for the labels.
To run the .py file select: Tools -> PythonScript -> Run

import rhinoscriptsyntax as rs
'''populate your surfaces, polysurfaces and extrusions with projected regular grid of points, and assign it's elevation as annotation text dot'''

def surfacePointHeight(ptsInU,ptsInV):
    if ptsInU and ptsInV:
        # selecting, creating a top surface of a boundingbox
        select = rs.Command("_SelSrf ")
        select = rs.Command("_SelPolysrf ")
        select = rs.Command("_SelExtrusion ")
        allSrfPlsrf = rs.GetObjects("",0,False,True,False)
        if allSrfPlsrf:
            rs.EnableRedraw(False)
            boxPts = rs.BoundingBox(allSrfPlsrf)
            rectanglePts = boxPts[-4:]
            rectanglePts.append(boxPts[-4])
            rectangle = rs.AddPolyline(rectanglePts)
            srf = rs.AddPlanarSrf(rectangle)
            rs.DeleteObject(rectangle)
            centroid = rs.SurfaceAreaCentroid(srf)
            srfScaled = rs.ScaleObject(srf,centroid[0],[0.95,0.95,0.95])

            # generating points on top surface
            domainU = rs.SurfaceDomain(srfScaled, 0)
            domainV = rs.SurfaceDomain(srfScaled, 1)
            uRange = domainU[1]-domainU[0]
            vRange = domainV[1]-domainV[0]
            stepU = uRange/(ptsInU - 1)
            stepV = vRange/(ptsInV - 1)
            startDomainU = domainU[0]
            startDomainV = domainV[0]
            uvList = []
            for i in range(ptsInU):
                u =  startDomainU + i*stepU
                for j in range(ptsInV):
                    v = startDomainV + j*stepV
                    uvList.append([u,v])
            ptsHorz = []
            for uv in uvList:
                pt = rs.EvaluateSurface(srfScaled, uv[0], uv[1])
                pt_id = rs.AddPoint(pt)
                ptsHorz.append(pt_id)
            rs.DeleteObject(srfScaled)

            # projecting points to lower srfs,polysrfs and extrusions
            ptsProj = rs.ProjectPointToSurface(ptsHorz, allSrfPlsrf, [0,0,-1])
            rs.DeleteObjects(ptsHorz)
            for ptProj in ptsProj:
                text = ptProj[2]
                text = "%1.0f" % text
                ptZ = rs.AddTextDot(text,ptProj)
                pt_id = rs.AddPoint(ptProj)
                rs.AddLayer("TextDot")
                rs.ObjectLayer(ptZ,"TextDot")
                rs.AddLayer("Point_Z",[0,120,255])
                rs.ObjectLayer(pt_id,"Point_Z")
                rs.Redraw()

        else:
            print "Something went wrong. You probably do not have any surfaces, polysurfaces or extrusions"
            return
    else:
        print "You did not enter the number of points in X and/or Y direction"
        return


# function input
x = rs.GetInteger("How many points in X direction do you want")
y = rs.GetInteger("How many points in Y direction do you want?")

# function call
surfacePointHeight(x,y)

contors2b.3dm (8.1 MB)

surfacePointHeight.py (2.8 KB)


#7

Wow! Thanks for your comprehensive example. I had put together something rather more bare-bones. My code works okay for a small number of points, but stops responding for larger values.

I’m very new to python. My programming background is in web scripting, so I’m more experienced in PHP, javascipt and perl. I don’t know whether my code is at fault, or if I’m running into some memory limitation. I might be able to make more headway if I output the values into a file then process it with something I’m more familiar with.

I’ve posted my script below, could you let me know if I’m doing something stupid?

Thanks.

import rhinoscriptsyntax as rs
import math

objs = rs.ObjectsByType(8)
heightarray=[[0 for j in range(600)] for i in range(800)]

rs.EnableRedraw(False)

for x in range(0,800000,1000):
  for y in range(0,600000,1000): 
    currentheight=0;
    for currentobject in objs:
      spotheight = rs.ProjectPointToSurface([-x,y,13000],currentobject,(0,0,-1))
      if(spotheight):
        if(spotheight[0][2]>currentheight):
          currentheight=spotheight[0][2]
    print x,y,int(currentheight)
    heightarray[int(x/1000)][int(y/1000)]=int(currentheight)

rs.EnableRedraw(True)

#8

You are selecting only surfaces with that “8” at rs.ObjectsByType(8). If you want to include polysurfaces too, add another 4 ( rs.ObjectsByType(8 | 4). The problem is that I do not know what is the filter number for extrusions (there was one in you model). So Instead of rs.ObjectsByType I used Rhino’s commands: SelSrf, SelPolysrf, SelExtrusion.
Appart from that you do not have to iterate surfaces, polysurfaces and extrusions** through rs.ProjectPointToSurface, as this function does that automatically. Just pass it the list of all the upper three ones you want your points to project to.
Point grid you’re creating assumes that your model is located in the first quadrant of Cartesian system, whereas in the model you attached it was located in second.
I am not sure if such a high number of point coordinates is a problem or not - 480 000 of them.

Try adding this part to my upper code: it will export the coordinates of your projected points in the form of .csv file.
Or just download the attached file.

             # export point coordinates
            filename = rs.SaveFileName("Save csv file","*.csv||", None, "projectedPoints", "csv")
            file = open(filename, 'w')
            headerline = "X,Y,Z\n"
            file.write(headerline)
            for ptProj in ptsProj:
                x = ptProj[0]
                y = ptProj[1]
                z = ptProj[2]
                line = "%.4f,%.4f,%.4f \n" %(x,y,z)
                file.write(line)
            file.close()

** this seems to be a missing information in the help file. Function works on extrusions too, and nobody knows if that extrusion is rotated or not.

surfacePointHeight2.py (3.3 KB)


#9

[quote=“djordje, post:8, topic:4587”]You are selecting only surfaces with that “8” at rs.ObjectsByType(8)[/quote] That’s my inexperience with Rhino, I hadn’t realised there was anything else to find in that model.

[quote]Appart from that you do not have to iterate surfaces, polysurfaces and extrusions** through rs.ProjectPointToSurface, as this function does that automatically.[/quote] That’s rather more powerful than I expected - I’ll take account of that in future.

Odd… I seemed to be getting valid output form the script - I’d better check the co-ordinates.

I suppose it depends how python handles these - but stuffing them all into a losely-typed array is probably not such a smart idea!

I’ll give your code a go and see what I can get out.

Thanks for all your help, it’s been really useful and encouraging.


#10

That’s my inexperience with Rhino, I hadn’t realised there was anything else to find in that model.

If you select a particular object in Rhino and then click on “Details”, a window will appear with an information about that object, and among other data, on the top of the window you will see what kind of an object you have selected:

Type the “SelAll” command to check how many and of what type, objects do you currently** have.

** objects in layers that are turned off will not be selected and counted.

Point grid you’re creating assumes that your model is located in the first quadrant of Cartesian system, whereas in the model you attached it was located in second.

My bad, sorry. I have just noticed you have that minus at “[**-**x,y,13000]” which means you are populating the correct quadrant - the second one.