home processing download documents tutorial python tutorial gallery source about
 Tutorials (back to the list of tutorials)

Lines on Surface

     Grid Points on Surface

Here we take a NURBS surface from an input file using IG.open() method shown in the previous section. In the following example, iGeo imports geometries from 3dm file or OBJ file and puts the imported surfaces by IG.surfaces() method as shown in this section. You can put any NURBS surface via 3dm file or OBJ. Here is a sample input files used in the example codes below. The code below use a special type of for loop for( ISurface surf : surfs ) and this for loop executes the body for each member of the array (in this case surfs is an array of ISurface) and the each member is put in the new variable (in this case ISurface surf). With this for loop, the operation in the code is applied to all surfaces in the file.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;

  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt = surf.pt( i*uinc, j*vinc );
      new IPoint(pt).clr( i*uinc, j*vinc, 0);
    }
  }

}

The for loop and the way to use surf.pt( i*uinc, j*vinc ) in the code above are a basic way to extract points on the surface to create new geometries on the surface.

When you don't need the input surface anymore, you can delete it by del() method.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt = surf.pt( i*uinc, j*vinc );
      new IPoint(pt).clr( i*uinc, j*vinc, 0);
    }
  }
  surf.del();

}


     Grid Lines

Here is an example to create lines on a surface in u direction. Please note that the condition of the for loop of index number i uses i < unum not i <= unum.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      IVec pt2 = surf.pt((i+1)*uinc, j*vinc);
      new ICurve(pt1, pt2).clr(0);
    }
  }
  surf.del();
}

In the similar way, you can draw lines on a surface in v direction, by switching the logic of i and j.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i <= unum; i++){
    for(int j=0; j < vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      IVec pt2 = surf.pt(i*uinc, (j+1)*vinc);
      new ICurve(pt1, pt2).clr(1.0);
    }
  }
  surf.del();
}

To combine both, dealing with the ending number difference in u and v direction, you'd use if condition to skip the logic around the ending number.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      if(i < unum){
        IVec pt2u = surf.pt((i+1)*uinc, j*vinc);
        new ICurve(pt1, pt2u).clr(0);
      }
      if(j < vnum){
        IVec pt2v = surf.pt(i*uinc, (j+1)*vinc);
        new ICurve(pt1, pt2v).clr(1.0);
      }
    }
  }
  surf.del();
}

When you run the for loops with the counter i and j, the behavior of the internal parameter of u and v, calculated by the counter i, j and the interval uinc, vinc on the surface can be diagrammed like the below.

When the iteration of for loop is going through, depending on the state (depending on what number i and j are assigned), the location of the point specified the parameter is relatively changed.

To build geometry relative to the current state of i and j in the for loop, you specify a relative location using the counter i, j and the interval uinc and vinc.


     Diagonal Lines

When you draw diagonal line inside the for loop like above, you'd connect point at pt( i*uinc, j*vinc ) and another at pt( (i+1)*uinc, (j+1)*vinc ).

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j < vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      IVec pt2 = surf.pt((i+1)*uinc, (j+1)*vinc);
      new ICurve(pt1, pt2).clr(0,1.,1.);
    }
  }
  surf.del();
}

To flip the direction of diagonals, use pt( i*uinc, (j+1)*vinc ) and pt( (i+1)*uinc, j*vinc ).

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j < vnum; j++){
      IVec pt1 = surf.pt(i*uinc, (j+1)*vinc);
      IVec pt2 = surf.pt((i+1)*uinc, j*vinc);
      new ICurve(pt1, pt2).clr(0,0,1.);
    }
  }
  surf.del();
}

The below is an example to combine diagonal lines and orthogonal u lines and v lines.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      if(i < unum){
        IVec pt2u = surf.pt((i+1)*uinc, j*vinc);
        new ICurve(pt1, pt2u).clr(0);
      }
      if(j < vnum){
        IVec pt2v = surf.pt(i*uinc, (j+1)*vinc);
        new ICurve(pt1, pt2v).clr(1.0);
      }
      if(i < unum && j < vnum){
        IVec pt2uv = surf.pt((i+1)*uinc, (j+1)*vinc);
        new ICurve(pt1, pt2uv).clr(0,1.,1.);
      }
    }
  }
  surf.del();
}


     Diagrid Lines

Diagrid lines can be drawn using if condition of if( (i+j)%2 == 0 ) .

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j <= vnum; j++){
      if( (i+j)%2 == 0 ){
        IVec pt1 = surf.pt(i*uinc, j*vinc);
        if( j > 0){
          IVec pt2 = surf.pt((i+1)*uinc, (j-1)*vinc);
          new ICurve(pt1, pt2).clr(0);
        }
        if( j < vnum ){
          IVec pt3 = surf.pt((i+1)*uinc, (j+1)*vinc);
          new ICurve(pt1, pt3).clr(0,0,1.);
        }
      }
    }
  }
  surf.del();
}

The if condition of if( (i+j)%2 == 0 ) picks every other point in the diagonal checker pattern way as shown in the diagram below.

Then on each point, pt1 at i*uinc, j*vinc, pt2 at (i+1)*uinc, (j-1)*vinc and pt3 at (i+1)*uinc, (j+1)*vinc forms two lines in "<" shape.

When this "<" shape is repeated at each diagrid point, it forms diagrid lines.


If you use the if condition of if( (i+j)%2 == 1 ) , instead of if( (i+j)%2 == 0 ) , The corner condition of diagrid lines can be changed.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j <= vnum; j++){
      if( (i+j)%2 == 1 ){
        IVec pt1 = surf.pt(i*uinc, j*vinc);
        if( j > 0){
          IVec pt2 = surf.pt((i+1)*uinc, (j-1)*vinc);
          new ICurve(pt1, pt2).clr(0);
        }
        if( j < vnum ){
          IVec pt3 = surf.pt((i+1)*uinc, (j+1)*vinc);
          new ICurve(pt1, pt3).clr(0,0,1.);
        }
      }
    }
  }
  surf.del();
}


     Variable Diagrid Lines

