public interface Tuyuan
{
	/**
	 * Ö»ÓÐµÈÒÆ¶¯¾àÀë³¬¹ýÕâ¸öÖµ²Å»á»æÍ¼
	 */
	public static final float TOUCH_TOLERANCE = 4.0f;
	
	/**
	 * »æÖÆÍ¼Ôª
	 */
	public void draw(Canvas canvas);

	/**
	 * ÊÖÖ¸°´ÏÂ
	 */
	public void touchDown(float x, float y);

	/**
	 * ÊÖÖ¸ÒÆ¶¯
	 */
	public void touchMove(float x, float y);

	/**
	 * ÊÖÖ¸ËÉ¿ª
	 */
	public void touchUp(float x, float y);

	/**
	 * ÊÇ·ñÒÑ¾­»æÖÆÁËÍ¼Ôª
	 */
	public boolean hasDraw();
	
	/**
	 * ÊÇ·ñ°üº¬µã(x,y)
	 */
	public boolean contains(float x,float y);
	
	/**
	 * ¸ßÁÁÏÔÊ¾
	 */
	public void setHighLight(Canvas canvas);
	
	/**
	 * Ñ¡ÔñÍ¼Ôª
	 */
	public void checked(Canvas canvas);
	
	/**
	 * Ëõ·Å
	 */
	public void scale(float offsetX,float offsetY);
	
	/**
	 * Æ½ÒÆ
	 */
	public void translate(float offsetX,float offsetY);
	
	/**
	 * Ðý×ª
	 */
	public void rotate(float degrees);
	/**
	 * Ìî³äµ±Ç°Í¼Ôª
	 */
	public void fill(int color);
	
	/**
	 * µ±Ç°Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	public boolean isFilled();
	
	/**
	 * ¿½±´µ±Ç°Í¼Ôª£¬¿½±´µÄÍ¼ÔªÐÎ×´ÓëÔ­Í¼ÔªÏàÍ¬£¬Î»ÖÃÎªÔ²Í¼ÔªµÄÓÒÏÂ·½(+10,+10)
	 */
	public Tuyuan copy();
}
 public class PaintStyle
{
	private static final String TAG = "PaintStyle";
	private Paint mPenPaint = null;
	private int type = ApplicationValues.PaintStyle.MODE_PLAIN_PEN;
	
	public PaintStyle(int type)
	{
		this.type = type;
		mPenPaint = new Paint();
	}
	/**
	 * ¿½±´µ±Ç°µÄ»­±ÊÑùÊ½
	 */
	public PaintStyle newInstance()
	{
		PaintStyle instance = new PaintStyle(type);
		return instance;
	}
	public void setPaintStyle(int type)
	{
		this.type = type;
	}
	public Paint getPaintStyle()
	{
		switch (type)
		{
		case ApplicationValues.PaintStyle.MODE_PLAIN_PEN:
			Log.i(TAG,"MODE_PLAIN_PEN");
			plainPen();//ÆÕÍ¨
			break;
		case ApplicationValues.PaintStyle.MODE_EMBOSS_PEN:
			Log.i(TAG,"MODE_EMBOSS_PEN");
			embossPen();
			break;
		case ApplicationValues.PaintStyle.MODE_BLUR_PEN:
			Log.i(TAG,"MODE_BLUR_PEN");
			blurPen();
			break;
		case ApplicationValues.PaintStyle.MODE_SHADER_PEN:
			Log.i(TAG,"MODE_SHADER_PEN");
			shaderPen();
			break;

		default:
			throw new RuntimeException("YITU:no such pen style found...");
		}
		
		return mPenPaint;
	}
	private void embossPen()
	{
		MaskFilter mEmboss = new EmbossMaskFilter(new float[]{ 1, 1, 1 }, 0.4f, 6, 3.5f);
		mPenPaint.setDither(true);
		mPenPaint.setAntiAlias(true);
		mPenPaint.setStyle(Paint.Style.STROKE);
		mPenPaint.setStrokeJoin(Paint.Join.ROUND);
		mPenPaint.setStrokeCap(Paint.Cap.ROUND);
		mPenPaint.setMaskFilter(mEmboss);
	}
	private void blurPen()
	{
		MaskFilter mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
		mPenPaint.setDither(true);
		mPenPaint.setAntiAlias(true);
		mPenPaint.setStyle(Paint.Style.STROKE);
		mPenPaint.setStrokeJoin(Paint.Join.ROUND);
		mPenPaint.setStrokeCap(Paint.Cap.ROUND);
		mPenPaint.setMaskFilter(mBlur);
	}
	
	private void plainPen()
	{
		mPenPaint.setDither(true);
		mPenPaint.setAntiAlias(true);
		mPenPaint.setStyle(Paint.Style.STROKE);
		mPenPaint.setStrokeJoin(Paint.Join.ROUND);
		mPenPaint.setStrokeCap(Paint.Cap.ROUND);
	}
	
	private void shaderPen()
	{
		mPenPaint.setDither(true);
		mPenPaint.setAntiAlias(true);
		mPenPaint.setStyle(Paint.Style.STROKE);
		mPenPaint.setStrokeJoin(Paint.Join.ROUND);
		mPenPaint.setStrokeCap(Paint.Cap.ROUND);
		mPenPaint.setShadowLayer(15,2,2,Color.WHITE);
	}
}
 public class Bezier implements Tuyuan
{
	/**
	 * »®ÏßÆðÊ¼µãºá×ø±ê
	 */
	private float mCurrentX = 0.0f;
	/**
	 * »®ÏßÆðÊ¼µã×Ý×ø±ê
	 */
	private float mCurrentY = 0.0f;
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	private boolean mHasDraw = false;
	
