Is there a way to read the points created when drawing a path? It seems silly to me that a path cannot be readable.
Or is it just better to manually write the current finger position to an array?
thanks
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.
As far as I know, I think that you can't get previously added points, but you can extend Path class and create your own, override add methods, and then store that points in an array or a list or whatever you prefer.
You mentioned finger position in your question. If you are drawing and using motion events, you could add the X and Y positions to an ArrayList during the event where all even indices are X's and odds are Y's. I used this in a couple of drawing apps I created. To recreate the path all you need is a for loop and Path.lineTo().
Also if you have drawn the path to a view with a specific color, say Color.Black, you can use Bitmap.getPixels(...) and create an array {x0,y0,x1,y1,....xn,yn} based off a for loop like
int i = 0;
for(int y = 0; y < bitmap.getHeight(); y++){
for(int x = 0; x < bitmap.getWidth(); x++){
if(pixels[y*bitmap.getWidth()+x] == Color.BLACK){
xy[i] = x;
i++;
xy[i] = y;
i++;
}
}
}
The array xy has all your coordinates.
Related
I load float values on two List arrays on a thread.
Once the values have been loaded, the arrays are set to two MainActivity static List arrays.
The values load perfectly into the List arrays. In my DummyDraw class which extends Drawable and overrides onDraw(), I am able to draw circles based on the values located inside the MainActivity List arrays, but when I try
to create a path object and load the values to the path object, and afterwards try to draw the path, it won't draw. Here's the code inside onDraw():
//inside onDraw() on DummyDraw class which extends Draw-able:
//in the constructor:
path = new path();
//inside onDraw():
for(int u = 0; u < MainActivity.valueList.size(); u++){
float x = MainActivity.valueList.get(u);
float y = MainActivity.valueList2.get(u);
if(u==0)path.moveTo(x,y);else path.lineTo(x,y);
//canvas.drawCircle(x,y,0.5f*densityMultiplier,points);
}
canvas.drawPath(path,points);// this doesn't draw anything to the screen
Any ideas or suggestions, thanks.
After much trial and error and reading about the quadto and rQuadTo methods, I found a way to create a very excellent approximation of a smooth curve for my graphing function needs:
using the notion of previous and current point on the List arrays:
for(int u = 0; u < MainActivity.valueList.size(); u++){
float x = MainActivity.valueList.get(u);//current point: x value
float y = MainActivity.valueList2.get(u);//current point: y value
if(u!=0){
float previousX = MainActivity.valueList.get(u-1);
float previousY = MainActivity.valueList2.get(u-1);
float middle1 = (previousX + x)/2f;
float middle2 = (previousY + y)/2f;
path.moveTo(previousX,previousY);
path.quadTo(x,y,middle1,middle2);
path.lineTo(x,y);
canvas.drawPath(path,points);//points is the name of my paint object
path.reset();//this is probably the most important line for it to work
}
}
the code above will iterate through two arrays that holds x and y coordinates and create a very excellent looking smooth curve. However, upon zooming into my view I can see some slight blurriness in my curve. Does anyone know what should I do with my paint object to eliminate this blurriness?
I'm in need of assistance with the program that I'm writing.
The code basically list of words from an array, chops it into specific Strings at certain indexes, then into Chars and displaying it into the canvas.
Then, the chars animates while sliding down the canvas.
But, whenever it animates slowly, the characters are on top of each other, and whenever it animates fast, the characters are separated.
How do I get the chars to be separated equally WHILE animating slowly?
One solution I came up with was to find a way to edit the frame rate, but I don't know how to do it :(.
public sketchUp(Context context) {
super(context);
}
String arr [] = {"love","happiness"};
protected void onDraw (Canvas canvas){
super.onDraw(canvas);
Rect disRect = new Rect();
disRect.set(0,0, canvas.getWidth(), canvas.getHeight()/2);
Paint col = new Paint();
Paint txt = new Paint();
txt.setTextSize(20);
txt.setColor(Color.BLACK);
col.setColor(Color.GREEN);
col.setStyle(Paint.Style.FILL);
canvas.drawRect(disRect, col);
if(y<canvas.getHeight()/2){
y+=1;
}
else{
y=0;
}
// if(x<canvas.getWidth()){
// x+=10;
// }
// else{
// x=0;
// }
for(int i=0; i<arr.length; i++){
for(int j=0; j<arr[i].length(); j++){
char result = arr[i].charAt(j);
// System.out.println(result);
canvas.drawText(String.valueOf(result), x, y+=0.5, txt);
//
}
}
invalidate();
}
Think of it this way:
That y+=0.5 sets the separation of the characters. It is the only thing that makes each character's position different. If it was just y, the characters would be on top of each other.
Why it affects animation speed
Each y+=0.5 changes y. So after drawing the characters y is lower than it was before.
How to fix this
First, you have to decide what y is supposed to be. You should rename it, so you remember what it is. For example it could become firstCharacterY.
Obviously, the first characters y should not change when drawing the characters, but should change each frame. To fix the drawing part, you can either set y = firstCharacterY - 0.5 before the loop or calculate y from i and j each iteration.
I am working on image editing using OPENGL in Android and I have applied filter to an image using photoshop curve now I want to reproduce the same in Android using glsl. Is there any formula to calculate single fragment color using photoshops curve output value?
EDIT
The math behind the photoshop curve has already been answered in this question
How to recreate the math behind photoshop curves but I am not very clear about how to reproduce the same in glsl fragment shader.
Screen Shot of my photoshop curve
You're after a function fragColour = curves(inColour, constants...). If you have just the one curve for red, green and blue you apply the same curve to each individually. This answer has a link (below) to code which plots points along the function. The key line is:
double y = ...
Which you'd return from curves. The variable x in the loop is your inColour. All you need now is the constants which come from the points and the second derivative sd arrays. These you'll have to pass in as uniforms. The function first has to figure out which point each colour x is between (finding cur, next, sd[i] and sd[i+1]), then evaluate and return y.
EDIT:
If you just want to apply some curve you've created in photoshop then the problem is much simpler. The easiest way is to create a simple function that gives a similar shape. I use these as a starting point. A gamma correction curve is also quite common.
This is overkill, but if you do need a more exact result, you could create an image with a linear ramp (e.g. 255 pixels from black to white), apply your filter to it in photoshop and the result becomes a lookup table. Passing in all 255 values to a shader is expensive so if it's a smooth curve you could try some curve fitting tools (for example).
Once you have a function, simply apply it to your colour in GLSL. Applying a gamma curve for example is done like this:
fragColour = vec4(pow(inColour.rgb, 1.0 / gamma.rgb), inColour.a);
EDIT2:
The curve you have looks very similar to this:
fragColour = vec4(pow(inColour.rgb, 1.0 / vec3(0.6)), inColour.a);
Or even simpler:
fragColour = vec4(inColour.rgb * inColour.rgb, inColour.a);
Just in case the link dies, I'll copy the code here (not that I've tested it):
Point[] points = /* liste de points, triés par "x" croissants */
double[] sd = secondDerivative(points);
for(int i=0;i<points.length-1;i++) {
Point cur = points[i];
Point next = points[i+1];
for(int x=cur.x;x<next.x;x++) {
double t = (double)(x-cur.x)/(next.x-cur.x);
double a = 1-t;
double b = t;
double h = next.x-cur.x;
double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
draw(x,y); /* ou tout autre utilisation */
}
}
And the second derivative:
public static double[] secondDerivative(Point... P) {
int n = P.length;
double yp1=0.0;
double ypn=0.0;
// build the tridiagonal system
// (assume 0 boundary conditions: y2[0]=y2[-1]=0)
double[][] matrix = new double[n][3];
double[] result = new double[n];
matrix[0][1]=1;
for(int i=1;i<n-1;i++) {
matrix[i][0]=(double)(P[i].x-P[i-1].x)/6;
matrix[i][1]=(double)(P[i+1].x-P[i-1].x)/3;
matrix[i][2]=(double)(P[i+1].x-P[i].x)/6;
result[i]=(double)(P[i+1].y-P[i].y)/(P[i+1].x-P[i].x) - (double)(P[i].y-P[i-1].y)/(P[i].x-P[i-1].x);
}
matrix[n-1][1]=1;
// solving pass1 (up->down)
for(int i=1;i<n;i++) {
double k = matrix[i][0]/matrix[i-1][1];
matrix[i][1] -= k*matrix[i-1][2];
matrix[i][0] = 0;
result[i] -= k*result[i-1];
}
// solving pass2 (down->up)
for(int i=n-2;i>=0;i--) {
double k = matrix[i][2]/matrix[i+1][1];
matrix[i][1] -= k*matrix[i+1][0];
matrix[i][2] = 0;
result[i] -= k*result[i+1];
}
// return second derivative value for each point P
double[] y2 = new double[n];
for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
return y2;
}
I have to move the sprite along the path that is drawn onTouch.For that I'm using Path and PathModifier
case MotionEvent.ACTION_UP:
int historySize = pSceneTouchEvent.getMotionEvent().getHistorySize();
pointX = new float[historySize];
pointY = new float[historySize];
for (int i = 1; i < historySize; i++) {
pointX[i] = pSceneTouchEvent.getMotionEvent().getHistoricalX(i);
pointY[i] = pSceneTouchEvent.getMotionEvent().getHistoricalY(i);
}
path = new path(pointX,pointY);
PathModifier pathModifier = new PathModifier(2.5f, path);
pathModifier.setRemoveWhenFinished(true);
sprite1.clearEntityModifiers();
sprite1.registerEntityModifier(pathModifier);
break;
Its giving me error as path needs at least 2 way points.
Any idea why so?
Normally this shouldn't happen, since a motion event is very often more than just one coordinate. Maybe you should test if the historySize is really bigger than 2. In addition you can add the sprites starting coordinates, otherwise the sprite would "jump" towards the first touch point (but that wasn't your question).
This isn't actually different – just another possibility:
path= new Path(historySize);
for (int i = 0; i < historySize; i++) {
float x = pSceneTouchEvent.getMotionEvent().getHistoricalX(i);
float y = pSceneTouchEvent.getMotionEvent().getHistoricalY(i);
path.to(x,y);
}
In addition I noticed you start your for-loop with int i=1 so if your historySizeis 2, the loop iterates only one times!
EDIT
I couldn't find the problem, but I found a solution:
Instead of using the motionEvent history, save the coordinates of the toucheEvent on the go as the touchEventoccurs:
ArrayList<Float> xCoordinates; // this is where you store all x coordinates of the touchEvents
ArrayList<Float> yCoordinates; // and here will be the y coordinates.
onSceneTouchEvent(TouchEvent sceneTouchEvent){
switch(sceneTouchEvent.getAction()){
case (TouchEvent.ACTION_DOWN):{
// init the list every time a new touchDown is registered
xCoordinates = new ArrayList<Float>();
yCoordinates = new ArrayList<Float>();
break;
}
case (TouchEvent.ACTION_MOVE): {
// while moving, store all touch points in the lists
xCoordinates.add(sceneTouchEvent.getX());
yCoordinates.add(sceneTouchEvent.getY());
break;
}
case (TouchEvent.ACTION_UP): {
// when the event is finished, create the path and make the sprite move
// instead of the history size use the size of your own lists
Path path = new Path(xCoordinates.size());
for (int i = 0; i < xCoordinates.size(); i++) {
path.to(xCoordinates.get(i), yCoordinates.get(i)); // add the coordinates to the path one by one
}
// do the rest and make the sprite move
PathModifier pathModifier = new PathModifier(2.5f, path);
pathModifier.setAutoUnregisterWhenFinished(true);
sprite1.clearEntityModifiers();
sprite1.registerEntityModifier(pathModifier);
break;
}
}
I tested this on my phone (which does not run in debug mode) and it works fine. But to make sure that no Exception will be thrown, you should always test if the xCoordinates list is bigger than 1. Although it is very probable that it is.
Well I hope it helps at least to go around your original problem. I noticed that some methods are named differently (e.g. setAutoUnregisterWhenFinished(true);) I guess you are using AndEngine GLES1 ? I use GLES2, so when a method has another name in my code, don't worry and just look for the equivalent in GLES1 (I didn't rename them because, the code works as it is)
Christoph
I have a 2D game that uses two integer arrays to track x and y coordinates as shown below:
private int gridX[] = { 0,0,0,0,0 }
private int gridY[] = { 0,0,0,0,0 }
The problem is I can have a LOT of objects on the screen that needs to be tracked. Is there a way to add integers / create new blocks as needed? IE in a loop, do something like
gridX[].add(); or something like that. I'm relatively new to java and droid development and I'm having trouble finding a good tutorial or example that shows how to do this without having to initialize the gridX and gridY to sizes of 100 or so.
This is important, as I am about 90% sure that all those unused 0's are causing androids garbage cleanup to lag my application.
Why dont you use an array list instead of an Integer array?
that way you can dynamically add items to the list
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(1);
myList.add(2);
Why not also use the Point class?
List<Point> points = new ArrayList<Point>();
points.add(new Point(0, 0));
points.add(new Point(50, 70));
Point point = points.get(1);
Log.d("MyApp", String.format("The point is: (%d, %d)", point.x, point.y);
This way you are keeping track of your x and y coordinates together and there is less opportunity for error.