面试
很久以前,我面试了很多图形编程职位的候选人。 成为一名优秀的面试官是一项艰苦的工作;我早期的尝试并不好。 随着时间的推移,我想出了这个问题来开始对话。
我:如果同事来找你说“我需要画一个圆圈”,你会怎么做?
- 候选人 0:我不知道。
- 候选人1:我不知道。 指南针?
- 候选人 2:嗯嗯。 我会打印一个小写字母“o”。
- 候选人 3:平方根应该可以。
- 候选 4:正弦和余弦应该可以。
- 候选 5:Bresenham 的圆绘制算法应该可以做到。
- 候选人 6:我会告诉他们寻找库函数,向他们展示文档所在的位置。 重用比发明更好。
- 候选人 7:我会说“我不知道。 你为什么要画一个圆?”因为也许他们并不真的需要画一个。 也许他们需要使用平方根知道圆内有什么。 也许他们需要一个椭圆。 一旦我们确定确实需要绘制一个圆,那么在哪里绘制它呢? 它是填充的、实心的还是有图案的? 很可能已经有一个函数可以做到这一点,并且现在已经调试良好。 您可能不需要自己编写它,但如果您这样做,请使用正弦和余弦,并使步长大小成为半径的函数。 需要多快? 根据设备的不同,Bresenham 可能比较合适。 在打印机上,小写字母“o”可能适用于标记并且足够好。
讨论
候选人 0、1、2、3、4、5 都错过了森林。 如果你是面试官,一定要帮助他们看到问题中的另一个人,因为那是问题的一半。 如果您是候选人,请注意两部分问题。
如果你是面试者,永远不要像 0 号候选人那样停止。 候选人 1 和 2 为面试官提出另一个问题提供了足够的机会。 如果您是面试官,请记住,候选人正处于压力之中,需要一些帮助来了解更多细节。
候选者 3、4 和 5 各自提出了一个技术解决方案,其中任何一个都可能有效,但没有一个总是最好的。 如果您是候选人,请继续谈论您的答案。 如果你是面试官,指导他们:“那会(快速、安全、正确等)吗?”
候选者 6 和候选者 7 在实用尺度上处于不同的位置。 需要更多的问题和讨论来确定最合适的方案。
答案
面试问题实际上与画圆无关,但如果这就是您仍在阅读的原因,这里有 JSL 的答案 2、3、4、5、6。
小写字母 o,三种方式
New Window( "Candidate 2, literal",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
Text( Center Justified, {50, 50}, "o" ) // "o" sits above the point
)
);
Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.Text sits above the baseline.文本位于基线上方。
New Window( "Candidate 2, modified",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
markersize(10),
marker( markerstate("O"), {50, 50}) // capital "O" is somewhat centered
)
);
Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.Using a marker with a capital O.使用带有大写 O 的标记。
New Window( "Candidate 2, reinvented",
Graph Box(
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
Marker Size( 100 ),
Marker( Marker State( 8 ), {50, 50} ) // bigger is thicker
)
);
If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.If you can use a marker, then you can pick the circle symbol.如果您可以使用标记,那么您可以选择圆形符号。
平方根,两种方式
New Window( "Candidate 3, sqrt hard way",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sqrt
// a lot of code, and not too pretty on the left and right
step=3; // to make the problem more obvious, use 1 to almost hide it
For( x = 0, x < 30, x += step,
// hyp = sqrt(x^2 + y^2)
// hyp^2 = x^2 + y^2
// hyp^2 - x^2 = y^2
y1 = Sqrt( 30 ^ 2 - x ^ 2 );
y2 = Sqrt( 30 ^ 2 - (x + step) ^ 2 );
// do all four quadrants in parallel
Line( {50 + x, 50 + y1}, {50 + (x + step), 50 + y2} );
Line( {50 - x, 50 + y1}, {50 - (x + step), 50 + y2} );
Line( {50 - x, 50 - y1}, {50 - (x + step), 50 - y2} );
Line( {50 + x, 50 - y1}, {50 + (x + step), 50 - y2} );
)
)
);
The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.The sqrt approach looks rough on the left and right because of the equal-sized steps in x.sqrt 方法在左侧和右侧看起来很粗糙,因为 x 中的步长大小相等。
New Window( "Candidate 3, sqrt with YFunction",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sqrt
// sqrt has two answers. Looks nice, thanks YFunction. Only a small gap.
Y Function( 50 + Sqrt( 30 ^ 2 - (x - 50) ^ 2 ), x );// top
Y Function( 50 - Sqrt( 30 ^ 2 - (x - 50) ^ 2 ), x );// bottom
)
);
The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.The Y Function adjusts the x step size automatically.Y 函数自动调整 x 步长。
正弦和余弦
New Window( "Candidate 4, sin/cos with XYFunction",
Graph Box(
framesize( 300, 300 ),
xaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 50, "Solid", "Black", "", 1 ) ),
// draw a circle at 50,50 with radius 30 using sin/cos
XY Function( 50 + 30 * Cos( t ), 50 + 30 * Sin( t ), t, Min( 0 ), Max( 2 * Pi() ) )
)
);
I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.I really like the XYFunction for this parametric description of a circle.我真的很喜欢 XYFunction 对圆的参数化描述。
布雷森纳姆
//Bresenham.
// using pixel functions (There is no reason I can think of to
// use this code; everything else will be faster! A long time
// ago there was no floating point arithmetic or sin/cos/sqrt
// and tricks like this were useful.)
drawCircle = Function( {xc, yc, x, y}, // not really pixels. this is not a good match for JMP!
Marker( Marker State( 0 ), {xc + x, yc + y} ); // invented for primitive hardware without
Marker( Marker State( 0 ), {xc - x, yc + y} ); // floating point.
Marker( Marker State( 0 ), {xc + x, yc - y} );
Marker( Marker State( 0 ), {xc - x, yc - y} );
Marker( Marker State( 0 ), {xc + y, yc + x} );
Marker( Marker State( 0 ), {xc - y, yc + x} );
Marker( Marker State( 0 ), {xc + y, yc - x} );
Marker( Marker State( 0 ), {xc - y, yc - x} );
);
circleBres = Function( {xc, yc, r}, // https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/
x = 0;
y = r;
d = 3 - 2 * r;
drawCircle( xc, yc, x, y );
While( y >= x,
x++;
If( d > 0,
y--;
d = d + 4 * (x - y) + 10;
,
d = d + 4 * x + 6
);
drawCircle( xc, yc, x, y );
);
);
New Window( "Candidate 5, really hard way using pixels",
Graph Box(
framesize( 900, 900 ),xscale(0,1000),yscale(0,1000),
xaxis( Add Ref Line( 500, "Solid", "Black", "", 1 ) ),
yaxis( Add Ref Line( 500, "Solid", "Black", "", 1 ) ),
// draw a circle at 500,500 with radius 300
circleBres( 500, 500, 300 ),
text({300,700},"Zoom in for detail")
)
);
The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)The point of the Bresenham circle drawing algorithm is to only use integers and avoid multiply and divide ( *2 and *4 can be shift operations.)Bresenham 圆绘制算法的要点是仅使用整数并避免乘法和除法(*2 和 *4 可以是移位运算。)
Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.Zoomed in the pixels always step in either x or y or both.放大像素始终步进 x 或 y 或两者。
库函数
New Window( "Candidate 6, Circle Function",
Graph Box(
xaxis( Show Major Grid( 1 ) ),
yaxis( Show Major Grid( 1 ) ),
Circle( {50, 50}, 30 )
)
);
The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.The Circle Function uses the Y dimension and makes a visibly round circle. Because the axes are not isometric, something seems odd.圆形函数使用 Y 维度并形成一个明显的圆形。 因为轴不是等轴测的,所以有些东西看起来很奇怪。
New Window( "Candidate 6, Circle on square paper",
Graph Box( framesize(400,400),
xaxis( Show Major Grid( 1 ) ),
yaxis( Show Major Grid( 1 ) ),
Circle( {50, 50}, 30 )
)
);
The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.The graph's popup menu, Size/Scale->SizeToIsometric will automatically make this adjustment.图形的弹出菜单“大小/比例”->“大小到等距”将自动进行此调整。
您可能更喜欢椭圆函数:
New Window( "Candidate 6, Oval function",
Graph Box( // framesize(600,400),
x=50;
y=50;
r=30;
Oval( x-r, y-r, x+r, y+r );
)
);
The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.The Oval function has a clear API for the vertical and horizontal dimensions.Oval 函数对于垂直和水平尺寸有明确的 API。
液压系统
I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.I traced a DVD; the cyborg hand is really teaching about hydraulics and levers and putting pieces together.我追踪了一张 DVD;机器人手实际上是在教授液压系统和杠杆以及将零件组装在一起。
我花了一月和二月帮助一个五岁的孩子组装这个巨型机器人手。 我建议七岁作为合理的最低年龄(盒子也是如此);我们每隔一天左右进行一次 10 到 15 分钟的课程。 大约 30 美元的价格非常超值。 最精彩的部分:有一天,5岁的孩子在回家的路上发现了一台挖掘机,并告诉我有关液压缸的信息。
Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.Huge! Actually too big for a five year old.巨大的! 对于五岁的孩子来说实际上太大了。