public class DrawHelper {
	
	private static DrawHelper instance = null;
	
	private RectF mRectF = null;
	private Path mPath = null;
	private Paint mPaint = null;

	public DrawHelper(){}

	public static synchronized DrawHelper getInstance()
	{
		if(instance == null){
			instance = new DrawHelper();
		}
		return instance;
	}
	
	private void initRectF()
	{
		if(null == mRectF)
			mRectF = new RectF();
	}
	
	private void initPath()
	{
		if(null == mPath)
		{
			mPath = new Path();
		}else{
			mPath.reset();
		}
	}
	
	private void initPaint()
	{
		if(null == mPaint)
		{
			mPaint = new Paint();
		}else{
			mPaint.reset();
		}
	}
	
	
	/**
	 *  得到一个随机颜色
	 * @return 随机颜色
	 */
	public int randomColor() {
	    Random random = new Random();
        int red = random.nextInt(256) ;
        int green = random.nextInt(256) ;
        int blue = random.nextInt(256);
        return Color.rgb(red, green, blue);
    }
	
	/**
	 * 通过透明度，算出对应颜色的浅色应当是什么效果
	 * @param color 颜色
	 * @param alpha 透明度
	 * @return 浅色
	 */
	public int getLightColor(int color,int alpha)
	{
		initPaint();
		mPaint.setColor(color);
		mPaint.setAlpha(alpha);
		return mPaint.getColor();
	}
	
	/**
	 * 得到深色
	 * @param color 颜色
	 * @return 深色
	 */
	public int getDarkerColor(int color){
	    float[] hsv = new float[3];
	    Color.colorToHSV(color, hsv);	   
	    hsv[1] = hsv[1] + 0.1f; 
	    hsv[2] = hsv[2] - 0.1f; 
	    int darkerColor = Color.HSVToColor(hsv);
	    return  darkerColor ;
	}	
	
	/**
	 * 得到单个字的高度
	 * @param paint 画笔
	 * @return 高度
	 */
	public float getPaintFontHeight(Paint paint)
	{
	     FontMetrics fm = paint.getFontMetrics();
	     return (float) Math.ceil(fm.descent - fm.ascent);
	}
	 
	/**
	 * 得到字符串的宽度
	 * @param paint 画笔
	 * @param str 字符串
	 * @return 宽度
	 */
	public float getTextWidth(Paint paint,String str)
	{
		if(str.length() == 0) return 0.0f;
		//float width = Math.abs(paint.measureText(str, 0, str.length()));		 
		return paint.measureText(str, 0, str.length());
	}
	
	/**
	 *  用于计算文字的竖直累加高度
	 * @param paint 画笔
	 * @param str   字符串
	 * @return 高度
	 */
	public float calcTextHeight(Paint paint,String str)
	{		
		if(str.length() == 0) return 0;
		return getPaintFontHeight(paint) * str.length();
	}
	
	/**
	 *  绘制旋转了指定角度的文字
	 * @param text	文字
	 * @param x		X坐标
	 * @param y		y坐标
	 * @param paint	画笔
	 * @param angle 角度
	 */
	public void drawRotateText(  String text , 
									float x ,float y,float angle,
									Canvas canvas,
									Paint paint 
									){	
		if("" == text|| text.length() == 0 ) return;
		
		if(angle != 0){
			canvas.rotate(angle, x, y); 
			//canvas.drawText(text, x, y, paint);
			drawText(canvas,paint,text,x,y);
			canvas.rotate(-1 * angle, x, y);
		}else{
			//canvas.drawText(text, x, y, paint);
			drawText(canvas,paint,text,x,y);
		}
	}			
	
	/**
	 * 绘制等腰三角形
	 * @param baseLine		底线长度
	 * @param baseLnCentX	底线中心点X坐标
	 * @param baseLnCentY	底线中心点Y坐标
	 * @param direction		三角形方向
	 * @param style			填充风格
	 * @param canvas		画布
	 * @param paint			画笔
	 */
	public void drawTrigangle(	float baseLine,
								float baseLnCentX,
								float baseLnCentY,
								XEnum.TriangleDirection direction,
								XEnum.TriangleStyle style,
								Canvas canvas,
								Paint paint)
	{
		 // 计算偏移量
		   int offset = (int)(baseLine / 2 * Math.tan(60 * Math.PI / 180));
		
		   initPath();		   
		   // 计算三角形3个顶点的坐标
	        switch (direction)
	        {
	            case UP: //向上

	            	mPath.moveTo(baseLnCentX- baseLine / 2 , baseLnCentY);
	            	mPath.lineTo(baseLnCentX + baseLine / 2,baseLnCentY);
	            	mPath.lineTo(baseLnCentX,baseLnCentY - offset);
	            	mPath.close();
	                break;
	            
	            case DOWN: //向下

	            	mPath.moveTo( baseLnCentX - baseLine / 2 , baseLnCentY);
	            	mPath.lineTo(baseLnCentX + baseLine / 2,baseLnCentY);
	            	mPath.lineTo(baseLnCentX,baseLnCentY + offset);
	            	mPath.close();

	                break;
	            case LEFT: //向左

	            	mPath.moveTo(baseLnCentX , baseLnCentY - baseLine / 2);
	            	mPath.lineTo(baseLnCentX , baseLnCentY + baseLine / 2);
	                mPath.lineTo(baseLnCentX - offset ,baseLnCentY);
	                mPath.close();

	                break;
	            case RIGHT: //向右
	        
	            	mPath.moveTo(baseLnCentX , baseLnCentY - baseLine / 2);
	                mPath.lineTo(baseLnCentX , baseLnCentY + baseLine / 2);
	                mPath.lineTo(baseLnCentX + offset ,baseLnCentY);
	                mPath.close();
	                break;
	        }
	  
	        
	        //三角形的填充风格
	        switch (style)
	        {
	            case OUTLINE : //空心
	                paint.setStyle(Paint.Style.STROKE);  
	                break;
	            case FILL : //FILL 
	               paint.setStyle(Paint.Style.FILL);  
	               break;
	        }
	        canvas.drawPath(mPath,paint);		
	        mPath.reset();
	}
	
	
	public PathEffect getDotLineStyle()
	{
		return( new DashPathEffect(new float[] { 2, 2, 2, 2}, 1));  
	}
	
	public PathEffect getDashLineStyle()
	{
		//虚实线
		return(new DashPathEffect(new float[] { 4, 8, 5, 10}, 1));
	}
	
	
	/**
	 * 绘制点
	 * @param startX	起始点X坐标
	 * @param startY	起始点Y坐标
	 * @param stopX		终止点X坐标
	 * @param stopY		终止点Y坐标
	 * @param canvas	画布
	 * @param paint		画笔
	 */
	public void drawDotLine(float startX,float startY,
			 float stopX,float stopY,							 
			 Canvas canvas,
			 Paint paint)
	{
		//PathEffect effects = new DashPathEffect(new float[] { 2, 2, 2, 2}, 1);  
		paint.setPathEffect(getDotLineStyle());  
		canvas.drawLine(startX, startY, stopX, stopY, paint); 
		paint.setPathEffect(null);
	}
	
	/**
	 * 绘制虚实线
	 * @param startX	起始点X坐标
	 * @param startY	起始点Y坐标
	 * @param stopX		终止点X坐标
	 * @param stopY		终止点Y坐标
	 * @param canvas	画布
	 * @param paint		画笔
	 */
	public void drawDashLine(float startX,float startY,
							 float stopX,float stopY,							 
							 Canvas canvas,
							 Paint paint)
	{
		//虚实线
		//PathEffect effects = new DashPathEffect(new float[] { 4, 8, 5, 10}, 1);  
		paint.setPathEffect(getDashLineStyle());  
		canvas.drawLine(startX, startY, stopX, stopY, paint);  
		paint.setPathEffect(null);
	}
	
	
	//下次应当做的:虚实线 比例的灵活定制,线的阴影渲染
	public void drawLine(XEnum.LineStyle style,
				float startX,float startY,
				float stopX,float stopY,			 
				Canvas canvas,
				Paint paint
			 	)
	{
		
		switch(style)
		{
		case SOLID:		
			canvas.drawLine(startX, startY, stopX, stopY, paint); 
			break;
		case DOT:
			drawDotLine(startX, startY, stopX, stopY, canvas,paint); 
			break;
		case DASH:		
			//虚实线 	
			drawDashLine(startX, startY, stopX, stopY, canvas,paint); 
			break;
		}		
	}
	
