画笔冲压算法/技术

发布于 2024-11-08 22:54:28 字数 299 浏览 0 评论 0原文

我正在玩弄一个小油漆应用。我想创建不同的画笔笔尖(不仅仅是简单的线条)。基本思想是沿着鼠标移动重复(冲压)画笔笔尖。因为鼠标移动不会为鼠标移动的每个像素调度所需的事件。 我当前的方法是使用 Bresenham 算法来获取我想要绘制的像素,然后将画笔笔尖印在每个像素上。然而,这不是很有效,因为画笔笔尖例如为 30x30 像素。我想以画笔宽度的 25% 进行印记,但我不知道如何以良好的方式完成此操作。我可以检测到距离,然后只进行踩踏,直到达到刷尖 25% 的距离。

还有其他想法如何实现考虑不规则鼠标事件并允许定义间距的冲压画笔算法吗?

感谢您的阅读!

I am toying around with a small paint application. I want to create different Brush tips (not only simple lines). The basic idea is to repeat (stamping) the brush tip along the mouse movements. Because the mouse movements don't dispatch the required event for every pixel the mouse moves.
My current approach is I use the Bresenham algorithm to geht the pixels were I want to paint and then stamp the brush tip over every pixel. This is however not very efficient, because the brush tip is for example 30x30 px. I want to stamp at 25% of the brush width but I don't know how this is done in a good way. I could detect the distance and only stamp until a distance of 25% brush tip is reaced.

Any other idea how to implement a stamping brush algorithm which considers irregular mouse events and allows the spacing to be defined?

Thanks for reading!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心在旅行 2024-11-15 22:54:28

回答有点晚了,但如果有人在这里搜索答案,我就是如何在 java 项目的代码中实现它的。

步长是画笔的百分比,因此如果它是 20x20 画笔,那么 25 步长就是 5 个像素,即空间。

然后,我根据鼠标的最后一个位置和当前位置创建一个标准化向量。

first(第一次点击)之后。
当距离大于空间时,将使用迭代器来处理所有距离,因为有时鼠标可以快速移动,因此存在多个 dib(或“邮票”,dibs 是该域中的术语)

iter=space- remn 用于将其与前一个 dib 对齐。

添加了 vector*iter 的前一个位置为我们提供了 dib 的位置。

当我们把它们都画出来之后,重要的部分就来了。

remn = dist-iter+space-remn; Remainder(remn) 是从前一个过程中收集的,添加到初始阶段的 dist(distance) 中。

为了理解数学,让我们举一个例子。

Brush = 30x30,step = 25%,remn=2.5,dist = 28.5(包括remn),space = 7.5(30*25/100)

下一个remn = 28.5(dist)-27.5(5初始+7.5*3次以来 )检查(<28.5-2.5)是在 iter 更新后完成的) +7.5(space)-2.5(previous remn) = 6 个像素

因此,由于已经移动了 6 个像素,因此鼠标必须为下一个 dib 移动 1.5 个像素。

在其他情况下,它就更简单了。

dist(已经添加了 remn)使 remn=dist 失败。

例如,如果距离上次有 2 个像素,我们将鼠标移动的距离加上 3 个像素,因此我们需要为下一个点移动额外的 2.5 个像素。

    int size =(Integer) tool.getAttribute("size");
        int step = (Integer) tool.getAttribute("step");
        double space = size*step/100.0f; //what is actualy need for the check algorithm for the step rate to work
        double dist = Point.distance(pZero.getX(),pZero.getY(),last.getX(),last.getY());
        int bleed = (int) (size/tilemap[0].getWidth()+size/tilemap[0].getHeight());
        Point2D.Double vec = new Point2D.Double(pZero.getX()-last.getX(),pZero.getY()-last.getY());
        vec.x /= dist;
        vec.y /= dist;
        dist+=remn;
        if(first){
            //System.out.println("First ");
            for(int y=0; y < tilesHigh; ++y) {
                for(int x=0; x < tilesWide; ++x) {

                    int pos = x+y*tilesWide;
                    // This should never exceed tilemap.length.
                    BufferedImage tile = tilemap[pos];
                    //tool.operate(tile.getGraphics(), new Point(pZero.x-x*tile.getWidth(), pZero.y-y*tile.getHeight()));
                    tool.operate(tile.getGraphics(), tilemapPointToTilePoint(pZero, pos));

                }
            }
            first = false;
        }else {
            if(dist>=space){//check to see if the mouse distance is enoght for a step(space)
                iter=space-remn;
                //test=0;
                //System.out.println("pZero="+pZero);
                while(iter<dist-remn){//fills the gap between with at the rate of step(space),if you move the mouse fast you use to get those
                    //do stuff
                    pZero.x =(int) Math.round(last.x + (vec.x*iter));
                    pZero.y =(int) Math.round(last.y + (vec.y*iter));
                    //int pos = xyToIndex(pZero.x, pZero.y);
                    //test++;
                    //System.out.println("iter = "+iter+" remn="+remn+" space="+space);
                    //System.out.println("pIter="+pZero);
                    //System.out.println("Second ");

                    for(int y=0; y < tilesHigh; ++y) {//bleed
                        for(int x=0; x < tilesWide; ++x) {
                            int pos = x+y*tilesWide;
                            // This should never exceed tilemap.length.
                            BufferedImage tile = tilemap[pos];
                            //tool.operate(tile.getGraphics(), new Point(pZero.x-x*tile.getWidth(), pZero.y-y*tile.getHeight()));
                            tool.operate(tile.getGraphics(), tilemapPointToTilePoint(pZero, pos));
                        }
                    }
                    iter += space;
                }
                //System.out.println("last = "+last);
                //System.out.println("test="+test);
                remn = dist-iter+space-remn;
            }else remn = dist;
        }

