我有一个简单的处理草图,绘制一条直线为20px的连续椭圆线。有没有办法修改草图,以便绘制矢量形状而不是像素?
void setup() {
size(900, 900);
background(110, 255, 94);
}
void draw() {
ellipse(mouseX, mouseY, 20, 20);
fill(255);
}
感谢所有能提供一些有用建议的人。
答案 0 :(得分:4)
扩展我的评论,有几件事需要解决:
绘制一条直线为20px的连续椭圆线
绘制矢量形状
目前,您正在根据鼠标移动绘制省略号。 副作用是,如果你足够快地移动鼠标,则椭圆之间会有间隙。
要填补空白,您可以计算出每两个椭圆之间的距离。 如果距离大于这两个椭圆的大小,则可以在两者之间绘制一些。
PVector类提供了lerp()函数,允许您在两点之间轻松插值。 您可以阅读更多相关内容并运行一些示例here
使用这两个点之间的距离与椭圆尺寸之间所需的点数。 以下是在拖动鼠标时将鼠标位置存储到PVectors列表的示例:
//create an array list to store points to draw
ArrayList<PVector> path = new ArrayList<PVector>();
//size of each ellipse
float size = 20;
//how tight will the extra ellipses be drawn together
float tightness = 1.25;
void setup() {
size(900, 900);
}
void draw() {
background(110, 255, 94);
fill(255);
//for each point in the path, starting at 1 (not 0)
for(int i = 1; i < path.size(); i++){
//get a reference to the current and previous point
PVector current = path.get(i);
PVector previous = path.get(i-1);
//calculate the distance between them
float distance = previous.dist(current);
//work out how many points will need to be added in between the current and previous points to keep the path continuous (taking the ellipse size into account)
int extraPoints = (int)(round(distance/size * tightness));
//draw the previous point
ellipse(previous.x,previous.y,size,size);
//if there are any exta points to be added, compute and draw them:
for(int j = 0; j < extraPoints; j++){
//work out a normalized (between 0.0 and 1.0) value of where each extra point should be
//think of this as a percentage along a line: 0.0 = start of line, 0.5 = 50% along the line, 1.0 = end of the line
float interpolation = map(j,0,extraPoints,0.0,1.0);
//compute the point in between using PVector's linear interpolation (lerp()) functionality
PVector inbetween = PVector.lerp(previous,current,interpolation);
//draw the point in between
ellipse(inbetween.x,inbetween.y,size,size);
}
}
//draw instructions
fill(0);
text("SPACE = clear\nLEFT = decrease tightness\nRIGHT = increase tightness\ntightness:"+tightness,10,15);
}
void mouseDragged(){
path.add(new PVector(mouseX,mouseY));
}
void keyPressed(){
if(keyCode == LEFT) tightness = constrain(tightness-0.1,0.0,3.0);
if(keyCode == RIGHT) tightness = constrain(tightness+0.1,0.0,3.0);
if(key == ' ') path.clear();
}
请注意,点之间的插值是线性。 它是最简单的,但正如其名称所暗示的那样,它都是关于线条的: 它总是以直线连接两个点,而不是曲线。
我添加了一个选项来控制插入椭圆的紧密程度。以下是一些具有不同紧密程度的屏幕截图。你会注意到随着紧度的增加,线条会变得更明显:
您运行以下代码:
//create an array list to store points to draw
var path = [];
//size of each ellipse
var ellipseSize = 20;
//how tight will the extra ellipses be drawn together
var tightness = 1.25;
function setup() {
createCanvas(900, 900);
}
function draw() {
background(110, 255, 94);
fill(255);
//for each point in the path, starting at 1 (not 0)
for(var i = 1; i < path.length; i++){
//get a reference to the current and previous point
var current = path[i];
var previous = path[i-1];
//calculate the distance between them
var distance = previous.dist(current);
//work out how many points will need to be added in between the current and previous points to keep the path continuous (taking the ellipse size into account)
var extraPoints = round(distance/ellipseSize * tightness);
//draw the previous point
ellipse(previous.x,previous.y,ellipseSize,ellipseSize);
//if there are any exta points to be added, compute and draw them:
for(var j = 0; j < extraPoints; j++){
//work out a normalized (between 0.0 and 1.0) value of where each extra point should be
//think of this as a percentage along a line: 0.0 = start of line, 0.5 = 50% along the line, 1.0 = end of the line
var interpolation = map(j,0,extraPoints,0.0,1.0);
//compute the point in between using PVector's linear interpolation (lerp()) functionality
var inbetween = p5.Vector.lerp(previous,current,interpolation);
//draw the point in between
ellipse(inbetween.x,inbetween.y,ellipseSize,ellipseSize);
}
}
//draw instructions
fill(0);
text("BACKSPACE = clear\n- = decrease tightness\n+ = increase tightness\ntightness:"+tightness,10,15);
}
function mouseDragged(){
path.push(createVector(mouseX,mouseY));
}
function keyPressed(){
if(keyCode == 189) tightness = constrain(tightness-0.1,0.0,3.0);
if(keyCode == 187) tightness = constrain(tightness+0.1,0.0,3.0);
if(keyCode == BACKSPACE) path = [];
}
//https://stackoverflow.com/questions/40673192/processing-draw-vector-instead-of-pixels
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.4/p5.min.js"></script>
如果想要更平滑的线条,则需要使用不同的插值,例如二次插值或三次插值。您可以从现有的处理函数开始绘制曲线,例如curve()或bezier(),您会发现一些与处理here,here和{{3无关的有用资源}}
关于矢量形状
您没有直接使用here,而是在绘制形状。 使用pixels[]可以轻松地将这些形状保存为PDF 查看动画中的单帧(带屏幕显示)示例。
以下是按's'键时保存为PDF的版本:
import processing.pdf.*;
//create an array list to store points to draw
ArrayList<PVector> path = new ArrayList<PVector>();
//size of each ellipse
float size = 20;
//how tight will the extra ellipses be drawn together
float tightness = 1.25;
//PDF saving
boolean record;
void setup() {
size(900, 900);
}
void draw() {
background(110, 255, 94);
fill(255);
//if we need to save the current frame to pdf, begin recording drawing instructions
if (record) {
// Note that #### will be replaced with the frame number. Fancy!
beginRecord(PDF, "frame-####.pdf");
}
//for each point in the path, starting at 1 (not 0)
for(int i = 1; i < path.size(); i++){
//get a reference to the current and previous point
PVector current = path.get(i);
PVector previous = path.get(i-1);
//calculate the distance between them
float distance = previous.dist(current);
//work out how many points will need to be added in between the current and previous points to keep the path continuous (taking the ellipse size into account)
int extraPoints = (int)(round(distance/size * tightness));
//draw the previous point
ellipse(previous.x,previous.y,size,size);
//if there are any exta points to be added, compute and draw them:
for(int j = 0; j < extraPoints; j++){
//work out a normalized (between 0.0 and 1.0) value of where each extra point should be
//think of this as a percentage along a line: 0.0 = start of line, 0.5 = 50% along the line, 1.0 = end of the line
float interpolation = map(j,0,extraPoints,0.0,1.0);
//compute the point in between using PVector's linear interpolation (lerp()) functionality
PVector inbetween = PVector.lerp(previous,current,interpolation);
//draw the point in between
ellipse(inbetween.x,inbetween.y,size,size);
}
}
//once what we want to save has been recorded to PDF, stop recording (this will skip saving the instructions text);
if (record) {
endRecord();
record = false;
println("pdf saved");
}
//draw instructions
fill(0);
text("SPACE = clear\nLEFT = decrease tightness\nRIGHT = increase tightness\ntightness:"+tightness+"\n's' = save PDF",10,15);
}
void mouseDragged(){
path.add(new PVector(mouseX,mouseY));
}
void keyPressed(){
if(keyCode == LEFT) tightness = constrain(tightness-0.1,0.0,3.0);
if(keyCode == RIGHT) tightness = constrain(tightness+0.1,0.0,3.0);
if(key == ' ') path.clear();
if(key == 's') record = true;
}
答案 1 :(得分:2)
除了乔治的好答案(我已经+1),我想提供一个更基本的选择:
问题,就像乔治所说的那样,当你移动鼠标时,实际上你会跳过一堆像素。因此,如果您只在mouseX, mouseY
处绘制省略号或点数,那么您最终会得到间隙。
愚蠢的修复: pmouseX
和pmouseY
变量保存光标的上一个位置。
这可能听起来不太有用,但它们可以帮助您解决问题。不是在当前鼠标位置绘制椭圆或点,而是从前一个位置到当前位置绘制线。这样可以消除线条中的任何空白。
void draw(){
line(pmouseX, pmouseY, mouseX, mouseY);
}
无耻的自我推销:我已经编写了一个关于在处理可用here中获取用户输入的教程。
注意:这种愚蠢的解决方案只有在不每帧重绘背景时才有效。如果你需要重新绘制每一帧的所有内容,那么乔治的答案是可行的方法。