矢量路径混合JavaScript或处理

时间:2011-08-22 22:30:59

标签: javascript jquery svg processing vector-graphics

我正在尝试编写一些类似于Adobe Illustrator混合工具的软件。目标是使用存储的路径作为不同权重的基础成分(即30%path1 70%path2)创建新路径。对于那些不熟悉的人,Adobe Illustrator示例如下所示:3 steps between two vector paths

问题是,我真的不知道从哪里开始。理想情况下,这将能够在浏览器中运行,所以我希望在JavaScript中执行此操作。我已经研究过在html5画布中使用带有Raphael.js和标准向量的SVG,但重要的是能够以某种方式从Illustrator导入矢量艺术(手动解析SVG文件没有问题,因为它只是xml)。 / p>

但是,我也考虑过在Processing中执行它,因为它的矢量支持非常突出,geomerative库看起来非常强大。

我只需要指向正确的方向,这样我就可以开始了,非常感谢!

1 个答案:

答案 0 :(得分:7)

你提到过SVG / JS / Raphael.js和几何学。 据我所知,你对插值位感兴趣,而不是向量加载/处理位(这将取决于你将使用JS / Java的版本)。

只要您想要混合的形状的顶点和要混合的形状的顶点(两个顶点集的顶点数相同),您只需要do是插值。 这将是:(1-t)*start+t*end;,其中t是混合量,0(开始形状)和1(结束形状)之间的值。

这是一个插入两组点(存储为PVector实例)的函数:

void interpolateVerts(float t,ArrayList<PVector> start,ArrayList<PVector> end,ArrayList<PVector> current){
  int numVerts = start.size();
  while(numVerts-- > 0) current.get(numVerts).set(PVector.add(PVector.mult(start.get(numVerts),(1-t)),PVector.mult(end.get(numVerts),t)));
}

预计t(混合量),开始和结束位置加上一个向量来存储当前的混合位置。

你可以看到快速而肮脏的演示here(注意停止图标混合周围的形状)。

实现此目的的另一种方法是使用lerp()函数,该函数用于在两个值之间进行插值。您将插入形状的每个坐标,PShapes'getVertex()方法将x y坐标返回到float []。我假设通过单个阵列循环,并且'lerp'-ing比使用PVector更简单,更便携:

void lerpArray(float t,float[] start,float[] end, float[] current){
  int i = start.length;
  while(i-- > 0) current[i] = lerp(start[i],end[i],t);
}

这是一个快速草图测试草图来说明这个想法(mouseX =混合量):

float[] start,end,current;
int len = 8;
void setup(){
  size(200,200);
  smooth();
  start = new float[len];
  end = new float[len];
  current = new float[len];
  setSquare(start,50,50,100,100);
  setSquare(current,50,50,100,100);
  setSquare(end,25,20,150,50);
}
void draw(){
  background(0);
  lerpArray((float)mouseX/width,start,end,current);
  beginShape();
  for(int i = 0 ; i < len; i+=2) vertex(current[i],current[i+1]);
  endShape();
}
void lerpArray(float t,float[] start,float[] end, float[] current){
  int i = start.length;
  while(i-- > 0) current[i] = lerp(start[i],end[i],t);
}
void setSquare(float[] verts,float x,float y,float width,float height){
  verts[0] = x+width;
  verts[1] = y;
  verts[2] = x+width;
  verts[3] = y+height;
  verts[4] = x;
  verts[5] = y+height;
  verts[6] = x;
  verts[7] = y;
}

<强>更新

嗯......事实证明它有点复杂。 获取顶点不是问题。重绘形状是一个。 PShape顶点具有'类型'(VERTEX,BEZIER_VERTEX等),因此在插值后,顶点将需要重绘。我试过扩展PShape和PShapeSVG,但很快遇到问题(因为PShape的树状结构)。由于Processing是开源的,出于好奇,我通过为顶点位置添加setter和为填充颜色添加getter / setter来调整PShape类,然后重新编译库(core.jar)

BlendShape1 BlendShape2 BlendShape3

您可以下载eclipse项目here,其中包含用户文件夹中重新编译的core.jar文件。请注意,这不是解决问题的推荐方法。 这里的前提是代码:

package svgblend;

import processing.core.PApplet;
import processing.core.PShape;

public class SVGBlend extends PApplet {
    PShape start,end,current;

    public void setup(){
      size(200,200);
      smooth();
      start   = loadShape("start.svg").getChild("start");
      end     = loadShape("end.svg").getChild("end");
      current = loadShape("start.svg").getChild("start");
      println(current.getFamily());
    }
    public void draw(){
      background(255);
      blendShape(start,end,current,(float)mouseX/width);
      shape(current,0,0);
    }
    void blendShape(PShape start,PShape end, PShape current,float amt){
        int i = start.getVertexCount();
        //verts
        while(i-- > 0) {
          float[] s = start.getVertex(i);
          float[] e = end.getVertex(i);
          current.setVertexX(i, lerp(s[0],e[0],amt));
          current.setVertexY(i, lerp(s[1],e[1],amt));
        }
        //colour
        int sFill = start.getFillColor();
        int eFill = end.getFillColor();
        current.setFillColor((int)lerpColor(sFill,eFill,amt));
    }
}

除了hacky PShape方法之外,这个工作/看起来还不错,因为开始形状中的顶点数量与结束形状中的顶点数量相同,并且位置不会以令人难以置信的数量变化。总而言之,这是一个肮脏和不灵活的看法。

使用另一个像Geomerative这样的库或者实现一种更简洁的方法来修改/更新通过解析SVG生成的形状更好,但解决了一半的问题。 另一半是正确混合。例如,在Illustrator中,您可以从两个任意形状混合(两个形状中顶点的数量不同)。 在插值之前,当形状具有不同数量的顶点并正确放置时,需要生成额外的顶点。有一些papers在讨论形状混合。我希望这些信息能为您提供所需的方向。

古德勒克!