![为什么这个 METAPOST primarydef 会损坏调用它的 vardef?](https://linux22.com/image/411437/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E4%B8%AA%20METAPOST%20primarydef%20%E4%BC%9A%E6%8D%9F%E5%9D%8F%E8%B0%83%E7%94%A8%E5%AE%83%E7%9A%84%20vardef%EF%BC%9F.png)
METAPOSTcutbefore
并不cutafter
完全可靠在哪里如果要切割的路径与必须切割的路径相交,则它们会切割多次。为了解决这个问题,我创建了两个primarydefs
(maxcutbefore 和 maxcutafter),它们可以像 cutbefore 和 cutafter 一样使用,但可以尽可能地移除。这有效。这个最小示例显示了这一点:
primarydef inPath mycutafter cutPath =
begingroup
save resultPath; path resultPath;
save tmpPath, checkPath; path tmpPath, checkPath;
save aT;
resultPath := inPath; % Algo: we return resultPath unless checkPath is an improvement
forever:
aT := arctime ((arclength resultPath)-1) of resultPath; % t where length is length minus 1bp
checkPath := subpath( 0, aT) of resultPath;
tmpPath := checkPath cutafter cutPath;
if (arclength tmpPath) < (arclength checkPath):
% we have actually cut the path further
resultPath := tmpPath; % set current result value and try again
else:
% we did not cut the path further, we have our result
exitif true;
fi
endfor;
resultPath
endgroup
enddef;
vardef TEST( expr inputConn, fromPicOutline, toPicOutline) =
save resultConn, workingConn; path resultConn, workingConn;
workingConn := inputConn;
% if true:
resultConn := (inputConn cutbefore fromPicOutline) mycutafter toPicOutline;
% else:
% show "HELLO";
% fi
resultConn
enddef;
path line, ca, cb;
ca := fullcircle scaled 2 shifted (-5,0);
cb := fullcircle scaled 2 shifted (5,0);
line := (-10,0)--(10,0);
line := TEST( line, ca, cb);
draw ca;
draw cb;
draw line;
如您所见,我正在使用mycutafter
。如果将其更改为cutafter
,它也可以工作,但线会被切到右圆的右侧,而不是左侧。
但是当我取消注释 if:--else:--fi 行时,vardefTEST
失败并显示:
metapost log > ! Extra 'else'.
metapost log > TEST->...2)cutbefore(EXPR3))mycutafter(EXPR4);else
metapost log > :show"HELLO";fi.resultConn...
metapost log > <*> ...-10,0)--(10,0); line := TEST( line, ca, cb)
metapost log > ; draw ca; draw cb; draw l...
但如果我取消注释这些行并使用原始的cutafter
,它也会起作用。关于 METAFONT 的语法,我肯定有些不明白的地方,导致我的 primarydef 干扰了我的 vardef 代码。但是什么呢?为什么呢?
答案1
我们可以将问题简化为一个更简单的文件:
tracingall;
if true:
forever:
if false:
else:
exitif true;
fi
endfor;
else:
fi
结果是
! Extra else
为什么?
exitif true
终止当前循环立即地。鉴于 MetaPost 不会事先解析文件,而是在解析过程中拾取标记,这意味着循环的剩余部分(包括内 fi
永远不会执行。因此,就 MetaPost 而言,内部if false
从未被终止,因此当看到外部时,fi
我们仍然在块中。这当然是不允许的,从而导致错误。else:
else:
Extra else
如何解决这个问题?正如 Scott H. 在评论中提到的,你可以使用与MetaPost - 如何关闭“当...时结束”消息?fi
在之前插入一个,只有在实际执行exitif
该块时才会看到。else
但是 MetaPost 的设计实际上已经预料到了这种需求,这就是为什么exitif
要接受一个条件:您可以if
通过在之后直接写入中断条件来避免这种情况exitif
:
primarydef inPath mycutafter cutPath =
begingroup
save resultPath; path resultPath;
save tmpPath, checkPath; path tmpPath, checkPath;
save aT;
resultPath := inPath; % Algo: we return resultPath unless checkPath is an improvement
forever:
aT := arctime ((arclength resultPath)-1) of resultPath; % t where length is length minus 1bp
checkPath := subpath( 0, aT) of resultPath;
tmpPath := checkPath cutafter cutPath;
exitif length cuttings = 0;
% if we reach this point we have actually cut the path further
resultPath := tmpPath; % set current result value and try again
endfor;
resultPath
endgroup
enddef;
vardef TEST( expr inputConn, fromPicOutline, toPicOutline) =
save resultConn, workingConn; path resultConn, workingConn;
workingConn := inputConn;
if true:
resultConn := (inputConn cutbefore fromPicOutline) mycutafter toPicOutline;
else:
show "HELLO";
fi
resultConn
enddef;
path line, ca, cb;
ca := fullcircle scaled 2 shifted (-5,0);
cb := fullcircle scaled 2 shifted (5,0);
line := (-10,0)--(10,0);
beginfig(0);
line := TEST( line, ca, cb);
draw ca;
draw cb;
draw line;
endfig;
end;