Quarks Shape3d - BezTube Editor Generating Wrong Code

Hello,

I have been exploring the (excellent) Shapes3D library by Quark. I attempted to reply to a thread from a post on this same topic last year where this exact problem was discussed but keep getting kicked back to the forum intro page! So I’ll post this as a new question even though technically it is not.

Using Processing v3, I imported the Shapes3d lib and tried the Bezier Tube Editor, creating a test Bezier tube and the code the editor produced is incorrect (out of step with the current release v2.2?).

A year ago Quark said that v1.9.1 had been updated so that BezTubeRadius had been subsumed under TubeRadius (which I had to change below). But creating an instance of Bezier3D is also failing. I looked inside the package and saw the (new?) class name seems to be P_Bezier3D, which I changed and then got it working.

Here is the generated code:

import peasy.*;
import shapes3d.utils.*;
import shapes3d.animation.*;
import shapes3d.*;
import guicomponents.*;

private PeasyCam pcam;
private BezTube btube;

// The greater segs the smoother the curve
// slices must be >= 3 
int segs = 100, slices = 8;

void setup(){
  size(600,600,P3D);
  btube = makeBezTube(); 
  
 
  pcam = new PeasyCam(this, 200);
  pcam.setMinimumDistance(60);
  pcam.setMaximumDistance(600);
}

void draw(){
  background(215,255,175);
  lights();
 
  btube.draw();
}

public BezTube makeBezTube(){
  float[] prf = new float[] {
    16f, 16f, 16f, 16f, 16f, 16f, 16f, 16f, 
16f, 16f, 16f, 16f, 16f, 16f, 16f, 16f
  };
  
  PVector[] p = new PVector[] {
    new PVector(-57f, 61f, -35f), 
    new PVector(-58f, -35f, -160f), 
    new PVector(-7.6f, -117.6f, -54.3f), 
    new PVector(66f, -79f, 3f), 
    new PVector(86f, -21f, 58f), 
    new PVector(53f, 55f, 87f), 
    new PVector(-16.6f, 82f, 80f), 
    new PVector(-41.6f, 163f, 64f), 
    new PVector(-57f, 59f, -38f)
  };

 // These are wrong:
  //BezTubeRadius btr = new BezTubeRadius(prf);
 //BezTube bt = new BezTube(this, new Bezier3D(p, p.length), btr, segs, slices);

  // These replacements work:
   TubeRadius btr = new TubeRadius(prf);
   BezTube bt = new BezTube(this, new P_Bezier3D (p, p.length), btr, segs, slices);
   
   //bt.joinEnds = false; //how do I join the ends?

  bt.fill(color(32,32,200));
  bt.stroke(color(64,200,200));
  bt.strokeWeight(2.5f);
  bt.drawMode(Shape3D.SOLID | Shape3D.WIRE);

  bt.fill(color(150,255,255), BezTube.BOTH_CAP);
  bt.drawMode(Shape3D.SOLID, BezTube.BOTH_CAP);

  return bt;
}

This is a very cool editor and probably just needs to be updated.

By the way, I know this is a separate question, but how do you created a closed Bezier curve, as in joining the ends?

In the docs, I see something called “PathTube.joinEnds = false” but did not have any luck with it; How would the code above be adjusted to create a closed loop? It would be really nice to have that option added to the editor.

regards
Bill

1 Like

Can you share a link to what specific previous post that is?

Is this dev feedback for @quark, or did you also have a question?

Do you mean in Processing (as in use the CLOSE keyword in endShape(CLOSE)) or is this also a Shapes3D question? Yes, if possible, ask a separate question unless it is a follow-up related to the workings of a specific code example.

Hi Jeremy,

Here is the link to the original issue on a forum post from last year. It refers to a problem (which still exists) about Quark’s Shape3D library:

https://forum.processing.org/one/topic/shapes3d-new-version.html

My answers to your remaining questions are in context below.

Looks like your other responses got truncated by reply-by-mail …

Just so you know, that old post on forum one is from a closed forum (you can’t post there, only here) and is from 2010 – it says “last year” because the forum closed in 2011.

Ahh, good to know (wow it’s really old) -thanks

