为什么这个 METAPOST primarydef 会损坏调用它的 vardef?

为什么这个 METAPOST primarydef 会损坏调用它的 vardef?

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;

在此处输入图片描述

相关内容