Tutorials | (back to the list of tutorials) |
Mathematics of NURBS Geometry
Similarly, a NURBS surface is defined by the formula below, where now control points Pi,j and weights wi,j are provided as n x m matrix. This is a function of two parameters u and v and it returns spatial coordinates corresponding to the input u and v.
For more detail description of NURBS geometries and basis functions, see Wikipedia pages of NURBS, B-Spline and Bernstein Polynomial
Creating NURBS Curves and Surfaces![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[] controlPoints1 = new IVec[4];
controlPoints1[0] = new IVec(0, 0, 0);
controlPoints1[1] = new IVec(20, 30, 30);
controlPoints1[2] = new IVec(40, -30, -30);
controlPoints1[3] = new IVec(60, 0, 0);
int deg1 = 3;
new ICurve(controlPoints1, deg1).clr(0);
IVec4[] controlPoints2 = new IVec4[4];
controlPoints2[0] = new IVec4(0, 0, 0, 1);
controlPoints2[1] = new IVec4(20, 30, 30, 0.5);
controlPoints2[2] = new IVec4(40, -30, -30, 0.5);
controlPoints2[3] = new IVec4(60, 0, 0, 1);
int deg2 = 3;
new ICurve(controlPoints2, deg2).clr(1.,0,0);
IVec[][] controlPoints3 = new IVec[][]{
new IVec[]{ new IVec(-70,0,0), new IVec(-70,20,30), new IVec(-70,40,0) },
new IVec[]{ new IVec(-50,30,30), new IVec(-50,50,60), new IVec(-50,70,30) },
new IVec[]{ new IVec(-30,-30,-30), new IVec(-30,-10,0), new IVec(-30,10,-30) },
new IVec[]{ new IVec(-10,0,30), new IVec(-10,20,60), new IVec(-10,40,30) }
};
int udeg3 = 3, vdeg3 = 2;
new ISurface(controlPoints3, udeg3, vdeg3).clr(0);
IVec4[][] controlPoints4 = new IVec4[][]{
new IVec4[]{ new IVec4(-70,0,0,1), new IVec4(-70,20,30,.5), new IVec4(-70,40,0,1) },
new IVec4[]{ new IVec4(-50,30,30,.5), new IVec4(-50,50,60,.5), new IVec4(-50,70,30,.5) },
new IVec4[]{ new IVec4(-30,-30,-30,.5), new IVec4(-30,-10,0,.5), new IVec4(-30,10,-30,.5) },
new IVec4[]{ new IVec4(-10,0,30,1), new IVec4(-10,20,60,.5), new IVec4(-10,40,30,1) }
};
int udeg4 = 3, vdeg4 = 2;
new ISurface(controlPoints4, udeg4, vdeg4).clr(1,.5,1);
Continuity of NURBS Geometry![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec curveEdgePt = new IVec(10,0,0);
IVec curveTangent = new IVec(20,20,20);
IVec[] cpts1 = new IVec[3];
cpts1[0] = curveEdgePt;
cpts1[1] = curveEdgePt.dup().sub(curveTangent);
cpts1[2] = new IVec(0, 40, -40);
IVec[] cpts2 = new IVec[4];
cpts2[0] = curveEdgePt;
cpts2[1] = curveEdgePt.dup().add(curveTangent);
cpts2[2] = new IVec(60,0,0);
cpts2[3] = new IVec(100,0,0);
new ICurve(cpts1, 2).clr(1.,0,0);
new ICurve(cpts2, 3).clr(.5,0,1);
// showing control points
for(int i=0; i < cpts1.length; i++){ new IPoint(cpts1[i]).clr(1.,0,0); }
for(int i=0; i < cpts2.length; i++){ new IPoint(cpts2[i]).clr(.5,0,1); }
// showing straight relationship
new ICurve(cpts1[1], cpts2[1]);
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec surfaceTangent1 = new IVec(20, 0, -10);
IVec surfaceTangent2 = new IVec(20, -20, -10);
IVec surfaceEdgePt1 = new IVec(0, 0, 0);
IVec surfaceEdgePt2 = new IVec(0, 30, 0);
IVec[][] cpts3 = new IVec[3][2];
cpts3[0][0] = surfaceEdgePt1;
cpts3[0][1] = surfaceEdgePt2;
cpts3[1][0] = surfaceEdgePt1.dup().sub(surfaceTangent1);
cpts3[1][1] = surfaceEdgePt2.dup().sub(surfaceTangent2);
cpts3[2][0] = new IVec(-10, 0, -30);
cpts3[2][1] = new IVec(-10, 30, -30);
IVec[][] cpts4 = new IVec[3][2];
cpts4[0][0] = surfaceEdgePt1;
cpts4[0][1] = surfaceEdgePt2;
cpts4[1][0] = surfaceEdgePt1.dup().add(surfaceTangent1);
cpts4[1][1] = surfaceEdgePt2.dup().add(surfaceTangent2);
cpts4[2][0] = new IVec(10, 0, 30);
cpts4[2][1] = new IVec(10, 30, 30);
new ISurface(cpts3, 2, 1).clr(0,0,1.);
new ISurface(cpts4, 2, 1).clr(0,.5,1.);
// showing control points
for(int i=0; i < cpts3.length; i++){
for(int j=0; j< cpts3[i].length; j++){ new IPoint(cpts3[i][j]).clr(0,0,1.); }
}
for(int i=0; i < cpts4.length; i++){
for(int j=0; j< cpts4[i].length; j++){ new IPoint(cpts4[i][j]).clr(0,.5,1.); }
}
// showing straight relationship
new ICurve(cpts3[1][0], cpts4[1][0]);
new ICurve(cpts3[1][1], cpts4[1][1]);
Point on NURBS Curve![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[] cpts=new IVec[]{new IVec(-60,0,0),new IVec(-20,0,0),
new IVec(20,0,60),new IVec(60,0,-30)};
ICurve curve = new ICurve(cpts, 2);
IVec pt1 = curve.pt(0.5);
IVec pt2 = curve.pt(0.8);
IVec pt3 = curve.pt(1.0);
// showing points
new IPoint(pt1).clr(1.,0,0);
new IPoint(pt2).clr(1.,.5,0);
new IPoint(pt3).clr(0,.5,0);
// using them for creating other geometries
new ICurve(new IVec(0,60,-20), pt1).clr(1.,0,0);
new ICurve(new IVec(0,60,-20), pt2).clr(1.,.5,0);
new ICurve(new IVec(0,60,-20), pt3).clr(0,.5,0);
Tangent on NURBS Curve![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[] cpts=new IVec[]{new IVec(-30,10,0),new IVec(-10,0,0),
new IVec(10,0,30),new IVec(30,0,-10)};
ICurve curve = new ICurve(cpts, 2);
IVec tan1 = curve.tan(0);
IVec tan2 = curve.tan(0.5);
IVec tan3 = curve.tan(0.8);
IVec tan4 = curve.tan(1.0);
// showing arrows at each point on the curve
tan1.show(curve.pt(0)).clr(1.,1.,0).size(10);
tan2.show(curve.pt(0.5)).clr(1.,0,0).size(10);
tan3.show(curve.pt(0.8)).clr(1,.5,0).size(10);
tan4.show(curve.pt(1.0)).clr(0,.5,0).size(10);
Point on NURBS Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[][] cpts = new IVec[][]{
new IVec[]{ new IVec(-40,-20,-20), new IVec(0,0,0), new IVec(40,0,-20) },
new IVec[]{ new IVec(-40,30,20), new IVec(0,30,0), new IVec(40,30,-10) }
};
ISurface surface = new ISurface(cpts,1,2);
IVec pt1 = surface.pt(0.5,0.5);
IVec pt2 = surface.pt(0.5,1.0);
IVec pt3 = surface.pt(0.3,0.2);
// showing points
new IPoint(pt1).clr(1.,0,0);
new IPoint(pt2).clr(1,.5,0);
new IPoint(pt3).clr(0,.5,0);
// using them for creating other geometries
new ICurve(new IVec(-20,0,40), pt1).clr(1.,0,0);
new ICurve(new IVec(-20,0,40), pt2).clr(1,.5,0);
new ICurve(new IVec(-20,0,40), pt3).clr(0,.5,0);
Tangent on NURBS Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[][] cpts = new IVec[][]{
new IVec[]{ new IVec(-40,-20,-20), new IVec(0,0,0), new IVec(40,0,-20) },
new IVec[]{ new IVec(-40,30,20), new IVec(0,30,0), new IVec(40,30,-10) }
};
ISurface surface = new ISurface(cpts,1,2);
IVec utan1 = surface.utan(0.5,0.5);
IVec utan2 = surface.utan(0.5,1.0);
IVec vtan1 = surface.vtan(0.5,0.5);
IVec vtan2 = surface.vtan(0.5,1.0);
// showing arrows at each point on the surface
utan1.show(surface.pt(0.5,0.5)).clr(1.,0,0).size(5);
utan2.show(surface.pt(0.5,1.0)).clr(0,0,1.).size(5);
vtan1.show(surface.pt(0.5,0.5)).clr(1,.5,0).size(5);
vtan2.show(surface.pt(0.5,1.0)).clr(0,.5,1).size(5);
Normal on NURBS Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[][] cpts = new IVec[][]{
new IVec[]{ new IVec(-40,30,20), new IVec(0,30,0), new IVec(40,30,-10) },
new IVec[]{ new IVec(-40,-20,-20), new IVec(0,0,0), new IVec(40,0,-20) }
};
ISurface surface = new ISurface(cpts,1,2);
IVec normal1 = surface.nrml(0.5,0.5).len(40);
IVec normal2 = surface.nrml(1.0,0.5).len(40);
IVec normal3 = surface.nrml(0.0,0.5).len(40);
IVec normal4 = surface.nrml(0.2,0.8).len(40);
// showing arrows at each point on the surface
normal1.show(surface.pt(0.5,0.5)).clr(1.,0,0).size(10);
normal2.show(surface.pt(1.0,0.5)).clr(1.,.5,0).size(10);
normal3.show(surface.pt(0.0,0.5)).clr(0,.5,0).size(10);
normal4.show(surface.pt(0.2,0.8)).clr(0,.5,1).size(10);
Offset Point on NURBS Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
size( 480, 360, IG.GL );
IVec[][] cpts = new IVec[][]{
new IVec[]{ new IVec(-40,30,20), new IVec(0,30,0), new IVec(40,30,-10) },
new IVec[]{ new IVec(-40,-20,-20), new IVec(0,0,0), new IVec(40,0,-20) }
};
ISurface surface = new ISurface(cpts,1,2);
IVec pt1 = surface.pt(0.5, 0.5, 10);
IVec pt2 = surface.pt(0.8, 0.5, 10);
IVec pt3 = surface.pt(0.8, 0.8, 10);
IVec pt4 = surface.pt(0.5, 0.8, 10);
// showing points
new IPoint(pt1).clr(1.,0,0);
new IPoint(pt2).clr(1.,.5,0);
new IPoint(pt3).clr(0,.5,0);
new IPoint(pt4).clr(0,.5,1);
// using them for creating other geometries
new ISurface(pt1,pt2,pt3,pt4).clr(.5,0,1);
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT