CSG (Constructive Solid Geometry)

I made it work easily by downloading the zip.

for 3D physics-engine-library see also : 3D physics engine library

More advanced example with a single marble track :

  • and below full Marble Track
//https://stackoverflow.com/questions/56999816/is-it-possible-to-use-jcsg-library-with-processing
//https://discourse.processing.org/t/csg-constructive-solid-geometry/12693


// the PShape reference which will contain the converted 
PShape csgResult, // red marble track 
  csgResult2;// green marble

void setup() {
  // 
  size(900, 900, P3D);
  noStroke();

  // JCSG sample code:

  // green marble
  CSG sphere = new Sphere(.60).toCSG();
  // red marble track 
  CSG cubeMinusSphere = defineRedCSG(); 

  // make to PShape 
  csgResult = CSGToPShape(cubeMinusSphere, 45, color(255, 0, 0)); // red marble track 
  csgResult2 = CSGToPShape(sphere, 45, color(0, 255, 0)); // green marble
}

void draw() {
  //
  background(0);
  lights();

  translate(width * 0.5, height * 0.5, 253);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateX(map(mouseY, 0, height, PI, -PI));

  shape(csgResult); // red marble track 
  shape(csgResult2);// green marble
}

//-----------------------------------------------------------------------------

CSG defineRedCSG() {
  // define the red marble track "cubeMinusSphere"

  // we use cube as base geometries (long thin cube for the track)
  CSG cubeMain = new Cube(12, 2, 2).toCSG();

  // this we cut out later 
  CSG cube2 = new Cube(12, 2, 2).toCSG();
  cube2 = translateXYZ(cube2, -2.1, 0, 1.14); 

  // this we cut out later 
  // cyl1 == vertical right
  float cylRadius=.65;
  CSG cyl1 = new Cylinder( cylRadius, cylRadius, 12, 43).toCSG();
  cyl1 = translateXYZ(cyl1, 5, 0, 0); 

  // this we cut out later 
  // cyl2 == horizontal, long    
  CSG cyl2 = new Cylinder( cylRadius, cylRadius, 12, 43).toCSG();
  cyl2 = cyl2.transformed(Transform.unity().rot(0, 90, 0));  // rotate in degrees
  cyl2 = translateXYZ(cyl2, cylRadius+1.2+2.1+1.2+.5, 0, 0); 

  // this we cut out later 
  // cyl3 == vertical left 
  CSG cyl3 = new Cylinder( cylRadius, cylRadius, 22, 43).toCSG();
  cyl3 = translateXYZ(cyl3, -5, 0, -4);

  // perform difference (cut out)
  CSG cubeMinusSphere = cubeMain.difference(cyl1);
  cubeMinusSphere = cubeMinusSphere.difference(cyl2);
  cubeMinusSphere = cubeMinusSphere.difference(cube2);
  cubeMinusSphere = cubeMinusSphere.difference(cyl3);

  return cubeMinusSphere;
}

CSG translateXYZ ( CSG csgItem, 
  float x, float y, float z ) {
  // tool for translate
  CSG csgItemNew = csgItem.transformed(Transform.unity().translateX(x));
  csgItemNew = csgItemNew.transformed(Transform.unity().translateY(y));
  csgItemNew = csgItemNew.transformed(Transform.unity().translateZ(z));

  return csgItemNew;
}

PShape CSGToPShape(CSG mesh, float scale, color colPShape) {
  // re-usable function to convert a CSG mesh to a Processing PShape

  // allocate a PShape group
  PShape csgResult = createShape(GROUP);

  // for each CSG polygon (Note: these can have 3,4 or more vertices)
  for (Polygon p : mesh.getPolygons()) {
    // make a child PShape
    PShape polyShape = createShape();
    // begin setting vertices to it
    polyShape.beginShape();
    fill(colPShape);

    // for each vertex in the polygon
    for (Vertex v : p.vertices) {
      // add each (scaled) polygon vertex
      polyShape.vertex((float)v.pos.getX() * scale, (float)v.pos.getY() * scale, (float)v.pos.getZ() * scale);
    }//for
    // finish this polygon

    polyShape.endShape();
    //append the child PShape to the parent
    csgResult.addChild(polyShape);
  }//for

  return csgResult;
}
//

  • and below full Marble Track

//https://stackoverflow.com/questions/56999816/is-it-possible-to-use-jcsg-library-with-processing
//https://discourse.processing.org/t/csg-constructive-solid-geometry/12693

import peasy.*;

PeasyCam cam;

// the PShape ArrayList which will contain the converted PShapes 
ArrayList<PShape> list = new ArrayList(); // red marble track and green marble

void setup() {
  // 
  size(2000, 1100, P3D);
  noStroke();
  cam=new PeasyCam(this, 2100); 

  makeSphere();
  makeMarbleTrack();
} // func 

void draw() {
  //
  background(0);
  lights();

  translate(width * 0.5, height * 0.5, 0); //  or use translate(width * 0.5, height * 0.5, 253);  OR  translate(width * 0.5, height * 0.5, 0); 
  //rotateY(map(mouseX, 0, width, -PI, PI));
  //rotateX(map(mouseY, 0, height, PI, -PI));

  for ( PShape ps : list ) {
    shape(ps); // red marble track and green marble
  }//for
  //
}//func 

//-----------------------------------------------------------------------------

void makeSphere() {

  // JCSG sample code:

  // green marble
  CSG sphere = new Sphere(.60).toCSG();

  // make sphere to PShape and add to list 
  PShape csgResult = CSGToPShape(sphere, 45, color(0, 255, 0)); // green marble
  list.add(csgResult);
}

