如何将运动剪辑到边界框?

时间:2019-09-02 20:14:13

标签: javascript algorithm authentication input hex

我正在努力寻找根据某种输入格式输出一系列笔位置的逻辑。

应该转换笔的位置数据,使其保持“下笔”和“上笔”状态(我正在工作),并且将超出矩形区域的笔移动剪切为输入(x = -8192,y = -8192)..(8191,8191)。我无法进行剪辑。

有关应如何进行裁剪的信息,请参见以下说明:

说明 enter image description here

enter image description here

预期输出示例
inputData: F0A0417F40004000417FC067086708804001C0670840004000187818784000804000

enter image description here

inputData: F0A0417F41004000417FC067086708804001C067082C3C18782C3C804000

enter image description here


//For decode inputData//
let commands =[] , command , allPos = "", lastPos;

function proDecode(hex) {
    for (let i = 0, len; i < hex.length; i+=len) {

        // Opcodes take 1 byte (i.e. 2 hex characters), and 
        // numbers take 2 bytes (4 characters)
        len = hex[i] >= '8' ? 2:4;
        let num = hex.slice(i,i+len)
        if (len === 2) { // opcode
         command = []
         commands.push(command)
        }
        else{
           num = penDecode(num);
           console.log(num);

        }
        command.push(num)
    }
    console.log(commands);

    return commands;
}