	/**
	 * 绘制图中显示所占比例 的扇区
	 * @param paintArc	画笔
	 * @param cirX	x坐标
	 * @param cirY	y坐标
	 * @param radius	半径
	 * @param startAngle	偏移角度
	 * @param sweepAngle	当前角度
	 * @throws Exception	例外
	 */
	public void drawPercent(Canvas canvas, Paint paintArc,
			final float cirX,
			final float cirY,
			final float radius,
			final float startAngle,
			final float sweepAngle,boolean useCenter) throws Exception
	{
		try{				
	        initRectF();
	        mRectF.left =  cirX - radius;  
	        mRectF.top =  cirY - radius ;  
	        mRectF.right  = cirX  +  radius ;  
	        mRectF.bottom  = cirY +  radius ;  	        			
			//在饼图中显示所占比例  
			canvas.drawArc(mRectF, startAngle, sweepAngle, useCenter, paintArc);	
			mRectF.setEmpty();
		}catch( Exception e){
			throw e;
		}
	}
	
	public void drawPathArc(Canvas canvas, Paint paintArc,
			final float cirX,
			final float cirY,
			final float radius,
			final float startAngle,
			final float sweepAngle) throws Exception
	{
		try{		
	        initRectF();
	        mRectF.left =  cirX - radius;  
	        mRectF.top =  cirY - radius ;  
	        mRectF.right  = cirX  +  radius ;  
	        mRectF.bottom  = cirY +  radius ;  			
			//弧形			 
			 initPath();			 
			 mPath.addArc(mRectF,startAngle, sweepAngle); 
			 canvas.drawPath(mPath, paintArc);	
			 mRectF.setEmpty();
			 mPath.reset();
		}catch( Exception e){
			throw e;
		}
	}	
	 	