I see you have discovered a bug in the S3D4P_BezTubeEditor example that comes with the library. Yes the code copied to the clipboard is for Processing 2 and earlier versions of G4P and Shapes3D - oops sorry I missed that when I released V2.2 :blush:

It will be fixed for the next release but I have no idea when that will be. In the meantime here is how you can permanently fix the sketch yourself provided you have a simple text editor.

This assumes your sketch folder is called Processing

Step 1
Locate the text file bte_sketch_1.txt in the folder
../Processing/libraries/Shapes3D/examples/S3D4P_BexTubeEditor/data

Step 2
Open the file in your text editor, can use NotePad (Windows) or TextEdit (macOS) and make the following changes -
(1) Change line 7 from

import guicomponents.*;

to

import g4p_controls.*;

(2) Changes lines 43 & 44 from

  BezTubeRadius btr = new BezTubeRadius(prf);
  BezTube bt = new BezTube(this, new Bezier3D(p, p.length), btr, segs, slices);

to

  TubeRadius btr = new TubeRadius(prf);
  BezTube bt = new BezTube(this, new P_Bezier3D(p, p.length), btr, segs, slices);

Now save the file overwriting the old one.

When you next use this example the code copied to the clipboard will work with Processing 3, Shapes3D V2.2 and the latest version of G4P.

It is not possible to modify the sketch to create closed shapes because it uses the BezTube class which only supports open ended curves.

If I remember correctly both the BezTube class and this example sketch were in the original release of Shapes3D.

The PathTube class was added in later versions of Shapes3D and effectively replaces the BezTube class because it can create any user defined tube including those based on a 3D Bezier curve. The BezTube class was left in the library for older sketches that use it.

A PathTube shape can be either open or closed.

HTH

1 Like

Thanks for the changes and I will apply them to the template you mention.

I defaulted to using the Bezier class because there was that cool little visual editor for Beziers. But (unless I am missing something) it looks like there is no equivalent editor for the PathTube class? The PathTube examples show Lissajous patterns, but how do you go about creating an arbitrary PathTube from scratch?

I will create a simple example which I will post here in the next few days.

1 Like

Wonderful -thanks in advance :slight_smile:

OK sorry for the delay. The sketch code below will create this snake
snake1
You can find more information about the code in this document

/**
An example of using the PathTube class to create a coiled snake.
created by Peter Lager 2018
*/

import shapes3d.*;
import shapes3d.animation.*;
import shapes3d.utils.*;

PathTube snake;
float angle = 0.7;

void setup() {
  size(400, 400, P3D);
  I_PathGen tubePath = new SnakePath(2.75, 50, 150, 250);
  I_RadiusGen tubeRadius = new SnakeTubeRadius(0.5, 24, 44, 0.2, 0.96);
  snake = new PathTube(this, tubePath, tubeRadius, 300, 12, false);
  // Set attributes for body
  snake.fill(color(0, 160, 0));
  snake.stroke(color(100, 230, 100));
  snake.strokeWeight(0.6);
  snake.drawMode(S3D.SOLID | S3D.WIRE);
  // Set attributes for the mouth.
  snake.fill(color(200, 10, 0), S3D.S_CAP);
  snake.stroke(color(255, 255, 0), S3D.S_CAP);
  snake.strokeWeight(0.3, S3D.S_CAP);
  snake.drawMode(S3D.SOLID | S3D.WIRE, S3D.S_CAP);
}

void draw() {
  background(0, 0, 60);
  translate(width/2, height/2, -260);
  rotateX(angle);
  rotateY(1.29 * angle);
  rotateZ(0.759 * angle);
  snake.draw();
  angle += 0.01;
}

public class SnakePath implements I_PathGen {

  private float snakeAngle;
  private float lowR, rangeR;
  private float lowZ, rangeZ;

  public SnakePath(float numberTurns, float lowRadius, float highRadius, float pitch) {
    snakeAngle = numberTurns * PApplet.TWO_PI;
    lowR = lowRadius;
    rangeR = highRadius - lowRadius;
    rangeZ = numberTurns * pitch / 2;
    lowZ = - rangeZ / 2;
  }

  public float x(float t) {
    return (lowR + t * rangeR) * PApplet.sin(t * snakeAngle);
  }

  public float y(float t) {
    return (lowR + t * rangeR) * PApplet.cos(t * snakeAngle);
  }

