How to show previous Path on canvas when scrolling pages in android? - android

I have pdf file and I am drawing a path on devious canvas.And I try to show the previous canvas when scrolling the pdf pages.For that I am saving pdf page number and path.
My code :
This is onTouch: in ACTION_DOWN I am creating new constructor for path every time.When it's calling new path was removing old path and overriding on old path.If I removing this paths are working fine.
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
signaturePaint = new Paint(Paint.DITHER_FLAG);
signaturePaint.setAntiAlias(true);
signaturePaint.setDither(true);
signaturePaint.setColor(0xff0000cc);
signaturePaint.setStyle(Paint.Style.STROKE);
signaturePaint.setStrokeJoin(Paint.Join.ROUND);
signaturePaint.setStrokeCap(Paint.Cap.ROUND);
signaturePaint.setStrokeWidth(1);
**signaturePath = new Path();// When calling this my problem occure**
if (Constants.draw) {
Point p = getPagePositionOnScreen(currentPage);
int currentPageWidth = getCurrentPageWidth(currentPage);
int currentPageHeight = (int) getCurrentPageHeight(currentPage);
if (currentPageWidth < x || currentPageHeight < y) {
} else {
if (Constants.isSignatureSelected)
signaturePath.moveTo(x, y);
// pdfcanvas.moveTo(x, y);
}
firstX = x;
firstY = y;
}
break;
case MotionEvent.ACTION_MOVE:
if (Constants.draw) {
mPageNumber.add(currentPage);
// int[][] currentPagesSize = pagesProvider.getPageSizes();
float pageMarginX = getCurrentMarginX();
float pageMarginy = getCurrentMarginY();
// int pageWidth = currentPagesSize[0][0];
// int pageHeight = currentPagesSize[0][1];
int currentPageWidth = getCurrentPageWidth(currentPage);
int currentPageHeight = (int) getCurrentPageHeight(currentPage);
if (currentPageWidth < x || currentPageHeight < y) {
} else {
resetDirtyRect(x, y);
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
expandDirtyRect(historicalX, historicalY);
if (Constants.isSignatureSelected)
signaturePath.lineTo(historicalX, historicalY);
}
}
}
break;
case MotionEvent.ACTION_UP:
if (Constants.draw) {
firstX = x;
firstY = y;
if (Constants.isSignatureSelected)
saveCanvas();
}
break;
}
invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
(int) (dirtyRect.top - HALF_STROKE_WIDTH),
(int) (dirtyRect.right + HALF_STROKE_WIDTH),
(int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
firstX = x;
firstY = y;
return true;
For savingCanvas in array list : this is saving my canvas paths in arraylist
private void saveCanvas() {
SaveCanvasDrawing canvasDrawing = new SaveCanvasDrawing();
canvasDrawing.setPath(signaturePath);
canvasDrawing.setPdfPageNumber(currentPage);
canvasDrawing.setxAxis(firstX);
canvasDrawing.setyAxis(firstY);
mSavingCanvasDrawing.add(canvasDrawing);
mCanvasHashMap.put(currentPage, mSavingCanvasDrawing);
}
For showing Paths on canvas : In this method in else block I am reseting path.When I am calling this canvas is not drawing my paths.But at the time of debugging my path not null.But it's not showing path on canvas.
private void redoCanvas() {
if (mCanvasHashMap.containsKey(currentPage)) {
mDrawingPath.clear();
mPageNumber.clear();
for (int j = 0; j < mSavingCanvasDrawing.size(); j++) {
int pageNumber = mSavingCanvasDrawing.get(j).getPdfPageNumber();
if (pageNumber == currentPage) {
float xAxis = mSavingCanvasDrawing.get(j).getxAxis();
float yAxis = mSavingCanvasDrawing.get(j).getyAxis();
Path path = mSavingCanvasDrawing.get(j).getPath();
mDrawingPath.add(path);
mPageNumber.add(pageNumber);
} else {
signaturePath.reset();
invalidate();
}
}
} else {
signaturePath.reset();
invalidate();
}
}
Finally onDraw() :
In this method I am checking when my isSignatureSelected = false; I am calling my saved arraylist for path and I am drawing.Here my problem was when I am reseting path in redoCanvas() it's not showing any paths on canvas.But if I remove those resetting lines canvas showng my paths but it's taking all paths from signaturePath.
protected void onDraw(Canvas canvas) {
if (Constants.isSignatureSelected) {
if (Constants.draw) {
canvas.drawPath(signaturePath, signaturePaint);
}
} else {
if (mPageNumber.contains(currentPage)) {
for (Path p : mDrawingPath) {
canvas.drawPath(p, signaturePaint);
}
}
}
}

Yes I got solution.In computeScroll() I am creating new constructor of Path and in onDraw() I am checking the my array list of paths and I am adding paths into canvas

Related

How to make a simple touch screen test application?

I want to make a simple touch screen test application like Samsung Device Diagnostic Tool.
A screenshot from Samsung Device Diagnostic Tool: http://i.stack.imgur.com/7KgKW.jpg
I'm not very familiar with Android App Development. Which way would you suggest me to make a simple application like the tool I mentioned above?
The development of this application easy matter. You need to understand:
How to get the coordinates of click.
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)(event.getX()/tileSize);
int y = (int)(event.getY()/tileSize);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
map[x][y] = true;
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
return false;
}
Override method onDraw, to draw rectangles.
private void init(){
tileSize = 10;
paint1 = new Paint();
paint1.setColor(Color.BLUE);
paint1.setStrokeWidth(10);
paint1.setStyle(Paint.Style.STROKE);
paint2 = new Paint();
paint2.setColor(Color.RED);
paint2.setStrokeWidth(10);
paint2.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < x; i++){
for (int j = 0; j < y; j++){
Paint p = null;
if(map[i][j]){
p=paint1;
}else{
p=paint2;
}
canvas.drawRect(i*tileSize, j*tileSize, tileSize, tileSize, paint);
}
}
}
}
Recently I also had to make this screen test in my app. So I had figured a solution. I am taking an array of RectF i.e. ArrayList<RectF> arr = new ArrayList<>() and drawing this Rects in following order :
Left vertical line
private void drawLeftLine(int width, int height) {
int leftPoint = 0;
int topPoint = 0;
int rightPoint = 100;
int bottomPoint = 100;
int maxNoOfRect = height / 100;
int lastRectHeight = height % 100;
for (int i = 0; i < maxNoOfRect; i++) {
arr.add(new RectF(leftPoint, topPoint, rightPoint, bottomPoint));
topPoint = bottomPoint;
bottomPoint = bottomPoint + 100;
}
}
Top Horizontal line
private void drawTopLine(int w, int h) {
int leftPoint = 0;
int topPoint = 0;
int rightPoint = 100;
int bottomPoint = 100;
int maxNoOfRect = w / 100;
int lastRectWidth = w % 100;
for (int i = 0; i < maxNoOfRect; i++) {
arr.add(new RectF(leftPoint, topPoint, rightPoint, bottomPoint));
leftPoint = rightPoint;
rightPoint = rightPoint + 100;
}
arr.add(new RectF(leftPoint, topPoint, rightPoint + lastRectWidth, bottomPoint));
}
and similarly; 3. Right vertical line 4. Bottom horizontal line, with the help of collections of RectF of size 100.
So, when user touch a point, check whether that co-ordinate lies in any of the RectF bounds? If yes, remove that RectF from the array.
like :
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mOnViewTouchedListener != null)
mOnViewTouchedListener.onViewTouched();
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
Log.d("TAG", "point: " + point);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i).contains(point.x, point.y)) {
Log.d("TAG", "Touch IN");
arr.remove(i);
invalidate();
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if (mOnViewTouchedListener != null)
mOnViewTouchedListener.onViewTouched();
Log.d("TAG", "ACTION_MOVE");
Point point1 = new Point();
point1.x = (int) event.getX();
point1.y = (int) event.getY();
Log.d("TAG", "point: " + point1);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i).contains(point1.x, point1.y)) {
Log.d("TAG", "Touch IN");
arr.remove(i);
invalidate();
break;
}
}
break;
default:
return false;
}
return true;
}
So, this is the solution for this. Same way the diagonal lines are also drawn.
Diagonal line from top left to bottom right :
private void drawTBDiagonalLine(int w, int h) {
float height = h;
float width = w;
float slope = (height / width);
float left = 0;
float top = 0;
float bottom = 100;
float right = bottom / slope;
int maxNoOfRect = h / 100;
for (int i = 0; i < maxNoOfRect; i++) {
arr.add(new RectF(left, top, right, bottom));
left = right;
top = bottom;
bottom = bottom + 100;
right = bottom / slope;
}
}

