处理:绘制矢量而不是像素

时间:2016-11-18 09:14:33

标签: vector processing pixel

我有一个简单的处理草图,绘制一条直线为20px的连续椭圆线。有没有办法修改草图,以便绘制矢量形状而不是像素?

  void setup() {
  size(900, 900); 
  background(110, 255, 94);  

} 

void draw() {
  ellipse(mouseX, mouseY, 20, 20);
 fill(255);
}

感谢所有能提供一些有用建议的人。

2 个答案:

答案 0 :(得分:4)

扩展我的评论,有几件事需要解决:

  1.   

    绘制一条直线为20px的连续椭圆线

  2.   

    绘制矢量形状

  3. 目前,您正在根据鼠标移动绘制省略号。 副作用是,如果你足够快地移动鼠标,则椭圆之间会有间隙。

    要填补空白,您可以计算出每两个椭圆之间的距离。 如果距离大于这两个椭圆的大小,则可以在两者之间绘制一些。

    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();
    }
    

    请注意,点之间的插值是线性。 它是最简单的,但正如其名称所暗示的那样,它都是关于线条的: 它总是以直线连接两个点,而不是曲线。

    我添加了一个选项来控制插入椭圆的紧密程度。以下是一些具有不同紧密程度的屏幕截图。你会注意到随着紧度的增加,线条会变得更明显:

    tightness 0

    tightness 1.5

    tightness 3.0

    您运行以下代码:

    //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(),您会发现一些与处理herehere和{{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处绘制省略号或点数,那么您最终会得到间隙。

愚蠢的修复: pmouseXpmouseY变量保存光标的上一个位置。

这可能听起来不太有用,但它们可以帮助您解决问题。不是在当前鼠标位置绘制椭圆或点,而是从前一个位置到当前位置绘制线。这样可以消除线条中的任何空白。

void draw(){
 line(pmouseX, pmouseY, mouseX, mouseY); 
}

无耻的自我推销:我已经编写了一个关于在处理可用here中获取用户输入的教程。

注意:这种愚蠢的解决方案只有在每帧重绘背景时才有效。如果你需要重新绘制每一帧的所有内容,那么乔治的答案是可行的方法。