  public float z(float t) {
    return lowZ + t * rangeZ;
  }
}

public class SnakeTubeRadius implements I_RadiusGen {

  private float tailTR, bodyTR, headTR;
  private float tTail, tHead;

  public SnakeTubeRadius(float tailTubeRadius, float bodyTubeRadius, float headTubeRadius, float tTailValue, float tHeadValue) {
    tailTR = tailTubeRadius;
    bodyTR = bodyTubeRadius;
    headTR = headTubeRadius;
    tTail = tTailValue;
    tHead = tHeadValue;
  }

  public float radius(float t) {
    float r = 0;
    if ( t < tTail) { // The radius for the tail section
      r = tailTR + (bodyTR - tailTR) * sin(t * 0.5 * PApplet.PI / tTail);
    } else if (t > tHead) { // The radius for the head section
      float dt = 1-t;
      r = bodyTR + (headTR - bodyTR) * sin(dt * PApplet.PI / (1 - tHead));
      r -= bodyTR * dt;
    } else { // the body between the tail and the head
      r = bodyTR;
    }
    return r;
  }

  public boolean hasConstantRadius() {
    return false;
  }

  public Object getController() {
    return null;
  }
}
2 Likes

Thanks for generously providing this elegant example and the included tutorial Mr Quark. :smile:

I am primarily interested in creating closed loop tube paths with ends that connect cleanly, so that objects can traverse the entire loop, repeating their journey around it. The Lissajous examples provide this closed loop path but are equation driven. My math skills are not such that I can take an imagined arbitrarily shaped spline and then use varieties of trig to create that loop from the ground up.

I don’t know what your current commitment is to the Shapes library in terms of time and resources, but Is it too much work for you to update the Bezier editor so that it works with the tubePath class instead of Bezier? Ideally, that update would include a radio button for creating constant radius tubes with a “join ends” option.Hey, there is no harm in asking :wink:

I got the idea for Shapes3D after answering a question on the forum about calculating the vertices for a spherical mesh. There have been 11 updates since then to add new shapes and to keep it compatible with Processing as it morphed from V1 to V3 the last one being in 2015.

I rarely use the library myself so this is the first time I have seriously looked at it for a long time. Trying to use the library has made me realise that the OO design and API is quirky and inconsistent and fixing these would give me the chance to add many more new features to make it more flexible in use. So to answer your question …

the answer is yes, it is too much trouble because the changes I envisage would make the multi-window style of editor redundant so I would be modify code that I would eventually trash.

I don’t know when I will get around updating Shapes3D because I have another idea for a library which could be used with Shapes3D or independently so would need to be created first.

Even if I could start on Shapes3D now, it would be several moths before it would be available.

I need to sit down with a stiff whiskey and think about it all :thinking:

1 Like

I was afraid of opening a can of annelids for you, but I had to ask. I at least hope that the whiskey was of adequate quality :wink:

Alright, so in the interim, how about a workaround something as follows:

I use the existing Bezier editor to draw my closed loop and generate something like this array, which I cut and paste, excerpting just the path portion, e.g.:

PVector[] p = new PVector[] {
    new PVector(-57f, 61f, -35f), 
    new PVector(-58f, -35f, -160f), 
    new PVector(-7.6f, -117.6f, -54.3f), 
    new PVector(66f, -79f, 3f), 
    new PVector(86f, -21f, 58f), 
    new PVector(53f, 55f, 87f), 
    new PVector(-16.6f, 82f, 80f), 
    new PVector(-41.6f, 163f, 64f), 
    new PVector(-57f, 61f, -35f)
  };

Can you show me a dead simple example of how I could then use that array with the tubePath class to implement I_PathGen? (Assume constant radius).

I see there is a joinEnds function. What is it for? Does this need to be set to “true” to make it a logically continuous loop?

-again, thanks

You cannot use an array of PVector with TubePath because it doesn’t meet the criteria for I_PathGen.
Have a look at the extrusion examples and see if you can work out what is happening.

Sorry but unfortunately I can do any more at the moment, very busy.

Not to worry, I understand.

I’ll poke around and figure something out.

-And I look forward to your upcoming new library. Keep up the excellent work :sunny: