Pro Question: get ALL in-between points from beginShape curveVertex() endShape

Hello all!

as we all know, we can use
beginShape curveVertex() endShape to make long complex curves.

See Reference / Processing.org

But it’s pretty much a black box.

How can I receive ALL points that are shown by curveVertex?

Apparently similar to curvePoint (with t / amt) but alas not quite

For a mcve see Easing equations with 'Influence' and 'In-/Outgoing Velocity' like in Adobe After Effects - #2 by Chrisir

Thank you all!

Chrisir

Hi @Chrisir,

Not that easy as each implementation JAVA2D, P2D,etc handles it different. There is a native catmul-rom implementation in PGraphics which would store the vertices as float array, but it doesn’t seems to be used at all…
for OpenGL related (P2D/P3D) ones there is an internal class InGeometry used to store the vertices which are not accessable and for JAVA2D it uses the awt.geom stuff.
Here is a quick and evil hack for the latter… :slight_smile:

Cheers
— mnse

import java.lang.reflect.*;
import java.awt.geom.*;

ArrayList<PVector> points = null;

void setup() {
  size(300, 300);
}

void draw() {
  background(0);
  stroke(255);
  noFill();
  beginShape();
  for (int x = 0; x < width; x+=width/8) {
    curveVertex(x, x%2==0 ? height*0.25:height*0.75);
  }
  endShape();

  if (points == null)
    points = getVertices();

  PVector current = points.get(int(millis()/100) % points.size());
  noStroke();
  fill(255, 0, 0);  
  ellipse(current.x, current.y, 8, 8);
}

Class findClass(Class c, String search) {
  if (c.getName().endsWith(search))
    return c;
  else if (c.getSuperclass() != null)
    return findClass(c.getSuperclass(), search);
  return null;
}

ArrayList<PVector> getVertices() {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  try {
    GeneralPath gpath = null;
    Class pgclass = findClass(g.getClass(), "PGraphicsJava2D");
    if (pgclass == null) {
      throw new Exception("PGraphicsJava2D class not found");
    }
    Field[] fields = pgclass.getDeclaredFields();
    for (Field f : fields) {
      if ("gpath".equals(f.getName())) {      
        f.setAccessible(true);
        gpath = (GeneralPath) f.get(g);
      }
    }

    if (gpath == null) {
      throw new Exception("class member gpath not found");
    }

    PathIterator i = gpath.getPathIterator(null, 1);
    while (!i.isDone()) {
      double[] coords = new double[6];
      int segType = i.currentSegment(coords);
      if (segType != PathIterator.SEG_CLOSE) {
        list.add(new PVector((float)coords[0], (float)coords[1]));
      }
      i.next();
    }
  } 
  catch(Exception e) {
    println("Error: " + e);
  }
  return list;
}

video

1 Like

Hello @mnse,

Please provide some context to above with links to the source in GitHub.

I took a quick look already but you have done the groundwork and others would benefit from that journey.

:)

1 Like

Hi,

Git-References:

Additional info:

Cheers
— mnse

2 Likes

Hi,

Just to add a way for P2D mode …

Cheers
— mnse

PS: For demonstration purposes only … so still quick hack without following good coding conventions. :slight_smile:

import java.lang.reflect.*;
import java.awt.geom.*;

ArrayList<PVector> points = null;

void setup() {
  size(300, 300, P2D);
}

void draw() {
  background(0);
  stroke(255);
  noFill();
  beginShape();
  for (int x = 0; x < width; x+=width/8) {
    curveVertex(x, x%2==0 ? height*0.25:height*0.75);
  }
  endShape();

  if (points == null) {
    try {
      points = getPoints();
      if (points.isEmpty())
        throw new Exception("no data found !?");
    } 
    catch(Exception e) {
      println("Error: " + e);
      exit();
      return;
    }
  }

  PVector current = points.get(int(frameCount/5.) % points.size());
  noStroke();
  fill(255, 0, 0);  
  ellipse(current.x, current.y, 8, 8);
}

