首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 與 MATLAB 繪製閉合多邊形完整對比:從算法原理到生產級視覺化

     編輯:Java 程式設計入門

前言:多邊形繪製的幾何本質

「閉合多邊形」在計算機圖形學中定義為:給定頂點序列 P₀, P₁, ..., Pₙ₋₁,依次連接 Pᵢ → Pᵢ₊₁,並連接 Pₙ₋₁ → P₀ 形成閉合輪廓。本文將對比 MATLAB 腳本繪圖與 Java AWT/Graphics2D 繪圖的實現差異、座標系統、渲染管線、擴展性,並提供生產級 Java 繪圖組件代碼。

1. MATLAB 實現:矩陣思維的向量化繪圖

核心代碼


% 閉合多邊形繪圖腳本
clear; clc;

% 頂點座標矩陣:第1行 x,第2行 y
vertices = [0  2  4  6  8  10 12 14;  % x 座標
            0  2  1  4  6  6  5  7];   % y 座標

[n, m] = size(vertices);  % n=2, m=8

figure('Name', 'MATLAB 閉合多邊形', 'Color', 'w');
hold on; axis equal; grid on;
title('MATLAB 繪製閉合多邊形'); xlabel('X'); ylabel('Y');

% 繪製邊:逐段連線
for i = 1:m-1
    line([vertices(1,i), vertices(1,i+1)], [vertices(2,i), vertices(2,i+1)], ...
         'Color', 'b', 'LineWidth', 2, 'Marker', 'o', 'MarkerFaceColor', 'r');
end

% 首尾閉合
line([vertices(1,1), vertices(1,m)], [vertices(2,1), vertices(2,m)], ...
     'Color', 'b', 'LineWidth', 2, 'Marker', 'o', 'MarkerFaceColor', 'r');

% 填充顏色(可選)
% fill(vertices(1,:), vertices(2,:), [0.8 0.9 1.0], 'FaceAlpha', 0.3);

MATLAB 特點分析

維度特點
數據結構矩陣/陣列原生,向量化運算極簡
繪圖模型Handle Graphics 物件模型,每個圖元可單獨屬性設置
座標系統笛卡爾座標,Y 軸向上,自動縮放適應數據範圍
閉合邏輯手動首尾連線,或 fill/patch 自動閉合填充
適用場景科研數據快速視覺化、算法驗證、教學演示

2. Java 實現:AWT Graphics2D 專業渲染管線

核心 API:Graphics.drawPolygon / fillPolygon


public abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints);
public abstract void fillPolygon(int[] xPoints, int[] yPoints, int nPoints);

參數語義:

  • xPoints[]、yPoints[]:頂點座標陣列,長度 ≥ nPoints
  • nPoints:頂點數(即邊數),系統自動閉合首尾
  • 座標系統:屏幕座標,原點左上角,X 向右,Y 向下

完整 Swing 組件實現(生產級)


import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.Random;

public class PolygonCanvas extends JPanel {

    private final int[] xPoints;
    private final int[] yPoints;
    private final int nPoints;
    private final Polygon polygon; // 用於碰撞檢測、包含判斷

