I programmed a drawing application, I want to retrieve all the X Y of my drawing. That is to say each time I touch the screen, the coordinates x and y I put them in a two dimensional table ,
I made a toast to find out when the coordinates change, and I found that they change in the movetouch method, so I declare a table in the method and I still make a toast to see the 10 line Of my array, the toast changed co-ordination so I understood that in fact values are crushed whenever the x and y change, or I am planting
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouche(x, y);
invalidate();
break;
}
return true;
}
Method moveTouch
public void moveTouche (float x,float y ) {
if ((canDraw)&& drawing) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if(dx >= Tolerance || dy >= Tolerance){
path.quadTo(mX,mY,(x+mX)/2,(y+mY)/2);
mX = x ;
mY = y;
double[][] point = new double [99][2];
for (int i = 0; i < 99; i++) {
point[i][0]=x;
point[i][1]=y;
}
Toast.makeText(getContext(),"y = "+point[10][1]+" ",Toast.LENGTH_LONG).show();
}}
}
You can read as many points as you want from any path. Example how to read coordinates from the middle of path:
PathMeasure pm = new PathMeasure(myPath, false);
//coordinates will be here
float aCoordinates[] = {0f, 0f};
//get coordinates of the middle point
pm.getPosTan(pm.getLength() * 0.5f, aCoordinates, null);
You can pass any distance from the path start to get point coordinates.
Related
I'm having trouble getting my program in Android Studio to properly constrain the joystick I have created. I have two ImageViews placed on top of one another, one being the joystick itself and one being the base of the joystick. Here is the code:
case R.id.analogStick:
switch(me.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
x = me.getRawX();
y = me.getRawY();
System.out.println(x);
System.out.println(y);
dx = x - v.getX();
dy = y - v.getY();
break;
case MotionEvent.ACTION_UP:
v.setX(originX);
v.setY(originY);
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
float xx = originX - me.getRawX();
float yy = originY - me.getRawY();
float displacement = (float) Math.sqrt((xx * xx) + (yy * yy));
if (displacement < baseRadius) {
v.setX(me.getRawX() - dx);
v.setY(me.getRawY() - dy);
}
else {
float ratio = (float) baseRadius / displacement;
float constrainedX = originX + (me.getRawX() - originX) * ratio;
float constrainedY = originY + (me.getRawY() - originY) * ratio;
v.setX(constrainedX);
v.setY(constrainedY);
}
break;
}
break;
The main problem here is when calculating the displacement. The value turns out to be too high even when within bounds of the baseRadius, so the program always goes to the else statement, executing the constrained joystick case at all times. I get the base radius by the following formula: baseRadius = baseJoystickImage.getWidth() / 2, with baseJoystickImage being an ImageView variable. I'm not sure what could be going wrong here, any help would be appreciated.
I need to create a movement/changing position of the camera with the x,y axes by touching screen. I've read many of the previous questions, but nowhere noticed something that will solve my problem.
how can i use this code ? :
class ESSurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousX;
private float mPreviousY;
#Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
if (y > getHeight() / 2) {
dx = dx * -1 ;
}
if (x < getWidth() / 2) {
dy = dy * -1 ;
}
GLRenderer.setAngle(
GLRenderer.getAngle() +
((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
public ESSurfaceView(Context context)
{
super(context);
setEGLContextClientVersion(2);
GLRenderer renderer = new GLRenderer();
setRenderer(renderer);
// Render the view only when there is a change in the drawing data
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}}
Offical Android Training has an example (mostly identically to yours) for that:
https://developer.android.com/training/graphics/opengl/touch.html
It also offers complete source.
By the way - you never move the camera in openGL - you move the world.
For further understanding please read:
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
This should give you a better understanding on how things work...
I am facing problem for rotating 3d model object. when i load my 3d object in GLSerfaceView with Scene Object the rotation is not working properly.
when i touch the screen and move down means top to bottom then it is working fine as i expected. but when i touch the screen from left to right the it is not rotate as i expected.
glSurfaceView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
previousX = motionEvent.getX();
previousY = motionEvent.getY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
x = motionEvent.getX();
y = motionEvent.getY();
float deltaX = (x - previousX) / density / 2f;
float deltaY = (y - previousY) / density / 2f;
objModel.rotation().x = objModel.rotation().x + deltaY;
objModel.rotation().y = objModel.rotation().y + deltaX;
previousX = x;
previousY = y;
break;
}
return true;
}
});
I have an ImageView where I need to differentiate between a click and longclick as well as swipes. To do so I use the following code :
public boolean onTouch(View v, MotionEvent event) {
Log.d(getClass().getName(), "touch event: " + event.toString());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x1 = event.getX();
y1 = event.getY();
t1 = System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
x2 = event.getX();
y2 = event.getY();
t2 = System.currentTimeMillis();
if (x1 == x2 && y1 == y2 && (t2 - t1) < LONG_PRESS_TIMEOUT) {
//SHORT CLICK
}
The other if conditions identify hold if the time exceeeds the LONG_PRESS_TIMEOUT and swipes if the positions of the touch and release differ significantly. Anyway this works however the user needs to press and let go in the exact same point which makes it not able to identify touches which are a bit rough or sloppy, how could I alter the if condition to allow for these messy clicks but at the same time not set the offset to high so that swipes don't get mistaken as clicks.
Define a radius of 'sloppy' clicks allowed which would effectively create a circle with the center coordinates of the initial click. Then validate that the release coordinates are within that circle.
To verify that the release coordinates are within that circle you would need to calculate the distance between the center of the circle and the point and validate that it's less than the radius. (See https://math.stackexchange.com/questions/198764/how-to-know-if-a-point-is-inside-a-circle for the math involved).
Pseudocode
bool isWithinCircle(int centerX, int centerY, int x, int y, double radius)
{
var temp = pow(x - centerX, 2) + pow(y - centerY, 2);
return sqrt(temp) < r;
}
then your if condition would be:
if (isWithinCircle(x1, y1, x2, y2, radius) && (t2 - t1) < LONG_PRESS_TIMEOUT) {
//SHORT CLICK
}
I've downloaded and run the opengl sample from android. now, i try to make a line with opengl es 2.0 while user is moving their finger. so far this is what i've done:
on my GlSurfaceView class onTouchEvent method:
#Override
public boolean onTouchEvent(MotionEvent e) {
mScaleDetector.onTouchEvent(e);
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN: {
float x = e.getX();
float y = e.getY();
mPreviousX = x;
mPreviousY = y;
// Save the ID of this pointer
mActivePointerId = e.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = e.findPointerIndex(mActivePointerId);
final float x = e.getX(pointerIndex);
final float y = e.getY(pointerIndex);
if (!mScaleDetector.isInProgress()) {
mRenderer.setLineCoordinates(mPreviousX, mPreviousY, x, y);
requestRender();
}
mPreviousX = x;
mPreviousY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (e.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = e.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mPreviousX = e.getX(newPointerIndex);
mPreviousY = e.getY(newPointerIndex);
mActivePointerId = e.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
on my renderer class:
public void onDrawFrame(GL10 gl) {
// Draw background color
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Set GL_MODELVIEW transformation mode
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the matrix to its default state
// When using GL_MODELVIEW, you must set the view point
GLU.gluLookAt(gl, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
gl.glScalef(factor, factor, 0.0f);
// Draw triangle
mTriangle.draw(gl);
mLine.draw(gl);
}
function inside renderer class to change coordinates:
public void setLineCoordinates(float mPreviousX
, float mPreviousY, float x, float y) {
// TODO Auto-generated method stub
lineCoords[0] = (float) (mPreviousX * 2.0 / WIDTH - 1.0);
lineCoords[1] = (float) (mPreviousY * -2.0 / HEIGHT + 1.0);
lineCoords[2] = 0.0f;
lineCoords[3] = (float) (x * 2.0 / WIDTH - 1.0);
lineCoords[4] = (float) (y * -2.0 / HEIGHT + 1.0);
lineCoords[5] = 0.0f;
}
when i move my finger, there's no line, just a moving piece of tiny line...
how can i draw the whole line and keep the line drawing while i keep moving my finger? also start new line when i touch down the screen again.
UPDATED
Thanks for #Gil Moshayof i can draw line now with my version like this
public void setLineCoordinates(float mPreviousX
, float mPreviousY, float x, float y) {
// TODO Auto-generated method stub
float lineCoords[] = new float[6];
lineCoords[0] = (float) (mPreviousX * 2.0 / WIDTH - 1.0);
lineCoords[1] = (float) (mPreviousY * -2.0 / HEIGHT + 1.0);
lineCoords[2] = 0.0f;
lineCoords[3] = (float) (x * 2.0 / WIDTH - 1.0);
lineCoords[4] = (float) (y * -2.0 / HEIGHT + 1.0);
lineCoords[5] = 0.0f;
bufferOfArrays.add(new Line(lineCoords));
if(isFirst) {
isFirst = false;
listOfArrays.addAll(bufferOfArrays);
view.requestRender();
}
}
public void setFirst(boolean isFirst) {
this.isFirst = isFirst;
}
and then:
#Override
public void onDrawFrame(GL10 gl) {
//... color, matrix, look at etc..
// Draw triangle
//mTriangle.draw(gl);
//TODO mLine.draw(gl);
for(Line line : listOfArrays) {
line.draw(gl);
}
isFirst = true;
}
but my app starts to slow down while moving my finger, still have no idea what's happening
The problem here is that you're always setting mPreviousX & mPreviousY on every move. Actually, the problem starts with the name you chose for these parameters. A better name would be mLineStartX/Y.
Set mLineStartX/Y on the touch down event, then update the x/y on every move and don't change the mLineStartX/Y.
As for adding multiple lines, you'll need to implement a bit more logic. You'll need to maintain an array list of some class you define which has 2 point (2xPointFs). The moment the user lifts his finger (touch up / touch cancel), create a new class with the 2 points, and on your render method, make sure you go over all such lines and render them.