Class findClass(Class c, String search) {
  if (c.getName().endsWith(search))
    return c;
  else if (c.getSuperclass() != null)
    return findClass(c.getSuperclass(), search);
  return null;
}

ArrayList<PVector> getPoints() throws Exception {
  if (sketchRenderer().endsWith("PGraphics2D")) {
    return getVerticesP2D();
  } else if (sketchRenderer().endsWith("PGraphicsJava2D")) {
    return getVerticesJAVA2D();
  } else {
    throw new Exception("unsupported renderer " + sketchRenderer() + "  !?");
  }
}

// JAVA2D Mode
ArrayList<PVector> getVerticesJAVA2D() throws Exception {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  GeneralPath gpath = null;
  Class pgclass = findClass(g.getClass(), "PGraphicsJava2D");
  if (pgclass == null) {
    throw new Exception("PGraphicsJava2D class not found");
  }
  Field[] fields = pgclass.getDeclaredFields();
  for (Field f : fields) {
    if ("gpath".equals(f.getName())) {      
      f.setAccessible(true);
      gpath = (GeneralPath) f.get(g);
      break;
    }
  }

  if (gpath == null) {
    throw new Exception("class member gpath not found");
  }

  PathIterator i = gpath.getPathIterator(null, 1);
  while (!i.isDone()) {
    double[] coords = new double[6];
    int segType = i.currentSegment(coords);
    if (segType != PathIterator.SEG_CLOSE) {
      list.add(new PVector((float)coords[0], (float)coords[1]));
    }
    i.next();
  }
  return list;
}

// P2D Mode
ArrayList<PVector> getVerticesP2D() throws Exception {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  float[] vertices = {};
  int vertexCount  = 0;
  Class pgclass = findClass(g.getClass(), "PGraphicsOpenGL");
  if (pgclass == null) {
    throw new Exception("PGraphicsOpenGL class not found");
  }
  for (Field pgField : pgclass.getDeclaredFields()) {
    if ("tessellator".equals(pgField.getName())) {      
      pgField.setAccessible(true);        
      Object tessellatorObj = pgField.get(g);               
      for (Field tessellatorField : tessellatorObj.getClass().getDeclaredFields()) {
        if ("pathVertexCount".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertexCount = (int) tessellatorField.get(tessellatorObj);
        }          
        else if ("pathVertices".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertices = (float[]) tessellatorField.get(tessellatorObj);
        }
      }
    }
  }
  if (vertexCount == 0) {
    throw new Exception("no Vertices found");
  }    
  for (int i = 0; i < vertexCount*3; i+=3) {
    list.add(new PVector(vertices[i], vertices[i+1]));
  }
  return list;
}

video2

Github refs:

1 Like

Hi,

finally, to be somehow complete, add version for P3D. Nearly the same as P2D just convert the 2D to 3D coords.

Cheers
— mnse

import java.lang.reflect.*;
import java.awt.geom.*;

ArrayList<PVector> points = null;

void setup() {
  size(300, 300, P3D);
}

void draw() {  
  background(0);
  stroke(255);
  noFill();
  beginShape();
  for (int x = 0; x < width; x+=width/8) {
    if (g.is3D())
      curveVertex(x, x%2==0 ? height*0.25:height*0.75,x*-3.);
    else
      curveVertex(x, x%2==0 ? height*0.25:height*0.75);
  }
  endShape();

  if (points == null) {
    try {
      points = getPoints();
      if (points.isEmpty())
        throw new Exception("no data found !?");
    } 
    catch(Exception e) {
      println("Error: " + e);
      exit();
      return;
    }
  }

  PVector current = points.get(int(frameCount/5.) % points.size());
  noStroke();
  fill(255, 0, 0);
  if (g.is3D())
    translate(current.x,current.y,current.z);
  else
    translate(current.x,current.y);

  ellipse(0,0,5,5);    
}

Class findClass(Class c, String search) {
  if (c.getName().endsWith(search))
    return c;
  else if (c.getSuperclass() != null)
    return findClass(c.getSuperclass(), search);
  return null;
}