	/**
	 * Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	private boolean isFilled = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	public Bezier(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
	}

	@Override
	public void touchMove(float x, float y)
	{
		if(isMoved(x, y))
		{
			drawBazier(x, y);
			mHasDraw = true;
		}
	}
	
	@Override
	public void touchUp(float x, float y)
	{
		drawBazier(x, y);
	}
	
	private void savePoint(float x, float y)
	{
		mCurrentX = x;
		mCurrentY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mCurrentX);
		float dy = Math.abs(y - mCurrentY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}
	
	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}
	
	/**
	 * »æÖÆÈý´Î±´Èû¶ûÇúÏß
	 */
	private void drawBazier(float x,float y)
	{
		mPath.reset();
		mPath.moveTo(mCurrentX, mCurrentY);
		
		float x1,y1,x2,y2;
		
		if(x>mCurrentX && y<mCurrentY)//µÚÒ»ÏóÏÞ
		{
			x1 = mCurrentX;
			y1 = y+(mCurrentY-y)/2.0f;
			x2 = x;
			y2 = y+(mCurrentY-y)/2.0f;		
		}else if(x<mCurrentX && y<mCurrentY)//µÚ¶þÏóÏÞ
		{
			x1 = mCurrentX;
			y1 = y+(mCurrentY-y)/2.0f;
			x2 = x;
			y2 = y+(mCurrentY-y)/2.0f;
		}else if(x<mCurrentX && y>mCurrentY)//µÚÈýÏóÏÞ
		{
			x2 = x+(mCurrentX-x)/2.0f;
			y2 = y;
			x1 = x+(mCurrentX-x)/2.0f;
			y1 = mCurrentY;
		}else//if(x>mCurrentX && y>mCurrentY)//µÚËÄÏóÏÞ
		{
			x1 = mCurrentX+(x-mCurrentX)/2.0f;
			y1 = mCurrentY;
			
			x2 = mCurrentX+(x-mCurrentX)/2.0f;
			y2 = y;
		}
		mPath.cubicTo(x1, y1, x2, y2, x, y);
	}
	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);//todo ¼ì²é×ø±ê
		return bounds.contains(x, y);
	}
	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}
	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		mPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		mPath.transform(matrix);
	}
	@Override
	public void fill(int color)
	{
	}
	@Override
	public boolean isFilled()
	{
		return isFilled;
	}
	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		float x0 = (bounds.right+bounds.left)/2.0f;
		float y0 = (bounds.top+bounds.bottom)/2.0f;
		matrix.setScale(offsetX, offsetY,x0,y0);
		
		mPath.transform(matrix);
	}
	private void setPath(Path mPath)
	{
		this.mPath = mPath;
	}
	@Override
	public Tuyuan copy()
	{
		Bezier copedTuyuan = new Bezier(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(mPath));
		copedTuyuan.translate(40,40);
		return copedTuyuan;
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		//ÖÐÐÄµã×ø±ê
		float x0 = (bounds.right+bounds.left)/2.0f;
		float y0 = (bounds.top+bounds.bottom)/2.0f;
		
		matrix.setRotate(degrees,x0,y0);
		
		mPath.transform(matrix);
	}
}
 public class BrokenLine implements Tuyuan
{
	/**
	 * »®ÏßÆðÊ¼µãºá×ø±ê
	 */
	private float mCurrentX = 0.0f;
	/**
	 * »®ÏßÆðÊ¼µã×Ý×ø±ê
	 */
	private float mCurrentY = 0.0f;
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	/**
	 * ×ªÕÛµÄ»Øµ÷½Ó¿Ú
	 */
	private OnTurnListener mListener = null;
	
	private boolean mHasDraw = false;
	
	private Path oldPath = new Path();
	
	/**
	 * ×é³É×îÖÕÂ·¾¶µÄµã¼¯ºÏ
	 */
	private List<PointF> points = new ArrayList<PointF>();
	
	/**
	 * ×îÖÕÂ·¾¶
	 */
	private Path finalPath = new Path();
	