How to draw an arrowhead in a free handed drawn line in Android?

I need to make a arrow head in a line that is defined by a lot of points, that the user will drawn.
I hope that I could be clear about what is my question.
Thanks.
Note: All the questions/answers that I saw here were to resolve the problem of a line that was defined by two points, taken in the ACTION_DOWN and ACTION_UP. It's different in my case, because I need to take the first point while the line is being drawn.
This is my onTouch() method. It just draw a line defined by where the user touches in the screen.
public boolean onTouch(View v, MotionEvent event) {
if(getEditMode()) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
//Here i have to draw an arrow.
drawCanvas.drawPath(path, paint);
path.reset();
invalidate();
break;
}
invalidate();
return true;
} else {
return false;
}
}
I override draw and rotate the canvas before drawing the arrow.
//NOTE: 0, 0 is the bottom center point
vehicle.draw(canvas);
//draw arrow
if (arrow != null && heading != BusLocation.NO_HEADING)
{
//put the arrow in window
int arrowLeft = -(arrow.getIntrinsicWidth() / 4);
int arrowTop = -vehicle.getIntrinsicHeight() + arrowTopDiff;
//use integer division when possible. This code is frequently executed
int arrowWidth = (arrow.getIntrinsicWidth() * 6) / 10;
int arrowHeight = (arrow.getIntrinsicHeight() * 6) / 10;
int arrowRight = arrowLeft + arrowWidth;
int arrowBottom = arrowTop + arrowHeight;
arrow.setBounds(arrowLeft, arrowTop, arrowRight, arrowBottom);
canvas.save();
//set rotation pivot at the center of the arrow image
canvas.rotate(heading, arrowLeft + arrowWidth/2, arrowTop + arrowHeight / 2);
Rect rect = arrow.getBounds();
arrow.draw(canvas);
arrow.setBounds(rect);
canvas.restore();
}
}
So, I found a solution.
I store all the points that construct the line in an arraylist.
After I took a point of the line that would be in the 0.9 * arraylist.size() as reference to draw an arrowhead that follow the line direction.
Here is my onTouch() method and the funciont that I used to draw the arrow.
public boolean onTouch(View v, MotionEvent event) {
if(getEditMode()) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
path.moveTo(eventX, eventY);
pList.clear(); // When I start a line need to clear the previous coorfinates.
break;
}
case MotionEvent.ACTION_MOVE: {
int hSize = event.getHistorySize();
path.lineTo(eventX, eventY);
PointF aux, auxH;
if(darrow) {
if(hSize > 0) { // If movement is too fast.
for(int i = 0; i < hSize; i++) {
auxH = new PointF(event.getHistoricalX(i), event.getHistoricalY(i));
pList.add(auxH);
}
}
aux = new PointF(eventX, eventY);
pList.add(aux);
}
break;
}
case MotionEvent.ACTION_UP: {
pend.x = eventX;
pend.y = eventY;
if(darrow) { // If need to draw an arrow head to the end of the line;
arrowPath = drawArrow(pend); // Store the right arrowhead to a path.
}
drawCanvas.drawPath(path, paint);
drawCanvas.drawPath(arrowPath, paint);
path.reset();
arrowPath.reset();
invalidate();
break;
}
}
invalidate();
return true;
} else {
return false;
}
}
And the drawArrow(PointF) function:
private Path drawArrow(PointF pfinal) {
float dx, dy;
PointF p1, p2;
PointF pstart;
Path auxPath = new Path();
if(pList.size() > 0) {
PointF[] auxArray = pList.toArray(new PointF[pList.size()]);
int index = (int)(auxArray.length * 0.9);
Log.d(msg, "Size: " + auxArray.length + " | index: " + index);
pstart = auxArray[index];
dx = pfinal.x - pstart.x;
dy = pfinal.y - pstart.y;
float length = (float)Math.sqrt(dx * dx + dy * dy);
float unitDx = dx / length;
float unitDy = dy / length;
final int arrowSize = 10;
p1 = new PointF(
(float)(pfinal.x - unitDx * arrowSize - unitDy * arrowSize),
(float)(pfinal.y - unitDy * arrowSize + unitDx * arrowSize));
p2 = new PointF(
(float)(pfinal.x - unitDx * arrowSize + unitDy * arrowSize),
(float)(pfinal.y - unitDy * arrowSize - unitDx * arrowSize));
auxPath.moveTo(pfinal.x, pfinal.y);
auxPath.lineTo(p1.x, p1.y);
auxPath.moveTo(pfinal.x, pfinal.y);
auxPath.lineTo(p2.x, p2.y);
auxPath.close();
}
return auxPath;
}

