# How to do laplacian smoothing on a nurbs surface

I want to do a laplacian smoothing on a surface moving the control points towards the average of its neighbors, but something I’m doing wrong because the following failures arise:

How should I update the edges?

How do I keep the seams fixed when it’s closed?

``````private void RunScript(Brep Brp, double S, int I, bool N, ref object A)
{

if(Brp == null || !Brp.IsValid)return;
if(I <= 0 || S <= 0){ A = Brp; return;}

S = Math.Min(1.0, S);
double S1 = 1.0 - S;

BrepFace bf = Brp.Faces[0];
NurbsSurface nurbs = bf.ToNurbsSurface();
Brep newBrep = Brp.DuplicateBrep();

int UC = nurbs.Points.CountU;
int VC = nurbs.Points.CountV;
bool cu = nurbs.IsClosed(0);
bool cv = nurbs.IsClosed(1);

while(I-- > 0){
NurbsSurface newSrf = new NurbsSurface(nurbs);
for(int i = 0; i < UC ; i++){
for(int j = 0; j < VC; j++){
if(N){
PointFaceRelation pfr = bf.IsPointOnFace(i, j);
if(pfr == PointFaceRelation.Boundary || pfr == PointFaceRelation.Exterior )continue;
}
Rhino.Geometry.ControlPoint cp = nurbs.Points.GetControlPoint(i, j);
Point3d avePt = new Point3d();
double aveW = 0;
int cnt = 0;
int id = -1;
if(GetID(i - 1, cu, UC, out id)){
Rhino.Geometry.ControlPoint cpa = nurbs.Points.GetControlPoint(id, j);
avePt += cpa.Location;
aveW += cpa.Weight;
cnt++;
}
if(GetID(i + 1, cu, UC, out id)){
Rhino.Geometry.ControlPoint cpa = nurbs.Points.GetControlPoint(id, j);
avePt += cpa.Location;
aveW += cpa.Weight;
cnt++;
}
if(GetID(j - 1, cv, VC, out id)){
Rhino.Geometry.ControlPoint cpa = nurbs.Points.GetControlPoint(i, id);
avePt += cpa.Location;
aveW += cpa.Weight;
cnt++;
}
if(GetID(j + 1, cv, VC, out id)){
Rhino.Geometry.ControlPoint cpa = nurbs.Points.GetControlPoint(i, id);
avePt += cpa.Location;
aveW += cpa.Weight;
cnt++;
}
avePt /= cnt;
aveW /= cnt;

newSrf.Points.SetControlPoint(i, j, new ControlPoint(
avePt * S + cp.Location * S1,
aveW * S + cp.Weight * S1));
}
}
nurbs = newSrf;
}
newBrep.Compact();
string log;
if(!newBrep.IsValidWithLog(out log)) Print(log);

A = newBrep;

}

public static bool GetID(int i, bool cu, int U, out int ri){
ri = -1;
if(!cu && (i < 0 || i >= U))return false;
ri = (i + U) % U;
return true;
}
``````

SurfaceSmooth.gh (33.7 KB)

If the surface is periodic then it will have a few rows of overlapping control-points at either end. These points need to remain overlapping during transformations otherwise you introduce gaps or kinks.

It is actually quite tricky to do this right. Have a look at a rebuild torus with ‘6’ control-points:

The `_List` command shows that actually the number of control-points in both the U and V directions is 9, not 6. That’s because a periodic surface has overlaps around the seam, meaning the real number of control-points is the number you think + degree. The Rhino UI hides these points from you, but as a programmer you’ll have to deal with them.

If the surface isn’t periodic but merely closed, then you’d still have a row of double-cps along the seam, and those are hidden by Rhino too.

Either way, figuring out the neighbours of a specific control-point isn’t as easy as [u - 1, v], [u, v-1], [u + 1, v], [u, v+1]

1 Like

Thank you very much for the answers. It’d be great if you see the file.

I am aware of that, but I don’t know how to deal with it.

I tried not to move them, but it doesn’t work.

In what way? Are they all available at NurbsSurface.Points? How do I know if a control point is one of these?

No? In which cases? Aren’t they always UV ordered?

Yeah all good questions, and I don’t know the answers. I’ll have to do some digging through the apis and code examples, but not on a Sunday…

2 Likes