If you change vnum and vinc inside the for loop in u direction with the counter i, you get variable diagrid like the below. Because you are accessing two different row of i and i+1 at the same time, you need to have vinc for the row of i and vinc2 for the row of i+1 separately.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 4;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    vnum++;
    vinc = 1.0/vnum;
    for(int j=0; j <= vnum; j++){
      double vinc2 = 1.0/(vnum+1);
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      IVec pt2 = surf.pt((i+1)*uinc, j*vinc2);
      IVec pt3 = surf.pt((i+1)*uinc, (j+1)*vinc2);
      new ICurve(pt1, pt2).clr(1.,0,0);
      new ICurve(pt1, pt3).clr(.5,0,1);
    }
  }
  surf.del();
}


     Hexagonal Grid Lines

By modifying the diagrid line algorithm, you can get hexagonal grid lines. The parameter r defines the angle of diagonal lines. If r = 0.0, it's same with diagrid, if 0 < r < 0.5, it's hexagonal, if r = 0.5, it's orthogonal, and if r > 0.5, it generates ribbon shape grid lines.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 20, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  double r = 0.3;
  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      if( (i+j)%2 == 0 ){
        IVec pt1 = surf.pt(i*uinc, (j-r)*vinc);
        IVec pt2 = surf.pt(i*uinc, (j+r)*vinc);
        new ICurve(pt1, pt2).clr(1.,0,1.);
        if( i < unum ){
          if( j > 0){
            IVec pt3 = surf.pt((i+1)*uinc, (j-1+r)*vinc);
            new ICurve(pt1, pt3).clr(0);
          }
          if( j < vnum ){
            IVec pt4 = surf.pt((i+1)*uinc, (j+1-r)*vinc);
            new ICurve(pt2, pt4).clr(0,0,1.);
          }
        }
      }
    }
  }
  surf.del();
}


     Hexagonal Grid Lines2

You can also create different type of hexagonal grid lines with two orthogonal lines and one diagonal line.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 12, vnum = 12;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      if( (i+j)%3 == 0 ){
        if( i < unum ){
          IVec pt2 = surf.pt((i+1)*uinc, j*vinc);
          new ICurve(pt1, pt2).clr(0); // orthogonal line
        }
        if( j < vnum ){
          IVec pt3 = surf.pt(i*uinc, (j+1)*vinc);
          new ICurve(pt1, pt3).clr(0.5); // orthogonal line
        }
      }
      if( (i+j)%3 == 1 ){
        if( i < unum && j < vnum ){
          IVec pt4 = surf.pt((i+1)*uinc, (j+1)*vinc);
          new ICurve(pt1, pt4).clr(1.,0,0); // diagonal line
        }
      }
    }
  }
  surf.del();
}


     Putting Cylinder around Line

You can create a cylinder around a line with ICylinder class by putting two end points and a radius. The code below is replaceing ICurve with ICylinder in the diagrid code.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 8, vnum = 8;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  for(int i=0; i < unum; i++){
    for(int j=0; j <= vnum; j++){
      if( (i+j)%2 == 0 ){
        IVec pt1 = surf.pt(i*uinc, j*vinc);
        if( j > 0){
          IVec pt2 = surf.pt((i+1)*uinc, (j-1)*vinc);
          new ICylinder(pt1, pt2, 0.5);
        }
        if( j < vnum ){
          IVec pt3 = surf.pt((i+1)*uinc, (j+1)*vinc);
          new ICylinder(pt1, pt3, 0.5);
        }
      }
    }
  }
  surf.del();
}


     Putting Fin Surface on Line

You can put fin surface along lines by creating rectangles with ISurface with offset points on the surface.

import processing.opengl.*;
import igeo.*;

size( 480, 360, IG.GL );

//IG.open("surface1.3dm");  //input geometry from 3dm file
IG.open("surface1.obj"); ///input geometry from OBJ file

ISurface[] surfs = IG.surfaces();

for( ISurface surf : surfs ){

  int unum = 12, vnum = 12;
  double uinc = 1.0/unum, vinc = 1.0/vnum;
  double depth = 3.0;

  for(int i=0; i <= unum; i++){
    for(int j=0; j <= vnum; j++){
      IVec pt1 = surf.pt(i*uinc, j*vinc);
      IVec pt1d = surf.pt(i*uinc, j*vinc, depth);
      if( (i+j)%3 == 0 ){
        if( i < unum ){
          IVec pt2 = surf.pt((i+1)*uinc, j*vinc);
          IVec pt2d = surf.pt((i+1)*uinc, j*vinc, depth);
          new ISurface(pt1, pt2, pt2d, pt1d).clr(0);
        }
        if( j < vnum ){
          IVec pt3 = surf.pt(i*uinc, (j+1)*vinc);
          IVec pt3d = surf.pt(i*uinc, (j+1)*vinc, depth);
          new ISurface(pt1, pt3, pt3d, pt1d).clr(0.5);
        }
      }
      if( (i+j)%3 == 1 ){
        if( i < unum && j < vnum ){
          IVec pt4 = surf.pt((i+1)*uinc, (j+1)*vinc);
          IVec pt4d = surf.pt((i+1)*uinc, (j+1)*vinc, depth);
          new ISurface(pt1, pt4, pt4d, pt1d).clr(1.,0,0);
        }
      }
    }
  }
  surf.del();
}


(back to the list of tutorials)

HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java / Python)
GALLERY
SOURCE CODE(GitHub)
ABOUT