JAVA實(shí)現(xiàn)掃描線算法(超詳細(xì))
首先說一下,教科書上的掃描線算法確實(shí)是用c++很好實(shí)現(xiàn),而且網(wǎng)上有很多源碼,而java實(shí)現(xiàn)的基本沒有(可能是我沒看到),所以肖先生還是打算自己碼(實(shí)驗(yàn)作業(yè)寫這個而自己又個是寫java的猿0.0)。
對于掃描線的實(shí)現(xiàn)過程,我只在這里大概講下書本上的內(nèi)容(自己去看),主要還是講一下自己實(shí)現(xiàn)時算法的改動和實(shí)現(xiàn)方法。
掃描線算法:顧名思義,就是從Ymin開始掃描,然后構(gòu)建出NET,之后根據(jù)NET建立AET。
貼個圖:


實(shí)現(xiàn)的時候首先是構(gòu)造NET,因?yàn)閷τ趈ava來說不能像c++一樣直接用指針?biāo)晕矣脤ο髷?shù)組和Node類(如下代碼)構(gòu)造了類似數(shù)組+指針的數(shù)據(jù)結(jié)構(gòu)。在實(shí)現(xiàn)了NET后開始通過NET實(shí)現(xiàn)AET,在這里我改變了一種實(shí)現(xiàn)方式,教科書上是一次次遍歷掃描線,然后將NET插入AET后進(jìn)行排序等一系列操作,而我因?yàn)槭亲约簩懙臄?shù)據(jù)結(jié)構(gòu),如果說再建個表按書上的方式來最后還得自己實(shí)現(xiàn)鏈表排序等一系列操作。所以我這里直接用一個包含Arraylist的對象數(shù)組代替了。我的方法是:直接從NET開始遍歷每個節(jié)點(diǎn),得到節(jié)點(diǎn)后將它以及它自己之后會引申出的插入AET的節(jié)點(diǎn)(比如當(dāng)前掃描線y=0 節(jié)點(diǎn) X:1 dx:-1 Ymax:3 那之后會插入AET的就是 0 -1 1 和 -1 -1 2 )將這些節(jié)點(diǎn)不論順序的先插入AET對應(yīng)掃描線位置的對象數(shù)組的list中,將NET中節(jié)點(diǎn)全部遍歷完之后再最后對AET中每個對象數(shù)組的list進(jìn)行排序。最后得到了NET在進(jìn)行打印。
貼個代碼(僅供參考學(xué)習(xí)交流):
package PolygonScanningAndFilling;
public class Node { //新編表記錄x,dx,yMax
public int x;
public float dx;
public int yMax;
public Node next;
public int ymin;
public Node(int x, int dx, int yMax){
this.x=x;
this.dx=dx;
this.yMax=yMax;
}
public void getYmin(int Ymin){
this.ymin=Ymin;
}
}
package PolygonScanningAndFilling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class classAndArray {
public List<Integer> list = new ArrayList<Integer>();
public classAndArray(){
}
public void listSort() {
Collections.sort(list);
}
}
package PolygonScanningAndFilling;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
public class PolygonScanning extends JPanel {
static int X0;
static int Y0;
static int X1;
static int Y1;
static int a[]=new int [10]; //保存點(diǎn)擊的10個x坐標(biāo)
static int b[]=new int [10]; //保存點(diǎn)擊的10個y坐標(biāo)
static int index=0;
static int time=0;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.addMouseListener(new MouseAdapter() {
public void mouseExited(MouseEvent e) {
time++;
repaint();
}
});
Graphics2D g2d = (Graphics2D)g;
int Ymax=0;
for(int i=0;i<b.length;i++)
{
if(Ymax<b[i])
Ymax=b[i];
}
// System.out.println("Ymax"+Ymax);
/*
* 畫出多邊形
*/
int Sum=0;
for(;Sum<=index;Sum++) {
if(Sum==index-1)
{
g2d.drawLine(a[Sum], b[Sum], a[0],b[0]);
break;
}
else
{
g2d.drawLine(a[Sum], b[Sum], a[Sum+1],b[Sum+1]);
}
}
if(time!=0) {
Node [] head =new Node [Ymax]; //建立對應(yīng)掃描邊數(shù)的鏈表長度
for(int i=0;i<index-1;i++)
{
if(b[i]<b[i+1]) //從第一個點(diǎn)開始若前一個點(diǎn)小于后一個點(diǎn)
{
if(head[b[i]]==null)
head[b[i]]=new Node(0,0,0);
head[b[i]].ymin=b[i];
if(head[b[i]].next==null) //該點(diǎn)是第一個插入的節(jié)點(diǎn)
{
head[b[i]].next=new Node(0,0,0);
head[b[i]].next.x=a[i];
head[b[i]].next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i]].next.yMax=b[i+1]; //ymax為后一點(diǎn)的y
}
else { //該點(diǎn)不是第一個插入的節(jié)點(diǎn)
if(head[b[i]].next.next==null)
head[b[i]].next.next=new Node(0,0,0);
if((float)(a[i]-a[i+1])/(b[i]-b[i+1])<head[b[i]].next.dx) //當(dāng)前插入x比之前存在的節(jié)點(diǎn)x小
{
head[b[i]].next.next.x=head[b[i]].next.x;
head[b[i]].next.next.dx=head[b[i]].next.dx;
head[b[i]].next.next.yMax=head[b[i]].next.yMax;
head[b[i]].next.x=a[i];
head[b[i]].next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i]].next.yMax=b[i+1];
}
else
{
head[b[i]].next.next.x=a[i];
head[b[i]].next.next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i]].next.next.yMax=b[i+1];
}
}
}
else
{
if(head[b[i+1]]==null)
head[b[i+1]]=new Node(0,0,0);
head[b[i+1]].ymin=b[i+1];
if(head[b[i+1]].next==null) //該點(diǎn)是第一個插入的節(jié)點(diǎn)
{
head[b[i+1]].next=new Node(0,0,0);
head[b[i+1]].next.x=a[i+1];
head[b[i+1]].next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i+1]].next.yMax=b[i]; //ymax為后一點(diǎn)的y
}
else { //該點(diǎn)不是第一個插入的節(jié)點(diǎn)
if(head[b[i+1]].next.next==null)
head[b[i+1]].next.next=new Node(0,0,0);
if((float)(a[i]-a[i+1])/(b[i]-b[i+1])<head[b[i+1]].next.dx) //當(dāng)前插入x比之前存在的節(jié)點(diǎn)x小
{
head[b[i+1]].next.next.x=head[b[i+1]].next.x;
head[b[i+1]].next.next.dx=(float)head[b[i+1]].next.dx;
head[b[i+1]].next.next.yMax=head[b[i+1]].next.yMax;
head[b[i+1]].next.x=a[i+1];
head[b[i+1]].next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i+1]].next.yMax=b[i];
}
else
{
head[b[i+1]].next.next.x=a[i+1];
head[b[i+1]].next.next.dx=(float)(a[i]-a[i+1])/(b[i]-b[i+1]);
head[b[i+1]].next.next.yMax=b[i];
}
}
}
}
if(index>0)
{ if(b[0]<b[index-1]) //從第一個點(diǎn)到最后一個點(diǎn)
{
if(head[b[0]]==null)
head[b[0]]=new Node(0,0,0);
head[b[0]].ymin=b[0];
if(head[b[0]].next==null) //該點(diǎn)是第一個插入的節(jié)點(diǎn)
{
head[b[0]].next=new Node(0,0,0);
head[b[0]].next.x=a[0];
head[b[0]].next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[0]].next.yMax=b[index-1]; //ymax為后一點(diǎn)的y
}
else { //該點(diǎn)不是第一個插入的節(jié)點(diǎn)
if(head[b[0]].next.next==null)
head[b[0]].next.next=new Node(0,0,0);
if((float)(a[0]-a[index-1])/(b[0]-b[index-1])<head[b[0]].next.dx) //當(dāng)前插入x比之前存在的節(jié)點(diǎn)x小
{
head[b[0]].next.next.x=head[b[0]].next.x;
head[b[0]].next.next.dx=head[b[0]].next.dx;
head[b[0]].next.next.yMax=head[b[0]].next.yMax;
head[b[0]].next.x=a[0];
head[b[0]].next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[0]].next.yMax=b[index-1];
}
else
{
head[b[0]].next.next.x=a[0];
head[b[0]].next.next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[0]].next.next.yMax=b[index-1];
}
}
}
else
{
if(head[b[index-1]]==null)
head[b[index-1]]=new Node(0,0,0);
head[b[index-1]].ymin=b[index-1];
if(head[b[index-1]].next==null) //該點(diǎn)是第一個插入的節(jié)點(diǎn)
{
head[b[index-1]].next=new Node(0,0,0);
head[b[index-1]].next.x=a[index-1];
head[b[index-1]].next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[index-1]].next.yMax=b[0]; //ymax為后一點(diǎn)的y
}
else { //該點(diǎn)不是第一個插入的節(jié)點(diǎn)
if(head[b[index-1]].next.next==null)
head[b[index-1]].next.next=new Node(0,0,0);
if((float)(a[0]-a[index-1])/(b[0]-b[index-1])<head[b[index-1]].next.dx) //當(dāng)前插入x比之前存在的節(jié)點(diǎn)x小
{
head[b[index-1]].next.next.x=head[b[index-1]].next.x;
head[b[index-1]].next.next.dx=head[b[index-1]].next.dx;
head[b[index-1]].next.next.yMax=head[b[index-1]].next.yMax;
head[b[index-1]].next.x=a[index-1];
head[b[index-1]].next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[index-1]].next.yMax=b[0];
}
else
{
head[b[index-1]].next.next.x=a[index-1];
head[b[index-1]].next.next.dx=(float)(a[0]-a[index-1])/(b[0]-b[index-1]);
head[b[index-1]].next.next.yMax=b[0];
}
}
}
}
for(int i=0;i<Ymax;i++)
if(head[i]!=null)
while(head[i].next!=null)
{ System.out.println("新編表y"+head[i].ymin+"新編表x"+head[i].next.x+"新編表dx"+head[i].next.dx+"新編表yMax"+head[i].next.yMax);
if(head[i].next.next!=null)
{
System.out.println("多的"+"新編表y"+head[i].ymin+"新編表x"+head[i].next.next.x+"新編表dx"+head[i].next.next.dx+"新編表yMax"+head[i].next.next.yMax);
}
break;
}
int YMIN=b[0];
for(int i=0;i<b.length;i++)
{
if(YMIN>b[i]&&b[i]!=0)
YMIN=b[i];
}
classAndArray [] ca=new classAndArray [Ymax];
for(int i=YMIN;i<Ymax;i++)
ca[i]=new classAndArray();
//一個點(diǎn)一個點(diǎn)的全裝入ca中再排序打印出點(diǎn)
for(int i=0;i<Ymax;i++)
{
if(head[i]!=null)
if(head[i].next!=null)
{
//System.out.println("新編表y"+head[i].ymin+"新編表x"+head[i].next.x+"新編表dx"+head[i].next.dx+"新編表yMax"+head[i].next.yMax);
for(int j=head[i].ymin;j<head[i].next.yMax;j++)
{
ca[i+j-head[i].ymin].list.add(head[i].next.x+(int)(0.5+((j-head[i].ymin)*head[i].next.dx)));
//System.out.print("ca[i+j-head[i].ymin]為"+(i+j-head[i].ymin)+"值為"+ca[i+j-head[i].ymin].list.toString());
//System.out.println("Ymin為"+i+" x為"+(head[i].next.x+(j-head[i].ymin)*head[i].next.dx));
}
if(head[i].next.next!=null)
{
for(int j=head[i].ymin;j<head[i].next.next.yMax;j++)
{
ca[i+j-head[i].ymin].list.add(head[i].next.next.x+(int)(0.5+(j-head[i].ymin)*head[i].next.next.dx));
//System.out.print("next中ca[i+j-head[i].ymin]為"+(i+j-head[i].ymin)+"值為"+ca[i+j-head[i].ymin].list.toString());
//System.out.println("Ymin為"+i+" x為"+head[i].next.next.x+(j-head[i].ymin)*head[i].next.next.dx);
}
//System.out.println("多的"+"新編表y"+head[i].ymin+"新編表x"+head[i].next.next.x+"新編表dx"+head[i].next.next.dx+"新編表yMax"+head[i].next.next.yMax);
}
}
}
//
for(int i=YMIN;i<Ymax;i++)
{
ca[i].listSort();
for (int j = 0; j < ca[i].list.size(); j++) {
if(j%2==0||(j==0))
{
g2d.drawLine(ca[i].list.get(j), i, ca[i].list.get(j+1), i);
}
}
System.out.println(ca[i].list.toString());
}
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setLocationRelativeTo(null);
frame.setLayout(null);
JPanel jp=new JPanel();
frame.setContentPane(jp);
frame.setVisible(true);
frame.addMouseListener(new MouseAdapter() {
});
jp.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(e.getButton() == e.BUTTON1)
{a[index]=e.getX();
b[index]=e.getY();
System.out.println("坐標(biāo)為("+a[index]+","+b[index]+")");
index++;
frame.setVisible(true);
}
if(e.getButton() == e.BUTTON3)
{
frame.setContentPane(new PolygonScanning());
frame.setVisible(true);
}
}
}
);
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) throws IOException {
createAndShowGUI();
}
}
效果截圖(先在面板里點(diǎn)擊點(diǎn),右鍵出現(xiàn)所需填充的輪廓,鼠標(biāo)移出面板填充)


