J2ME Graphics.fillPolygon() 僅支持凸多邊形,且部分實現有 Bug。對於凹多邊形、複雜幾何體,需自行實現掃描線算法。本文提供一個完整的 Canvas 子類,演示如何將任意多邊形轉換為水平掃描線段並填充,最後支持裁剪輸出為新 Image。
drawLine(Xstart, Y, Xend, Y)。// 檢查掃描線 y 是否與線段 (y0,y1) 相交
private boolean checkForCut(int y, int y0, int y1) {
return (y0 >= y && y1 <= y) || (y0 <= y && y1 >= y);
}
// 獲取第 y 行所有交點 X,存入堆棧
private void getCut(int[][] nodes, int y) {
int n = nodes.length;
for (int i = 0; i < n - 1; i++) {
int x0 = nodes[i][0], y0 = nodes[i][1];
int x1 = nodes[i+1][0], y1 = nodes[i+1][1];
if (y0 == y1 && y0 == y) { push(x0); push(x1); continue; }
if (checkForCut(y, y0, y1)) {
int tx = (x1 - x0) * (y - y0) / (y1 - y0) + x0;
push(tx);
}
}
// 首尾閉合邊
if (nodes[0][1] == nodes[n-1][1] && nodes[0][1] == y) {
push(nodes[0][0]); push(nodes[n-1][0]);
} else if (checkForCut(y, nodes[n-1][1], nodes[0][1])) {
int tx = (nodes[0][0] - nodes[n-1][0]) * (y - nodes[n-1][1])
/ (nodes[0][1] - nodes[n-1][1]) + nodes[n-1][0];
push(tx);
}
sortHeapDesc(); // 冒泡降序
}
// 填充主循環
private void fillPolygon(int[][] nodes) {
gb.setColor(0xFF0000);
for (int y = 0; y < nHeight; y++) {
getCut(nodes, y);
if (heap == null) continue;
int j = 0, startX = 0;
while (heap != null) {
int x = pop();
if ((j % 2) == 0) startX = x;
else gb.drawLine(startX, y, x, y);
j++;
}
}
}
為避免 Vector 開銷,採用動態數組模擬堆棧:
push():數組擴容 +1,複製舊數據,存入新元素,System.gc()。pop():取尾元素,數組縮容 -1,複製數據,System.gc()。sortHeapDesc():簡單冒泡排序,點數通常 < 20,性能可接受。填充繪製在離屏 bufImg 上,需裁剪某矩形區域時:
private Image theCutImg;
private void cutGraphics(int x, int y, int w, int h) {
theCutImg = Image.createImage(w, h);
Graphics tg = theCutImg.getGraphics();
tg.drawImage(bufImg, -x, -y, 0); // 負座標偏移實現裁剪
}
class PolygonFillCanvas extends Canvas implements Runnable {
int[][] nodes = {{20,100},{100,40},{170,80},{150,110},{170,170},{160,150},{110,110},{50,130}};
Image bufImg; Graphics gb;
// ... 構造函數創建 bufImg/gb
public void run() {
gb.setColor(0xFFFFFF); gb.fillRect(0,0,getWidth(),getHeight());
fillPolygon(nodes);
drawPolygonOutline(nodes); // 綠色描邊
repaint();
}
public void paint(Graphics g) { g.drawImage(bufImg,0,0,0); }
}
drawImage。