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;&nbsp;y1  First point of the first line.
    *   @param x2;&nbsp;y2  Second point of the first line and the first point of the second line.
    *   @param x3;&nbsp;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;&nbsp;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 + -
显示快捷键?