首先说一下,教科书上的扫描线算法确实是用c++很好实现,而且网上有很多源码,而java实现的基本没有(可能是我没看到),所以还是打算自己码(实验作业写这个而自己又个是写java的猿0.0)。

对于扫描线的实现过程,我只在这里大概讲下书本上的内容(自己去看),主要还是讲一下自己实现时算法的改动和实现方法

扫描线算法:顾名思义,就是从Ymin开始扫描,然后构建出NET,之后根据NET建立AET。

贴个图:

 

实现的时候首先是构造NET,因为对于java来说不能像c++一样直接用指针所以我用对象数组和Node类(如下代码)构造了类似数组+指针的数据结构。在实现了NET后开始通过NET实现AET,在这里我改变了一种实现方式,教科书上是一次次遍历扫描线,然后将NET插入AET后进行排序等一系列操作,而我因为是自己写的数据结构,如果说再建个表按书上的方式来最后还得自己实现链表排序等一系列操作。所以我这里直接用一个包含Arraylist的对象数组代替了。我的方法是:直接从NET开始遍历每个节点,得到节点后将它以及它自己之后会引申出的插入AET的节点(比如当前扫描线y=0 节点  X:1 dx:-1  Ymax:3 那之后会插入AET的就是 0 -1 1  和   -1  -1  2 )将这些节点不论顺序的先插入AET对应扫描线位置的对象数组的list中,将NET中节点全部遍历完之后再最后对AET中每个对象数组的list进行排序。最后得到了NET在进行打印。

贴个代码(仅供参考学习交流):

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]; //保存点击的10个x坐标
static int b[]=new int [10]; //保存点击的10个y坐标
static int index=0;
static int time=0;
static int time2=0;
static boolean add;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.addMouseListener(new MouseAdapter() {
public void mouseExited(MouseEvent e) {
time++;
repaint(); }
public void mouseClicked(MouseEvent e) { if(e.getButton() == e.BUTTON1) {
add=true;
if(index!=0)
{
for(int i=0;i<index;i++)
{
if(a[i]==e.getX()&&b[i]==e.getY())
add=false;
}
}
if(add)
{ a[index]=e.getX();
b[index]=e.getY(); System.out.println("坐标为("+a[index]+","+b[index]+")");
index++; //frame.setVisible(true);
repaint();
System.out.print(time2);
if(time2==0)
time2++;
}
} // if(e.getButton() == e.BUTTON3)
// {
//
// }
} }); 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); /*
* 画出多边形
*/
if(time2>0)
{
System.out.print("开始");
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]; //建立对应扫描边数的链表长度
for(int i=0;i<index-1;i++)
{ if(b[i]<b[i+1]) //从第一个点开始若前一个点小于后一个点
{
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) //该点是第一个插入的节点
{
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为后一点的y
}
else { //该点不是第一个插入的节点
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) //当前插入x比之前存在的节点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) //该点是第一个插入的节点
{
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为后一点的y
}
else { //该点不是第一个插入的节点
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) //当前插入x比之前存在的节点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]) //从第一个点到最后一个点
{
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) //该点是第一个插入的节点
{
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为后一点的y
}
else { //该点不是第一个插入的节点
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) //当前插入x比之前存在的节点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) //该点是第一个插入的节点
{
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为后一点的y
}
else { //该点不是第一个插入的节点
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) //当前插入x比之前存在的节点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();
//一个点一个点的全装入ca中再排序打印出点
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.setVisible(true); frame.setContentPane(new PolygonScanning()); 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(); }
}

效果截图(先在面板里点击点,鼠标移出面板填充)

