📄 shapemaker.java
字号:
package com.zcsoft.graphics;
import java.awt.geom.*;
import java.awt.Shape;
import javax.swing.*;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.Point;
import com.zcsoft.graphics.line.ShapePane;
/*
* Title: 公用类
* Description: 为使用公司开发工具软件提供基础类
* Copyright: Copyright (c) 2001
* Company: 苏州至诚软件
* @author 蒋智湘
* @version 2.2
*/
/**
* 图形绘制器。
* 图形构造由方法<code>Shape makeShape(DoublePoint[])</code>实现。
* 该类的非抽象的子类必须实现该方法。如果子类除了绘制由上述方法构造的
* 图形外,还将绘制其他内容,如果文本等,则需要重新实现<code>void paint(Graphics2D)</code>。
*/
public abstract class ShapeMaker implements java.io.Serializable
{
/** 控制点 */
protected DoublePoint points[];
/** 图形所在区域 */
protected Rectangle range = new Rectangle(0,0,0,0);
/** 是否被选中 */
private transient boolean selected = false;
/** 选中的控制点之索引 */
private transient int pIndx = -1;
/** 控制点被选择时,选择框的边长 */
public static final int SIZE = 6;
/** 图形的绘制颜色 */
private java.awt.Color shapeColor;
/** 图形的名称 */
private String name;
/** 图形是否可以移动标记
* @since 2.0
*/
private boolean movable = true;
/** 绘制该图形的容器
* @since 2.0
*/
private ShapePane owner;
/** 背景颜色
* @since 2.0
*/
private java.awt.Color backgroud;
/** 是否可见
* @since 2.2
*/
private boolean visible = true;
/**
* 构造一个空的图形
*/
public ShapeMaker(){}
/**
* 构造一个空的图形,并指定绘制该图形的组件容器
*/
public ShapeMaker(ShapePane owner)
{
this.setOwner(owner);
}
/**
* 根据所给给定的控制点构造图形
*/
public ShapeMaker(DoublePoint p[])
{
this.points=p;
}
/**
* 绘制该图形。绘制由<code>getShape()</code>方法的图形。
* @see #getShape()
*/
public synchronized void paint(java.awt.Graphics2D g2)
{
Shape sp=getShape();
if(sp!=null)
{
java.awt.Color old=g2.getColor();
if(getShapeColor()!=null)
g2.setColor(getShapeColor());
g2.draw(sp);
g2.setColor(old);
}
}
/**
* 获取即将绘制的图形。
* 在由makeShape(DoublePoint[])返回的图形的基础上,
* 且当图形被选择的情形下,对图形中的控制点周围绘制一个大小为SIZE的矩形。
* @see #makeShape(DoublePoint[])
* @see #getCrypticPoints()
*/
protected Shape getShape()
{
DoublePoint ps[]=getCrypticPoints();
Shape s=makeShape(ps);
if(s==null)
return null;
if(isSelected())
{
GeneralPath p = new GeneralPath();
p.append(s,false);
if(ps!=null)
{
for (int i = 0; i < ps.length; i++)
{
double x=ps[i].getX() - SIZE/2;
double y=ps[i].getY() - SIZE/2;
p.append(new Rectangle2D.Double(x,y,SIZE,SIZE),false);
}
}
return p;
}
else
return s;
}
/**
* 根据控制点构造图形。
* @param p 控制点(如果存在对原始控制点的单位转换,则为转换后的控制点)
* @see #getCrypticPoints()
*/
protected abstract Shape makeShape(DoublePoint p[]);
/**
* 将指定的控制点置换成新的点
* @param indx 所要变更的点的索引。如果索引不存在,则忽略。
* @param newPoint 替换点。如果点的坐标不大于零,则忽略。
* @return 如果变更无效,则返回false,否则返回true。
*/
public boolean refreshPoint(int indx,DoublePoint newPoint)
{
DoublePoint ps[]=getPoints();
if(newPoint.getX()<=0.0||newPoint.getY()<=0.0||!check(indx,ps))
return false;
DoublePoint old=ps[indx];
this.points[indx]=newPoint;
if(indx<2&&ps.length>0&&!isTopLeft(0,1,SIZE))
{
this.points[indx]=old;
return false;
}
return true;
}
/**
* 将所有点移动某个偏移量
* @param offsetX X轴方法偏移量。
* @param offsetY Y轴方法偏移量。
* @param 如果允许偏移,则返回true,否则返回false。
* 默认情况下,偏移后的点如果超出边界,则返回false.
*/
public boolean translate(double offsetX,double offsetY)
{
DoublePoint old[]=this.getPoints();
if(old == null)
return false;
boolean out=false;
for(int i=0;i<points.length;i++)
{
this.points[i].translate(offsetX,offsetY);
if(!range.contains(points[i].getX(),points[i].getY()))
{
out=true;
break;
}
}
if(out)
{
setPoints(old);
return false;
}
return true;
}
/**
* 判断点<code>i</code>是否在点<code>j</code>的左上方向。
*/
protected boolean isTopLeft(int i,int j,double size)
{
DoublePoint ps[]=getCrypticPoints();
if(!check(i,ps)||!check(j,ps))
return false;
return ps[i].getX()+size<=ps[j].getX()&&ps[i].getY()+size<=ps[j].getY();
}
/**
* 判断该图形所在区域是否包含指定的点。
*
* @param p 基于整个图形所在坐标系上的点
* @see #setRange(Rectangle)
* @see #getRange();
*/
public boolean contains(java.awt.Point p)
{
return p != null && this.range.contains(p);
}
/**
* 找到指定点下的控制点索引
* @param p
* @return -1表示未找到
*/
public int findControlPointUnder(Point p)
{
int index = -1;
DoublePoint[] points = this.points;
if (points != null)
{
for (int i = points.length - 1; i >= 0; i--)
{
if ( overlap(points[i], p) )
{
index = i;
break;
}
}
}
return index;
}
/**
* 判断控制点A是否可以被认为同坐标点b重合
* 如果点b落在以a为中心,SIZE(缺省值为6)为边长为正方形内,则认为时重合的。
* 如果a或b为null,则不认为a同b是重合的。
* @param a
* @param b
* @return
*/
public boolean overlap(DoublePoint a, Point b)
{
if (a == null || b == null)
{
return false;
}
double x = a.getX() - (SIZE >> 1);
double y = a.getY() - (SIZE >> 1);
return b.x >= x && b.y >= y && b.x < x + SIZE && b.y < y + SIZE;
}
/**
* 判断指定控制点是否与给定的点重合。
* @param indx 遍历判断时的控制点索引。
* @param p 给定的点
*/
public boolean superPosition(int indx, java.awt.Point p)
{
DoublePoint ps[] = getCrypticPoints();
if(!check(indx, ps) || ps[indx] == null)
return false;
return overlap(ps[indx], p);
}
/**
* 设置该图形是否被选中
*/
public final void setSelected(boolean yes)
{
boolean old = this.selected;
this.selected = yes;
if(!yes)
{
pIndx = -1;
}
if (old != yes)
{
repaint();
}
}
private void repaint()
{
if ( this.getOwner() != null )
{
this.getOwner().repaint(this.range);
}
}
/**
* 设置选中的控制点。
*/
public void setSelectedPoint(int indx)
{
int oldIndx = this.pIndx;
this.pIndx = indx;
if (indx >= 0)
{
this.selected = true;
}
if (oldIndx != indx)
{
this.repaint();
}
}
/**
* 获取选中的控制点。如果图形没有被选中则返回-1.
*/
public int getSelectedPoint()
{
return this.pIndx;
}
/**
* 判断图形是否被选中
*/
public boolean isSelected()
{
return selected;
}
/**
* 设置控制点
* @param newPoints 新的控制点序列
*/
public void setPoints(DoublePoint[] newPoints)
{
this.points = newPoints;
}
/**
* 获取“加密”后的点。
* 在根据实际的控制点进行绘制时,有时需要对这些控制点的进行某种转化。
* 该方法就是获得转化后的控制点值,以防止破坏用户传递过来的控制点的实际值。
* @see #getPoints()
*/
protected DoublePoint[] getCrypticPoints()
{
return getPoints();
}
/**
* 获取实际控制点的拷贝。
*/
public DoublePoint[] getPoints()
{
return copyPoints(this.points);
}
/**
* 获取对指定点的拷贝
* @param p 要被复制的点序列。
*/
protected DoublePoint[] copyPoints(DoublePoint p[])
{
if(p==null)
return null;
DoublePoint[] ps=new DoublePoint[p.length];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -