面試
很久以前,我面試了很多圖形程式設計職位的候選人。 成為一名優秀的面試官是一項艱苦的工作;我早期的嘗試並不好。 隨著時間的推移,我想出了這個問題來開始對話。
我:如果同事來找你說“我需要畫一個圓圈”,你會怎麼做?
- 候選人 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.文字位於基線上方。
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.使用帶有大寫 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.如果您可以使用標記,那麼您可以選擇圓形符號。
平方根,兩種方式
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.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.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.我真的很喜歡 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.)Bresenham 圓繪製演算法的要點是只使用整數並避免乘法和除法(*2 和 *4 可以是移位運算。)
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.圓形函數使用 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.圖形的彈出式選單“大小/比例”->“大小到等距”將自動進行此調整。
您可能更喜歡橢圓函數:
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.Oval 函數對於垂直和水平尺寸有明確的 API。
液壓系統
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.巨大的! 對於五歲的孩子來說實際上太大了。