A bit late in answering but if someone searches for answers here is how I implement it in my code for a project in java.

The step is the percent of the brush so if it's 20x20 brush then 25 step is 5 pixels which is the space.

I then create a normalized vector from the the last and current position of the mouse.

After the first which is the first click.
When the dist is more then the space an iterator is made to process all the distance because sometimes the mouse can move fast so there is multiple dibs(or "stamps", dibs is the term in this domain)

iter=space-remn is for aligning it with the previous dib.

The previous position added with the vector*iter gets us the position for the dib.

After we draw them all comes the important bits.

remn = dist-iter+space-remn; Remainder(remn) is collected from a previous process added to the dist(distance) from the initial stage.

To understand the math lets show an example.

brush = 30x30, step = 25%, remn=2.5, dist = 28.5(including remn), space = 7.5(30*25/100)

The next remn = 28.5(dist)-27.5(5 initially+7.5*3 times since the check(<28.5-2.5) is done after iter is updated) +7.5(space)-2.5(previous remn) = 6 pixels

So the mouse has to travel 1.5pixels for the next dib since 6 pixles are already traveled.

In the else case its even more straightforward.

dist(which already has remn added) fails the remn=dist.

For example if we have 2 pixels from last time we add the distance traveled by the mouse say 3 pixels so we need to travel an additional 2.5 pixels for the next dib.

    int size =(Integer) tool.getAttribute("size");
        int step = (Integer) tool.getAttribute("step");
        double space = size*step/100.0f; //what is actualy need for the check algorithm for the step rate to work
        double dist = Point.distance(pZero.getX(),pZero.getY(),last.getX(),last.getY());
        int bleed = (int) (size/tilemap[0].getWidth()+size/tilemap[0].getHeight());
        Point2D.Double vec = new Point2D.Double(pZero.getX()-last.getX(),pZero.getY()-last.getY());
        vec.x /= dist;
        vec.y /= dist;
        dist+=remn;
        if(first){
            //System.out.println("First ");
            for(int y=0; y < tilesHigh; ++y) {
                for(int x=0; x < tilesWide; ++x) {

                    int pos = x+y*tilesWide;
                    // This should never exceed tilemap.length.
                    BufferedImage tile = tilemap[pos];
                    //tool.operate(tile.getGraphics(), new Point(pZero.x-x*tile.getWidth(), pZero.y-y*tile.getHeight()));
                    tool.operate(tile.getGraphics(), tilemapPointToTilePoint(pZero, pos));

                }
            }
            first = false;
        }else {
            if(dist>=space){//check to see if the mouse distance is enoght for a step(space)
                iter=space-remn;
                //test=0;
                //System.out.println("pZero="+pZero);
                while(iter<dist-remn){//fills the gap between with at the rate of step(space),if you move the mouse fast you use to get those
                    //do stuff
                    pZero.x =(int) Math.round(last.x + (vec.x*iter));
                    pZero.y =(int) Math.round(last.y + (vec.y*iter));
                    //int pos = xyToIndex(pZero.x, pZero.y);
                    //test++;
                    //System.out.println("iter = "+iter+" remn="+remn+" space="+space);
                    //System.out.println("pIter="+pZero);
                    //System.out.println("Second ");

                    for(int y=0; y < tilesHigh; ++y) {//bleed
                        for(int x=0; x < tilesWide; ++x) {
                            int pos = x+y*tilesWide;
                            // This should never exceed tilemap.length.
                            BufferedImage tile = tilemap[pos];
                            //tool.operate(tile.getGraphics(), new Point(pZero.x-x*tile.getWidth(), pZero.y-y*tile.getHeight()));
                            tool.operate(tile.getGraphics(), tilemapPointToTilePoint(pZero, pos));
                        }
                    }
                    iter += space;
                }
                //System.out.println("last = "+last);
                //System.out.println("test="+test);
                remn = dist-iter+space-remn;
            }else remn = dist;
        }
橙幽之幻 2024-11-15 22:54:28

Brasenham 是一种近似算法,因为您已经在近似而不是混叠,所以您可以更进一步...

通过对算法进行轻微修改,您可以将画笔宽度作为参数(或者更好的是打印距离) :

  • 阈值是打印距离 * 矢量方向乘数(45,135,225,315 度 = sqrt(2)),
  • 而不是在 X,Y 处绘制像素 -> 计数像素
  • 当 PixelCount >= 位置 X、Y 处的阈值打印画笔时

并重置 PixelCount使用浮点数作为计数器,如果像素不是方形,则为您逐步执行的每个 deltaY 或 deltaX 添加不同的量,并考虑从 x1,y1 到 x2,y2 的向量方向以获得每个像素要添加的实际距离。

相当简单的修改...

The Brasenham is an approximation algorithm, since you are already approximating instead of aliasing, you could go that way further...

With a slight modification of the algorithm where you get the brush width as a parameter (or better yet, the print distance):

  • threshold is the print distance * vector orientation multiplier (45,135,225,315 degrees = sqrt(2))
  • instead of drawing Pixels at X,Y -> count pixels
  • when pixelCount >= threshold print brush at location X,Y and reset pixelCount

Use a float for the counter, and if pixels are not square then add a different amount for each deltaY or deltaX you step through, and take into account the vector orientation from x1,y1 to x2,y2 to get the real distance to add for each pixel.

Pretty simple modification...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文