目的:
サザーランド・ホッジマン ポリゴン クリッピング アルゴリズムを使用して、図に示すポリゴンをクリップします。各クリップに対応するグラフィックスを描画し、入力頂点と出力頂点を示す必要があります。自分で作成した Sutherland-Hodgeman ポリゴン クリッピング プログラムで検証してください
実験原理:
一度にウィンドウの片側ずつポリゴンをクリップします。
ウィンドウの 1 つの端と、平面を 2 つの部分 (可視側と不可視側) に分割する延長線によって形成されるクリッピング ラインについて考えてみましょう。多角形の各辺の終点 S および P。クリッピングラインとの位置関係は4つだけです
図 1 は 1 つの頂点 P のみを出力します。
図 2 では頂点が 0 個出力されます。
図 3 は、線分 SP とクリッピング ラインの交点 I を出力します。
図4は、線分SPとクリッピングラインとの交点Iと端点Pを出力する。
3: 実験手順とソースコード
关键代码:
//判断点在线段的内侧还是外侧
int Inside(Point p, Boundary b, Point wMin, Point wMax)
{
switch (b)
{
case Left:
if (p.x < wMin.x) return (false);
break;
case Top:
if (p.y > wMax.y) return (false);
break;
case Right:
if (p.x > wMax.x) return (false);
break;
case Bottom:
if (p.y < wMin.y) return (false);
break;
}
return true;
}
//判断两点在同侧还是异侧
int Cross(Point p1, Point p2, Boundary b, Point wMin, Point wMax)
{
if (Inside(p1, b, wMin, wMax) == Inside(p2, b, wMin, wMax))
return (false);
else
return true;
}
//求交点
Point Intersect(Point p1, Point p2, Boundary b, Point wMin, Point wMax)
{
Point iPt = { 0,0 };
float m = 0;
if (p1.x != p2.x) m = (p2.y - p1.y) / (p2.x - p1.x);
switch (b)
{
case Left:
iPt.x = wMin.x;
iPt.y = p2.y + (wMin.x - p2.x) * m;
break;
case Right:
iPt.x = wMax.x;
iPt.y = p2.y + (wMax.x - p2.x) * m;
break;
case Bottom:
iPt.y = wMin.y;
if (p1.x != p2.x)iPt.x = p2.x + (wMin.y - p2.y) / m;
else iPt.x = p2.x;
break;
case Top:
iPt.y = wMax.y;
if (p1.x != p2.x) iPt.x = p2.x + (wMax.y - p2.y) / m;
else iPt.x = p2.x;
break;
}
return iPt;
}
//返回裁剪后的顶点个数
int edgeCliper(Boundary b, Point wMin, Point wMax, Point* pIn, int cnt, Point* pOut)
{
Point s;
int i, Outcnt = 0;
s = pIn[0];
for (i = 1; i <= cnt; i++)
{
if (!Inside(s, b, wMin, wMax) && Inside(pIn[i], b, wMin, wMax))
{
pOut[Outcnt] = Intersect(s, pIn[i], b, wMin, wMax);
Outcnt++;
pOut[Outcnt] = pIn[i];
Outcnt++;
}
else if (Inside(s, b, wMin, wMax) && Inside(pIn[i], b, wMin, wMax))
{
pOut[Outcnt] = pIn[i];
Outcnt++;
}
else if (Inside(s, b, wMin, wMax) && (!Inside(pIn[i], b, wMin, wMax)))
{
pOut[Outcnt] = Intersect(s, pIn[i], b, wMin, wMax);
Outcnt++;
}
s = pIn[i];
}
return (Outcnt);
}
void ClipPolygonSuthHodg(vector<VERTEX>& polygon)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
int i, cnt, Outcnt, b;
Point points[6] = { {400, 100}, {500, 400}, {800, 100}, {600, 800}, {100, 500},{400, 100} };
cnt = 5;
Point pOut[20], pIn[20];
Point wMin = { 200, 200 }, wMax = { 600, 600 };
for (i = 0; i < 4 * cnt; i++)
{
pIn[i].x = 0.0;
pIn[i].y = 0.0;
pOut[i].x = 0.0;
pOut[i].y = 0.0;
}
for (i = 0; i <= cnt; i++) pIn[i] = points[i];
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
glVertex2f(wMin.x, wMin.y);
glVertex2f(wMax.x, wMin.y);
glVertex2f(wMax.x, wMax.y);
glVertex2f(wMin.x, wMax.y);
glEnd();
glLineWidth(1.0);
glLineStipple(1, 0x0F0F);
glBegin(GL_LINE_LOOP);
for (i = 0; i < cnt; i++)
glVertex2f(pIn[i].x, pIn[i].y);
glEnd();
for (b = 0; b < 4; b++)
{
Outcnt = edgeCliper(Boundary(b), wMin, wMax, pIn, cnt, pOut);
for (int i = 0; i < Outcnt; i++)
for (i = 0; i < Outcnt; i++)
pIn[i] = pOut[i];
pIn[Outcnt] = pOut[0];
cnt = Outcnt;
}
glDisable(GL_LINE_STIPPLE);
glLineWidth(2.0);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
for (i = 0; i < cnt; i++)
glVertex2f(pOut[i].x, pOut[i].y);
glEnd();
glFlush();
}
実験結果と分析
オリジナルグラフィック:
トリミングされたグラフィックス
分析: ポリゴン アルゴリズムに従ってクリップされたグラフィックスが上の赤い線で示されています。これが私たちが望むものです。各エッジを 1 回クリップすると、頂点シーケンスが再取得されます 4 つのエッジを合計 4 回カットします アルゴリズムの考え方は難しくありませんが、アルゴリズムの実装はさらに面倒で、交点の計算が必要ですも少し難しいです。