	//绘制有换行的文本
	public float drawText(Canvas canvas,Paint paint,String text,float x,float y)
	{
		if(text.length() > 0 )
		{					
			 if( text.indexOf("\n") > 0 ){
				 float height = getPaintFontHeight(paint);	
	 			 String[] arr = text.split("\n");
	 			 for(int i=0;i<arr.length;i++){
	 				canvas.drawText(arr[i],x , y, paint);
	 				y += height;
	 			 }
			 }else{
				 canvas.drawText(text,x , y, paint);
			 }		
		}
		 return y;
	}
} public class MathHelper {

	private static MathHelper instance = null;
	
	//Position位置
	private float mPosX = 0.0f;
	private float mPosY = 0.0f;
	private PointF mPointF = new PointF();
	
	//除法运算精度
	private static final int DEFAULT_DIV_SCALE = 10;
	
	//
	private boolean mHighPrecision = true;

	public MathHelper()
	{	
	}
	
	public static synchronized MathHelper getInstance()
	{
		 if(instance == null)
		 {
			 instance = new MathHelper();
		 }
		 return instance;
	}
		
	private void resetEndPointXY()
	{
		mPosX = mPosY = 0.0f;
		mPointF.x = mPosX;
		mPointF.y = mPosY;
	}	
	
	//依圆心坐标，半径，扇形角度，计算出扇形终射线与圆弧交叉点的xy坐标	
	public PointF calcArcEndPointXY(float cirX, 
									float cirY, 
									float radius, 
									float cirAngle)
	{	
		resetEndPointXY();		
		if( Float.compare(cirAngle, 0.0f) == 0 || 
			Float.compare(radius, 0.0f) == 0   )
		{
			 return mPointF;		
		}
		
			
		//将角度转换为弧度		
	    float arcAngle = (float) (Math.PI *  div(cirAngle , 180.0f));
	    if( Float.compare(arcAngle,0.0f) == -1)mPosX = mPosY = 0.0f;	
	    
	    if (Float.compare(cirAngle , 90.0f) == -1)
	    {	    		    
	    	mPosX = add(cirX , (float)Math.cos(arcAngle) * radius);
	        mPosY = add(cirY , (float)Math.sin(arcAngle) * radius) ;
	    }
	    else if (Float.compare(cirAngle,90.0f) == 0)
	    {
	        mPosX = cirX;
	        mPosY = add(cirY , radius);
	    }
	    else if (Float.compare(cirAngle,90.0f) == 1 &&
	    		 Float.compare(cirAngle,180.0f) == -1)
	    {
	    	arcAngle = (float) (Math.PI * (sub(180f , cirAngle)) / 180.0f);	 	    		    		    		    
	        mPosX = sub(cirX , (float) (Math.cos(arcAngle) * radius));
	        mPosY = add(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    else if (Float.compare(cirAngle,180.0f) == 0)
	    {
	        mPosX = cirX - radius;
	        mPosY = cirY;
	    }
	    else if (Float.compare(cirAngle,180.0f) == 1 &&
	    		 Float.compare(cirAngle,270.0f) == -1) 
	    {
	    	arcAngle = (float) (Math.PI * ( sub(cirAngle , 180.0f)) / 180.0f);
	        mPosX = sub(cirX , (float) (Math.cos(arcAngle) * radius));
	        mPosY = sub(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    else if (Float.compare(cirAngle,270.0f) == 0)
	    {
	        mPosX = cirX;
	        mPosY = sub (cirY , radius);
	    }
	    else
	    {
	    	arcAngle = (float) (Math.PI * ( sub(360.0f , cirAngle )) / 180.0f);
	        mPosX = add(cirX , (float) (Math.cos(arcAngle) * radius)) ;
	        mPosY = sub(cirY , (float) (Math.sin(arcAngle) * radius));
	    }
	    	    
	    mPointF.x = mPosX;
	    mPointF.y = mPosY;	    
	    return mPointF;				
	}
	
	public PointF getArcEndPointF()
	{		
		return mPointF;
	}
	
	public float getPosX() {
		return mPosX;
	}
		
	public float getPosY() {
		return mPosY;
	}	
	
	
	//两点间的角度
	public double getDegree(float sx, float sy, float tx, float ty) 
    {
        float nX = tx - sx;
        float nY = ty - sy;
        double angrad = 0d,angel = 0d,tpi = 0d;
        float tan = 0.0f;
        
        if (Float.compare(nX ,0.0f) != 0) {
            tan = Math.abs(nY / nX);
            angel  = Math.atan(tan);
            
            if ( Float.compare(nX,0.0f) == 1 )
            {
            	if( Float.compare(nY,0.0f) == 1 || Float.compare(nY,0.0f) ==  0)
            	{
            		 angrad = angel;
            	}else{
            		 angrad = 2 * Math.PI - angel;
            	}
            }else{
            	if( Float.compare(nY,0.0f) == 1 || Float.compare(nY,0.0f) ==  0)
            	{
            		angrad = Math.PI - angel;
            	}else{
            		angrad = Math.PI + angel;
            	}
            }                      

        } else {
        	tpi  = Math.PI / 2;        	
        	if( Float.compare(nY,0.0f) == 1)
        	{
        		angrad = tpi;
        	}else{
        		angrad = -1 * tpi;
        	}
        }        
        return  Math.toDegrees(angrad);
    }
		
    //两点间的距离
    public double getDistance(float sx,float sy,float tx,float ty)
    {	 
    	float nx = Math.abs(tx - sx);
        float ny = Math.abs(ty - sy);	       
          
      	return Math.hypot(nx, ny);
    }	
    
    
    /**
     * 将百分比转换为图心角角度
     * @param totalAngle	总角度(如:360度)
     * @param percentage	百分比
     * @return 圆心角度
     */
	public float getSliceAngle(float totalAngle,float percentage) 
	{			
		float Angle = 0.0f;
		try{
			
			float currentValue = percentage;
			if(currentValue >= 101f || currentValue < 0.0f)
			{
				//Log.e(TAG,"输入的百分比不合规范.须在0~100之间.");			
			}else{						
				Angle =  MathHelper.getInstance().round( 
								MathHelper.getInstance().mul(totalAngle,
									MathHelper.getInstance().div(currentValue,100f) ) ,2);												
			}
			
		}catch(Exception ex)
		{
			Angle = -1f;
		}finally{
			
		}
		return  Angle;
	}
	
	
	//函数来自LnChart，位置算法现在到处都是，可以考虑优化下。[各轴，定制线]
	public float getLnPlotXValPosition(float plotScreenWidth,float plotAreaLeft,
								   double xValue, double maxValue,double minValue) {
		// 对应的X坐标
		double maxminRange = sub(maxValue, minValue);
		double xScale = div(sub(xValue, minValue), maxminRange);
		return mul(plotScreenWidth, (float) xScale);
	}    
	
	public float getLnXValPosition(float plotScreenWidth,float plotAreaLeft,
			   double xValue, double maxValue,double minValue) {
		// 对应的X坐标
		return add(plotAreaLeft, 
				getLnXValPosition(plotScreenWidth,plotAreaLeft,xValue,maxValue,minValue) );
	}    		
        
    public void disableHighPrecision()
    {
    	mHighPrecision = false;
    }
    
    public void enabledHighPrecision()
    {
    	mHighPrecision = true;
    }
	 
	/**
	 * 加法运算
	 * @param v1
	 * @param v2
	 * @return
	 */
	 public float add(float v1, float v2) 
	 {
		 if(!mHighPrecision)
		 {
			 return (v1+v2);	 
		 }else{
			 // BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		
			 BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		 
		 	 BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
		 	 return bgNum1.add(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 减法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float sub(float v1, float v2) 
	 {
		 if(!mHighPrecision)
		 {
			 return (v1 - v2);	 
		 }else{
			 BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));		 		 
			 BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			 return bgNum1.subtract(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 乘法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float mul(float v1, float v2) 
	 {		
		 if(!mHighPrecision)
		 {
			 return (v1 * v2);	 
		 }else{
			  BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			  return bgNum1.multiply(bgNum2).floatValue();
		 }
	 }
		 
	 /**
	  * 除法运算,当除不尽时，精确到小数点后10位
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public float div(float v1, float v2)
	 {		
		return div(v1, v2, DEFAULT_DIV_SCALE);		 
	 }
		 
	 /**
	  * 除法运算,当除不尽时，精确到小数点后scale位
	  * @param v1
	  * @param v2
	  * @param scale
	  * @return 运算结果
	  */
	 public float div(float v1, float v2, int scale) 
	 {		 		 
		  if (scale < 0) 
		   throw new IllegalArgumentException("The scale must be a positive integer or zero");
		
		  if( Float.compare(v2, 0.0f) == 0)return 0.0f;
		  
		  if(!mHighPrecision)
		  {
			 return (v1 / v2);	 
		  }else{		  							
			  BigDecimal bgNum1 = new BigDecimal(Float.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Float.toString(v2));
			  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
		  }
	 }
		 
	 /**
	  * 四舍五入到小数点后scale位
	  * @param v
	  * @param scale
	  * @return 
	  */
	 public float round(float v, int scale) 
	 {
		  if (scale < 0) 
			  throw new IllegalArgumentException("The scale must be a positive integer or zero");
			
		  BigDecimal bgNum1 = new BigDecimal(Float.toString(v));
		  BigDecimal bgNum2 = new BigDecimal("1");
		  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).floatValue();		  
		 // return b.setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
	 }
	
	 public double add(double v1, double v2) 
	 {
		 if(!mHighPrecision)
		  {
			 return (v1 + v2);	 
		  }else{
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.add(bgNum2).doubleValue();
		  }
	 }
	 
	 public double sub(double v1, double v2) 
	 {		 
		 if(!mHighPrecision)
		  {
			 return (v1 - v2);	 
		  }else{
			 BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			 BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			 return bgNum1.subtract(bgNum2).doubleValue();
		  }
	 }
	 
	 
	 /**
	  * 除法计算,使用默认精度
	  * @param v1
	  * @param v2
	  * @return
	  */
	 public double div(double v1, double v2) 
	 {
		 return div(v1,v2,DEFAULT_DIV_SCALE);
	 }
	 
	 /**
	  * 除法计算
	  * @param v1
	  * @param v2
	  * @param scale	指定保留精度
	  * @return
	  */
	 public double div(double v1, double v2, int scale) 
	 {
		  if (scale < 0) 
		   throw new IllegalArgumentException("The scale must be a positive integer or zero");
		
		  if(Double.compare(v2, 0d) == 0) return 0d;
		  
		  if(!mHighPrecision)
		  {
			 return (v1 / v2);	 
		  }else{		  
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
		  }
	 }	 	 	
	 
	 /**
	  * 乘法运算
	  * @param v1
	  * @param v2
	  * @return 运算结果
	  */
	 public double mul(double v1, double v2) 
	 {		
		 if(!mHighPrecision)
		 {
			 return (v1 * v2);	 
		 }else{
			  BigDecimal bgNum1 = new BigDecimal(Double.toString(v1));
			  BigDecimal bgNum2 = new BigDecimal(Double.toString(v2));
			  return bgNum1.multiply(bgNum2).doubleValue();
		 }
	 }
	 
	 /**
	  * 四舍五入到小数点后scale位
	  * @param v
	  * @param scale
	  * @return 
	  */
	 public double round(double v, int scale) 
	 {
		  if (scale < 0) 
			  throw new IllegalArgumentException("The scale must be a positive integer or zero");
			
		  BigDecimal bgNum1 = new BigDecimal(Double.toString(v));
		  BigDecimal bgNum2 = new BigDecimal("1");
		  return bgNum1.divide(bgNum2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();		  
		 // return b.setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
	 }
	 
} public class RdChart extends EventChart {
	
	private String TAG = "RdChart";
	
	//半径
	private float mRadius=0.0f;	
	//初始偏移角度
	private int mOffsetAngle = 0;//180;		
					
	//格式化线中点的标签显示
	 private IFormatterDoubleCallBack mDotLabelFormatter;		
	 
	//开放标签和线画笔让用户设置
	private Paint mPaintLabel = null;	
	private Paint mPaintLine = null;
		
	
	public RdChart() {		
		
		//初始化图例
		if(null != plotLegend)
		{
			plotLegend.show();
			plotLegend.setType(XEnum.LegendType.ROW);
			plotLegend.setHorizontalAlign(XEnum.HorizontalAlign.CENTER);
			plotLegend.setVerticalAlign(XEnum.VerticalAlign.BOTTOM);
			plotLegend.showBox();
			plotLegend.hideBackground();
		}
				
	}
			
	@Override
	protected void calcPlotRange()
	{
		super.calcPlotRange();		
		this.mRadius = Math.min( div(this.plotArea.getWidth() ,2f) , 
				 				 div(this.plotArea.getHeight(),2f) );	
	}
	
	/**
	 * 返回当前点击点的信息
	 * @param x 点击点X坐标
	 * @param y	点击点Y坐标
	 * @return 返回对应的位置记录
	 */
	public PointPosition getPositionRecord(float x,float y)
	{		
		return getPointRecord(x,y);
	}
		
	
	/**
	 * 返回半径
	 * @return 半径
	 */
	public float getRadius()
	{
		return mRadius;
	}
	
	/**
	 * 设置图起始偏移角度
	 * @param Angle 偏移角度
	 */
	public void setInitialAngle(final int Angle)
	{
		if(Angle < 0 || Angle > 360)
		{
			Log.e(TAG, "起始偏移角度不能小于0或大于360");
		}else
			mOffsetAngle = Angle;
	}
	

	/**
	 * 返回图的起始偏移角度
	 * @return 偏移角度
	 */
	public int getInitialAngle()
	{
		return mOffsetAngle;
	}
	
	
	/**
	 * 设置线上点标签显示格式
	 * 
	 * @param callBack
	 *            回调函数
	 */
	public void setDotLabelFormatter(IFormatterDoubleCallBack callBack) {
		this.mDotLabelFormatter = callBack;
	}

	/**
	 * 返回线上点标签显示格式
	 * 
	 * @param value 传入当前值
	 * @return 显示格式
	 */	
	protected String getFormatterDotLabel(double value) {
		String itemLabel = "";
		try {
			itemLabel = mDotLabelFormatter.doubleFormatter(value);
		} catch (Exception ex) {
			itemLabel = Double.toString(value);
			// DecimalFormat df=new DecimalFormat("#0");
			// itemLabel = df.format(value).toString();
		}
		return itemLabel;
	}
		
	/**
	 * 开放标签画笔
	 * @return 画笔
	 */
	public Paint getLabelPaint()
	{
		if(null == mPaintLabel)
		{
			mPaintLabel = new Paint();
			mPaintLabel.setColor(Color.BLACK);
			mPaintLabel.setTextSize(18);
			mPaintLabel.setAntiAlias(true);
			mPaintLabel.setTextAlign(Align.CENTER);
		}
		return mPaintLabel;
	}
	
	/**
	 * 开放画网线的画笔
	 * @return 画笔
	 */
	public Paint getLinePaint()
	{
		if(null == mPaintLine)
		{
			mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
			mPaintLine.setColor(Color.rgb(180, 205, 230));
			mPaintLine.setStyle(Style.STROKE);
			mPaintLine.setStrokeWidth(3);	
		}		
		return mPaintLine;
	}
	
	
	@Override
	public boolean render(Canvas canvas) throws Exception {
		// TODO Auto-generated method stubcalcPlotRange
		
		try {
				if (null == canvas)
						return false;								
				
				
				if(getPanModeStatus())
				{											
					canvas.save();
					//设置原点位置					
					switch(this.getPlotPanMode())
					{
					case HORIZONTAL:
						canvas.translate(mTranslateXY[0],0);		
						break;
					case VERTICAL:
						canvas.translate(0,mTranslateXY[1]);		
						break;
					default:
						canvas.translate(mTranslateXY[0],mTranslateXY[1]);
						break;
					}
					
					//绘制图表
					super.render(canvas);
						
					//还原								
					canvas.restore();			
				}else{
					//绘制图表
					super.render(canvas);
				}
				
				return true;				
		} catch (Exception e) {
			throw e;
		}
		//return ret;
	}
	
	

} public class XEnum {
	
		/**
		 * 横向显示位置,靠左，中间，还是靠右(如图标题......)
		 * @author XCL
		 *
		 */
		public enum HorizontalAlign {
			LEFT, CENTER ,RIGHT
		}			
		
		/**
		 * 竖向显示位置,上方，中间，底部 (如坐标轴标签......)
		 * @author XCL
		 *
		 */
		public enum VerticalAlign
		{
			TOP,MIDDLE,BOTTOM
		}
		
		/**
		 * 设置轴线风格
		 * @author XCL
		 *
		 */
		public enum AxisLineStyle
		{
			NONE,CAP,FILLCAP
		}
			
		/**
		 * 对于圆形的图，如饼图之类，用来确定标签的显示位置
		 * @author XCL  
		 *
		 */
		public enum SliceLabelStyle{		
			HIDE,INSIDE,OUTSIDE,BROKENLINE
		}
				
		/**
		 * 是显示全圆还是半圆
		 * @author XCL
		 *
		 */
		public enum CircleType {		
			FULL,HALF
		}
				
		
		/**
		 * 三角形的朝向
		 * @author XCL
		 *
		 */
		public enum TriangleDirection {
			UP,DOWN,LEFT,RIGHT
		}
		 
		/**
		 * 三角形填充风格 
		 * @author XCL
		 *
		 */
		public enum TriangleStyle {
			OUTLINE,FILL 
		}

		
		/**
		 * 线的几种显示风格:Solid、Dot、Dash
		 * @author XCL
		 *
		 */
		public enum LineStyle {
			SOLID,DOT,DASH
		}
		
		/**
		 * 框的类型
		 * @author XCL
		 *
		 */
		public enum RectType {
			RECT,ROUNDRECT
		}
		
		/**
		 * 标签标注框形状
		 * @author XCL
		 *
		 */
		public enum LabelBoxStyle{
			TEXT,RECT,CIRCLE,CAPRECT,ROUNDRECT,CAPROUNDRECT
		}
		
		
		/**
		 * 用于设定柱形的风格，仅对flatbar有效
		 * @author XCL
		 *
		 */
		public enum BarStyle {
			GRADIENT,FILL,STROKE,OUTLINE,TRIANGLE,ROUNDBAR
		}
		
		/**
		 * 柱形居中位置,依刻度线居中或依刻度中间点居中。
		 * @author XCL
		 *
		 */
		public enum BarCenterStyle {
			TICKMARKS, SPACE
		}	
		
		/**
		 * 横向或竖向网格线
		 * @author XCL
		 *
		 */
		public enum Direction {
			HORIZONTAL, VERTICAL
		}
		

		/**
		 * 轴标记类别:刻度线/标签
		 * @author XCL
		 *
		 */
		public enum TickType {
			MARKS,LABELS
		}
		

		
		/**
		 * 图例类型 
		 * @author XCL
		 *
		 */
		public enum LegendType
		{
			COLUMN,ROW
		}
									
		
		
		/**
		 * 线的类型，默认的直线还是贝塞尔曲线(Bézier curve)
		 * @author XCL
		 *
		 */
		public enum CrurveLineStyle
		{			
			BEELINE,BEZIERCURVE
		}			
		
		/**
		 * 点的类型，隐藏，三角形,方形,实心圆,空心圆,棱形
		 * @author XCL
		 * @param HIDE	隐藏，不显示点
		 * @param TRIANGLE	三角形
		 * @param RECT	方形
		 * @param DOT	圆点
		 * @param RING	圆环
		 * @param PRISMATIC	棱形
		 */
		public enum DotStyle {		
			HIDE,TRIANGLE,RECT,DOT,RING,RING2,PRISMATIC,X,CROSS
		}
		
		/**
		 * 批注背景形状
		 * @author XCL
		 *
		 */
		public enum AnchorStyle{
			RECT,CAPRECT,ROUNDRECT,CAPROUNDRECT,CIRCLE,VLINE,HLINE,TOBOTTOM,TOTOP,TOLEFT,TORIGHT
		}
		
		
		/**
		 * 数据区域的填充方式(雷达图/批注)
		 * @author XCL
		 *
		 */
		public enum DataAreaStyle {
			FILL,STROKE
		}
		
		/**
		 * 设置圆形轴的类型
		 * @author XCL
		 *
		 */
		//DialChart RoundAxis
		public enum RoundAxisType {			
			TICKAXIS,RINGAXIS,ARCLINEAXIS,FILLAXIS,CIRCLEAXIS,LINEAXIS
		}
		

		/**
		 * 位置
		 * @author XCL
		 *
		 */
		public enum Location {  
			TOP,BOTTOM,LEFT,RIGHT
		}
		
		/**
		 * 轴位置
		 * @author XCL
		 *
		 */
		public enum AxisLocation {  
			TOP,BOTTOM,LEFT,RIGHT,HORIZONTAL_CENTER, VERTICAL_CENTER
		}
		
		
		/**
		 * 指针类型
		 * @author XCL
		 *
		 */
		public enum PointerStyle {			
			TRIANGLE,LINE
		}
		
		/**
		 * 设置圆形Tick轴的类型
		 * @author XCL
		 *
		 */
		public enum RoundTickAxisType {			
			INNER_TICKAXIS,OUTER_TICKAXIS
		}
		
		/**
		 * 雷达图显示类型(蛛网或圆形)
		 * @author XCL
		 *
		 */
		public enum RadarChartType{
			RADAR,ROUND
		}
		
		/**
		 * 手势平移模式(模向，纵向，自由移动)
		 * @author XCL
		 *
		 */
		public enum PanMode {  
			HORIZONTAL,VERTICAL,FREE
		}
		
		
		/**
		 * 动态边框风格
		 * @author XCL
		 *
		 */
		public enum DyInfoStyle {			
			RECT,ROUNDRECT,CAPRECT,CIRCLE,CAPROUNDRECT //,ELLIPSE
		}
		
		/**
		 * 动态线类型 
		 * Cross 指定交叉的水平线和垂直线。
		 * BackwardDiagonal 从右上到左下的对角线的线条图案。
		 * Vertical		垂直线
		 * Horizontal 水平线
		 * @author XCL
		 *
		 */
		public enum DyLineStyle{
			Cross,BackwardDiagonal,Vertical,Horizontal
		}
		
		/**
		 * 标签线是否显示圆点及显示风格
		 * @author XCL
		 *
		 */
		public enum LabelLinePoint{
			NONE,BEGIN,END,ALL
		}
		
		
		/**
		 * 标签信息的保存类型 
		 * 	ONLYPOSITION : 保存坐标信息，但不显示标签
		 *  ALL : 保存坐标信息，也显示标签
		 * @author XCL
		 *
		 */
		public enum LabelSaveType{
			NONE,ONLYPOSITION,ALL
		}
		
		/**
		 * 轴标题显示几格.
		 * NORMAL 显示在轴中间
		 * ENDPOINT 显示在轴的结束点及交叉点(仅支持左下点)位置
		 * @author XCL
		 *
		 */
		public enum AxisTitleStyle{
			NORMAL,ENDPOINT
		}
		
		/**
		 * 排序类型 
		 * @author XCL
		 *
		 */
		public enum SortType {		
			NORMAL,ASC,DESC
		}
		
		/**
		 * 标签显示方式
		 * @author XCL
		 *
		 */
		public enum LabelLineFeed {		
			NORMAL,ODD_EVEN,EVEN_ODD
		}
		
		public enum ODD_EVEN {		
			ODD,EVEN,NONE
		}
		
		//柱形标签位置
		public enum ItemLabelStyle {			
			NORMAL,INNER,OUTER,BOTTOM
		}
				
		/**
		 * 图的所属类型
		 * @author XCL
		 *
		 */
		public enum ChartType{
			NONE,BAR,BAR3D,STACKBAR,PIE,PIE3D,DOUNT,LINE,SPLINE,AREA,
			ROSE,RADAR,DIAL,RANGEBAR,ARCLINE,CIRCLE,SCATTER,BUBBLE,GAUGE,FUNNEL
		}
		
} public class CategoryAxis extends XYAxis {
	
	//分类轴分隔值	
	private double  mAxisSteps = 0.0d;
	
	private boolean mAxisBindStd = false;
	
	public CategoryAxis()
	{
		
	}
	
	/**
	 * 设置分类轴步长
	 * @param steps 步长
	 */
	public void setAxisSteps(double steps)
	{
		 mAxisSteps = steps;
	}
	
	/**
	 * 返回分类轴步长
	 * @return 步长
	 */
	public double getAxisSteps()
	{
		return mAxisSteps;
	}
	
	/**
	 * 是否将分类轴与数据轴的正负标准值绑定, 
	 * 如绑定，则轴会显示在标准值所在位置
	 * @param status 设置状态
	 */
	public void setAxisBuildStd(boolean status)
	{
		mAxisBindStd = status;
	}
	
	/**
	 * 分类轴与数据轴的正负标准值绑定状态 
	 * @return 状态
	 */
	public boolean getAxisBuildStdStatus()
	{
		return mAxisBindStd;
	}
	

} public class CategoryAxisRender extends CategoryAxis { 
	

	
	public CategoryAxisRender()
	{		
		getTickLabelPaint().setTextAlign(Align.CENTER);				
	}
	
	/**
	 * 返回数据源
	 * @return 数据源
	 */
	public List<String> getDataSet()
	{
		return this.mDataSet;
	}	

	/**
	 * 绘制横向刻度标识
	 * @param xchart	图表基类
	 * @param canvas	画布
	 * @param centerX	点X坐标
	 * @param centerY	点Y坐标
	 * @param text	内容
	 */	
	/*
	public 	void renderAxisHorizontalTick(XChart xchart,Canvas canvas, 
							float centerX,float centerY,
							String text,float labelX, float labelY, boolean isTickVisible)
	{			
	   renderHorizontalTick(xchart,canvas,centerX,centerY,text,labelX,labelY,isTickVisible);
	}
	*/
	public 	void renderAxisHorizontalTick(float chatLeft,float plotLeft,
			Canvas canvas, 
			float centerX,float centerY,
			String text,
			float labelX, float labelY, boolean isTickVisible) //,XEnum.ODD_EVEN oe)
	{			
		renderHorizontalTick(chatLeft,plotLeft,
				canvas,centerX,centerY,
				text,labelX,labelY,isTickVisible); //,oe);
	}

	
	
	/**
	 * 绘制竖向刻度标识
	 * @param centerX	点X坐标
	 * @param centerY	点Y坐标
	 * @param text	内容
	 */
	public void renderAxisVerticalTick(Canvas canvas,
							float centerX,float centerY,
							String text,float labelX, float labelY, 
							boolean isTickVisible,XEnum.ODD_EVEN oe)
	{		
		renderVerticalTick(canvas,centerX,centerY,text,labelX,labelY,isTickVisible,oe);
	}
	
	/**
	 * 绘制轴线
	 * @param startX 起始点X坐标
	 * @param startY 起始点Y坐标
	 * @param stopX	 终止点X坐标	
	 * @param stopY	 终止点Y坐标
	 */
	public void renderAxis(Canvas canvas,float startX,float startY,float stopX,float stopY)
	{
		if(isShow() && isShowAxisLine())
			drawAxisLine(canvas,startX, startY, stopX, stopY);
	}
	
	public void renderAxisLine(Canvas canvas,float startX,float startY,float stopX,float stopY)
	{		
		drawAxisLine(canvas,startX, startY, stopX, stopY);
	}

	
	/**
	 * 设置分类轴数据源
	 * @param dataSet 数据源
	 */
	public void setDataBuilding(List<String> dataSet)
	{		
		 mDataSet = dataSet;
	}
	
} public class DataAxis extends XYAxis {

	//轴数据来源
	 private double mDataAxisMin = 0d;
	 private double mDataAxisMax = 0d;
	 private double mDataAxisSteps = 0d;
	 private double mDetailModeSteps = 0d;
	 
	//是否显示第一个序号的标签文本
	 protected boolean mShowFirstTick = true;
	 
	 private float mDataAxisStd = 0.0f;
	 private boolean mAxisStdStatus = false;
	
	
	//轴范围分区数据集
	//private LinkedHashMap<Double,Double> mRangeMap ;	 
	//private ArrayList<Integer> mRangeColor ;	
	 
	public DataAxis()
	{		
	}
	
	/**
	 * 激活正负标准值处理，激活后，数据与标准值比较后，依大小向各自方向绘制
	 */
	public void enabledAxisStd(){
		mAxisStdStatus = true;
	}
	
	/**
	 * 禁掉正负标准值处理
	 */
	public void disableddAxisStd(){
		mAxisStdStatus = false;
	}
	
	/**
	 * 设置具体的标准值
	 * @param std 标准值
	 */
	public void setAxisStd(float std){
		mDataAxisStd = std;
	}
				
	/**
	 * 返回正负标准值处理状态
	 * @return 状态
	 */
	public boolean getAxisStdStatus(){
		return mAxisStdStatus;
	}
	
	/**
	 * 返回当前正负标准值，如没设则默认为轴的最小值
	 * @return 标准值
	 */
	public float getAxisStd(){
		if(mAxisStdStatus)
		{
			return mDataAxisStd;
		}else{
			return (float) mDataAxisMin;
		}
	}
	 
	/**
	 * 设置数据轴最小值,默认为0
	 * @param min 最小值
	 */
	 public void setAxisMin(double min)
	 {
		 mDataAxisMin = min;
	 }
	 
	 /**
	  * 设置数据轴最大值
	  * @param max 最大值
	  */
	 public void setAxisMax(double max)
	 {
		 mDataAxisMax = max;
	 }
	 /**
	  * 设置数据轴步长
	  * @param steps 步长
	  */
	 public void setAxisSteps(double steps)
	 {
		 mDataAxisSteps = steps;
	 }
	 
	 
	 /**
	  * 设置后，会启用为明细模式，轴刻度线会分长短,背景线会分粗细
	  * @param steps 步长
	  */
	 public void setDetailModeSteps(double steps)
	 {
		 mDetailModeSteps = steps;
	 }
	 
		 
	 /**
	  * 返回数据轴最小值
	  * @return 最小值
	  */
	 public float getAxisMin() {
		return (float) mDataAxisMin;
	 }

	/**
	 * 返回数据轴最大值
	 * @return 最大值
	 */
	 public float getAxisMax() {
		return (float)mDataAxisMax;
	 }

	/**
	 * 返回数据轴步长
	 * @return 步长
	 */
	public double getAxisSteps() {
		return mDataAxisSteps;
	}	
	
	/**
	 * 返回区分刻度线明细的步长
	 * @return 步长
	 */
	public double getDetailModeSteps() {
		return mDetailModeSteps;
	}	
	
	/**
	 * 返回是否启用明细模式
	 * @return 是否有启用
	 */
	public boolean isDetailMode()
	{		
		return((Double.compare(mDetailModeSteps, 0d) == 0)?false:true); 
	}
	
	/**
	 * 显示数据轴第一个序号的值，默认显示
	 */
	public void showFirstTick()
	{
		mShowFirstTick = true;
	}
	
	/**
	 * 不显示数据轴第一个序号的值，默认显示
	 */
	public void hideFirstTick()
	{
		mShowFirstTick = false;
	}
	
	/*
	 * 绘制轴范围分区  ........ 没心情，不做了
	public void setRangeAxis(LinkedHashMap<Double,Double> rangeMap,
							  ArrayList<Integer> rangeColor)
	{
		mRangeMap = rangeMap;
		mRangeColor = rangeColor;
	}
	*/

	
} public class DataAxisRender extends DataAxis { 

	//当前刻度线ID
	private int mCurrentId = 0;
	
		
	public DataAxisRender()
	{	
	}
		
	/**
	 * 返回轴值的范围(即最大-最小值).
	 * @return 轴值范围
	 */
	public float getAxisRange()
	{
		//return (int) Math.abs(getAxisMax() - getAxisMin());		
		return MathHelper.getInstance().sub(getAxisMax(), getAxisMin());
	}
	
	
	/**
	 * 数据轴值范围(最大与最小之间的范围)  /  传的的步长  = 显示的Tick总数
	 * @return 显示的刻度标记总数
	 */
	public int getAixTickCount()
	{
		int tickCount = (int) Math.ceil( getAxisRange() / getAxisSteps() ) ;		
		return tickCount;
	}
	
	
	/**
	 * 设置当前刻度线在轴上的序号ID,注意,此序号与轴的值与关，仅用来说明是轴上的第几个标识
	 * @param id  刻度线ID
	 */
	public void setAxisTickCurrentID(int id)
	{
		mCurrentId = id;
	}
	
	/**
	 * 依据当前id序号与steps的比较来区分当前是否为主tick
	 * @return 是否为主tick
	 */
	public boolean isPrimaryTick()
	{		
		return isPrimaryTick(mCurrentId);		
	}
	
	public boolean isPrimaryTick(int id)
	{
		if(isDetailMode())
		{		
			if(0 == id && mShowFirstTick) return true;
			
			if( id < getDetailModeSteps() 
					|| id%getDetailModeSteps() != 0 )
				return false;
		}		
		return true;		
	}
	
	
	/**
	 * 用于处理明细横式下，细分部份的轴刻度线长度缩短为正常的一半，用来突出主明细刻度
	 * @return 刻度线长度
	 */
	@Override
	public int getTickMarksLength()
	{		
		int len = super.getTickMarksLength();		
		return(isPrimaryTick()?len:len/2);
	}
	
	/**
	 * 用于处理明细模式下，细分部份的标签不显示出来
	 */
	@Override
	public boolean isShowAxisLabels() {		
		return (!isPrimaryTick()?false:super.isShowAxisLabels());	
	}
	

	//public boolean isShowAxisDetailModeLabels() {		
	//	return (!isPrimaryTick()?false:isShowAxisLabels());	
	//}


	/**
	 * 绘制横向刻度标记
	 * @param chatLeft  图最左边
	 * @param plotLeft	绘图区最左边
	 * @param canvas	画布
	 * @param centerX	中心点X坐标
	 * @param centerY	中心点Y坐标
	 * @param text		文本
	 * @param isTickVisible	是否显示
	 */
	public 	void renderAxisHorizontalTick(float chatLeft,float plotLeft,
			Canvas canvas, 
			float centerX,float centerY,
			String text,
			boolean isTickVisible)
	{								
		renderHorizontalTick(chatLeft,plotLeft,canvas, 
							 centerX,centerY,text,centerX,centerY,isTickVisible);
	}


	/**
	 * 绘制竖向刻度标记
	 * @param canvas	画布
	 * @param centerX	中心点X坐标
	 * @param centerY	中心点Y坐标
	 * @param text		文本
	 */
	public void renderAxisVerticalTick(Canvas canvas,float centerX,float centerY,
			String text,
			boolean isTickVisible,XEnum.ODD_EVEN oe)
	{		
		renderVerticalTick(canvas,centerX,centerY,text,centerX,centerY,isTickVisible,oe);		
	}
		

	/**
	 * 绘制轴
	 * @param canvas 画布
	 * @param startX 起始点X坐标
	 * @param startY 起始点Y坐标
	 * @param stopX	  结束点X坐标	
	 * @param stopY	  结束点Y坐标
	 */
	public void renderAxis(Canvas canvas, float startX,float startY,float stopX,float stopY)
	{
		if(isShow() && isShowAxisLine())
		{
			drawAxisLine(canvas,startX, startY, stopX, stopY); 
		}
	}	
	
	public void renderAxisLine(Canvas canvas, float startX,float startY,float stopX,float stopY)
	{		
		drawAxisLine(canvas,startX, startY, stopX, stopY); 
	}	
	

} public class PlotDot {

	//private Paint mPaintDot = null;
	
	private int mColor = Color.BLACK;
	private int mRingInnerColor = Color.WHITE;
	private int mRing2InnerColor = Color.RED;
	
	//Triangle 三角  	
	//线上的点为圆或角
	protected XEnum.DotStyle mDotStyle = XEnum.DotStyle.DOT;
	
	private float mRadius = 10.0f;
	
	private int mAlpha = 255;
	
	public PlotDot()
	{		
	}
	
	/**
	 * 设置颜色
	 * @param color	颜色
	 */
	public void setColor(int color)
	{
		mColor = color;
	}
	
	/**
	 * 返回颜色
	 * @return 颜色
	 */
	public int getColor()
	{
		return mColor;
	}
			
	/**
	 * 设置点形状为环形时，内部所填充的颜色.仅对环形有效
	 * @param color 内部填充颜色
	 */
	public void setRingInnerColor(int color)
	{
		mRingInnerColor = color;
	}
	
	/**
	 * 设置点形状为环形时，最内部所填充的颜色.仅对环形有效
	 * @param color 最内部填充颜色
	 */
	public void setRing2InnerColor(int color)
	{
		mRing2InnerColor = color;
	}
	
	
	/**
	 * 设置当前环形点内部填充颜色
	 * @return 内部填充颜色
	 */
	public int getRingInnerColor()
	{
		return mRingInnerColor;
	}
	
	/**
	 * 设置当前环形点最内部填充颜色
	 * @return 内部填充颜色
	 */
	public int getRing2InnerColor()
	{
		return mRing2InnerColor;
	}
	

	/**
	 * 设置点的显示风格
	 * @param style 显示风格
	 */
	public void setDotStyle( XEnum.DotStyle style)
	{
		mDotStyle = style;
	}
	
	/**
	 * 返回点的显示风格
	 * @return 显示风格
	 */
	public XEnum.DotStyle getDotStyle()
	{
		return mDotStyle;
	}
	
	/**
	 * 设置点的绘制半径大小，会依此指定的半径来绘制相关图形
	 * @param radius 半径
	 */
	public void setDotRadius(float radius)
	{
		mRadius = radius;
	}
	
	/**
	 * 返回点的绘制半径大小
	 * @return 半径
	 */
	public float getDotRadius()
	{
		return mRadius;
	}
	
	/**
	 * 设置透明度
	 * @param alpha 透明度
	 */
	public void setAlpah(int alpha)
	{
		mAlpha = alpha;
	}
	
	/**
	 * 返回当前透明度
	 * @return 透明度
	 */
	public int getAlpha()
	{
		return mAlpha;
	}
	
	
} public class PlotDotRender {
	
	private static PlotDotRender instance = null;
	
	protected Paint mPaintFill = null;
	
	private Path mPath = null;
	private RectF mRect = new RectF();

	public PlotDotRender()
	{

	}
	
	public static synchronized PlotDotRender getInstance()
	{
		if(instance == null)
		{
			instance = new PlotDotRender();
		}
		return instance;
	}
	
	private void initPath()
	{
		if(null == mPath)
		{
			mPath = new Path();
		}else{
			mPath.reset();
		}		
	}	

	
	/**
	 * 开放填充内部环形的画笔
	 */
	public Paint getInnerFillPaint()
	{
		if(null == mPaintFill)
		{
			mPaintFill = new Paint();
			mPaintFill.setColor(Color.WHITE); 
			mPaintFill.setStyle(Style.FILL);
			mPaintFill.setAntiAlias(true);
		}
		return mPaintFill; 
	}
	
	/**
	 * 绘制线上的坐标点
	 * 
	 * @param canvas 画布
	 * @param pDot	点类型
	 * @param cirX	x坐标
	 * @param cirY	Y坐标
	 * @param paint	画笔
	 */	
	public RectF renderDot(Canvas canvas, PlotDot pDot, 
			  float cirX, float cirY, Paint paint) {
		
		float radius = pDot.getDotRadius();
						
		if(Float.compare(radius, 0.0f) == 0 
				|| Float.compare(radius, 0.0f) == -1){			
			return new RectF(0.0f,0.0f,0.0f,0.0f);
		}	
	
		float left = cirX - radius ;
		float top = cirY - radius; 
		float right = cirX + radius ;
		float bottom = cirY + radius ;
		
		if(XEnum.DotStyle.DOT == pDot.getDotStyle() ||
				XEnum.DotStyle.RING == pDot.getDotStyle() ||
						XEnum.DotStyle.X == pDot.getDotStyle()	)
		{
			mRect.left =  left;
			mRect.top =   top ;
			mRect.right =  right;
			mRect.bottom = bottom;	
		}
		
		switch (pDot.getDotStyle()) {
		case DOT:										
			canvas.drawCircle(cirX, cirY,radius, paint);			
			break;
		case RING:					
			renderRing(canvas,paint,radius,pDot,cirX, cirY);
			break;
		case RING2:					
			renderRing2(canvas,paint,radius,pDot,cirX, cirY);
			break;
		case TRIANGLE: // 等腰三角形
			renderTriangle(canvas,paint,radius,cirX, cirY);			
			break;
		case PRISMATIC: // 棱形 Prismatic			
			//renderPrismatic(canvas,paint,radius,right,bottom,left );       
			renderPrismatic(canvas,paint,radius,cirX, cirY); 
			break;
		case RECT:
			renderRect(canvas,paint,radius,cirX, cirY);			
			break;
		case X:
			renderX(canvas,paint);			    
			break;
		case CROSS:
			renderCross(canvas,paint,radius,cirX, cirY);			    
			break;	
		case HIDE:
		default:
		}						
		return mRect;		
	}
	
	private void renderRing(Canvas canvas,Paint paint,float radius,
													PlotDot pDot,float cX ,float bottom)
	{
		float ringRadius = radius * 0.7f; // MathHelper.getInstance().mul(radius, 0.7f);		
        canvas.drawCircle(cX, bottom, radius, paint);

        getInnerFillPaint().setColor(pDot.getRingInnerColor());
        canvas.drawCircle(cX, bottom,ringRadius, getInnerFillPaint());         
	}
	
	private void renderRing2(Canvas canvas,Paint paint,float radius,
			PlotDot pDot,float cX ,float bottom)
	{
		float ringRadius = radius * 0.7f; // MathHelper.getInstance().mul(radius, 0.7f);		
		canvas.drawCircle(cX, bottom, radius, paint);
	
		getInnerFillPaint().setColor(pDot.getRingInnerColor());
		canvas.drawCircle(cX, bottom,ringRadius, getInnerFillPaint());        
		
		ringRadius = radius * 0.3f;
		getInnerFillPaint().setColor(pDot.getRing2InnerColor());
		canvas.drawCircle(cX, bottom,ringRadius, getInnerFillPaint());    
	}
	
	private void renderTriangle(Canvas canvas,Paint paint,float radius,float cirX,float cirY)
	{
		
		float halfRadius = MathHelper.getInstance().div(radius , 2f);		
		float triganaleHeight = radius + radius / 2;
		
		initPath();
		mPath.moveTo(cirX - radius, cirY + halfRadius);
		mPath.lineTo(cirX, cirY - triganaleHeight);
		mPath.lineTo(cirX + radius, cirY + halfRadius);
		mPath.close();
        canvas.drawPath(mPath, paint);
        mPath.reset();
                    
        mRect.left =  (cirX - radius);
		mRect.top = ( cirY - triganaleHeight);
		mRect.right =  ( cirX + radius);
		mRect.bottom =  ( cirY + halfRadius);	
	}
	
	private void renderPrismatic(Canvas canvas,Paint paint,
			float radius,float cirX,float cirY)
	{
		initPath();
		
		float left = cirX - radius ;
		float right = cirX + radius ;
		float centerX = left + (right - left) / 2;
		
		float top = cirY - radius ;
		float bottom = cirY + radius ;
		
		mPath.moveTo(centerX ,  top);
		mPath.lineTo(left, cirY );
		mPath.lineTo(centerX,  bottom );
		mPath.lineTo(right, cirY );
		mPath.lineTo(centerX ,  top);
				
		mPath.close();
		canvas.drawPath(mPath, paint);
		mPath.reset();
		
		mRect.left =left;
		mRect.top =  top;
		mRect.right =  right;
		mRect.bottom =  bottom;
	}
		
	private void renderRect(Canvas canvas,Paint paint,float radius,float cirX,float cirY )
	{
		paint.setStyle(Style.FILL);	
		
		mRect.left =  (cirX - radius);
		mRect.top =   (cirY - radius); 
		mRect.right =  (cirX + radius);
		mRect.bottom = (cirY + radius);
		canvas.drawRect(mRect,paint);
	}
	
	private void renderX(Canvas canvas,Paint paint)
	{
		canvas.drawLine(mRect.left, mRect.top, mRect.right, mRect.bottom , paint);
	    canvas.drawLine(mRect.left, mRect.bottom, mRect.right, mRect.top, paint);	   
	}
	
	private void renderCross(Canvas canvas,Paint paint,float radius,float cirX,float cirY)
	{
		canvas.drawLine(cirX - radius, cirY, cirX + radius, cirY , paint);
	    canvas.drawLine(cirX, cirY - radius,cirX, cirY + radius, paint);	   
	}
	
} public class PlotLine {
	
	private Paint mPaintLine = null;
	private Paint mPaintLabel = null;	
	private Paint mPaintDot = null;	
	private PlotDot mPlotDot = null;
			
	public PlotLine()
	{
		if(null == mPlotDot)mPlotDot = new PlotDot();			
	}
	
	private void initLinePaint()
	{
		if(null == mPaintLine)
		{
			mPaintLine = new Paint();
			mPaintLine.setColor(Color.BLUE);
			mPaintLine.setAntiAlias(true);
			mPaintLine.setStrokeWidth(5);
		}
	}
	
	private void initLabelPaint()
	{
		if(null == mPaintLabel)
		{
			mPaintLabel= new Paint();
			mPaintLabel.setColor(Color.BLUE);
			mPaintLabel.setTextSize(18);
			mPaintLabel.setTextAlign(Align.CENTER);
			mPaintLabel.setAntiAlias(true);
		}
	}
		
	
	/**
	 * 开放线画笔
	 * @return 画笔
	 */
	public Paint getLinePaint()
	{
		initLinePaint();
		return mPaintLine;
	}
	
	/**
	 * 开放标签画笔
	 * @return 画笔
	 */
	public Paint getDotLabelPaint()
	{
		initLabelPaint();
		return mPaintLabel;
	}
	
	/**
	 * 开放点画笔
	 * @return 画笔
	 */
	public Paint getDotPaint()
	{
		if(null == mPaintDot)
		{
			mPaintDot = new Paint();
			mPaintDot.setColor(Color.BLUE);
			mPaintDot.setAntiAlias(true);
			mPaintDot.setStrokeWidth(5);
		}
		return mPaintDot;// mPlotDot.getDotPaint();
	}
	
	/**
	 * 开放点绘制类
	 * @return 点绘制类
	 */
	public PlotDot getPlotDot()
	{
		return mPlotDot;
	}

	/**
	 * 设置点的显示风格
	 * @param style 风格
	 */
	public void setDotStyle( XEnum.DotStyle style)
	{
		mPlotDot.setDotStyle(style);
	}	
	
	/**
	 * 返回点的显示风格
	 * @return 风格
	 */
	public XEnum.DotStyle getDotStyle()
	{
		return mPlotDot.getDotStyle();
	}


}
import org.xclcharts.renderer.axis.CategoryAxisRender;
import org.xclcharts.renderer.axis.DataAxis;
import org.xclcharts.renderer.axis.DataAxisRender;
import org.xclcharts.renderer.line.PlotDot;
import org.xclcharts.renderer.line.PlotDotRender;
import org.xclcharts.renderer.line.PlotLine;
import android.graphics.Canvas;
import android.graphics.Paint.Align;
import android.graphics.Path;
import android.util.Log;
import java.util.List;
import org.xclcharts.common.DrawHelper;
import org.xclcharts.common.MathHelper;
import org.xclcharts.renderer.RdChart;
import org.xclcharts.renderer.XEnum;
import org.xclcharts.renderer.axis.CategoryAxis;
		for(int i=0;i<mArrayRadius.length;i++)
		{			
			canvas.drawCircle(plotArea.getCenterX(), plotArea.getCenterY(), 
								mArrayRadius[i], getLinePaint());			
		}
	}
	
	
	/**
	 * 绘制各个圆心角的轴线
	 * @param canvas 画布
	 */
	private void renderAxisLines(Canvas canvas)
	{				
		float cirX = plotArea.getCenterX();
		float cirY = plotArea.getCenterY();
		
		//标签个数决定角的个数
		int labelsCount =  getPlotAgentNumber();
		//轴线tick总数
		int dataAxisTickCount = getAxisTickCount();
				
		//轴线总数
		int i = dataAxisTickCount - 1;
		for(int j=0;j < labelsCount ;j++)
		{														
			//用于绘制各个方向上的轴线
			canvas.drawLine(cirX,cirY, mArrayDotX[i][j], 
										mArrayDotY[i][j], getLinePaint());									
												      
		} //end for labels													
	}
	
	
	/**
	 * 绘制最外围的标签及主轴的刻度线标签
	 * @param canvas 画布
	 */
	private void renderAxisLabels(Canvas canvas)
	{				
		//标签个数决定角的个数
		int labelsCount =  getPlotAgentNumber();
		//轴线tick总数
		int dataAxisTickCount = getAxisTickCount();
						
		for(int i=0; i < dataAxisTickCount;i++)
		{			
			for(int j=0;j < labelsCount ;j++)
			{							
				
				//绘制最外围的标签
				if(i == dataAxisTickCount - 1  )
				{		
					//绘制最外围的标签		
					 String label = categoryAxis.getDataSet().get(j);					
				        					
				     canvas.drawText(label, 
				    		 mArrayLabelX[i][j], mArrayLabelY[i][j], getLabelPaint());   					
				}
				
				
				//绘制主轴的刻度线与标签
				if(0 == j){ //显示在第一轴线上(即270度的那根线)										
					//绘制主轴(DataAxis)的刻度线				
					double tick = this.dataAxis.getAxisSteps() * i + dataAxis.getAxisMin();										
					dataAxis.renderAxisHorizontalTick(this.getLeft(),this.getPlotArea().getLeft(),canvas,
							 mArrayDotX[i][j], mArrayDotY[i][j],
							 Double.toString(tick),true);
				}
				
			      
			} //end for labels		
									
		} //end for data
	}
	
	
	/**
	 * 轴线上tick总个数
	 * @return 总个数
	 */
	private int getAxisTickCount()
	{		
		if(null == dataAxis) return 0;
		return Math.round(dataAxis.getAixTickCount() + 1);
	}
	
	/**
	 * 标签个数决定了图中角的个数
	 * @return 标签总个数
	 */
	private int getPlotAgentNumber()
	{
		if(null == categoryAxis)return 0;
		return categoryAxis.getDataSet().size();
	}
	
	/**
	 * 设置外围标签位置的偏移距离
	 * @param offset  偏移距离
	 */
	public void setlabelOffset(int offset)
	{
		mLabelOffset = offset;
	}
	
	/**
	 * 得到所有相关的交叉点坐标
	 */
	private void calcAllPoints()
	{				
		float cirX = plotArea.getCenterX();
		float cirY = plotArea.getCenterY();
		
		//标签个数决定角的个数
		int labelsCount =  getPlotAgentNumber();
		//轴线tick总数
		int dataAxisTickCount = getAxisTickCount();
				
		//扇形角度,依标签个数决定 				
		float pAngle = MathHelper.getInstance().div(360f, labelsCount) ; //   72f; 