ArrayList<PVector> getPoints() throws Exception {
  if (sketchRenderer().equals(P2D)) {
    return getVerticesP2D();
  } else if (sketchRenderer().equals(P3D)) {
    return getVerticesP3D();
  } else if (sketchRenderer().equals(JAVA2D)) {
    return getVerticesJAVA2D();
  } else {
    throw new Exception("unsupported renderer " + sketchRenderer() + "  !?");
  }
}

// JAVA2D Mode
ArrayList<PVector> getVerticesJAVA2D() throws Exception {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  GeneralPath gpath = null;
  Class pgclass = findClass(g.getClass(), "PGraphicsJava2D");
  if (pgclass == null) {
    throw new Exception("PGraphicsJava2D class not found");
  }
  Field[] fields = pgclass.getDeclaredFields();
  for (Field f : fields) {
    if ("gpath".equals(f.getName())) {      
      f.setAccessible(true);
      gpath = (GeneralPath) f.get(g);
      break;
    }
  }

  if (gpath == null) {
    throw new Exception("class member gpath not found");
  }

  PathIterator i = gpath.getPathIterator(null, 1);
  while (!i.isDone()) {
    double[] coords = new double[6];
    int segType = i.currentSegment(coords);
    if (segType != PathIterator.SEG_CLOSE) {
      list.add(new PVector((float)coords[0], (float)coords[1], 0));
    }
    i.next();
  }
  return list;
}

// P2D Mode
ArrayList<PVector> getVerticesP2D() throws Exception {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  float[] vertices = {};
  int vertexCount  = 0;
  Class pgclass = findClass(g.getClass(), "PGraphicsOpenGL");
  if (pgclass == null) {
    throw new Exception("PGraphicsOpenGL class not found");
  }
  for (Field pgField : pgclass.getDeclaredFields()) {
    if ("tessellator".equals(pgField.getName())) {      
      pgField.setAccessible(true);        
      Object tessellatorObj = pgField.get(g);               
      for (Field tessellatorField : tessellatorObj.getClass().getDeclaredFields()) {
        if ("pathVertexCount".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertexCount = (int) tessellatorField.get(tessellatorObj);
        }          
        if ("pathVertices".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertices = (float[]) tessellatorField.get(tessellatorObj);
        }
      }
    }
  }
  if (vertexCount == 0) {
    throw new Exception("no Vertices found");
  }    
  for (int i = 0; i < vertexCount*3; i+=3) {
    list.add(new PVector(vertices[i], vertices[i+1],0));
  }
  return list;
}

// P3D Mode
ArrayList<PVector> getVerticesP3D() throws Exception {
  ArrayList<PVector> list = new ArrayList<PVector>(); 
  float[] vertices = {};
  int vertexCount  = 0;
  Class pgclass = findClass(g.getClass(), "PGraphicsOpenGL");
  if (pgclass == null) {
    throw new Exception("PGraphicsOpenGL class not found");
  }
  for (Field pgField : pgclass.getDeclaredFields()) {
    if ("tessellator".equals(pgField.getName())) {      
      pgField.setAccessible(true);        
      Object tessellatorObj = pgField.get(g);               
      for (Field tessellatorField : tessellatorObj.getClass().getDeclaredFields()) {
        if ("pathVertexCount".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertexCount = (int) tessellatorField.get(tessellatorObj);
        }          
        if ("pathVertices".equals(tessellatorField.getName())) {      
          tessellatorField.setAccessible(true);        
          vertices = (float[]) tessellatorField.get(tessellatorObj);
        }
      }
    }
  }
  if (vertexCount == 0) {
    throw new Exception("no Vertices found");
  }    
  for (int i = 0; i < vertexCount*3; i+=3) {
    PVector m = new PVector(modelX(vertices[i],vertices[i+1],vertices[i+2])
                           ,modelY(vertices[i],vertices[i+1],vertices[i+2])
                           ,modelZ(vertices[i],vertices[i+1],vertices[i+2]));   
    list.add(new PVector(screenX(m.x,m.y,m.z)
                        ,screenY(m.x,m.y,m.z)
                        ,screenZ(m.x,m.y,m.z)));
  }
  return list;
}

video3

3 Likes