    public PolygonCanvas(int[] xPoints, int[] yPoints) {
        if (xPoints.length != yPoints.length || xPoints.length < 3) {
            throw new IllegalArgumentException("頂點數組長度需一致且 ≥ 3");
        }
        this.xPoints = xPoints.clone();
        this.yPoints = yPoints.clone();
        this.nPoints = xPoints.length;
        this.polygon = new Polygon(this.xPoints, this.yPoints, this.nPoints);
        setPreferredSize(new Dimension(600, 400));
        setBackground(Color.WHITE);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        // 開啟抗鋸齒
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

        // 1. 繪製座標軸
        drawAxes(g2);

        // 2. 填充多邊形(半透明)
        g2.setColor(new Color(0x87CEEB, true)); // SkyBlue + Alpha
        g2.fillPolygon(xPoints, yPoints, nPoints);

        // 3. 繪製邊框
        g2.setStroke(new BasicStroke(2.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2.setColor(new Color(0x1E90FF)); // DodgerBlue
        g2.drawPolygon(xPoints, yPoints, nPoints);

        // 4. 標註頂點
        g2.setColor(Color.RED);
        for (int i = 0; i < nPoints; i++) {
            g2.fillOval(xPoints[i] - 4, yPoints[i] - 4, 8, 8);
            g2.drawString("P" + i, xPoints[i] + 6, yPoints[i] - 6);
        }

        // 5. 顯示幾何屬性
        g2.setColor(Color.DARK_GRAY);
        g2.drawString(String.format("面積: %.2f", polygon.getBounds2D().getWidth() * polygon.getBounds2D().getHeight()), 10, 20);
        g2.drawString(String.format("重心: (%.1f, %.1f)", centroidX(), centroidY()), 10, 40);
    }

    private void drawAxes(Graphics2D g2) {
        int w = getWidth(), h = getHeight();
        g2.setColor(Color.LIGHT_GRAY);
        g2.drawLine(50, h - 50, w - 50, h - 50); // X 軸
        g2.drawLine(50, h - 50, 50, 50);         // Y 軸
        // 刻度略
    }

    /** 計算多邊形重心(質心) */
    private double centroidX() {
        double cx = 0, area = 0;
        for (int i = 0, j = nPoints - 1; i < nPoints; j = i++) {
            double cross = xPoints[j] * yPoints[i] - xPoints[i] * yPoints[j];
            area += cross;
            cx += (xPoints[j] + xPoints[i]) * cross;
        }
        return cx / (3 * area);
    }
    private double centroidY() {
        double cy = 0, area = 0;
        for (int i = 0, j = nPoints - 1; i < nPoints; j = i++) {
            double cross = xPoints[j] * yPoints[i] - xPoints[i] * yPoints[j];
            area += cross;
            cy += (yPoints[j] + yPoints[i]) * cross;
        }
        return cy / (3 * area);
    }

    /** 主程序啟動 */
    public static void main(String[] args) {
        // 測試數據:凹多邊形
        int[] xs = {100, 200, 300, 250, 150, 50};
        int[] ys = {300, 100, 200, 300, 350, 250};

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Java 閉合多邊形繪製 - Graphics2D");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new PolygonCanvas(xs, ys));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

3. 深度對比:MATLAB vs Java

維度MATLABJava (AWT/Graphics2D)
閉合方式手動首尾連線或 fill/patch 自動drawPolygon/fillPolygon 內建自動閉合
座標系統數學座標(Y↑),自動適應屏幕座標(Y↓),需手動變換
渲染質量向量圖形,導出 EPS/PDF 無損光柵化,抗鋸齒依賴 RenderingHints
交互性圖形窗口基礎交互完整事件模型(滑鼠、鍵盤、拖拽、縮放)
幾何計算內建 polyarea、centroid、inpolygonPolygon/Area 類支援面積、包含、布爾運算
部署形態腳本/MATLAB RuntimeJAR/原生映像/Web (Applet 已棄用)
性能(萬級頂點)較慢(解釋執行)極快(JIT 編譯、GPU 加速管線)

4. 進階主題:座標變換與自適應縮放

Java 繪圖常需將業務座標(如經緯度、米制)映射到屏幕像素。推薦使用 AffineTransform:


/** 計算適應面板的變換:業務座標 → 屏幕座標 */
private AffineTransform calculateTransform() {
    Rectangle2D bounds = polygon.getBounds2D();
    double scaleX = (getWidth() - 100) / bounds.getWidth();
    double scaleY = (getHeight() - 100) / bounds.getHeight();
    double scale = Math.min(scaleX, scaleY) * 0.9; // 留邊距

    AffineTransform at = new AffineTransform();
    at.translate(50, getHeight() - 50);      // 原點移至左下角(模擬數學座標)
    at.scale(scale, -scale);                 // Y 軸翻轉 + 縮放
    at.translate(-bounds.getCenterX(), -bounds.getCenterY()); // 幾何中心對齊
    return at;
}

@Override
protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    AffineTransform at = calculateTransform();
    Shape transformed = at.createTransformedShape(polygon);
    g2.fill(transformed);
    g2.draw(transformed);
}

5. 頂點順序與多邊形類型

文中提到:「是否能構成多邊形,凸多邊形,還是凹多邊形,這些與給定的點的順序有關。程序只是負責將相鄰的節點連接,以及首尾連接。」

  • 順時針/逆時針:影響填充規則(非零環數規則 vs 奇偶規則),Graphics2D 默認非零環數
  • 自相交:頂點順序導致邊相交,形成複雜多邊形,填充效果視規則而定
  • 凸包:若需保證凸多邊形,先計算凸包(Graham Scan / Andrew 算法)再繪製

6. 現代替代方案:JavaFX / Processing / JFreeChart

方案優勢適用場景
JavaFX硬體加速、CSS 樣式、FXML 分離、WebView 整合現代桌面應用、複雜 UI
Processing藝術編程、簡單 API、跨平台導出創意編程、教學、快速原型
JFreeChart / XChart專業圖表庫、多種圖表類型、導出高質量圖片商業報表、數據分析
OpenGL (JOGL/LWJGL)GPU 級性能、著色器、3D遊戲、科學視覺化、大數據渲染

總結

Java 與 MATLAB 繪製閉合多邊形的核心差異在於:

  • MATLAB:數據科學視角,矩陣操作、數學座標、向量化腳本、快速驗證
  • Java:工程落地視角,Graphics2D 渲染管線、屏幕座標、事件驅動、高性能、可部署

本文提供的 PolygonCanvas 組件已包含:抗鋸齒、填充+描邊、頂點標註、座標軸、幾何屬性顯示、自適應縮放變換,可直接集成到 Swing/JavaFX(通過 SwingNode)應用中。若需導出向量圖,可改用 Graphics2D 繪製到 PDFGraphics2D(iText)或 SVGGraphics2D(Batik)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved