【问题标题】:how do you draw a line in a pixel array你如何在像素数组中画一条线
【发布时间】:2021-01-05 14:17:11
【问题描述】:

我喜欢最大限度地控制屏幕,所以我必须控制每一个像素,这有利有弊。一个缺点是我真的没有任何内置函数的帮助。所以我不知道如何画一条线。 我试图制作一个函数来处理线条画,但我无法让它工作! 这是我用来画线的代码

  int startX;
  int startY;
  int deltaX = x1/x2;
  int deltaY = y1/y2;
  float deltaPixl = deltaX/deltaY;
  for(int i=0;i<deltaY;i=i+1){
    if(x1>x2){ startX = x2;}else{ startX=x1;}
    if(y1>y2){ startY = y2;}else{ startY=y1;}
    pixl(startX+i,round(startY+(deltaPixl*i)),0);
  }

它使用了一个名为 pixl 的函数,以便轻松地将像素绘制到像素数组中, 只是为了澄清为什么代码中有一个名为 pixl 的函数。

当我尝试使用此代码时,它不会崩溃,就像处理通常在出现错误时那样! 它只是不起作用,而是什么都不做!

在这个问题上我需要一些帮助。

【问题讨论】:

  • 我们真的需要看看你使用的是什么java包,以及你使用的最少代码。请edit您的问题添加此信息。
  • 请提供一个minimal reproducible example,我们可以自己运行。然后向我们展示您获得的结果,并说明您希望它做哪些不同的事情。

标签: java processing pixel line-drawing


【解决方案1】:

我有点晚了,但我在this website 上找到了一种非常简单的将线条绘制到像素阵列的方法。 这是我在 Monogame 中制作的一个简单实现(顺便说一句,抱歉它没有使用处理 - 我从未使用过它):

public void drawLine(int x1, int y1, int x2, int y2)
{
    //this will store the colour data of the canvas pixels
    Color[] canvasData = new Color[canvas.Width * canvas.Height];
    //store the pixel data of the canvas in canvasData
    canvas.GetData<Color>(canvasData);

    //drawing line starts here
    int dx = x2 - x1;
    int dy = y2 - y1;

    for (int x = x1; x < x2; x++)
    {
        int y = y1 + dy * (x - x1) / dx;
        //[y*canvas.Width+x] converts the 2d array index to a 1d array index
        canvasData[y * canvas.Width + x] = Color.Black;
    }
    //line drawing ended

    //setting the canvas' pixels to the modified pixels with the line
    canvas.SetData<Color>(canvasData);
}

【讨论】:

    【解决方案2】:

    您可以轻松使用PGraphics。 这个想法是,一旦你有了一个 PGraphics 实例,你就可以使用点符号来访问以前使用的绘图函数(只要它们在 .beginDraw().endDraw() 之间调用)。

    使用noSmooth() 你可以让它看起来像像素一样完美。

    这里有一个基本的草图来说明这个想法:

    // disable anti-aliasing
    noSmooth();
    // create a PGraphics layer
    PGraphics layer = createGraphics(25, 25);
    // render a line
    layer.beginDraw();
    layer.line(0, 24, 24, 0);
    layer.endDraw();
    // render the line at 100%
    image(layer, 0, 0);
    // render the line scaled up
    image(layer, 0, 0, width, height);
    

    这应该适用于大多数情况。 (只有very small values and transparency 更棘手的情况可能会让您头疼)

    如果由于某种原因您需要更多控制,您可以始终实现自己的光栅化方法。你可能开始的地方是Bresenham's line algorithm

    关于您的代码,有几处可能会出错:

    • float deltaPixl = deltaX/deltaY;:如果 deltaY 为零,您将遇到 exception
    • 您正在对 deltaXdeltaY 进行整数除法(可能导致其中任何一个值都为 0)
    • 您应该在 for 循环之前尝试带有开始/结束值的 println() 语句,以了解该循环是否会实际执行。此外,在for 循环中,您可以println(i) 来查看您是否获得了预期的值。

    总的来说,我建议检查Kevin Workman's How to Debug guide

    此外,您可以使用lerp() 来计算线的起点和终点之间的线性插值位置。传递每个坐标和一个标准化(介于 0.0 和 1.0 之间)值,其中 0.0 = 起点,1.0 = 终点,中间的任何值都在线上(例如,0.5 = 沿线的 50%)。

    这是一个基本的例子:

    void drawLinePoints(int x1, int y1, int x2, int y2, int numberOfPoints){
        // for each point  
        for(int i = 0; i < numberOfPoints; i++){
          // map the counter to a normalized (0.0 to 1.0) value for lerp
          // 0.0 = 0 % along the line, 0.5 = 50% along the line, 1.0 = 100% along the line
          float t = map(i, 0, numberOfPoints, 0.0, 1.0);
          // linearly interpolate between the start / end points (and snap to whole pixels (casting to integer type))
          int x = (int)lerp(x1, x2, t);
          int y = (int)lerp(y1, y2, t);
          // render the point
          point(x, y);
        }
      
    }
    
    void setup(){
      // render points are large squares
      strokeWeight(6);
      strokeCap(PROJECT);
    }
    
    void draw(){
      // clear frame
      background(255);
      // calculate distance
      float distance = dist(10, 10, mouseX, mouseY);
      // map distance the number of points to illustrate interpolation (more points = continuous line)
      int numPoints = (int)distance / 8;
      // render points along the line
      drawLinePoints(10, 10, mouseX, mouseY, numPoints);
    }
    

    为了完整起见,上面的 sn-p 使用 pixels[] 代替:

    void drawLinePoints(int x1, int y1, int x2, int y2, int numberOfPoints){
        // for each point  
        for(int i = 0; i < numberOfPoints; i++){
          // map the counter to a normalized (0.0 to 1.0) value for lerp
          // 0.0 = 0 % along the line, 0.5 = 50% along the line, 1.0 = 100% along the line
          float t = map(i, 0, numberOfPoints, 0.0, 1.0);
          // linearly interpolate between the start / end points (and snap to whole pixels (casting to integer type))
          int x = (int)lerp(x1, x2, t);
          int y = (int)lerp(y1, y2, t);
          // convert the x, y coordinate to pixels array index and render the point in black
          pixels[x + (y * width)] = color(0);
        }
      
    }
    
    void setup(){
      noSmooth();
    }
    
    void draw(){
      // clear frame
      loadPixels();
      java.util.Arrays.fill(pixels, color(255));
      // calculate distance
      float distance = dist(10, 10, mouseX, mouseY);
      // map distance the number of points to illustrate interpolation (more points = continuous line)
      int numPoints = (int)distance;
      // render points along the line
      drawLinePoints(10, 10, mouseX, mouseY, numPoints);
      // update pixels
      updatePixels();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 1970-01-01
      相关资源
      最近更新 更多