void makeMarbleTrack() {

  // JCSG sample code:

  PShape csgResult;

  // red marble track 
  CSG cubeMinusSphere = defineRedCSG(); 

  // staple red
  csgResult = CSGToPShape(cubeMinusSphere, 45, color(255, 0, 0)); // red marble track
  list.add(csgResult); 

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, -91); 
  csgResult.rotateZ(PI); 
  list.add(csgResult);

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, 2*-91); 
  // csgResult.rotateZ(PI); 
  list.add(csgResult);

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, 3*-91); 
  csgResult.rotateZ(PI); 
  list.add(csgResult);

  // ------------------------
  // 1st to the right 
  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(-500+55, 0, 4*-91); 
  csgResult.rotateZ(PI); 
  list.add(csgResult);

  // ------------------------
  // 2nd to the right 
  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  //  csgResult.rotateZ(PI);
  csgResult.translate(2*(-500+55), 0, 5*-91);
  csgResult.rotateZ(PI+.4); 
  csgResult.translate(62, -259, 0);
  list.add(csgResult);

  // ------------------------
  // staple red II 
  float xTranslate=1315;
  float yTranslate=175;
  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, 6*-91); 
  csgResult.rotateZ(PI); 
  csgResult.translate(xTranslate, yTranslate, 0); 
  list.add(csgResult);

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(xTranslate, yTranslate, 7*-91); 
  list.add(csgResult);

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, 8*-91); 
  csgResult.rotateZ(PI);
  csgResult.translate(xTranslate, yTranslate, 0); 
  list.add(csgResult);

  // ------------------------
  // next right 

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 0, 0)); // red marble track
  csgResult.translate(0, 0, 9*-91); 
  csgResult.rotateZ(PI);
  csgResult.translate(xTranslate+447, yTranslate, 0); 
  list.add(csgResult);

  // ------------------------
  // 2 final ones going back   

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 222, 0)); // red marble track
  csgResult.translate(0, 0, 10*-91); 
  csgResult.rotateZ(PI/2-.2);
  csgResult.translate(xTranslate+447+40+136, yTranslate-131-60-33, 0); 
  list.add(csgResult);

  csgResult = CSGToPShape(cubeMinusSphere.clone(), 45, color(255, 2, 222)); // red marble track
  csgResult.translate(0, 0, 11*-91); 
  csgResult.rotateZ(PI/2-.2-.22);
  csgResult.translate(xTranslate+447-340-3+17-77+111+111+222, yTranslate+131-222-222-66-199-77, 0); 
  list.add(csgResult);
  //----
}

CSG defineRedCSG() {
  // define the red marble track "cubeMinusSphere"

  // we use cube as base geometries (long thin cube for the track)
  CSG cubeMain = new Cube(12, 2, 2).toCSG();

  // this we cut out later 
  CSG cube2 = new Cube(12, 2, 2).toCSG();
  cube2 = translateXYZ(cube2, -2.1, 0, 1.14); 

  // this we cut out later 
  // cyl1 == vertical right
  float cylRadius=.65;
  CSG cyl1 = new Cylinder( cylRadius, cylRadius, 12, 43).toCSG();
  cyl1 = translateXYZ(cyl1, 5, 0, 0); 

  // this we cut out later 
  // cyl2 == horizontal, long    
  CSG cyl2 = new Cylinder( cylRadius, cylRadius, 12, 43).toCSG();
  cyl2 = cyl2.transformed(Transform.unity().rot(0, 90, 0));  // rotate in degrees
  cyl2 = translateXYZ(cyl2, cylRadius+1.2+2.1+1.2+.5, 0, 0); 

  // this we cut out later 
  // cyl3 == vertical left 
  CSG cyl3 = new Cylinder( cylRadius, cylRadius, 22, 43).toCSG();
  cyl3 = translateXYZ(cyl3, -5, 0, -4);

  // perform difference (cut out)
  CSG cubeMinusSphere = cubeMain.difference(cyl1);
  cubeMinusSphere = cubeMinusSphere.difference(cyl2);
  cubeMinusSphere = cubeMinusSphere.difference(cube2);
  cubeMinusSphere = cubeMinusSphere.difference(cyl3);

  return cubeMinusSphere;
}

CSG translateXYZ ( CSG csgItem, 
  float x, float y, float z ) {
  // tool for translate
  CSG csgItemNew = csgItem.transformed(Transform.unity().translateX(x));
  csgItemNew = csgItemNew.transformed(Transform.unity().translateY(y));
  csgItemNew = csgItemNew.transformed(Transform.unity().translateZ(z));

  return csgItemNew;
}

PShape CSGToPShape(CSG mesh, float scale, color colPShape) {
  // re-usable function to convert a CSG mesh to a Processing PShape

  // allocate a PShape group
  PShape csgResult = createShape(GROUP);

  // for each CSG polygon (Note: these can have 3,4 or more vertices)
  for (Polygon p : mesh.getPolygons()) {
    // make a child PShape
    PShape polyShape = createShape();
    // begin setting vertices to it
    polyShape.beginShape();
    fill(colPShape);

    // for each vertex in the polygon
    for (Vertex v : p.vertices) {
      // add each (scaled) polygon vertex
      polyShape.vertex(
        (float)v.pos.getX() * scale, 
        (float)v.pos.getY() * scale, 
        (float)v.pos.getZ() * scale);
    }//for
    // finish this polygon

    polyShape.endShape();
    //append the child PShape to the parent
    csgResult.addChild(polyShape);
  }//for

  return csgResult;
}
//
3 Likes