總結(jié)
以上所述是小編給大家介紹的JAVA實(shí)現(xiàn)掃描線算法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
SpringBoot+Prometheus+Grafana實(shí)現(xiàn)應(yīng)用監(jiān)控和報(bào)警的詳細(xì)步驟
這篇文章主要介紹了SpringBoot+Prometheus+Grafana實(shí)現(xiàn)應(yīng)用監(jiān)控和報(bào)警的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02
nas實(shí)現(xiàn)java開發(fā)的環(huán)境詳解
這篇文章主要為大家介紹了nas實(shí)現(xiàn)java開發(fā)的環(huán)境詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
SpringBoot集成Zipkin實(shí)現(xiàn)分布式全鏈路監(jiān)控
這篇文章主要介紹了SpringBoot集成Zipkin實(shí)現(xiàn)分布式全鏈路監(jiān)控的方法啊,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
springboot工程jar包部署到云服務(wù)器的方法
這篇文章主要介紹了springboot工程jar包部署到云服務(wù)器的方法,本文通過實(shí)例介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友參考下吧2018-05-05
利用Java代碼實(shí)現(xiàn)區(qū)塊鏈技術(shù)
這篇文章主要介紹了利用Java代碼實(shí)現(xiàn)區(qū)塊鏈技術(shù),區(qū)塊鏈的應(yīng)用范圍幾乎無窮無盡,關(guān)于區(qū)塊鏈?zhǔn)侨绾芜\(yùn)作的,下文來看看具體的內(nèi)容介紹吧,需要的朋友可以參考一下2022-04-04
GC調(diào)優(yōu)實(shí)戰(zhàn)之過早提升Premature?Promotion
這篇文章主要為大家介紹了GC調(diào)優(yōu)實(shí)戰(zhàn)之過早提升Premature?Promotion2022-01-01

