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.Faces[0].ChangeSurface(newBrep.AddSurface(nurbs));
  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