Problem with Bezier Curves when exporting SVG from illustrator,

hi all,

I came across this little problem: when exporting a bezier curve as svg from illustrator and then importing it to processing, the control points are considered as vertices, does anyone know how to access anchor points and control points separately? is there any trick to get a good export from illustrator or any way to clean the svg before using it in processing?
curve in illustrator:


result in processing:
jpg

PShape SVG1;


void setup() {
  smooth(8);
  size(400, 500);
  beginRecord(SVG, "export.svg");
}

void draw(){
 
 background(0);

impor();
save("jpg.jpg");
noLoop();
endRecord();
}

void impor(){
   SVG1=loadShape("Z1.svg");
  SVG1.disableStyle();

  int numChild=SVG1.getChildCount();
  println("num="+numChild);

  for (int i=0; i<numChild; i++) {
    PShape temp=SVG1.getChild(i);
    noFill();
    stroke(128);
    shape(temp);
    
      int vCount=temp.getVertexCount();
      for(int k=0;k<vCount;k++){
        PVector vert=temp.getVertex(k);
        noStroke();
        fill(255,0,0);
        ellipse(vert.x,vert.y,5,5);
        
      
      }

    }
  }

thanx

1 Like

If the Processing core can’t offer a solution, it might be worthwhile to check out the library Geomerative. Not sure it can fix your issue, but the description looks promising:

(…) This library exposes the shapes (such as vector drawings or typographies) in a more approchable way. Geomerative makes it easy to access the paths, the handles and the points, (…)

1 Like

Hi @jeykech,

tldr, I agree with @Tiemen, research a library with better curve / SVG support. Processing core’s SVG support, afaik, was never intended to be comprehensive. PShape is an interface which serves as a jack-of-all trades – it has to provide a common lexicon between 2D vector-based shapes and 3D meshes.

You may also wish to look around on Adobe Illustrator forums to see if, from the export side of the workflow, your question has already been asked and answered.

Searching for they keywords SVG ‘simplify’, ‘minify’ or ‘optimize’ should also give you a bunch of options. You’ll have to experiment, though, to see if they just condense code or actually attempt to remove extraneous data from an SVG path.

Next, I’m linking to your prior thread. I’m not sure from your description above if, after anchor points have been separated from control points, the control point data can then be discarded. Since your more complex patternwork looks to use straight lines, it may be helpful to specify. (EDIT: I’m going to assume for now that they can be.)

Suppose I have this SVG file, called “demo.svg”:

<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  viewBox="0 0 512 512">
<!-- <g
  transform="
    translate(256.0, 256.0)
    rotate(0.0) 
    scale(128.0, 128.0)">
<g 
  stroke-width="0.015" 
  stroke-opacity="1.00" 
  stroke="#202020" 
  fill-opacity="1.00" 
  fill="#9ad8e2"> -->
<path d="
  M -1.0000 0.0000 
  C -0.9166 0.0833,-0.8333 0.1666,-0.7500 0.2500 
  C -0.7500 0.4166,-0.7500 0.5833,-0.7500 0.7500 
  C -0.5833 0.7500,-0.4166 0.7500,-0.2500 0.7500 
  C -0.1666 0.8333,-0.0833 0.9166,0.0000 1.0000 
  C 0.0833 0.9166,0.1666 0.8333,0.2500 0.7500 
  C 0.4166 0.7500,0.5833 0.7500,0.7500 0.7500 
  C 0.7500 0.5833,0.7500 0.4166,0.7500 0.2500 
  C 0.8333 0.1666,0.9166 0.0833,1.0000 0.0000 
  C 0.9166 -0.0833,0.8333 -0.1666,0.7500 -0.2500 
  C 0.7500 -0.4166,0.7500 -0.5833,0.7500 -0.7500 
  C 0.5833 -0.7500,0.4166 -0.7500,0.2500 -0.7500 
  C 0.1666 -0.8333,0.0833 -0.9166,0.0000 -1.0000 
  C -0.0833 -0.9166,-0.1666 -0.8333,-0.2500 -0.7500 
  C -0.4166 -0.7500,-0.5833 -0.7500,-0.7500 -0.7500 
  C -0.7500 -0.5833,-0.7500 -0.4166,-0.7500 -0.2500 
  C -0.8333 -0.1666,-0.9166 -0.0833,-1.0000 0.0000
  Z"></path>
<!-- </g> -->
<!-- </g> -->
</svg>

I’ve formatted it to make it somewhat human-readable. Also, I’ve commented out the transformation and style groups to make it simpler to deal with in Processing. The M (move-to) command, followed by the C (cubic Bezier curve-to) command, and finally Z (close path) parallels Processing’s beginShape, vertex, bezierVertex and endShape.

If you number the vertices retrieved from the PShape once it’s been loaded into Processing,

PShape demo;
PVector[] vertices;

float scale = 256.0 * 0.95;
PVector trns = new PVector(256.0, 256.0);

void setup() {
  size(512, 512);
  demo = loadShape("demo.svg");
  demo = demo.getChild(0);
  
  // This is known to be a closed shape, so the last
  // vertex and the first vertex should be the same.
  int vertCount = demo.getVertexCount() - 1;
  vertices = new PVector[vertCount];
  for (int i = 0; i < vertCount; ++i) {
    vertices[i] = demo.getVertex(i);
    vertices[i].mult(scale);
    vertices[i].add(trns);
  }
  
  textSize(14);
  textAlign(CENTER, CENTER);
}