JAVA实现扫描线算法的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. hdu-1542 Atlantis(离散化+线段树+扫描线算法)

    题目链接: Atlantis Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/32768 K (Java/Others) ...

  3. JAVA实现种子填充算法

    种子填充算法原理在网上很多地方都能找到,这篇是继上篇扫描线算法后另一种填充算法,直接上实现代码啦0.0 我的实现只是实现了种子填充算法,但是运行效率不快,如果大佬有改进方法,欢迎和我交流,谢谢! 最后 ...

  4. 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题

    背景起因: 记起以前的另一次也是关于内存的调优分享下   有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...

  5. Elasticsearch之java的基本操作一

    摘要   接触ElasticSearch已经有一段了.在这期间,遇到很多问题,但在最后自己的不断探索下解决了这些问题.看到网上或多或少的都有一些介绍ElasticSearch相关知识的文档,但个人觉得 ...

  6. 论:开发者信仰之“天下IT是一家“(Java .NET篇)

    比尔盖茨公认的IT界领军人物,打造了辉煌一时的PC时代. 2008年,史蒂夫鲍尔默接替了盖茨的工作,成为微软公司的总裁. 2013年他与微软做了最后的道别. 2013年以后,我才真正看到了微软的变化. ...

  7. 故障重现, JAVA进程内存不够时突然挂掉模拟

    背景,服务器上的一个JAVA服务进程突然挂掉,查看产生了崩溃日志,如下: # Set larger code cache with -XX:ReservedCodeCacheSize= # This ...

  8. 死磕内存篇 --- JAVA进程和linux内存间的大小关系

    运行个JAVA 用sleep去hold住 package org.hjb.test; public class TestOnly { public static void main(String[] ...

  9. 【小程序分享篇 一 】开发了个JAVA小程序, 用于清除内存卡或者U盘里的垃圾文件非常有用

    有一种场景, 手机内存卡空间被用光了,但又不知道哪个文件占用了太大,一个个文件夹去找又太麻烦,所以我开发了个小程序把手机所有文件(包括路径下所有层次子文件夹下的文件)进行一个排序,这样你就可以找出哪个 ...

随机推荐

  1. ActiveMQ+ZooKeeper搭建高可用集群

    一.说明 实际的应用中,一般为了应用的高可用性,都会搭建集群环境去处理.部署多台应用,这样,即使一台有问题,其他热备应用可以立马顶上,继续提供服务. ActiveMQ的集群部署,基于zookeeper ...

  2. BERT预训练模型的演进过程!(附代码)

    1. 什么是BERT BERT的全称是Bidirectional Encoder Representation from Transformers,是Google2018年提出的预训练模型,即双向Tr ...

  3. alpha测试和beta测试的区别

    alpha测试版,有点相当于内部测试,一般开发人员在场   ,是由用户做测试,但开发人员在场,一般是请用户到开发现场去测试  beta测试版,完全交给用户,由用户做测试,返回测试报告,相当于发行前的一 ...

  4. Wordpress SEO

    Wordpress SEO 安装插件 Baidu Sitemap Generator, 作者 柳城, 主要用于按照配置参数生成 sitemap.xml 网站地图. 设置路径 设置 => Baid ...

  5. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

  6. 读《深入理解Elasticsearch》点滴-查询评分

    计算文档得分的因子: 文档权重(document boost):索引期赋予某个文档的权重值 字段权重(field boost):查询期赋予某个文档的权重值 协调因子(coord):基于文档中词项个数的 ...

  7. Linux 查看端口状态netstat

    netstat命令参数: -t : 指明显示TCP端口 -u : 指明显示UDP端口 -l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序) -p ...

  8. Redis-->windows上的安装教程

    Windows下安装Redis服务 说明:本文拷贝自http://www.cnblogs.com/jaign/articles/7920588.html Redis是有名的NoSql数据库,一般Lin ...

  9. 激突要塞代码解阵算法+用C++/Python处理代码

    激突要塞的代码长度为6的倍数,其中每6个字符代表着一个单位,这六个字符中,第一位代表着单位的种类,后五位则包含着单位角度.X值.Y值的信息. 那么这个第一位究竟代表什么呢?一图以示之. 那么在代码中就 ...

  10. linux分析利刃之sar命令详解

    一.sar的概述 在我使用的众多linux分析工具中,sar是一个非常全面的一个分析工具,可以比较瑞士军刀,对文件的读写,系统调用的使用情况,磁盘IO,CPU相关使用情况,内存使用情况,进程活动等都可 ...