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, 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, 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, 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 + -
显示快捷键?