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,&nbsp;y1 One end point of this line. 
    *
    * @param x2,&nbsp;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,&nbsp;y1 One end point of this line. 
    *
    * @param x2,&nbsp;y2 The other end point of this line.
    *
    * @param centerX,&nbsp;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,&nbsp;acrossY The point that the line acrossed.
    *
    * @param centerX,&nbsp;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 + -
显示快捷键?