polyline.java
来自「用Java开发的、实现类似Visio功能的应用程序源码」· Java 代码 · 共 1,251 行 · 第 1/3 页
JAVA
1,251 行
/**
* $Id:PolyLine.java $
*
* Copyright 2004 ~ 2005 JingFei International Cooperation LTD. All rights reserved. *
*/
package com.jfimagine.jfgraph.geom;
import java.awt.Graphics;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import com.jfimagine.jfgraph.geom.JFPoint;
import com.jfimagine.jfgraph.geom.JFPointNode;
import com.jfimagine.jfgraph.geom.LineSeg;
import com.jfimagine.jfgraph.geom.GeomConst;
/**
* A PolyLine class used to represents a continuous arbitrary line segments collection.
*
* <p> Attention: Here we used a clockwise quadrant system.
* And the first quadrant is under right bottom corner.
*
* @author CookieMaker
*
* @version $Revision: 1.00 $
*/
public class PolyLine implements Cloneable {
/**
* Minimum line segment(MIN_LINELENGTH_SEGMENT) that can be divided into four slips. It's not equal as MIN_LINELENGTH,
* that's a length that don't need to be divided, so it(MIN_LINELENGTH)) is a very small pixel numbers than MIN_LINELENGTH_SEGMENT.
*/
private static final int MIN_LINELENGTH_SEGMENT=30;
/** An open polyline*/
public static final int POLYLINE_OPEN =0;
/** An closed polyline, it's really a polygon*/
public static final int POLYLINE_CLOSED =1;
/**
* A point node list for constructing a whole polyline.
*/
private List m_nodeList =new ArrayList();
/**
* If this polyline is open polyline or closed polygon.
*/
private int m_polyState =POLYLINE_OPEN;
/**
* If this polyline is actually a polygon.
* @return True if a polygon, false polyline.
*/
public boolean isPolygon(){
return m_polyState==POLYLINE_CLOSED;
}
/**
* Get point node list
*
* @return The point node list.
*
*/
public List getNodeList(){
return m_nodeList;
}
/**
* Set point node list
*
* @param val A new point node list.
*
*/
public void setNodeList(List nodeList){
clearNodes();
for (int i=0; i<nodeList.size(); i++){
try{
Object obj =nodeList.get(i);
if (obj!=null && obj instanceof JFPointNode)
m_nodeList.add(new JFPointNode((JFPointNode)obj));
}catch(Exception e){
}
}
}
/**
* Set point node list
*
* @param xpoints an array of x coordinates
* @param ypoints an array of y coordinates
* @param npoints the total number of points in the Polygon
*
*/
public void setNodeList(int[] xpoints, int[] ypoints, int npoints){
clearNodes();
double x,y;
for (int i=0; i<npoints; i++){
if (xpoints.length<i+1)
break;
if (ypoints.length<i+1)
break;
x =xpoints[i];
y =ypoints[i];
addNode(x,y);
}
}
/**
* Clear all nodes of this polyline.
*/
public void clearNodes(){
m_nodeList =new ArrayList();
}
/**
* Get node count of polyline.
* @return node count.
*/
public int getNodeCount(){
return m_nodeList.size();
}
/**
* Get end node count of polyline.
* @return End node count.
*/
public int getEndNodeCount(){
int cnt=0;
Iterator it =m_nodeList.iterator();
while (it!=null && it.hasNext()){
JFPointNode node =(JFPointNode)it.next();
if (node.getNodeType()==JFPointNode.NODETYPE_END)
cnt++;
}
return cnt;
}
/**
* Get a specified node of this polyline.
* @param nodeIndex A node index.
* @return the specified node.
*/
public JFPointNode getNode(int nodeIndex){
int size= m_nodeList.size();
if (nodeIndex<0 || nodeIndex>size-1)
return null;
else
try{
return (JFPointNode)m_nodeList.get(nodeIndex);
}catch(Exception e){
return null;
}
}
/**
* Get a node's index inside a node list.
* @param node A specified node to be found.
*/
public int getNodeIndex(JFPointNode node){
if (node==null)
return -1;
for (int i=0; i<m_nodeList.size(); i++){
try{
JFPointNode newNode =(JFPointNode)m_nodeList.get(i);
if (newNode.equals(node))
return i;
}catch(Exception e){
return -1;
}
}
return -1;
}
/**
* Remove a specified node.
* @param node A node in the node list to be removed.
*/
public void removeNode(JFPointNode node){
if (node==null)
return;
int ind =getNodeIndex(node);
removeNode(ind);
}
/**
* Remove a specified node.
* @param nodeIndex The index of specified node.
*/
public void removeNode(int nodeIndex){
if (nodeIndex<0 || nodeIndex >m_nodeList.size()-1)
return;
try{
m_nodeList.remove(nodeIndex);
}catch(Exception e){
}
}
/**
* Get last node of a polyline.
* @param reverse True if get last node of this node list, False get first.
* @return the last node.
*/
private JFPointNode getLastNode(boolean reverse){
if (reverse)
return getNode(m_nodeList.size()-1);
else
return getNode(0);
}
/**
* Get next node of a polyline.
* @param node The node to start finding.
* @param reverse False if get next node of this node, true if get prior node of this node.
* @return the next node.
*/
public JFPointNode getNextNode(JFPointNode node,boolean reverse){
if (node==null)
return null;
int nodeIndex =getNodeIndex(node);
return getNextNode(nodeIndex,reverse);
}
/**
* Get next node of a polyline.
* @param nodeIndex The node index to start finding.
* @param reverse False if get next node of this node, true if get prior node of this node.
* @return the next node.
*/
public JFPointNode getNextNode(int nodeIndex,boolean reverse){
JFPointNode ret=null;
if (reverse){
while (true){
nodeIndex--;
ret =getNode(nodeIndex);
if (ret==null){
if (isPolygon())
return getNode(m_nodeList.size()-2);
else
return null;
}else{
if (ret.getNodeType()==JFPointNode.NODETYPE_END)
return ret;
}
}
}else{
while (true){
nodeIndex++;
ret =getNode(nodeIndex);
if (ret==null){
if (isPolygon())
return getNode(0);
else
return null;
}else{
if (ret.getNodeType()==JFPointNode.NODETYPE_END)
return ret;
}
}
}
}
/**
* Finish drawing, and combine some nodes which are on same line.
*/
public void finishDrawing(){
List tempList =new ArrayList();
//move m_nodeList to tempList.
Iterator it =m_nodeList.iterator();
while (it!=null && it.hasNext()){
tempList.add(it.next());
}
//clear m_nodeList
clearNodes();
//re-add all nodes to m_nodeList
it =tempList.iterator();
JFPointNode node;
while (it!=null && it.hasNext()){
node =(JFPointNode)it.next();
if (node.getNodeType()==JFPointNode.NODETYPE_END)
addNode(node.getX(),node.getY());
}
//if node count is only 1, we will add a HELP node for construct a line.
JFPointNode lastNode;
int nodeCount =m_nodeList.size();
if (nodeCount==1){
lastNode =getLastNode(true);
m_nodeList.add(new JFPointNode(lastNode.getX()+GeomConst.MIN_LINELENGTH,lastNode.getY(),JFPointNode.NODETYPE_END));
}
if (isPolygon()){
//if node count is only 2, we will add a HELP node for construct a polygon.
nodeCount =m_nodeList.size();
if (nodeCount==2){
lastNode =getLastNode(true);
m_nodeList.add(new JFPointNode(lastNode.getX()-GeomConst.MIN_LINELENGTH/2,lastNode.getY()-GeomConst.MIN_LINELENGTH,JFPointNode.NODETYPE_END));
}else{
closePolygon();
}
}
}
/**
* Add a new node to polyline.
* @param node A new node.
*/
public void addNode(JFPointNode pnt){
if (pnt==null)
return;
addNode(pnt.getX(),pnt.getY());
}
/**
* Test if the line from x1,y1 to x2,y2 has a same slope of the line from x2,y2 to x3,y3
* @param x1; y1 First point of the first line.
* @param x2; y2 Second point of the first line and the first point of the second line.
* @param x3; y3 Second point of the second line.
*/
private boolean sameSlope(double x1, double y1, double x2, double y2, double x3, double y3){
JFPoint pnt =new JFPoint();
pnt.setValue(x2,y2);
double slope1 =pnt.getSlope(x1,y1);
double slope2 =pnt.getSlope(x3,y3);
//if minus of the two slope of less than 1/5 of the maximum slope, we consider that they're equal.
double minMinus =Math.max(Math.abs(slope1),Math.abs(slope2))/5;
if (minMinus<0.1) minMinus =0.1;
double MAXSLOPE =20;//set a max slope for vertical line.
if (Math.abs(slope1-slope2)<minMinus || (Math.abs(slope1)>MAXSLOPE && Math.abs(slope2)>MAXSLOPE))
return true;
else
return false;
}
/**
* Add a new node to polyline.
* @param x; y A new node.
*/
public void addNode(double x, double y){
JFPointNode lastNode =getLastNode(true);
if (lastNode==null){
m_nodeList.add(new JFPointNode(x,y,JFPointNode.NODETYPE_END));
return;
}
double distance =lastNode.distance(x,y);
if (distance<=GeomConst.MIN_LINELENGTH)
return;
JFPointNode lastSecNode =getNextNode(lastNode,true);
if (lastSecNode!=null){
if (sameSlope(lastSecNode.getX(),lastSecNode.getY(),lastNode.getX(),lastNode.getY(),x,y)){
cancelLastNode();
addNode(x,y);
return;
}
}
if (distance>=MIN_LINELENGTH_SEGMENT){
double midx =(x+lastNode.getX())/2;
double midy =(y+lastNode.getY())/2;
m_nodeList.add(new JFPointNode(midx,midy,JFPointNode.NODETYPE_MIDDLE));
}
m_nodeList.add(new JFPointNode(x,y,JFPointNode.NODETYPE_END));
}
/**
* close path for polygon
* @return true if can close, false otherwise.
*/
public boolean closePolygon(){
if (getEndNodeCount()<3)
return false;
m_polyState =POLYLINE_CLOSED;
//try to add a MID node between the first node and last node.
JFPointNode firstNode =getLastNode(false);
JFPointNode lastNode =getLastNode(true);
if (lastNode!=null && lastNode.getNodeType()==JFPointNode.NODETYPE_MIDDLE){
removeNode(m_nodeList.size()-1);
lastNode =getLastNode(true);
}
double distance =lastNode.distance(firstNode);
double midx =0;
double midy =0;
if (distance>=MIN_LINELENGTH_SEGMENT){
midx =(firstNode.getX()+lastNode.getX())/2;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?