jflabelline.java

来自「用Java开发的、实现类似Visio功能的应用程序源码」· Java 代码 · 共 1,053 行 · 第 1/2 页

JAVA
1,053
字号
/**
 *    $Id:JFLabelLine.java $
 *
 *    Copyright 2004 ~ 2005  JingFei International Cooperation LTD. All rights reserved. *
 */
package com.jfimagine.jfgraph.shape.line;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import java.awt.Graphics;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.awt.BasicStroke;
import java.awt.geom.AffineTransform;

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

import com.jfimagine.jfdom.Document;
import com.jfimagine.jfdom.Element;

import com.jfimagine.jfgraph.shape.base.AbstractObject;
import com.jfimagine.jfgraph.shape.base.AbstractShape;
import com.jfimagine.jfgraph.shape.base.ShapeConst;
import com.jfimagine.jfgraph.shape.base.ObjectList;
import com.jfimagine.jfgraph.shape.base.JFVersion;
import com.jfimagine.jfgraph.shape.base.Node;

import com.jfimagine.jfgraph.shape.decorate.LineFormat;
import com.jfimagine.jfgraph.shape.decorate.Arrow;

import com.jfimagine.jfgraph.geom.JFPoint;
import com.jfimagine.jfgraph.geom.Angle;
import com.jfimagine.jfgraph.geom.JFVector;
import com.jfimagine.jfgraph.geom.Rect;
import com.jfimagine.jfgraph.geom.LabelLine;
import com.jfimagine.jfgraph.geom.GeomConst;
 
 
 /**
 * JFLabelLine class.  
 * A JFLabelLine class used to represent a line to describe the size of shapes.
 *
 * @author     CookieMaker    
 *
 * @version $Revision: 1.00 $
 */  
 public class JFLabelLine extends AbstractShape{

   /**
    *   A XML string tag represents a Line
    */
   public  static final String	 XML_LABELLINE		="LabelLine";

   /**  A XML string tag represents the x coordinate of start point */
   public  static final String   XML_STARTX		="startX";
   /**  A XML string tag represents the y coordinate of start point */
   public  static final String   XML_STARTY		="startY";
   /**  A XML string tag represents the x coordinate of end point */
   public  static final String   XML_ENDX		="endX";
   /**  A XML string tag represents the y coordinate of end point */
   public  static final String   XML_ENDY		="endY";

   /**  A XML string tag represents the ctrl1Direction */
   public  static final String   XML_CTRL1DIRECTION	="ctrl1Direction";
   /**  A XML string tag represents length of the line segment from control point1 to start point*/
   public  static final String   XML_CTRL1LEN		="ctrl1Len";
   /**  A XML string tag represents length of the line segment from control point2 to start point*/
   public  static final String   XML_CTRL2LEN		="ctrl2Len";
   /**  A XML string tag represents length of the line segment from control point3 to end point*/
   public  static final String   XML_CTRL3LEN		="ctrl3Len";
   /**  A XML string tag represents length of the line segment from control point4 to end point*/
   public  static final String   XML_CTRL4LEN		="ctrl4Len";



   /**
    *   arrow format of current line.
    */ 
   protected Arrow  m_arrow	=new Arrow();


   /**
    *   line format of current line.
    */ 
   protected LineFormat  m_lineFormat = new LineFormat();

   /**
    *   Internal LabelLine object.
    */ 
   protected LabelLine  m_labelLine = new LabelLine();

   /**
    *   first node settled while drawing.
    */
   protected JFPoint 	m_firstNode		=new JFPoint();

   /**
    *   while drawing rectangle, how many nodes have been decided. called by addnode method.
    */
   protected int	m_nodeAdded		=0;

   
   /**
    *   Constructor for label Line
    */
   public JFLabelLine(){
   	setObjectType(ShapeConst.SHAPETYPE_LABELLINE);
   	setXMLTag(XML_LABELLINE);
   }	

   /**
    *   Constructor for label Line
    *   @param x1,y1 start points for label line
    *   @param x2,y2 end points for label line
    */
   public JFLabelLine(double x1, double y1,double x2, double y2){
   	setObjectType(ShapeConst.SHAPETYPE_LABELLINE);
   	setXMLTag(XML_LABELLINE);
   	
   	addNode(x1,y1);
   	addNode(x2,y2);
   	finishDrawing();
   }

   
   /**
    *   Get the arrow format of current object.
    * 
    *   @return  The arrow format.
    *
    */ 	
   public Arrow getArrow(){
   	return m_arrow;
   }

   /**
    *   Set the arrow format of current object.
    *
    *   @param arrow  A new arrow format object.
    *
    */ 	
   public void setArrow(Arrow arrow){
   	m_arrow.setValue(arrow);
   }

   /**
    *   Get the line format of current line.
    * 
    *   @return  The line format.
    *
    */ 	
   public LineFormat getLineFormat(){
   	return m_lineFormat;
   }

   /**
    *   Set the line format of current line.
    *
    *   @param lineFormat A new line format.
    *
    */ 	
   public void setLineFormat(LineFormat lineFormat){
   	m_lineFormat	=lineFormat;
   }

   /**
    *   Init all nodes of this label line.
    */ 	
   private void initNodes(){
   	/*
   	 *  for label line, will always have six nodes, two for end points of line, other four
   	 *  for control points.
   	 */
   	while (m_nodeList.size()<6){
   		try{	m_nodeList.add(new Node());  }catch(Exception e){break;}
   	}
	
	try{	
       		Node destNode;	
       		
       		destNode	=(Node)m_nodeList.getByIndex(0);
       		destNode.setNodePoint(m_labelLine.getPoint1());
       		destNode.setParent(this);
       		
       		destNode	=(Node)m_nodeList.getByIndex(1);
       		destNode.setNodePoint(m_labelLine.getPoint2());
       		destNode.setParent(this);

       		destNode	=(Node)m_nodeList.getByIndex(2);
       		destNode.setNodePoint(m_labelLine.getCtrlPoint1());
       		destNode.setParent(this);
       		
       		destNode	=(Node)m_nodeList.getByIndex(3);
       		destNode.setNodePoint(m_labelLine.getCtrlPoint2());
       		destNode.setParent(this);

       		destNode	=(Node)m_nodeList.getByIndex(4);
       		destNode.setNodePoint(m_labelLine.getCtrlPoint3());
       		destNode.setParent(this);

       		destNode	=(Node)m_nodeList.getByIndex(5);
       		destNode.setNodePoint(m_labelLine.getCtrlPoint4());
       		destNode.setParent(this);

        	
	}catch(Exception e){
	}
	
	m_nodeList.setZoomScale(getZoomScale());
   }

   /**
    *   Get which node of current shape that intersects with point pnt.
    * 
    *   @param  pnt A JFPoint used to test intersection.
    *   @param  usage Purpose to get a node intersected, e.g. move or rotate. 
    *
    *   @return A node of current shape.
    *
    */ 	
   public Node  nodeIntersects(JFPoint pnt,int usage){
   	if (isInvisible()){
   		return null;
   	}
   	
   	
   	Node 	node=super.nodeIntersects(pnt,usage);
   	
   	//when under rotation sitation, the rotate node must be start or end node.
	if (node!=null && usage==Node.NODEUSAGE_ROTATE){
       		try{
       			Node startNode	=(Node)m_nodeList.getByIndex(0);
       			Node endNode	=(Node)m_nodeList.getByIndex(1);
       		
       			if (!node.equals(startNode) && !node.equals(endNode)){
       				return null;
       			}
       		}catch(Exception e){
       			return null;
       		}
	}   	
	return node;
   }

   /**
    *   Draw picked state of current object on graphic canvas.
    * 
    *   @param g A graphic canvas.
    *   @param ifRotate If user's operation or other actions force objects to be rotated.
    *
    */  	
  public void drawPicked(Graphics g, boolean ifRotate){ 
	//if this shape is invisible, so draw virtual nodes
	if (isInvisible()){
		initBoundsNodeList();
		m_boundsNodeList.draw(g,false);
		return;
	}  	

	
	((Graphics2D)g).setStroke(new BasicStroke(1));
  	
   	//A AbstractArc should always consisted by it's nodes.
   	ObjectList nodeList = getNodeList();
   	Node	node1;
   	//pick up each nodes,then draw them.
   	for (int i=0; i<nodeList.size(); i++){
		try{
			node1	=(Node)nodeList.getByIndex(i);   		
			node1.draw(g,ifRotate);
			//if under rotation situation, only two nodes: start node and end node will be drawn.
			if (i>=1 && ifRotate)
				break;
		}catch(Exception e){
			break; //slient break loop here.
		}
   	}
   }


   /**
    *   Get the rotate angle of current label line. 
    *   @return The rotate angle.
    *
    */ 	
   public double getRotateAngle(){
	JFPoint startPoint	=m_labelLine.getPoint1();
	JFPoint endPoint	=m_labelLine.getPoint2();
	JFPoint ctrlPoint	=m_labelLine.getCtrlPoint2();

	boolean clockwise	=JFVector.underClockwiseSide(endPoint,startPoint,ctrlPoint,startPoint);
	double angle=0;
	if (clockwise)
		angle	=Angle.getAngle(endPoint,startPoint,false);
	else	
		angle	=Angle.getAngle(startPoint,endPoint,false);

	//force the angle between -PI/2 to PI/2.	
	angle	=Angle.getValidAngle(angle);
	if (angle>Angle.PI*3/2)
		angle	=angle - Angle.PI * 2;
	else if (angle>Angle.PI/2)
		angle	=angle	-Angle.PI;


	return angle;
   }

   /**
    *   Set the intial position of this internal label.
    *
    */ 	
   protected void initLabel(){
   	m_label.setParent(this);   	
   	JFPoint center	=m_labelLine.getCenter();
   	center.setY(center.getY()- m_lineFormat.getLineWidth() - GeomConst.PICK_OFFSET * 2);
   	m_label.setLabelPoint(center);
   	m_label.setMovable(false);
   }
   
   /**
    *   Draw label of current shape.
    * 
    *   @param g A graphic canvas.
    *
    */  	
  public void drawLabel(Graphics g){
  	
  	initLabel();
  	
  	double zoom	=getZoomScale();
  	Graphics2D g2	=(Graphics2D)g;
  	g2.setColor(m_fontFormat.getFontColor());
  	
	double angle	=getRotateAngle();
  	
	AffineTransform origXform = g2.getTransform();
	AffineTransform newXform = (AffineTransform)(origXform.clone());
     		
	JFPoint	center	=m_labelLine.getCenter();
	int xRot = (int)(center.getX() * zoom);
	int yRot = (int)(center.getY() * zoom);
	newXform.rotate(angle, xRot, yRot);
	g2.setTransform(newXform);
  	m_label.draw(g2);
	g2.setTransform(origXform);
  }


   /**
    *   Add a new node for current node list.
    *   here this method will always be called by DrawState class or any drawing class.
    * 
    *   @param x,&nbsp;y Coordinates of a new node.
    *
    */ 	
   public void addNode(double x, double y){
   	//increase node added number.
   	m_nodeAdded++;
	if (m_nodeAdded>2) m_nodeAdded=2;
	   	
   	//for a rectangular shape, the first node is to decide the left-top vertex,
   	//and the second noe is the last node to decide the right-bottom vertex.
   	if (m_nodeAdded==1){
   		m_firstNode.setValue(x,y);
   	}else if (m_nodeAdded>1){
   		m_labelLine.setValue(m_firstNode.getX(),m_firstNode.getY(),x,y);
   		initNodes();
   	}
   }

   /**
    *   Remove last node added by addNode method.
    *   @return Last node that remained.
    *
    */ 	
   public Node removeLastNode(){
   	//for rectanglular shape, removeLastNode is same as remove all nodes.
   	m_nodeAdded=0;
   	return null;
   }   

   /**
    *   If a label line has been drew.
    *   @return True when complete, false otherwise.
    *
    */ 	
   public boolean ifCompleteDrawing(){
   	//two nodes added will decide a label line.
   	return (m_nodeAdded==2);
   }

   /**
    *   Finish drawing object.
    *
    */ 	
   public boolean finishDrawing(){
	m_arrow.setStartArrow(Arrow.ARROWTYPE_TRIANGLE);   	
	m_arrow.setEndArrow(Arrow.ARROWTYPE_TRIANGLE);   	
	initLabel();
   	return true;
   }
   

   /**
    *   Test if current object intersects with a specified point.
    * 
    *   @param  pnt A JFPoint used to test intersection.
    *
    */ 	
   public boolean  intersects(JFPoint pnt){ 
   	if (isInvisible())
   		return getBounds().contains(pnt);
   	else
   		return m_labelLine.contains(pnt,GeomConst.PICK_OFFSET);
   }
 	
   /**
    *   Test if current object intersects with a specified rectangle.
    * 
    *   @param  rect A Rect used to test intersection.
    *
    */ 	
   public boolean  intersects(Rect rect){  
   	if (isInvisible())     
   		return getBounds().intersects(rect);
   	else
   		return m_labelLine.intersects(rect);
   }

   /**
    *   Scale current object by specified points and scale percent.
    *   We only support a concurrent width-height scale here, suppose width as the length from
    *   basePoint to refPoint1, height as the length from basePoint to refPoint2, and 
    *   one scale percent acts on both width and height.
    *
    *   @param basePoint A base point that is unmovable.
    *   @param refPoint1 A 'width' reference point.
    *   @param refPoint2 A 'height' reference point.
    *   @param scale A reference scale percent.
    *
    */ 	
   public void scaleBy(JFPoint basePoint, JFPoint refPoint1, JFPoint refPoint2, double scale){
   	startMoveLabel();
	m_labelLine.scaleBy(basePoint,refPoint1,refPoint2,scale);   	
	initNodes();
   	finishMoveLabel();   	
   }

   /**
    *   Scale current object by a specified x and y scale.<br>
    *   This is a special scale method used to scale a shape in arbitrary x and y scale.<br>
    *   Please see AbstractShape.scaleBy for detailed description.
    *
    *   @param basePoint A base scale point for scaling reference.
    *   @param xScale  A scale percentage in x coordinate, default to 1.0
    *   @param yScale  A scale percentage in y coordinate, default to 1.0
    *
    */ 	
   public void scaleBy(JFPoint basePoint,double xScale, double yScale){
   	if (basePoint==null)
   		return;
   		
   	startMoveLabel();
	m_labelLine.scaleBy(basePoint.getX(),basePoint.getY(),xScale,yScale);
	initNodes();
   	finishMoveLabel();   	
  }


   /**
    *   Move current object by an x and y offset.
    * 
    *   @param  x,&nbsp;y Moving offsets.
    *
    */ 	
   public void  moveBy(double x, double y){
   	m_labelLine.moveBy(x,y);
   	initNodes();
   }

   /**
    *   Rotate this object by an angle theta.
    *
    *   @param theta A rotate angle.
    *
    */ 	
   public void rotateBy(double theta){
   	m_labelLine.rotateBy(theta);
   	initNodes();
   }

   /**
    *   Rotate current object by a specified point and an angle theta.
    *
    *   @param baseX,&nbsp;baseY A rotate center coordinates.
    *
    *   @param theta A rotate angle.
    *
    */ 	
   public void rotateBy(double baseX,double baseY, double theta){
   	m_labelLine.rotateBy(baseX,baseY,theta);
   	initNodes();
   }

   /**
    *   Mirror this object by a central x coordinate of this object. We make a left-right flip here.
    */ 	
   public void mirrorBy(){
   	m_labelLine.mirrorBy();
   	initNodes();
   }

   /**
    *   Mirror this object by a x coordinate. We make a left-right mirror here.
    *
    *   @param baseX  A mirror base x coordinate.
    *
    */ 	
   public void mirrorBy(double baseX){
   	m_labelLine.mirrorBy(baseX);
   	initNodes();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?