ellipse.java
来自「用Java开发的、实现类似Visio功能的应用程序源码」· Java 代码 · 共 877 行 · 第 1/2 页
JAVA
877 行
/**
* $Id:Ellipse.java $
*
* Copyright 2004 ~ 2005 JingFei International Cooperation LTD. All rights reserved. *
*/
package com.jfimagine.jfgraph.geom;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import com.jfimagine.jfgraph.geom.LineSeg;
import com.jfimagine.jfgraph.geom.Angle;
import com.jfimagine.jfgraph.geom.Rect;
import com.jfimagine.jfgraph.geom.Curve;
import com.jfimagine.jfgraph.geom.JFEllipsePoint;
import com.jfimagine.jfgraph.geom.JFCurvePoint;
import com.jfimagine.jfgraph.geom.JFPoint;
/**
* Ellipse class. A class used to represent an ellipse shape.
*
* <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 Ellipse extends Rect {
/** a horizontal ellipse, length=2a and height =2b */
public static final int ELLIPSE_HORIZONTAL =1;
/** a vertical ellipse, length=2b and height =2a */
public static final int ELLIPSE_VERTICAL =2;
/** a circle, a=b */
public static final int ELLIPSE_CIRCLE =3;
/*
* Constructor for this ellipse.
*/
public Ellipse(){
}
/*
* Constructor for this ellipse.
* @param e An ellipse to be clone.
*/
public Ellipse(Ellipse e){
setValue(e);
}
/*
* get the length of top side.
*
* @return The length of top side.
*/
private double getTopLen(){
return m_leftTop.distance(m_rightTop);
}
/*
* get the length of left side.
*
* @return The length of left side.
*/
private double getLeftLen(){
return m_leftTop.distance(m_leftBottom);
}
/*
* get the length of semimajor axis.
*
* @return The length of semimajor axis. we call it as 'a'.
*/
public double getSemimajor(){
switch (getType()){
case ELLIPSE_HORIZONTAL:
return getTopLen()/2;
default:
return getLeftLen()/2;
}
}
/*
* get the length of semiminor axis.
*
* @return The length of semiminor axis. we call it as 'b'.
*/
public double getSemiminor(){
switch (getType()){
case ELLIPSE_HORIZONTAL:
return getLeftLen()/2;
default:
return getTopLen()/2;
}
}
/* Get the type of this ellipse.
*
* @return The type, HORIZONTAL, VERTICAL or CIRCLE.
*/
public int getType(){
double a=getTopLen();
double b=getLeftLen();
if (a>b)
return ELLIPSE_HORIZONTAL;
else if (a<b)
return ELLIPSE_VERTICAL;
else
return ELLIPSE_CIRCLE;
}
/*
* get distance from center to one focus of ellipse.
*
* @return The distance. we call it as 'c'.
*/
public double getFocusOffset(){
//semimajor.
double a =getSemimajor();;
//semiminor.
double b =getSemiminor();
//distance from center to one focus of ellipse.
return Math.sqrt(a*a-b*b);
}
/*
* get first focus of this ellipse.
*
* @return The first focus.
*/
public JFPoint getFirstFocus(){
return getFocus(1);
}
/*
* get second focus of this ellipse.
*
* @return The second focus.
*/
public JFPoint getSecondFocus(){
return getFocus(2);
}
/*
* get a focus of this ellipse.
*
* @param focusId The focus id, 1 or 2.
*
* @return The specified focus.
*/
private JFPoint getFocus(int focusId){
double c =getFocusOffset();//distance from center to one focus of ellipse.
JFPoint center =getCenter();
switch (focusId){
case 1:
switch (getType()){
case ELLIPSE_HORIZONTAL:
JFPoint left =m_leftTop.midPoint(m_leftBottom);
return center.nearPoint(left,c);
default:
JFPoint top =m_leftTop.midPoint(m_rightTop);
return center.nearPoint(top,c);
}
case 2:
switch (getType()){
case ELLIPSE_HORIZONTAL:
JFPoint right =m_rightTop.midPoint(m_rightBottom);
return center.nearPoint(right,c);
default:
JFPoint bottom =m_leftBottom.midPoint(m_rightBottom);
return center.nearPoint(bottom,c);
}
}
return null;
}
/*
* get rotate angle of this ellipse.
*
* @return The angle.
*/
public double getAngle(){
return Angle.getAngle(m_leftTop,m_rightTop,false);
}
/*
* get valid points which is on the specified line segment.
*
* @param pntList Points list.
*
* @param x1, y1 One end point of this line.
*
* @param x2, y2 The other end point of this line.
*
* @return A list of valid points.
*/
private static List pointsOnLine(List pntList,double x1, double y1, double x2, double y2){
if (pntList==null || pntList.size()==0)
return pntList;
List ret =new ArrayList();
//test if these points are actually on the line segment from x1,y1 to x2,y2
LineSeg line =new LineSeg(x1,y1,x2,y2);
Iterator it =pntList.iterator();
while (it!=null && it.hasNext()){
JFPoint pnt =(JFPoint)it.next();
if (line.contains(pnt)){
ret.add(pnt);
}
}
return ret;
}
/*
* get points intersected between a line and a circle.
*
* @param slope The slope of this line.
*
* @param across The point that the line acrossed.
*
* @param center The center of the circle.
*
* @param radius The radius of the circle.
*
* @return A list of points that the line intersect with the circle.
*/
public static List pointsIntersected(double slope, JFPoint across, JFPoint center, double radius){
if (across==null || center==null)
return new ArrayList();
else
return pointsIntersected(slope,across.getX(),across.getY(),center.getX(),center.getY(),radius);
}
/*
* get points intersected between a line segment and a circle.
*
* @param x1, y1 One end point of this line.
*
* @param x2, y2 The other end point of this line.
*
* @param centerX, centerY The center of the circle.
*
* @param radius The radius of the circle.
*
* @return A list of points that the line intersect with the circle.
*/
public static List pointsIntersected(double x1, double y1, double x2, double y2,double centerX, double centerY, double radius){
double slope=0;
if ((float)x1==(float)x2)
slope =GeomConst.LARGE_VALUE;
else
slope =(y2-y1)/(x2-x1);
//get the points intersected between the line that from x1,y1 to x2,y2(including its extended line) and the circle.
List pntList =pointsIntersected(slope,x1,y1,centerX,centerY,radius);
return pointsOnLine(pntList,x1,y1,x2,y2);
}
/*
* get points intersected between a line and a circle.
*
* @param slope The slope of this line.
*
* @param acrossX, acrossY The point that the line acrossed.
*
* @param centerX, centerY The center of the circle.
*
* @param radius The radius of the circle.
*
* @return A list of points that the line intersect with the circle.
*/
public static List pointsIntersected(double slope, double acrossX,double acrossY,double centerX, double centerY, double radius){
List ret=new ArrayList();
double x=0,y=0;
//for a line with a slope k and a crossed point x1,y1, will have equation below.
//y=k(x-x1)+y1
//for a circle with center point x0,y0 and a radius r, will have equation below.
//(y-y0)^2 + (x-x0)^2=r^2
//solve the two equations, and get a new equation like below.
//ax^2 + bx + c=0
//a=1+k^2
//b=-2 * k^2 * x1 + 2 * k * (y1-y0) - 2 * x0
//c= k^2 * x1^2-2*k*(y1-y0)*x1+(y1-y0)^2+x0^2-r^2
//there will be two special situations, the line is vertical or horizontal one.
//if line is vertical, then the x coordinates is decided,so
//y=y0 +/- sqrt(r ^ 2 -(x - x0) ^2)
//if line is horizontal, then the y coordinates is decided,so
//x=x0 +/- sqrt(r ^ 2 -(y - y0) ^2)
double k=slope;
double x1=acrossX;
double y1=acrossY;
double x0=centerX;
double y0=centerY;
double r=radius;
//vertical line.
if (k==GeomConst.LARGE_VALUE){
x =x1;
double radicand = r * r - (x - x0) * ( x -x0);
if (radicand<0)
return ret;
else if (radicand==0){
y =y0;
ret.add(new JFPoint(x,y));
return ret;
}
else if (radicand>0){
y =y0+Math.sqrt(radicand);
ret.add(new JFPoint(x,y));
y =y0-Math.sqrt(radicand);
ret.add(new JFPoint(x,y));
return ret;
}
//horizontal line.
}else if ((float)k==0){
y =y1;
double radicand = r * r - (y - y0) * ( y -y0);
if (radicand<0)
return ret;
else if (radicand==0){
x =x0;
ret.add(new JFPoint(x,y));
return ret;
}
else if (radicand>0){
x =x0+Math.sqrt(radicand);
ret.add(new JFPoint(x,y));
x =x0-Math.sqrt(radicand);
ret.add(new JFPoint(x,y));
return ret;
}
}
//arbitrary line process.
double a= 1 + k * k;
double b= -2 * (k * k) * x1 + 2 * k * (y1-y0) -2 * x0;
double c= (k * k) * (x1 * x1) - 2 * k * (y1 - y0) * x1 + (y1-y0)*(y1-y0) + x0 * x0 - r * r;
double delta=b * b - 4 * a * c;
if (delta<0)
return ret;
else if (delta==0){
x =-1 * b /(2*a);
y =k * (x-x1)+y1;
ret.add(new JFPoint(x,y));
return ret;
}else{
x =(-1 * b + Math.sqrt(delta)) /(2*a);
y =k * (x-x1)+y1;
ret.add(new JFPoint(x,y));
x =(-1 * b - Math.sqrt(delta)) /(2*a);
y =k * (x-x1)+y1;
ret.add(new JFPoint(x,y));
return ret;
}
}
/**
* Creates a new object of the same class and with the same contents as this object.
*
* @return A clone of this instance.
*
*/
public Object clone() throws CloneNotSupportedException{
try{
return new Ellipse(this);
}catch(Exception e){
throw new CloneNotSupportedException(e.getMessage());
}
}
/**
* sum of the two length of lines that from this point to two foci
* of ellipse
*
* @param x X coordinate of this point.
*
* @param y Y coordinate of this point.
*
* @return Sum of two length.
*
*/
private double getFociLen(double x, double y){
double a = getSemimajor();
JFPoint focus1 = getFirstFocus();
JFPoint focus2 = getSecondFocus();
if (focus1==null || focus2==null)
return 0;
else
return focus1.distance(x,y)+focus2.distance(x,y);
}
/**
* Test if a point(x, y coordinates for instead) is within this ellipse.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?