我正在努力寻找根据某种输入格式输出一系列笔位置的逻辑。
应该转换笔的位置数据,使其保持“下笔”和“上笔”状态(我正在工作),并且将超出矩形区域的笔移动剪切为输入(x = -8192,y = -8192)..(8191,8191)。我无法进行剪辑。
有关应如何进行裁剪的信息,请参见以下说明:
预期输出示例
inputData:
F0A0417F40004000417FC067086708804001C0670840004000187818784000804000
inputData: F0A0417F41004000417FC067086708804001C067082C3C18782C3C804000
//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
}
预期结果 创建与上面示例相同的输出。
答案 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 给出。
满足以下条件之一时将不存在交集:
因此,要确定线段是否与边界框(-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"));
您在问题中发布的代码存在一些问题(这就是为什么我使用原始代码而不进行任何更改的原因):
使用commands
,command
,allPos
和lastPos
之类的全局变量是一种不好的做法:您可以在函数中更改它们的值,从而得到函数side effects;
在以下语句中设置了color
变量,但从未使用过该值:
color = "CO" + 0 + 0 + 0 + 255 + ";\n";
此外,该值未遵循所需的语法(RGB值之间缺少空格)。无论如何,它对您的功能没有任何作用,因此您可以忽略它。
以下字符串不包含y
的 value ,而是文字“ y”:
output += "y PEN UP" + ";\n";
此外,在代码中的那个位置生成输出是错误的:您将需要先将已经收集的坐标刷新到输出。并且此时输出y
或其值也不符合输出语法。