在JS中绘制线条和圆圈并填充孔形状

时间:2017-04-10 11:55:34

标签: javascript arrays node.js algorithm dxf

我使用dxf解析器(https://github.com/bjnortier/dxf)读取NodeJS中dxf文件(仅2D)的内容,然后我得到一个包含以下输出的数组:

  • LINE:start.x,start.y,end.x,end.y
  • CIRCLE:x,y,radius
  • ARC:x,y,radius,startAngle,endAngle

我根据Bresenham算法编写了3个函数来设置数组中所需的像素,我想稍后用它来绘制画布。

输入参数是

  1. data:数组中的denorm dxf数据
  2. coordSystem:设置所需像素的数组
  3. module.exports: {
    
        processLINE: function(data, coordSystem) {
    
            var setPixel = function(x, y) {
                x = Math.ceil(x);
                y = Math.ceil(y);
    
                coordSystem[x][y] = 1;
            }
    
            var line = function(x0, y0, x1, y1) {
               var dx = Math.abs(x1-x0);
               var dy = Math.abs(y1-y0);
               var sx = (x0 < x1) ? 1 : -1;
               var sy = (y0 < y1) ? 1 : -1;
               var err = dx-dy;
               var e2;
    
               while(true) {
                 setPixel(x0,y0);
                 if ((x0===x1) && (y0===y1)) break;
                 e2 = 2*err;
                 if (e2 >-dy){ err -= dy; x0  += sx; }
                 if (e2 < dx){ err += dx; y0  += sy; }
               }
            }
    
            line(Math.ceil(data.start.x), Math.ceil(data.start.y), Math.ceil(data.end.x), Math.ceil(data.end.y))
    
            return coordSystem;
    
    
        },
    
        processCIRCLE: function(data, coordSystem) {
    
            var setPixel = function(x, y) {
    
                x = Math.ceil(x);
                y = Math.ceil(y);
    
                coordSystem[x][y] = 1;
            }
    
            var createCircle = function(x0, y0, radius)
            {
                var f = 1 - radius;
                var ddF_x = 0;
                var ddF_y = -2 * radius;
                var x = 0;
                var y = radius;
    
                setPixel(x0, y0 + radius);
                setPixel(x0, y0 - radius);
                setPixel(x0 + radius, y0);
                setPixel(x0 - radius, y0);
    
                while(x < y) 
                {
                  if(f >= 0) 
                  {
                    y--;
                    ddF_y += 2;
                    f += ddF_y;
                  }
                  x++;
                  ddF_x += 2;
                  f += ddF_x + 1;
    
                  setPixel(x0 + x, y0 + y);
                  setPixel(x0 - x, y0 + y);
                  setPixel(x0 + x, y0 - y);
                  setPixel(x0 - x, y0 - y);
                  setPixel(x0 + y, y0 + x);
                  setPixel(x0 - y, y0 + x);
                  setPixel(x0 + y, y0 - x);
                  setPixel(x0 - y, y0 - x);
                }
            }
    
            createCircle(data.x, data.y, data.r);
    
            return coordSystem;
    
        },
    
        processARC: function(data, coordSystem) {
    
            var setPixel = function(x, y, coordinates) {
    
                x = Math.ceil(x);
                y = Math.ceil(y);
    
                coordSystem[x][y] = 1;
            }
    
            var createPartialcircle = function()
            {
    
                startAngle = data.startAngle*180/Math.PI;
                endAngle = data.endAngle*180/Math.PI;
    
                if(startAngle>endAngle) {
                    for (var i=startAngle; i>endAngle; i--) {
                        var radians = i * Math.PI / 180;
                        var px = data.x - data.r * Math.cos(radians);
                        var py = data.y - data.r * Math.sin(radians);
                        setPixel(px, py, coordinates);
                    }
                } else {
                    for (var i=startAngle; i<endAngle; i++) {
                        var radians = i * Math.PI / 180;
                        var px = data.x + data.r * Math.cos(radians);
                        var py = data.y + data.r * Math.sin(radians);
                        setPixel(px, py, coordinates);
                    }
                }
            }
    
            createPartialcircle(data.x, data.y, data.r);
    
            return coordSystem;
        }
    }
    

    有了这个,我得到以下形状:  你可以看到它的工作原理,但是有一些“漏洞”,因此我的最后一个函数应该填充孔形状(扫描线算法),效果不好......

    shape

    以下是填充形状的方法 我从HERE获取了这段代码,并用JavaScript-Style编写了它。

    function scanLineFill(config, data, x, y, fillColor) {
    
                function getPixel(x,y) {
                    return data[x][y];
                }
    
                function setPixel(x,y) {
                    data[x][y] = fillColor;
                }
    
                // Config
                var nMinX = 0;
                var nMinY = 0;
                var nMaxX = config.maxValues.x;
                var nMaxY = config.maxValues.y;
                var seedColor = getPixel(x,y);
    
    
                function lineFill(x1, x2, y) {
    
                    var xL,xR;
                    if( y < nMinY || nMaxY < y || x1 < nMinX || nMaxX < x1 || x2 < nMinX || nMaxX < x2 )
                        return;
                    for( xL = x1; xL >= nMinX; --xL ) { // scan left
                        if( getPixel(xL,y) !== seedColor )
                            break;
                        setPixel(xL,y);
                    }
                    if( xL < x1 ) {
                        lineFill(xL, x1, y-1); // fill child
                        lineFill(xL, x1, y+1); // fill child
                        ++x1;
                    }
                    for( xR = x2;  xR <= nMaxX; ++xR ) { // scan right
                        console.log('FOR: xR --> ', xR)
                        if( getPixel(xR,y) !== seedColor )
                            break;
                        setPixel(xR,y);
                    }
                    if(  xR > x2 ) {
                        lineFill(x2, xR, y-1); // fill child
                        lineFill(x2, xR, y+1); // fill child
                        --x2;
                    }
                    for( xR = x1; xR <= x2 && xR <= nMaxX; ++xR ) {  // scan betweens
                        if( getPixel(xR,y) === seedColor )
                            setPixel(xR,y);
                        else {
                            if( x1 < xR ) {
                                // fill child
                                lineFill(x1, xR-1, y-1);
                                // fill child
                                lineFill(x1, xR-1, y+1);
                                x1 = xR;
                            }
                            // Note: This function still works if this step is removed.
                            for( ; xR <= x2 && xR <= nMaxX; ++xR) { // skip over border
                                if( getPixel(xR,y) === seedColor ) {
                                    x1 = xR--;
                                    break;
                                }
                            }
                        }
                    }
    
                }
    
    
                if( fillColor !== seedColor ) {
                    lineFill(x, x, y);
                }
    
                return data;
    
            }
    

    结果如下:

    shapeFilled

    我认为如果形状没有孔,填充功能会填充正确的形状。但是我怎么能实现这个目标呢?

0 个答案:

没有答案