void draw() {
  background(#fff7d5);

  int len = vertices.length;
  for (int i = 0; i < len; ++i) {

    if (i % 3 == 0) {
      fill(#232323);
    } else {
      fill(#ff2828);
    }
    
    PVector v = vertices[i];
    text(i, v.x, v.y);
  }
}

the result looks like this:

For every anchor point, in black, there are two control points, in red. Between any two anchor points, say the segment between 6 and 9, the control points 7 and 8 lie on the line segment formed by 6 and 9. I’ll leave it to you to research how to test whether a point lies on a line segment. Keep in mind, this order only holds because I’ve used a simple SVG: with all C commands.

Now suppose I simplify the above SVG file even further:

<svg
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  viewBox="0 0 512 512">
<path d="
  M -1.0000 0.0000 
  L -0.7500 0.2500 
  L -0.7500 0.7500 
  L -0.2500 0.7500 
  L 0.0000 1.0000 
  L 0.2500 0.7500 
  L 0.7500 0.7500 
  L 0.7500 0.2500 
  L 1.0000 0.0000 
  L 0.7500 -0.2500 
  L 0.7500 -0.7500 
  L 0.2500 -0.7500 
  L 0.0000 -1.0000 
  L -0.2500 -0.7500 
  L -0.7500 -0.7500 
  L -0.7500 -0.2500 
  L -1.0000 0.0000
  Z"></path>
</svg>

I’ve replaced each C command with L (line-to) and discarded all but the last coordinate pair from the comma-separated list that followed C. If I update my Processing code in draw to draw the lines between the vertices

void draw() {
  background(#fff7d5);

  int len = vertices.length;
  PVector prev = vertices[0];
  PVector curr = vertices[1];
  fill(#202020);
  text(0, prev.x, prev.y);
  for (int i = 1; i < len; ++i) {
    curr = vertices[i];
    stroke(#ff2828);
    line(prev.x, prev.y, curr.x, curr.y);
    text(i, curr.x, curr.y);
    prev = curr;
  }
}

I get this

Depending on which commands an SVG path element’s d attribute contains, I suspect you’ll get a different count of vertices. A path with a variety of commands (for example, L, Q and C) would likely require more complex parsing, in which case I’d recommend moving away from PShape altogether. I’ll link to the source code if you wish to see how Processing parses an SVG path.

Hope that helps. Best,
Jeremy

4 Likes

@behreajj thank you for taking time to answer my question.
I am facing so many problems with the imports, I think the best way is to reconsider my workflow or find an other way to export only the necessary data from my vectors. doing it manually will take forever.!

hi again,
this is for future readers
this topic is also related to this other one topic1
well, after being lost in translation between illustrator and processing, I came to a solution that works fine form for the moment and I think could be developed.
for my exemple , let’s say I have a geometrical shape and I wanted to connect the middle points of the segments with lines. this is my workflow:

  1. draw vectors in illustrator, using all the features that illustrator has to offer.
  2. export as SVG
  3. import to processing using PShape or geomerative library
  4. do the stuff I want in processing.

this seems simple but for some reasons the export and import have many issues. I am not sure but for the moment I tend to believe that the tools used to draw in illustrator influence how the shape is exported. a simple pen drawing will have no problem but when using Pathfinder or compound shapes and then expanding them gives me problems.
so my solution is this :

after finishing the drawing in illustrator, run a script that copy the same path in a new layer using only the necessary information. this is done by:

  1. create a new layer illustrator
  2. selecting all the paths that you want to export
  3. expand them, ungroup them , release all masks ,…
  4. run this script ( copy it in any text editor and save it as filename.js, then go to File>scripts>other scripts and navigate to your file)
  5. delete the old layer
  6. save as .svg

(this is an illustrator script and not processing script !!!)
( and thanx to fabianmoronzirfas from stackoverflow )

var doc = app.activeDocument; // get the active doc
var artLayer = doc.layers[0];
mysel = app.activeDocument.selection;
main();
function main(){

    if(mysel == null) {
    // check if something is slected
    alert ("You need to sevlect a path");
    return;
    }
for(var kk=0;kk<mysel.length;kk++){
var coords = new Array(); // make a new array for the coords of the path
var directions = new Array();

var sel = mysel[kk];
    var points = sel.pathPoints;// isolate pathpoints
    // loop points
    for (var i = 0; i < points.length; i++) {
    // this could be done in one lines
    // just to see whats going on line like
//~      coords.push(new Array(points[i].anchor[0],points[i].anchor[1]));
    var p = points[i]; // the point
    var a = p.anchor; // his anchor
    var px = a[0];// x
    var py = a[1]; // y
    var ldir = p.leftDirection;
    var rdir = p.rightDirection;
    directions.push(new Array(ldir,rdir));
    coords.push(new Array(px,py));// push into new array of array   
  }
var new_path = artLayer.pathItems.add(); // add a new pathitem

new_path.setEntirePath(coords); // now build the path
    // check if path was closed
if(sel.closed){
    new_path.closed = true;
    new_path.fillColor = makeColor(0,0,255);// the color is to see difference
    // script could be modified to copy the color and stroke of each path
    new_path.filled = true;
    }

// set the left and right directions
for(var j = 0; j < new_path.pathPoints.length;j++){

    new_path.pathPoints[j].leftDirection = directions[j][0];
    new_path.pathPoints[j].rightDirection = directions[j][1];    
    }
}}

function makeColor(r,g,b){
    var c = new RGBColor();
    c.red   = r;
    c.green = g;
    c.blue  = b;
    return c;
}

in this Gif you can see the first frame is before running the script and the second is after running the script and exporting the svg again.

anim1
the same exemple with multiple shapes.

anim
I hope this could help!

6 Likes