我最近开始使用 asymptote 进行一些绘图和绘画,用于我的研究。然而,我偶然发现了一些我想做的事情 - 但我不知道是否有可能。
我有这样的身材,
我想将其映射到圆的周长,像这样
如果我能像第一个图形那样在常规笛卡尔坐标系(x,y)中绘制该图形,然后将其映射到极坐标系(r,\theta)
,再返回到笛卡尔坐标系(\tilde x,\tilde y')
,那么绘制该图形就会简单得多。映射到极坐标系中将是,
r = y, \theta = \frac{x}{r} = \frac{x}{y}
映射回新的笛卡尔系统将是
\tilde x (r,\theta) = r \cos (\theta) = y \cos (\frac{x}{y}),
\tilde y (r,\theta) = r \csin (\theta) = y \sin (\frac{x}{y}).
我已经研究过可能的变换,但它们似乎都不允许这种变换。我是否可以自己制作一个允许使用非仿射变换的程序?
如果这可以在 TikZ 中实现,我也会对此非常感兴趣。
谢谢,克里斯蒂安
附言:如果有人能告诉我如何使我的数学看起来正确,那也将不胜感激。
答案1
尝试这个:
\documentclass[margin=10pt]{standalone}
\usepackage{asymptote}
\begin{asydef}
struct planeTransformation {
int nInterpolate = 4;
pair apply(real, real);
pair apply(pair uv) { return apply(uv.x, uv.y); }
transform derivative(real, real);
transform derivative(pair uv) { return derivative(uv.x, uv.y); }
transform linearization(real u, real v) {
return shift(apply(u,v)) * derivative(u,v) * shift(-(u,v));
}
transform linearization(pair uv) {
return linearization(uv.x, uv.y);
}
/* Apply to a single Bezier spline. */
guide _apply(pair p1, pair c1, pair c2, pair p2) {
return apply(p1) .. controls linearization(p1)*c1 and linearization(p2)*c2 .. apply(p2);
}
guide _apply(path g) {
assert((length(g)) == 1);
return _apply(point(g,0), postcontrol(g,0), precontrol(g,1), point(g,1));
}
path apply(path g, int nInterpolate = nInterpolate) {
guide toreturn;
for (int i = 0; i < nInterpolate*length(g); ++i) {
real currentpos = i / nInterpolate;
real nextpos = (i+1) / nInterpolate;
toreturn = toreturn & _apply(subpath(g, currentpos, nextpos));
}
if (cyclic(g)) toreturn = toreturn & cycle;
return toreturn;
}
}
planeTransformation polar;
polar.apply = new pair(real r, real theta) {
return r * expi(theta);
};
polar.derivative = new transform(real r, real theta) {
transform t = (0, 0, cos(theta), -r*sin(theta), sin(theta), r*cos(theta));
return t;
};
\end{asydef}
\begin{document}
\begin{asy}
size(5cm);
path curvedbox = polar.apply(box((1, -pi), (2, pi)));
draw(curvedbox);
\end{asy}
\end{document}
结果:
请注意,这只是一个近似变换。为了使其更精确,请调用该函数,例如,polar.apply(g, nInterpolate=16);
其中g
是应应用变换的路径。默认值为nInterpolate = 4
;不同的路径将需要不同级别的插值。路径越复杂,所需的插值点可能就越少。
结果如下
path curvedbox = polar.apply(box((1, -pi), (2, pi)), nInterpolate=16);
补充说明:上面的代码将y
-value 映射到角度,而 OP 最初要求将 -value 映射y
到半径。以下函数应切换到最初请求的顺序:
path switchedPolar(path g) {
return polar.apply(reflect((0,0),(1,1)) * g);
}
polar.apply
或者,在和的定义中,和polar.derivative
的顺序可以互换:r
theta
polar.apply = new pair(real theta, real r) {
ETC。