Creating 2d surface from Rows x Cols controlpoints

hi There,

Im trying to deform a texture using a grid of control points that initially are a uniform grid (texture is not deformed) and one can move control points to deform texture (a map between the rectangle and the new 2d surface)

Seems like a simple thing. However, after I create the surface, the result of PointAt(u,v), 0 <= u,v <= 1 are very different from the control points values (in the form Point4d(x,y ,0,1))

    size = [10, 10]
    dim = 3
    u_degree = 2
    v_degree = 2
    # creates internal uninitialized arrays for 
    # control points and knots
    self._surf = NurbsSurface.Create(
        u_degree + 1,
        v_degree + 1,
    u_knot = [0] * (size[0] + u_degree - 1)
    v_knot = [0] * (size[1] + v_degree - 1)

    for i in range(u_degree):
        u_knot[i] = 0

    for i in range(u_degree, len(u_knot)):
        u_knot[i] = 1.0

    for i in range(v_degree):
        v_knot[i] = 0

    for i in range(v_degree, len(v_knot)):
        v_knot[i] = 1.0

    # add the knots
    for i in range(0, len(self._surf.KnotsU)):
        self._surf .KnotsU[i] = u_knot[i]
    for j in range(0, len(self._surf.KnotsV)):
        self._surf .KnotsV[j] = v_knot[j]

    items = gridItem.GetItems()
    for row in range(len(items)):
        for col in range(len(items[row])):
            item = items[row][col]
            pos = item.pos()
            # log.error('>>>>>>>> ITEM row,col = %r, %r =>> %r, %r', row,col,pos.x(), pos.y())
            self._surf.Points[col, row] = Point4d(pos.x(), pos.y(), 0, 1)

Currently my control points vary x,y in range (0,0 to 460, 250)

But PointAt retturns in the range completelly different (75, 35).

I guess is something related to the knots. I have 11 knots.

What I need is the control points to stay in the surface matching teh regular grid initially, and then the grid will be deformed so the surface can map the texture deformation

What is missing?

Hi @pablo.cael,

Does this help?

import Rhino
import scriptcontext as sc

def create_deformable_plane(corners, u_degree, v_degree, u_points, v_points):
    p0, p1, p2, p3 = corners
    domain0 = Rhino.Geometry.Interval(0.0, p0.DistanceTo(p1))
    domain1 = Rhino.Geometry.Interval(0.0, p0.DistanceTo(p3))
    srf = Rhino.Geometry.NurbsSurface.Create(3, False, 2, 2, 2, 2)
    srf.Points.SetPoint(0, 0, p0)
    srf.Points.SetPoint(1, 0, p1)
    srf.Points.SetPoint(0, 1, p3)
    srf.Points.SetPoint(1, 1, p2)
    srf.KnotsU[0] = 0.0
    srf.KnotsU[1] = domain0.Length
    srf.KnotsV[0] = 0.0
    srf.KnotsV[1] = domain1.Length
    if u_degree > 1:
    if v_degree > 1:
    new_points = u_points - u_degree - 1
    span = domain0.Length
    dx = span / (new_points + 1)
    s0 = domain0.Min
    for i in range(0, new_points):
        s0 += dx
    new_points = v_points - v_degree - 1
    span = domain1.Length
    dx = span / (new_points + 1)
    s0 = domain1.Min
    for i in range(0, new_points):
        s0 += dx
    return srf
def test_deformable_plane():
    rc, corners = Rhino.Input.RhinoGet.GetRectangle()
    if rc != Rhino.Commands.Result.Success: 
        return rc
    srf = create_deformable_plane(corners, 2, 2, 10, 10)
    if srf and srf.IsValid:


– Dale

RH-58858 is fixed in the latest WIP

Hi Dale, thanks for the reply and sorry for the delay.
Unfortunatelly, Im not sure why I was not able to make it work, as I try to use it with degree 3 and configurable number of points. I want each control point to be movable and independent so I need to add control points in the grid. I have tried this:

indent preformatted text by 4 spaces

static ON_NurbsSurface create_deformable_plane( int width, int height,  int u_degree, int v_degree, int u_points,  int v_points) {
    auto domain0 = ON_Interval(0.0, width);
    auto domain1 = ON_Interval(0.0, height);

 auto srf = ON_NurbsSurface();
srf.Create(3, false, u_degree+1, v_degree+1, u_points, v_points);
double offsetu = 1.0 / (u_points-1);
double offsetv = 1.0 / (v_points-1);
int iu,iv;
iu = 0;
iv = 0;
srf.MakePeriodicUniformKnotVector(0, offsetu);
srf.MakePeriodicUniformKnotVector(1, offsetv);
for(double u =0; u <= 1; u+=offsetu) {
  iv = 0;
  for(double v =0; v <= 1; v+=offsetv) {
    srf.SetCV(iu, iv, ON_3dPoint(domain0.ParameterAt(u), domain1.ParameterAt(v), 0.0));


return srf;


but strangely, when creating the plane with width=10 and height=10 and calling PointAt, within [0,1] parameter space, Im getting the domain space to be from 0 to 11.6667 and not from 0 to 10.

Now, the most important thing for me is the knot vector. I need my control points to pass throw the data points, like a Piecewise Bézier… If you can help me just setting up the knot vector correctly so my control points grid pass through the data always and PointAt() function interpolates correctly.

Ps: Im now using the C++ api!
Ps2: I have already read the knot vector guidelines but I cannot make it work well.
Ps3: Im pretty sure Im the one not knowing how to do things right, I thank you for the patience and the help!

thanks a lot.


Hi @pablo.cael,

Did you try my Python script? Did you try porting it to C++?

– Dale

Hi Dale, first of all, thanks a lot for the replies so far.
I have tried your example in c++. It seems to retrieve the correct points at extremes of parametrization t in [0,1], u in [0,1]. But I havent checked more since I actually need a grid of controlpoints that can be manipulated, and not a linear grid from 4 points. I want all controlpoints to pass through the image data, so I need a a correct knot vector for that (like a piecewise bspline), so initially, the controlpoints grid is a regular grid passing through the image pixels. I have tried to create this with this latest code, but seems that controlpoints are not passing through the data since extremes of parametrization do not match extremes do the domain.

Is it possible to come up with a knot vector for this purpose?


Maybe its easier to just implement a tensor product of splines in my case, since I actually want a spline surface so each control point passes through the data. ;}

Hi @pablo.cael,

Sorry, but it is unclear to me what you want. Can you use Rhino command(s) to produce the surface? If so, can you post the geometry?


– Dale