//for outPut//
unction proOutput(commands){
    let isPenDown = false;
    let x = 0, y = 0;
    let output = "";
    let color = ""
    for (let [opcode, ...args] of commands) {        
        if (opcode === 'F0') {            
            x = y = 0;
            isPenDown = false;
            color = "CO" + 0 + 0 + 0 + 255 + ";\n";
            output += "CLR;\n";
        } else if (opcode === '80') {
            isPenDown = args[0] > 0;
            output += "PEN " + (isPenDown ? "DOWN" : "UP") + ";\n";
        } else if (opcode === 'A0') {
            color = "CO " + args.join(" ") + ";\n";
            output += color
        } else if (opcode === 'C0') {
            let allPos = "", lastPos;
            for (let i = 0; i < args.length; i+=2) {
                x += args[i];
                y += args[i+1];
                if(x <-8192){
                    x= -8192          
                } else if (x>8191){
                    x= 8191
                    lastPos = ` (${x}, ${y})`;              
                }else if (y<-8192){
                    y= -8192          
                }else if (y>8191){
                    y= 8191
                    output += "y PEN UP" + ";\n";
                } else{
                }
                lastPos = ` (${x}, ${y})`;
                if (isPenDown) allPos += lastPos;  
            }
            output += "MV" + (allPos || lastPos) + ";\n";
        } // else: ignore unknown commands
    }

预期结果 创建与上面示例相同的输出。

1 个答案:

答案 0 :(得分:0)

每当坐标移出边界(或在边界内返回)时,都需要找到与边界框的交点。在某些情况下,线段甚至可以进入和退出框,从而产生两个相交。

计算线段(从 x 1 ,y 1 x 2 < / sub>,y 2 )和一条位于 y 的水平线,则可以将此公式用于 x 坐标:

x = x 1 +(y-y 1 )*(x 2 -x 1 )/(y 2 -y 1

显然,交点的 y 坐标已经由 y 给出。

满足以下条件之一时将不存在交集:

  • y 1 2
  • y 1 > y和y 2 > y
  • y 1 = y 2

因此,要确定线段是否与边界框(-8192,-8192)到(8191、8191)的四个边之一交叉,则需要检查4个交点。然后,您可以找到0、1或2个此类交点。

这是代码,我从我对上一个问题的回答中得到了改编(十六进制编码):

function intersectionWithAxis(x1, y1, x2, y2, y) {
    if (y1 < y && y2 < y || y1 > y && y2 > y || y1 === y2) return []; // No intersection
    return [Math.round(x1 + (y - y1) * (x2 - x1) / (y2 - y1)), y];
}

function decode(hex) {
    let commands = [];
    for (let i = 0, len, command; i < hex.length; i += len) {
        // Opcodes take 1 byte (i.e. 2 hex characters), and 
        // numbers take 2 bytes (4 characters)
        len = hex[i] >= "8" ? 2 : 4;
        let num = parseInt(hex.slice(i, i+len), 16);
        if (len === 2) { // Opcode
            command = []; // start a new command
            commands.push(command);
        } else { // Number. Encoded in offset-binary, using 2 x 7 bits 
            num = ((num & 0x7F00) >> 1) + (num & 0x7F) - 0x2000; 
        }
        command.push(num); // Push opcode or argument in current command
    }
    return commands;
}

function disassemble(hex) {
    let isPenDown = false;
    let isPenInBox = true;
    let x = 0, y = 0;
    let output = "";
    let commands = decode(hex);
    for (let [opcode, ...args] of commands) {
        if (opcode === 0xF0) {
            x = y = 0;
            isPenDown = false;
            isPenInBox = true;
            output += "CLR;\n";
        } else if (opcode === 0x80) {
            isPenDown = args[0] > 0;
            if (isPenInBox) output += "PEN " + (isPenDown ? "DOWN" : "UP") + ";\n";
        } else if (opcode === 0xA0) {
            output += "CO " + args.join(" ") + ";\n";
        } else if (opcode === 0xC0) {
            if (!isPenDown) {
                for (let i = 0; i < args.length; i += 2) {
                    let [dx, dy] = args.slice(i, i + 2);
                    x += dx;
                    y += dy;
                }
                output += `MV (${x}, ${y});\n`;
            } else {
                let buffer = "";
                for (let i = 0; i < args.length; i += 2) {
                    let [dx, dy] = args.slice(i, i + 2);
                    let toX = x + dx;
                    let toY = y + dy;
                    // Get intersections with top, bottom, left and right side of box:
                    let intersections = [
                        intersectionWithAxis(x, y, toX, toY, -8192),
                        intersectionWithAxis(x, y, toX, toY, 8191),
                        intersectionWithAxis(y, x, toY, toX, -8192).reverse(),
                        intersectionWithAxis(y, x, toY, toX, 8191).reverse()
                    ].filter(p => 
                        // Only keep the intersection points
                        p.length && p.every(x => x >= -8192 && x <= 8191)
                    );
                    if (intersections.length === 0) { // Position remains at same side of the box (inside or outside)
                        if (isPenInBox) buffer += ` (${x}, ${y})`;
                    } else if (intersections.length === 1) { // Moving from outside to inside of box, or vice versa
                        // Flush previous positions to output, move to the intersection point, and toggle the pen
                        output += `MV${buffer} (${intersections[0].join(", ")});\nPEN ${(isPenInBox ? "UP" : "DOWN")};\n`
                        isPenInBox = !isPenInBox;
                        // Start new series with positions
                        buffer = isPenInBox ? ` (${toX}, ${toY})` : "";
                    } else { // Moving from outside the box, through the box, and outside again
                        output += `MV (${intersections[0].join(", ")});\nPEN DOWN;\nMV (${intersections[1].join(", ")});\nPEN UP;\n`;
                    }
                    x = toX;
                    y = toY;
                }
                // Flush previous positions to output
                if (buffer) output += `MV${buffer};\n`;
            }
        } // else: ignore unknown commands
    }
    return output;
}

// Two samples as in question:
console.log(disassemble("F0A0417F40004000417FC067086708804001C0670840004000187818784000804000"));
console.log("---");
console.log(disassemble("F0A0417F41004000417FC067086708804001C067082C3C18782C3C804000"));

您在问题中发布的代码存在一些问题(这就是为什么我使用原始代码而不进行任何更改的原因):

  • 使用commandscommandallPoslastPos之类的全局变量是一种不好的做法:您可以在函数中更改它们的值,从而得到函数side effects;

  • 在以下语句中设置了color变量,但从未使用过该值:

    color = "CO" + 0 + 0 + 0 + 255 + ";\n";
    

    此外,该值未遵循所需的语法(RGB值之间缺少空格)。无论如何,它对您的功能没有任何作用,因此您可以忽略它。

  • 以下字符串不包含y value ,而是文字“ y”:

    output += "y PEN UP" + ";\n";
    

    此外,在代码中的那个位置生成输出是错误的:您将需要先将已经收集的坐标刷新到输出。并且此时输出y或其值也不符合输出语法。