abstractrectangle.java
来自「用Java开发的、实现类似Visio功能的应用程序源码」· Java 代码 · 共 1,128 行 · 第 1/3 页
JAVA
1,128 行
* Get a node by vertex type.
*
* @param vertexType Vertex type of current node.
* @return A node of current rectangle.
*/
public Node getNodeByVertexType(int vertexType){
try{
switch(vertexType){
case Rect.VERTEXTYPE_LEFTTOP:
return (Node)m_nodeList.getByIndex(0);
case Rect.VERTEXTYPE_RIGHTTOP:
return (Node)m_nodeList.getByIndex(1);
case Rect.VERTEXTYPE_LEFTBOTTOM:
return (Node)m_nodeList.getByIndex(2);
case Rect.VERTEXTYPE_RIGHTBOTTOM:
return (Node)m_nodeList.getByIndex(3);
}
}catch(Exception e){
}
return null;
}
/**
* Get vertex type by a node.
*
* @param node A node of this rectangle.
* @return the vertex type of this node.
*/
public int getVertexTypeByNode(Node node){
int vertexType = Rect.VERTEXTYPE_LEFTTOP;
if (node!=null)
if (node.equals(getNodeByVertexType(Rect.VERTEXTYPE_LEFTTOP)))
vertexType =Rect.VERTEXTYPE_LEFTTOP;
else if (node.equals(getNodeByVertexType(Rect.VERTEXTYPE_RIGHTTOP)))
vertexType =Rect.VERTEXTYPE_RIGHTTOP;
else if (node.equals(getNodeByVertexType(Rect.VERTEXTYPE_LEFTBOTTOM)))
vertexType =Rect.VERTEXTYPE_LEFTBOTTOM;
else if (node.equals(getNodeByVertexType(Rect.VERTEXTYPE_RIGHTBOTTOM)))
vertexType =Rect.VERTEXTYPE_RIGHTBOTTOM;
return vertexType;
}
/**
* 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);
}
}
/**
* 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 rectanglue has been drew.
* @return True when complete, false otherwise.
*
*/
public boolean ifCompleteDrawing(){
//two nodes added will decide a rectangle.
return (m_nodeAdded==2);
}
/**
* Finish drawing object.
*
*/
public boolean finishDrawing(){
initNodes();
initPorts();
initLabel();
return true;
}
/**
* Draw current object on graphic canvas.
*
* @param g A graphic canvas.
* @param isXorMode If is in xor mode now.
*
*/
public void draw(Graphics g,boolean isXorMode){
if (g==null)
return;
//if user hide this shape, we'll draw an 'invisible' bounds here.
if (isInvisible()){
drawInvisibleBounds(g,isXorMode);
return;
}
if (!isXorMode)
setTransparencyComposite(g);
double zoom =getZoomScale();
GeneralPath path= new GeneralPath(GeneralPath.WIND_EVEN_ODD);
LineSeg left =m_rect.getSide(Rect.SIDETYPE_LEFT);
LineSeg top =m_rect.getSide(Rect.SIDETYPE_TOP);
LineSeg right =m_rect.getSide(Rect.SIDETYPE_RIGHT);
LineSeg bottom =m_rect.getSide(Rect.SIDETYPE_BOTTOM);
path.moveTo((float)(left.getX1()*zoom), (float)(left.getY1()*zoom));
path.lineTo((float)(left.getX2()*zoom), (float)(left.getY2()*zoom));
path.lineTo((float)(top.getX2()*zoom),( float)(top.getY2()*zoom));
path.lineTo((float)(right.getX2()*zoom),(float)(right.getY2()*zoom));
path.lineTo((float)(bottom.getX2()*zoom),(float)(bottom.getY2()*zoom));
path.closePath();
if (!isXorMode){
Rect rect =getBounds();
rect.setValue(rect.getX() * zoom, rect.getY() * zoom, rect.getWidth() * zoom, rect.getHeight() * zoom);
m_fillFormat.draw(g,path,rect);
m_lineFormat.draw(g,path);
}else{
Graphics2D g2=(Graphics2D)g;
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.black);
g2.draw(path);
}
if (!isXorMode)
restoreTransparencyComposite(g);
if (!isXorMode){
drawPort(g);
drawLabel(g);
}
}
/**
* 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{
//we use intersects but not contains here, for an accurate pick.
return m_rect.intersects(pnt,GeomConst.PICK_OFFSET) || m_rect.contains(pnt);
}
}
/**
* 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_rect.intersects(rect);
}
}
/**
* Add a new port to this shape.
* @param x,y Current picking position.
*
*/
public Port addPort(double x,double y){
JFPoint startPoint =new JFPoint();
JFPoint endPoint =new JFPoint();
JFPoint portPoint =new JFPoint();
if (!m_rect.canAddPort(x,y,startPoint,endPoint,portPoint))
return null;
Port newPort=m_portList.addPort(new Port(this,Port.PORTTYPE_CUSTOM,startPoint,endPoint,portPoint));
m_portList.setZoomScale(getZoomScale());
return newPort;
}
/**
* When moving a node, in some cases, e.g. ctrl key or shift key pressed to force preserving
* the form of a shape, or force equilateral shapes, we need to recalculate the actual moving
* node's position.
*
* @param movePos Desire moving position of a node.
* @param moveCase Move case of a node, normal, shift key pressed or ctrl key pressed
* @return The actual moving position of a node.
*
*/
public JFPoint getMoveNodePos(Node node,JFPoint movePos,int moveCase){
if (node==null || movePos==null)
return null;
switch (moveCase){
case ShapeConst.MOVEMENT_NORMAL:
return movePos;
case ShapeConst.MOVEMENT_SHIFTDOWN:
case ShapeConst.MOVEMENT_CTRLDOWN:
int vertexType =getVertexTypeByNode(node);
JFPoint base,neibor1,neibor2;
//get the base vertex(peer point of current vertex),and other two neibor vertexes.
switch (vertexType){
case Rect.VERTEXTYPE_LEFTTOP:
base =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTBOTTOM);
neibor1 =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTTOP);
neibor2 =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTBOTTOM);
break;
case Rect.VERTEXTYPE_RIGHTBOTTOM:
base =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTTOP);
neibor1 =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTTOP);
neibor2 =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTBOTTOM);
break;
case Rect.VERTEXTYPE_RIGHTTOP:
base =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTBOTTOM);
neibor1 =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTTOP);
neibor2 =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTBOTTOM);
break;
case Rect.VERTEXTYPE_LEFTBOTTOM:
base =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTTOP);
neibor1 =m_rect.getVertex(m_rect.VERTEXTYPE_LEFTTOP);
neibor2 =m_rect.getVertex(m_rect.VERTEXTYPE_RIGHTBOTTOM);
break;
default:
return movePos;
}
//two new neibors(upright feet) generated by move pos.
LineSeg line =new LineSeg();
line.setValue(base,neibor1);
JFPoint newNeibor1 =line.uprightFoot(movePos.getX(),movePos.getY());
double slope1 =line.getSlope();
line.setValue(base,neibor2);
JFPoint newNeibor2 =line.uprightFoot(movePos.getX(),movePos.getY());
double slope2 =line.getSlope();
//distances from base to neibors.
double distance1 =base.distance(newNeibor1);
double distance2 =base.distance(newNeibor2);
//generate new moving pos by base,newNeibor1 and newNeibor2
JFPoint newMovePos;
boolean direction;
if (distance1>distance2){
direction =JFVector.underClockwiseSide(newNeibor1,movePos,newNeibor1,newNeibor2);
newMovePos =newNeibor1.nearPoint(slope2,distance1,newNeibor2,direction);
//newNeibor2 =base.nearPoint(newNeibor2,distance1);
}else{
direction =JFVector.underClockwiseSide(newNeibor2,movePos,newNeibor2,newNeibor1);
newMovePos =newNeibor2.nearPoint(slope1,distance2,newNeibor1,direction);
//newNeibor1 =base.nearPoint(newNeibor1,distance2);
}
return newMovePos;
}
return movePos;
}
protected Rect m_originalRect;
/**
* Start move a node.
*
* @param node The node will be moved.
*
*/
public void startMoveNode(Node node){
m_originalRect =new Rect(m_rect);
startMoveLabel();
}
/**
* finish move/adjust a node of current object.
*
* @param node Currently moving node.
*
* @param x, y Moving offsets.
*
* @param g current drawing canvas.
*
*/
public void finishMoveNode(Node node, double x, double y,Graphics g){
finishMoveLabel();
m_portList.movePort(m_originalRect.getVertex(Rect.VERTEXTYPE_LEFTTOP),m_originalRect.getVertex(Rect.VERTEXTYPE_RIGHTTOP),
m_rect.getVertex(Rect.VERTEXTYPE_LEFTTOP),m_rect.getVertex(Rect.VERTEXTYPE_RIGHTTOP));
m_portList.movePort(m_originalRect.getVertex(Rect.VERTEXTYPE_RIGHTTOP),m_originalRect.getVertex(Rect.VERTEXTYPE_RIGHTBOTTOM),
m_rect.getVertex(Rect.VERTEXTYPE_RIGHTTOP),m_rect.getVertex(Rect.VERTEXTYPE_RIGHTBOTTOM));
m_portList.movePort(m_originalRect.getVertex(Rect.VERTEXTYPE_RIGHTBOTTOM),m_originalRect.getVertex(Rect.VERTEXTYPE_LEFTBOTTOM),
m_rect.getVertex(Rect.VERTEXTYPE_RIGHTBOTTOM),m_rect.getVertex(Rect.VERTEXTYPE_LEFTBOTTOM));
m_portList.movePort(m_originalRect.getVertex(Rect.VERTEXTYPE_LEFTBOTTOM),m_originalRect.getVertex(Rect.VERTEXTYPE_LEFTTOP),
m_rect.getVertex(Rect.VERTEXTYPE_LEFTBOTTOM),m_rect.getVertex(Rect.VERTEXTYPE_LEFTTOP));
}
/**
* Move/adjust a node of current object.
*
* @param node Currently moving node.
*
* @param x, y Moving offsets.
*
* @param g current drawing canvas.
*
*/
public void moveNode(Node node, double x, double y,Graphics g){
if (node!=null){
if (node.getXOffset()==x && node.getYOffset()==y){
//only eliminate old dragging shape here
draw(g,true);
}
else{
//processing issues by sub-classes
}
}
}
/**
* 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.
*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?