	private boolean isTouchUp = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	/**
	 * Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	private boolean isFilled = false;
	
	public BrokenLine(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			if(isTouchUp)//Èç¹û¶à±ßÐÎÒÑ¾­Éú³É£¬ÄÇÃ´Ö±½ÓÓÃfinalpath£¬Ö®Ç°µÄoldpathºÍmpath¶¼×÷·Ï
			{
				canvas.drawPath(finalPath, mPenPaint);
				return;
			}
			//»æÖÆ¹ýÈ¥µÄÂ·¾¶
			canvas.drawPath(oldPath, mPenPaint);
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
		
		points.add(new PointF(x, y));
	}

	@Override
	public void touchMove(float x, float y)
	{
		if(isMoved(x, y))
		{
			if(mListener!=null && mListener.onTurn())//Èç¹ûµ±Ç°µãÊÇ×ªÕÛµã¾Í¼ÇÂ¼µ±Ç°µÄÎ»ÖÃ£¬²¢×÷ÎªÐÂÆðÊ¼µã
			{
				oldPath.addPath(mPath);
				savePoint(x, y);
				mPath = new Path();
				points.add(new PointF(x, y));
			}
			drawBrokenLine(x, y);
			mHasDraw = true;
		}
	}
	
	@Override
	public void touchUp(float x, float y)
	{
		drawBrokenLine(x, y);
		points.add(new PointF(x, y));
		isTouchUp = true;
		
		finalPath.addPath(mPath);
		//Éú³É×îÖÕÂ·¾¶
		for(int i = 0; i < points.size(); i++)
		{
			if(i == 0)//µÚÒ»¸öµã
			{
				finalPath.moveTo(points.get(i).x,points.get(i).y);
			}
			else
			{
				finalPath.lineTo(points.get(i).x, points.get(i).y);
			}
		}
	}
	private void savePoint(float x, float y)
	{
		mCurrentX = x;
		mCurrentY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mCurrentX);
		float dy = Math.abs(y - mCurrentY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}
	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}
	/**
	 * »æÖÆÖ±Ïß
	 */
	private void drawBrokenLine(float x,float y)
	{
		mPath.reset();
		mPath.moveTo(mCurrentX, mCurrentY);
		mPath.lineTo(x, y);
	}
	
	/**
	 * @param listener
	 * ±ØÐë×¢²á»Øµ÷ÊÂ¼þ
	 */
	public void setOnTurnListener(OnTurnListener listener)
	{
		this.mListener = listener;
	}
	/**
	 * @author Rowand jj
	 *×ªÕÛ»Øµ÷ÊÂ¼þ
	 */
	public interface OnTurnListener
	{
		public boolean onTurn();
	}
	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);//todo ¼ì²é×ø±ê
		return bounds.contains(x, y);
	}
	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}
	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		finalPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		
		finalPath.transform(matrix);
	}
	@Override
	public void fill(int color)
	{
	}
	@Override
	public boolean isFilled()
	{
		return false;
	}
	private void setPath(Path mPath)
	{
		this.finalPath = mPath;
	}
	private void setTouchUp(boolean istouchup)
	{
		this.isTouchUp = istouchup;
	}
	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);
		matrix.setScale(offsetX, offsetY, (bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		finalPath.transform(matrix);
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);
		matrix.setRotate(degrees,(bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		finalPath.transform(matrix);
	}
	@Override
	public Tuyuan copy()
	{
		BrokenLine copedTuyuan = new BrokenLine(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(finalPath));
		copedTuyuan.translate(40,40);
		copedTuyuan.setTouchUp(true);
		return copedTuyuan;
	}
}
 public interface OnTurnListener
{
	public boolean onTurn();
}
 public class Free implements Tuyuan
{
	private float mCurrentX = 0.0f;
	private float mCurrentY = 0.0f;
	private Path mPath = new Path();
	private Paint mPenPaint = null;
	private boolean mHasDraw = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;

	private boolean isFilled = false;
	public Free(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}

	public void setPenSize(int width)
	{
		mPenPaint.setStrokeWidth(width);
	}

	public void setPenColor(int color)
	{
		mPenPaint.setColor(color);
	}

	@Override
	public void draw(Canvas canvas)
	{
		if (canvas != null)
		{
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		// Ã¿´ÎdownµÄÊ±ºò¶¼Òª½«pathÇå¿Õ£¬²¢ÇÒÖØÐÂÉèÖÃÆðµã
		mPath.reset();
		// ÖØÐÂÉèÖÃÆðµã
		mPath.moveTo(x, y);
		savePoint(x, y);
	}

	@Override
	public void touchMove(float x, float y)
	{
		if (isMoved(x, y))
		{
			drawBeziercurve(x, y);
			savePoint(x, y);
			mHasDraw = true;
		}
	}

	@Override
	public void touchUp(float x, float y)
	{
		mPath.lineTo(x, y);
	}

	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}

	private void savePoint(float x, float y)
	{
		mCurrentX = x;
		mCurrentY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mCurrentX);
		float dy = Math.abs(y - mCurrentY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}

	private void drawBeziercurve(float x, float y)
	{
		mPath.quadTo(mCurrentX, mCurrentY, (x + mCurrentX) / 2,(y + mCurrentY) / 2);
	}

	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);//todo ¼ì²é×ø±ê
		return bounds.contains(x, y);
	}

	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}

	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		mPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		mPath.transform(matrix);
	}

	@Override
	public void fill(int color)
	{
	}

	@Override
	public boolean isFilled()
	{
		return isFilled;
	}

	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		matrix.setScale(offsetX, offsetY, (bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		matrix.setRotate(degrees,(bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);
	}
	private void setPath(Path mPath)
	{
		this.mPath = mPath;
	}
	@Override
	public Tuyuan copy()
	{
		Free copedTuyuan = new Free(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(mPath));
		copedTuyuan.translate(40,40);
		return copedTuyuan;
	}
}
 public class Line implements Tuyuan
{
	/**
	 * »®ÏßÆðÊ¼µãºá×ø±ê
	 */
	private float mSrcX = 0.0f;
	/**
	 * »®ÏßÆðÊ¼µã×Ý×ø±ê
	 */
	private float mSrcY = 0.0f;
	
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	private boolean mHasDraw = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	/**
	 * Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	private boolean isFilled = false;
	
	public Line(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
	}

	@Override
	public void touchMove(float x, float y)
	{
		if(isMoved(x, y))
		{
			drawLine(x, y);
			mHasDraw = true;
		}
	}

	@Override
	public void touchUp(float x, float y)
	{
		drawLine(x, y);
	}

	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}
	
	private void savePoint(float x, float y)
	{
		mSrcX = x;
		mSrcY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mSrcX);
		float dy = Math.abs(y - mSrcY);
		boolean isMoved = dx >= (TOUCH_TOLERANCE+3) || dy >= (TOUCH_TOLERANCE+3);
		return isMoved;
	}
	/**
	 * »®Ïß
	 */
	private void drawLine(float x,float y)
	{
		mPath.reset();
		mPath.moveTo(mSrcX, mSrcY);
		mPath.lineTo(x, y);
	}
	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);//todo ¼ì²é×ø±ê
		return bounds.contains(x, y);
	}
	private void setPath(Path mPath)
	{
		this.mPath = mPath;
	}
	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}
	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	
	private void checked(Canvas canvas,int color)
	{
		//»æÖÆÐéÏßµÄ»­±Ê
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		mPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		mPath.transform(matrix);
	}
	@Override
	public void fill(int color)
	{
	}
	@Override
	public boolean isFilled()
	{
		return false;
	}
	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		float x0 = (bounds.right+bounds.left)/2.0f;
		float y0 = (bounds.top+bounds.bottom)/2.0f;
		
		matrix.setScale(offsetX, offsetY,x0,y0);
		
		mPath.transform(matrix);
	}
	
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		//ÖÐÐÄµã×ø±ê
		float x0 = (bounds.right+bounds.left)/2.0f;
		float y0 = (bounds.top+bounds.bottom)/2.0f;
		
		matrix.setRotate(degrees,x0,y0);
		
		mPath.transform(matrix);
	}
	
	@Override
	public Tuyuan copy()
	{
		Line copedTuyuan = new Line(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(mPath));
		copedTuyuan.translate(40,40);
		return copedTuyuan;
	}
}
 public class Oval implements Tuyuan
{
	private float mSrcX = 0.0f;
	private float mSrcY = 0.0f;
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	private RectF mRect = null;
	