Curves are broken while drawing path in canvas

I am using the following code to draw a path based on variable width changes on a Canvas, So far everything works fine and i can easily draw path using this code.
But the path drawn is not smooth, Especially when i draw a curved path all the lines look broken, Why does this happen? Is anything wrong in my code?
public class FingerPaint extends GraphicsActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
}
public void colorChanged(int color)
{
}
public class MyView extends View implements OnTouchListener
{
private static final float STROKE_WIDTH = 3f;
private Paint paint = new Paint();
private Path mPath = new Path();
ArrayList<Path> mPaths = new ArrayList<Path>();
private Canvas m_CanvasView;
private Bitmap m_CanvasBitmap;
int variableWidthDelta = 1;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
ArrayList<Point> points = new ArrayList<Point>(64);
public MyView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
m_CanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
m_CanvasView = new Canvas(m_CanvasBitmap);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(m_CanvasBitmap, 0f, 0f, null);
m_CanvasView.drawPath(mPath, paint);
}
public boolean onTouch(View arg0, MotionEvent event)
{
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
break;
}
case MotionEvent.ACTION_MOVE:
{
if (event.getPressure()>=0.00 && event.getPressure()<0.05)
{
variableWidthDelta = 1;
}
else if (event.getPressure()>=0.05 && event.getPressure()<0.10)
{
variableWidthDelta = 1;
}
else if (event.getPressure()>=0.10 && event.getPressure()<0.15)
{
variableWidthDelta = 2;
}
else if (event.getPressure()>=0.15 && event.getPressure()<0.20)
{
variableWidthDelta = 2;
}
else if (event.getPressure()>=0.20 && event.getPressure()<0.25)
{
variableWidthDelta = 1;
}
else if (event.getPressure() >= 0.25 && event.getPressure()<0.30)
{
variableWidthDelta = 1;
}
else if (event.getPressure() >= 0.30 && event.getPressure()<0.35)
{
variableWidthDelta = 2;
}
else if (event.getPressure() >= 0.35 && event.getPressure()<0.40)
{
variableWidthDelta = 2;
}
else if (event.getPressure() >= 0.40 && event.getPressure()<0.45)
{
variableWidthDelta = 3;
}
else if (event.getPressure() >= 0.45 && event.getPressure()<0.50)
{
variableWidthDelta = 4;
}
paint.setStrokeWidth(STROKE_WIDTH + variableWidthDelta);
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
{
points.add(new Point(event.getX(), event.getY()));
mPath = new Path();
mPath = generatePath();
}
break;
}
case MotionEvent.ACTION_UP:
{
break;
}
}
invalidate();
return true;
}
class Point
{
public final float x;
public final float y;
public Point(float x, float y)
{
this.x = x;
this.y = y;
}
}
public Path generatePath()
{
final float tangentScale = 0.3F;
int pointcount = points.size();
mPath.moveTo(points.get(0).x, points.get(0).y);
mPath.cubicTo(
points.get(0).x + (points.get(1).x - points.get(0).x)*tangentScale,
points.get(0).y + (points.get(1).y - points.get(0).y)*tangentScale,
points.get(1).x - (points.get(2).x - points.get(0).x)*tangentScale,
points.get(1).y - (points.get(2).y - points.get(0).y)*tangentScale,
points.get(1).x, points.get(1).y
);
for(int p=2; p<pointcount-1; p++)
{
mPath.cubicTo(
points.get(p-1).x + (points.get(p).x - points.get(p-2).x)*tangentScale,
points.get(p-1).y + (points.get(p).y - points.get(p-2).y)*tangentScale,
points.get(p).x - (points.get(p+1).x - points.get(p-1).x)*tangentScale,
points.get(p ).y - (points.get(p+1).y - points.get(p-1).y)*tangentScale,
points.get(p).x, points.get(p).y
);
}
mPath.cubicTo(
points.get(pointcount-2).x + (points.get(pointcount-1).x - points.get(pointcount-3).x)*tangentScale,
points.get(pointcount-2).y + (points.get(pointcount-1).y - points.get(pointcount-3).y)*tangentScale,
points.get(pointcount-1).x - (points.get(pointcount-1).x - points.get(pointcount-2).x)*tangentScale,
points.get(pointcount-1).y - (points.get(pointcount-1).y - points.get(pointcount-2).y)*tangentScale,
points.get(pointcount-1).x, points.get(pointcount-1).y
);
return mPath;
}
}
}
The onTouch event is not fired fast enough, so if you draw curves fast enough you will see this happening.
You can improve the point resolution by getting all recorded points between this onTouch event and the last one. Use event.getHistorySize() to get the amount of available points, and get their positions with event.getHistoricalX(int) and event.getHistoricalY(int).
If you still have problems, you would probably have to implement some sort of interpolation of the points.
Here is a simple example using cubicTo() to get a smooth path:
points is an array of all points that are to be drawn.
pointcount is the amount of points
//This code is untested
public Path generatePath(){
Path path = new Path();
if( points.size() < 3 ) return path;
final float tangentScale = 0.3;
path.moveTo(points[0].x, points[0].y);
path.cubicTo(
points[0].x + (points[1].x - points[0].x)*tangentScale,
points[0].y + (points[1].y - points[0].y)*tangentScale,
points[1].x - (points[2].x - points[0].x)*tangentScale,
points[1].y - (points[2].y - points[0].y)*tangentScale,
points[1].x, points[1].y
);
for(int p=2; p<pointcount-1; p++){
path.cubicTo(
points[p-1].x + (points[p].x - points[p-2].x)*tangentScale,
points[p-1].y + (points[p].y - points[p-2].y)*tangentScale,
points[p ].x - (points[p+1].x - points[p-1].x)*tangentScale,
points[p ].y - (points[p+1].y - points[p-1].y)*tangentScale,
points[p].x, points[p].y
);
}
path.cubicTo(
points[pointcount-2].x + (points[pointcount-1].x - points[pointcount-3].x)*tangentScale,
points[pointcount-2].y + (points[pointcount-1].y - points[pointcount-3].y)*tangentScale,
points[pointcount-1].x - (points[pointcount-1].x - points[pointcount-2].x)*tangentScale,
points[pointcount-1].y - (points[pointcount-1].y - points[pointcount-2].y)*tangentScale,
points[pointcount-1].x, points[pointcount-1].y
);
return path;
}
Adapting this for your specific case:
(You will have to modify the above method to use .get() instead of array accessors, since I am using a list here)
//A class for holding x and y values:
class Point{
public final float x;
public final float y;
public Point(float x, float y){
this.x = x;
this.y = y;
}
}
//In your View:
ArrayList<Point> points = new ArrayList<Points>(64);
//In the onTouch-method if the tolerance is ok:
points.add(new Point(event.getX(), event.GetY());
mPath = generatePath();
The above will generate a rounded path that you can draw. Note that it uses all points, so they will all be redrawn every time (you might have to clear the canvas to avoid some artiefacts). You might want to move the generatePath-call to when you lift the finger, so you get a faster, but jagged preview path while drawing.

Android: How to prevent moving object crossing the line

#Override protected void onDraw(Canvas canvas) {
//canvas.drawPicture();
canvas.drawColor(Color.CYAN);
Paint p= new Paint();
p.setColor(Color.RED);
p.setStrokeWidth(20);
canvas.drawLine(100, 200, 400, 500, p);
if(movingObjects.size() > 0){
for (MovingObject ball : movingObjects) {
canvas.drawBitmap(ball.getBitmap(), ball.getX(), ball.getY(), null);
}
}
}
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int)event.getX();
int Y = (int)event.getY();
boolean redraw = false;
switch (eventaction ) {
case MotionEvent.ACTION_DOWN:
currentMovingObjectId = 0;
for (MovingObject movingObject : movingObjects) {
int topLeftX = movingObject.getX() ;
int topLeftY = movingObject.getY() ;
double imageSize = movingObject.getSize();
double radCircle = Math.sqrt( (double) (((topLeftX-X)*(topLeftX-X)) + (topLeftY-Y)*(topLeftY-Y)));
if ( (radCircle < imageSize) &&
(X- topLeftX) < movingObject.getWidth() && (Y - topLeftY) < movingObject.getHeight() &&
(X- topLeftX) > 0 && (Y- topLeftY) > 0){
currentMovingObjectId = movingObjects.indexOf(movingObject) + 1;
offsetX = X- topLeftX;
offsetY = Y - topLeftY;
redraw = true;
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if ( currentMovingObjectId > 0) {
drawAtX = X - offsetX;
drawAtY = Y - offsetY;
if(drawAtX < 0 || (drawAtX + movingObjects.get(currentMovingObjectId-1).getWidth()) > MovingObject.screenWidth)
drawAtX = movingObjects.get(currentMovingObjectId-1).getX();
if(drawAtY < 0 || (drawAtY + movingObjects.get(currentMovingObjectId-1).getHeight()) > MovingObject.screenHeight)
drawAtY = movingObjects.get(currentMovingObjectId-1).getY();
if(drawAtX != movingObjects.get(currentMovingObjectId-1).getX() || drawAtY != movingObjects.get(currentMovingObjectId-1).getY()){
movingObjects.get(currentMovingObjectId-1).setX(drawAtX);
movingObjects.get(currentMovingObjectId-1).setY(drawAtY);
redraw = true;
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
if(redraw)
invalidate();
return true;
}
The above code describes the onTouch and onDraw method in my custom view class and i have to prevent image cross the line.As we can implement using matrix where we can move the object horizontal and vertical avoiding the object by setting the wall on 4 sides of cell but i have to move object freely inside a puzzle.Any logic would be helpful i am stuck.Thanks in advance

how to bound set of points (custom shape) and touch event on it android

i am able to get my bitmap set of points (as an array) using this link
now my question is how can i bound these points as shape/region. Means when user touched on area of my bounded points, i want to move objects(shape) according to that. Above link return points of colored bitmap (it remove transparent part), only colored part points are return as an array.
This is what my code :
1) CustomSahpe.java
public class CustomShape {
private final Context context;
Bitmap bitmap;
int width, height;
int[] pixels;
private final ArrayList<Point> points = new ArrayList<Point>();
public CustomShape(Context context) {
// TODO Auto-generated constructor stub
// super(context);
this.context = context;
bitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_menu_balloon);
width = bitmap.getWidth();
height = bitmap.getHeight();
pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
getActualBitmap();
}
public ArrayList<Point> getPoints(){
return points;
}
public void getActualBitmap() {
for (int x = 0; x < width; x+=2) {
int firstY = -1, lastY = -1;
for (int y = 0; y < height; y+=2) {
boolean transparent = (pixels[y * width + x] == Color.TRANSPARENT);
if (!transparent) {
if (firstY == -1) {
firstY = y;
}
lastY = y;
}
}
if (firstY != -1) {
points.add(new Point(x, firstY));
points.add(new Point(x, lastY));
}
}
}
}
2) MyShapre.java
class MyShape{
CustomShape customShape ;
Point points[];
private int x, y;
Path path = new Path();
public MyShape(Context context) {
customShape = new CustomShape(ScaleTestActivity.this);
points = new Point[customShape.getPoints().size()];
for(int i=0;i<customShape.getPoints().size();i++){
points[i] = new Point();
points[i] = customShape.getPoints().get(i);
}
}
public Path getPath(){
return path;
}
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Paint paint = new Paint();
paint.setColor(Color.WHITE);
for(int i =0 ;i<points.length;i++){
Point point = new Point(points[i].x + getX(), points[i].y + getY());
path.lineTo(points[i].x, points[i].y);
canvas.drawPoint(point.x,point.y,paint);
}
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
}
}
3) MainPanel.java
class MainPanel extends View{
Context context;
MyShape myShape;
boolean flag = false;
public MainPanel(Context context) {
super(context);
this.context = context;
myShape = new MyShape(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.RED);
myShape.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int x,y;
x = (int)event.getX();
y = (int)event.getY();
Point point = new Point(x, y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
myShape.setX(x);
myShape.setY(y);
RectF rectF = new RectF();
Path path = myShape.getPath();
path.computeBounds(rectF, true);
Region region = new Region();
region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
if(region.contains(x,y)){
flag = true;
Log.i("System out","onDown");
}
break;
case MotionEvent.ACTION_MOVE:
Log.i("System out","onMove : "+flag);
if(flag){
myShape.setX(x);
myShape.setY(y);
Log.i("System out","onMove");
}
break;
case MotionEvent.ACTION_UP:
// myShape.setX(x);
// myShape.setY(y);
flag = false;
Log.i("System out","onUp");
break;
default:
break;
}
invalidate();
return true;
}
}
4) ScaleTestActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MainPanel(this));
}
I use a Polygon class to detect touches on rotated bitmaps. It's based mostly on information and code from this site http://alienryderflex.com/polygon/. This should work with your code.
public class Polygon {
// Polygon coodinates.
private final int[] polyY, polyX;
// Number of sides in the polygon.
private final int polySides;
/**
* Default constructor.
* #param px Polygon y coods.
* #param py Polygon x coods.
* #param ps Polygon sides count.
*/
public Polygon( final int[] px, final int[] py, final int ps ) {
polyX = px;
polyY = py;
polySides = ps;
}
/**
* Checks if the Polygon contains a point.
* #see "http://alienryderflex.com/polygon/"
* #param x Point horizontal pos.
* #param y Point vertical pos.
* #return Point is in Poly flag.
*/
public boolean contains( final float x, final float y ) {
boolean oddTransitions = false;
for( int i = 0, j = polySides -1; i < polySides; j = i++ ) {
if( ( polyY[ i ] < y && polyY[ j ] >= y ) || ( polyY[ j ] < y && polyY[ i ] >= y ) ) {
if( polyX[ i ] + ( y - polyY[ i ] ) / ( polyY[ j ] - polyY[ i ] ) * ( polyX[ j ] - polyX[ i ] ) < x ) {
oddTransitions = !oddTransitions;
}
}
}
return oddTransitions;
}
}
You could add this constructor to help you convert a Point array to a Polygon object.
public Polygon(Point[] points){
polySides = points.length;
polyY = new int[polySides];
polyX = new int[polySides];
for(int i = 0; i < polySides; i++){
polyY[i] = points[i].y;
polyX[i] = points[i].x;
}
}
You might be able to use it in your MyShape class with this method.
public boolean isTouched(final float X, final float Y){
final Polygon p = new Polygon(points);
return p.contains(X, Y);
}
Now if you have an odd shape you should be able to detect exactly if the use touches it. I have used this method many times.
Are you looking for a way to tell whether a touch event falls on the non-transparent portion of your drawn bitmap? If so, why don't you just map the touch coordinate to the proper pixel on the bitmap and test the color?
And if that's the case, then you can skip all the path clipping stuff, since the link you posted was only doing that to overcome emulator inefficiencies.
It's a bit complicated so I am not going to provide the full source but I will give you an idea.
You need to transfer your shape in to a triangles collection, then on touch find the nearest point of your shape and check if your are inside this point triangle.
For searching and sorting points you can use red-black-red tree structure.
The search algorithm eventually should be at O(log(N)) and creating shape structure should be O(N*Log(N))

Categories

Resources