我正在尝试编写一些类似于Adobe Illustrator混合工具的软件。目标是使用存储的路径作为不同权重的基础成分(即30%path1 70%path2)创建新路径。对于那些不熟悉的人,Adobe Illustrator示例如下所示:
问题是,我真的不知道从哪里开始。理想情况下,这将能够在浏览器中运行,所以我希望在JavaScript中执行此操作。我已经研究过在html5画布中使用带有Raphael.js和标准向量的SVG,但重要的是能够以某种方式从Illustrator导入矢量艺术(手动解析SVG文件没有问题,因为它只是xml)。 / p>
但是,我也考虑过在Processing中执行它,因为它的矢量支持非常突出,geomerative库看起来非常强大。
我只需要指向正确的方向,这样我就可以开始了,非常感谢!
答案 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)
您可以下载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在讨论形状混合。我希望这些信息能为您提供所需的方向。
古德勒克!