	private boolean isFilled = false;
	
	private boolean mHasDraw = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	public Oval(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
	}

	@Override
	public void touchMove(float x, float y)
	{
		if(isMoved(x, y))
		{
			drawOval(x, y);
			mHasDraw = true;
		}
	}

	@Override
	public void touchUp(float x, float y)
	{
		drawOval(x, y);
	}

	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}

	private void savePoint(float x, float y)
	{
		mSrcX = x;
		mSrcY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mSrcX);
		float dy = Math.abs(y - mSrcY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}
	
	/**
	 * »æÖÆÍÖÔ²
	 */
	private void drawOval(float x,float y)
	{
		mPath.reset();
		if(mRect == null)
		{
			mRect = new RectF();
		}
		mRect.set(mSrcX, mSrcY, x, y);
		mPath.addOval(mRect,Path.Direction.CW);
	}

	@Override
	public boolean contains(float x, float y)
	{
		//µÃµ½ÍâÇÐ¾ØÐÎ
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		
		//¸ù¾ÝÍÖÔ²·½³Ì¼ÆËã
		float a = Math.abs((bounds.left - bounds.right)/2.0f);
		float b = Math.abs((bounds.top - bounds.bottom)/2.0f);
		
		float centerX = (bounds.left + bounds.right)/2.0f;
		float centerY = (bounds.top + bounds.bottom)/2.0f;
		return (x-centerX)*(x-centerX)/(float)(a*a)+(y-centerY)*(y-centerY)/(float)(b*b) <= 1;
	}

	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}

	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		mPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		
		canvas.drawCircle(bounds.left, bounds.top + (bounds.bottom-bounds.top)/2.0f,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top + (bounds.bottom-bounds.top)/2.0f,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left+(bounds.right-bounds.left)/2.0f, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left+(bounds.right-bounds.left)/2.0f, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}

	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		mPath.transform(matrix);		
	}
	

	@Override
	public void fill(int color)
	{
		mPenPaint.setStyle(Style.FILL);
		mPenPaint.setColor(color);
		isFilled = true;
	}

	@Override
	public boolean isFilled()
	{
		return isFilled;
	}

	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		matrix.setScale(offsetX, offsetY, (bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		matrix.setRotate(degrees,(bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);		
	}
	private void setPath(Path mPath)
	{
		this.mPath = mPath;
	}
	@Override
	public Tuyuan copy()
	{
		Oval copedTuyuan = new Oval(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(mPath));
		copedTuyuan.translate(40,40);
		return copedTuyuan;
	}
}
 public class Polygn implements Tuyuan
{
	/**
	 * »®ÏßÆðÊ¼µãºá×ø±ê
	 */
	private float mCurrentX = 0.0f;
	/**
	 * »®ÏßÆðÊ¼µã×Ý×ø±ê
	 */
	private float mCurrentY = 0.0f;
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	/**
	 * ×ªÕÛµÄ»Øµ÷½Ó¿Ú
	 */
	private OnTurnListener mListener = null;
	
	private boolean mHasDraw = false;
	
	private Path oldPath = new Path();
	
	/**
	 * Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	private boolean isFilled = false;
	
	/**
	 * ´ú±í´ÓÆðµãµ½ÖÕµãµÄÒ»ÌõÖ±Ïß
	 */
	private Path endPath = new Path();
	
	private float startX = 0.0f;
	private float startY = 0.0f;
	
	private float tempX = 0.0f;
	private float tempY = 0.0f;
	
	private boolean isTouchUp = false;
	
	/**
	 * ×îÖÕÂ·¾¶
	 */
	private Path finalPath = new Path();
	
	/**
	 * ×é³É×îÖÕÂ·¾¶µÄµã¼¯ºÏ
	 */
	private List<PointF> points = new ArrayList<PointF>();
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	
	public Polygn(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			if(isTouchUp)//Èç¹û¶à±ßÐÎÒÑ¾­Éú³É£¬ÄÇÃ´Ö±½ÓÓÃfinalpath£¬Ö®Ç°µÄoldpathºÍmpath¶¼×÷·Ï
			{
				canvas.drawPath(finalPath, mPenPaint);
				return;
			}
			//»æÖÆ¹ýÈ¥µÄÂ·¾¶
			canvas.drawPath(oldPath, mPenPaint);
			if(mHasDraw && !isTouchUp)//´ÓÆðÊ¼µãµ½ÖÕµã»­Ò»ÌõÏß
			{
				canvas.drawPath(mPath, mPenPaint);
				endPath.reset();
				endPath.moveTo(startX, startY);
				endPath.lineTo(tempX, tempY);
				canvas.drawPath(endPath, mPenPaint);
			}
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
		startX = x;
		startY = y;
		
		points.add(new PointF(x, y));
	}

	@Override
	public void touchMove(float x, float y)
	{
		tempX = x;
		tempY = y;
		if(isMoved(x, y))
		{
			if(mListener!=null && mListener.onTurn())//Èç¹ûµ±Ç°µãÊÇ×ªÕÛµã¾Í¼ÇÂ¼µ±Ç°µÄÎ»ÖÃ£¬²¢×÷ÎªÐÂÆðÊ¼µã
			{
				oldPath.addPath(mPath);
				savePoint(x, y);
				mPath = new Path();
				points.add(new PointF(x, y));
			}
			
			drawPolygnLine(x, y);
			mHasDraw = true;
		}
	}
	
	@Override
	public void touchUp(float x, float y)
	{
		drawPolygnLine(x, y);
		oldPath.addPath(endPath);
		oldPath.addPath(mPath);
		isTouchUp = true;
		points.add(new PointF(x, y));
		
		//µ±touchupÊÂ¼þ´¥·¢ºó£¬´ú±í¶à±ßÐÎ»æÖÆÍê±Ï£¬´ËÊ±¸ù¾ÝÖ®Ç°µÄµã¼¯Éú³ÉÒ»Ìõ´ú±í´Ë¶à±ßÐÎµÄpath£¬ÒÔºó¶Ô¶à±ßÐÎµÄ
		//Æ½ÒÆÌîÉ«µÈ²Ù×÷¾ùÔÚ´ËpathÉÏ½øÐÐ
		
		//Éú³É×îÖÕÂ·¾¶
		for(int i = 0; i < points.size(); i++)
		{
			if(i == 0)//µÚÒ»¸öµã
			{
				finalPath.moveTo(points.get(i).x,points.get(i).y);
			}
			else
			{
				finalPath.lineTo(points.get(i).x, points.get(i).y);
			}
		}
		finalPath.close();//±ÕºÏ×îÖÕÂ·¾¶£¨¼´´ÓÆðµãµ½ÖÕµã»æÖÆÒ»ÌõÏß£©
	}
	
	/**
	 * ±£´æµ±Ç°µã
	 */
	private void savePoint(float x, float y)
	{
		mCurrentX = x;
		mCurrentY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mCurrentX);
		float dy = Math.abs(y - mCurrentY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}
	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}
	
	private void drawPolygnLine(float x,float y)
	{
		mPath.reset();
		mPath.moveTo(mCurrentX, mCurrentY);
		mPath.lineTo(x, y);
	}
	
	/**
	 * @param listener
	 * ±ØÐë×¢²á»Øµ÷ÊÂ¼þ
	 */
	public void setOnTurnListener(OnTurnListener listener)
	{
		this.mListener = listener;
	}
	/**
	 * @author Rowand jj
	 *×ªÕÛ»Øµ÷ÊÂ¼þ
	 */
	public interface OnTurnListener
	{
		public boolean onTurn();
	}
	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);
		return bounds.contains(x, y);
	}
	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);		
	}
	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		finalPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		finalPath.transform(matrix);
	}
	@Override
	public void fill(int color)
	{
		mPenPaint.setColor(color);
		mPenPaint.setStyle(Style.FILL);
		isFilled = true;
	}
	@Override
	public boolean isFilled()
	{
		return isFilled;
	}
	private void setPath(Path mPath)
	{
		this.finalPath = mPath;
	}
	private void setTouchUp(boolean istouchup)
	{
		this.isTouchUp = istouchup;
	}
	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);
		matrix.setScale(offsetX, offsetY, (bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		finalPath.transform(matrix);
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		finalPath.computeBounds(bounds, true);
		matrix.setRotate(degrees,(bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		finalPath.transform(matrix);		
	}
	@Override
	public Tuyuan copy()
	{
		Polygn copedTuyuan = new Polygn(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(finalPath));
		copedTuyuan.translate(40,40);
		copedTuyuan.setTouchUp(true);
		return copedTuyuan;
	}
}
 public class Rectangle implements Tuyuan
{
	private float mSrcX = 0.0f;
	private float mSrcY = 0.0f;
	/**
	 * »­±Ê
	 */
	private Paint mPenPaint = null;
	/**
	 * Â·¾¶
	 */
	private Path mPath = new Path();
	
	private boolean mHasDraw = false;
	
	/**
	 * Í¼ÔªÊÇ·ñ±»Ìî³ä
	 */
	private boolean isFilled = false;
	
	private int penSize;
	private int penColor;
	private PaintStyle paintStyle;
	private int alpha;
	
	public Rectangle(int penSize, int penColor,int alpha,PaintStyle paintStyle)
	{
		mPenPaint = paintStyle.getPaintStyle();
		
		mPenPaint.setStrokeWidth(penSize);
		mPenPaint.setColor(penColor);
		mPenPaint.setAlpha(255-alpha);
		
		this.penSize = penSize;
		this.penColor = penColor;
		this.alpha = alpha;
		this.paintStyle = paintStyle;
	}
	@Override
	public void draw(Canvas canvas)
	{
		if(canvas != null)
		{
			canvas.drawPath(mPath, mPenPaint);
		}
	}

	@Override
	public void touchDown(float x, float y)
	{
		mPath.reset();
		mPath.moveTo(x, y);
		savePoint(x, y);
	}

	@Override
	public void touchMove(float x, float y)
	{
		if(isMoved(x, y))
		{
			drawRect(x, y);
			mHasDraw = true;
		}
	}

	@Override
	public void touchUp(float x, float y)
	{
	 	drawRect(x, y);
	}

	@Override
	public boolean hasDraw()
	{
		return mHasDraw;
	}
	
	private void savePoint(float x, float y)
	{
		mSrcX = x;
		mSrcY = y;
	}

	private boolean isMoved(float x, float y)
	{
		float dx = Math.abs(x - mSrcX);
		float dy = Math.abs(y - mSrcY);
		boolean isMoved = dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE;
		return isMoved;
	}
	
	/**
	 * »æÖÆ¾ØÐÎ
	 */
	private void drawRect(float x,float y)
	{
		mPath.reset();
		if(x>mSrcX && y<mSrcY)//µÚÒ»ÏóÏÞ
		{
			mPath.addRect(mSrcX, y, x, mSrcY, Path.Direction.CW);
		}else if(x<mSrcX && y<mSrcY)//µÚ¶þÏóÏÞ
		{
			mPath.addRect(x, y, mSrcX, mSrcY, Path.Direction.CW);
		}else if(x<mSrcX && y>mSrcY)//µÚÈýÏóÏÞ
		{
			mPath.addRect(x, mSrcY, mSrcX, y, Path.Direction.CW);
		}else//µÚËÄÏóÏÞ
		{
			mPath.addRect(mSrcX,mSrcY,x,y,Path.Direction.CW);
		}
	}
	@Override
	public boolean contains(float x, float y)
	{
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);//todo ¼ì²é×ø±ê
		return bounds.contains(x, y);
	}
	@Override
	public void setHighLight(Canvas canvas)
	{
		checked(canvas, Color.YELLOW);
	}
	@Override
	public void checked(Canvas canvas)
	{
		checked(canvas,Color.BLACK);
	}
	
	private void checked(Canvas canvas,int color)
	{
		Paint p = PaintUtils.getDashedPaint();
		p.setColor(color);
		RectF bounds = new RectF();
		
		//¼ÆËã±ß½ç
		mPath.computeBounds(bounds, true);
		canvas.drawRect(bounds, p);
		//»æÖÆ¹Ø¼üµã
		Paint pTemp = new Paint();
		pTemp.setStyle(Style.FILL);
		pTemp.setColor(color);
		canvas.drawCircle(bounds.left, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
		
		canvas.drawCircle(bounds.left, bounds.top + (bounds.bottom-bounds.top)/2.0f,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.right, bounds.top + (bounds.bottom-bounds.top)/2.0f,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left+(bounds.right-bounds.left)/2.0f, bounds.top,ApplicationValues.Base.RADIUS,pTemp);
		canvas.drawCircle(bounds.left+(bounds.right-bounds.left)/2.0f, bounds.bottom,ApplicationValues.Base.RADIUS,pTemp);
	}
	
	@Override
	public void translate(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		matrix.setTranslate(offsetX, offsetY);
		mPath.transform(matrix);
	}
	@Override
	public void rotate(float degrees)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		//ÈÆÖÐÐÄµãÐý×ª
		matrix.setRotate(degrees,(bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);
	}
	@Override
	public void fill(int color)
	{
		//ËùÎ½µÄÌî³ä¹¦ÄÜÆäÊµ¾ÍÊÇ½«»­±ÊµÄÑùÊ½¸ÄÎªÌî³ä
		mPenPaint.setStyle(Style.FILL);
		mPenPaint.setColor(color);
		isFilled = true;
	}
	@Override
	public boolean isFilled()
	{
		return isFilled;
	}
	@Override
	public void scale(float offsetX, float offsetY)
	{
		Matrix matrix = new Matrix();
		RectF bounds = new RectF();
		mPath.computeBounds(bounds, true);
		matrix.setScale(offsetX, offsetY, (bounds.right+bounds.left)/2.0f,(bounds.top+bounds.bottom)/2.0f);
		mPath.transform(matrix);
	}
	private void setPath(Path mPath)
	{
		this.mPath = mPath;
	}
	
	@Override
	public Tuyuan copy()
	{
		Rectangle copedTuyuan = new Rectangle(penSize, penColor, alpha, paintStyle.newInstance());
		if(isFilled)
		{
			copedTuyuan.fill(mPenPaint.getColor());
		}
		copedTuyuan.setPath(new Path(mPath));
		copedTuyuan.translate(40,40);
		return copedTuyuan;
	}
}
 public interface ApplicationValues
{
	/**
	 *»ù±¾ÅäÖÃÐÅÏ¢
	 */
	public interface Base
	{
		/**
		 * shareprefÖÐ´æ´¢µÄxmlÃû
		 */
		public static final String BASE_PREF = "base_pref";
		/**
		 * ×÷Æ·±£´æµÄÂ·¾¶
		 */
		public static final String SAVE_PATH = "/yitu";
		/**
		 * ÁÙÊ±ÎÄ¼þ¼Ð
		 */
		public static final String TEMP_PATH = "/yituTemp";
		
		/**
		 * µ±Ç°Í¼Æ¬µÄ´æ´¢Â·¾¶
		 */
		public static final String IMAGE_STORE_PATH = "image_store_path";
		/*intentÀàÐÍ*/
		public static final String PREVIEW_TYPE = "preview_type";//Ô¤ÀÀÀàÐÍ
		public static final String TYPE_CAMERA = "type_camera";
		public static final String TYPE_GALLERY = "type_gallery";
		public static final String TYPE_MY_WORKS = "type_my_works";
		public static final String TYPE_NORMAL_MODEL = "type_normal_model";
		
		public static final int RADIUS = 8;
	}
	/**
	 *ÉèÖÃÐÅÏ¢
	 */
	public interface Settings 
	{
		/**
		 * shareprefÖÐ´æ´¢µÄxmlÃû
		 */
		public static final String SETTING_PREF = "setting_pref";
		
		/**
		 * ÆÁÄ»×´Ì¬£¨ÊÇ·ñ»­Í¼Ê±ÆÁÄ»³£ÁÁ£©
		 */
		public static final String SCREEN_STATE = "screen_state";
		
		/**
		 * Ò¹¼äÄ£Ê½
		 */
		public static final String NIGHT_MODEL = "night_model";
		
		/**
		 * "Ò¡Ò»Ò¡"Æô¶¯app
		 */
		public static final String SHAKE_MODEL = "shake_model";
		
		/**
		 * »­²¼¿í
		 */
		public static final String CANVAS_WIDTH = "canvas_width";
		
		/**
		 * »­²¼¸ß
		 */
		public static final String CANVAS_HEIGHT = "canvas_height";
	}
	
	/**
	 * @author Rowand jj
	 *»­±ÊÑùÊ½
	 */
	public interface PaintStyle
	{
		/**
		 * Ç¦±Ê
		 */
		public static final int MODE_PLAIN_PEN = 1;
		
		public static final int MODE_EMBOSS_PEN = 2;
		
		public static final int MODE_BLUR_PEN = 3;
		
		/**
		 * »­Ë¢
		 */
		public static final int MODE_BRUSH = 4;
		
		public static final int MODE_SHADER_PEN = 5;
	}
	
	public interface TuyuanStyle
	{
		/**
		 * ×ÔÓÉÊÖ»æ
		 */
		public static final int STYLE_FREE = 1;
		
		/**
		 * Èý´Î±´Èû¶ûÇúÏß
		 */
		public static final int STYLE_BEZIER = 2;

		/**
		 * Ô²/ÍÖÔ²
		 */
		public static final int STYLE_OVAL = 3;
		
		/**
		 * ¾ØÐÎ
		 */
		public static final int STYLE_RECT = 4;
		
		/**
		 * Ö±Ïß
		 */
		public static final int STYLE_LINE = 6;
		
		/**
		 * ÕÛÏß
		 */
		public static final int STYLE_BROKEN_LINE = 7;
		
		/**
		 * ¶à±ßÐÎ
		 */
		public static final int STYLE_POLYGN = 8;
	}
	
	public interface PaintSettings
	{
		/**
		 * »­±ÊÄ¬ÈÏÑÕÉ«
		 */
		public static final int PENCOLOR_DEFAULT = Color.BLACK;
		
		/**
		 * »­±ÊÄ¬ÈÏ´óÐ¡
		 */
		public static final int PENSIZE_DEFAULT = 4;
		
		/**
		 * ÏðÆ¤¿í¶È
		 */
		public static final int ERASER_WIDER_DEFAULT = 3;
		
		/**
		 * Ä¬ÈÏÍ¸Ã÷¶È
		 */
		public static final int PEN_ALPHA_DEFAULT = 0;
	}
}

import java.util.LinkedList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import cn.edu.chd.domain.Tuyuan;
import cn.edu.chd.domain.PaintStyle;
import cn.edu.chd.graphics.Bezier;
import cn.edu.chd.graphics.BrokenLine;
import cn.edu.chd.graphics.BrokenLine.OnTurnListener;
import cn.edu.chd.graphics.Free;
import cn.edu.chd.graphics.Line;
import cn.edu.chd.graphics.Oval;
import cn.edu.chd.graphics.Polygn;
import cn.edu.chd.graphics.Rectangle;
import cn.edu.chd.values.ApplicationValues;

	@Override
	public void onLongPress(MotionEvent e)
	{
		shouldDrag(e);//ÅÐ¶ÏÊÇ·ñÐèÒªÇÐ»»ÎªÍÏ¶¯×´Ì¬
	}


	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY)
	{
		return false;
	}
	
	/**
	 * ÅÐ¶ÏÊÇ·ñÐèÒªÇÐ»»ÎªÍÏ¶¯×´Ì¬
	 */
	private void shouldDrag(MotionEvent e)
	{
		//»ñÈ¡ÊÖÖ¸µ±Ç°°´ÏÂÎ»ÖÃ
		float x = e.getX();
		float y = e.getY();
		//¼ì²éµ±Ç°Î»ÖÃÊÇ·ñÓÐÍ¼ÔªÄÜ¹»±»Ñ¡ÖÐ
		Tuyuan c = mPaintStack.check(x, y);
		//Èç¹ûµ±Ç°µã»÷µÄÍ¼ÔªÕýºÃÊÇÖ®Ç°Ñ¡ÖÐµÄÍ¼ÔªÄÇÃ´¸ÃÍ¼Ôª±äÎªÍÏ¶¯×´Ì¬
		if(c != null && checkedElement != null && c.equals(checkedElement))
		{
			shouldDrag = true;
		}else
		{
			shouldDrag = false;
		}
		invalidate();
	}
	/**
	 * ÊÓÍ¼ÖØ»æ·½·¨
	 * */
	@Override
	protected void onDraw(Canvas canvas)
	{
		//TODO
		if(tempBitmap != null)
		{
			super.onDraw(canvas);
			canvas.drawBitmap(tempBitmap, 0, 0, mPaint);//»æÖÆÖ®Ç°µÄÂ·¾¶
			if(!isTouchUp)
			{
				mCurrentPaint.draw(canvas);//ÔÚviewÉÏ»æÖÆµ±Ç°Â·¾¶
			}
		}
		
		//Ñ¡ÔñµÄÍ¼Ôª²»Îª¿Õ
		if(checkedElement != null)
		{
			if(shouldDrag)//ÍÏ¶¯×´Ì¬ÏÂÐèÒª¸ßÁÁÏÔÊ¾
			{	
				checkedElement.setHighLight(canvas);
				checkedElement.draw(mCanvas);
//				checkedElement.draw(canvas);
			}else if(fillMode)//Ìî³äÄ£Ê½
			{
				checkedElement.draw(mCanvas);
	//			checkedElement.draw(canvas);
			}else if(zoomMode)//Í¼ÔªËõ·ÅÄ£Ê½
			{
				checkedElement.checked(canvas);
				checkedElement.draw(mCanvas);
//				checkedElement.draw(canvas);
				zoomMode = false;
			}else if(rotateMode)//Í¼ÔªÐý×ªÄ£Ê½
			{
				checkedElement.checked(canvas);
				checkedElement.draw(mCanvas);
//				checkedElement.draw(canvas);
				rotateMode = false;
			}
			else//·ñÔòÖ»ÊÇÑ¡ÖÐ×´Ì¬
			{
				checkedElement.checked(canvas);
			}
		}
		//¼ôÌù°åÊÇ·ñÓÐÄÚÈÝ£¬Èç¹ûÓÐÄÚÈÝÔò»æÖÆ
		if(pasteFlag && copedTuyuan!=null)
		{
			Log.i(TAG,"=======ONDRAW_PASTE=======");
			copedTuyuan.draw(mCanvas);
			copedTuyuan = null;
			pasteFlag = false;
		}
	}
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh)
	{
		super.onSizeChanged(w, h, oldw, oldh);
		mBitmapWidth = w;
		mBitmapHeight = h;
		if(isFirstCreated)
		{
			createCanvasBitmap(mBitmapWidth, mBitmapHeight);
			isFirstCreated = false;
		}
	}
	/**
	 * @param type Í¼ÔªÀàÐÍ
	 * @return Í¼Ôª
	 * 
	 * ´´½¨ÐÂµÄÍ¼ÔªÄ£Ê½
	 */
	public Tuyuan createNewTuyuan(int type)
	{
		Tuyuan tool = null;
		switch (type)
		{
		case ApplicationValues.TuyuanStyle.STYLE_FREE://×ÔÓÉÊÖ»æ
			tool = new Free(mPenSize, mPenColor,mPenAlpha,new PaintStyle(paintStyleValue));
			break;
		case ApplicationValues.TuyuanStyle.STYLE_LINE://Ö±Ïß
			tool = new Line(mPenSize, mPenColor,mPenAlpha,new PaintStyle(paintStyleValue));
			break;
		case ApplicationValues.TuyuanStyle.STYLE_RECT://¾ØÐÎ

			tool = new Rectangle(mPenSize, mPenColor, mPenAlpha,new PaintStyle(paintStyleValue));
