矢量路径混合JavaScript或处理

Sai*_*ato 1 javascript processing jquery svg vector-graphics

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

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

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

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

Geo*_*nza 7

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

只要您想要混合的形状的顶点和要混合的形状的顶点(两个顶点集的顶点数相同),您需要做的就是插值价值.这将是这样的:(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)));
}
Run Code Online (Sandbox Code Playgroud)

它期望t(混合量),开始和结束位置加上一个向量来存储当前的混合位置.

你可以在这里看到一个快速而肮脏的演示(注意停止图标混合周围的形状).

实现此目的的另一种方法是使用lerp()函数,该函数用于在两个值之间进行插值.您将插入形状的每个坐标,PShapes的getVertex()方法将xy坐标返回到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);
}
Run Code Online (Sandbox Code Playgroud)

这里有一个快速草图测试草图来说明这个想法(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;
}
Run Code Online (Sandbox Code Playgroud)

更新

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

BlendShape1BlendShape2BlendShape3

您可以在此处下载eclipse项目,其中包括用户文件夹中重新编译的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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

祝好运!